1 /* $NetBSD: ip_encap.c,v 1.1 2000/04/19 06:30:54 itojun 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; 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