当前位置: 首页 > Linux

XFRM--IPsec协议核心实现框架

时间:2023-04-06 05:22:07 Linux

IPsec协议帮助IP层建立安全可靠的数据包传输通道。目前有比较成熟的解决方案如StrongSwan和OpenSwan,它们都是使用Linux内核中的XFRM框架来接收和发送消息。XFRM的正确读法是transform(转换),意思是内核协议栈接收到的IPsec报文需要进行转换,才能恢复成原来的报文;同样,要发送的原始消息也需要转换成IPsec消息才能发送出去。概述XFRM实例IPsec中有两个重要的概念:SecurityAssociation和SecurityPolicy。这两种类型的信息都需要存储在内核XFRM中。KernelXFRM使用netns_xfrm结构来组织这些信息,也称为xfrm实例(instance)。从它的名字也可以看出这个实例是和网络命名空间相关的,每个命名空间都有这样一个实例,并且这些实例之间是相互独立的。所以同一主机上的不同容器可以使用XFRMstructnet{...#ifdefCONFIG_XFRMstructnetns_xfrmxfrm;#endif…}Netlink通道提到了SecurityAssociation和SecurityPolicy信息,这些信息一般由用户态IPsec进程(例如StrongSwan)传递给内核XFRM,传递通道是在网络命名空间初始化时创建的。staticint__net_initxfrm_user_net_init(structnet*net){structsock*nlsk;structnetlink_kernel_cfgcfg={.groups=XFRMNLGRP_MAX,.input=xfrm_netlink_rcv,};nlsk=netlink_kernel_create(net,NETLINK_XFRM);&cfreturn0;}这样,当用户下发IPsec配置时,内核可以调用xfrm_netlink_rcv()来接收XFRMStateXFRM使用xfrm_state来表示IPsec协议栈中的SecurityAssociation,它代表了一个单向IPsec所需要的所有信息traffic,包括模式(传输或隧道)、密钥和重放参数等信息。用户态IPsec进程通过发送一个XFRM_MSG_NEWSA请求,可以让XFRM创建一个xfrm_state结构xfrm_state包含很多字段,这里就不贴了,只列出最重要的字段:id:是一个xfrm_id结构,其中包含SA'sDestinationaddress,SPI,andprotocol(AH/ESP)props:表示SA的其他属性,包括IPsecMode(Transport/Tunnel),源地址等信息。每个xfrm_state都会在内核中添加多个哈希表。因此,内核可以从多个特征中找到同一个SA:xfrm_state_lookup():通过指定的SPI信息查找SAxfrm_state_lookup_byaddr():通过源地址查找SAxfrm_state_find():通过目的地址查找SA通过ipxfrmstatels可以列出用户command当前主机上的xfrm_statesrc192.168.0.1dst192.168.0.2protoespspi0xc420a5ed(3290473965)reqid1(0x00000001)modetunnelreplay-window0seq0x00000000flagaf-unspec(0x00100000)auth-trunchmac(sha256)0xa65e95de83369bd9f3be3afafc5c363ea5e5e3e12c3017837a7b9dd40fe1901f(256bits)128enccbc(aes)0x61cd9e16bb8c1d9757852ce1ff46791f(128bits)anti-replaycontext:seq0x0,oseq0x1,bitmap0x00000000lifetimeconfig:limit:soft(INF)(soft(bytes),hard(INF)limit)()(数据包),硬(INF)(数据包)过期添加:软1004(秒),硬1200(秒)过期e使用:软0(秒),硬0(秒)生命周期当前:84(字节),1(数据包)添加2019-09-0210:25:39使用2019-09-0210:25:39统计数据:replay-window0replay0failed0XFRMPolicyXFRM使用xfrm_policy来表示IPsec协议栈中的SecurityPolicy。通过发布这样的规则,用户可以让XFRM允许或禁止发送和接收具有某些特征的流通过发送XFRM_MSG_POLICY请求,用户态IPsec进程可以让XFRM创建一个xfrm_state结构体structxfrm_policy{......structhlist_nodebydst;结构hlist_nodebyidx;/*这个锁只影响除了entry之外的元素。*/rwlock_t锁;atomic_t引用;结构timer_list计时器;结构flow_cache_objectflo;atomic_t基因;u32优先;u32指数;结构xfrm_mark标记;结构xfrm_selector选择器;结构xfrm_lifetime_cfglft;结构xfrm_lifetime_curcurlft;结构xfrm_policy_walk_entry步行;结构xfrm_policy_queuepolq;u8型;u8动作;u8标志;u8xfrm_nr;u16家庭;结构xfrm_sec_ctx*安全;结构xfrm_tmplxfrm_vec[XFRM_MAX_DEPTH];结构rcu_headrcu;};这个结构体中有很多字段,但是大部分不需要关注,我们重点关注下面列出的几个字段即可:selector:表示策略匹配的流的特征动作:值为XFRM_POLICY_ALLOW(0)或XFRM_POLICY_BLOCK(1),前者表示允许流量,后者表示不允许xfrm_nr:表示这个Policy关联的模板数量,template可以理解为xfrm_state的简化版,xfrm_nr决定了流量转化的数量,通常这个值是1xfrm_vec:表示这个Policy关联的模板,每个元素都是xfrm_tmpl,一个xfrm_tmpl可以被恢复(resolve)成一个类似于xfrm_state的完整状态,用户可以通过ipxfrmpolicyls命令10.1.0.0/16dst10.2.0.0/16uid0diroutaction列出当前主机上的xfrm_policysrcallowindex5025priority383615ptypemainshareanyflag(0x00000000)lifetimeconfig:limit:soft(INF)(bytes),hard(INF)(bytes)限制:soft(INF)(packets),hard(INF)(packets)expireadd:soft0(sec),hard0(sec)expireuse:soft0(sec),hard0(sec)lifetimecurrent:0(bytes),0(packets)添加2019-09-0210:25:39使用2019-09-0210:25:39tmplsrc192.168.0.1dst192.168.0.2protoespspi0xc420a5ed(3290473965)reqid1(0x00000001)模式隧道级别需要auth共享skff任何ffff-ffmaff-maff接收和发送ffIPsec报文接收下图是XFRM帧接收IPsec报文的过程:从整体上看,IPsec报文的接收是一个迂回的过程。IP层收到后,根据报文的protocol字段,如果是IPsec类型(AH,ESP),就会进入XFRM框架接收。在这个过程中,比较重要的过程是xfrm_state_lookup(),它搜索SA。如果找到,则根据不同的协议从模式进入不同的处理过程。最后获取原始消息的信息,重新进入ip_local_deliver()。然后需要通过XFRMPolicy进行过滤,最后送到应用层进行投递。下图是XFRM框架下发IPsec消息的过程:XFRM在消息路由搜索后检查是否有满足条件的SA,如果没有则直接进入ip_output(),否则进入XFRM处理流程,根据模式和协议做相应的处理,最后通过不同的路由返回ip_output()REFLinuxKernelNetworkingImplementationandThry