Branch data Line data Source code
1 : : /*
2 : : * xfrm4_input.c
3 : : *
4 : : * Changes:
5 : : * YOSHIFUJI Hideaki @USAGI
6 : : * Split up af-specific portion
7 : : * Derek Atkins <derek@ihtfp.com>
8 : : * Add Encapsulation support
9 : : *
10 : : */
11 : :
12 : : #include <linux/slab.h>
13 : : #include <linux/module.h>
14 : : #include <linux/string.h>
15 : : #include <linux/netfilter.h>
16 : : #include <linux/netfilter_ipv4.h>
17 : : #include <net/ip.h>
18 : : #include <net/xfrm.h>
19 : :
20 : 0 : int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb)
21 : : {
22 : 0 : return xfrm4_extract_header(skb);
23 : : }
24 : :
25 : 0 : static inline int xfrm4_rcv_encap_finish(struct sk_buff *skb)
26 : : {
27 [ # # ]: 0 : if (skb_dst(skb) == NULL) {
28 : : const struct iphdr *iph = ip_hdr(skb);
29 : :
30 [ # # ]: 0 : if (ip_route_input_noref(skb, iph->daddr, iph->saddr,
31 : : iph->tos, skb->dev))
32 : : goto drop;
33 : : }
34 : 0 : return dst_input(skb);
35 : : drop:
36 : 0 : kfree_skb(skb);
37 : 0 : return NET_RX_DROP;
38 : : }
39 : :
40 : 0 : int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
41 : : int encap_type)
42 : : {
43 : 0 : XFRM_SPI_SKB_CB(skb)->family = AF_INET;
44 : 0 : XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
45 : 0 : return xfrm_input(skb, nexthdr, spi, encap_type);
46 : : }
47 : : EXPORT_SYMBOL(xfrm4_rcv_encap);
48 : :
49 : 0 : int xfrm4_transport_finish(struct sk_buff *skb, int async)
50 : : {
51 : : struct iphdr *iph = ip_hdr(skb);
52 : :
53 : 0 : iph->protocol = XFRM_MODE_SKB_CB(skb)->protocol;
54 : :
55 : : #ifndef CONFIG_NETFILTER
56 : : if (!async)
57 : : return -iph->protocol;
58 : : #endif
59 : :
60 : 0 : __skb_push(skb, skb->data - skb_network_header(skb));
61 [ # # ]: 0 : iph->tot_len = htons(skb->len);
62 : 0 : ip_send_check(iph);
63 : :
64 : 0 : NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,
65 : : xfrm4_rcv_encap_finish);
66 : 0 : return 0;
67 : : }
68 : :
69 : : /* If it's a keepalive packet, then just eat it.
70 : : * If it's an encapsulated packet, then pass it to the
71 : : * IPsec xfrm input.
72 : : * Returns 0 if skb passed to xfrm or was dropped.
73 : : * Returns >0 if skb should be passed to UDP.
74 : : * Returns <0 if skb should be resubmitted (-ret is protocol)
75 : : */
76 : 0 : int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
77 : : {
78 : : struct udp_sock *up = udp_sk(sk);
79 : : struct udphdr *uh;
80 : : struct iphdr *iph;
81 : : int iphlen, len;
82 : :
83 : : __u8 *udpdata;
84 : : __be32 *udpdata32;
85 : 0 : __u16 encap_type = up->encap_type;
86 : :
87 : : /* if this is not encapsulated socket, then just return now */
88 [ # # ]: 0 : if (!encap_type)
89 : : return 1;
90 : :
91 : : /* If this is a paged skb, make sure we pull up
92 : : * whatever data we need to look at. */
93 : 0 : len = skb->len - sizeof(struct udphdr);
94 [ # # ]: 0 : if (!pskb_may_pull(skb, sizeof(struct udphdr) + min(len, 8)))
95 : : return 1;
96 : :
97 : : /* Now we can get the pointers */
98 : : uh = udp_hdr(skb);
99 : : udpdata = (__u8 *)uh + sizeof(struct udphdr);
100 : : udpdata32 = (__be32 *)udpdata;
101 : :
102 [ # # ]: 0 : switch (encap_type) {
103 : : default:
104 : : case UDP_ENCAP_ESPINUDP:
105 : : /* Check if this is a keepalive packet. If so, eat it. */
106 [ # # ][ # # ]: 0 : if (len == 1 && udpdata[0] == 0xff) {
107 : : goto drop;
108 [ # # ][ # # ]: 0 : } else if (len > sizeof(struct ip_esp_hdr) && udpdata32[0] != 0) {
109 : : /* ESP Packet without Non-ESP header */
110 : : len = sizeof(struct udphdr);
111 : : } else
112 : : /* Must be an IKE packet.. pass it through */
113 : : return 1;
114 : : break;
115 : : case UDP_ENCAP_ESPINUDP_NON_IKE:
116 : : /* Check if this is a keepalive packet. If so, eat it. */
117 [ # # ][ # # ]: 0 : if (len == 1 && udpdata[0] == 0xff) {
118 : : goto drop;
119 [ # # ][ # # ]: 0 : } else if (len > 2 * sizeof(u32) + sizeof(struct ip_esp_hdr) &&
120 [ # # ]: 0 : udpdata32[0] == 0 && udpdata32[1] == 0) {
121 : :
122 : : /* ESP Packet with Non-IKE marker */
123 : : len = sizeof(struct udphdr) + 2 * sizeof(u32);
124 : : } else
125 : : /* Must be an IKE packet.. pass it through */
126 : : return 1;
127 : : break;
128 : : }
129 : :
130 : : /* At this point we are sure that this is an ESPinUDP packet,
131 : : * so we need to remove 'len' bytes from the packet (the UDP
132 : : * header and optional ESP marker bytes) and then modify the
133 : : * protocol to ESP, and then call into the transform receiver.
134 : : */
135 [ # # ]: 0 : if (skb_unclone(skb, GFP_ATOMIC))
136 : : goto drop;
137 : :
138 : : /* Now we can update and verify the packet length... */
139 : : iph = ip_hdr(skb);
140 : 0 : iphlen = iph->ihl << 2;
141 [ # # ][ # # ]: 0 : iph->tot_len = htons(ntohs(iph->tot_len) - len);
[ # # ][ # # ]
[ # # ]
142 [ # # ]: 0 : if (skb->len < iphlen + len) {
143 : : /* packet is too small!?! */
144 : : goto drop;
145 : : }
146 : :
147 : : /* pull the data buffer up to the ESP header and set the
148 : : * transport header to point to ESP. Keep UDP on the stack
149 : : * for later.
150 : : */
151 : 0 : __skb_pull(skb, len);
152 : : skb_reset_transport_header(skb);
153 : :
154 : : /* process ESP */
155 : 0 : return xfrm4_rcv_encap(skb, IPPROTO_ESP, 0, encap_type);
156 : :
157 : : drop:
158 : 0 : kfree_skb(skb);
159 : 0 : return 0;
160 : : }
161 : :
162 : 0 : int xfrm4_rcv(struct sk_buff *skb)
163 : : {
164 : 0 : return xfrm4_rcv_spi(skb, ip_hdr(skb)->protocol, 0);
165 : : }
166 : : EXPORT_SYMBOL(xfrm4_rcv);
|