1 /* $OpenBSD: if_gre.c,v 1.7 2001/01/17 19:50:14 angelos Exp $ */ 2 /* $NetBSD: if_gre.c,v 1.9 1999/10/25 19:18:11 drochner Exp $ */ 3 4 /* 5 * Copyright (c) 1998 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Heiko W.Rupp <hwr@pilhuhn.de> 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * Encapsulate L3 protocols into IP, per RFC 1701 and 1702. 42 * See gre(4) for more details. 43 * Also supported: IP in IP encapsulation (proto 55) per RFC 2004. 44 */ 45 46 #include "gre.h" 47 #if NGRE > 0 48 49 #include "bpfilter.h" 50 51 #include <sys/param.h> 52 #include <sys/proc.h> 53 #include <sys/mbuf.h> 54 #include <sys/socket.h> 55 #include <sys/sockio.h> 56 #include <sys/kernel.h> 57 #include <sys/systm.h> 58 59 #include <net/if.h> 60 #include <net/if_types.h> 61 #include <net/netisr.h> 62 #include <net/route.h> 63 64 #ifdef INET 65 #include <netinet/in.h> 66 #include <netinet/in_systm.h> 67 #include <netinet/in_var.h> 68 #include <netinet/ip.h> 69 #include <netinet/ip_var.h> 70 #include <netinet/if_ether.h> 71 #else 72 #error "if_gre used without inet" 73 #endif 74 75 #ifdef NS 76 #include <netns/ns.h> 77 #include <netns/ns_if.h> 78 #endif 79 80 #ifdef NETATALK 81 #include <netatalk/at.h> 82 #include <netatalk/at_var.h> 83 #include <netatalk/at_extern.h> 84 #endif 85 86 #if NBPFILTER > 0 87 #include <net/bpf.h> 88 #endif 89 90 #include <net/if_gre.h> 91 92 #ifndef GRE_RECURSION_LIMIT 93 #define GRE_RECURSION_LIMIT 3 /* How many levels of recursion allowed */ 94 #endif /* GRE_RECURSION_LIMIT */ 95 96 #define GREMTU 1450 /* XXX this is below the standard MTU of 97 1500 Bytes, allowing for headers, 98 but we should possibly do path mtu discovery 99 before changing if state to up to find the 100 correct value */ 101 102 #define LINK_MASK (IFF_LINK0|IFF_LINK1|IFF_LINK2) 103 104 struct gre_softc gre_softc[NGRE]; 105 106 /* 107 * We can control the acceptance of GRE and MobileIP packets by 108 * altering the sysctl net.inet.gre.allow and net.inet.mobileip.allow values 109 * respectively. Zero means drop them, all else is acceptance. 110 */ 111 int gre_allow = 0; 112 int ip_mobile_allow = 0; 113 114 static void gre_compute_route(struct gre_softc *sc); 115 116 void 117 greattach(void) 118 { 119 struct gre_softc *sc; 120 int i; 121 122 for (i = 0, sc = gre_softc ; i < NGRE ; sc++ ) { 123 snprintf(sc->sc_if.if_xname, sizeof(sc->sc_if.if_xname), 124 "gre%d", i++); 125 sc->sc_if.if_softc = sc; 126 sc->sc_if.if_type = IFT_OTHER; 127 sc->sc_if.if_addrlen = 4; 128 sc->sc_if.if_hdrlen = 24; /* IP + GRE */ 129 sc->sc_if.if_mtu = GREMTU; 130 sc->sc_if.if_flags = IFF_POINTOPOINT|IFF_MULTICAST; 131 sc->sc_if.if_output = gre_output; 132 sc->sc_if.if_ioctl = gre_ioctl; 133 sc->sc_if.if_collisions = 0; 134 sc->sc_if.if_ierrors = 0; 135 sc->sc_if.if_oerrors = 0; 136 sc->sc_if.if_ipackets = 0; 137 sc->sc_if.if_opackets = 0; 138 sc->g_dst.s_addr = sc->g_src.s_addr = INADDR_ANY; 139 sc->g_proto = IPPROTO_GRE; 140 141 if_attach(&sc->sc_if); 142 143 #if NBPFILTER > 0 144 bpfattach(&sc->sc_if.if_bpf, &sc->sc_if, DLT_RAW, 145 sizeof(u_int32_t) ); 146 #endif 147 } 148 } 149 150 /* 151 * The output routine. Takes a packet and encapsulates it in the protocol 152 * given by sc->g_proto. See also RFC 1701 and RFC 2004. 153 */ 154 155 int 156 gre_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 157 struct rtentry *rt) 158 { 159 int error = 0; 160 struct gre_softc *sc = (struct gre_softc *) (ifp->if_softc); 161 struct greip *gh = NULL; 162 struct ip *inp = NULL; 163 u_short etype = 0; 164 struct mobile_h mob_h; 165 static int recursions = 0; /* XXX MUTEX */ 166 167 /* Try to limit infinite recursion through misconfiguration */ 168 if (++recursions >= GRE_RECURSION_LIMIT) { 169 IF_DROP(&ifp->if_snd); 170 m_freem(m); 171 recursions = 0; 172 return (EIO); /* Use the same as in if_gif.c */ 173 } 174 175 #if NBPFILTER >0 176 if (ifp->if_bpf) 177 bpf_mtap(ifp->if_bpf, m); 178 #endif 179 180 if (sc->g_proto == IPPROTO_MOBILE) { 181 if (ip_mobile_allow == 0) { 182 IF_DROP(&ifp->if_snd); 183 m_freem(m); 184 recursions = 0; 185 return (EACCES); 186 } 187 188 if (dst->sa_family == AF_INET) { 189 struct mbuf *m0; 190 int msiz; 191 192 /* 193 * Make sure the complete IP header (with options) 194 * is in the first mbuf. 195 */ 196 if (m->m_len < sizeof(struct ip)) 197 { 198 m = m_pullup(m, sizeof(struct ip)); 199 if (m == 0) { 200 IF_DROP(&ifp->if_snd); 201 recursions = 0; 202 return (ENOBUFS); 203 } 204 else 205 inp = mtod(m, struct ip *); 206 207 if (m->m_len < inp->ip_hl << 2) { 208 m = m_pullup(m, 209 sizeof(inp->ip_hl << 2)); 210 if (m == 0) { 211 IF_DROP(&ifp->if_snd); 212 recursions = 0; 213 return (ENOBUFS); 214 } 215 } 216 } 217 218 inp = mtod(m, struct ip *); 219 220 bzero(&mob_h, MOB_H_SIZ_L); 221 mob_h.proto = (inp->ip_p) << 8; 222 mob_h.odst = inp->ip_dst.s_addr; 223 inp->ip_dst.s_addr = sc->g_dst.s_addr; 224 225 /* 226 * If the packet comes from our host, we only change 227 * the destination address in the IP header. 228 * Otherwise we need to save and change the source. 229 */ 230 if (inp->ip_src.s_addr == sc->g_src.s_addr) { 231 msiz = MOB_H_SIZ_S; 232 } else { 233 mob_h.proto |= MOB_H_SBIT; 234 mob_h.osrc = inp->ip_src.s_addr; 235 inp->ip_src.s_addr = sc->g_src.s_addr; 236 msiz = MOB_H_SIZ_L; 237 } 238 239 HTONS(mob_h.proto); 240 mob_h.hcrc = gre_in_cksum((u_short *) &mob_h, msiz); 241 242 /* Squeeze in the mobility header */ 243 if ((m->m_data - msiz) < m->m_pktdat) { 244 /* Need new mbuf */ 245 MGETHDR(m0, M_DONTWAIT, MT_HEADER); 246 if (m0 == NULL) { 247 IF_DROP(&ifp->if_snd); 248 m_freem(m); 249 recursions = 0; 250 return (ENOBUFS); 251 } 252 253 m0->m_len = msiz + (inp->ip_hl << 2); 254 m0->m_data += max_linkhdr; 255 m0->m_pkthdr.len = m->m_pkthdr.len + msiz; 256 m->m_data += inp->ip_hl << 2; 257 m->m_len -= inp->ip_hl << 2; 258 259 bcopy((caddr_t) inp, mtod(m0, caddr_t), 260 sizeof(struct ip)); 261 262 m0->m_next = m; 263 m = m0; 264 } else { /* we have some space left in the old one */ 265 m->m_data -= msiz; 266 m->m_len += msiz; 267 m->m_pkthdr.len += msiz; 268 bcopy(inp, mtod(m, caddr_t), 269 inp->ip_hl << 2); 270 } 271 272 /* Copy Mobility header */ 273 inp = mtod(m, struct ip *); 274 bcopy(&mob_h, (caddr_t)(inp + 1), (unsigned) msiz); 275 NTOHS(inp->ip_len); 276 inp->ip_len += msiz; 277 } else { /* AF_INET */ 278 IF_DROP(&ifp->if_snd); 279 m_freem(m); 280 recursions = 0; 281 return (EINVAL); 282 } 283 } else if (sc->g_proto == IPPROTO_GRE) { 284 if (gre_allow == 0) { 285 IF_DROP(&ifp->if_snd); 286 m_freem(m); 287 recursions = 0; 288 return (EACCES); 289 } 290 291 switch(dst->sa_family) { 292 case AF_INET: 293 if (m->m_len < sizeof(struct ip)) { 294 m = m_pullup(m, sizeof(struct ip)); 295 if (m == 0) { 296 IF_DROP(&ifp->if_snd); 297 recursions = 0; 298 return (ENOBUFS); 299 } 300 } 301 302 inp = mtod(m, struct ip *); 303 etype = ETHERTYPE_IP; 304 break; 305 #ifdef NETATALK 306 case AF_APPLETALK: 307 etype = ETHERTYPE_AT; 308 break; 309 #endif 310 #ifdef NS 311 case AF_NS: 312 etype = ETHERTYPE_NS; 313 break; 314 #endif 315 default: 316 IF_DROP(&ifp->if_snd); 317 m_freem(m); 318 recursions = 0; 319 return (EAFNOSUPPORT); 320 } 321 322 M_PREPEND(m, sizeof(struct greip), M_DONTWAIT); 323 } else { 324 error = EINVAL; 325 IF_DROP(&ifp->if_snd); 326 m_freem(m); 327 recursions = 0; 328 return (error); 329 } 330 331 if (m == NULL) { 332 IF_DROP(&ifp->if_snd); 333 recursions = 0; 334 return (ENOBUFS); 335 } 336 337 gh = mtod(m, struct greip *); 338 if (sc->g_proto == IPPROTO_GRE) { 339 /* We don't support any GRE flags for now */ 340 341 bzero((void *) &gh->gi_g, sizeof(struct gre_h)); 342 gh->gi_ptype = htons(etype); 343 } 344 345 gh->gi_pr = sc->g_proto; 346 if (sc->g_proto != IPPROTO_MOBILE) { 347 gh->gi_src = sc->g_src; 348 gh->gi_dst = sc->g_dst; 349 ((struct ip *) gh)->ip_hl = (sizeof(struct ip)) >> 2; 350 ((struct ip *) gh)->ip_ttl = ip_defttl; 351 ((struct ip *) gh)->ip_tos = inp->ip_tos; 352 gh->gi_len = m->m_pkthdr.len; 353 } 354 355 ifp->if_opackets++; 356 ifp->if_obytes += m->m_pkthdr.len; 357 358 /* Send it off */ 359 error = ip_output(m, NULL, &sc->route, 0, NULL, NULL); 360 if (error) 361 ifp->if_oerrors++; 362 recursions = 0; 363 return (error); 364 } 365 366 int 367 gre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 368 { 369 370 struct ifaddr *ifa = (struct ifaddr *) data; 371 struct ifreq *ifr = (struct ifreq *) data; 372 struct in_ifaddr *ia = (struct in_ifaddr *) data; 373 struct gre_softc *sc = ifp->if_softc; 374 int s; 375 struct sockaddr_in si; 376 struct sockaddr *sa = NULL; 377 int error = 0; 378 struct proc *prc = curproc; /* XXX */ 379 380 s = splimp(); 381 switch(cmd) { 382 case SIOCSIFADDR: 383 case SIOCSIFDSTADDR: 384 /* 385 * set tunnel endpoints in case that we "only" 386 * have ip over ip encapsulation. This allows to 387 * set tunnel endpoints with ifconfig. 388 */ 389 if (ifa->ifa_addr->sa_family == AF_INET) { 390 sa = ifa->ifa_addr; 391 sc->g_src = (satosin(sa))->sin_addr; 392 sc->g_dst = ia->ia_dstaddr.sin_addr; 393 if ((sc->g_src.s_addr != INADDR_ANY) && 394 (sc->g_dst.s_addr != INADDR_ANY)) { 395 if (sc->route.ro_rt != 0) { 396 /* free old route */ 397 RTFREE(sc->route.ro_rt); 398 sc->route.ro_rt = (struct rtentry *) 0; 399 } 400 401 gre_compute_route(sc); 402 if (sc->route.ro_rt == 0) { 403 sc->g_src.s_addr = INADDR_ANY; 404 sc->g_dst.s_addr = INADDR_ANY; 405 return EIO; /* Is this is good ? */ 406 } 407 408 ifp->if_flags |= IFF_UP; 409 } 410 } 411 break; 412 case SIOCSIFFLAGS: 413 if ((sc->g_dst.s_addr == INADDR_ANY) || 414 (sc->g_src.s_addr == INADDR_ANY)) 415 ifp->if_flags &= ~IFF_UP; 416 417 switch(ifr->ifr_flags & LINK_MASK) { 418 case IFF_LINK0: 419 sc->g_proto = IPPROTO_GRE; 420 ifp->if_flags |= IFF_LINK0; 421 ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2); 422 break; 423 case IFF_LINK2: 424 sc->g_proto = IPPROTO_MOBILE; 425 ifp->if_flags |= IFF_LINK2; 426 ifp->if_flags &= ~(IFF_LINK0|IFF_LINK1); 427 break; 428 } 429 break; 430 case SIOCADDMULTI: 431 case SIOCDELMULTI: 432 if (ifr == 0) { 433 error = EAFNOSUPPORT; 434 break; 435 } 436 switch (ifr->ifr_addr.sa_family) { 437 #ifdef INET 438 case AF_INET: 439 break; 440 #endif 441 default: 442 error = EAFNOSUPPORT; 443 break; 444 } 445 break; 446 case GRESPROTO: 447 /* Check for superuser */ 448 if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0) 449 break; 450 451 sc->g_proto = ifr->ifr_flags; 452 switch (sc->g_proto) { 453 case IPPROTO_GRE : 454 ifp->if_flags |= IFF_LINK0; 455 ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2); 456 break; 457 case IPPROTO_MOBILE : 458 ifp->if_flags |= IFF_LINK2; 459 ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2); 460 break; 461 default: 462 ifp->if_flags &= ~(IFF_LINK0|IFF_LINK1|IFF_LINK2); 463 } 464 break; 465 case GREGPROTO: 466 ifr->ifr_flags = sc->g_proto; 467 break; 468 case GRESADDRS: 469 case GRESADDRD: 470 /* Check for superuser */ 471 if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0) 472 break; 473 474 /* 475 * set tunnel endpoints, compute a less specific route 476 * to the remote end and mark if as up 477 */ 478 sa = &ifr->ifr_addr; 479 if (cmd == GRESADDRS ) 480 sc->g_src = (satosin(sa))->sin_addr; 481 if (cmd == GRESADDRD ) 482 sc->g_dst = (satosin(sa))->sin_addr; 483 if ((sc->g_src.s_addr != INADDR_ANY) && 484 (sc->g_dst.s_addr != INADDR_ANY)) { 485 if (sc->route.ro_rt != 0) { 486 /* free old route */ 487 RTFREE(sc->route.ro_rt); 488 sc->route.ro_rt = (struct rtentry *) 0; 489 } 490 491 gre_compute_route(sc); 492 if (sc->route.ro_rt == 0) 493 { 494 sc->g_src.s_addr = INADDR_ANY; 495 sc->g_dst.s_addr = INADDR_ANY; 496 return EIO; /* Is this is good ? */ 497 } 498 ifp->if_flags |= IFF_UP; 499 } 500 break; 501 case GREGADDRS: 502 si.sin_addr.s_addr = sc->g_src.s_addr; 503 sa = sintosa(&si); 504 ifr->ifr_addr = *sa; 505 break; 506 case GREGADDRD: 507 si.sin_addr.s_addr = sc->g_dst.s_addr; 508 sa = sintosa(&si); 509 ifr->ifr_addr = *sa; 510 break; 511 default: 512 error = EINVAL; 513 } 514 515 splx(s); 516 return (error); 517 } 518 519 /* 520 * computes a route to our destination that is not the one 521 * which would be taken by ip_output(), as this one will loop back to 522 * us. If the interface is p2p as a--->b, then a routing entry exists 523 * If we now send a packet to b (e.g. ping b), this will come down here 524 * gets src=a, dst=b tacked on and would from ip_ouput() sent back to 525 * if_gre. 526 * Goal here is to compute a route to b that is less specific than 527 * a-->b. We know that this one exists as in normal operation we have 528 * at least a default route which matches. 529 */ 530 531 static void 532 gre_compute_route(struct gre_softc *sc) 533 { 534 struct route *ro; 535 u_int32_t a, b, c; 536 537 ro = &sc->route; 538 539 bzero(ro, sizeof(struct route)); 540 ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = sc->g_dst; 541 ro->ro_dst.sa_family = AF_INET; 542 ro->ro_dst.sa_len = sizeof(ro->ro_dst); 543 544 /* 545 * toggle last bit, so our interface is not found, but a less 546 * specific route. I'd rather like to specify a shorter mask, 547 * but this is not possible. Should work though. XXX 548 * there is a simpler way ... 549 */ 550 if ((sc->sc_if.if_flags & IFF_LINK1) == 0) { 551 a = ntohl(sc->g_dst.s_addr); 552 b = a & 0x01; 553 c = a & 0xfffffffe; 554 b = b ^ 0x01; 555 a = b | c; 556 ((struct sockaddr_in *) &ro->ro_dst)->sin_addr.s_addr = htonl(a); 557 } 558 559 rtalloc(ro); 560 if (ro->ro_rt == 0) 561 return; 562 563 /* 564 * Check whether we just created a loop. An even more paranoid 565 * check would be against all GRE interfaces, but that would 566 * not allow people to link GRE tunnels. 567 */ 568 if (ro->ro_rt->rt_ifp == &sc->sc_if) { 569 RTFREE(ro->ro_rt); 570 ro->ro_rt = (struct rtentry *) 0; 571 return; 572 } 573 574 /* 575 * now change it back - else ip_output will just drop 576 * the route and search one to this interface ... 577 */ 578 if ((sc->sc_if.if_flags & IFF_LINK1) == 0) 579 ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = sc->g_dst; 580 } 581 582 /* 583 * do a checksum of a buffer - much like in_cksum, which operates on 584 * mbufs. 585 */ 586 587 u_short 588 gre_in_cksum(u_short *p, u_int len) 589 { 590 u_int sum = 0; 591 int nwords = len >> 1; 592 593 while (nwords-- != 0) 594 sum += *p++; 595 596 if (len & 1) { 597 union { 598 u_short w; 599 u_char c[2]; 600 } u; 601 u.c[0] = *(u_char *) p; 602 u.c[1] = 0; 603 sum += u.w; 604 } 605 606 /* end-around-carry */ 607 sum = (sum >> 16) + (sum & 0xffff); 608 sum += (sum >> 16); 609 return (~sum); 610 } 611 #endif 612