ip_encap.c revision 1.2 1 /* $NetBSD: ip_encap.c,v 1.2 2000/07/05 18:45:26 thorpej Exp $ */
2 /* $KAME: ip_encap.c,v 1.30 2000/04/19 04:29:37 itojun Exp $ */
3
4 /*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32 /*
33 * My grandfather said that there's a devil inside tunnelling technology...
34 *
35 * We have surprisingly many protocols that want packets with IP protocol
36 * #4 or #41. Here's a list of protocols that want protocol #41:
37 * RFC1933 configured tunnel
38 * RFC1933 automatic tunnel
39 * RFC2401 IPsec tunnel
40 * RFC2473 IPv6 generic packet tunnelling
41 * RFC2529 6over4 tunnel
42 * mobile-ip6 (uses RFC2473)
43 * 6to4 tunnel
44 * Here's a list of protocol that want protocol #4:
45 * RFC1853 IPv4-in-IPv4 tunnelling
46 * RFC2003 IPv4 encapsulation within IPv4
47 * RFC2344 reverse tunnelling for mobile-ip4
48 * RFC2401 IPsec tunnel
49 * Well, what can I say. They impose different en/decapsulation mechanism
50 * from each other, so they need separate protocol handler. The only one
51 * we can easily determine by protocol # is IPsec, which always has
52 * AH/ESP/IPComp header right after outer IP header.
53 *
54 * So, clearly good old protosw does not work for protocol #4 and #41.
55 * The code will let you match protocol via src/dst address pair.
56 */
57 /* XXX is M_NETADDR correct? */
58
59 #ifdef __FreeBSD__
60 # include "opt_mrouting.h"
61 # if __FreeBSD__ == 3
62 # include "opt_inet.h"
63 # endif
64 # if __FreeBSD__ >= 4
65 # include "opt_inet.h"
66 # include "opt_inet6.h"
67 # endif
68 #else
69 # ifdef __NetBSD__
70 # include "opt_mrouting.h"
71 # include "opt_inet.h"
72 # endif
73 #endif
74
75 #include <sys/param.h>
76 #include <sys/systm.h>
77 #include <sys/socket.h>
78 #include <sys/sockio.h>
79 #include <sys/mbuf.h>
80 #include <sys/errno.h>
81 #include <sys/protosw.h>
82
83 #include <net/if.h>
84 #include <net/route.h>
85
86 #include <netinet/in.h>
87 #include <netinet/in_systm.h>
88 #include <netinet/ip.h>
89 #include <netinet/ip_var.h>
90 #include <netinet/ip_encap.h>
91 #ifdef MROUTING
92 #include <netinet/ip_mroute.h>
93 #endif /* MROUTING */
94 #ifdef __OpenBSD__
95 #include <netinet/ip_ipsp.h>
96 #endif
97
98 #ifdef INET6
99 #include <netinet/ip6.h>
100 #include <netinet6/ip6_var.h>
101 #include <netinet6/ip6protosw.h>
102 #endif
103
104 #include <machine/stdarg.h>
105
106 #ifdef __NetBSD__
107 # include "ipip.h"
108 # if NIPIP > 0
109 # include <netinet/ip_ipip.h>
110 # else
111 # ifdef MROUTING
112 # include <netinet/ip_mroute.h>
113 # endif
114 # endif
115 #endif
116
117 #include <net/net_osdep.h>
118
119 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
120 #include <sys/kernel.h>
121 #include <sys/malloc.h>
122 MALLOC_DEFINE(M_NETADDR, "Export Host", "Export host address structure");
123 #endif
124
125 static void encap_add __P((struct encaptab *));
126 static int mask_match __P((const struct encaptab *, const struct sockaddr *,
127 const struct sockaddr *));
128 static void encap_fillarg __P((struct mbuf *, const struct encaptab *));
129
130 /* rely upon BSS initialization */
131 LIST_HEAD(, encaptab) encaptab = LIST_HEAD_INITIALIZER(&encaptab);
132
133 void
134 encap_init()
135 {
136 #if 0
137 /*
138 * we cannot use LIST_INIT() here, since drivers may want to call
139 * encap_attach(), on driver attach. encap_init() wlil be called
140 * on AF_INET{,6} initialization, which happens after driver
141 * initialization - using LIST_INIT() here can nuke encap_attach()
142 * from drivers.
143 */
144 LIST_INIT(&encaptab);
145 #endif
146 }
147
148 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 4)
149 void
150 #if __STDC__
151 encap4_input(struct mbuf *m, ...)
152 #else
153 encap4_input(m, va_alist)
154 struct mbuf *m;
155 va_dcl
156 #endif
157 {
158 int off, proto;
159 struct ip *ip;
160 struct sockaddr_in s, d;
161 struct encaptab *ep, *match;
162 va_list ap;
163 int prio, matchprio;
164
165 va_start(ap, m);
166 off = va_arg(ap, int);
167 #ifndef __OpenBSD__
168 proto = va_arg(ap, int);
169 #endif
170 va_end(ap);
171
172 ip = mtod(m, struct ip *);
173 #ifdef __OpenBSD__
174 proto = ip->ip_p;
175 #endif
176
177 bzero(&s, sizeof(s));
178 s.sin_family = AF_INET;
179 s.sin_len = sizeof(struct sockaddr_in);
180 s.sin_addr = ip->ip_src;
181 bzero(&d, sizeof(d));
182 d.sin_family = AF_INET;
183 d.sin_len = sizeof(struct sockaddr_in);
184 d.sin_addr = ip->ip_dst;
185
186 match = NULL;
187 matchprio = 0;
188 for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
189 if (ep->af != AF_INET)
190 continue;
191 if (ep->proto >= 0 && ep->proto != proto)
192 continue;
193 if (ep->func)
194 prio = (*ep->func)(m, off, proto, ep->arg);
195 else {
196 /*
197 * it's inbound traffic, we need to match in reverse
198 * order
199 */
200 prio = mask_match(ep, (struct sockaddr *)&d,
201 (struct sockaddr *)&s);
202 }
203
204 /*
205 * We prioritize the matches by using bit length of the
206 * matches. mask_match() and user-supplied matching function
207 * should return the bit length of the matches (for example,
208 * if both src/dst are matched for IPv4, 64 should be returned).
209 * 0 or negative return value means "it did not match".
210 *
211 * The question is, since we have two "mask" portion, we
212 * cannot really define total order between entries.
213 * For example, which of these should be preferred?
214 * mask_match() returns 48 (32 + 16) for both of them.
215 * src=3ffe::/16, dst=3ffe:501::/32
216 * src=3ffe:501::/32, dst=3ffe::/16
217 *
218 * We need to loop through all the possible candidates
219 * to get the best match - the search takes O(n) for
220 * n attachments (i.e. interfaces).
221 */
222 if (prio <= 0)
223 continue;
224 if (prio > matchprio) {
225 matchprio = prio;
226 match = ep;
227 }
228 }
229
230 if (match) {
231 /* found a match, "match" has the best one */
232 if (match->psw && match->psw->pr_input) {
233 encap_fillarg(m, match);
234 (*match->psw->pr_input)(m, off, proto);
235 } else
236 m_freem(m);
237 return;
238 }
239
240 /* backward compatibility clauses */
241 #ifdef MROUTING
242 if (proto == IPPROTO_IPV4 && mrt_ipip_input(m, off)) {
243 /*
244 * Multicast routing code claimed this one. No
245 * more processing at this level.
246 */
247 return;
248 }
249 #endif
250
251 /* last resort: inject to raw socket */
252 rip_input(m, off, proto);
253 }
254 #endif
255
256 #ifdef INET6
257 int
258 encap6_input(mp, offp, proto)
259 struct mbuf **mp;
260 int *offp;
261 int proto;
262 {
263 struct mbuf *m = *mp;
264 struct ip6_hdr *ip6;
265 struct sockaddr_in6 s, d;
266 struct ip6protosw *psw;
267 struct encaptab *ep, *match;
268 int prio, matchprio;
269
270 ip6 = mtod(m, struct ip6_hdr *);
271
272 bzero(&s, sizeof(s));
273 s.sin6_family = AF_INET6;
274 s.sin6_len = sizeof(struct sockaddr_in6);
275 s.sin6_addr = ip6->ip6_src;
276 bzero(&d, sizeof(d));
277 d.sin6_family = AF_INET6;
278 d.sin6_len = sizeof(struct sockaddr_in6);
279 d.sin6_addr = ip6->ip6_dst;
280
281 match = NULL;
282 matchprio = 0;
283 for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
284 if (ep->af != AF_INET6)
285 continue;
286 if (ep->proto >= 0 && ep->proto != proto)
287 continue;
288 if (ep->func)
289 prio = (*ep->func)(m, *offp, proto, ep->arg);
290 else {
291 /*
292 * it's inbound traffic, we need to match in reverse
293 * order
294 */
295 prio = mask_match(ep, (struct sockaddr *)&d,
296 (struct sockaddr *)&s);
297 }
298
299 /* see encap4_input() for issues here */
300 if (prio <= 0)
301 continue;
302 if (prio > matchprio) {
303 matchprio = prio;
304 match = ep;
305 }
306 }
307
308 if (match) {
309 /* found a match */
310 psw = (struct ip6protosw *)match->psw;
311 if (psw && psw->pr_input) {
312 encap_fillarg(m, match);
313 return (*psw->pr_input)(mp, offp, proto);
314 } else {
315 m_freem(m);
316 return IPPROTO_DONE;
317 }
318 }
319
320 /* last resort: inject to raw socket */
321 return rip6_input(mp, offp, proto);
322 }
323 #endif
324
325 static void
326 encap_add(ep)
327 struct encaptab *ep;
328 {
329
330 LIST_INSERT_HEAD(&encaptab, ep, chain);
331 }
332
333 /*
334 * sp (src ptr) is always my side, and dp (dst ptr) is always remote side.
335 * length of mask (sm and dm) is assumed to be same as sp/dp.
336 * Return value will be necessary as input (cookie) for encap_detach().
337 */
338 const struct encaptab *
339 encap_attach(af, proto, sp, sm, dp, dm, psw, arg)
340 int af;
341 int proto;
342 const struct sockaddr *sp, *sm;
343 const struct sockaddr *dp, *dm;
344 const struct protosw *psw;
345 void *arg;
346 {
347 struct encaptab *ep;
348 int error;
349 int s;
350
351 #if defined(__NetBSD__) || defined(__OpenBSD__)
352 s = splsoftnet();
353 #else
354 s = splnet();
355 #endif
356 /* sanity check on args */
357 if (sp->sa_len > sizeof(ep->src) || dp->sa_len > sizeof(ep->dst)) {
358 error = EINVAL;
359 goto fail;
360 }
361 if (sp->sa_len != dp->sa_len) {
362 error = EINVAL;
363 goto fail;
364 }
365 if (af != sp->sa_family || af != dp->sa_family) {
366 error = EINVAL;
367 goto fail;
368 }
369
370 /* check if anyone have already attached with exactly same config */
371 for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
372 if (ep->af != af)
373 continue;
374 if (ep->proto != proto)
375 continue;
376 if (ep->src.ss_len != sp->sa_len ||
377 bcmp(&ep->src, sp, sp->sa_len) != 0 ||
378 bcmp(&ep->srcmask, sm, sp->sa_len) != 0)
379 continue;
380 if (ep->dst.ss_len != dp->sa_len ||
381 bcmp(&ep->dst, dp, dp->sa_len) != 0 ||
382 bcmp(&ep->dstmask, dm, dp->sa_len) != 0)
383 continue;
384
385 error = EEXIST;
386 goto fail;
387 }
388
389 ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT); /*XXX*/
390 if (ep == NULL) {
391 error = ENOBUFS;
392 goto fail;
393 }
394 bzero(ep, sizeof(*ep));
395
396 ep->af = af;
397 ep->proto = proto;
398 bcopy(sp, &ep->src, sp->sa_len);
399 bcopy(sm, &ep->srcmask, sp->sa_len);
400 bcopy(dp, &ep->dst, dp->sa_len);
401 bcopy(dm, &ep->dstmask, dp->sa_len);
402 ep->psw = psw;
403 ep->arg = arg;
404
405 encap_add(ep);
406
407 error = 0;
408 splx(s);
409 return ep;
410
411 fail:
412 splx(s);
413 return NULL;
414 }
415
416 const struct encaptab *
417 encap_attach_func(af, proto, func, psw, arg)
418 int af;
419 int proto;
420 int (*func) __P((const struct mbuf *, int, int, void *));
421 const struct protosw *psw;
422 void *arg;
423 {
424 struct encaptab *ep;
425 int error;
426 int s;
427
428 #if defined(__NetBSD__) || defined(__OpenBSD__)
429 s = splsoftnet();
430 #else
431 s = splnet();
432 #endif
433 /* sanity check on args */
434 if (!func) {
435 error = EINVAL;
436 goto fail;
437 }
438
439 ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT); /*XXX*/
440 if (ep == NULL) {
441 error = ENOBUFS;
442 goto fail;
443 }
444 bzero(ep, sizeof(*ep));
445
446 ep->af = af;
447 ep->proto = proto;
448 ep->func = func;
449 ep->psw = psw;
450 ep->arg = arg;
451
452 encap_add(ep);
453
454 error = 0;
455 splx(s);
456 return ep;
457
458 fail:
459 splx(s);
460 return NULL;
461 }
462
463 int
464 encap_detach(cookie)
465 const struct encaptab *cookie;
466 {
467 const struct encaptab *ep = cookie;
468 struct encaptab *p;
469
470 for (p = LIST_FIRST(&encaptab); p; p = LIST_NEXT(p, chain)) {
471 if (p == ep) {
472 LIST_REMOVE(p, chain);
473 free(p, M_NETADDR); /*XXX*/
474 return 0;
475 }
476 }
477
478 return EINVAL;
479 }
480
481 static int
482 mask_match(ep, sp, dp)
483 const struct encaptab *ep;
484 const struct sockaddr *sp;
485 const struct sockaddr *dp;
486 {
487 struct sockaddr_storage s;
488 struct sockaddr_storage d;
489 int i;
490 u_int8_t *p, *q, *r;
491 int matchlen;
492
493 if (sp->sa_len > sizeof(s) || dp->sa_len > sizeof(d))
494 return 0;
495 if (sp->sa_family != ep->af || dp->sa_family != ep->af)
496 return 0;
497 if (sp->sa_len != ep->src.ss_len || dp->sa_len != ep->dst.ss_len)
498 return 0;
499
500 matchlen = 0;
501
502 p = (u_int8_t *)sp;
503 q = (u_int8_t *)&ep->srcmask;
504 r = (u_int8_t *)&s;
505 for (i = 0 ; i < sp->sa_len; i++) {
506 r[i] = p[i] & q[i];
507 /* XXX estimate */
508 matchlen += (q[i] ? 8 : 0);
509 }
510
511 p = (u_int8_t *)dp;
512 q = (u_int8_t *)&ep->dstmask;
513 r = (u_int8_t *)&d;
514 for (i = 0 ; i < dp->sa_len; i++) {
515 r[i] = p[i] & q[i];
516 /* XXX rough estimate */
517 matchlen += (q[i] ? 8 : 0);
518 }
519
520 /* need to overwrite len/family portion as we don't compare them */
521 s.ss_len = sp->sa_len;
522 s.ss_family = sp->sa_family;
523 d.ss_len = dp->sa_len;
524 d.ss_family = dp->sa_family;
525
526 if (bcmp(&s, &ep->src, ep->src.ss_len) == 0 &&
527 bcmp(&d, &ep->dst, ep->dst.ss_len) == 0) {
528 return matchlen;
529 } else
530 return 0;
531 }
532
533 static void
534 encap_fillarg(m, ep)
535 struct mbuf *m;
536 const struct encaptab *ep;
537 {
538 #if 0
539 m->m_pkthdr.aux = ep->arg;
540 #else
541 struct mbuf *n;
542
543 n = m_aux_add(m, AF_INET, IPPROTO_IPV4);
544 if (n) {
545 *mtod(n, void **) = ep->arg;
546 n->m_len = sizeof(void *);
547 }
548 #endif
549 }
550
551 void *
552 encap_getarg(m)
553 struct mbuf *m;
554 {
555 void *p;
556 #if 0
557 p = m->m_pkthdr.aux;
558 m->m_pkthdr.aux = NULL;
559 return p;
560 #else
561 struct mbuf *n;
562
563 p = NULL;
564 n = m_aux_find(m, AF_INET, IPPROTO_IPV4);
565 if (n) {
566 if (n->m_len == sizeof(void *))
567 p = *mtod(n, void **);
568 m_aux_delete(m, n);
569 }
570 return p;
571 #endif
572 }
573