1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
| /* net/ipv4/xfrm4_input.c */
int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
{
int err;
__be32 spi, seq;
struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH];
struct xfrm_state *x;
int xfrm_nr = 0;
int decaps = 0;
// 获取skb中的spi和序列号信息
if ((err = xfrm4_parse_spi(skb, skb->nh.iph->protocol, &spi, &seq)) != 0)
goto drop;
// 进入循环进行解包操作
do {
struct iphdr *iph = skb->nh.iph;
// 循环解包次数太深的话放弃
if (xfrm_nr == XFRM_MAX_DEPTH)
goto drop;
// 根据地址, SPI和协议查找SA
x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, iph->protocol, AF_INET);
if (x == NULL)
goto drop;
// 以下根据SA定义的操作对数据解码
spin_lock(&x->lock);
if (unlikely(x->km.state != XFRM_STATE_VALID))
goto drop_unlock;
// 检查由SA指定的封装类型是否和函数指定的封装类型相同
if ((x->encap ? x->encap->encap_type : 0) != encap_type)
goto drop_unlock;
// SA重放窗口检查
if (x->props.replay_window && xfrm_replay_check(x, seq))
goto drop_unlock;
// SA生存期检查
if (xfrm_state_check_expire(x))
goto drop_unlock;
// type可为esp,ah,ipcomp, ipip等, 对输入数据解密
if (x->type->input(x, skb))
goto drop_unlock;
/* only the first xfrm gets the encap type */
encap_type = 0;
// 更新重放窗口
if (x->props.replay_window)
xfrm_replay_advance(x, seq);
// 包数,字节数统计
x->curlft.bytes += skb->len;
x->curlft.packets++;
spin_unlock(&x->lock);
xfrm_vec[xfrm_nr++] = x;
// mode可为通道,传输等模式, 对输入数据解封装
if (x->mode->input(x, skb))
goto drop;
// 如果是IPSEC通道模式,将decaps参数置1,否则表示是传输模式
if (x->props.mode == XFRM_MODE_TUNNEL) {
decaps = 1;
break;
}
// 看内层协议是否还要继续解包, 不需要解时返回1, 需要解时返回0, 错误返回负数
// 协议类型可以多层封装的,比如用AH封装ESP, 就得先解完AH再解ESP
if ((err = xfrm_parse_spi(skb, skb->nh.iph->protocol, &spi, &seq)) < 0)
goto drop;
} while (!err);
/* Allocate new secpath or COW existing one. */
// 为skb包建立新的安全路径(struct sec_path)
if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
struct sec_path *sp;
sp = secpath_dup(skb->sp);
if (!sp)
goto drop;
if (skb->sp)
secpath_put(skb->sp);
skb->sp = sp;
}
if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH)
goto drop;
// 将刚才循环解包用到的SA拷贝到安全路径
// 因此检查一个数据包是否是普通明文包还是解密后的明文包就看skb->sp参数是否为空
memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec,
xfrm_nr * sizeof(xfrm_vec[0]));
skb->sp->len += xfrm_nr;
nf_reset(skb);
if (decaps) {
// 通道模式
if (!(skb->dev->flags&IFF_LOOPBACK)) {
dst_release(skb->dst);
skb->dst = NULL;
}
// 重新进入网卡接收函数
netif_rx(skb);
return 0;
} else {
// 传输模式
#ifdef CONFIG_NETFILTER
// 如果定义NETFILTER, 进入PRE_ROUTING链处理,然后进入路由选择处理
// 其实现在已经处于INPUT点, 但解码后需要将该包作为一个新包看待
// 可能需要进行目的NAT操作, 这时候可能目的地址就会改变不是到自身
// 的了, 因此需要将其相当于是放回PRE_PROUTING点去操作, 重新找路由
// 这也说明可以制定针对解码后明文包的NAT规则,在还是加密包的时候不匹配
// 但解码后能匹配上
__skb_push(skb, skb->data - skb->nh.raw);
skb->nh.iph->tot_len = htons(skb->len);
ip_send_check(skb->nh.iph);
NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL, xfrm4_rcv_encap_finish);
return 0;
#else
// 内核不支持NETFILTER, 该包肯定就是到自身的了
// 返回IP协议的负值, 表示重新进行IP层协议的处理
// 用解码后的内层协议来处理数据
return -skb->nh.iph->protocol;
#endif
}
drop_unlock:
spin_unlock(&x->lock);
xfrm_state_put(x);
drop:
while (--xfrm_nr >= 0)
xfrm_state_put(xfrm_vec[xfrm_nr]);
kfree_skb(skb);
return 0;
}
|