接上篇讲述的ipsec。原文链接:
2.1.11 发送处理
2.1.11.1 实现思想
首先要判断是否需要进行分片处理。转发的IP包,或者是本地产生的经过IPSec处理过的IP包的长度有可能大于发送接口的MTU,此时必须进行分片处理。分片结束后将IP包交给链路层处理模块,然后由网卡发送该数据包。
2.1.11.2 实现细节
1、判断是否需要分片,如果需要,则调用分片函数ip_fragment进行分片。
2、将IP包交给链路层处理模块:dev_queue_xmit。
2.2 功能模块的实现
2.2.1 策略库(SPD)的实现:
2.2.1.1 实现思想:
我们将安全策略库的配置设置在安全网关上,各个安全网关独立配置策略库。但要保证策略的一致性。
安全策略库(SPD)说明了对IP数据报提供何种保护,并以何种方式实施保护。SPD中策略项的建立和维护应通过协商;而且对于进入和外出处理都应该有自己的策略库。对于进入或外出的每一份数据报,都可能有三种处理:丢弃、绕过或应用IPSec。SPD提供了便于用户或系统管理员进行维护的管理接口。可允许主机中的应用程序选择IPSec安全处理。SPD中的策略项记录对SA(SA束)进行了规定,其字段包含了IPsec协议、模式、算法和嵌套等要求。SPD还控制密钥管理(如ISAKMP)的数据包,即对ISAKMP数据包的处理明确说明。
SPD是利用radix树型结构来构造。每一个结点就是一个策略项。策略项中包含一个SAID数据结构,它是SPD与SAD之间的接口。可以由它来查找SAD,从而指定相关的SA(或SA串)。这样使得策略项可以对应相关的一个SA或者多个SA(SA串)。
SPD中策略项的查找是通过选择符来进行的。SA或SA束的粒度决定于选择符。通过选择符,可以找到外出或进入IP包应该实行的策略项。两个策略项的选择符可以相同。我们选用第一匹配项,并保证SPD始终以同样的顺序进行查找,这样就保证了第一匹配策略项的一致性选择。
2.2.1.2 实现细节
1、策略库的构建方式:采用radix树型结构。存放在内核中。
2、选择符的构成。选择符包含下列参数:目的地IP地址、源IP地址、名字(用户ID、系统名字)、数据保密等级、源端口和目的端口
3、策略项的构成。策略项包含下列参数:radix树相关数据结构、SAID结构、地址、掩码。
4、为用户层提供的接口(PF_key),允许用户程序可通过接口对库进行操作:添加、删除、搜索(匹配)。
5、对策略库的操作时机:用户通过配置界面对策略库进行相关操作;IKE协商SA完毕后,在更新SAD的同时,也要建立新的SAD与SPD之间的关联。
2.2.1.3 基本操作
用户配置程序通过PF_key接口调用内核相关程序程序,实现对安全策略库的操作。
1、添加策略项:ipsec_create_policy
根据用户传入的信息构造策略项结构,然后将该结构加入到radix树中。
2、删除策略项:ipsec_delete_policy
根据用户传入信息,在radix树中找到该策略项,然后删除该节点。
3、查找策略项:ipsec_find_policy
根据用户传入信息,在radix树中查找到该策略项。
2.2.2 安全关联库(SAD)的实现
2.2.2.1 实现思想
安全关联(SA)是构成IPSec的基础。SA是两个通信实体经过协商建立起来的一种协定。他们决定了用来保护数据保安全的IPSec协议、模式、算法及密钥、生存期、抗重播窗口、计数器等等。SA是单向的,因此外出和进入处理需要不同的SA。SA还与协议相关,每一种协议都有一个SA。
安全关联库(SAD)维护了IPSec协议用来保障数据保安全的SA记录。每个SA都在SAD中有一条记录相对应。对于外出处理,应SPD中查找指向SAD中SA的指针,如SA未建立,则应激活IKE建立SA,并同SPD和SAD的记录关联起来。对于进入处理,SAD的记录用目的IP地址、IPSec协议类型和SPI标识。
SAD是利用HASH表来构造的。
SAD的查找是通过一个三元组(SAID):协议、目的地址、SPI来进行的,三元组标识了唯一的SA。通过对SAID的散列找到SA头,然后再进行详细匹配找到相应的SA。
SA的管理可以通过手工进行,也可以通过IKE来进行动态协商。为了进行SA的管理,我们利用PF_key实现了一个用户应用与内核通讯的接口。
2.2.2.2 实现细节
1、安全关联库(SAD)的构建方式:通过hash表(如图)
2、SAD库的查找通过一个SAID:目的地址、协议、SPI>
3、SA记录的构成。每一个SA的基本结构包括:
l 序号计数器:32比特。
l 序号计数器溢出标志:标识序号计数器是否溢出。如果溢出,则产生一个审计事件,并禁止用SA继续发送数据包。
l 抗重播窗口:32比特计数器及位图,用于决定进入的AH或ESP数据包是否为重发的。
l AH验证算法及其密钥等。
l ESP加密算法、密钥、IV模式、IV等。
l ESP验证算法、密钥等。如未选择验证服务,该字段为空。
l 安全关联的生存期:一个时间间隔。
l IPsec协议模式:隧道、传输或通配:主机实施应支持所有模式;网关实施应支持隧道模式
l PMTU:所考察的路径的MTU及其寿命变量。
4、SAD和SPD之间是通过SAID进行关联的。通过查看SPD中的SAID值,可对SAD进行查找,找到该策略项所应该实施的SA。
5、安全关联库与用户程序(IKE)的接口,通过PF_key来实现。无论是手工创建一个SA(手工创建一个SA时需要对其进行SPI的赋值),还是通过密钥管理协议IKE动态创建SA,都通过该接口对SAD和SPD进行操作。
2.2.2.3 基本操作
1、创建一个SA:ipsec_create_sa
根据用户提供的SA相关参数构建SA结构,然后提取SAID值,并对SAID进行散列。将SA结构放入散列链头。
2、删除一个SA:ipsec_delete_sa
根据用户参数,提取SAID。根据SAID查找SAD,找到后将SA结构从链中删除。
3、查找一个SA:ipsec_find_sa
根据用户参数,提取SAID。对SAID散列后,在SAD散列表中中找到SA链头,再进行详细SAID匹配找到为一的SA。
2.2.3 AH协议处理模块实现
2.2.3.1 AH格式:
各字段含义如下:
1) 下一头(8比特):标识紧跟验证头的下一个头的类型。
2) 载荷长度(8比特):以32-位字为单位的验证头的长度,再减去2。例如,缺省的验证数据字段的长度是96比特(3个32-位字),加上3个字长的固定头,头部共6个字长,因此该字段的值为4。
3) 保留(16比特):保留为将来使用。
4) 安全参数索引(32比特):用于标识一个安全关联。
5) 序号(8比特):单增的计数器值。
6) 验证数据(可变):该字段的长度可变(但应为32-位字的整数倍),包含的数据有数据包的ICV(完整性校验值)或MAC。
2.2.3.2 实现功能:
AH用于为IP提供数据完整性、数据原始身份验证和一些可选的、有限的抗重播服务。
2.2.3.3 实现模式:
在安全网关上只实现隧道模式:
AH:
外部IP头
下一个头
载荷长度
保留
安全参数索引(SPI)
序列号
验证数据
内部IP头
TCP头
数据
2.2.4 ESP协议处理模块实现
2.2.4.1 ESP格式
各字段含义如下:
1) 安全参数索引(32比特):标识一个安全关联。
2) 序号(32比特):单增的计数器值。
3) 载荷数据(可变):传输层数据段(传输模式)或IP包(隧道模式),通过加密得到保护。
4) 填充(0-255字节):额外的字节。有的加密算法要求明文长度是8位组的某个整倍数。
5) 填充长度(8比特):表示填充的字节数。
6) 下一头(8比特):通过标识载荷中的第一个头(如IPv6中的扩展头,或诸如TCP之类的上层协议头),确定载荷数据字段中数据的类型。
验证数据(可变):长度可变的字段(应为32-位字的整数倍),用于填入ICV。ICV的计算范围为ESP包中除去验证数据字段的部分。
2.2.4.2 实现功能:
ESP用于为IP提供机密性、数据源验证、抗重播以及数据完整性等安全服务。
2.2.4.3 实现模式
在安全网关上只实现隧道模式:
ESP:
IP头
安全参数索引(SPI)
序列号
内部IP头
TCP头
数据
填充项
填充项长度
下一个头
验证数据
2.2.5 算法实现
2.2.5.1 实现思想
支持多种认证算法和加密算法,并且可以动态添加。其中现有认证算法支持:hmac-md5-96和hmac-sha1-96;加密算法支持:3des-md5-96和3des-sha1-96。密钥生成分为两种:一种是预共享密钥PSK,一种是公私钥RSA。如果利用PSK生成密钥,则通讯双方的PSK密钥必须相同。
2.2.5.2 实现细节
2.2.6 日志、统计、配置与审计实现
2.2.6.1 日志与审计
VPN网关将记录对网关进行的各种操作,包括错误信息、安全规则文件的修改等等。并按照安全等级、事件名称和发生时间、事件内容及操作者以图表的方式显示在VPN配置服务器上。
通过安全事件的日志记录,可以提高VPN网关管理的安全性,并通过审查日志发现违反安全规则的操作,并及时采取相应的措施。
2.2.6.2 统计
对各种流量信息进行统计:通过的总IP包数,丢弃的总IP包数、经过IPSec处理过的IP包数、绕过处理的IP包数,各种流过的协议,时间统计等等。
2.2.6.3 配置
为用户提供友好的配置界面,可以对VPN网关的的各种信息进行配置。(如图)
2.2.7 应用程序与内核的通讯接口实现
2.2.7.1 实现思想
用户的各种配置请求,以及密钥管理守护进程(IKE)都将涉及到对内核相关数据结构(安全策略库SPD、安全关联库SAD)的修改。因此我们利用PF_KEY协议来实现用户应用程序与内核的通讯。(如图)
如图,用户配置信息和IKE守护进程可以通过PF_KEY协议接口对内核空间的安全策略库(SAD)进行操作。同样,内核程序也可以通过PF_KEY协议接口向应用程序发出协商SA的请求。
PF_KEY协议簇的socket的操作同其他类型的socket操作无差别。
int s = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
用户进程通过使用这个socket接口来发送和接收信息与内核通信。对这个socket 的操作同其它socket一样,bind(), connect(), socketpair(), accept(), getpeername(), getsockname(), ioctl(), and listen().
实现的主要消息种类:
◆ SADB_ADD 向内核的SADB增加一个SA
◆ SADB_DELETE 从内核的SADB删除一个SA
◆ SADB_GET 从内核的SADB获取一个SA
◆ SADB_REGISTER IKE守护进程注册策自己能提供服务的协议类型,AH,ESP或其它
◆ SADB_EXPIRE 内核发送给IKE守护进程某个SA过期,包括软、硬过期
2.2.7.2 实现细节
1、PF_KEY消息头格式
上面是PF_KEY消息的基本头,每个基本头后面都可以跟随一个或多个扩展域:生存期域、地址域、密钥域等等。
2、内核实现
内核启动时调用ipsec_init()(/ipsec_init.c),为了使用pf_key接口它调用pfkey_init()(/pfkey_v2.c)。此函数注册它要服务的SA类型:AH,ESP,IPIP,如果配置了IP_COMP那么也注册。首先建立几个全局变量结构结构,然后把定义的SA类型添加到对应的pfkey_supported_list队列中,然后注册pfkey的socket操作集。
l struct supported_list *pfkey_supported_list[SADB_SATYPE_MAX+1];
每种SA类型一个链表数组,说明了当前内核支持的Sa类型。
l struct socket_list *pfkey_registered_sockets[SADB_SATYPE_MAX+1];
每种SA类型一个链表数组,说明了在当前内核中注册使用的pfkey socket。
l struct socket_list *pfkey_open_sockets = NULL
应用pfkey接口的进程打开的socket
l struct sock *pfkey_sock_list = NULL;
应用pfkey接口的进程打开的socket对应的sock
应用程序和内核之间通讯时,首先要建立一个PF_KEY消息结构,然后将消息类型和消息相关内容填入PF_KEY消息中,最后发送消息。
在接收消息时,将会根据不同的消息类型进行不同的处理。
总的来说,对于VPN和IPSec的关系,IPSec的关键其实是为IP数据报文提供安全性security,而VPN只是在实现这种安全特性下产生的解决方案。