日期:2014-05-16 浏览次数:20841 次
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(