Blame view

net/ipv4/xfrm4_input.c 4.17 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
  /*
   * xfrm4_input.c
   *
   * Changes:
   *	YOSHIFUJI Hideaki @USAGI
   *		Split up af-specific portion
   *	Derek Atkins <derek@ihtfp.com>
   *		Add Encapsulation support
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
9
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
   */
5a0e3ad6a   Tejun Heo   include cleanup: ...
11
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
  #include <linux/module.h>
  #include <linux/string.h>
b05e10669   Patrick McHardy   [IPV4/6]: Netfilt...
14
15
  #include <linux/netfilter.h>
  #include <linux/netfilter_ipv4.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
  #include <net/ip.h>
  #include <net/xfrm.h>
227620e29   Herbert Xu   [IPSEC]: Separate...
18
19
20
21
  int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb)
  {
  	return xfrm4_extract_header(skb);
  }
b05e10669   Patrick McHardy   [IPV4/6]: Netfilt...
22
23
  static inline int xfrm4_rcv_encap_finish(struct sk_buff *skb)
  {
adf30907d   Eric Dumazet   net: skb->dst acc...
24
  	if (skb_dst(skb) == NULL) {
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
25
  		const struct iphdr *iph = ip_hdr(skb);
4a94445c9   Eric Dumazet   net: Use ip_route...
26
27
  		if (ip_route_input_noref(skb, iph->daddr, iph->saddr,
  					 iph->tos, skb->dev))
b05e10669   Patrick McHardy   [IPV4/6]: Netfilt...
28
29
30
31
32
33
34
  			goto drop;
  	}
  	return dst_input(skb);
  drop:
  	kfree_skb(skb);
  	return NET_RX_DROP;
  }
b05e10669   Patrick McHardy   [IPV4/6]: Netfilt...
35

c4541b41c   Herbert Xu   [IPSEC]: Move tun...
36
37
  int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
  		    int encap_type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
  {
2fcb45b6b   Herbert Xu   [IPSEC]: Use the ...
39
  	XFRM_SPI_SKB_CB(skb)->family = AF_INET;
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
40
41
42
43
  	XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
  	return xfrm_input(skb, nexthdr, spi, encap_type);
  }
  EXPORT_SYMBOL(xfrm4_rcv_encap);
b05e10669   Patrick McHardy   [IPV4/6]: Netfilt...
44

716062fd4   Herbert Xu   [IPSEC]: Merge mo...
45
46
  int xfrm4_transport_finish(struct sk_buff *skb, int async)
  {
60d5fcfb1   Herbert Xu   [IPSEC]: Remove n...
47
48
49
  	struct iphdr *iph = ip_hdr(skb);
  
  	iph->protocol = XFRM_MODE_SKB_CB(skb)->protocol;
0883ae0e5   Herbert Xu   [IPSEC]: Fix tran...
50
51
52
53
  #ifndef CONFIG_NETFILTER
  	if (!async)
  		return -iph->protocol;
  #endif
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
54
  	__skb_push(skb, skb->data - skb_network_header(skb));
60d5fcfb1   Herbert Xu   [IPSEC]: Remove n...
55
56
  	iph->tot_len = htons(skb->len);
  	ip_send_check(iph);
b05e10669   Patrick McHardy   [IPV4/6]: Netfilt...
57

9bbc768aa   Jan Engelhardt   netfilter: ipv4: ...
58
  	NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
59
60
  		xfrm4_rcv_encap_finish);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
  }
067b207b2   James Chapman   [UDP]: Cleanup UD...
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  
  /* If it's a keepalive packet, then just eat it.
   * If it's an encapsulated packet, then pass it to the
   * IPsec xfrm input.
   * Returns 0 if skb passed to xfrm or was dropped.
   * Returns >0 if skb should be passed to UDP.
   * Returns <0 if skb should be resubmitted (-ret is protocol)
   */
  int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
  {
  	struct udp_sock *up = udp_sk(sk);
  	struct udphdr *uh;
  	struct iphdr *iph;
  	int iphlen, len;
067b207b2   James Chapman   [UDP]: Cleanup UD...
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
  
  	__u8 *udpdata;
  	__be32 *udpdata32;
  	__u16 encap_type = up->encap_type;
  
  	/* if this is not encapsulated socket, then just return now */
  	if (!encap_type)
  		return 1;
  
  	/* If this is a paged skb, make sure we pull up
  	 * whatever data we need to look at. */
  	len = skb->len - sizeof(struct udphdr);
  	if (!pskb_may_pull(skb, sizeof(struct udphdr) + min(len, 8)))
  		return 1;
  
  	/* Now we can get the pointers */
  	uh = udp_hdr(skb);
  	udpdata = (__u8 *)uh + sizeof(struct udphdr);
  	udpdata32 = (__be32 *)udpdata;
  
  	switch (encap_type) {
  	default:
  	case UDP_ENCAP_ESPINUDP:
  		/* Check if this is a keepalive packet.  If so, eat it. */
  		if (len == 1 && udpdata[0] == 0xff) {
  			goto drop;
  		} else if (len > sizeof(struct ip_esp_hdr) && udpdata32[0] != 0) {
  			/* ESP Packet without Non-ESP header */
  			len = sizeof(struct udphdr);
  		} else
  			/* Must be an IKE packet.. pass it through */
  			return 1;
  		break;
  	case UDP_ENCAP_ESPINUDP_NON_IKE:
  		/* Check if this is a keepalive packet.  If so, eat it. */
  		if (len == 1 && udpdata[0] == 0xff) {
  			goto drop;
  		} else if (len > 2 * sizeof(u32) + sizeof(struct ip_esp_hdr) &&
  			   udpdata32[0] == 0 && udpdata32[1] == 0) {
  
  			/* ESP Packet with Non-IKE marker */
  			len = sizeof(struct udphdr) + 2 * sizeof(u32);
  		} else
  			/* Must be an IKE packet.. pass it through */
  			return 1;
  		break;
  	}
  
  	/* At this point we are sure that this is an ESPinUDP packet,
  	 * so we need to remove 'len' bytes from the packet (the UDP
  	 * header and optional ESP marker bytes) and then modify the
  	 * protocol to ESP, and then call into the transform receiver.
  	 */
  	if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
  		goto drop;
  
  	/* Now we can update and verify the packet length... */
  	iph = ip_hdr(skb);
  	iphlen = iph->ihl << 2;
  	iph->tot_len = htons(ntohs(iph->tot_len) - len);
  	if (skb->len < iphlen + len) {
  		/* packet is too small!?! */
  		goto drop;
  	}
  
  	/* pull the data buffer up to the ESP header and set the
  	 * transport header to point to ESP.  Keep UDP on the stack
  	 * for later.
  	 */
  	__skb_pull(skb, len);
  	skb_reset_transport_header(skb);
067b207b2   James Chapman   [UDP]: Cleanup UD...
147
  	/* process ESP */
f2712fd0b   Herbert Xu   ipsec: Remove use...
148
  	return xfrm4_rcv_encap(skb, IPPROTO_ESP, 0, encap_type);
067b207b2   James Chapman   [UDP]: Cleanup UD...
149
150
151
152
153
154
155
156
  
  drop:
  	kfree_skb(skb);
  	return 0;
  }
  
  int xfrm4_rcv(struct sk_buff *skb)
  {
c4541b41c   Herbert Xu   [IPSEC]: Move tun...
157
  	return xfrm4_rcv_spi(skb, ip_hdr(skb)->protocol, 0);
067b207b2   James Chapman   [UDP]: Cleanup UD...
158
  }
067b207b2   James Chapman   [UDP]: Cleanup UD...
159
  EXPORT_SYMBOL(xfrm4_rcv);