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