详细设计说明书示例
维修打印机-
1
.引言
编写目的
本说明书提供了
freeswan
各个模块部件的说明,以供编码人员具体实现及今后的<
/p>
维护工作。
2
.总体设计
设计原则
在确定目标系统的过程中,主要遵循了以下几个原则:
目标系统基本上完整地实现
IPSe
c
协议族,完全支持
VPN
的要求;<
/p>
目标系统的服务器端一定要建立在具
有自主版权的内核操作系统之上;
目标系统的客户端使用方便、界面友好、配置和管理简单灵活。
软件结构
该软件由如下几个模块组成:
KLIPS
模块――
实现对进入或外出
IP
包的安全处理,如:加密、认证
等(运行在内核
空间)
Pluto
模块――
实现
IKE
协议,完成安全联盟的协商(运行在用户空
间)
PF_KEY
模块――
实现
pfkey2
协议,完成上述两个模块间关于<
/p>
SA
的通信
3
.程序描述
源代码文件组成
本程序由两大模块组
成,一部分是
klips
,它运行在操作系统内核空间,主要负
责安全
联盟和密钥的管理工作,以及对数据报的加密、解密的处理工作;一部分是
pluto
,它是一
个运行在用户空间的守护
进程,
主要负责安全联盟的协商工作。
下面分别是它们的文件组
成:
源文件目录
|―――freeswan
|
――
kl
ips
|
p>
――
libdes
|
――
pluto
|
――
utils
KLIPS
(内核
< br>IPsec
)详细设计
--―――
klips
ipsec
的核心实现模块
|
――
net
|
――
ipsec
|
――
登记模块,并初始化
数据包的处理并发送模块
|
――
ipsec_tunnel.
|
――
|
――
|
――
|
――
|
――
|
――
|
――
|
――
|
――
|
――
|<
/p>
――
utils
|
――
|
――
|
――
|
――
|
――
数据包接收并处理模块
管理
SA
的模块
sha1
实现模块,由改编
实现模块
路由表的
< br>radix
数的实现模块
对上个文件的改编
实现
PF_KEY2
协议的模块
对上个文件的改编
用户操作
eroute
表的模块
用户操作
SA
库的模块
同上
用户操作虚接口的模块
登记及初始化模块
概要说明
功能
向内核系统登记几个
proc
文件,以便于向内核空间中查询安全联盟和
eoute
表,以及
虚接口的状况;
初始化
SA
数据库(
< br>tdb
链)
;
初始化
SPDB
数据库(
er
oute
表)
;
初始化
pf_key
(
PF_KE
Y
套接口)
;
模块所涉及的文件
:
:
:
:
int
ipsec_init(void)
int
ipsec_tdbinit(void)
int
ipsec_radijinit(void)
int
pfkey_init(void)
变量说明
proc
文件结构
< br>将下列结构登记到内核系统中,则内核就可以通过
proc
文件系统向应用程序提供一个
安全的界面来存取如
SA
、
eroute
表等资料。
< br>
struct proc_dir_entry ipsec_eroute
;
struct proc_dir_entry
ipsec_spi
struct
proc_dir_entry ipsec_spigrp
struct proc_dir_entry ipsec_tncfg
;
struct proc_dir_entry
ipsec_spinew
struct
proc_dir_entry ipsec_klipsdebug
notifier_block
结构
struct notifier_block
结构是在
include/linux/
里面的:
struct notifier_block
{
int
(*notifier_call)(struct notifier_block *self,
unsigned long, void *);
struct notifier_block *next;
int priority;
};
而
re
gister_netdevice_notifier
函数在
net/core/
里面,是这样的:
int register_netdevice_notifier(struct
notifier_block *nb)
{
return
notifier_chain_register(&netdev_chain,
nb);
}
而
notifier_chain_register
函数在
include/linux/
里面,是这样的:
extern __inline__ int
notifier_chain_register(
struct notifier_block **list, struct
notifier_block *n)
{
while(*list)
{
if(n->priority
> (*list)->priority)
break;
list=
&((*list)->next);
}
n->next =
*list;
*list=n;
return 0;
}
显然就是根据每个
block
的优先级把这个
block
排列在一个
block
的链表里面,在
notifier_chain_register
函数里面我们可以发现这个
链表是
netdev_chain
。实际上这个链表的
作用就是在每个
interface
打开,关闭
状态改变或者外界调用相应的
ioctl
的时候通知这个链
p>
表上面的所有相关的设备,而每一个协议都调用
register_
netdevice_notifier
注册了一个
netde
v_notifier
的结构体,这样就可以在
interfa
ce
改变的时候得到通知了
(
通过调用
每个
notifier_call
函数
)
。
inet_protocol
结构
struct inet_protocol ah_protocol
=
{
ipsec_rcv,
NULL,
0,
/*
AH handler
,
定义此协议处理函数
*/
/* TUNNEL error
control
,错误处理函数
*/
/* next
*/
IPPROTO_AH,
0,
/* protocol ID */
/*
copy */
/* data
*/
/* name */
NULL,
};
ips
ec_rcv
函数是用来接收数据的
callback
函数,第二个是错误处理函数,其它的
copy
是用
来协议共享的,这个以后再说,
data
< br>当然就是这个结构体的私有数据了。
struct inet_protocol esp_protocol
同上;
i
net_add_protocol
函数在
net/ipv4<
/p>
/
里实现:
void inet_add_protocol(struct
inet_protocol *prot)
{
unsigned char
hash;
struct inet_protocol
*p2;
hash =
prot->protocol & (MAX_INET_PROTOS - 1);
prot ->next =
inet_protos[hash];
inet_protos[hash] = prot;
prot->copy = 0;
p2 = (struct inet_protocol *)
prot->next;
while(p2 !=
NULL)
{
if (p2->protocol == prot->protocol)
{
prot->copy = 1;
break;
}
p2 = (struct
inet_protocol *) p2->next;
}
}
p>
这个函数是生成了一个
hash
表,然后每
个
hash
表项都是一个链表头,然后通过这个
hash
表加链表的方式访问每个协议结构体。
函数说明
登记及初始化模块包括以下一些函数:
init_modules()
,
<
/p>
ipsec_init()
,
clean
up_module()
,
ipsec_cleanup()
,
ipsec_eroute_get_info()
,
ipse
c_spi_get_info()
,
ipsec_spigr
p_get_info()
,
ips
ec_tncfg_get_info()
,
ipsec_ve
rsion_get_info()
,
ipsec_spi_g
et_new()
int
init_module(void)
装载
< br>ipsec
时进行登记及初始化工作。
无
目的:
参数:
返回值:
0
――
初始化成功,非
0
值
――
初始化未成功
算法描述:
调用
ipsec_init()
。
int cleanup_module(void)
卸载
ipsec
进行清除工作。
无
目的:
参数:
返回值:
0
――
初始化成功,非
0
值――初始化未成功
算法描述:
调用
ipsec_cleanup()
。
int
ipsec_int(void)
装载
ipsec
时进行登记及初始化工作。
。
无
目的:
参数:
返回值:
0
――
初始化成功,非
0
值――初始化未成功
算法描述:
1
.将定义好的几个
proc_dir_entry
结构注册到系统中,如:
proc_regi
ster(proc_net,&ipsec_eroute);/*PROC_FS_21*/
或
pro
c_register_dynamic(&proc_net,&ipsec_eroute);
或
pro
c_net_create(“ipsec_eroute”,0,ipsec_eroute_get_inf
o)
;
proc_register
为系统调用,在
fs/proc/
中实
现,主要就是在
proc_net
对应的目录下面生成每
个协议的子目录。用户可以通过访问
/proc/net
目录下面的相应目录得到相关的资料。
2
.调用
ipsec_tdbinit()
函数初
始化
SA
数据库,此函数在文件中实现;
3
.调用
ipsec_radij
init()
函数初始化
SPD
数据库
,此函数在文件中实现;
4
.调用<
/p>
pfkey_init()
函数初始化
P
FKEY
,此函数在文件中实现;
5
.
调
用
reg
ister_netdevice_notifier(&ipsec_dev_notifier)
函
数
向
系
统
中
注
册
已
定
义
的
ipsec_dev_notifier
结构,
registe
r_netdevice_ntifier()
为系统调用;
6
.
调用
in
et_add_protocol(&esp_protocol)
和
< br>inet_add_protocol(&ah_protocol)
函数向系统
中注
册
ESP
协议和
< br>AH
协议,
inet_add_protocol()<
/p>
为系统调用;
7
.
调用
ipsec_tunnel_init_device
s()
函数,
登记并初始化
ipsec
虚接口,
此函数定义在文件中。
int
ipsec_cleanup(void)
卸载
ipsec
进行清除工作。
无
目的:
参数:
返回值:
0
――
清除成功,非
< br>0
值――清除未成功
算法描述:
1
.调用
ipsec_tunnel_cleanup_de
vice(void)
函数,清除向系统登记的
ipsec
p>
虚接口,此函数在
中实现;
2
.调用
inet_del_protocol(&
ah_protocol)
和
inet_del_protoc
ol(&esp_protocol)
清除掉在系统中
注册的<
/p>
ESP
协议和
AH
协议;
3
.调用系统调用
unregister_netdevice_notifier(&ipsec_dev_no
tifier)
清除掉系统中注册的
ipsec_dev_no
tifier
;
4
< br>.调用
ipsec_tdbcleanup(0)
清除系
统中的
SA
数据库,此函数在中文件实现;
5
.调用
ipsec_radi
jcleanup()
清除系统中的
SPD
数据库,此函数在文件中实现;
6
.调用
pfkey_cleanup()
做
< br>pfkey
清除工作;
7
p>
.调用系统调用
proc_net_unregister()
p>
清除
freeswan
在系统中登记的各个
proc
文件。
虚接口模块
概要说明
功能
为了在不改变现有的操作系统的
网络协议栈的状况下,更好地将
IPsec
嵌入,本程序采
p>
用了虚接口的概念。实现中,将创建
4
个<
/p>
ipsec
虚接口,可以将虚接口绑定在物理接口
上。对于从
tcp/udp
协议层传下来的数据,将首
先查询
eroute
表,根据
erou
te
表项决
定将数据包发往哪一个接口,
物理接口与虚接口将被视为一致的。
此时,
如果数据包发
p>
往虚接口,则调用函数进行处理。
(该程序类似于网卡驱动程序的编
写)
构成文件
变量说明
device
结构
虚接口定义为
struct
device
结构,如:
static struct device dev_ipsec0 =
{
0,
0,
0,
0,
/* name */
/*
recv memory end */
/* recv
memory start */
/* memory
end */
/* memory start
*/
0x0,
0,
/* base I/O address
*/
/* IRQ */
/*
flags */
/* next device
*/
0, 0, 0,
NULL,
ipsec_tunnel_probe
/* setup
*/
};
ipsecpriv
结构
struct ipsecpriv
{
struct
sk_buff_head sendq;
struct
device *dev;
struct
wait_queue *wait_queue;
char
locked;
int
(*hard_start_xmit) (struct sk_buff
*skb, struct device *dev);
int
(*hard_header) (struct sk_buff
*skb,
struct device
*dev,
unsigned short
type,
void
*daddr,
void
*saddr,
unsigned
len);
#ifdef
NET_21
int
(*rebuild_header)(struct sk_buff
*skb);
#else /* NET_21
*/
int
(*rebuild_header)(void *buff, struct
device *dev,
unsigned long
raddr, struct sk_buff *skb);
#endif /* NET_21 */
int
(*set_mac_address)(struct device *dev,
void *addr);
#ifndef
NET_21
void
(*header_cache_bind)(struct hh_cache **hhp, struct
device *dev,
unsigned short
htype, __u32 daddr);
#endif
/* !NET_21 */
void
(*header_cache_update)(struct hh_cache *hh, struct
device *dev, unsigned char *
struct
enet_statistics *(*get_stats)(struct device
*dev);
struct
enet_statistics mystats;
int
mtu;
/* What is the desired MTU
*/
};
haddr);
函数说明
int
ipsec_tunnel_init_devices(void)
目的:
登记
ipsec
虚接口。
参数:
无
返回值:
0
――
登
记成功,非
0
值――登记未成功
算法描述:
调用系统调用
register_netdev(&dev_ipsec0~3)
p>
,向系统登记
4
个
ipsec
虚接口。
int ipsec_tunnel_init(struct device
*dev)
初始化
ipsec
虚接口,完成
device
中变量的初始化和
系统资源的申请。
0
――
清除成功,非
< br>0
值――清除未成功
目的:
参数:
返回值:
算法描述:
1
.填充
device
结构中的几个
函数,如:
a)dev->open
= ipsec_tunnel_open;
b)dev->stop
=
ipsec_tunnel_stop;
c)dev->hard_start_xmit
d)dev->get_stats
=
ipsec_tunnel_start_xmit;
=
ipsec_tunnel_get_stats;
2
.给
dev
配空间,
dev->priv = kmalloc(sizeof(struct
ipsecpriv),GFP_KERNEL);
3
.初始化
dev
结构:
skb_queue_head_init(&dev->buffs[i]);
<
/p>
4
.填充
dev
结构的其它值,如:
dev->set_mac_address =
NULL
等等。
int ipsec_tunnel_attach (struct device*
tndev, struct ipsecpriv* prv,struct device
*dev)
目的:
将某个虚接口绑定到指定的物理接口上。
参数:
返回值:
0
――
绑定成功,非
< br>0
值――绑定未成功
算法描述:
int ipsec_open(struct
device *dev)
目的:
参数:
要
open
的
device
返回值:
0
――
o
pen
成功,非
0
值――
open
未成功
算法描述:
此方法在网络设备驱动程序里是网络设备被激活的时候被调用(即设备状态由
down
->up
)
。
驱动程序作为一个模块被装入:
如果虚接口尚未绑定到物理接口,
返回错误信息;
否则
调用
MOD_
INC_USE_COUNT
宏,以防止模块卸载是设备处于打开状态。
int
ipsec_tunnel_start_xmit(struct sk_buff *skb,struct
device *dev)
目的:
假定此函数由
dev_queue_xmit()
函数调用,主要负责发送从
tcp/udp
协议层传
来的
数据包
参数:
返回值:
由
dev_queue_xmit()
函数填充好的
skb
,及要发往的网络接口
0
――
open
成功,非
0
值――
open
未成功
算法描述:
1
.
skb, dev
有效吗
有效继续,
无效返回;
prv =
dev->priv
获取
ipsec
接口私有数据;
若
prv
为空,返回;
获取系列参数:物理接口参数
physdev, physmtu,
stats
;
2
.
如果需
要,拷贝
skb
:
Ifdef
NET_21, then
skb_cloned(skb)
;
3
.
获取<
/p>
Ip
头
iph
,
判断该包是否是
IPV4
,若不是则丢弃;
4
.
计算硬件头长度(
hard_header_len
)
;
5
.
将
p>
ip
包的
ttl
减
小,并计算校验和。
6
.
填充查
找键键值,根据键值查找
eroute
表,获取
eroute
,若找到,取出
SA
,即
outgonging_said
;
< br>
7
.
判断此
IP
包是否是
IKE
协商包(
UDP port
500
)
,若是,则跳出;
8
.
进入封
装处理大循环(几乎一切处理都由
outgoing_said
决定,一个
said
对应一个或多
个<
/p>
tdb
(通道描述块)
,根据每个
tdb
对其进行处理)
:
(1)
check for DROP or
missing eroute
(2)
check for REJECT eroute
(3)
check for PASS
eroute
(4)
check for HOLD eroute
(5)
check for TRAP
eroute, signal PF_KEY
, swap to HOLD
eroute
(6)
acquire lock for walking tdb
chain
(7)
calculate headroom required for
chain
1)
check if SA is in larval, drop
2)
check if
SA is dead, drop
3)
check if replay overflowed, expire SA
4)
check if
lifetime counters have overflowed, expire SA
5)
switch on
protocol type, to calculate headroom size.
I.
if ESP
switch on protocol type to calculate tailroom
size.
(8)
alculate mtudiff, send ICMP fragment
needed. Mark ``note2''
(9)
ack MSS if desired
(10) copy upper (layer 2) header to
safety if it was present
(11) check if data fits in existing
skb, else expand.
(12)
apply grouped transforms
1)
apply disaster of #ifdefs.
2)
switch by protocol
type, calculate headroom for this stage
I.
if
ESP
, then switch by cipher get headroom
II.
if
ESP
, then switch by hash to get
tailroom
3)
double check (not in NDEBUG) if there
is enough headroom
4)
push the data ahead
5)
double check (not in
NDEBUG) if there is enough tailroom
6)
extend the data
behind
7)
see if packet has become too long
(bigger than 64K)
8)
finally move the plaintext as
appropriate
9)
switch on protocol type
10) case: ESP
I.
switch on cipher type, prepare IV
II.
prepare
self-describing padding
III.
switch on cipher
type, do encryption
IV.
switch on cipher type, update IV
V.
switch
on hash type, do authentication
11) case: AH
I.
prep replay info, headroom
II.
switch on hash
type, do authentication
12)
case: IPIP
, apply encap
13) case: IPCOMP
I.
call skb_compress
II.
do some
debugging
14) recalculate
header checksum
⒀
lookup eroute by new outer
header, if we found something and the src/dst have
changed
9
.
end
ICMP if packet has become too big
10
.
re-apply link layer header if there was
one.
11
.
attempt to re-route the packet
12
.
drop packet if new route leads to us
again.
13
.
do connection tracking
14
.
do netfilter localout output call
15
.
call ip_send or IP_SEND depending on
kernel version
⑴.
取得一些初始值
,
如
dst, src, iphlen, pyldsz,
⑵.
接下来是一系列合法性和安全性检查,对不合理部分有两种处理方法:
1
)
不进行安全处理,直接从物理接口上发送并返回;
2
)
丢弃数据包,返回。
⑶.
有
eroute
吗
没有
,则从
physdev
发送数据包并返回,有则继续;
⑷.
< br>若指定隧道模式,却找不到
spi
,不做处理,按
1)
发送,返回;
⑸.
根据
said
取得
tdbp
链,和
sa_len
,若
tdbp<
/p>
链为空,报错返回;
⑹.
进入
tdb
处理循环,求出
ipsec
处理所需的
headroom
和
< br>tailroom
;
对
tdbp
链中每一个
tdb
< br>进行如下处理:
①
<
/p>
大量的合法性判断,包括
tdb
状态是否
对,
SA
是否过时,
PFKEYv2<
/p>
处理等;
②
根据
tdbp->
计算
headroom
和
tailroom
。方法是,根据不同而算法不同:
IPPROTO_AH: headroom += sizeof(struct
ah);
IPPROTO_ESP:
Ⅰ
.tdbp->tdb_enca
lg
(加密算法)
ESP_DES
:
headroom += sizeof(struct
esp);
ESP_3DES
:
headroom += sizeof(struct
esp);
ESP_NULL
:
headroom += offsetof(struct esp,
esp_iv);
default:
丢弃包。
Ⅱ
.tdbp->tdb_autoalg
(认证算法)
AH_MD5: tailroom += AHHMAC_HASHLEN;
AH_SHA: tailroom +=
AHHMAC_HASHLEN;
AH_NONE:
NOP
(不处理)
;
default:
不对,丢弃包。
Ⅲ
.
计算:
(
数据包要是
16
()字节的倍数,不然加空补齐。
tailroom += ((8 - ((pyldsz + 2 *
sizeof(unsigned char)) % 8)) % 8) + 2;
IPPROTO_IPIP:
headroom += sizeof(struct
iphdr);
default:
出错,丢弃。
最后,对链表中每一个
tdb
求出的
headroom
、
tailroom
求和得出
max_headroom
、
max_tailroo
m
,
pyldsz
也相应改变(加上<
/p>
headroom, tailroom
)
。
(
Ln
1016
)
⑺.
求出
tot_headroom,
tot_tailroom,
mtu_diff
;若
mtu_diff>0
,说明
< br>prv->mtu
计算不
合适,重新计算;
⑻.
调整
mss
;
⑼.
hard_h
eader_stripped
处理;
(
Ln 1077
)
⑽.
!
。原
skb
空间够用吗不够就重新分配一个
skb
并进行
extend_copy
;
⑾.
进入
tdb
链循环,进行真正的
ipsec
安全处理。
①
定义变量并赋初值;
②
根据
tdbp->
确定
headroom, tailroom
;与
(6)
的处理类似。
③
处理
skb
,移动数据指针
(
skb_push, skb_put
函数
)
;
④
ip
头前移;
⑤
根据不同的协议类型进行不同的处理:
switch(tdbp->
IPPROTO_ESP:
填写
espp
(
spi, rpl,...
)
;
求出
iv[0], iv[1] (
初
始化向量
)
;
求出
idat, ilen
(
内部数据区域
)
要加密的数据地址及长度;
求出
pad, padlen.
(为
了认证)
;
(
pad
< br>前面两个字节分别存放
pad
长度和前
< br>iph->protocol.
由
tdbp->tdb_encalg
决定调用加密算法:
ESP_DES:
des_cbc_encrypt(idat,idat,
ilen,(caddr_t)tdbp->tdb_key_e,(caddr_t)iv,
1);
ESP_3DES:
des_ede3_cbc_encrypt(idat, idat,
ilen,(caddr_t)(&((struct
des_eks*)(tdbp->tdb_key_e))[0]),
(caddr_t)(&((struct
des_eks*)(tdbp->tdb_key_e))[1]),
(caddr_t)(&((struct
des_eks*)(tdbp->tdb_key_e))[2]),
(caddr_t)iv, 1);
由
tdbp->tdb_encalg
决定如何进行认证:
p>
AH_MD5
:
AH_SHA
:
IPPROTO_AH
:
填写
ahp
;
...
由
tdbp->tdb_encalg
决定如何进行认证:
AH_MD5
:
AH_SHA
:
IPPROTO_IPIP:
构造
IP
头;
⑥
计算
IP
头校验,调整
skb
内部参数
,
tdb
循环处理;
⑿.
取出源、目的地址,再次求
er;
⒀.
还要继续循环吗
⒁.
while(/*((orgdst != newdst) || (orgsrc
!= newsrc))*/(orgedst !=
&&
&&er);
⒂.
硬件头处理;
⒃.
求物理接口,寻路由;
⒄.
发送。
ip_send(skb)
int
ipsec_tunnel_detach(struct device *dev,struct
ipsecpriv *prv)
目的:
将某个绑定了的虚接口解除绑定。
参数:
返回值:
0
――成功,非
0
值――未成功
算法描述:
将
prv
的各个值清空
int ipsec_tunnel_clear(void)
目的:
清除所有的绑定虚接口。
参数:
无
返回值:
0
――成功,非
0
< br>值――未成功
算法描述:
<
/p>
将
prv
的各个值清空
< br>
int
ipsec_tunnel_cleanup_devices(void)
目的:
清除
4
个注册的
ipsec
虚接口。
参数:
无
返回值:
0
――
清
除成功,非
0
值――清除未成功
算法描述:
1
.调用系统调用
unregister_netdev(&
dev_ipsec0~3)
清除虚拟接口;
2
.调用系统调用
kfree_s(dev_ipse
c0~,sizeof(struct
ipsecpriv))
释放为虚接口分配的空间。
接收处理模块
概要说明
功能
主要负责处理接收到的
ipsec
数据包。
构成文件
文件
流程
如图
3
-
1
所示。
传输层处理
正
常包处理
包处理
重组外出包
查找
SA
库
加认证
加密
进入策略处理
根据
SA
进行处理
检查
SA
状
IPSec
处理
IP
路由
态、生存期
检查
SA
状态、重
播窗口、生存期
根据
SA
进行处理
IPSec
处理
查找
SA
库
解密
认证
分片重组处理
本地包
绕过
应用
丢弃
重组进入包
转发到本网
IP
路由
IP
分片处理
关内的包
策略处理
链路层接收包
链路层发送包
正常包处理
包处理
策略库查找
物理接口驱动
物理接口驱动
虚接口驱动
虚接口驱动
链路层
图
3.1
传统
IPSec
网关接收和转发包示意图
函数说明
int ipsec_rcv(struct sk_buff
*skb,unsighed short xlen)
目的:
接收并处理
< br>ipsec
数据包。
参数:
skb
-
接收到的数据包,
xlen
-
返回值:
0
――
登记成功,非
< br>0
值――登记未成功
算法描述:
1
.
SKB
正确性判断(有无数据,
头长度等)
;
2
.如果包被克隆过,对包进行一个留头处理,为后面做准备;
3
.是
AH
或
ESP
格式吗(只支持这两种格式)不是则丢弃包;
4
.进入解报循环;
⑴是
ESP
包但长度不是
4<
/p>
字节的倍数,丢弃。
(因
ESP
包会有补齐验证,见组报)
;
⑵计算
ESP
或
AH
头,求出
said
(
spi, proto,
等)
;
⑶若
为
AH
头,计算头长度和下一个头;
⑷为
tdb
链加锁;
< br>
⑸取出
tdbp
(
TDB
头)
,若为空,丢弃包;
< br>
⑹
tdb
的状态对吗
larval, dead
以及超时(有多种情况)均将丢弃包;
⑺根据认证标志
tdbp->tdb_authalg
对数据
包进行验证;
⑻对
ESP
包进行解密;
⑼计算新的
IP
数据包头;
⑽解锁;
(中间丢弃包时也先解锁)
⑾如果新
的数据包还是
IPSec
包,循环处理;
5
.对
tdb
链进行处理;
6
.把解开的包送
入
IP
接收队列。
netifrx(skb)
。
安全联盟的管理模块
概要说明
功能
实现了对
SA
数据库的初始化,添加、删除或更新
SA
。
组成文件
,
变量说明
tdb
结构
struct tdb
{
struct tdb
*
tdb_hnext;
/*
next in hash chain */
struct
tdb
*
tdb_onext;
/* next in output */
struct tdb
*
tdb_inext;
struct ifnet
struct sa_id
__u32
/* next in input
(prev!) */
/* related rcv
encap interface */
/* tunnel descriptor block
*/
*tdb_rcvif;
tdb_said; /* SA ID */
tdb_seq;
/* seq num of msg
that set this SA */
__u32
#if 1
tdb_pid;
/* PID of process that set this SA
*/
struct xformsw
caddr_t
#endif
__u8
__u8
__u32
__u32
__u32
__u32
__u32
__u8
__u8
__u32
__u64
__u32
__u32
__u32
__u32
__u32
__u64
__u64
__u64
__u64
__u64
__u64
__u64
__u64
__u64
__u64
__u64
*tdb_xform;
/*
transformation to use (host order)*/
/* transformation data (opaque)
*/
tdb_xdata;
tdb_authalg;
/* auth
algorithm for this SA */
tdb_encalg;
/* enc algorithm
for this SA */
tdb_alg_errs;
/* number of algorithm errors
*/
/* number of
authentication errors */
tdb_auth_errs;
tdb_encsize_errs;
/* number
of encryption size errors */
tdb_encpad_errs;
/* number
of encryption size errors */
tdb_replaywin_errs;
/*
number of pkt sequence errors */
tdb_replaywin;
tdb_state;
/* replay window size */
/* state of SA */
tdb_replaywin_lastseq;
/*
last pkt sequence num */
tdb_replaywin_bitmap;
/*
bitmap of received pkts */
tdb_replaywin_maxdiff; /* maximum pkt
sequence difference */
tdb_flags;
/* generic xform
flags */
tdb_lifetime_allocations_c;
/* see rfc2367 */
tdb_lifetime_allocations_s;
tdb_lifetime_allocations_h;
tdb_lifetime_bytes_c;
tdb_lifetime_bytes_s;
tdb_lifetime_bytes_h;
tdb_lifetime_addtime_c;
tdb_lifetime_addtime_s;
tdb_lifetime_addtime_h;
tdb_lifetime_usetime_c;
tdb_lifetime_usetime_s;
tdb_lifetime_usetime_h;
tdb_lifetime_packets_c;
tdb_lifetime_packets_s;
__u64
__u64
tdb_lifetime_packets_h;
tdb_lifetime_usetime_l; /* last time
transform was used */
*tdb_addr_s;
/* src sockaddr
*/
*tdb_addr_d;
/* dst sockaddr */
*tdb_addr_p;
/* proxy
sockaddr */
struct sockaddr
struct sockaddr
struct
sockaddr
__u16
__u16
__u16
__u16
__u16
__u16
__u16
__u8
__u16
__u16
tdb_iv_size;
tdb_addr_s_size;
tdb_addr_d_size;
tdb_addr_p_size;
tdb_key_bits_a;
/* size of
authkey in bits */
tdb_auth_bits;
/
*
size of authenticator in bits */
tdb_key_bits_e;
/* size of
enckey in bits */
tdb_iv_bits;
/* size of IV
in bits */
tdb_key_a_size;
tdb_key_e_size;
/* authentication key */
/* encryption key */
/* Initialisation Vector */
caddr_t
tdb_key_a;
caddr_t
tdb_key_e;
caddr_t
tdb_iv;
__u16
__u16
__u64
__u64
__u8
__u8
tdb_ident_type_s;
/* src
identity type */
tdb_ident_type_d;
/* dst
identity type */
tdb_ident_id_s;
tdb_ident_id_d;
/* src
identity id */
/* dst
identity id */
tdb_ident_len_s;
/* src
identity type */
tdb_ident_len_d;
/* dst
identity type */
caddr_t
tdb_ident_data_s;
/* src
identity data */
caddr_t
tdb_ident_data_d;
/* dst
identity data */
#if
0
sens
#endif
};
函数说明
int ipsec_tdbinit(void)
目的:
初始化
tdb
链。
参数:
无
返回值:
0
――
成
功,非
0
值――失败
算法描述:
将
tdb
链清空。
int tdb_init(struct tdb *tdbp,struct
encap_msghdr *em)
目的:
参数:
返回值:
0
――
成功,非
0
值――失败
算法描述:
int puttdb(struct tdb
*tdbp)
目的:
将一个新的
tdb
块-
td
bp
加入在
tdbh
链中
参数:
tdbp
――
要添加的
tdb
块
返回值:
0
――
成功,非
0
值――失败
算法描述:
判断传入的
tdbp
是否为空,若为空,返回失败信息;
p>
计算根据
tdbp->tdb_spi
、
tdbp->
和
< br>tdbp->tdb_proto
计算出
hashval
;
将
tdb
链
加锁,以免同时有其它存取
tdb
链的行为;
< br>
将
tdbp
插入
tdb
链中:
tdbp-
>tdb_hnext = tdbh[hashval];
tdbh[hashval]=tdbp
;
将
tdb
链解锁。
struct tdb*
gettdb(struct sa_id *said)
目的:
根据给出的
< br>said
值查找相应的
tdb
块
。
参数:
said
――
与要查找的
tdb
块相应的
sai
d
值
返回值:
struct tdb
――
找到的
tdb
块,
NULL
――
失败
算法描述:
判断
said
值是否有效,若为空,返回
NULL
;
根据
said
计算
hashval
;
根据
hashval
值找到所要的
tdb
块,失败则返回
NULL
。
int deltdb(struct tdb *tdbp)
目的:
删除某个指定的
tdb
块。
参数:
tdbp
――
要删除的
tdb
块
返回值:
0
――
成功,非
0
值――
失败
算法描述:
判断
tdbp
的有效性,若无效,则返回失败信息;
计算
hashval
值;
根据
hashval
找到
tdbp
,并删除它,若失败,返回错误。<
/p>
int
deltdbchain(struct tdb *tdbp)
目的:
删除整个
tdbp
链。
参数:
tdbp
――
要删除的
tdb
链
返回值:
0
――
成功,非
0
值――
失败
算法描述:
判断
tdbp
是否有效,若无效,返回错误信息;
将
tdbp
移至最后的
tdbp->tdb_onext
;
删除所有的
tdb
块。
int
ipsec_tdbwipe(struct tdb *tdbp)
目的:
将指定
tdb
块中的所有值清空。
参数:
tdbp
――
要清空的
tdb
块
返回值:
0
――成功,非
0
值――
失败
算法描述:
将所有值置为
NULL
。
安全策略数据库的管理模块
概要说明
功能
实现了对
SPD
数据库的初始化,添加、删除
eroute
。
组成文件
,
变量说明
eroute
struct
eroute
{
struct rjtentry er_rjt;
struct sa_id er_said;
struct sockaddr_encap
er_eaddr;
struct
sockaddr_encap er_emask;
};
函数说明
int ipsec_radijinit(void)
目的:
初始化
radij
树
参数:
无
返回值:
0
――
成
功,非
0
值――
失败
算法描述:调用
rj_init()
函数初始化。
int
ipsec_makeroute(struct
sockaddr_encap
*eaddr,
struct
sockaddr_encap
*emask,
struct
sa_id said)
目的:
根据
said
值,生成新的
eroute
项
。
参数:
eaddr
――
封装的有效目的地址,
emask
――
封装的目的地址掩码,
said
――
传入的
said
值
返回值:
0
――成功,非
0
值――
失败
算法描述:
分配
eroute
空间――
retrt
,并先清
0
;
给
retrt
赋
值
< br>:
retrt->er_eaddr
=
*eaddr;
retrt->er_emask
=
*emask;
retrt->er_said = said;
给
eroute
表加锁;
调用函数
rj_addroute(&(retrt->er_
eaddr), &(retrt->er_emask), rnh,
retrt->
,向
eroute
< br>表中加入新生成的该项;
解锁,返回。
int ipsec_breakroute(struct
sockaddr_encap *eaddr, struct sockaddr_encap
*emask)
目的:
删除指定的
route
。
参数:
eaddr
――
有效目的地址,
emask
-
目的地址的掩码
返回值:
0
――
成功,非
0
值――
失败
算法描述:
锁住
eroute
表;
调用函数
rj_delete(eaddr, emask,
rnh, &rn)
删除这个指定
route
< br>;
解锁,将该
route
p>
项清
0
,调用系统调用
kfree
释放该空间。
struct eroute *ipsec_findroute(struct
sockaddr_encap *eaddr)
目的:
接收并处理
< br>ipsec
数据包。
参数:
eaddr
――
< br>要查找的
route
所具有的
e
addr
值
返回值:
struct
eroute
――
找到的
eroute
值,
NULL
――
未找到
算法描述:
调用函数
rj_match((caddr_t)eaddr,
rnh)
,
根据
eaddr
查找相应的
eroute
项;
返回找到的
eroute
项。<
/p>
int
ipsec_cleareroutes(void)
目的:
清空
eroute
表。
参数:
无
返回值:
0
――
成
功,非
0
值――
失败
算法描述:首先,锁住
eroute
表;调用函数
radijclea
rtree()
函数;解锁,返回。
int ipsec_radijcleanup(void)
目的:
参数:
无
返回值:
0
――
成
功,非
0
值――
失败
算法描述:首先,锁住
eroute
表;调用函数
radijclea
nup()
函数;解锁,返回。
密钥协商及管理模块
概要说明
功能
前面所描述的
< br>KLIPS
模块,基本完成了对输入、输出数据包的加密、认证工作,但其前
p>
提是处理数据包的
SA
已经协商完毕,
p>
而这个
SA
的协商工作正是由
IKE
所负责的。
在本
程序
中,
Pluto
模块是
IKE
的一个实现,它可以自动完成两个主机或网关间的安全联盟
的协商工作。
源代码组成
――――
Pluto
|
|
――
|
――
|
|
――
|
――
|
――
|
――
|
――
|
――
|
――
|
――
|
――
源文件目录
启动后台进程
pluto
的主程序
监听
IKE
消息、
whack
消息和
pfkey
消息
,
调用相应处理过程
由
server
调用,处理
IKE
消息
处理
IKE
消息的头文件,主要定义消息的结构
描述建立
ISAKMP
SA
和
IPSEC
SA
的过程
state
头文件,主要定义
state
结构
描
述对
state
的各种操作,为建立
S
A
服务
connection
头文件,定义
connection
结构
p>
描述对
connection
的各种操作,为建立
SA
服务
构造和解析
SA
载荷,为建立
SA
服务<
/p>
定义了各种
ISAKMP
包的消息头格式,以及构造消息头的算
法和解析消息头的算法
|
――
|
――
|
――
|
――
|
――
|
――
|
――
|
――
|
――
|
――
|
――
|
――
|
――
|
――
与建立
SA
相关的各种定义
描述对
cookie
s
值的各种操作
调用加密算法的接口模块
ID
的表示及操作
处理时间事件
随机数函数模块
SHA
-
1
散列函数模块
MD5
散列函数模块
DSA
签名模块
共享密钥的处理模块
其它一些函数的定义
|
――
|
|
――
|
――
<
/p>
由
server
调用,处理
whack
消息
接收
ipsec
whack
命令,构造相应的
whack
消息,发送到
p>
whackfd
,由监听,发到处理
|
|
――
|
|
――
|
――
启动模块
概要说明
由
server
调用,处理
pfkey
消
息,操作内核中的
SADB
库
日志处理模块
功能
启动
P
luto
后台进程。
源代码组成
函数说明
int main(int argc, char
**argv)
目的:分析使用程序的参数,做
pluto
进程的初始化工作
参数:
argc
argv
返回值:
0
――
成功,非
0
值
――
失败
算法:
分析使用
pluto
的命令行参数,并做相应的操作;
调用函数
init_log()
,初始化日志;<
/p>
调用函数
init_rnd_pool
()
,初始化随机数池;
调用函数<
/p>
init_secret()
,生成密钥值;
调用函数
init_states()
< br>,初始化状态表(
state
table
)
;
3
.调用函数
init_crypto()
,做好加密准备;
4
.调用
函数
init_demux()
,填充
state_microcode_table
;
5
.调用函数
call_server()
,启动服务器,监听到来的
ISAKMP
包和
Whcak
信息。
int
create_lock(void)
目的:生成一个
lockfile
文件,以保证同时只有一个
pluto
进程运行
参数:
无
返回值:
0
――
成功,非
0
值
――
失败
算法:略
int delete_lock(void)
目的:删除
lockfile
文件
< br>
参数:
无
返回值:
0
――
成功,非
0
值
――
失败
算法:略
void exit_pluto(int status)
目的:以
status
的状态离开
p>
pluto
进程。
参数:
status
――
0
ok
1 general
discomfor
10 lock file
exists
返回值:无
算法:略
监听模块
概要说明
功能
该模块主要用于监听
SA
协商消息――
IKE
消息、
whack
消息和
pfkey<
/p>
消息,收到上述几
种消息后,再调用相应处理模块。
源代码组成
文件
函数说明
void call_server(void)
目的:监听
SA
协商消息――
IKE
消息、
whack
消息和<
/p>
pfkey
消息,收到上述几种消息后,再
调用相应处理模块。
参数:无
返回值:无
算法:
调用函数
init_pfkeyed()
,创建
PF_KEY
类型的套接口;
调用函数
< br>init_whackfd()
,创建
AF_UNIX<
/p>
型套接口,用于通信;
进入循环等待,接收到来的消息:
如
果收到
IKE
协商消息,调用函数
co
mm_handle()
处理;
如果
收到
whack
消息,调用函数
wha
ck_handle()
处理;
如果
收到
pfkey
消息,调用函数
pfk
ey_handle()
处理。
void find_ifaces(void)
目的:
参数:无
返回值:无
算法:
static int
init_pfkeyfd(void)
目的:创建
PF_KEY
型的套接口
参数:无
返回值:-
1
――
失败,
其它
――
成功
算法:调用系统调用
socket()
创建
socket
,返回之。
static int
init_whackfd(void)
目的:创建
AF_UNIX
型的套接口。
参数:无
返回值:
-
1
――
失败,
其它
――
成功
算法:
调用系统调用
socket()
创建套接口,
并用
bind()
绑定到
ctl_addr
上,
调用系统调用
listen()
监听。
协商安全联盟的模块
概要说明
功能
协商
ISAKMP
SA
和
IPSEC
SA
。
源代码组成
详细说明
ISAKMP SA
的建立过程
(
p>
主模式
)
p>
消息
1
:发起方的
Cookie
值
CKY-I
、发起方提
出的一个或多个对
ISAKMP
消息的保护方案
static
stf_status
main_outI1(int
whack_sock,
struct
connection
*c,
bool
pending_quick,
lset_t
policy, unsigned long try)
<
/p>
目的:发起连接
c
的
SA
的协商,在这个初始协商消息中,将发送发起方的
co
okie
值,
和对
ISAKMP
p>
消息的保护方案。
参数:
whack_sock
――
whack
套接口
c
――
这个初始协商消息是为
c
这个连接发出的
标识在生成
ISAKMP
SA
后,是否需要立即协商
IPSEC
SA
pending_quick
――
policy
――
安全策略
try
――
发起方最多可以重试的协商次数
返回值:
STF_NO_REPLY
――
成功;其它
――
有错误
算法:
调用函数
new_state()
,为这个
connection<
/p>
-
c
构造一个新的
state
;
给这个
state
结构
st
的成员
变量赋值,其中部分值如下:
st->st_connection = c;
st->st_try = try;
nterface
等于
NULL
,返回
TRUE
;
与内核
S
ADB
引擎的交互模块
概要说明
功能
将协商好的
SA
安装到内核中的
SADB
库中
,或按照要求从
SADB
中删除作废的
SA
,等
等。原理是,构造
pfkey
消息,发送到
pfkey
套接口,内核
的
SADB
引擎收到后,解析
消息,完
成相应操作。
(
pfkey
的详情参见
PF_KEY
模块)
源代码组成
文件
函数说明
void pfkey_handle(void)
目的:
从读取
pfkeyfd
套接口读取
pfkey
消息,并分析此消息
参数:
无
返回值:无
算法:
调用系统调用
read()
,从
pfkeyfd
套接口读取
pfkey
消息;
<
/p>
调用函数
pfkey_msg_parse()
< br>分析收到的消息;
ipsec_spi_t get_ipsec_spi(ipsec_spi_t
avoid)
目的:
生成唯一的
SPI
值
参数:
avoid
返回值:
ipsec_spi_t
算法:略
bool do_command(struct connection *c,
const char *verb)
目的:
启动
_updown
脚本,执行其中的防火墙命令规则
参数:
返回值:
算法:
bool
pfkey_build(int
error,
const
char
*description,
const
char
*text_said,
sturct sadb_ext
*extensions[SADB_EXT_MAX + 1])
目的:
调用其它构造函数,如果构造
成功,返回
TRUE
,失败,在释放
e
xtensions
的空间
返回
FAL
SE
。
参数:
返回值:
TRUE
――
,
FALSE
――
算法:略
bool finish_pfkey_msg(struct sadb_ext
*extensions[SADB_EXT_MAX + 1], const
char * description, const char
*text_said)
目的:
<
/p>
结束
pfkey
消息的构造。
参数:
extensions[]
――
description
――
text_said
――
返回值:
FALSE
――
失败,
TURE
――
成功
算法:
调用函数
pfkey_msg_build(&pfkey_msg,extensions,EXT_BITS_I N)
,构造
pfkey
消息,若构
p>
造失败,返回
FALSE
;
调用系统调用
write(pfkeyfd,pfk
ey_msg,len)
,
将
pfke
y
消息发送出去如发送失败,则返回
FALSE
;
调用函数
pfkey_e
xtensions_free(extensions)
和
p
fkey_msg_free(&pfkey_msg)
释放空间。
bool do_eroute(struct
state *st, unsigned op, const char *opname
UNUSED)
目的:
根据要建立的一个
SA
,构造一个
eroute
表项(构造和发送的都是地址消息)
。<
/p>
参数:
st
――
描述一个
SA
的状态
op
――
UNUSED
――
返回值:
TRUE
――
成功,
FALSE
――
失败
算法:
根据
st
获得
SPI
值和
< br>protocol
;
调用函数
set_text_said()
,将计算所得的
said
放入
text_said
< br>中;
将六个地址转化为结构的变量:
< br>、
、
、
、
、
;
调用函数
pfkey_extensions_init(extensions)
,初始化
extensions
;
调用消息构造函数
pfkey_build
构造消
息,并调用
finish_pfkey_build()
完成构
造,把消息
发送出去。
bool del_spi(ipsec_spi_t spi, int
proto, struct in_addr src, struct in_addr
dest)
目的:
删除一个
SA
。
参数:
spi
――
SPI
值
proto
――
协议
src
――
源地址
dst
――
目的地址
返回值:
TRUE
――
成功,
FALSE
――
失败
算法:
调用函数
pfkey_extensions_init(extensions)
,进行构
造消息之前的初始化;
调用函数
se
t_text_said()
,设置
text_said
值;
调用函数
pf
key_build()
,构造删除一个
SA
< br>的
pfkey
消息,调用函数
f
inish_pfkey_build()
结束构造,并发送。
bool
setup_half_ipsec_sa(struct state *st, bool
inbound)
目的:
建立半个
SA
(即,两个网关或主机之间,对于
其中某一个来说,数据包进入或出
去的所用
SA
)
参数:
st
――
描述一个
SA
的状态
< br>
――表示此
SA
是进入的还是
外出的
INBOUND
返回值:
TRUE
――
成功,
FALSE
――
失败
算法:
根据
st
,调用函数
pfkey_build()
< br>构造合适的
pfkey
消息,再调用函数
finish_pfkey_build()
发送;若此过程中有错误发生,则
返回
FALSE
,否则,返回
TRUE
。
bool teardown_half_ipsec_sa(struct
state *st, bool inbound)
目的:
删除半个
SA
(即,两个网关或主机之间,对于其中某一个来说,数据包进入或出
去的所用
SA
)
参数:
st
――
描述一个
SA
的状态
――表示此
SA
是进入的还是外出的
< br>
INBOUND
返回值:
TRUE
――
成功,
FALSE
――
失败
算法:
根据
st
,取出该
SA
中设置的
spi
、
proto
,调
用函数
del_spi
删除它。
bool could_eroute(struct
connection *c, struct connection *ero)
目的:
参数:
c
――
描述一个
connection
ero
――
返回值:
TRUE
――
成功,
FALSE
――
失败
算法:
bool install_inbound_ipsec_sa(struct
state *st)
目的:
p>
安装
SA
,仅被被响应方使用,响应方接着
会用
install_ipsec_sa
来安装
outbound
的
SA
;而
发起方使用
install_ipsec_sa
来安装
inbound
和
outbound
的
SA
。
参数:
st
――
描述一个
SA
的状态
返回值:
TRUE
――
成功,
FALSE
――
失败
算法:
如果对方的
< br>client
有固定的
IP
地址
,
检查我们是否有一条达到那里的路由,
这条路由与
现在的相矛盾(不知道这样说对不对)
;如果有,则删除之;
调用函数
could_eroute(c,
p>
route_owner(c,TRUE))
,检查我们是否有
p>
eroute
表项,如果没
有,返回
FALSE
;
调用函数
route_connection(c,
FALSE)
,检查我们是否可以将外出的数据包路由到某个
ipsec
虚接口。事实上,这只检查了我们的
p
eer
不在他的子网中,或者如果他在,我们
使用
UDP 500
端口的
IKE
消息,使得它不被处理;
调用函数
setup_half_ipsec_sa(st)
,建立进入的
SA
。
bool install_ipsec_sa(struct state *st,
bool inbound_alse)
目的:
安装
SA
。
参数:
st
――
描述一个
SA
的状态
inbound_also
――
<
/p>
标识这个
SA
是
inbound
,或
outbound
返回值:
TRUE
――
成功,
FALSE
――
失败
算法:
调用函数
route_owner(c, TRUE)
,查找是谁拥有这个
eroute
;
调用函数
could_eroute(c,
ero)
,
;
调用函数
route_connection(c,
TRUE)
,检查我们是否可以将外出的数据包路由到某个
ipsec
虚接口;
调用
函数
setup_half_ipsec_sa()
,根据
p>
inbound_also
,建立进入的或外出的
< br>SA
;
如果建立成功,如果<
/p>
c->eroute_owner
为
SO
S_NOBODY
,则调用函数
do_eroute(…,”a
dd”)
添加
eroute
表项,再调
用函数
do_command()
启动脚本;如果不是
SOS_NOBODY
,则调
用
do_eroute(…,”replace”)
更新
eroute
表项。
bool delete_ipsec_sa(struct state *st,
bool inbound_only)
目的:
安装
SA
。
参数:
st
――
描述一个
SA
的状态
inbound_only
――
<
/p>
是否只删
inbound
的
SA
返回值:
TRUE
――
成功,
FALSE
――
失败
算法:
如果
inbound_only
为
TRUE
,则调用函数
teardown_half_ipsec_sa()
删除半个
SA
;
如果
inbound_only
为
FALSE
,判断是否
c->eroute_owner
== st->st_serialno
,如果相等,
调用函数
do_command(…,”down”)
启动脚本关闭,及
调用
do_eroute(…,”delete”)
删除
eroute
;如果上述步骤成功,再调用
t
eardown_half_ipsec_sa()
删除
SA<
/p>
。
PF_KEY
模块
概要说明
PF_KEY
是一种新型的协议族,由
PF_ROUTE
衍生而来
。在协议族中,
PF_KEY
被定义为
15
。目前,实现所依据的时
PF_KEY
的第二个版本。密钥管理进程可以使用它与操作系
统中的“
key
engine
”或安全联盟数据库(
< br>SADB
)通信,并使用
PF_INET
通过网络与远
程密钥管理进程进行通信。密钥管理进程与
PF_KEY
的关系如图所示:
+----------------------+
|Key Mgmt Daemon|
+----------------------+
|
|
|
|
Applications
p>
=====[PF_KEY]====[PF_INET]===============
===========
|
|
OS Kernel
+------------+
+-----------------+
| Key Engine |
| TCP/IP
,
|
|
or
SADB
|---| including IPsec
|
+------------+
|
|
+-----------------+
|
+-----------+
|
Network
|
| Interface
|
+-----------+
Figure 1: Relationship of Key Mgmt to
PF_KEY
该模块大致由四部分组成:
――
PF_KEYv2 Key
management API domain socket I/F
――
PF_KEYv2 Key management API message
parser
提供了一个可用于
IP
sec
密钥管理函数库(
key management
API
)
。
――
PF_KEYv2 Key
management API message parser
――
实现用户层与核心之间对于密钥协商的交互处理