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;
}
  |