Linux内核中的IPSEC实现(1)
本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。<br>msn: <a href="mailto:yfydz_no1@hotmail.com" target="_blank">yfydz_no1@hotmail.com</a><br>
来源:<a href="http://yfydz.cublog.cn/" target="_blank">http://yfydz.cublog.cn</a>
<div><br>
1. 前言</div>
<div><br>
在Linux2.6内核中自带了IPSEC的实现,这样就不用象2.4那样打补丁来实现了。该实现包括以下几个部分:
PF_KEY类型套接口,
用来提供和用户层空间进行PF_KEY通信,代码在net/key目录下,前面已经介绍过;安全联盟SA和安全策略SP管理,是使用xfrm库来实现的,
代码在net/xfrm/目录下定义;ESP,AH等协议实现,在net/ipv4(6)下定义;加密认证算法库,在crypto目录下定义,这些算法都
是标准代码了。本系列文章主要描述XFRM库的实现以及在IPV4下相关协议的处理部分, IPV6的忽略。</div>
<div><br>
本文Linux内核代码版本为2.6.19.2。xfrm是内核中变化比较大的部分,每个版本中都有不小的差异,
同时也说明了该模块的不成熟性。</div>
<div>在net/xfrm目录下的各文件大致功能说明如下:</div>
<div>xfrm_state.c: xfrm状态管理<br>
xfrm_policy.c: xfrm策略管理<br>
xfrm_algo.c: 算法管理<br>
xfrm_hash.c: HASH计算函数<br>
xfrm_input.c: 安全路径(sec_path)处理,用于进入的ipsec包<br>
xfrm_user.c: netlink接口的SA和SP管理</div>
<div>在net/ipv4目录下的和ipsec相关各文件大致功能说明如下:</div>
<div>ah4.c: IPV4的AH协议处理<br>
esp4.c: IPV4的ESP协议处理<br>
ipcomp.c: IP压缩协议处理<br>
xfrm4_input: 接收的IPV4的IPSEC包处理<br>
xfrm4_output: 发出的IPV4的IPSEC包处理<br>
xfrm4_state: IPV4的SA处理<br>
xfrm4_policy: IPV4的策略处理<br>
xfrm4_tunnel: IPV4的通道处理<br>
xfrm4_mode_transport: 传输模式<br>
xfrm4_mode_tunnel: 通道模式<br>
xfrm4_mode_beet: BEET模式</div>
<div><br>
2. 数据结构</div>
<div><br>
内核SA的定义用xfrm_state结构定义,SP用xfrm_policy结构定义,在include/net/xfrm.h中定义。</div>
<div><br>
2.1 状态(SA)</div>
<div><br>
xfrm_state状态结构用来描述SA在内核中的具体实现:</div>
<div>struct xfrm_state<br>
{<br>
<br>
// 每个状态结构挂接到三个HASH链表中<br>
struct hlist_node bydst; //
按目的地址HASH<br>
struct hlist_node bysrc; //
按源地址HASH<br>
struct hlist_node byspi; //
按SPI值HASH</div>
<div>
atomic_t refcnt;
// 所有使用计数<br>
spinlock_t lock;
// 状态锁</div>
<div> struct
xfrm_id id; // ID结构,
即目的地址,SPI,协议三元组<br>
struct xfrm_selector sel; //
状态选择子</div>
<div>
u32 genid;
// 状态的标志值, 防止发生碰撞</div>
<div> <br>
struct {<br>
u8 state;<br>
u8 dying;<br>
u32 seq;<br>
} km; // KEY回调管理处理结构参数</div>
<div> <br>
struct {<br>
u32 reqid;
// 请求ID<br>
u8 mode;
// 模式: 传输/通道<br>
u8 replay_window;
// 回放窗口<br>
u8 aalgo,
ealgo, calgo; // 认证,加密,压缩算法ID值<br>
u8 flags;
// 一些标准<br>
u16 family;
// 协议族<br>
xfrm_address_t saddr;
// 源地址<br>
int header_len;
// 添加的协议头长度<br>
int trailer_len;
//<br>
} props; // SA相关参数结构</div>
<div> struct xfrm_lifetime_cfg lft; //
生存时间配置</div>
<div> <br>
struct xfrm_algo *aalg; //
hash算法<br>
struct xfrm_algo *ealg; //
加密算法<br>
struct xfrm_algo *calg; //
压缩算法</div>
<div> <br>
struct xfrm_encap_tmpl *encap;
// NAT-T封装信息</div>
<div> <br>
xfrm_address_t *coaddr;</div>
<div> <br>
struct
xfrm_state *tunnel; // 通道,
实际是另一个SA</div>
<div> <br>
atomic_t tunnel_users;
// 通道的使用数</div>
<div> <br>
struct xfrm_replay_state replay; //
回放检测结构,包含各种序列号掩码等信息</div>
<div> <br>
struct xfrm_replay_state preplay; //
上次的回放记录值</div>
<div> <br>
u32 xflags;
// 标志</div>
<div> <br>
u32 replay_maxage;
// 回放最大时间间隔<br>
u32 replay_maxdiff;
// 回放最大差值</div>
<div> <br>
struct timer_list rtimer; //
回放检测定时器</div>
<div> <br>
struct xfrm_stats stats; //
统计值</div>
<div> struct xfrm_lifetime_cur curlft; //
当前时间计数器<br>
struct
timer_list timer; // SA定时器</div>
<div> <br>
u64 lastused;
// 上次使用时间</div>
<div> <br>
struct
xfrm_type *type; // 协议,
ESP/AH/IPCOMP<br>
struct
xfrm_mode *mode; // 模式,
通道或传输</div>
<div> <br>
struct xfrm_sec_ctx *security;
// 安全上下文, 加密时使用</div>
<div> <br>
void *data;
// 内部数据<br>
};</div>
<div> </div>
<div>2.2 安全策略(SP)</div>
<div><br>
xfrm_policy结构用于描述SP在内核内部的具体实现:</div>
<div>struct xfrm_policy<br>
{<br>
struct xfrm_policy *next; //
下一个策略<br>
struct hlist_node bydst; //
按目的地址HASH的链表<br>
struct hlist_node byidx; //
按索引号HASH的链表</div>
<div> <br>
rwlock_t lock;
// 策略结构锁<br>
atomic_t refcnt;
// 引用次数<br>
struct timer_list timer; //
策略定时器</div>
<div>
u8 type;
// 类型<br>
u32 priority;
// 策略优先级<br>
u32 index;
// 策略索引号<br>
struct xfrm_selector selector;
// 选择子<br>
struct xfrm_lifetime_cfg
lft;
// 策略生命期<br>
struct xfrm_lifetime_cur
curlft; // 当前的生命期数据<br>
struct
dst_entry
*bundles; // 路由链表<br>
__u16 family;
// 协议族<br>
__u8 action;
// 策略动作, 接受/加密/阻塞...<br>
__u8 flags;
// 标志<br>
__u8 dead;
// 策略死亡标志<br>
__u8 xfrm_nr;
// 使用的xfrm_vec的数量<br>
struct xfrm_sec_ctx *security;
// 安全上下文<br>
struct
xfrm_tmpl
xfrm_vec; // 状态模板<br>
};</div>
<div><br>
xfrm模板结构, 用于状态和策略的查询:</div>
<div>struct xfrm_tmpl<br>
{<br>
<br>
// SA三元组, 目的地址, 协议, SOI<br>
struct
xfrm_id id;</div>
<div><br>
// 源地址<br>
xfrm_address_t saddr;</div>
<div>// 请求ID<br>
__u32 reqid;</div>
<div><br>
__u8 mode;</div>
<div><br>
__u8 share;</div>
<div><br>
__u8 optional;</div>
<div><br>
__u32 aalgos;<br>
__u32 ealgos;<br>
__u32 calgos;<br>
};</div>
<div> </div>
<div>2.3 协议结构</div>
<div>对ESP, AH, IPCOMP等协议的描述是通过xfrm_type结构来描述的,
多个协议的封装就是靠多个协议结构形成的链表来实现:</div>
<div>struct xfrm_type<br>
{<br>
char *description;
// 描述字符串<br>
struct
module *owner; // 协议模块<br>
__u8 proto;
// 协议值<br>
__u8 flags;
// 标志<br>
#define XFRM_TYPE_NON_FRAGMENT 1<br>
// 初始化状态<br>
int (*init_state)(struct
xfrm_state *x);<br>
// 析构函数<br>
void (*destructor)(struct
xfrm_state *);<br>
// 数据输入函数<br>
int (*input)(struct
xfrm_state *, struct sk_buff *skb);<br>
// 数据输出函数<br>
int (*output)(struct
xfrm_state *, struct sk_buff *pskb);<br>
// 拒绝函数<br>
int (*reject)(struct
xfrm_state *, struct sk_buff *, struct flowi *);<br>
// 头部偏移<br>
int (*hdr_offset)(struct
xfrm_state *, struct sk_buff *, u8 **);<br>
// 本地地址<br>
xfrm_address_t *(*local_addr)(struct
xfrm_state *, xfrm_address_t *);<br>
// 远程地址<br>
xfrm_address_t *(*remote_addr)(struct
xfrm_state *, xfrm_address_t *);<br>
<br>
// 最大数据报长度<br>
u32 (*get_max_size)(struct
xfrm_state *, int size);<br>
};</div>
<div>具体的协议结构定义如下, 通常只定义初始化,析构,输入和输出四个成员函数:<br>
AH协议定义<br>
<br>
static struct xfrm_type ah_type =<br>
{<br>
.description = "AH4",<br>
.owner =
THIS_MODULE,<br>
.proto
= IPPROTO_AH,<br>
.init_state =
ah_init_state,<br>
.destructor = ah_destroy,<br>
.input =
ah_input,<br>
.output =
ah_output<br>
};</div>
<div>ESP协议定义:<br>
<br>
static struct xfrm_type esp_type =<br>
{<br>
.description = "ESP4",<br>
.owner =
THIS_MODULE,<br>
.proto
= IPPROTO_ESP,<br>
.init_state =
esp_init_state,<br>
.destructor = esp_destroy,<br>
.get_max_size =
esp4_get_max_size,<br>
.input =
esp_input,<br>
.output =
esp_output<br>
};</div>
<div>IP压缩协议定义:<br>
<br>
static struct xfrm_type ipcomp_type = {<br>
.description = "IPCOMP4",<br>
.owner =
THIS_MODULE,<br>
.proto
= IPPROTO_COMP,<br>
.init_state =
ipcomp_init_state,<br>
.destructor =
ipcomp_destroy,<br>
.input =
ipcomp_input,<br>
.output =
ipcomp_output<br>
};</div>
<div>IPIP协议定义:<br>
<br>
static struct xfrm_type ipip_type = {<br>
.description = "IPIP",<br>
.owner =
THIS_MODULE,<br>
.proto
= IPPROTO_IPIP,<br>
.init_state =
ipip_init_state,<br>
.destructor =
ipip_destroy,<br>
.input =
ipip_xfrm_rcv,<br>
.output =
ipip_output<br>
};</div>
<div>2.4 模式结构</div>
<div><br>
模式结构用于描述IPSEC连接描述, 可为通道模式或传输模式两种:</div>
<div>struct xfrm_mode {<br>
// 数据输入函数<br>
int (*input)(struct xfrm_state *x, struct sk_buff
*skb);<br>
// 数据输出函数<br>
int (*output)(struct xfrm_state *x,struct sk_buff
*skb);<br>
// 模块指针<br>
struct module *owner;<br>
// 封装<br>
unsigned int encap;<br>
};</div>
<div>通道模式结构定义:<br>
<br>
static struct xfrm_mode xfrm4_tunnel_mode = {<br>
.input = xfrm4_tunnel_input,<br>
.output = xfrm4_tunnel_output,<br>
.owner = THIS_MODULE,<br>
.encap = XFRM_MODE_TUNNEL,<br>
};</div>
<div>传输模式结构定义:<br>
<br>
static struct xfrm_mode xfrm4_transport_mode = {<br>
.input = xfrm4_transport_input,<br>
.output = xfrm4_transport_output,<br>
.owner = THIS_MODULE,<br>
.encap = XFRM_MODE_TRANSPORT,<br>
};</div>
<div>beet模式, 不知道在哪用<br>
<br>
static struct xfrm_mode xfrm4_beet_mode = {<br>
.input = xfrm4_beet_input,<br>
.output = xfrm4_beet_output,<br>
.owner = THIS_MODULE,<br>
.encap = XFRM_MODE_BEET,<br>
};</div>
<div><br>
2.5 策略的相关协议处理结构</div>
<div><br>
以下结构用于描述具体协议族下的的策略处理:</div>
<div>struct xfrm_policy_afinfo {<br>
// 协议族<br>
unsigned
short family;<br>
// 协议类型<br>
struct
xfrm_type *type_map;<br>
// 模式<br>
struct
xfrm_mode *mode_map;<br>
// 目的操作结构<br>
struct
dst_ops *dst_ops;<br>
// 垃圾搜集<br>
void (*garbage_collect)(void);<br>
// 路由选择<br>
int (*dst_lookup)(struct
xfrm_dst **dst, struct flowi *fl);<br>
// 获取源地址<br>
int (*get_saddr)(xfrm_address_t
*saddr, xfrm_address_t *daddr);<br>
// 查找路由项<br>
struct
dst_entry *(*find_bundle)(struct flowi *fl, struct
xfrm_policy *policy);<br>
// 创建新路由项<br>
int (*bundle_create)(struct
xfrm_policy *policy,<br>
struct xfrm_state **xfrm,<br>
int nx,<br>
struct flowi *fl,<br>
struct dst_entry **dst_p);<br>
// 解码会话<br>
void (*decode_session)(struct
sk_buff *skb,<br>
struct flowi *fl);<br>
};</div>
<div><br>
IPV4的策略协议相关处理结构定义如下:</div>
<div><br>
static struct xfrm_policy_afinfo xfrm4_policy_afinfo = {<br>
.family =
AF_INET,<br>
.dst_ops
= &xfrm4_dst_ops,<br>
.dst_lookup
= xfrm4_dst_lookup,<br>
.get_saddr
= xfrm4_get_saddr,<br>
.find_bundle =
__xfrm4_find_bundle,<br>
.bundle_create
= __xfrm4_bundle_create,<br>
.decode_session
= _decode_session4,</div>
<div><br>
2.5 状态的相关协议处理结构</div>
<div>以下结构用于描述具体协议族下的的状态处理:</div>
<div>struct xfrm_state_afinfo {<br>
// 协议族<br>
unsigned
short family;<br>
// 初始化标志<br>
int (*init_flags)(struct
xfrm_state *x);<br>
// 初始化模板选择<br>
void (*init_tempsel)(struct
xfrm_state *x, struct flowi *fl,<br>
struct
xfrm_tmpl *tmpl,<br>
xfrm_address_t
*daddr, xfrm_address_t *saddr);<br>
// 模板排序<br>
int (*tmpl_sort)(struct
xfrm_tmpl **dst, struct xfrm_tmpl **src, int n);<br>
// 状态排序<br>
int (*state_sort)(struct
xfrm_state **dst, struct xfrm_state **src, int n);<br>
};</div>
<div>IPV4的状态相关协议处理结构</div>
<div>static struct xfrm_state_afinfo xfrm4_state_afinfo = {<br>
.family =
AF_INET,<br>
.init_flags =
xfrm4_init_flags,<br>
.init_tempsel =
__xfrm4_init_tempsel,<br>
};</div>
<div><br>
2.6 回调通知信息结构</div>
<div>struct xfrm_mgr<br>
{<br>
struct list_head list;<br>
char *id;<br>
// 状态通知<br>
int (*notify)(struct
xfrm_state *x, struct km_event *c);<br>
// 获取, 如获取SA<br>
int (*acquire)(struct
xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp, int
dir);<br>
// 编译策略<br>
struct
xfrm_policy *(*compile_policy)(struct sock *sk,
int opt, u8 *data, int len, int *dir);<br>
// 映射<br>
int (*new_mapping)(struct
xfrm_state *x, xfrm_address_t *ipaddr, u16 sport);<br>
// 策略通知<br>
int (*notify_policy)(struct
xfrm_policy *x, int dir, struct km_event *c);<br>
// 报告<br>
int (*report)(u8
proto, struct xfrm_selector *sel, xfrm_address_t *addr);<br>
};</div>
<div><br>
在net/key/pf_key.c中定义了pkeyv2_mgr结构:</div>
<div>static struct xfrm_mgr pfkeyv2_mgr =<br>
{<br>
.id =
"pfkeyv2",<br>
.notify =
pfkey_send_notify,<br>
.acquire =
pfkey_send_acquire,<br>
.compile_policy =
pfkey_compile_policy,<br>
.new_mapping =
pfkey_send_new_mapping,<br>
.notify_policy =
pfkey_send_policy_notify,<br>
};</div>
<div><br>
3. 初始化</div>
<div><br>
<br>
// xfrm初始化函数包括状态, 策略和输入处理的三初始化函数<br>
// xfrm是不支持模块方式的<br>
void __init xfrm_init(void)<br>
{<br>
xfrm_state_init();<br>
xfrm_policy_init();<br>
xfrm_input_init();<br>
}</div>
<div><br>
3.1 xfrm状态初始化</div>
<div><br>
void __init xfrm_state_init(void)<br>
{<br>
unsigned int sz;<br>
// 初始HASH表不大, 每个HASH中初始化为8个链表, 但随着状态数量的增加<br>
// 会动态增加HASH表数量<br>
sz = sizeof(struct hlist_head) * 8;</div>
<div>// 建立3组HASH, 分别按SA的源地址, 目的地址和SPI值<br>
xfrm_state_bydst = xfrm_hash_alloc(sz);<br>
xfrm_state_bysrc = xfrm_hash_alloc(sz);<br>
xfrm_state_byspi = xfrm_hash_alloc(sz);<br>
if (!xfrm_state_bydst || !xfrm_state_bysrc ||
!xfrm_state_byspi)<br>
panic("XFRM: Cannot allocate
bydst/bysrc/byspi hashes.");</div>
<div>// xfrm_state_hmask初始值为=7, 计算出的HASH值与该值与来得到链表号<br>
xfrm_state_hmask = ((sz / sizeof(struct
hlist_head)) - 1);<br>
// 初始化工作队列work_queue, 完成对状态垃圾的搜集和释放<br>
INIT_WORK(&xfrm_state_gc_work,
xfrm_state_gc_task, NULL);<br>
}</div>
<div><br>
3.2 策略初始化</div>
<div><br>
static void __init xfrm_policy_init(void)<br>
{<br>
unsigned int hmask, sz;<br>
int dir;</div>
<div>// 建立一个内核cache, 用于分配xfrm_dst结构()<br>
xfrm_dst_cache =
kmem_cache_create("xfrm_dst_cache",<br>
sizeof(struct xfrm_dst),<br>
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,<br>
NULL, NULL);<br>
// 分配状态HASH表, 初始是8个HASH链表,以后随着策略数量的增加<br>
// 会动态增加HASH表的数量<br>
hmask = 8 - 1;<br>
sz = (hmask+1) * sizeof(struct hlist_head);<br>
// 该HASH表是按策略的index参数进行索引的<br>
xfrm_policy_byidx = xfrm_hash_alloc(sz);<br>
xfrm_idx_hmask = hmask;<br>
if (!xfrm_policy_byidx)<br>
panic("XFRM: failed to allocate
byidx hash\n");</div>
<div>// 输入, 输出, 转发三个处理点, 双向<br>
for (dir = 0; dir <
XFRM_POLICY_MAX * 2; dir++) {<br>
struct xfrm_policy_hash
*htab;</div>
<div>// 初始化inexact链表头, inexact处理选择子相关长度不是标准值的一些特别策略<br>
INIT_HLIST_HEAD(&xfrm_policy_inexact);</div>
<div>// 分配按地址HASH的HASH表<br>
htab =
&xfrm_policy_bydst;<br>
htab->table =
xfrm_hash_alloc(sz);<br>
htab->hmask =
hmask;<br>
if
(!htab->table)<br>
panic("XFRM:
failed to allocate bydst hash\n");<br>
}<br>
// 初始化策略垃圾搜集的工作队列, 完成对策略垃圾的搜集和释放<br>
INIT_WORK(&xfrm_policy_gc_work,
xfrm_policy_gc_task, NULL);<br>
// 登记网卡通知<br>
register_netdevice_notifier(&xfrm_dev_notifier);<br>
}</div>
<div>xfrm的网卡通知回调结构<br>
static struct notifier_block xfrm_dev_notifier = {<br>
xfrm_dev_event,<br>
NULL,<br>
0<br>
};</div>
<div>// 网卡通知回调函数<br>
static int xfrm_dev_event(struct notifier_block *this, unsigned
long event, void *ptr)<br>
{<br>
switch (event) {<br>
// 如果网卡down掉的话, 清除相关的所有的xfrm路由项<br>
case NETDEV_DOWN:<br>
xfrm_flush_bundles();<br>
}<br>
return NOTIFY_DONE;<br>
}</div>
<div>// 清除相关的所有的xfrm路由项<br>
static int xfrm_flush_bundles(void)<br>
{<br>
// 将不用的路由项删除<br>
xfrm_prune_bundles(stale_bundle);<br>
return 0;<br>
}</div>
<div> </div>
<div>3.3 输入初始化</div>
<div><br>
void __init xfrm_input_init(void)<br>
{<br>
// 建立一个内核cache, 用于分配sec_path结构(安全路径)<br>
secpath_cachep =
kmem_cache_create("secpath_cache",<br>
sizeof(struct sec_path),<br>
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,<br>
NULL, NULL);<br>
}</div>
<div>struct sec_path结构是对输入的加密包进行层层解包的处理, 在sk_buff中有该结构的指针sp,
如果sp非空表示这是个IPSEC解密后的包。</div>
<div> </div>
<div>...... 待续 ......</div>
页:
[1]