1*fb492c37Smpi /* $OpenBSD: ip_ipip.c,v 1.60 2015/06/16 11:09:40 mpi Exp $ */ 29a570b6dSangelos /* 39a570b6dSangelos * The authors of this code are John Ioannidis (ji@tla.org), 49a570b6dSangelos * Angelos D. Keromytis (kermit@csd.uch.gr) and 59a570b6dSangelos * Niels Provos (provos@physnet.uni-hamburg.de). 69a570b6dSangelos * 7b1efc16cSangelos * The original version of this code was written by John Ioannidis 8b1efc16cSangelos * for BSD/OS in Athens, Greece, in November 1995. 99a570b6dSangelos * 109a570b6dSangelos * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996, 119a570b6dSangelos * by Angelos D. Keromytis. 129a570b6dSangelos * 139a570b6dSangelos * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis 149a570b6dSangelos * and Niels Provos. 159a570b6dSangelos * 169a570b6dSangelos * Additional features in 1999 by Angelos D. Keromytis. 179a570b6dSangelos * 189a570b6dSangelos * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis, 199a570b6dSangelos * Angelos D. Keromytis and Niels Provos. 200775ebe4Sangelos * Copyright (c) 2001, Angelos D. Keromytis. 219a570b6dSangelos * 220775ebe4Sangelos * Permission to use, copy, and modify this software with or without fee 239a570b6dSangelos * is hereby granted, provided that this entire notice is included in 249a570b6dSangelos * all copies of any software which is or includes a copy or 259a570b6dSangelos * modification of this software. 269a570b6dSangelos * You may use this code under the GNU public license if you so wish. Please 279a570b6dSangelos * contribute changes back to the authors under this freer than GPL license 289a570b6dSangelos * so that we may further the use of strong encryption without limitations to 299a570b6dSangelos * all. 309a570b6dSangelos * 319a570b6dSangelos * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR 329a570b6dSangelos * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY 339a570b6dSangelos * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE 349a570b6dSangelos * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR 359a570b6dSangelos * PURPOSE. 369a570b6dSangelos */ 379a570b6dSangelos 389a570b6dSangelos /* 399a570b6dSangelos * IP-inside-IP processing 409a570b6dSangelos */ 419a570b6dSangelos 420c8db51fShenning #include "pf.h" 430c8db51fShenning 449a570b6dSangelos #include <sys/param.h> 4564c11355Sderaadt #include <sys/systm.h> 469a570b6dSangelos #include <sys/mbuf.h> 479a570b6dSangelos #include <sys/socket.h> 489a570b6dSangelos #include <sys/sysctl.h> 499a570b6dSangelos 509a570b6dSangelos #include <net/if.h> 510deb6685Smpi #include <net/if_var.h> 529a570b6dSangelos #include <net/route.h> 539a570b6dSangelos #include <net/netisr.h> 549acf6950Sangelos #include <net/bpf.h> 559a570b6dSangelos 569a570b6dSangelos #include <netinet/in.h> 579a570b6dSangelos #include <netinet/ip.h> 589a570b6dSangelos #include <netinet/in_pcb.h> 599a570b6dSangelos #include <netinet/ip_var.h> 609a570b6dSangelos #include <netinet/ip_ecn.h> 619a570b6dSangelos 629a570b6dSangelos #ifdef MROUTING 639a570b6dSangelos #include <netinet/ip_mroute.h> 649a570b6dSangelos #endif 659a570b6dSangelos 669a570b6dSangelos #include <netinet/ip_ipsp.h> 679a570b6dSangelos #include <netinet/ip_ipip.h> 689a570b6dSangelos 699acf6950Sangelos #include "bpfilter.h" 709acf6950Sangelos 710c8db51fShenning #if NPF > 0 720c8db51fShenning #include <net/pfvar.h> 730c8db51fShenning #endif 740c8db51fShenning 759a570b6dSangelos #ifdef ENCDEBUG 769a570b6dSangelos #define DPRINTF(x) if (encdebug) printf x 779a570b6dSangelos #else 789a570b6dSangelos #define DPRINTF(x) 799a570b6dSangelos #endif 809a570b6dSangelos 819a570b6dSangelos /* 829a570b6dSangelos * We can control the acceptance of IP4 packets by altering the sysctl 839a570b6dSangelos * net.inet.ipip.allow value. Zero means drop them, all else is acceptance. 849a570b6dSangelos */ 859a570b6dSangelos int ipip_allow = 0; 869a570b6dSangelos 879a570b6dSangelos struct ipipstat ipipstat; 889a570b6dSangelos 899a570b6dSangelos #ifdef INET6 909a570b6dSangelos /* 919a570b6dSangelos * Really only a wrapper for ipip_input(), for use with IPv6. 929a570b6dSangelos */ 939a570b6dSangelos int 949a570b6dSangelos ip4_input6(struct mbuf **m, int *offp, int proto) 959a570b6dSangelos { 96ae26b3edSitojun /* If we do not accept IP-in-IP explicitly, drop. */ 976593f73dSangelos if (!ipip_allow && ((*m)->m_flags & (M_AUTH|M_CONF)) == 0) { 989a570b6dSangelos DPRINTF(("ip4_input6(): dropped due to policy\n")); 999a570b6dSangelos ipipstat.ipips_pdrops++; 1009a570b6dSangelos m_freem(*m); 1019a570b6dSangelos return IPPROTO_DONE; 1029a570b6dSangelos } 1039a570b6dSangelos 10421579e10Sclaudio ipip_input(*m, *offp, NULL, proto); 1059a570b6dSangelos return IPPROTO_DONE; 1069a570b6dSangelos } 1079a570b6dSangelos #endif /* INET6 */ 1089a570b6dSangelos 1099a570b6dSangelos /* 1109a570b6dSangelos * Really only a wrapper for ipip_input(), for use with IPv4. 1119a570b6dSangelos */ 1129a570b6dSangelos void 1139a570b6dSangelos ip4_input(struct mbuf *m, ...) 1149a570b6dSangelos { 11521579e10Sclaudio struct ip *ip; 1169a570b6dSangelos va_list ap; 1179a570b6dSangelos int iphlen; 1189a570b6dSangelos 119ae26b3edSitojun /* If we do not accept IP-in-IP explicitly, drop. */ 1206593f73dSangelos if (!ipip_allow && (m->m_flags & (M_AUTH|M_CONF)) == 0) { 1219a570b6dSangelos DPRINTF(("ip4_input(): dropped due to policy\n")); 1229a570b6dSangelos ipipstat.ipips_pdrops++; 1239a570b6dSangelos m_freem(m); 1249a570b6dSangelos return; 1259a570b6dSangelos } 1269a570b6dSangelos 1279a570b6dSangelos va_start(ap, m); 1289a570b6dSangelos iphlen = va_arg(ap, int); 1299a570b6dSangelos va_end(ap); 1309a570b6dSangelos 13121579e10Sclaudio ip = mtod(m, struct ip *); 13221579e10Sclaudio 13321579e10Sclaudio ipip_input(m, iphlen, NULL, ip->ip_p); 1349a570b6dSangelos } 1359a570b6dSangelos 1369a570b6dSangelos /* 1379a570b6dSangelos * ipip_input gets called when we receive an IP{46} encapsulated packet, 1389a570b6dSangelos * either because we got it at a real interface, or because AH or ESP 139*fb492c37Smpi * were being used in tunnel mode (in which case the ph_ifidx element 140*fb492c37Smpi * will contain the index of the encX interface associated with the 141*fb492c37Smpi * tunnel. 1429a570b6dSangelos */ 1439a570b6dSangelos 1449a570b6dSangelos void 14521579e10Sclaudio ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp, int proto) 1469a570b6dSangelos { 14764aa4cc7Sitojun struct sockaddr_in *sin; 14864aa4cc7Sitojun struct ifnet *ifp; 14964aa4cc7Sitojun struct ifaddr *ifa; 15098a920fdSdlg struct niqueue *ifq = NULL; 1519a570b6dSangelos struct ip *ipo; 1527d3e2ec5Sclaudio u_int rdomain; 1539a570b6dSangelos #ifdef INET6 15464aa4cc7Sitojun struct sockaddr_in6 *sin6; 15521579e10Sclaudio struct ip6_hdr *ip6; 1569a570b6dSangelos #endif 15798a920fdSdlg int mode, hlen; 158c9857360Smarkus u_int8_t itos, otos; 1599a570b6dSangelos u_int8_t v; 16021579e10Sclaudio sa_family_t af; 1619a570b6dSangelos 1629a570b6dSangelos ipipstat.ipips_ipackets++; 1639a570b6dSangelos 1649a570b6dSangelos m_copydata(m, 0, 1, &v); 1659a570b6dSangelos 1666593f73dSangelos switch (v >> 4) { 1679a570b6dSangelos case 4: 1689a570b6dSangelos hlen = sizeof(struct ip); 1699a570b6dSangelos break; 1709a570b6dSangelos #ifdef INET6 1719a570b6dSangelos case 6: 1729a570b6dSangelos hlen = sizeof(struct ip6_hdr); 1739a570b6dSangelos break; 1749a570b6dSangelos #endif 175795830a0Sangelos default: 176ae26b3edSitojun ipipstat.ipips_family++; 1779a570b6dSangelos m_freem(m); 1789a570b6dSangelos return /* EAFNOSUPPORT */; 1799a570b6dSangelos } 1809a570b6dSangelos 1819a570b6dSangelos /* Bring the IP header in the first mbuf, if not there already */ 1826593f73dSangelos if (m->m_len < hlen) { 1836593f73dSangelos if ((m = m_pullup(m, hlen)) == NULL) { 1849a570b6dSangelos DPRINTF(("ipip_input(): m_pullup() failed\n")); 1859a570b6dSangelos ipipstat.ipips_hdrops++; 1869a570b6dSangelos return; 1879a570b6dSangelos } 1889a570b6dSangelos } 1899a570b6dSangelos 1909a570b6dSangelos 1916593f73dSangelos /* Keep outer ecn field. */ 192ae26b3edSitojun switch (v >> 4) { 193ae26b3edSitojun case 4: 19421579e10Sclaudio ipo = mtod(m, struct ip *); 1959a570b6dSangelos otos = ipo->ip_tos; 196ae26b3edSitojun break; 1979a570b6dSangelos #ifdef INET6 198ae26b3edSitojun case 6: 19921579e10Sclaudio ip6 = mtod(m, struct ip6_hdr *); 20021579e10Sclaudio otos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 201ae26b3edSitojun break; 2029a570b6dSangelos #endif 203ae26b3edSitojun default: 204ae26b3edSitojun panic("ipip_input: should never reach here"); 205ae26b3edSitojun } 2069a570b6dSangelos 2072b1f9644Sangelos /* Remove outer IP header */ 2089a570b6dSangelos m_adj(m, iphlen); 2099a570b6dSangelos 2106d386255Sangelos /* Sanity check */ 2116d386255Sangelos if (m->m_pkthdr.len < sizeof(struct ip)) { 2126d386255Sangelos ipipstat.ipips_hdrops++; 2136d386255Sangelos m_freem(m); 2146d386255Sangelos return; 2156d386255Sangelos } 2166d386255Sangelos 21721579e10Sclaudio switch (proto) { 21821579e10Sclaudio case IPPROTO_IPV4: 2199a570b6dSangelos hlen = sizeof(struct ip); 2209a570b6dSangelos break; 2219a570b6dSangelos 2229a570b6dSangelos #ifdef INET6 22321579e10Sclaudio case IPPROTO_IPV6: 2249a570b6dSangelos hlen = sizeof(struct ip6_hdr); 2259a570b6dSangelos break; 2269a570b6dSangelos #endif 227ae26b3edSitojun default: 228ae26b3edSitojun ipipstat.ipips_family++; 229ae26b3edSitojun m_freem(m); 230ae26b3edSitojun return; /* EAFNOSUPPORT */ 2319a570b6dSangelos } 2329a570b6dSangelos 2336593f73dSangelos /* 23421579e10Sclaudio * Bring the inner header into the first mbuf, if not there already. 2356593f73dSangelos */ 2366593f73dSangelos if (m->m_len < hlen) { 2376593f73dSangelos if ((m = m_pullup(m, hlen)) == NULL) { 2389a570b6dSangelos DPRINTF(("ipip_input(): m_pullup() failed\n")); 2399a570b6dSangelos ipipstat.ipips_hdrops++; 2409a570b6dSangelos return; 2419a570b6dSangelos } 2429a570b6dSangelos } 2439a570b6dSangelos 2449a570b6dSangelos /* 2459a570b6dSangelos * RFC 1853 specifies that the inner TTL should not be touched on 2469a570b6dSangelos * decapsulation. There's no reason this comment should be here, but 2479a570b6dSangelos * this is as good as any a position. 2489a570b6dSangelos */ 2499a570b6dSangelos 250ae26b3edSitojun /* Some sanity checks in the inner IP header */ 25121579e10Sclaudio switch (proto) { 25221579e10Sclaudio case IPPROTO_IPV4: 2539a570b6dSangelos ipo = mtod(m, struct ip *); 25421579e10Sclaudio #ifdef INET6 25521579e10Sclaudio ip6 = NULL; 25621579e10Sclaudio #endif 257c9857360Smarkus itos = ipo->ip_tos; 258c9857360Smarkus mode = m->m_flags & (M_AUTH|M_CONF) ? 259c9857360Smarkus ECN_ALLOWED_IPSEC : ECN_ALLOWED; 260c9857360Smarkus if (!ip_ecn_egress(mode, &otos, &ipo->ip_tos)) { 261c9857360Smarkus DPRINTF(("ipip_input(): ip_ecn_egress() failed")); 262c9857360Smarkus ipipstat.ipips_pdrops++; 26374e8fb40Skjc m_freem(m); 26474e8fb40Skjc return; 26574e8fb40Skjc } 266c9857360Smarkus /* re-calculate the checksum if ip_tos was changed */ 267c9857360Smarkus if (itos != ipo->ip_tos) { 268c9857360Smarkus hlen = ipo->ip_hl << 2; 269c9857360Smarkus if (m->m_pkthdr.len >= hlen) { 270c9857360Smarkus ipo->ip_sum = 0; 271c9857360Smarkus ipo->ip_sum = in_cksum(m, hlen); 272c9857360Smarkus } 273c9857360Smarkus } 2749a570b6dSangelos break; 2759a570b6dSangelos #ifdef INET6 27621579e10Sclaudio case IPPROTO_IPV6: 27721579e10Sclaudio ipo = NULL; 27821579e10Sclaudio ip6 = mtod(m, struct ip6_hdr *); 2799a570b6dSangelos itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 28074e8fb40Skjc if (!ip_ecn_egress(ECN_ALLOWED, &otos, &itos)) { 281c9857360Smarkus DPRINTF(("ipip_input(): ip_ecn_egress() failed")); 282c9857360Smarkus ipipstat.ipips_pdrops++; 28374e8fb40Skjc m_freem(m); 28474e8fb40Skjc return; 28574e8fb40Skjc } 2869a570b6dSangelos ip6->ip6_flow &= ~htonl(0xff << 20); 2879a570b6dSangelos ip6->ip6_flow |= htonl((u_int32_t) itos << 20); 2889a570b6dSangelos break; 2899a570b6dSangelos #endif 290ae26b3edSitojun default: 29121579e10Sclaudio ipo = NULL; 29221579e10Sclaudio #ifdef INET6 29321579e10Sclaudio ip6 = NULL; 29421579e10Sclaudio #endif 2959a570b6dSangelos } 2969a570b6dSangelos 2979a570b6dSangelos /* Check for local address spoofing. */ 298*fb492c37Smpi if (((ifp = if_get(m->m_pkthdr.ph_ifidx)) == NULL || 299*fb492c37Smpi !(ifp->if_flags & IFF_LOOPBACK)) && ipip_allow != 2) { 3005ee8afe3Smpi rdomain = rtable_l2(m->m_pkthdr.ph_rtableid); 3011573508eSmiod TAILQ_FOREACH(ifp, &ifnet, if_list) { 3027d3e2ec5Sclaudio if (ifp->if_rdomain != rdomain) 30322760f56Sclaudio continue; 3041573508eSmiod TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 3056593f73dSangelos if (ipo) { 3066593f73dSangelos if (ifa->ifa_addr->sa_family != 3076593f73dSangelos AF_INET) 3089a570b6dSangelos continue; 3099a570b6dSangelos 31021579e10Sclaudio sin = (struct sockaddr_in *) 31121579e10Sclaudio ifa->ifa_addr; 3126593f73dSangelos if (sin->sin_addr.s_addr == 3136593f73dSangelos ipo->ip_src.s_addr) { 3149a570b6dSangelos ipipstat.ipips_spoof++; 3159a570b6dSangelos m_freem(m); 3169a570b6dSangelos return; 3179a570b6dSangelos } 3189a570b6dSangelos } 3199a570b6dSangelos #ifdef INET6 3206593f73dSangelos if (ip6) { 3216593f73dSangelos if (ifa->ifa_addr->sa_family != 3226593f73dSangelos AF_INET6) 3239a570b6dSangelos continue; 3249a570b6dSangelos 32521579e10Sclaudio sin6 = (struct sockaddr_in6 *) 32621579e10Sclaudio ifa->ifa_addr; 32721579e10Sclaudio if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 32821579e10Sclaudio &ip6->ip6_src)) { 3296593f73dSangelos ipipstat.ipips_spoof++; 3309a570b6dSangelos m_freem(m); 3319a570b6dSangelos return; 3329a570b6dSangelos } 3339a570b6dSangelos 3349a570b6dSangelos } 3359a570b6dSangelos #endif /* INET6 */ 3369a570b6dSangelos } 3379a570b6dSangelos } 3389a570b6dSangelos } 3399a570b6dSangelos 3409a570b6dSangelos /* Statistics */ 3419a570b6dSangelos ipipstat.ipips_ibytes += m->m_pkthdr.len - iphlen; 3429a570b6dSangelos 3439a570b6dSangelos /* 3449a570b6dSangelos * Interface pointer stays the same; if no IPsec processing has 3459a570b6dSangelos * been done (or will be done), this will point to a normal 3469a570b6dSangelos * interface. Otherwise, it'll point to an enc interface, which 3479a570b6dSangelos * will allow a packet filter to distinguish between secure and 3489a570b6dSangelos * untrusted packets. 3499a570b6dSangelos */ 3509a570b6dSangelos 35121579e10Sclaudio switch (proto) { 35221579e10Sclaudio case IPPROTO_IPV4: 3539a570b6dSangelos ifq = &ipintrq; 35421579e10Sclaudio af = AF_INET; 355ae26b3edSitojun break; 3569a570b6dSangelos #ifdef INET6 35721579e10Sclaudio case IPPROTO_IPV6: 3589a570b6dSangelos ifq = &ip6intrq; 35921579e10Sclaudio af = AF_INET6; 360ae26b3edSitojun break; 361ae26b3edSitojun #endif 362ae26b3edSitojun default: 363ae26b3edSitojun panic("ipip_input: should never reach here"); 3649a570b6dSangelos } 3659a570b6dSangelos 3669acf6950Sangelos #if NBPFILTER > 0 36763df607fSpascoe if (gifp && gifp->if_bpf) 36821579e10Sclaudio bpf_mtap_af(gifp->if_bpf, af, m, BPF_DIRECTION_IN); 3699acf6950Sangelos #endif 3700c8db51fShenning #if NPF > 0 3710c8db51fShenning pf_pkt_addr_changed(m); 3720c8db51fShenning #endif 3739acf6950Sangelos 37498a920fdSdlg if (niq_enqueue(ifq, m) != 0) { 3759a570b6dSangelos ipipstat.ipips_qfull++; 3766593f73dSangelos DPRINTF(("ipip_input(): packet dropped because of full " 3776593f73dSangelos "queue\n")); 3789a570b6dSangelos return; 3799a570b6dSangelos } 3809a570b6dSangelos } 3819a570b6dSangelos 3829a570b6dSangelos int 3830085a3a2Sclaudio ipip_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int dummy, 3840085a3a2Sclaudio int dummy2) 3859a570b6dSangelos { 3869a570b6dSangelos u_int8_t tp, otos; 3879a570b6dSangelos 3889a570b6dSangelos u_int8_t itos; 3899a570b6dSangelos struct ip *ipo; 3909a570b6dSangelos 3919a570b6dSangelos #ifdef INET6 392d5b56032Sitojun struct ip6_hdr *ip6, *ip6o; 3939a570b6dSangelos #endif /* INET6 */ 3943514aacbSmikeb #ifdef ENCDEBUG 3953514aacbSmikeb char buf[INET6_ADDRSTRLEN]; 3963514aacbSmikeb #endif 3979a570b6dSangelos 3986593f73dSangelos /* XXX Deal with empty TDB source/destination addresses. */ 3999a570b6dSangelos 4009a570b6dSangelos m_copydata(m, 0, 1, &tp); 4016593f73dSangelos tp = (tp >> 4) & 0xff; /* Get the IP version number. */ 4029a570b6dSangelos 4036593f73dSangelos switch (tdb->tdb_dst.sa.sa_family) { 4049a570b6dSangelos case AF_INET: 4056593f73dSangelos if (tdb->tdb_src.sa.sa_family != AF_INET || 4066593f73dSangelos tdb->tdb_src.sin.sin_addr.s_addr == INADDR_ANY || 4076593f73dSangelos tdb->tdb_dst.sin.sin_addr.s_addr == INADDR_ANY) { 4086593f73dSangelos 4096593f73dSangelos DPRINTF(("ipip_output(): unspecified tunnel endpoind " 4106593f73dSangelos "address in SA %s/%08x\n", 4113514aacbSmikeb ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)), 4123514aacbSmikeb ntohl(tdb->tdb_spi))); 4136593f73dSangelos 4149a570b6dSangelos ipipstat.ipips_unspec++; 4159a570b6dSangelos m_freem(m); 4169a570b6dSangelos *mp = NULL; 4179a570b6dSangelos return EINVAL; 4189a570b6dSangelos } 4199a570b6dSangelos 4209a570b6dSangelos M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); 42164a3f76cSjsg if (m == NULL) { 4229a570b6dSangelos DPRINTF(("ipip_output(): M_PREPEND failed\n")); 4239a570b6dSangelos ipipstat.ipips_hdrops++; 4249a570b6dSangelos *mp = NULL; 4259a570b6dSangelos return ENOBUFS; 4269a570b6dSangelos } 4279a570b6dSangelos 4289a570b6dSangelos ipo = mtod(m, struct ip *); 4299a570b6dSangelos 4309a570b6dSangelos ipo->ip_v = IPVERSION; 4319a570b6dSangelos ipo->ip_hl = 5; 4329a570b6dSangelos ipo->ip_len = htons(m->m_pkthdr.len); 4339a570b6dSangelos ipo->ip_ttl = ip_defttl; 4349a570b6dSangelos ipo->ip_sum = 0; 4359a570b6dSangelos ipo->ip_src = tdb->tdb_src.sin.sin_addr; 4369a570b6dSangelos ipo->ip_dst = tdb->tdb_dst.sin.sin_addr; 4379a570b6dSangelos 4389a570b6dSangelos /* 4399a570b6dSangelos * We do the htons() to prevent snoopers from determining our 4409a570b6dSangelos * endianness. 4419a570b6dSangelos */ 4429a570b6dSangelos ipo->ip_id = htons(ip_randomid()); 4439a570b6dSangelos 4446593f73dSangelos /* If the inner protocol is IP... */ 4456593f73dSangelos if (tp == IPVERSION) { 4469a570b6dSangelos /* Save ECN notification */ 4476593f73dSangelos m_copydata(m, sizeof(struct ip) + 4486593f73dSangelos offsetof(struct ip, ip_tos), 4499a570b6dSangelos sizeof(u_int8_t), (caddr_t) &itos); 4509a570b6dSangelos 4519a570b6dSangelos ipo->ip_p = IPPROTO_IPIP; 4529a570b6dSangelos 4539a570b6dSangelos /* 4546593f73dSangelos * We should be keeping tunnel soft-state and 4556593f73dSangelos * send back ICMPs if needed. 4569a570b6dSangelos */ 4576593f73dSangelos m_copydata(m, sizeof(struct ip) + 4586593f73dSangelos offsetof(struct ip, ip_off), 4599a570b6dSangelos sizeof(u_int16_t), (caddr_t) &ipo->ip_off); 4606c66c2abSangelos NTOHS(ipo->ip_off); 46170d36f83Sangelos ipo->ip_off &= ~(IP_DF | IP_MF | IP_OFFMASK); 4626c66c2abSangelos HTONS(ipo->ip_off); 4639a570b6dSangelos } 4649a570b6dSangelos #ifdef INET6 4656593f73dSangelos else if (tp == (IPV6_VERSION >> 4)) { 4669a570b6dSangelos u_int32_t itos32; 4676593f73dSangelos 4686593f73dSangelos /* Save ECN notification. */ 4699a570b6dSangelos m_copydata(m, sizeof(struct ip) + 4709a570b6dSangelos offsetof(struct ip6_hdr, ip6_flow), 4719a570b6dSangelos sizeof(u_int32_t), (caddr_t) &itos32); 4729a570b6dSangelos itos = ntohl(itos32) >> 20; 4739a570b6dSangelos ipo->ip_p = IPPROTO_IPV6; 4749a570b6dSangelos ipo->ip_off = 0; 4759a570b6dSangelos } 4769a570b6dSangelos #endif /* INET6 */ 4776593f73dSangelos else { 4789a570b6dSangelos m_freem(m); 4799a570b6dSangelos *mp = NULL; 48005020a09Sangelos ipipstat.ipips_family++; 4819a570b6dSangelos return EAFNOSUPPORT; 4829a570b6dSangelos } 4839a570b6dSangelos 4849a570b6dSangelos otos = 0; 4859a570b6dSangelos ip_ecn_ingress(ECN_ALLOWED, &otos, &itos); 4869a570b6dSangelos ipo->ip_tos = otos; 4879a570b6dSangelos break; 4889a570b6dSangelos 4899a570b6dSangelos #ifdef INET6 4909a570b6dSangelos case AF_INET6: 4919a570b6dSangelos if (IN6_IS_ADDR_UNSPECIFIED(&tdb->tdb_dst.sin6.sin6_addr) || 4926593f73dSangelos tdb->tdb_src.sa.sa_family != AF_INET6 || 4936593f73dSangelos IN6_IS_ADDR_UNSPECIFIED(&tdb->tdb_src.sin6.sin6_addr)) { 4946593f73dSangelos 4956593f73dSangelos DPRINTF(("ipip_output(): unspecified tunnel endpoind " 4966593f73dSangelos "address in SA %s/%08x\n", 4973514aacbSmikeb ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)), 4983514aacbSmikeb ntohl(tdb->tdb_spi))); 4996593f73dSangelos 5009a570b6dSangelos ipipstat.ipips_unspec++; 5019a570b6dSangelos m_freem(m); 5029a570b6dSangelos *mp = NULL; 5039a570b6dSangelos return ENOBUFS; 5049a570b6dSangelos } 5059a570b6dSangelos 506424a21eaStodd /* If the inner protocol is IPv6, clear link local scope */ 507424a21eaStodd if (tp == (IPV6_VERSION >> 4)) { 508d5b56032Sitojun /* scoped address handling */ 509d5b56032Sitojun ip6 = mtod(m, struct ip6_hdr *); 51065b748d4Sitojun if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src)) 511d5b56032Sitojun ip6->ip6_src.s6_addr16[1] = 0; 51265b748d4Sitojun if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst)) 513d5b56032Sitojun ip6->ip6_dst.s6_addr16[1] = 0; 514424a21eaStodd } 515d5b56032Sitojun 5169a570b6dSangelos M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT); 51764a3f76cSjsg if (m == NULL) { 5189a570b6dSangelos DPRINTF(("ipip_output(): M_PREPEND failed\n")); 5199a570b6dSangelos ipipstat.ipips_hdrops++; 5209a570b6dSangelos *mp = NULL; 5219a570b6dSangelos return ENOBUFS; 5229a570b6dSangelos } 5239a570b6dSangelos 5249a570b6dSangelos /* Initialize IPv6 header */ 5259a570b6dSangelos ip6o = mtod(m, struct ip6_hdr *); 5269a570b6dSangelos ip6o->ip6_flow = 0; 5279a570b6dSangelos ip6o->ip6_vfc &= ~IPV6_VERSION_MASK; 5289a570b6dSangelos ip6o->ip6_vfc |= IPV6_VERSION; 529086d35e9Smarkus ip6o->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6o)); 5309a570b6dSangelos ip6o->ip6_hlim = ip_defttl; 53156958091Sitojun in6_embedscope(&ip6o->ip6_src, &tdb->tdb_src.sin6, NULL, NULL); 53256958091Sitojun in6_embedscope(&ip6o->ip6_dst, &tdb->tdb_dst.sin6, NULL, NULL); 5339a570b6dSangelos 5346593f73dSangelos if (tp == IPVERSION) { 5359a570b6dSangelos /* Save ECN notification */ 5369a570b6dSangelos m_copydata(m, sizeof(struct ip6_hdr) + 5379a570b6dSangelos offsetof(struct ip, ip_tos), sizeof(u_int8_t), 5389a570b6dSangelos (caddr_t) &itos); 5399a570b6dSangelos 5406593f73dSangelos /* This is really IPVERSION. */ 5416593f73dSangelos ip6o->ip6_nxt = IPPROTO_IPIP; 5429a570b6dSangelos } 5439a570b6dSangelos else 5446593f73dSangelos if (tp == (IPV6_VERSION >> 4)) { 5459a570b6dSangelos u_int32_t itos32; 5466593f73dSangelos 5476593f73dSangelos /* Save ECN notification. */ 5489a570b6dSangelos m_copydata(m, sizeof(struct ip6_hdr) + 5499a570b6dSangelos offsetof(struct ip6_hdr, ip6_flow), 5509a570b6dSangelos sizeof(u_int32_t), (caddr_t) &itos32); 5519a570b6dSangelos itos = ntohl(itos32) >> 20; 5529a570b6dSangelos 5539a570b6dSangelos ip6o->ip6_nxt = IPPROTO_IPV6; 5546593f73dSangelos } else { 5559a570b6dSangelos m_freem(m); 5569a570b6dSangelos *mp = NULL; 55705020a09Sangelos ipipstat.ipips_family++; 5589a570b6dSangelos return EAFNOSUPPORT; 5599a570b6dSangelos } 5609a570b6dSangelos 5619a570b6dSangelos otos = 0; 5629a570b6dSangelos ip_ecn_ingress(ECN_ALLOWED, &otos, &itos); 5639a570b6dSangelos ip6o->ip6_flow |= htonl((u_int32_t) otos << 20); 5649a570b6dSangelos break; 5659a570b6dSangelos #endif /* INET6 */ 5669a570b6dSangelos 5679a570b6dSangelos default: 5689a570b6dSangelos DPRINTF(("ipip_output(): unsupported protocol family %d\n", 5699a570b6dSangelos tdb->tdb_dst.sa.sa_family)); 5709a570b6dSangelos m_freem(m); 5719a570b6dSangelos *mp = NULL; 5729a570b6dSangelos ipipstat.ipips_family++; 57367a9371aSangelos return EAFNOSUPPORT; 5749a570b6dSangelos } 5759a570b6dSangelos 5769a570b6dSangelos ipipstat.ipips_opackets++; 5779a570b6dSangelos *mp = m; 5789a570b6dSangelos 5796593f73dSangelos if (tdb->tdb_dst.sa.sa_family == AF_INET) { 5809a570b6dSangelos if (tdb->tdb_xform->xf_type == XF_IP4) 5816593f73dSangelos tdb->tdb_cur_bytes += 5826593f73dSangelos m->m_pkthdr.len - sizeof(struct ip); 5839a570b6dSangelos 5849a570b6dSangelos ipipstat.ipips_obytes += m->m_pkthdr.len - sizeof(struct ip); 5859a570b6dSangelos } 5869a570b6dSangelos 5879a570b6dSangelos #ifdef INET6 5886593f73dSangelos if (tdb->tdb_dst.sa.sa_family == AF_INET6) { 5899a570b6dSangelos if (tdb->tdb_xform->xf_type == XF_IP4) 5906593f73dSangelos tdb->tdb_cur_bytes += 5916593f73dSangelos m->m_pkthdr.len - sizeof(struct ip6_hdr); 5929a570b6dSangelos 5936593f73dSangelos ipipstat.ipips_obytes += 5946593f73dSangelos m->m_pkthdr.len - sizeof(struct ip6_hdr); 5959a570b6dSangelos } 5969a570b6dSangelos #endif /* INET6 */ 5979a570b6dSangelos 5989a570b6dSangelos return 0; 5999a570b6dSangelos } 6009a570b6dSangelos 6019a570b6dSangelos #ifdef IPSEC 6029a570b6dSangelos int 6039a570b6dSangelos ipe4_attach() 6049a570b6dSangelos { 6059a570b6dSangelos return 0; 6069a570b6dSangelos } 6079a570b6dSangelos 6089a570b6dSangelos int 6099a570b6dSangelos ipe4_init(struct tdb *tdbp, struct xformsw *xsp, struct ipsecinit *ii) 6109a570b6dSangelos { 6119a570b6dSangelos tdbp->tdb_xform = xsp; 6129a570b6dSangelos return 0; 6139a570b6dSangelos } 6149a570b6dSangelos 6159a570b6dSangelos int 6169a570b6dSangelos ipe4_zeroize(struct tdb *tdbp) 6179a570b6dSangelos { 6189a570b6dSangelos return 0; 6199a570b6dSangelos } 6209a570b6dSangelos 6219a570b6dSangelos void 6229a570b6dSangelos ipe4_input(struct mbuf *m, ...) 6239a570b6dSangelos { 6246593f73dSangelos /* This is a rather serious mistake, so no conditional printing. */ 6259a570b6dSangelos printf("ipe4_input(): should never be called\n"); 6269a570b6dSangelos if (m) 6279a570b6dSangelos m_freem(m); 6289a570b6dSangelos } 6299a570b6dSangelos #endif /* IPSEC */ 6309a570b6dSangelos 6319a570b6dSangelos int 6326593f73dSangelos ipip_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, 6336593f73dSangelos size_t newlen) 6349a570b6dSangelos { 6359a570b6dSangelos /* All sysctl names at this level are terminal. */ 6369a570b6dSangelos if (namelen != 1) 6379a570b6dSangelos return (ENOTDIR); 6389a570b6dSangelos 6399a570b6dSangelos switch (name[0]) { 6409a570b6dSangelos case IPIPCTL_ALLOW: 6419a570b6dSangelos return (sysctl_int(oldp, oldlenp, newp, newlen, &ipip_allow)); 642ab46c28dSderaadt case IPIPCTL_STATS: 643ab46c28dSderaadt if (newp != NULL) 644ab46c28dSderaadt return (EPERM); 645ab46c28dSderaadt return (sysctl_struct(oldp, oldlenp, newp, newlen, 646ab46c28dSderaadt &ipipstat, sizeof(ipipstat))); 6479a570b6dSangelos default: 6489a570b6dSangelos return (ENOPROTOOPT); 6499a570b6dSangelos } 6509a570b6dSangelos /* NOTREACHED */ 6519a570b6dSangelos } 652