1*c9857360Smarkus /* $OpenBSD: ip_ipip.c,v 1.48 2012/03/15 16:37:11 markus 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> 489b074ffaStedu #include <sys/proc.h> 499a570b6dSangelos #include <sys/sysctl.h> 509a570b6dSangelos 519a570b6dSangelos #include <net/if.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/in_systm.h> 589a570b6dSangelos #include <netinet/ip.h> 599a570b6dSangelos #include <netinet/in_pcb.h> 609a570b6dSangelos #include <netinet/in_var.h> 619a570b6dSangelos #include <netinet/ip_var.h> 629a570b6dSangelos #include <netinet/ip_ecn.h> 639a570b6dSangelos 649a570b6dSangelos #ifdef MROUTING 659a570b6dSangelos #include <netinet/ip_mroute.h> 669a570b6dSangelos #endif 679a570b6dSangelos 689a570b6dSangelos #include <netinet/ip_ipsp.h> 699a570b6dSangelos #include <netinet/ip_ipip.h> 709a570b6dSangelos 719acf6950Sangelos #include "bpfilter.h" 729acf6950Sangelos 730c8db51fShenning #if NPF > 0 740c8db51fShenning #include <net/pfvar.h> 750c8db51fShenning #endif 760c8db51fShenning 779a570b6dSangelos #ifdef ENCDEBUG 789a570b6dSangelos #define DPRINTF(x) if (encdebug) printf x 799a570b6dSangelos #else 809a570b6dSangelos #define DPRINTF(x) 819a570b6dSangelos #endif 829a570b6dSangelos 839a570b6dSangelos /* 849a570b6dSangelos * We can control the acceptance of IP4 packets by altering the sysctl 859a570b6dSangelos * net.inet.ipip.allow value. Zero means drop them, all else is acceptance. 869a570b6dSangelos */ 879a570b6dSangelos int ipip_allow = 0; 889a570b6dSangelos 899a570b6dSangelos struct ipipstat ipipstat; 909a570b6dSangelos 919a570b6dSangelos #ifdef INET6 929a570b6dSangelos /* 939a570b6dSangelos * Really only a wrapper for ipip_input(), for use with IPv6. 949a570b6dSangelos */ 959a570b6dSangelos int 969a570b6dSangelos ip4_input6(struct mbuf **m, int *offp, int proto) 979a570b6dSangelos { 98ae26b3edSitojun /* If we do not accept IP-in-IP explicitly, drop. */ 996593f73dSangelos if (!ipip_allow && ((*m)->m_flags & (M_AUTH|M_CONF)) == 0) { 1009a570b6dSangelos DPRINTF(("ip4_input6(): dropped due to policy\n")); 1019a570b6dSangelos ipipstat.ipips_pdrops++; 1029a570b6dSangelos m_freem(*m); 1039a570b6dSangelos return IPPROTO_DONE; 1049a570b6dSangelos } 1059a570b6dSangelos 10621579e10Sclaudio ipip_input(*m, *offp, NULL, proto); 1079a570b6dSangelos return IPPROTO_DONE; 1089a570b6dSangelos } 1099a570b6dSangelos #endif /* INET6 */ 1109a570b6dSangelos 1119a570b6dSangelos #ifdef INET 1129a570b6dSangelos /* 1139a570b6dSangelos * Really only a wrapper for ipip_input(), for use with IPv4. 1149a570b6dSangelos */ 1159a570b6dSangelos void 1169a570b6dSangelos ip4_input(struct mbuf *m, ...) 1179a570b6dSangelos { 11821579e10Sclaudio struct ip *ip; 1199a570b6dSangelos va_list ap; 1209a570b6dSangelos int iphlen; 1219a570b6dSangelos 122ae26b3edSitojun /* If we do not accept IP-in-IP explicitly, drop. */ 1236593f73dSangelos if (!ipip_allow && (m->m_flags & (M_AUTH|M_CONF)) == 0) { 1249a570b6dSangelos DPRINTF(("ip4_input(): dropped due to policy\n")); 1259a570b6dSangelos ipipstat.ipips_pdrops++; 1269a570b6dSangelos m_freem(m); 1279a570b6dSangelos return; 1289a570b6dSangelos } 1299a570b6dSangelos 1309a570b6dSangelos va_start(ap, m); 1319a570b6dSangelos iphlen = va_arg(ap, int); 1329a570b6dSangelos va_end(ap); 1339a570b6dSangelos 13421579e10Sclaudio ip = mtod(m, struct ip *); 13521579e10Sclaudio 13621579e10Sclaudio ipip_input(m, iphlen, NULL, ip->ip_p); 1379a570b6dSangelos } 1389a570b6dSangelos #endif /* INET */ 1399a570b6dSangelos 1409a570b6dSangelos /* 1419a570b6dSangelos * ipip_input gets called when we receive an IP{46} encapsulated packet, 1429a570b6dSangelos * either because we got it at a real interface, or because AH or ESP 1439a570b6dSangelos * were being used in tunnel mode (in which case the rcvif element will 1449a570b6dSangelos * contain the address of the encX interface associated with the tunnel. 1459a570b6dSangelos */ 1469a570b6dSangelos 1479a570b6dSangelos void 14821579e10Sclaudio ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp, int proto) 1499a570b6dSangelos { 15064aa4cc7Sitojun struct sockaddr_in *sin; 15164aa4cc7Sitojun struct ifnet *ifp; 15264aa4cc7Sitojun struct ifaddr *ifa; 1539a570b6dSangelos struct ifqueue *ifq = NULL; 1549a570b6dSangelos struct ip *ipo; 1557d3e2ec5Sclaudio u_int rdomain; 1569a570b6dSangelos #ifdef INET6 15764aa4cc7Sitojun struct sockaddr_in6 *sin6; 15821579e10Sclaudio struct ip6_hdr *ip6; 1599a570b6dSangelos #endif 1609a570b6dSangelos int isr; 161*c9857360Smarkus int mode, hlen, s; 162*c9857360Smarkus u_int8_t itos, otos; 1639a570b6dSangelos u_int8_t v; 16421579e10Sclaudio sa_family_t af; 1659a570b6dSangelos 1669a570b6dSangelos ipipstat.ipips_ipackets++; 1679a570b6dSangelos 1689a570b6dSangelos m_copydata(m, 0, 1, &v); 1699a570b6dSangelos 1706593f73dSangelos switch (v >> 4) { 1719a570b6dSangelos #ifdef INET 1729a570b6dSangelos case 4: 1739a570b6dSangelos hlen = sizeof(struct ip); 1749a570b6dSangelos break; 1759a570b6dSangelos #endif /* INET */ 1769a570b6dSangelos #ifdef INET6 1779a570b6dSangelos case 6: 1789a570b6dSangelos hlen = sizeof(struct ip6_hdr); 1799a570b6dSangelos break; 1809a570b6dSangelos #endif 181795830a0Sangelos default: 182ae26b3edSitojun ipipstat.ipips_family++; 1839a570b6dSangelos m_freem(m); 1849a570b6dSangelos return /* EAFNOSUPPORT */; 1859a570b6dSangelos } 1869a570b6dSangelos 1879a570b6dSangelos /* Bring the IP header in the first mbuf, if not there already */ 1886593f73dSangelos if (m->m_len < hlen) { 1896593f73dSangelos if ((m = m_pullup(m, hlen)) == NULL) { 1909a570b6dSangelos DPRINTF(("ipip_input(): m_pullup() failed\n")); 1919a570b6dSangelos ipipstat.ipips_hdrops++; 1929a570b6dSangelos return; 1939a570b6dSangelos } 1949a570b6dSangelos } 1959a570b6dSangelos 1969a570b6dSangelos 1976593f73dSangelos /* Keep outer ecn field. */ 198ae26b3edSitojun switch (v >> 4) { 1999a570b6dSangelos #ifdef INET 200ae26b3edSitojun case 4: 20121579e10Sclaudio ipo = mtod(m, struct ip *); 2029a570b6dSangelos otos = ipo->ip_tos; 203ae26b3edSitojun break; 2049a570b6dSangelos #endif /* INET */ 2059a570b6dSangelos #ifdef INET6 206ae26b3edSitojun case 6: 20721579e10Sclaudio ip6 = mtod(m, struct ip6_hdr *); 20821579e10Sclaudio otos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 209ae26b3edSitojun break; 2109a570b6dSangelos #endif 211ae26b3edSitojun default: 212ae26b3edSitojun panic("ipip_input: should never reach here"); 213ae26b3edSitojun } 2149a570b6dSangelos 2152b1f9644Sangelos /* Remove outer IP header */ 2169a570b6dSangelos m_adj(m, iphlen); 2179a570b6dSangelos 2186d386255Sangelos /* Sanity check */ 2196d386255Sangelos if (m->m_pkthdr.len < sizeof(struct ip)) { 2206d386255Sangelos ipipstat.ipips_hdrops++; 2216d386255Sangelos m_freem(m); 2226d386255Sangelos return; 2236d386255Sangelos } 2246d386255Sangelos 22521579e10Sclaudio switch (proto) { 2269a570b6dSangelos #ifdef INET 22721579e10Sclaudio case IPPROTO_IPV4: 2289a570b6dSangelos hlen = sizeof(struct ip); 2299a570b6dSangelos break; 2309a570b6dSangelos #endif /* INET */ 2319a570b6dSangelos 2329a570b6dSangelos #ifdef INET6 23321579e10Sclaudio case IPPROTO_IPV6: 2349a570b6dSangelos hlen = sizeof(struct ip6_hdr); 2359a570b6dSangelos break; 2369a570b6dSangelos #endif 237ae26b3edSitojun default: 238ae26b3edSitojun ipipstat.ipips_family++; 239ae26b3edSitojun m_freem(m); 240ae26b3edSitojun return; /* EAFNOSUPPORT */ 2419a570b6dSangelos } 2429a570b6dSangelos 2436593f73dSangelos /* 24421579e10Sclaudio * Bring the inner header into the first mbuf, if not there already. 2456593f73dSangelos */ 2466593f73dSangelos if (m->m_len < hlen) { 2476593f73dSangelos if ((m = m_pullup(m, hlen)) == NULL) { 2489a570b6dSangelos DPRINTF(("ipip_input(): m_pullup() failed\n")); 2499a570b6dSangelos ipipstat.ipips_hdrops++; 2509a570b6dSangelos return; 2519a570b6dSangelos } 2529a570b6dSangelos } 2539a570b6dSangelos 2549a570b6dSangelos /* 2559a570b6dSangelos * RFC 1853 specifies that the inner TTL should not be touched on 2569a570b6dSangelos * decapsulation. There's no reason this comment should be here, but 2579a570b6dSangelos * this is as good as any a position. 2589a570b6dSangelos */ 2599a570b6dSangelos 260ae26b3edSitojun /* Some sanity checks in the inner IP header */ 26121579e10Sclaudio switch (proto) { 2629a570b6dSangelos #ifdef INET 26321579e10Sclaudio case IPPROTO_IPV4: 2649a570b6dSangelos ipo = mtod(m, struct ip *); 26521579e10Sclaudio #ifdef INET6 26621579e10Sclaudio ip6 = NULL; 26721579e10Sclaudio #endif 268*c9857360Smarkus itos = ipo->ip_tos; 269*c9857360Smarkus mode = m->m_flags & (M_AUTH|M_CONF) ? 270*c9857360Smarkus ECN_ALLOWED_IPSEC : ECN_ALLOWED; 271*c9857360Smarkus if (!ip_ecn_egress(mode, &otos, &ipo->ip_tos)) { 272*c9857360Smarkus DPRINTF(("ipip_input(): ip_ecn_egress() failed")); 273*c9857360Smarkus ipipstat.ipips_pdrops++; 27474e8fb40Skjc m_freem(m); 27574e8fb40Skjc return; 27674e8fb40Skjc } 277*c9857360Smarkus /* re-calculate the checksum if ip_tos was changed */ 278*c9857360Smarkus if (itos != ipo->ip_tos) { 279*c9857360Smarkus hlen = ipo->ip_hl << 2; 280*c9857360Smarkus if (m->m_pkthdr.len >= hlen) { 281*c9857360Smarkus ipo->ip_sum = 0; 282*c9857360Smarkus ipo->ip_sum = in_cksum(m, hlen); 283*c9857360Smarkus } 284*c9857360Smarkus } 2859a570b6dSangelos break; 2869a570b6dSangelos #endif /* INET */ 2879a570b6dSangelos #ifdef INET6 28821579e10Sclaudio case IPPROTO_IPV6: 28921579e10Sclaudio #ifdef INET 29021579e10Sclaudio ipo = NULL; 29121579e10Sclaudio #endif 29221579e10Sclaudio ip6 = mtod(m, struct ip6_hdr *); 2939a570b6dSangelos itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 29474e8fb40Skjc if (!ip_ecn_egress(ECN_ALLOWED, &otos, &itos)) { 295*c9857360Smarkus DPRINTF(("ipip_input(): ip_ecn_egress() failed")); 296*c9857360Smarkus ipipstat.ipips_pdrops++; 29774e8fb40Skjc m_freem(m); 29874e8fb40Skjc return; 29974e8fb40Skjc } 3009a570b6dSangelos ip6->ip6_flow &= ~htonl(0xff << 20); 3019a570b6dSangelos ip6->ip6_flow |= htonl((u_int32_t) itos << 20); 3029a570b6dSangelos break; 3039a570b6dSangelos #endif 304ae26b3edSitojun default: 30521579e10Sclaudio #ifdef INET 30621579e10Sclaudio ipo = NULL; 30721579e10Sclaudio #endif 30821579e10Sclaudio #ifdef INET6 30921579e10Sclaudio ip6 = NULL; 31021579e10Sclaudio #endif 3119a570b6dSangelos } 3129a570b6dSangelos 3139a570b6dSangelos /* Check for local address spoofing. */ 3147164ca36Sangelos if ((m->m_pkthdr.rcvif == NULL || 3157164ca36Sangelos !(m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK)) && 3166593f73dSangelos ipip_allow != 2) { 3177d3e2ec5Sclaudio rdomain = rtable_l2(m->m_pkthdr.rdomain); 3181573508eSmiod TAILQ_FOREACH(ifp, &ifnet, if_list) { 3197d3e2ec5Sclaudio if (ifp->if_rdomain != rdomain) 32022760f56Sclaudio continue; 3211573508eSmiod TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 3229a570b6dSangelos #ifdef INET 3236593f73dSangelos if (ipo) { 3246593f73dSangelos if (ifa->ifa_addr->sa_family != 3256593f73dSangelos AF_INET) 3269a570b6dSangelos continue; 3279a570b6dSangelos 32821579e10Sclaudio sin = (struct sockaddr_in *) 32921579e10Sclaudio ifa->ifa_addr; 3306593f73dSangelos if (sin->sin_addr.s_addr == 3316593f73dSangelos ipo->ip_src.s_addr) { 3329a570b6dSangelos ipipstat.ipips_spoof++; 3339a570b6dSangelos m_freem(m); 3349a570b6dSangelos return; 3359a570b6dSangelos } 3369a570b6dSangelos } 3379a570b6dSangelos #endif /* INET */ 3389a570b6dSangelos #ifdef INET6 3396593f73dSangelos if (ip6) { 3406593f73dSangelos if (ifa->ifa_addr->sa_family != 3416593f73dSangelos AF_INET6) 3429a570b6dSangelos continue; 3439a570b6dSangelos 34421579e10Sclaudio sin6 = (struct sockaddr_in6 *) 34521579e10Sclaudio ifa->ifa_addr; 34621579e10Sclaudio if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 34721579e10Sclaudio &ip6->ip6_src)) { 3486593f73dSangelos ipipstat.ipips_spoof++; 3499a570b6dSangelos m_freem(m); 3509a570b6dSangelos return; 3519a570b6dSangelos } 3529a570b6dSangelos 3539a570b6dSangelos } 3549a570b6dSangelos #endif /* INET6 */ 3559a570b6dSangelos } 3569a570b6dSangelos } 3579a570b6dSangelos } 3589a570b6dSangelos 3599a570b6dSangelos /* Statistics */ 3609a570b6dSangelos ipipstat.ipips_ibytes += m->m_pkthdr.len - iphlen; 3619a570b6dSangelos 3629a570b6dSangelos /* 3639a570b6dSangelos * Interface pointer stays the same; if no IPsec processing has 3649a570b6dSangelos * been done (or will be done), this will point to a normal 3659a570b6dSangelos * interface. Otherwise, it'll point to an enc interface, which 3669a570b6dSangelos * will allow a packet filter to distinguish between secure and 3679a570b6dSangelos * untrusted packets. 3689a570b6dSangelos */ 3699a570b6dSangelos 37021579e10Sclaudio switch (proto) { 3719a570b6dSangelos #ifdef INET 37221579e10Sclaudio case IPPROTO_IPV4: 3739a570b6dSangelos ifq = &ipintrq; 3749a570b6dSangelos isr = NETISR_IP; 37521579e10Sclaudio af = AF_INET; 376ae26b3edSitojun break; 377ae26b3edSitojun #endif 3789a570b6dSangelos #ifdef INET6 37921579e10Sclaudio case IPPROTO_IPV6: 3809a570b6dSangelos ifq = &ip6intrq; 3819a570b6dSangelos isr = NETISR_IPV6; 38221579e10Sclaudio af = AF_INET6; 383ae26b3edSitojun break; 384ae26b3edSitojun #endif 385ae26b3edSitojun default: 386ae26b3edSitojun panic("ipip_input: should never reach here"); 3879a570b6dSangelos } 3889a570b6dSangelos 3899acf6950Sangelos #if NBPFILTER > 0 39063df607fSpascoe if (gifp && gifp->if_bpf) 39121579e10Sclaudio bpf_mtap_af(gifp->if_bpf, af, m, BPF_DIRECTION_IN); 3929acf6950Sangelos #endif 3930c8db51fShenning #if NPF > 0 3940c8db51fShenning pf_pkt_addr_changed(m); 3950c8db51fShenning #endif 3969acf6950Sangelos 397aaed91e5Sbrad s = splnet(); /* isn't it already? */ 3986593f73dSangelos if (IF_QFULL(ifq)) { 3999a570b6dSangelos IF_DROP(ifq); 4009a570b6dSangelos m_freem(m); 4019a570b6dSangelos ipipstat.ipips_qfull++; 4029a570b6dSangelos 4039a570b6dSangelos splx(s); 4049a570b6dSangelos 4056593f73dSangelos DPRINTF(("ipip_input(): packet dropped because of full " 4066593f73dSangelos "queue\n")); 4079a570b6dSangelos return; 4089a570b6dSangelos } 4099a570b6dSangelos 4109a570b6dSangelos IF_ENQUEUE(ifq, m); 4119a570b6dSangelos schednetisr(isr); 4129a570b6dSangelos splx(s); 4139a570b6dSangelos return; 4149a570b6dSangelos } 4159a570b6dSangelos 4169a570b6dSangelos int 4170085a3a2Sclaudio ipip_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int dummy, 4180085a3a2Sclaudio int dummy2) 4199a570b6dSangelos { 4209a570b6dSangelos u_int8_t tp, otos; 4219a570b6dSangelos 4229a570b6dSangelos #ifdef INET 4239a570b6dSangelos u_int8_t itos; 4249a570b6dSangelos struct ip *ipo; 4259a570b6dSangelos #endif /* INET */ 4269a570b6dSangelos 4279a570b6dSangelos #ifdef INET6 428d5b56032Sitojun struct ip6_hdr *ip6, *ip6o; 4299a570b6dSangelos #endif /* INET6 */ 4309a570b6dSangelos 4316593f73dSangelos /* XXX Deal with empty TDB source/destination addresses. */ 4329a570b6dSangelos 4339a570b6dSangelos m_copydata(m, 0, 1, &tp); 4346593f73dSangelos tp = (tp >> 4) & 0xff; /* Get the IP version number. */ 4359a570b6dSangelos 4366593f73dSangelos switch (tdb->tdb_dst.sa.sa_family) { 4379a570b6dSangelos #ifdef INET 4389a570b6dSangelos case AF_INET: 4396593f73dSangelos if (tdb->tdb_src.sa.sa_family != AF_INET || 4406593f73dSangelos tdb->tdb_src.sin.sin_addr.s_addr == INADDR_ANY || 4416593f73dSangelos tdb->tdb_dst.sin.sin_addr.s_addr == INADDR_ANY) { 4426593f73dSangelos 4436593f73dSangelos DPRINTF(("ipip_output(): unspecified tunnel endpoind " 4446593f73dSangelos "address in SA %s/%08x\n", 4456593f73dSangelos ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); 4466593f73dSangelos 4479a570b6dSangelos ipipstat.ipips_unspec++; 4489a570b6dSangelos m_freem(m); 4499a570b6dSangelos *mp = NULL; 4509a570b6dSangelos return EINVAL; 4519a570b6dSangelos } 4529a570b6dSangelos 4539a570b6dSangelos M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); 4546593f73dSangelos if (m == 0) { 4559a570b6dSangelos DPRINTF(("ipip_output(): M_PREPEND failed\n")); 4569a570b6dSangelos ipipstat.ipips_hdrops++; 4579a570b6dSangelos *mp = NULL; 4589a570b6dSangelos return ENOBUFS; 4599a570b6dSangelos } 4609a570b6dSangelos 4619a570b6dSangelos ipo = mtod(m, struct ip *); 4629a570b6dSangelos 4639a570b6dSangelos ipo->ip_v = IPVERSION; 4649a570b6dSangelos ipo->ip_hl = 5; 4659a570b6dSangelos ipo->ip_len = htons(m->m_pkthdr.len); 4669a570b6dSangelos ipo->ip_ttl = ip_defttl; 4679a570b6dSangelos ipo->ip_sum = 0; 4689a570b6dSangelos ipo->ip_src = tdb->tdb_src.sin.sin_addr; 4699a570b6dSangelos ipo->ip_dst = tdb->tdb_dst.sin.sin_addr; 4709a570b6dSangelos 4719a570b6dSangelos /* 4729a570b6dSangelos * We do the htons() to prevent snoopers from determining our 4739a570b6dSangelos * endianness. 4749a570b6dSangelos */ 4759a570b6dSangelos ipo->ip_id = htons(ip_randomid()); 4769a570b6dSangelos 4776593f73dSangelos /* If the inner protocol is IP... */ 4786593f73dSangelos if (tp == IPVERSION) { 4799a570b6dSangelos /* Save ECN notification */ 4806593f73dSangelos m_copydata(m, sizeof(struct ip) + 4816593f73dSangelos offsetof(struct ip, ip_tos), 4829a570b6dSangelos sizeof(u_int8_t), (caddr_t) &itos); 4839a570b6dSangelos 4849a570b6dSangelos ipo->ip_p = IPPROTO_IPIP; 4859a570b6dSangelos 4869a570b6dSangelos /* 4876593f73dSangelos * We should be keeping tunnel soft-state and 4886593f73dSangelos * send back ICMPs if needed. 4899a570b6dSangelos */ 4906593f73dSangelos m_copydata(m, sizeof(struct ip) + 4916593f73dSangelos offsetof(struct ip, ip_off), 4929a570b6dSangelos sizeof(u_int16_t), (caddr_t) &ipo->ip_off); 4936c66c2abSangelos NTOHS(ipo->ip_off); 49470d36f83Sangelos ipo->ip_off &= ~(IP_DF | IP_MF | IP_OFFMASK); 4956c66c2abSangelos HTONS(ipo->ip_off); 4969a570b6dSangelos } 4979a570b6dSangelos #ifdef INET6 4986593f73dSangelos else if (tp == (IPV6_VERSION >> 4)) { 4999a570b6dSangelos u_int32_t itos32; 5006593f73dSangelos 5016593f73dSangelos /* Save ECN notification. */ 5029a570b6dSangelos m_copydata(m, sizeof(struct ip) + 5039a570b6dSangelos offsetof(struct ip6_hdr, ip6_flow), 5049a570b6dSangelos sizeof(u_int32_t), (caddr_t) &itos32); 5059a570b6dSangelos itos = ntohl(itos32) >> 20; 5069a570b6dSangelos ipo->ip_p = IPPROTO_IPV6; 5079a570b6dSangelos ipo->ip_off = 0; 5089a570b6dSangelos } 5099a570b6dSangelos #endif /* INET6 */ 5106593f73dSangelos else { 5119a570b6dSangelos m_freem(m); 5129a570b6dSangelos *mp = NULL; 51305020a09Sangelos ipipstat.ipips_family++; 5149a570b6dSangelos return EAFNOSUPPORT; 5159a570b6dSangelos } 5169a570b6dSangelos 5179a570b6dSangelos otos = 0; 5189a570b6dSangelos ip_ecn_ingress(ECN_ALLOWED, &otos, &itos); 5199a570b6dSangelos ipo->ip_tos = otos; 5209a570b6dSangelos break; 5219a570b6dSangelos #endif /* INET */ 5229a570b6dSangelos 5239a570b6dSangelos #ifdef INET6 5249a570b6dSangelos case AF_INET6: 5259a570b6dSangelos if (IN6_IS_ADDR_UNSPECIFIED(&tdb->tdb_dst.sin6.sin6_addr) || 5266593f73dSangelos tdb->tdb_src.sa.sa_family != AF_INET6 || 5276593f73dSangelos IN6_IS_ADDR_UNSPECIFIED(&tdb->tdb_src.sin6.sin6_addr)) { 5286593f73dSangelos 5296593f73dSangelos DPRINTF(("ipip_output(): unspecified tunnel endpoind " 5306593f73dSangelos "address in SA %s/%08x\n", 5316593f73dSangelos ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); 5326593f73dSangelos 5339a570b6dSangelos ipipstat.ipips_unspec++; 5349a570b6dSangelos m_freem(m); 5359a570b6dSangelos *mp = NULL; 5369a570b6dSangelos return ENOBUFS; 5379a570b6dSangelos } 5389a570b6dSangelos 539424a21eaStodd /* If the inner protocol is IPv6, clear link local scope */ 540424a21eaStodd if (tp == (IPV6_VERSION >> 4)) { 541d5b56032Sitojun /* scoped address handling */ 542d5b56032Sitojun ip6 = mtod(m, struct ip6_hdr *); 54365b748d4Sitojun if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src)) 544d5b56032Sitojun ip6->ip6_src.s6_addr16[1] = 0; 54565b748d4Sitojun if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst)) 546d5b56032Sitojun ip6->ip6_dst.s6_addr16[1] = 0; 547424a21eaStodd } 548d5b56032Sitojun 5499a570b6dSangelos M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT); 5506593f73dSangelos if (m == 0) { 5519a570b6dSangelos DPRINTF(("ipip_output(): M_PREPEND failed\n")); 5529a570b6dSangelos ipipstat.ipips_hdrops++; 5539a570b6dSangelos *mp = NULL; 5549a570b6dSangelos return ENOBUFS; 5559a570b6dSangelos } 5569a570b6dSangelos 5579a570b6dSangelos /* Initialize IPv6 header */ 5589a570b6dSangelos ip6o = mtod(m, struct ip6_hdr *); 5599a570b6dSangelos ip6o->ip6_flow = 0; 5609a570b6dSangelos ip6o->ip6_vfc &= ~IPV6_VERSION_MASK; 5619a570b6dSangelos ip6o->ip6_vfc |= IPV6_VERSION; 562086d35e9Smarkus ip6o->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6o)); 5639a570b6dSangelos ip6o->ip6_hlim = ip_defttl; 56456958091Sitojun in6_embedscope(&ip6o->ip6_src, &tdb->tdb_src.sin6, NULL, NULL); 56556958091Sitojun in6_embedscope(&ip6o->ip6_dst, &tdb->tdb_dst.sin6, NULL, NULL); 5669a570b6dSangelos 5679a570b6dSangelos #ifdef INET 5686593f73dSangelos if (tp == IPVERSION) { 5699a570b6dSangelos /* Save ECN notification */ 5709a570b6dSangelos m_copydata(m, sizeof(struct ip6_hdr) + 5719a570b6dSangelos offsetof(struct ip, ip_tos), sizeof(u_int8_t), 5729a570b6dSangelos (caddr_t) &itos); 5739a570b6dSangelos 5746593f73dSangelos /* This is really IPVERSION. */ 5756593f73dSangelos ip6o->ip6_nxt = IPPROTO_IPIP; 5769a570b6dSangelos } 5779a570b6dSangelos else 5789a570b6dSangelos #endif /* INET */ 5796593f73dSangelos if (tp == (IPV6_VERSION >> 4)) { 5809a570b6dSangelos u_int32_t itos32; 5816593f73dSangelos 5826593f73dSangelos /* Save ECN notification. */ 5839a570b6dSangelos m_copydata(m, sizeof(struct ip6_hdr) + 5849a570b6dSangelos offsetof(struct ip6_hdr, ip6_flow), 5859a570b6dSangelos sizeof(u_int32_t), (caddr_t) &itos32); 5869a570b6dSangelos itos = ntohl(itos32) >> 20; 5879a570b6dSangelos 5889a570b6dSangelos ip6o->ip6_nxt = IPPROTO_IPV6; 5896593f73dSangelos } else { 5909a570b6dSangelos m_freem(m); 5919a570b6dSangelos *mp = NULL; 59205020a09Sangelos ipipstat.ipips_family++; 5939a570b6dSangelos return EAFNOSUPPORT; 5949a570b6dSangelos } 5959a570b6dSangelos 5969a570b6dSangelos otos = 0; 5979a570b6dSangelos ip_ecn_ingress(ECN_ALLOWED, &otos, &itos); 5989a570b6dSangelos ip6o->ip6_flow |= htonl((u_int32_t) otos << 20); 5999a570b6dSangelos break; 6009a570b6dSangelos #endif /* INET6 */ 6019a570b6dSangelos 6029a570b6dSangelos default: 6039a570b6dSangelos DPRINTF(("ipip_output(): unsupported protocol family %d\n", 6049a570b6dSangelos tdb->tdb_dst.sa.sa_family)); 6059a570b6dSangelos m_freem(m); 6069a570b6dSangelos *mp = NULL; 6079a570b6dSangelos ipipstat.ipips_family++; 60867a9371aSangelos return EAFNOSUPPORT; 6099a570b6dSangelos } 6109a570b6dSangelos 6119a570b6dSangelos ipipstat.ipips_opackets++; 6129a570b6dSangelos *mp = m; 6139a570b6dSangelos 6149a570b6dSangelos #ifdef INET 6156593f73dSangelos if (tdb->tdb_dst.sa.sa_family == AF_INET) { 6169a570b6dSangelos if (tdb->tdb_xform->xf_type == XF_IP4) 6176593f73dSangelos tdb->tdb_cur_bytes += 6186593f73dSangelos m->m_pkthdr.len - sizeof(struct ip); 6199a570b6dSangelos 6209a570b6dSangelos ipipstat.ipips_obytes += m->m_pkthdr.len - sizeof(struct ip); 6219a570b6dSangelos } 6229a570b6dSangelos #endif /* INET */ 6239a570b6dSangelos 6249a570b6dSangelos #ifdef INET6 6256593f73dSangelos if (tdb->tdb_dst.sa.sa_family == AF_INET6) { 6269a570b6dSangelos if (tdb->tdb_xform->xf_type == XF_IP4) 6276593f73dSangelos tdb->tdb_cur_bytes += 6286593f73dSangelos m->m_pkthdr.len - sizeof(struct ip6_hdr); 6299a570b6dSangelos 6306593f73dSangelos ipipstat.ipips_obytes += 6316593f73dSangelos m->m_pkthdr.len - sizeof(struct ip6_hdr); 6329a570b6dSangelos } 6339a570b6dSangelos #endif /* INET6 */ 6349a570b6dSangelos 6359a570b6dSangelos return 0; 6369a570b6dSangelos } 6379a570b6dSangelos 6389a570b6dSangelos #ifdef IPSEC 6399a570b6dSangelos int 6409a570b6dSangelos ipe4_attach() 6419a570b6dSangelos { 6429a570b6dSangelos return 0; 6439a570b6dSangelos } 6449a570b6dSangelos 6459a570b6dSangelos int 6469a570b6dSangelos ipe4_init(struct tdb *tdbp, struct xformsw *xsp, struct ipsecinit *ii) 6479a570b6dSangelos { 6489a570b6dSangelos tdbp->tdb_xform = xsp; 6499a570b6dSangelos return 0; 6509a570b6dSangelos } 6519a570b6dSangelos 6529a570b6dSangelos int 6539a570b6dSangelos ipe4_zeroize(struct tdb *tdbp) 6549a570b6dSangelos { 6559a570b6dSangelos return 0; 6569a570b6dSangelos } 6579a570b6dSangelos 6589a570b6dSangelos void 6599a570b6dSangelos ipe4_input(struct mbuf *m, ...) 6609a570b6dSangelos { 6616593f73dSangelos /* This is a rather serious mistake, so no conditional printing. */ 6629a570b6dSangelos printf("ipe4_input(): should never be called\n"); 6639a570b6dSangelos if (m) 6649a570b6dSangelos m_freem(m); 6659a570b6dSangelos } 6669a570b6dSangelos #endif /* IPSEC */ 6679a570b6dSangelos 6689a570b6dSangelos int 6696593f73dSangelos ipip_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, 6706593f73dSangelos size_t newlen) 6719a570b6dSangelos { 6729a570b6dSangelos /* All sysctl names at this level are terminal. */ 6739a570b6dSangelos if (namelen != 1) 6749a570b6dSangelos return (ENOTDIR); 6759a570b6dSangelos 6769a570b6dSangelos switch (name[0]) { 6779a570b6dSangelos case IPIPCTL_ALLOW: 6789a570b6dSangelos return (sysctl_int(oldp, oldlenp, newp, newlen, &ipip_allow)); 679ab46c28dSderaadt case IPIPCTL_STATS: 680ab46c28dSderaadt if (newp != NULL) 681ab46c28dSderaadt return (EPERM); 682ab46c28dSderaadt return (sysctl_struct(oldp, oldlenp, newp, newlen, 683ab46c28dSderaadt &ipipstat, sizeof(ipipstat))); 6849a570b6dSangelos default: 6859a570b6dSangelos return (ENOPROTOOPT); 6869a570b6dSangelos } 6879a570b6dSangelos /* NOTREACHED */ 6889a570b6dSangelos } 689