禁用于任何商业用途。
msn: [email protected]
来源:http://yfydz.cublog.cn
UNP第一卷的第3版是著名的RWS先生魂归上帝后由后人添加新的一些新的东西后发布的,增加的部分包括 PF_KEY和SCTP等的相关编程。今天重读UNP,看看PF_KEY一章。 PF_KEY协议族主要用来处理安全联盟SA的,对SADB(SA数据库)进行管理,主要用在IPSEC协议中,其他 协议如OSPF等用到密钥的协议中也可以用。 PF_KEY_v2的编程API在RFC2367中定义,其实在freeswan的pluto中有完整的PF_KEY运用实例。在UNP这 本书中只是很简单的介绍了一下,属于入门级,详细说明要看RFC,程序实例看pluto。 PF_KEY协议族只支持RAW模式,只能由ROOT权限的用户打开PF_KEY类型的套接口,这和netlink类型套接 口是类似的,而且数据格式也是以消息方式传输。 进程PF_KEY类型的套接口和netlink套接口一样,可以双向和内核进行通信。可以向内核和其他打开了 PF_KEY套接口发送消息,可进行SADB中的SA项的增加和删除;也可以从内核中接收消息。 PF_KEY的消息的数据格式都是有一个格式相同的数据头(12字节长), 说明数据类型等信息, 然后后面可 以跟0到多个扩展的结构用来描述不同类型的具体数据内容: 消息头: struct sadb_msg { u_int8_t sadb_msg_version; /* PF_KEY_V2 */ u_int8_t sadb_msg_type; /* see Figure 19.2 */ u_int8_t sadb_msg_errno; /* error indication */ u_int8_t sadb_msg_satype; /* see Figure 19.3 */ u_int16_t sadb_msg_len; /* length of header + extensions / 8 */ u_int16_t sadb_msg_reserved; /* zero on transmit, ignored on receive */ u_int32_t sadb_msg_seq; /* sequence number */ u_int32_t sadb_msg_pid; /* process ID of source or dest */ }; 结构中的元素含义都比较直观, sadb_msg_type是消息的类型, 基本反映命令动作, 如读当前SADB, 增 加删除SA等, sadb_msg_satype表示的是要操作的SA的类型,表示要对哪些SA进行命令动作. 基本通信过程: 先打开PF_KEY的套接口, 填消息头信息, 必要时再填后续数据信息, 可以用write()函数将数据写到套 接口, 用read()函数从套接口读回应数据: dump_sadb: 1 void 2 sadb_dump(int type) 3 { 4 int s; 5 char buf[4096]; 6 struct sadb_msg msg; 7 int goteof; 8 s = Socket(PF_KEY, SOCK_RAW, PF_KEY_V2); 9 /* Build and write SADB_DUMP request */ 10 bzero(&msg, sizeof (msg)); 11 msg.sadb_msg_version = PF_KEY_V2; 12 msg.sadb_msg_type = SADB_DUMP; 13 msg.sadb_msg_satype = type; 14 msg.sadb_msg_len = sizeof (msg) / 8; 15 msg.sadb_msg_pid = getpid(); 16 printf("Sending dump message:\n"); 17 print_sadb_msg (&msg, sizeof (msg)); // write发送 18 Write(s, &msg, sizeof (msg)); 19 printf("\nMessages returned:\n"); 20 /* Read and print SADB_DUMP replies until done */ 21 goteof = 0; 22 while (goteof == 0) { 23 int msglen; 24 struct sadb_msg *msgp; // read读 25 msglen = Read(s, &buf, sizeof (buf)); 26 msgp = (struct sadb_msg *) &buf; 27 print_sadb_msg(msgp, msglen); // 注意判断消息结束的方法 28 if (msgp->sadb_msg_seq == 0) 29 goteof = 1; 30 } 31 close(s); 32 } 建立SA: 建立SA分两类, 一种是静态SA, 一般建立后就不变了; 一种是动态SA, SA有一定寿命, 需要周期性的更 新密钥。前者一般用在手工建立的IPSEC连接,一般只是调试时使用,后者用于自动密钥协商,是常用 的情况。 为建立一个静态SA,需要发送的消息除了消息头外,还必须要有三个扩展数据部分:SA、地址和密钥; 可选的还可有生命期(lifetime)、身份(identity)和敏感性(sensitivity)。 SA结构: struct sadb_sa { u_int16_t sadb_sa_len; /* length of extension / 8 */ u_int16_t sadb_sa_exttype; /* SADB_EXT_SA */ u_int32_t sadb_sa_spi; /* Security Parameters Index (SPI) */ u_int8_t sadb_sa_replay; /* replay window size, or zero */ u_int8_t sadb_sa_state; /* SA state, see Figure 19.7 */ u_int8_t sadb_sa_auth; /* authentication algorithm, see Figure 19.8 */ u_int8_t sadb_sa_encrypt; /* encryption algorithm, see Figure 19.8 */ u_int32_t sadb_sa_flags; /* bitmask of flags */ }; 地址结构,该结构后面跟相关地址族的sockaddr结构(sockaddr_in, sockaddr_in6等): struct sadb_address { u_int16_t sadb_address_len; /* length of extension + address / 8 */ u_int16_t sadb_address_exttype; /* SADB_EXT_ADDRESS_{SRC,DST,PROXY} */ u_int8_t sadb_address_proto; /* IP protocol, or 0 for all */ u_int8_t sadb_address_prefixlen; /* # significant bits in address */ u_int16_t sadb_address_reserved; /* reserved for extension */ }; 密钥结构, 密钥跟在该结构后面: struct sadb_key { u_int16_t sadb_key_len; /* length of extension + key / 8 */ u_int16_t sadb_key_exttype; /* SADB_EXT_KEY_{AUTH, ENCRYPT} */ u_int16_t sadb_key_bits; /* # bits in key */ u_int16_t sadb_key_reserved; /* reserved for extension */ }; 要写程序实现建立SA过程,就是在一大块缓冲区中依次填入消息头结构、SA结构、相关地址信息、密钥 结构、密钥,然后发到套接口,然后接收数据,接收时要注意判断消息的进程号和类型是否和自己的相 符,相符了才是发给自己的,因为内核会向所有打开了PF_KEY套接口的进程发送消息。 对于动态SA,一般用户空间都是一个daemon来定时维护,一开始并没有设置算法密钥,需要协商决定,这 时daemon需要知道内核中支持了哪些算法, 因此这个daemon需要向内核登记注册自身,指出能处理的SA 类型,然后内核回应所支持的加密和认证算法的类型,daemon通过IKE协商出SA后将SA信息发送到内核,此 时一般会带生命期, SA到期后会从SADB中删除, 需要重新协商新的SA. 支持结构: struct sadb_supported { u_int16_t sadb_supported_len; /* length of extension + algorithms / 8 */ u_int16_t sadb_supported_exttype; /* SADB_EXT_SUPPORTED_{AUTH, ENCRYPT} */ u_int32_t sadb_supported_reserved; /* reserved for future expansion */ }; /* followed by algorithm list */ 算法结构: struct sadb_alg { u_int8_t sadb_alg_id; /* algorithm ID from Figure 19.8 */ u_int8_t sadb_alg_ivlen; /* IV length, or zero */ u_int16_t sadb_alg_minbits; /* minimum key length */ u_int16_t sadb_alg_maxbits; /* maximum key length */ u_int16_t sadb_alg_reserved; /* reserved for future expansion */ }; 后记: UNP中对PF_KEY的介绍太简单了, 以后将分析pluto从中再学习了.