Blame view

net/ipv4/xfrm4_input.c 4.19 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
  /*
   * 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...
10
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
   */
5a0e3ad6a   Tejun Heo   include cleanup: ...
12
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
  #include <linux/module.h>
  #include <linux/string.h>
b05e10669   Patrick McHardy   [IPV4/6]: Netfilt...
15
16
  #include <linux/netfilter.h>
  #include <linux/netfilter_ipv4.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
  #include <net/ip.h>
  #include <net/xfrm.h>
acf568ee8   Herbert Xu   xfrm: Reinject tr...
19
20
21
22
23
  static int xfrm4_rcv_encap_finish2(struct net *net, struct sock *sk,
  				   struct sk_buff *skb)
  {
  	return dst_input(skb);
  }
0c4b51f00   Eric W. Biederman   netfilter: Pass n...
24
25
  static inline int xfrm4_rcv_encap_finish(struct net *net, struct sock *sk,
  					 struct sk_buff *skb)
b05e10669   Patrick McHardy   [IPV4/6]: Netfilt...
26
  {
51456b291   Ian Morris   ipv4: coding styl...
27
  	if (!skb_dst(skb)) {
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
28
  		const struct iphdr *iph = ip_hdr(skb);
c6cffba4f   David S. Miller   ipv4: Fix input r...
29
30
  		if (ip_route_input_noref(skb, iph->daddr, iph->saddr,
  					 iph->tos, skb->dev))
b05e10669   Patrick McHardy   [IPV4/6]: Netfilt...
31
32
  			goto drop;
  	}
acf568ee8   Herbert Xu   xfrm: Reinject tr...
33
34
35
36
37
  
  	if (xfrm_trans_queue(skb, xfrm4_rcv_encap_finish2))
  		goto drop;
  
  	return 0;
b05e10669   Patrick McHardy   [IPV4/6]: Netfilt...
38
39
40
41
  drop:
  	kfree_skb(skb);
  	return NET_RX_DROP;
  }
b05e10669   Patrick McHardy   [IPV4/6]: Netfilt...
42

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

7785bba29   Steffen Klassert   esp: Add a softwa...
57
58
  	if (xo && (xo->flags & XFRM_GRO)) {
  		skb_mac_header_rebuild(skb);
bfc0698be   Sowmini Varadhan   xfrm: reset trans...
59
  		skb_reset_transport_header(skb);
7785bba29   Steffen Klassert   esp: Add a softwa...
60
61
  		return 0;
  	}
29a26a568   Eric W. Biederman   netfilter: Pass s...
62
63
  	NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING,
  		dev_net(skb->dev), NULL, skb, skb->dev, NULL,
716062fd4   Herbert Xu   [IPSEC]: Merge mo...
64
65
  		xfrm4_rcv_encap_finish);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
  }
067b207b2   James Chapman   [UDP]: Cleanup UD...
67
68
69
70
71
72
73
74
75
76
77
78
79
80
  
  /* 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...
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
  
  	__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.
  	 */
14bbd6a56   Pravin B Shelar   net: Add skb_uncl...
134
  	if (skb_unclone(skb, GFP_ATOMIC))
067b207b2   James Chapman   [UDP]: Cleanup UD...
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
  		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...
152
  	/* process ESP */
f2712fd0b   Herbert Xu   ipsec: Remove use...
153
  	return xfrm4_rcv_encap(skb, IPPROTO_ESP, 0, encap_type);
067b207b2   James Chapman   [UDP]: Cleanup UD...
154
155
156
157
158
159
160
161
  
  drop:
  	kfree_skb(skb);
  	return 0;
  }
  
  int xfrm4_rcv(struct sk_buff *skb)
  {
c4541b41c   Herbert Xu   [IPSEC]: Move tun...
162
  	return xfrm4_rcv_spi(skb, ip_hdr(skb)->protocol, 0);
067b207b2   James Chapman   [UDP]: Cleanup UD...
163
  }
067b207b2   James Chapman   [UDP]: Cleanup UD...
164
  EXPORT_SYMBOL(xfrm4_rcv);