1 /* $NetBSD: ip_encap.c,v 1.3 2000/07/05 21:32:51 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 /* 390 * XXX NEED TO CHECK viftable IN THE ip_mroute CODE!!! 391 * XXX Actually, that code needs to be replaced with 392 * XXX new code that uses `gif' tunnels. 393 */ 394 395 ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT); /*XXX*/ 396 if (ep == NULL) { 397 error = ENOBUFS; 398 goto fail; 399 } 400 bzero(ep, sizeof(*ep)); 401 402 ep->af = af; 403 ep->proto = proto; 404 bcopy(sp, &ep->src, sp->sa_len); 405 bcopy(sm, &ep->srcmask, sp->sa_len); 406 bcopy(dp, &ep->dst, dp->sa_len); 407 bcopy(dm, &ep->dstmask, dp->sa_len); 408 ep->psw = psw; 409 ep->arg = arg; 410 411 encap_add(ep); 412 413 error = 0; 414 splx(s); 415 return ep; 416 417 fail: 418 splx(s); 419 return NULL; 420 } 421 422 const struct encaptab * 423 encap_attach_func(af, proto, func, psw, arg) 424 int af; 425 int proto; 426 int (*func) __P((const struct mbuf *, int, int, void *)); 427 const struct protosw *psw; 428 void *arg; 429 { 430 struct encaptab *ep; 431 int error; 432 int s; 433 434 #if defined(__NetBSD__) || defined(__OpenBSD__) 435 s = splsoftnet(); 436 #else 437 s = splnet(); 438 #endif 439 /* sanity check on args */ 440 if (!func) { 441 error = EINVAL; 442 goto fail; 443 } 444 445 ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT); /*XXX*/ 446 if (ep == NULL) { 447 error = ENOBUFS; 448 goto fail; 449 } 450 bzero(ep, sizeof(*ep)); 451 452 ep->af = af; 453 ep->proto = proto; 454 ep->func = func; 455 ep->psw = psw; 456 ep->arg = arg; 457 458 encap_add(ep); 459 460 error = 0; 461 splx(s); 462 return ep; 463 464 fail: 465 splx(s); 466 return NULL; 467 } 468 469 int 470 encap_detach(cookie) 471 const struct encaptab *cookie; 472 { 473 const struct encaptab *ep = cookie; 474 struct encaptab *p; 475 476 for (p = LIST_FIRST(&encaptab); p; p = LIST_NEXT(p, chain)) { 477 if (p == ep) { 478 LIST_REMOVE(p, chain); 479 free(p, M_NETADDR); /*XXX*/ 480 return 0; 481 } 482 } 483 484 return EINVAL; 485 } 486 487 static int 488 mask_match(ep, sp, dp) 489 const struct encaptab *ep; 490 const struct sockaddr *sp; 491 const struct sockaddr *dp; 492 { 493 struct sockaddr_storage s; 494 struct sockaddr_storage d; 495 int i; 496 u_int8_t *p, *q, *r; 497 int matchlen; 498 499 if (sp->sa_len > sizeof(s) || dp->sa_len > sizeof(d)) 500 return 0; 501 if (sp->sa_family != ep->af || dp->sa_family != ep->af) 502 return 0; 503 if (sp->sa_len != ep->src.ss_len || dp->sa_len != ep->dst.ss_len) 504 return 0; 505 506 matchlen = 0; 507 508 p = (u_int8_t *)sp; 509 q = (u_int8_t *)&ep->srcmask; 510 r = (u_int8_t *)&s; 511 for (i = 0 ; i < sp->sa_len; i++) { 512 r[i] = p[i] & q[i]; 513 /* XXX estimate */ 514 matchlen += (q[i] ? 8 : 0); 515 } 516 517 p = (u_int8_t *)dp; 518 q = (u_int8_t *)&ep->dstmask; 519 r = (u_int8_t *)&d; 520 for (i = 0 ; i < dp->sa_len; i++) { 521 r[i] = p[i] & q[i]; 522 /* XXX rough estimate */ 523 matchlen += (q[i] ? 8 : 0); 524 } 525 526 /* need to overwrite len/family portion as we don't compare them */ 527 s.ss_len = sp->sa_len; 528 s.ss_family = sp->sa_family; 529 d.ss_len = dp->sa_len; 530 d.ss_family = dp->sa_family; 531 532 if (bcmp(&s, &ep->src, ep->src.ss_len) == 0 && 533 bcmp(&d, &ep->dst, ep->dst.ss_len) == 0) { 534 return matchlen; 535 } else 536 return 0; 537 } 538 539 static void 540 encap_fillarg(m, ep) 541 struct mbuf *m; 542 const struct encaptab *ep; 543 { 544 #if 0 545 m->m_pkthdr.aux = ep->arg; 546 #else 547 struct mbuf *n; 548 549 n = m_aux_add(m, AF_INET, IPPROTO_IPV4); 550 if (n) { 551 *mtod(n, void **) = ep->arg; 552 n->m_len = sizeof(void *); 553 } 554 #endif 555 } 556 557 void * 558 encap_getarg(m) 559 struct mbuf *m; 560 { 561 void *p; 562 #if 0 563 p = m->m_pkthdr.aux; 564 m->m_pkthdr.aux = NULL; 565 return p; 566 #else 567 struct mbuf *n; 568 569 p = NULL; 570 n = m_aux_find(m, AF_INET, IPPROTO_IPV4); 571 if (n) { 572 if (n->m_len == sizeof(void *)) 573 p = *mtod(n, void **); 574 m_aux_delete(m, n); 575 } 576 return p; 577 #endif 578 } 579