没有合适的资源?快使用搜索试试~ 我知道了~
首页ipsec(linux内核实现)
ipsec(linux内核实现)
4星 · 超过85%的资源 需积分: 50 112 下载量 75 浏览量
更新于2023-07-16
4
收藏 891KB DOC 举报
讲解linux内核最新代码中ipsec pfkey的实现过程。很具有参考价值。
资源详情
资源推荐
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(&pfkey_family_ops);
if (err != 0)
goto out_unregister_key_proto;
#ifdef CONFIG_PROC_FS
err = -ENOMEM;
// 建立只读的 pfkey 的 PROC 文件: /proc/net/pfkey
if (create_proc_read_entry("net/pfkey", 0, NULL, pfkey_read_proc, NULL) == NULL)
goto out_sock_unregister;
#endif
// 登记通知(notify)处理 pfkeyv2_mgr
err = xfrm_register_km(&pfkeyv2_mgr);
if (err != 0)
goto out_remove_proc_entry;
out:
return err;
out_remove_proc_entry:
#ifdef CONFIG_PROC_FS
remove_proc_entry("net/pfkey", NULL);
out_sock_unregister:
#endif
sock_unregister(PF_KEY);
out_unregister_key_proto:
proto_unregister(&key_proto);
goto out;
}
4. pfkey 套接口操作
4.1 建立套接口
/* net/key/af_key.c */
// pfkey 协议族操作, 在用户程序使用 socket 打开 pfkey 类型的 socket 时调用,
// 相应的 create 函数在__sock_create(net/socket.c)函数中调用:
static struct net_proto_family pfkey_family_ops = {
.family = PF_KEY,
.create = pfkey_create,
.owner = THIS_MODULE,
};
// 在用户空间每次打开 pfkey socket 时都会调用此函数:
static int pfkey_create(struct socket *sock, int protocol)
{
struct sock *sk;
int err;
// 建立 PFKEY 的 socket 必须有 ROOT 权限
if (!capable(CAP_NET_ADMIN))
return -EPERM;
// socket 类型必须是 RAW, 协议为 PF_KEY_V2
if (sock->type != SOCK_RAW)
return -ESOCKTNOSUPPORT;
if (protocol != PF_KEY_V2)
return -EPROTONOSUPPORT;
err = -ENOMEM;
// 分配 sock 结构, 并清零
sk = sk_alloc(PF_KEY, GFP_KERNEL, &key_proto, 1);
if (sk == NULL)
goto out;
// PFKEY 类型 socket 的操作
sock->ops = &pfkey_ops;
剩余63页未读,继续阅读
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功