Commit 0a69452cb45add0841c2bc1e75c25f6bd4f1d8d9
Committed by
David S. Miller
1 parent
80246ab36e
[XFRM]: BEET mode
This patch introduces the BEET mode (Bound End-to-End Tunnel) with as specified by the ietf draft at the following link: http://www.ietf.org/internet-drafts/draft-nikander-esp-beet-mode-06.txt The patch provides only single family support (i.e. inner family = outer family). Signed-off-by: Diego Beltrami <diego.beltrami@gmail.com> Signed-off-by: Miika Komu <miika@iki.fi> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Abhinav Pathak <abhinav.pathak@hiit.fi> Signed-off-by: Jeff Ahrenholz <ahrenholz@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 14 changed files with 309 additions and 11 deletions Side-by-side Diff
include/linux/in.h
... | ... | @@ -40,6 +40,7 @@ |
40 | 40 | |
41 | 41 | IPPROTO_ESP = 50, /* Encapsulation Security Payload protocol */ |
42 | 42 | IPPROTO_AH = 51, /* Authentication Header protocol */ |
43 | + IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET */ | |
43 | 44 | IPPROTO_PIM = 103, /* Protocol Independent Multicast */ |
44 | 45 | |
45 | 46 | IPPROTO_COMP = 108, /* Compression Header protocol */ |
include/linux/ip.h
... | ... | @@ -80,6 +80,8 @@ |
80 | 80 | #define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ |
81 | 81 | #define IPOPT_TS_PRESPEC 3 /* specified modules only */ |
82 | 82 | |
83 | +#define IPV4_BEET_PHMAXLEN 8 | |
84 | + | |
83 | 85 | struct iphdr { |
84 | 86 | #if defined(__LITTLE_ENDIAN_BITFIELD) |
85 | 87 | __u8 ihl:4, |
... | ... | @@ -121,6 +123,13 @@ |
121 | 123 | __u8 nexthdr; |
122 | 124 | __u8 flags; |
123 | 125 | __be16 cpi; |
126 | +}; | |
127 | + | |
128 | +struct ip_beet_phdr { | |
129 | + __u8 nexthdr; | |
130 | + __u8 hdrlen; | |
131 | + __u8 padlen; | |
132 | + __u8 reserved; | |
124 | 133 | }; |
125 | 134 | |
126 | 135 | #endif /* _LINUX_IP_H */ |
include/linux/ipsec.h
include/linux/xfrm.h
... | ... | @@ -129,7 +129,8 @@ |
129 | 129 | #define XFRM_MODE_TUNNEL 1 |
130 | 130 | #define XFRM_MODE_ROUTEOPTIMIZATION 2 |
131 | 131 | #define XFRM_MODE_IN_TRIGGER 3 |
132 | -#define XFRM_MODE_MAX 4 | |
132 | +#define XFRM_MODE_BEET 4 | |
133 | +#define XFRM_MODE_MAX 5 | |
133 | 134 | |
134 | 135 | /* Netlink configuration messages. */ |
135 | 136 | enum { |
net/ipv4/Kconfig
... | ... | @@ -434,6 +434,15 @@ |
434 | 434 | |
435 | 435 | If unsure, say Y. |
436 | 436 | |
437 | +config INET_XFRM_MODE_BEET | |
438 | + tristate "IP: IPsec BEET mode" | |
439 | + default y | |
440 | + select XFRM | |
441 | + ---help--- | |
442 | + Support for IPsec BEET mode. | |
443 | + | |
444 | + If unsure, say Y. | |
445 | + | |
437 | 446 | config INET_DIAG |
438 | 447 | tristate "INET: socket monitoring interface" |
439 | 448 | default y |
net/ipv4/Makefile
... | ... | @@ -23,6 +23,7 @@ |
23 | 23 | obj-$(CONFIG_INET_ESP) += esp4.o |
24 | 24 | obj-$(CONFIG_INET_IPCOMP) += ipcomp.o |
25 | 25 | obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o |
26 | +obj-$(CONFIG_INET_XFRM_MODE_BEET) += xfrm4_mode_beet.o | |
26 | 27 | obj-$(CONFIG_INET_TUNNEL) += tunnel4.o |
27 | 28 | obj-$(CONFIG_INET_XFRM_MODE_TRANSPORT) += xfrm4_mode_transport.o |
28 | 29 | obj-$(CONFIG_INET_XFRM_MODE_TUNNEL) += xfrm4_mode_tunnel.o |
net/ipv4/esp4.c
... | ... | @@ -253,7 +253,8 @@ |
253 | 253 | * as per draft-ietf-ipsec-udp-encaps-06, |
254 | 254 | * section 3.1.2 |
255 | 255 | */ |
256 | - if (x->props.mode == XFRM_MODE_TRANSPORT) | |
256 | + if (x->props.mode == XFRM_MODE_TRANSPORT || | |
257 | + x->props.mode == XFRM_MODE_BEET) | |
257 | 258 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
258 | 259 | } |
259 | 260 | |
260 | 261 | |
261 | 262 | |
262 | 263 | |
263 | 264 | |
... | ... | @@ -271,17 +272,28 @@ |
271 | 272 | { |
272 | 273 | struct esp_data *esp = x->data; |
273 | 274 | u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4); |
275 | + int enclen = 0; | |
274 | 276 | |
275 | - if (x->props.mode == XFRM_MODE_TUNNEL) { | |
276 | - mtu = ALIGN(mtu + 2, blksize); | |
277 | - } else { | |
278 | - /* The worst case. */ | |
277 | + switch (x->props.mode) { | |
278 | + case XFRM_MODE_TUNNEL: | |
279 | + mtu = ALIGN(mtu +2, blksize); | |
280 | + break; | |
281 | + default: | |
282 | + case XFRM_MODE_TRANSPORT: | |
283 | + /* The worst case */ | |
279 | 284 | mtu = ALIGN(mtu + 2, 4) + blksize - 4; |
285 | + break; | |
286 | + case XFRM_MODE_BEET: | |
287 | + /* The worst case. */ | |
288 | + enclen = IPV4_BEET_PHMAXLEN; | |
289 | + mtu = ALIGN(mtu + enclen + 2, blksize); | |
290 | + break; | |
280 | 291 | } |
292 | + | |
281 | 293 | if (esp->conf.padlen) |
282 | 294 | mtu = ALIGN(mtu, esp->conf.padlen); |
283 | 295 | |
284 | - return mtu + x->props.header_len + esp->auth.icv_trunc_len; | |
296 | + return mtu + x->props.header_len + esp->auth.icv_trunc_len - enclen; | |
285 | 297 | } |
286 | 298 | |
287 | 299 | static void esp4_err(struct sk_buff *skb, u32 info) |
net/ipv4/ipcomp.c
... | ... | @@ -206,6 +206,7 @@ |
206 | 206 | static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x) |
207 | 207 | { |
208 | 208 | struct xfrm_state *t; |
209 | + u8 mode = XFRM_MODE_TUNNEL; | |
209 | 210 | |
210 | 211 | t = xfrm_state_alloc(); |
211 | 212 | if (t == NULL) |
... | ... | @@ -216,7 +217,9 @@ |
216 | 217 | t->id.daddr.a4 = x->id.daddr.a4; |
217 | 218 | memcpy(&t->sel, &x->sel, sizeof(t->sel)); |
218 | 219 | t->props.family = AF_INET; |
219 | - t->props.mode = XFRM_MODE_TUNNEL; | |
220 | + if (x->props.mode == XFRM_MODE_BEET) | |
221 | + mode = x->props.mode; | |
222 | + t->props.mode = mode; | |
220 | 223 | t->props.saddr.a4 = x->props.saddr.a4; |
221 | 224 | t->props.flags = x->props.flags; |
222 | 225 |
net/ipv4/xfrm4_mode_beet.c
1 | +/* | |
2 | + * xfrm4_mode_beet.c - BEET mode encapsulation for IPv4. | |
3 | + * | |
4 | + * Copyright (c) 2006 Diego Beltrami <diego.beltrami@gmail.com> | |
5 | + * Miika Komu <miika@iki.fi> | |
6 | + * Herbert Xu <herbert@gondor.apana.org.au> | |
7 | + * Abhinav Pathak <abhinav.pathak@hiit.fi> | |
8 | + * Jeff Ahrenholz <ahrenholz@gmail.com> | |
9 | + */ | |
10 | + | |
11 | +#include <linux/init.h> | |
12 | +#include <linux/kernel.h> | |
13 | +#include <linux/module.h> | |
14 | +#include <linux/skbuff.h> | |
15 | +#include <linux/stringify.h> | |
16 | +#include <net/dst.h> | |
17 | +#include <net/ip.h> | |
18 | +#include <net/xfrm.h> | |
19 | + | |
20 | +/* Add encapsulation header. | |
21 | + * | |
22 | + * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt. | |
23 | + * The following fields in it shall be filled in by x->type->output: | |
24 | + * tot_len | |
25 | + * check | |
26 | + * | |
27 | + * On exit, skb->h will be set to the start of the payload to be processed | |
28 | + * by x->type->output and skb->nh will be set to the top IP header. | |
29 | + */ | |
30 | +static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb) | |
31 | +{ | |
32 | + struct iphdr *iph, *top_iph = NULL; | |
33 | + int hdrlen, optlen; | |
34 | + | |
35 | + iph = skb->nh.iph; | |
36 | + skb->h.ipiph = iph; | |
37 | + | |
38 | + hdrlen = 0; | |
39 | + optlen = iph->ihl * 4 - sizeof(*iph); | |
40 | + if (unlikely(optlen)) | |
41 | + hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4); | |
42 | + | |
43 | + skb->nh.raw = skb_push(skb, x->props.header_len + hdrlen); | |
44 | + top_iph = skb->nh.iph; | |
45 | + hdrlen = iph->ihl * 4 - optlen; | |
46 | + skb->h.raw += hdrlen; | |
47 | + | |
48 | + memmove(top_iph, iph, hdrlen); | |
49 | + if (unlikely(optlen)) { | |
50 | + struct ip_beet_phdr *ph; | |
51 | + | |
52 | + BUG_ON(optlen < 0); | |
53 | + | |
54 | + ph = (struct ip_beet_phdr *)skb->h.raw; | |
55 | + ph->padlen = 4 - (optlen & 4); | |
56 | + ph->hdrlen = (optlen + ph->padlen + sizeof(*ph)) / 8; | |
57 | + ph->nexthdr = top_iph->protocol; | |
58 | + | |
59 | + top_iph->protocol = IPPROTO_BEETPH; | |
60 | + top_iph->ihl = sizeof(struct iphdr) / 4; | |
61 | + } | |
62 | + | |
63 | + top_iph->saddr = x->props.saddr.a4; | |
64 | + top_iph->daddr = x->id.daddr.a4; | |
65 | + | |
66 | + return 0; | |
67 | +} | |
68 | + | |
69 | +static int xfrm4_beet_input(struct xfrm_state *x, struct sk_buff *skb) | |
70 | +{ | |
71 | + struct iphdr *iph = skb->nh.iph; | |
72 | + int phlen = 0; | |
73 | + int optlen = 0; | |
74 | + __u8 ph_nexthdr = 0, protocol = 0; | |
75 | + int err = -EINVAL; | |
76 | + | |
77 | + protocol = iph->protocol; | |
78 | + | |
79 | + if (unlikely(iph->protocol == IPPROTO_BEETPH)) { | |
80 | + struct ip_beet_phdr *ph = (struct ip_beet_phdr*)(iph + 1); | |
81 | + | |
82 | + if (!pskb_may_pull(skb, sizeof(*ph))) | |
83 | + goto out; | |
84 | + | |
85 | + phlen = ph->hdrlen * 8; | |
86 | + optlen = phlen - ph->padlen - sizeof(*ph); | |
87 | + if (optlen < 0 || optlen & 3 || optlen > 250) | |
88 | + goto out; | |
89 | + | |
90 | + if (!pskb_may_pull(skb, phlen)) | |
91 | + goto out; | |
92 | + | |
93 | + ph_nexthdr = ph->nexthdr; | |
94 | + } | |
95 | + | |
96 | + skb_push(skb, sizeof(*iph) - phlen + optlen); | |
97 | + memmove(skb->data, skb->nh.raw, sizeof(*iph)); | |
98 | + skb->nh.raw = skb->data; | |
99 | + | |
100 | + iph = skb->nh.iph; | |
101 | + iph->ihl = (sizeof(*iph) + optlen) / 4; | |
102 | + iph->tot_len = htons(skb->len); | |
103 | + iph->daddr = x->sel.daddr.a4; | |
104 | + iph->saddr = x->sel.saddr.a4; | |
105 | + if (ph_nexthdr) | |
106 | + iph->protocol = ph_nexthdr; | |
107 | + else | |
108 | + iph->protocol = protocol; | |
109 | + iph->check = 0; | |
110 | + iph->check = ip_fast_csum(skb->nh.raw, iph->ihl); | |
111 | + err = 0; | |
112 | +out: | |
113 | + return err; | |
114 | +} | |
115 | + | |
116 | +static struct xfrm_mode xfrm4_beet_mode = { | |
117 | + .input = xfrm4_beet_input, | |
118 | + .output = xfrm4_beet_output, | |
119 | + .owner = THIS_MODULE, | |
120 | + .encap = XFRM_MODE_BEET, | |
121 | +}; | |
122 | + | |
123 | +static int __init xfrm4_beet_init(void) | |
124 | +{ | |
125 | + return xfrm_register_mode(&xfrm4_beet_mode, AF_INET); | |
126 | +} | |
127 | + | |
128 | +static void __exit xfrm4_beet_exit(void) | |
129 | +{ | |
130 | + int err; | |
131 | + | |
132 | + err = xfrm_unregister_mode(&xfrm4_beet_mode, AF_INET); | |
133 | + BUG_ON(err); | |
134 | +} | |
135 | + | |
136 | +module_init(xfrm4_beet_init); | |
137 | +module_exit(xfrm4_beet_exit); | |
138 | +MODULE_LICENSE("GPL"); | |
139 | +MODULE_ALIAS_XFRM_MODE(AF_INET, XFRM_MODE_BEET); |
net/ipv6/Kconfig
... | ... | @@ -136,6 +136,16 @@ |
136 | 136 | |
137 | 137 | If unsure, say Y. |
138 | 138 | |
139 | +config INET6_XFRM_MODE_BEET | |
140 | + tristate "IPv6: IPsec BEET mode" | |
141 | + depends on IPV6 | |
142 | + default IPV6 | |
143 | + select XFRM | |
144 | + ---help--- | |
145 | + Support for IPsec BEET mode. | |
146 | + | |
147 | + If unsure, say Y. | |
148 | + | |
139 | 149 | config INET6_XFRM_MODE_ROUTEOPTIMIZATION |
140 | 150 | tristate "IPv6: MIPv6 route optimization mode (EXPERIMENTAL)" |
141 | 151 | depends on IPV6 && EXPERIMENTAL |
net/ipv6/Makefile
... | ... | @@ -26,6 +26,7 @@ |
26 | 26 | obj-$(CONFIG_INET6_XFRM_MODE_TRANSPORT) += xfrm6_mode_transport.o |
27 | 27 | obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o |
28 | 28 | obj-$(CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION) += xfrm6_mode_ro.o |
29 | +obj-$(CONFIG_INET6_XFRM_MODE_BEET) += xfrm6_mode_beet.o | |
29 | 30 | obj-$(CONFIG_NETFILTER) += netfilter/ |
30 | 31 | |
31 | 32 | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o |
net/ipv6/ipcomp6.c
... | ... | @@ -199,6 +199,7 @@ |
199 | 199 | static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x) |
200 | 200 | { |
201 | 201 | struct xfrm_state *t = NULL; |
202 | + u8 mode = XFRM_MODE_TUNNEL; | |
202 | 203 | |
203 | 204 | t = xfrm_state_alloc(); |
204 | 205 | if (!t) |
... | ... | @@ -212,7 +213,9 @@ |
212 | 213 | memcpy(t->id.daddr.a6, x->id.daddr.a6, sizeof(struct in6_addr)); |
213 | 214 | memcpy(&t->sel, &x->sel, sizeof(t->sel)); |
214 | 215 | t->props.family = AF_INET6; |
215 | - t->props.mode = XFRM_MODE_TUNNEL; | |
216 | + if (x->props.mode == XFRM_MODE_BEET) | |
217 | + mode = x->props.mode; | |
218 | + t->props.mode = mode; | |
216 | 219 | memcpy(t->props.saddr.a6, x->props.saddr.a6, sizeof(struct in6_addr)); |
217 | 220 | |
218 | 221 | if (xfrm_init_state(t)) |
net/ipv6/xfrm6_mode_beet.c
1 | +/* | |
2 | + * xfrm6_mode_beet.c - BEET mode encapsulation for IPv6. | |
3 | + * | |
4 | + * Copyright (c) 2006 Diego Beltrami <diego.beltrami@gmail.com> | |
5 | + * Miika Komu <miika@iki.fi> | |
6 | + * Herbert Xu <herbert@gondor.apana.org.au> | |
7 | + * Abhinav Pathak <abhinav.pathak@hiit.fi> | |
8 | + * Jeff Ahrenholz <ahrenholz@gmail.com> | |
9 | + */ | |
10 | + | |
11 | +#include <linux/init.h> | |
12 | +#include <linux/kernel.h> | |
13 | +#include <linux/module.h> | |
14 | +#include <linux/skbuff.h> | |
15 | +#include <linux/stringify.h> | |
16 | +#include <net/dsfield.h> | |
17 | +#include <net/dst.h> | |
18 | +#include <net/inet_ecn.h> | |
19 | +#include <net/ipv6.h> | |
20 | +#include <net/xfrm.h> | |
21 | + | |
22 | +/* Add encapsulation header. | |
23 | + * | |
24 | + * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt. | |
25 | + * The following fields in it shall be filled in by x->type->output: | |
26 | + * payload_len | |
27 | + * | |
28 | + * On exit, skb->h will be set to the start of the encapsulation header to be | |
29 | + * filled in by x->type->output and skb->nh will be set to the nextheader field | |
30 | + * of the extension header directly preceding the encapsulation header, or in | |
31 | + * its absence, that of the top IP header. The value of skb->data will always | |
32 | + * point to the top IP header. | |
33 | + */ | |
34 | +static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb) | |
35 | +{ | |
36 | + struct ipv6hdr *iph, *top_iph; | |
37 | + u8 *prevhdr; | |
38 | + int hdr_len; | |
39 | + | |
40 | + skb_push(skb, x->props.header_len); | |
41 | + iph = skb->nh.ipv6h; | |
42 | + | |
43 | + hdr_len = ip6_find_1stfragopt(skb, &prevhdr); | |
44 | + skb->nh.raw = prevhdr - x->props.header_len; | |
45 | + skb->h.raw = skb->data + hdr_len; | |
46 | + memmove(skb->data, iph, hdr_len); | |
47 | + | |
48 | + skb->nh.raw = skb->data; | |
49 | + top_iph = skb->nh.ipv6h; | |
50 | + skb->nh.raw = &top_iph->nexthdr; | |
51 | + skb->h.ipv6h = top_iph + 1; | |
52 | + | |
53 | + ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr); | |
54 | + ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr); | |
55 | + | |
56 | + return 0; | |
57 | +} | |
58 | + | |
59 | +static int xfrm6_beet_input(struct xfrm_state *x, struct sk_buff *skb) | |
60 | +{ | |
61 | + struct ipv6hdr *ip6h; | |
62 | + int size = sizeof(struct ipv6hdr); | |
63 | + int err = -EINVAL; | |
64 | + | |
65 | + if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) | |
66 | + goto out; | |
67 | + | |
68 | + skb_push(skb, size); | |
69 | + memmove(skb->data, skb->nh.raw, size); | |
70 | + skb->nh.raw = skb->data; | |
71 | + | |
72 | + skb->mac.raw = memmove(skb->data - skb->mac_len, | |
73 | + skb->mac.raw, skb->mac_len); | |
74 | + | |
75 | + ip6h = skb->nh.ipv6h; | |
76 | + ip6h->payload_len = htons(skb->len - size); | |
77 | + ipv6_addr_copy(&ip6h->daddr, (struct in6_addr *) &x->sel.daddr.a6); | |
78 | + ipv6_addr_copy(&ip6h->saddr, (struct in6_addr *) &x->sel.saddr.a6); | |
79 | + err = 0; | |
80 | +out: | |
81 | + return err; | |
82 | +} | |
83 | + | |
84 | +static struct xfrm_mode xfrm6_beet_mode = { | |
85 | + .input = xfrm6_beet_input, | |
86 | + .output = xfrm6_beet_output, | |
87 | + .owner = THIS_MODULE, | |
88 | + .encap = XFRM_MODE_BEET, | |
89 | +}; | |
90 | + | |
91 | +static int __init xfrm6_beet_init(void) | |
92 | +{ | |
93 | + return xfrm_register_mode(&xfrm6_beet_mode, AF_INET6); | |
94 | +} | |
95 | + | |
96 | +static void __exit xfrm6_beet_exit(void) | |
97 | +{ | |
98 | + int err; | |
99 | + | |
100 | + err = xfrm_unregister_mode(&xfrm6_beet_mode, AF_INET6); | |
101 | + BUG_ON(err); | |
102 | +} | |
103 | + | |
104 | +module_init(xfrm6_beet_init); | |
105 | +module_exit(xfrm6_beet_exit); | |
106 | +MODULE_LICENSE("GPL"); | |
107 | +MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_BEET); |