1*70464ff2Sgnezdo /* $OpenBSD: ip_ipip.c,v 1.90 2021/01/09 20:59:44 gnezdo 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 42ab2f8295Sbluhm #include "bpfilter.h" 43ab2f8295Sbluhm #include "gif.h" 440c8db51fShenning #include "pf.h" 450c8db51fShenning 469a570b6dSangelos #include <sys/param.h> 4764c11355Sderaadt #include <sys/systm.h> 489a570b6dSangelos #include <sys/mbuf.h> 499a570b6dSangelos #include <sys/socket.h> 509a570b6dSangelos #include <sys/sysctl.h> 519a570b6dSangelos 529a570b6dSangelos #include <net/if.h> 53ab2f8295Sbluhm #include <net/if_types.h> 540deb6685Smpi #include <net/if_var.h> 559a570b6dSangelos #include <net/route.h> 569a570b6dSangelos #include <net/netisr.h> 579acf6950Sangelos #include <net/bpf.h> 589a570b6dSangelos 599a570b6dSangelos #include <netinet/in.h> 609a570b6dSangelos #include <netinet/ip.h> 619a570b6dSangelos #include <netinet/in_pcb.h> 629a570b6dSangelos #include <netinet/ip_var.h> 639a570b6dSangelos #include <netinet/ip_ecn.h> 64ea784840Sbluhm #include <netinet/ip_ipip.h> 659a570b6dSangelos 669a570b6dSangelos #ifdef MROUTING 679a570b6dSangelos #include <netinet/ip_mroute.h> 689a570b6dSangelos #endif 699a570b6dSangelos 700c8db51fShenning #if NPF > 0 710c8db51fShenning #include <net/pfvar.h> 720c8db51fShenning #endif 730c8db51fShenning 749a570b6dSangelos #ifdef ENCDEBUG 759a570b6dSangelos #define DPRINTF(x) if (encdebug) printf x 769a570b6dSangelos #else 779a570b6dSangelos #define DPRINTF(x) 789a570b6dSangelos #endif 799a570b6dSangelos 809a570b6dSangelos /* 819a570b6dSangelos * We can control the acceptance of IP4 packets by altering the sysctl 829a570b6dSangelos * net.inet.ipip.allow value. Zero means drop them, all else is acceptance. 839a570b6dSangelos */ 849a570b6dSangelos int ipip_allow = 0; 859a570b6dSangelos 8660dafcf9Sjca struct cpumem *ipipcounters; 8760dafcf9Sjca 8860dafcf9Sjca void 8960dafcf9Sjca ipip_init(void) 9060dafcf9Sjca { 9160dafcf9Sjca ipipcounters = counters_alloc(ipips_ncounters); 9260dafcf9Sjca } 939a570b6dSangelos 949a570b6dSangelos /* 95ab2f8295Sbluhm * Really only a wrapper for ipip_input_if(), for use with pr_input. 969a570b6dSangelos */ 979a570b6dSangelos int 98ab2f8295Sbluhm ipip_input(struct mbuf **mp, int *offp, int nxt, int af) 999a570b6dSangelos { 100ab2f8295Sbluhm struct ifnet *ifp; 101ab2f8295Sbluhm 102ae26b3edSitojun /* If we do not accept IP-in-IP explicitly, drop. */ 103f0c13189Sderaadt if (!ipip_allow && ((*mp)->m_flags & (M_AUTH|M_CONF)) == 0) { 104ea784840Sbluhm DPRINTF(("%s: dropped due to policy\n", __func__)); 10560dafcf9Sjca ipipstat_inc(ipips_pdrops); 10636c0109eSbluhm m_freemp(mp); 1079a570b6dSangelos return IPPROTO_DONE; 1089a570b6dSangelos } 1099a570b6dSangelos 110ab2f8295Sbluhm ifp = if_get((*mp)->m_pkthdr.ph_ifidx); 111ab2f8295Sbluhm if (ifp == NULL) { 112ab2f8295Sbluhm m_freemp(mp); 113ab2f8295Sbluhm return IPPROTO_DONE; 114ab2f8295Sbluhm } 115ab2f8295Sbluhm nxt = ipip_input_if(mp, offp, nxt, af, ifp); 116ab2f8295Sbluhm if_put(ifp); 117ab2f8295Sbluhm 118ab2f8295Sbluhm return nxt; 1199a570b6dSangelos } 1209a570b6dSangelos 1219a570b6dSangelos /* 1229a570b6dSangelos * ipip_input gets called when we receive an IP{46} encapsulated packet, 1239a570b6dSangelos * either because we got it at a real interface, or because AH or ESP 124fb492c37Smpi * were being used in tunnel mode (in which case the ph_ifidx element 125fb492c37Smpi * will contain the index of the encX interface associated with the 126fb492c37Smpi * tunnel. 1279a570b6dSangelos */ 1289a570b6dSangelos 12996be3d96Sbluhm int 130ab2f8295Sbluhm ipip_input_if(struct mbuf **mp, int *offp, int proto, int oaf, 131ab2f8295Sbluhm struct ifnet *ifp) 1329a570b6dSangelos { 13396be3d96Sbluhm struct mbuf *m = *mp; 13464aa4cc7Sitojun struct sockaddr_in *sin; 1351bcb5a76Sbluhm struct ip *ip; 1369a570b6dSangelos #ifdef INET6 13764aa4cc7Sitojun struct sockaddr_in6 *sin6; 13821579e10Sclaudio struct ip6_hdr *ip6; 1399a570b6dSangelos #endif 14098a920fdSdlg int mode, hlen; 141c9857360Smarkus u_int8_t itos, otos; 142ea784840Sbluhm sa_family_t iaf; 1439a570b6dSangelos 14460dafcf9Sjca ipipstat_inc(ipips_ipackets); 1459a570b6dSangelos 146289a9ae9Sbluhm switch (oaf) { 147289a9ae9Sbluhm case AF_INET: 1489a570b6dSangelos hlen = sizeof(struct ip); 1499a570b6dSangelos break; 1509a570b6dSangelos #ifdef INET6 151289a9ae9Sbluhm case AF_INET6: 1529a570b6dSangelos hlen = sizeof(struct ip6_hdr); 1539a570b6dSangelos break; 1549a570b6dSangelos #endif 155795830a0Sangelos default: 156289a9ae9Sbluhm unhandled_af(oaf); 1579a570b6dSangelos } 1589a570b6dSangelos 1599a570b6dSangelos /* Bring the IP header in the first mbuf, if not there already */ 1606593f73dSangelos if (m->m_len < hlen) { 161eabae73bSbluhm if ((m = *mp = m_pullup(m, hlen)) == NULL) { 162ea784840Sbluhm DPRINTF(("%s: m_pullup() failed\n", __func__)); 16360dafcf9Sjca ipipstat_inc(ipips_hdrops); 164458cfda4Sbluhm goto bad; 1659a570b6dSangelos } 1669a570b6dSangelos } 1679a570b6dSangelos 1686593f73dSangelos /* Keep outer ecn field. */ 169289a9ae9Sbluhm switch (oaf) { 170289a9ae9Sbluhm case AF_INET: 1711bcb5a76Sbluhm ip = mtod(m, struct ip *); 1721bcb5a76Sbluhm otos = ip->ip_tos; 173ae26b3edSitojun break; 1749a570b6dSangelos #ifdef INET6 175289a9ae9Sbluhm case AF_INET6: 17621579e10Sclaudio ip6 = mtod(m, struct ip6_hdr *); 17721579e10Sclaudio otos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 178ae26b3edSitojun break; 1799a570b6dSangelos #endif 180ae26b3edSitojun } 1819a570b6dSangelos 1822b1f9644Sangelos /* Remove outer IP header */ 1831bcb5a76Sbluhm KASSERT(*offp > 0); 1841bcb5a76Sbluhm m_adj(m, *offp); 1851bcb5a76Sbluhm *offp = 0; 1861bcb5a76Sbluhm ip = NULL; 1871bcb5a76Sbluhm #ifdef INET6 1881bcb5a76Sbluhm ip6 = NULL; 1891bcb5a76Sbluhm #endif 1906d386255Sangelos 19121579e10Sclaudio switch (proto) { 19221579e10Sclaudio case IPPROTO_IPV4: 1939a570b6dSangelos hlen = sizeof(struct ip); 1949a570b6dSangelos break; 1959a570b6dSangelos 1969a570b6dSangelos #ifdef INET6 19721579e10Sclaudio case IPPROTO_IPV6: 1989a570b6dSangelos hlen = sizeof(struct ip6_hdr); 1999a570b6dSangelos break; 2009a570b6dSangelos #endif 201ae26b3edSitojun default: 20260dafcf9Sjca ipipstat_inc(ipips_family); 203458cfda4Sbluhm goto bad; 2049a570b6dSangelos } 2059a570b6dSangelos 2061bcb5a76Sbluhm /* Sanity check */ 2071bcb5a76Sbluhm if (m->m_pkthdr.len < hlen) { 2081bcb5a76Sbluhm ipipstat_inc(ipips_hdrops); 209458cfda4Sbluhm goto bad; 2101bcb5a76Sbluhm } 2111bcb5a76Sbluhm 2126593f73dSangelos /* 21321579e10Sclaudio * Bring the inner header into the first mbuf, if not there already. 2146593f73dSangelos */ 2156593f73dSangelos if (m->m_len < hlen) { 216eabae73bSbluhm if ((m = *mp = m_pullup(m, hlen)) == NULL) { 217ea784840Sbluhm DPRINTF(("%s: m_pullup() failed\n", __func__)); 21860dafcf9Sjca ipipstat_inc(ipips_hdrops); 219458cfda4Sbluhm goto bad; 2209a570b6dSangelos } 2219a570b6dSangelos } 2229a570b6dSangelos 2239a570b6dSangelos /* 2249a570b6dSangelos * RFC 1853 specifies that the inner TTL should not be touched on 2259a570b6dSangelos * decapsulation. There's no reason this comment should be here, but 2269a570b6dSangelos * this is as good as any a position. 2279a570b6dSangelos */ 2289a570b6dSangelos 229ae26b3edSitojun /* Some sanity checks in the inner IP header */ 23021579e10Sclaudio switch (proto) { 23121579e10Sclaudio case IPPROTO_IPV4: 232ca37dd6cSbluhm iaf = AF_INET; 2331bcb5a76Sbluhm ip = mtod(m, struct ip *); 2341bcb5a76Sbluhm hlen = ip->ip_hl << 2; 2351bcb5a76Sbluhm if (m->m_pkthdr.len < hlen) { 2361bcb5a76Sbluhm ipipstat_inc(ipips_hdrops); 237ab2f8295Sbluhm goto bad; 2381bcb5a76Sbluhm } 2391bcb5a76Sbluhm itos = ip->ip_tos; 240c9857360Smarkus mode = m->m_flags & (M_AUTH|M_CONF) ? 241c9857360Smarkus ECN_ALLOWED_IPSEC : ECN_ALLOWED; 242412c1a0aSdlg if (!ip_ecn_egress(mode, &otos, &itos)) { 243ea784840Sbluhm DPRINTF(("%s: ip_ecn_egress() failed\n", __func__)); 24460dafcf9Sjca ipipstat_inc(ipips_pdrops); 245458cfda4Sbluhm goto bad; 24674e8fb40Skjc } 247c9857360Smarkus /* re-calculate the checksum if ip_tos was changed */ 248412c1a0aSdlg if (itos != ip->ip_tos) 249412c1a0aSdlg ip_tos_patch(ip, itos); 2509a570b6dSangelos break; 2519a570b6dSangelos #ifdef INET6 25221579e10Sclaudio case IPPROTO_IPV6: 253ca37dd6cSbluhm iaf = AF_INET6; 25421579e10Sclaudio ip6 = mtod(m, struct ip6_hdr *); 2559a570b6dSangelos itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 25674e8fb40Skjc if (!ip_ecn_egress(ECN_ALLOWED, &otos, &itos)) { 257ea784840Sbluhm DPRINTF(("%s: ip_ecn_egress() failed\n", __func__)); 25860dafcf9Sjca ipipstat_inc(ipips_pdrops); 259458cfda4Sbluhm goto bad; 26074e8fb40Skjc } 2619a570b6dSangelos ip6->ip6_flow &= ~htonl(0xff << 20); 2629a570b6dSangelos ip6->ip6_flow |= htonl((u_int32_t) itos << 20); 2639a570b6dSangelos break; 2649a570b6dSangelos #endif 2659a570b6dSangelos } 2669a570b6dSangelos 2679a570b6dSangelos /* Check for local address spoofing. */ 268ab2f8295Sbluhm if (!(ifp->if_flags & IFF_LOOPBACK) && ipip_allow != 2) { 269d33580a9Smpi struct sockaddr_storage ss; 270d33580a9Smpi struct rtentry *rt; 271d33580a9Smpi 272d33580a9Smpi memset(&ss, 0, sizeof(ss)); 273d33580a9Smpi 2741bcb5a76Sbluhm if (ip) { 275d33580a9Smpi sin = (struct sockaddr_in *)&ss; 276d33580a9Smpi sin->sin_family = AF_INET; 277d33580a9Smpi sin->sin_len = sizeof(*sin); 2781bcb5a76Sbluhm sin->sin_addr = ip->ip_src; 2799a570b6dSangelos #ifdef INET6 280d33580a9Smpi } else if (ip6) { 281d33580a9Smpi sin6 = (struct sockaddr_in6 *)&ss; 282d33580a9Smpi sin6->sin6_family = AF_INET6; 283d33580a9Smpi sin6->sin6_len = sizeof(*sin6); 284d33580a9Smpi sin6->sin6_addr = ip6->ip6_src; 2859a570b6dSangelos #endif /* INET6 */ 2869a570b6dSangelos } 2879c681c75Sbluhm rt = rtalloc(sstosa(&ss), 0, m->m_pkthdr.ph_rtableid); 288d33580a9Smpi if ((rt != NULL) && (rt->rt_flags & RTF_LOCAL)) { 28960dafcf9Sjca ipipstat_inc(ipips_spoof); 290d33580a9Smpi rtfree(rt); 291458cfda4Sbluhm goto bad; 2929a570b6dSangelos } 293d33580a9Smpi rtfree(rt); 2949a570b6dSangelos } 2959a570b6dSangelos 2969a570b6dSangelos /* Statistics */ 2971bcb5a76Sbluhm ipipstat_add(ipips_ibytes, m->m_pkthdr.len - hlen); 2989a570b6dSangelos 299ab2f8295Sbluhm #if NBPFILTER > 0 && NGIF > 0 300ab2f8295Sbluhm if (ifp->if_type == IFT_GIF && ifp->if_bpf != NULL) 301ab2f8295Sbluhm bpf_mtap_af(ifp->if_bpf, iaf, m, BPF_DIRECTION_IN); 302ca37dd6cSbluhm #endif 303ca37dd6cSbluhm #if NPF > 0 304ca37dd6cSbluhm pf_pkt_addr_changed(m); 305ca37dd6cSbluhm #endif 306ca37dd6cSbluhm 3079a570b6dSangelos /* 3089a570b6dSangelos * Interface pointer stays the same; if no IPsec processing has 3099a570b6dSangelos * been done (or will be done), this will point to a normal 3109a570b6dSangelos * interface. Otherwise, it'll point to an enc interface, which 3119a570b6dSangelos * will allow a packet filter to distinguish between secure and 3129a570b6dSangelos * untrusted packets. 3139a570b6dSangelos */ 3149a570b6dSangelos 31521579e10Sclaudio switch (proto) { 31621579e10Sclaudio case IPPROTO_IPV4: 317bb24c526Sbluhm return ip_input_if(mp, offp, proto, oaf, ifp); 3189a570b6dSangelos #ifdef INET6 31921579e10Sclaudio case IPPROTO_IPV6: 320bb24c526Sbluhm return ip6_input_if(mp, offp, proto, oaf, ifp); 321ae26b3edSitojun #endif 3229a570b6dSangelos } 323458cfda4Sbluhm bad: 32436c0109eSbluhm m_freemp(mp); 32596be3d96Sbluhm return IPPROTO_DONE; 3269a570b6dSangelos } 3279a570b6dSangelos 3289a570b6dSangelos int 3290085a3a2Sclaudio ipip_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int dummy, 3300085a3a2Sclaudio int dummy2) 3319a570b6dSangelos { 3322edaa7baSmpi u_int8_t tp, otos, itos; 3332edaa7baSmpi u_int64_t obytes; 3349a570b6dSangelos struct ip *ipo; 3359a570b6dSangelos #ifdef INET6 336d5b56032Sitojun struct ip6_hdr *ip6, *ip6o; 3379a570b6dSangelos #endif /* INET6 */ 3383514aacbSmikeb #ifdef ENCDEBUG 3393514aacbSmikeb char buf[INET6_ADDRSTRLEN]; 3403514aacbSmikeb #endif 3419a570b6dSangelos 3426593f73dSangelos /* XXX Deal with empty TDB source/destination addresses. */ 3439a570b6dSangelos 3449a570b6dSangelos m_copydata(m, 0, 1, &tp); 3456593f73dSangelos tp = (tp >> 4) & 0xff; /* Get the IP version number. */ 3469a570b6dSangelos 3476593f73dSangelos switch (tdb->tdb_dst.sa.sa_family) { 3489a570b6dSangelos case AF_INET: 3496593f73dSangelos if (tdb->tdb_src.sa.sa_family != AF_INET || 3506593f73dSangelos tdb->tdb_src.sin.sin_addr.s_addr == INADDR_ANY || 3516593f73dSangelos tdb->tdb_dst.sin.sin_addr.s_addr == INADDR_ANY) { 3526593f73dSangelos 353ea784840Sbluhm DPRINTF(("%s: unspecified tunnel endpoind " 354ea784840Sbluhm "address in SA %s/%08x\n", __func__, 3553514aacbSmikeb ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)), 3563514aacbSmikeb ntohl(tdb->tdb_spi))); 3576593f73dSangelos 35860dafcf9Sjca ipipstat_inc(ipips_unspec); 3599a570b6dSangelos m_freem(m); 3609a570b6dSangelos *mp = NULL; 3619a570b6dSangelos return EINVAL; 3629a570b6dSangelos } 3639a570b6dSangelos 3649a570b6dSangelos M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); 36564a3f76cSjsg if (m == NULL) { 366ea784840Sbluhm DPRINTF(("%s: M_PREPEND failed\n", __func__)); 36760dafcf9Sjca ipipstat_inc(ipips_hdrops); 3689a570b6dSangelos *mp = NULL; 3699a570b6dSangelos return ENOBUFS; 3709a570b6dSangelos } 3719a570b6dSangelos 3729a570b6dSangelos ipo = mtod(m, struct ip *); 3739a570b6dSangelos 3749a570b6dSangelos ipo->ip_v = IPVERSION; 3759a570b6dSangelos ipo->ip_hl = 5; 3769a570b6dSangelos ipo->ip_len = htons(m->m_pkthdr.len); 3779a570b6dSangelos ipo->ip_ttl = ip_defttl; 3789a570b6dSangelos ipo->ip_sum = 0; 3799a570b6dSangelos ipo->ip_src = tdb->tdb_src.sin.sin_addr; 3809a570b6dSangelos ipo->ip_dst = tdb->tdb_dst.sin.sin_addr; 3819a570b6dSangelos 3829a570b6dSangelos /* 3839a570b6dSangelos * We do the htons() to prevent snoopers from determining our 3849a570b6dSangelos * endianness. 3859a570b6dSangelos */ 3869a570b6dSangelos ipo->ip_id = htons(ip_randomid()); 3879a570b6dSangelos 3886593f73dSangelos /* If the inner protocol is IP... */ 3896593f73dSangelos if (tp == IPVERSION) { 3909a570b6dSangelos /* Save ECN notification */ 3916593f73dSangelos m_copydata(m, sizeof(struct ip) + 3926593f73dSangelos offsetof(struct ip, ip_tos), 3939a570b6dSangelos sizeof(u_int8_t), (caddr_t) &itos); 3949a570b6dSangelos 3959a570b6dSangelos ipo->ip_p = IPPROTO_IPIP; 3969a570b6dSangelos 3979a570b6dSangelos /* 3986593f73dSangelos * We should be keeping tunnel soft-state and 3996593f73dSangelos * send back ICMPs if needed. 4009a570b6dSangelos */ 4016593f73dSangelos m_copydata(m, sizeof(struct ip) + 4026593f73dSangelos offsetof(struct ip, ip_off), 4039a570b6dSangelos sizeof(u_int16_t), (caddr_t) &ipo->ip_off); 404faf7e06fSmpi ipo->ip_off = ntohs(ipo->ip_off); 40570d36f83Sangelos ipo->ip_off &= ~(IP_DF | IP_MF | IP_OFFMASK); 406faf7e06fSmpi ipo->ip_off = htons(ipo->ip_off); 4079a570b6dSangelos } 4089a570b6dSangelos #ifdef INET6 4096593f73dSangelos else if (tp == (IPV6_VERSION >> 4)) { 4109a570b6dSangelos u_int32_t itos32; 4116593f73dSangelos 4126593f73dSangelos /* Save ECN notification. */ 4139a570b6dSangelos m_copydata(m, sizeof(struct ip) + 4149a570b6dSangelos offsetof(struct ip6_hdr, ip6_flow), 4159a570b6dSangelos sizeof(u_int32_t), (caddr_t) &itos32); 4169a570b6dSangelos itos = ntohl(itos32) >> 20; 4179a570b6dSangelos ipo->ip_p = IPPROTO_IPV6; 4189a570b6dSangelos ipo->ip_off = 0; 4199a570b6dSangelos } 4209a570b6dSangelos #endif /* INET6 */ 4216593f73dSangelos else { 4229a570b6dSangelos m_freem(m); 4239a570b6dSangelos *mp = NULL; 42460dafcf9Sjca ipipstat_inc(ipips_family); 4259a570b6dSangelos return EAFNOSUPPORT; 4269a570b6dSangelos } 4279a570b6dSangelos 4289a570b6dSangelos otos = 0; 4299a570b6dSangelos ip_ecn_ingress(ECN_ALLOWED, &otos, &itos); 4309a570b6dSangelos ipo->ip_tos = otos; 4319a570b6dSangelos break; 4329a570b6dSangelos 4339a570b6dSangelos #ifdef INET6 4349a570b6dSangelos case AF_INET6: 4359a570b6dSangelos if (IN6_IS_ADDR_UNSPECIFIED(&tdb->tdb_dst.sin6.sin6_addr) || 4366593f73dSangelos tdb->tdb_src.sa.sa_family != AF_INET6 || 4376593f73dSangelos IN6_IS_ADDR_UNSPECIFIED(&tdb->tdb_src.sin6.sin6_addr)) { 4386593f73dSangelos 439ea784840Sbluhm DPRINTF(("%s: unspecified tunnel endpoind " 440ea784840Sbluhm "address in SA %s/%08x\n", __func__, 4413514aacbSmikeb ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)), 4423514aacbSmikeb ntohl(tdb->tdb_spi))); 4436593f73dSangelos 44460dafcf9Sjca ipipstat_inc(ipips_unspec); 4459a570b6dSangelos m_freem(m); 4469a570b6dSangelos *mp = NULL; 4479a570b6dSangelos return ENOBUFS; 4489a570b6dSangelos } 4499a570b6dSangelos 450424a21eaStodd /* If the inner protocol is IPv6, clear link local scope */ 451424a21eaStodd if (tp == (IPV6_VERSION >> 4)) { 452d5b56032Sitojun /* scoped address handling */ 453d5b56032Sitojun ip6 = mtod(m, struct ip6_hdr *); 45465b748d4Sitojun if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src)) 455d5b56032Sitojun ip6->ip6_src.s6_addr16[1] = 0; 45665b748d4Sitojun if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst)) 457d5b56032Sitojun ip6->ip6_dst.s6_addr16[1] = 0; 458424a21eaStodd } 459d5b56032Sitojun 4609a570b6dSangelos M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT); 46164a3f76cSjsg if (m == NULL) { 462ea784840Sbluhm DPRINTF(("%s: M_PREPEND failed\n", __func__)); 46360dafcf9Sjca ipipstat_inc(ipips_hdrops); 4649a570b6dSangelos *mp = NULL; 4659a570b6dSangelos return ENOBUFS; 4669a570b6dSangelos } 4679a570b6dSangelos 4689a570b6dSangelos /* Initialize IPv6 header */ 4699a570b6dSangelos ip6o = mtod(m, struct ip6_hdr *); 4709a570b6dSangelos ip6o->ip6_flow = 0; 4719a570b6dSangelos ip6o->ip6_vfc &= ~IPV6_VERSION_MASK; 4729a570b6dSangelos ip6o->ip6_vfc |= IPV6_VERSION; 473086d35e9Smarkus ip6o->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6o)); 4749a570b6dSangelos ip6o->ip6_hlim = ip_defttl; 4752305623bSclaudio in6_embedscope(&ip6o->ip6_src, &tdb->tdb_src.sin6, NULL); 4762305623bSclaudio in6_embedscope(&ip6o->ip6_dst, &tdb->tdb_dst.sin6, NULL); 4779a570b6dSangelos 4786593f73dSangelos if (tp == IPVERSION) { 4799a570b6dSangelos /* Save ECN notification */ 4809a570b6dSangelos m_copydata(m, sizeof(struct ip6_hdr) + 4819a570b6dSangelos offsetof(struct ip, ip_tos), sizeof(u_int8_t), 4829a570b6dSangelos (caddr_t) &itos); 4839a570b6dSangelos 4846593f73dSangelos /* This is really IPVERSION. */ 4856593f73dSangelos ip6o->ip6_nxt = IPPROTO_IPIP; 4869a570b6dSangelos } 4879a570b6dSangelos else 4886593f73dSangelos if (tp == (IPV6_VERSION >> 4)) { 4899a570b6dSangelos u_int32_t itos32; 4906593f73dSangelos 4916593f73dSangelos /* Save ECN notification. */ 4929a570b6dSangelos m_copydata(m, sizeof(struct ip6_hdr) + 4939a570b6dSangelos offsetof(struct ip6_hdr, ip6_flow), 4949a570b6dSangelos sizeof(u_int32_t), (caddr_t) &itos32); 4959a570b6dSangelos itos = ntohl(itos32) >> 20; 4969a570b6dSangelos 4979a570b6dSangelos ip6o->ip6_nxt = IPPROTO_IPV6; 4986593f73dSangelos } else { 4999a570b6dSangelos m_freem(m); 5009a570b6dSangelos *mp = NULL; 50160dafcf9Sjca ipipstat_inc(ipips_family); 5029a570b6dSangelos return EAFNOSUPPORT; 5039a570b6dSangelos } 5049a570b6dSangelos 5059a570b6dSangelos otos = 0; 5069a570b6dSangelos ip_ecn_ingress(ECN_ALLOWED, &otos, &itos); 5079a570b6dSangelos ip6o->ip6_flow |= htonl((u_int32_t) otos << 20); 5089a570b6dSangelos break; 5099a570b6dSangelos #endif /* INET6 */ 5109a570b6dSangelos 5119a570b6dSangelos default: 512ea784840Sbluhm DPRINTF(("%s: unsupported protocol family %d\n", __func__, 5139a570b6dSangelos tdb->tdb_dst.sa.sa_family)); 5149a570b6dSangelos m_freem(m); 5159a570b6dSangelos *mp = NULL; 51660dafcf9Sjca ipipstat_inc(ipips_family); 51767a9371aSangelos return EAFNOSUPPORT; 5189a570b6dSangelos } 5199a570b6dSangelos 52060dafcf9Sjca ipipstat_inc(ipips_opackets); 5219a570b6dSangelos *mp = m; 5229a570b6dSangelos 5236593f73dSangelos if (tdb->tdb_dst.sa.sa_family == AF_INET) { 5242edaa7baSmpi obytes = m->m_pkthdr.len - sizeof(struct ip); 5259a570b6dSangelos if (tdb->tdb_xform->xf_type == XF_IP4) 5262edaa7baSmpi tdb->tdb_cur_bytes += obytes; 5279a570b6dSangelos 5282edaa7baSmpi ipipstat_add(ipips_obytes, obytes); 5299a570b6dSangelos } 5309a570b6dSangelos 5319a570b6dSangelos #ifdef INET6 5326593f73dSangelos if (tdb->tdb_dst.sa.sa_family == AF_INET6) { 5332edaa7baSmpi obytes = m->m_pkthdr.len - sizeof(struct ip6_hdr); 5349a570b6dSangelos if (tdb->tdb_xform->xf_type == XF_IP4) 5352edaa7baSmpi tdb->tdb_cur_bytes += obytes; 5369a570b6dSangelos 5372edaa7baSmpi ipipstat_add(ipips_obytes, obytes); 5389a570b6dSangelos } 5399a570b6dSangelos #endif /* INET6 */ 5409a570b6dSangelos 5419a570b6dSangelos return 0; 5429a570b6dSangelos } 5439a570b6dSangelos 5449a570b6dSangelos #ifdef IPSEC 5459a570b6dSangelos int 546c799dc6dSnaddy ipe4_attach(void) 5479a570b6dSangelos { 5489a570b6dSangelos return 0; 5499a570b6dSangelos } 5509a570b6dSangelos 5519a570b6dSangelos int 5529a570b6dSangelos ipe4_init(struct tdb *tdbp, struct xformsw *xsp, struct ipsecinit *ii) 5539a570b6dSangelos { 5549a570b6dSangelos tdbp->tdb_xform = xsp; 5559a570b6dSangelos return 0; 5569a570b6dSangelos } 5579a570b6dSangelos 5589a570b6dSangelos int 5599a570b6dSangelos ipe4_zeroize(struct tdb *tdbp) 5609a570b6dSangelos { 5619a570b6dSangelos return 0; 5629a570b6dSangelos } 5639a570b6dSangelos 564dde15c32Sbluhm int 565dde15c32Sbluhm ipe4_input(struct mbuf *m, struct tdb *tdb, int hlen, int proto) 5669a570b6dSangelos { 5676593f73dSangelos /* This is a rather serious mistake, so no conditional printing. */ 5689a570b6dSangelos printf("ipe4_input(): should never be called\n"); 5699a570b6dSangelos m_freem(m); 570dde15c32Sbluhm return EINVAL; 5719a570b6dSangelos } 5729a570b6dSangelos #endif /* IPSEC */ 5739a570b6dSangelos 5749a570b6dSangelos int 57560dafcf9Sjca ipip_sysctl_ipipstat(void *oldp, size_t *oldlenp, void *newp) 57660dafcf9Sjca { 57760dafcf9Sjca struct ipipstat ipipstat; 57860dafcf9Sjca 57960dafcf9Sjca CTASSERT(sizeof(ipipstat) == (ipips_ncounters * sizeof(uint64_t))); 580c8915b1eSderaadt memset(&ipipstat, 0, sizeof ipipstat); 58160dafcf9Sjca counters_read(ipipcounters, (uint64_t *)&ipipstat, ipips_ncounters); 58260dafcf9Sjca return (sysctl_rdstruct(oldp, oldlenp, newp, 58360dafcf9Sjca &ipipstat, sizeof(ipipstat))); 58460dafcf9Sjca } 58560dafcf9Sjca 58660dafcf9Sjca int 5876593f73dSangelos ipip_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, 5886593f73dSangelos size_t newlen) 5899a570b6dSangelos { 590df4a15bcSmpi int error; 591df4a15bcSmpi 5929a570b6dSangelos /* All sysctl names at this level are terminal. */ 5939a570b6dSangelos if (namelen != 1) 5949a570b6dSangelos return (ENOTDIR); 5959a570b6dSangelos 5969a570b6dSangelos switch (name[0]) { 5979a570b6dSangelos case IPIPCTL_ALLOW: 598df4a15bcSmpi NET_LOCK(); 599*70464ff2Sgnezdo error = sysctl_int_bounded(oldp, oldlenp, newp, newlen, 600*70464ff2Sgnezdo &ipip_allow, 0, 2); 601df4a15bcSmpi NET_UNLOCK(); 602df4a15bcSmpi return (error); 603ab46c28dSderaadt case IPIPCTL_STATS: 60460dafcf9Sjca return (ipip_sysctl_ipipstat(oldp, oldlenp, newp)); 6059a570b6dSangelos default: 6069a570b6dSangelos return (ENOPROTOOPT); 6079a570b6dSangelos } 6089a570b6dSangelos /* NOTREACHED */ 6099a570b6dSangelos } 610