日期:2014-05-16 浏览次数:20718 次
1. 前言 在Linux2.6内核中自带了PF_KEY协议族的实现,这样就不用象2.4那样打补丁来实现了。内核中PF_KEY实现要完成的功能是实现维护内核的安全联盟(SA)和安全策略(SP)数据库, 以及和用户空间的接口。 以下内核代码版本为2.6.19.2, PF_KEY相关代码在net/key/目录下,定义了内核中PF_KEY与用户空间的接口,这个接口是RFC定义的,因此各种实现都基本类似;但具体关于SA和SP的内部的实现和管理则是与实现相关的,各种实现各自不同,在linux内核是使用xfrm库来实现的,代码在net/xfrm/目录下定义。 2. 数据结构 关于SA和SP的数据结构已经在RFC2367中定义, 头文件为include/linux/pfkeyv2.h, 这些是用户空间和内核空间共享的,只是作为接口的数据结构;而内核中具体使用的数据结构为xfrm定义的结构,在include/net/xfrm.h中定义。 2.1 PF_KEY类型的sock struct pfkey_sock { /* struct sock must be the first member of struct pfkey_sock */ struct sock sk; // 比普通sock添加两个参数 // 是否进行登记 int registered; // 是否是混杂模式 int promisc; }; 2.2 状态(SA) xfrm状态用来描述SA在内核中的具体实现: struct xfrm_state { /* Note: bydst is re-used during gc */ // 每个状态结构挂接到三个HASH链表中 struct hlist_node bydst; // 按目的地址HASH struct hlist_node bysrc; // 按源地址HASH struct hlist_node byspi; // 按SPI值HASH atomic_t refcnt; // 所有使用计数 spinlock_t lock; // 状态锁 struct xfrm_id id; // ID struct xfrm_selector sel; // 状态选择子 u32 genid; /* Key manger bits */ struct { u8 state; u8 dying; u32 seq; } km; /* Parameters of this state. */ struct { u32 reqid; u8 mode; u8 replay_window; u8 aalgo, ealgo, calgo; u8 flags; u16 family; xfrm_address_t saddr; int header_len; int trailer_len; } props; struct xfrm_lifetime_cfg lft; // 生存时间 /* Data for transformer */ struct xfrm_algo *aalg; // hash算法 struct xfrm_algo *ealg; // 加密算法 struct xfrm_algo *calg; // 压缩算法 /* Data for encapsulator */ struct xfrm_encap_tmpl *encap; // NAT-T封装信息 /* Data for care-of address */ xfrm_address_t *coaddr; /* IPComp needs an IPIP tunnel for handling uncompressed packets */ struct xfrm_state *tunnel; /* If a tunnel, number of users + 1 */ atomic_t tunnel_users; /* State for replay detection */ struct xfrm_replay_state replay; /* Replay detection state at the time we sent the last notification */ struct xfrm_replay_state preplay; /* internal flag that only holds state for delayed aevent at the * moment */ u32 xflags; /* Replay detection notification settings */ u32 replay_maxage; u32 replay_maxdiff; /* Replay detection notification timer */ struct timer_list rtimer; /* Statistics */ struct xfrm_stats stats; struct xfrm_lifetime_cur curlft; struct timer_list timer; /* Last used time */ u64 lastused; /* Reference to data common to all the instances of this * transformer. */ struct xfrm_type *type; struct xfrm_mode *mode; /* Security context */ struct xfrm_sec_ctx *security; /* Private data of this transformer, format is opaque, * interpreted by xfrm_type methods. */ void *data; }; 2.3 策略(SP) struct xfrm_policy { struct xfrm_policy *next; // 下一个策略 struct hlist_node bydst; // 按目的地址HASH的链表 struct hlist_node byidx; // 按索引号HASH的链表 /* This lock only affects elements except for entry. */ rwlock_t lock; atomic_t refcnt; struct timer_list timer; u8 type; u32 priority; u32 index; struct xfrm_selector selector; struct xfrm_lifetime_cfg lft; struct xfrm_lifetime_cur curlft; struct dst_entry *bundles; __u16 family; __u8 action; __u8 flags; __u8 dead; __u8 xfrm_nr; struct xfrm_sec_ctx *security; struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH]; }; 2.4 事件 struct km_event { union { u32 hard; u32 proto; u32 byid; u32 aevent; u32 type; } data; u32 seq; u32 pid; u32 event; }; 3. 初始化 /* net/key/af_key.c */ static int __init ipsec_pfkey_init(void) { // 登记key_proto结构, 该结构定义如下: // static struct proto key_proto = { // .name = "KEY", // .owner = THIS_MODULE, // .obj_size = sizeof(struct pfkey_sock), //}; // 最后一个参数为0, 表示不进行slab的分配, 只是简单的将key_proto结构 // 挂接到系统的网络协议链表中,这个结构最主要是告知了pfkey sock结构的大小 int err = proto_register(&key_proto, 0); if (err != 0) goto out; // 登记pfkey协议族的的操作结构 err = sock_register(