1*7af0f08fSmvs /* $OpenBSD: ip_ipip.c,v 1.105 2024/08/22 10:58:31 mvs 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> 63940d25acSbluhm #include <netinet6/ip6_var.h> 649a570b6dSangelos #include <netinet/ip_ecn.h> 65ea784840Sbluhm #include <netinet/ip_ipip.h> 669a570b6dSangelos 679a570b6dSangelos #ifdef MROUTING 689a570b6dSangelos #include <netinet/ip_mroute.h> 699a570b6dSangelos #endif 709a570b6dSangelos 710c8db51fShenning #if NPF > 0 720c8db51fShenning #include <net/pfvar.h> 730c8db51fShenning #endif 740c8db51fShenning 75*7af0f08fSmvs /* 76*7af0f08fSmvs * Locks used to protect data: 77*7af0f08fSmvs * a atomic 78*7af0f08fSmvs */ 79*7af0f08fSmvs 809a570b6dSangelos #ifdef ENCDEBUG 81698a75ddSbluhm #define DPRINTF(fmt, args...) \ 82698a75ddSbluhm do { \ 83698a75ddSbluhm if (encdebug) \ 84698a75ddSbluhm printf("%s: " fmt "\n", __func__, ## args); \ 85698a75ddSbluhm } while (0) 869a570b6dSangelos #else 87698a75ddSbluhm #define DPRINTF(fmt, args...) \ 88698a75ddSbluhm do { } while (0) 899a570b6dSangelos #endif 909a570b6dSangelos 919a570b6dSangelos /* 929a570b6dSangelos * We can control the acceptance of IP4 packets by altering the sysctl 939a570b6dSangelos * net.inet.ipip.allow value. Zero means drop them, all else is acceptance. 949a570b6dSangelos */ 95*7af0f08fSmvs int ipip_allow = 0; /* [a] */ 969a570b6dSangelos 9760dafcf9Sjca struct cpumem *ipipcounters; 9860dafcf9Sjca 9960dafcf9Sjca void 10060dafcf9Sjca ipip_init(void) 10160dafcf9Sjca { 10260dafcf9Sjca ipipcounters = counters_alloc(ipips_ncounters); 10360dafcf9Sjca } 1049a570b6dSangelos 1059a570b6dSangelos /* 106ab2f8295Sbluhm * Really only a wrapper for ipip_input_if(), for use with pr_input. 1079a570b6dSangelos */ 1089a570b6dSangelos int 109ab2f8295Sbluhm ipip_input(struct mbuf **mp, int *offp, int nxt, int af) 1109a570b6dSangelos { 111ab2f8295Sbluhm struct ifnet *ifp; 112*7af0f08fSmvs int ipip_allow_local = atomic_load_int(&ipip_allow); 113ab2f8295Sbluhm 114ae26b3edSitojun /* If we do not accept IP-in-IP explicitly, drop. */ 115*7af0f08fSmvs if (ipip_allow_local == 0 && ((*mp)->m_flags & (M_AUTH|M_CONF)) == 0) { 116698a75ddSbluhm DPRINTF("dropped due to policy"); 11760dafcf9Sjca ipipstat_inc(ipips_pdrops); 11836c0109eSbluhm m_freemp(mp); 1199a570b6dSangelos return IPPROTO_DONE; 1209a570b6dSangelos } 1219a570b6dSangelos 122ab2f8295Sbluhm ifp = if_get((*mp)->m_pkthdr.ph_ifidx); 123ab2f8295Sbluhm if (ifp == NULL) { 124ab2f8295Sbluhm m_freemp(mp); 125ab2f8295Sbluhm return IPPROTO_DONE; 126ab2f8295Sbluhm } 127*7af0f08fSmvs nxt = ipip_input_if(mp, offp, nxt, af, ipip_allow_local, ifp); 128ab2f8295Sbluhm if_put(ifp); 129ab2f8295Sbluhm 130ab2f8295Sbluhm return nxt; 1319a570b6dSangelos } 1329a570b6dSangelos 1339a570b6dSangelos /* 1349a570b6dSangelos * ipip_input gets called when we receive an IP{46} encapsulated packet, 1359a570b6dSangelos * either because we got it at a real interface, or because AH or ESP 136fb492c37Smpi * were being used in tunnel mode (in which case the ph_ifidx element 137fb492c37Smpi * will contain the index of the encX interface associated with the 138fb492c37Smpi * tunnel. 1399a570b6dSangelos */ 1409a570b6dSangelos 14196be3d96Sbluhm int 142*7af0f08fSmvs ipip_input_if(struct mbuf **mp, int *offp, int proto, int oaf, int allow, 143ab2f8295Sbluhm struct ifnet *ifp) 1449a570b6dSangelos { 14596be3d96Sbluhm struct mbuf *m = *mp; 14664aa4cc7Sitojun struct sockaddr_in *sin; 1471bcb5a76Sbluhm struct ip *ip; 1489a570b6dSangelos #ifdef INET6 14964aa4cc7Sitojun struct sockaddr_in6 *sin6; 15021579e10Sclaudio struct ip6_hdr *ip6; 1519a570b6dSangelos #endif 15298a920fdSdlg int mode, hlen; 153c9857360Smarkus u_int8_t itos, otos; 154ea784840Sbluhm sa_family_t iaf; 1559a570b6dSangelos 15660dafcf9Sjca ipipstat_inc(ipips_ipackets); 1579a570b6dSangelos 158289a9ae9Sbluhm switch (oaf) { 159289a9ae9Sbluhm case AF_INET: 1609a570b6dSangelos hlen = sizeof(struct ip); 1619a570b6dSangelos break; 1629a570b6dSangelos #ifdef INET6 163289a9ae9Sbluhm case AF_INET6: 1649a570b6dSangelos hlen = sizeof(struct ip6_hdr); 1659a570b6dSangelos break; 1669a570b6dSangelos #endif 167795830a0Sangelos default: 168289a9ae9Sbluhm unhandled_af(oaf); 1699a570b6dSangelos } 1709a570b6dSangelos 1719a570b6dSangelos /* Bring the IP header in the first mbuf, if not there already */ 1726593f73dSangelos if (m->m_len < hlen) { 173eabae73bSbluhm if ((m = *mp = m_pullup(m, hlen)) == NULL) { 174698a75ddSbluhm DPRINTF("m_pullup() failed"); 17560dafcf9Sjca ipipstat_inc(ipips_hdrops); 176458cfda4Sbluhm goto bad; 1779a570b6dSangelos } 1789a570b6dSangelos } 1799a570b6dSangelos 1806593f73dSangelos /* Keep outer ecn field. */ 181289a9ae9Sbluhm switch (oaf) { 182289a9ae9Sbluhm case AF_INET: 1831bcb5a76Sbluhm ip = mtod(m, struct ip *); 1841bcb5a76Sbluhm otos = ip->ip_tos; 185ae26b3edSitojun break; 1869a570b6dSangelos #ifdef INET6 187289a9ae9Sbluhm case AF_INET6: 18821579e10Sclaudio ip6 = mtod(m, struct ip6_hdr *); 18921579e10Sclaudio otos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 190ae26b3edSitojun break; 1919a570b6dSangelos #endif 192ae26b3edSitojun } 1939a570b6dSangelos 1942b1f9644Sangelos /* Remove outer IP header */ 1951bcb5a76Sbluhm KASSERT(*offp > 0); 1961bcb5a76Sbluhm m_adj(m, *offp); 1971bcb5a76Sbluhm *offp = 0; 1981bcb5a76Sbluhm ip = NULL; 1991bcb5a76Sbluhm #ifdef INET6 2001bcb5a76Sbluhm ip6 = NULL; 2011bcb5a76Sbluhm #endif 2026d386255Sangelos 20321579e10Sclaudio switch (proto) { 20421579e10Sclaudio case IPPROTO_IPV4: 2059a570b6dSangelos hlen = sizeof(struct ip); 2069a570b6dSangelos break; 2079a570b6dSangelos 2089a570b6dSangelos #ifdef INET6 20921579e10Sclaudio case IPPROTO_IPV6: 2109a570b6dSangelos hlen = sizeof(struct ip6_hdr); 2119a570b6dSangelos break; 2129a570b6dSangelos #endif 213ae26b3edSitojun default: 21460dafcf9Sjca ipipstat_inc(ipips_family); 215458cfda4Sbluhm goto bad; 2169a570b6dSangelos } 2179a570b6dSangelos 2181bcb5a76Sbluhm /* Sanity check */ 2191bcb5a76Sbluhm if (m->m_pkthdr.len < hlen) { 2201bcb5a76Sbluhm ipipstat_inc(ipips_hdrops); 221458cfda4Sbluhm goto bad; 2221bcb5a76Sbluhm } 2231bcb5a76Sbluhm 2246593f73dSangelos /* 22521579e10Sclaudio * Bring the inner header into the first mbuf, if not there already. 2266593f73dSangelos */ 2276593f73dSangelos if (m->m_len < hlen) { 228eabae73bSbluhm if ((m = *mp = m_pullup(m, hlen)) == NULL) { 229698a75ddSbluhm DPRINTF("m_pullup() failed"); 23060dafcf9Sjca ipipstat_inc(ipips_hdrops); 231458cfda4Sbluhm goto bad; 2329a570b6dSangelos } 2339a570b6dSangelos } 2349a570b6dSangelos 2359a570b6dSangelos /* 2369a570b6dSangelos * RFC 1853 specifies that the inner TTL should not be touched on 2379a570b6dSangelos * decapsulation. There's no reason this comment should be here, but 2389a570b6dSangelos * this is as good as any a position. 2399a570b6dSangelos */ 2409a570b6dSangelos 241ae26b3edSitojun /* Some sanity checks in the inner IP header */ 24221579e10Sclaudio switch (proto) { 24321579e10Sclaudio case IPPROTO_IPV4: 244ca37dd6cSbluhm iaf = AF_INET; 2451bcb5a76Sbluhm ip = mtod(m, struct ip *); 2461bcb5a76Sbluhm hlen = ip->ip_hl << 2; 2471bcb5a76Sbluhm if (m->m_pkthdr.len < hlen) { 2481bcb5a76Sbluhm ipipstat_inc(ipips_hdrops); 249ab2f8295Sbluhm goto bad; 2501bcb5a76Sbluhm } 2511bcb5a76Sbluhm itos = ip->ip_tos; 252c9857360Smarkus mode = m->m_flags & (M_AUTH|M_CONF) ? 253c9857360Smarkus ECN_ALLOWED_IPSEC : ECN_ALLOWED; 254412c1a0aSdlg if (!ip_ecn_egress(mode, &otos, &itos)) { 255698a75ddSbluhm DPRINTF("ip_ecn_egress() failed"); 25660dafcf9Sjca ipipstat_inc(ipips_pdrops); 257458cfda4Sbluhm goto bad; 25874e8fb40Skjc } 259c9857360Smarkus /* re-calculate the checksum if ip_tos was changed */ 260412c1a0aSdlg if (itos != ip->ip_tos) 261412c1a0aSdlg ip_tos_patch(ip, itos); 2629a570b6dSangelos break; 2639a570b6dSangelos #ifdef INET6 26421579e10Sclaudio case IPPROTO_IPV6: 265ca37dd6cSbluhm iaf = AF_INET6; 26621579e10Sclaudio ip6 = mtod(m, struct ip6_hdr *); 2679a570b6dSangelos itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 26874e8fb40Skjc if (!ip_ecn_egress(ECN_ALLOWED, &otos, &itos)) { 269698a75ddSbluhm DPRINTF("ip_ecn_egress() failed"); 27060dafcf9Sjca ipipstat_inc(ipips_pdrops); 271458cfda4Sbluhm goto bad; 27274e8fb40Skjc } 2739a570b6dSangelos ip6->ip6_flow &= ~htonl(0xff << 20); 2749a570b6dSangelos ip6->ip6_flow |= htonl((u_int32_t) itos << 20); 2759a570b6dSangelos break; 2769a570b6dSangelos #endif 2779a570b6dSangelos } 2789a570b6dSangelos 2799a570b6dSangelos /* Check for local address spoofing. */ 280*7af0f08fSmvs if (!(ifp->if_flags & IFF_LOOPBACK) && allow != 2) { 281d33580a9Smpi struct sockaddr_storage ss; 282d33580a9Smpi struct rtentry *rt; 283d33580a9Smpi 284d33580a9Smpi memset(&ss, 0, sizeof(ss)); 285d33580a9Smpi 2861bcb5a76Sbluhm if (ip) { 287d33580a9Smpi sin = (struct sockaddr_in *)&ss; 288d33580a9Smpi sin->sin_family = AF_INET; 289d33580a9Smpi sin->sin_len = sizeof(*sin); 2901bcb5a76Sbluhm sin->sin_addr = ip->ip_src; 2919a570b6dSangelos #ifdef INET6 292d33580a9Smpi } else if (ip6) { 293d33580a9Smpi sin6 = (struct sockaddr_in6 *)&ss; 294d33580a9Smpi sin6->sin6_family = AF_INET6; 295d33580a9Smpi sin6->sin6_len = sizeof(*sin6); 296d33580a9Smpi sin6->sin6_addr = ip6->ip6_src; 2979a570b6dSangelos #endif /* INET6 */ 2989a570b6dSangelos } 2999c681c75Sbluhm rt = rtalloc(sstosa(&ss), 0, m->m_pkthdr.ph_rtableid); 300d33580a9Smpi if ((rt != NULL) && (rt->rt_flags & RTF_LOCAL)) { 30160dafcf9Sjca ipipstat_inc(ipips_spoof); 302d33580a9Smpi rtfree(rt); 303458cfda4Sbluhm goto bad; 3049a570b6dSangelos } 305d33580a9Smpi rtfree(rt); 3069a570b6dSangelos } 3079a570b6dSangelos 3089a570b6dSangelos /* Statistics */ 3091bcb5a76Sbluhm ipipstat_add(ipips_ibytes, m->m_pkthdr.len - hlen); 3109a570b6dSangelos 311ab2f8295Sbluhm #if NBPFILTER > 0 && NGIF > 0 312ab2f8295Sbluhm if (ifp->if_type == IFT_GIF && ifp->if_bpf != NULL) 313ab2f8295Sbluhm bpf_mtap_af(ifp->if_bpf, iaf, m, BPF_DIRECTION_IN); 314ca37dd6cSbluhm #endif 315ca37dd6cSbluhm #if NPF > 0 316ca37dd6cSbluhm pf_pkt_addr_changed(m); 317ca37dd6cSbluhm #endif 318ca37dd6cSbluhm 3199a570b6dSangelos /* 3209a570b6dSangelos * Interface pointer stays the same; if no IPsec processing has 3219a570b6dSangelos * been done (or will be done), this will point to a normal 3229a570b6dSangelos * interface. Otherwise, it'll point to an enc interface, which 3239a570b6dSangelos * will allow a packet filter to distinguish between secure and 3249a570b6dSangelos * untrusted packets. 3259a570b6dSangelos */ 3269a570b6dSangelos 32721579e10Sclaudio switch (proto) { 32821579e10Sclaudio case IPPROTO_IPV4: 329bb24c526Sbluhm return ip_input_if(mp, offp, proto, oaf, ifp); 3309a570b6dSangelos #ifdef INET6 33121579e10Sclaudio case IPPROTO_IPV6: 332bb24c526Sbluhm return ip6_input_if(mp, offp, proto, oaf, ifp); 333ae26b3edSitojun #endif 3349a570b6dSangelos } 335458cfda4Sbluhm bad: 33636c0109eSbluhm m_freemp(mp); 33796be3d96Sbluhm return IPPROTO_DONE; 3389a570b6dSangelos } 3399a570b6dSangelos 3409a570b6dSangelos int 341ead5a062Sbluhm ipip_output(struct mbuf **mp, struct tdb *tdb) 3429a570b6dSangelos { 343ead5a062Sbluhm struct mbuf *m = *mp; 3442edaa7baSmpi u_int8_t tp, otos, itos; 3452edaa7baSmpi u_int64_t obytes; 3469a570b6dSangelos struct ip *ipo; 3479a570b6dSangelos #ifdef INET6 348d5b56032Sitojun struct ip6_hdr *ip6, *ip6o; 3499a570b6dSangelos #endif /* INET6 */ 3503514aacbSmikeb #ifdef ENCDEBUG 3513514aacbSmikeb char buf[INET6_ADDRSTRLEN]; 3523514aacbSmikeb #endif 353e4b51ed2Sbluhm int error; 3549a570b6dSangelos 3556593f73dSangelos /* XXX Deal with empty TDB source/destination addresses. */ 3569a570b6dSangelos 3579a570b6dSangelos m_copydata(m, 0, 1, &tp); 3586593f73dSangelos tp = (tp >> 4) & 0xff; /* Get the IP version number. */ 3599a570b6dSangelos 3606593f73dSangelos switch (tdb->tdb_dst.sa.sa_family) { 3619a570b6dSangelos case AF_INET: 3626593f73dSangelos if (tdb->tdb_src.sa.sa_family != AF_INET || 3636593f73dSangelos tdb->tdb_src.sin.sin_addr.s_addr == INADDR_ANY || 3646593f73dSangelos tdb->tdb_dst.sin.sin_addr.s_addr == INADDR_ANY) { 3656593f73dSangelos 366df8d9afdSjsg DPRINTF("unspecified tunnel endpoint address " 367698a75ddSbluhm "in SA %s/%08x", 3683514aacbSmikeb ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)), 369698a75ddSbluhm ntohl(tdb->tdb_spi)); 3706593f73dSangelos 37160dafcf9Sjca ipipstat_inc(ipips_unspec); 372e4b51ed2Sbluhm error = EINVAL; 373e4b51ed2Sbluhm goto drop; 3749a570b6dSangelos } 3759a570b6dSangelos 376ead5a062Sbluhm M_PREPEND(*mp, sizeof(struct ip), M_DONTWAIT); 377ead5a062Sbluhm if (*mp == NULL) { 378698a75ddSbluhm DPRINTF("M_PREPEND failed"); 37960dafcf9Sjca ipipstat_inc(ipips_hdrops); 380e4b51ed2Sbluhm error = ENOBUFS; 381e4b51ed2Sbluhm goto drop; 3829a570b6dSangelos } 383ead5a062Sbluhm m = *mp; 3849a570b6dSangelos 3859a570b6dSangelos ipo = mtod(m, struct ip *); 3869a570b6dSangelos 3879a570b6dSangelos ipo->ip_v = IPVERSION; 3889a570b6dSangelos ipo->ip_hl = 5; 3899a570b6dSangelos ipo->ip_len = htons(m->m_pkthdr.len); 3909a570b6dSangelos ipo->ip_ttl = ip_defttl; 3919a570b6dSangelos ipo->ip_sum = 0; 3929a570b6dSangelos ipo->ip_src = tdb->tdb_src.sin.sin_addr; 3939a570b6dSangelos ipo->ip_dst = tdb->tdb_dst.sin.sin_addr; 3949a570b6dSangelos 3959a570b6dSangelos /* 3969a570b6dSangelos * We do the htons() to prevent snoopers from determining our 3979a570b6dSangelos * endianness. 3989a570b6dSangelos */ 3999a570b6dSangelos ipo->ip_id = htons(ip_randomid()); 4009a570b6dSangelos 4016593f73dSangelos /* If the inner protocol is IP... */ 4026593f73dSangelos if (tp == IPVERSION) { 4039a570b6dSangelos /* Save ECN notification */ 4046593f73dSangelos m_copydata(m, sizeof(struct ip) + 4056593f73dSangelos offsetof(struct ip, ip_tos), 4069a570b6dSangelos sizeof(u_int8_t), (caddr_t) &itos); 4079a570b6dSangelos 4089a570b6dSangelos ipo->ip_p = IPPROTO_IPIP; 4099a570b6dSangelos 4109a570b6dSangelos /* 4116593f73dSangelos * We should be keeping tunnel soft-state and 4126593f73dSangelos * send back ICMPs if needed. 4139a570b6dSangelos */ 4146593f73dSangelos m_copydata(m, sizeof(struct ip) + 4156593f73dSangelos offsetof(struct ip, ip_off), 4169a570b6dSangelos sizeof(u_int16_t), (caddr_t) &ipo->ip_off); 417faf7e06fSmpi ipo->ip_off = ntohs(ipo->ip_off); 41870d36f83Sangelos ipo->ip_off &= ~(IP_DF | IP_MF | IP_OFFMASK); 419faf7e06fSmpi ipo->ip_off = htons(ipo->ip_off); 4209a570b6dSangelos } 4219a570b6dSangelos #ifdef INET6 4226593f73dSangelos else if (tp == (IPV6_VERSION >> 4)) { 4239a570b6dSangelos u_int32_t itos32; 4246593f73dSangelos 4256593f73dSangelos /* Save ECN notification. */ 4269a570b6dSangelos m_copydata(m, sizeof(struct ip) + 4279a570b6dSangelos offsetof(struct ip6_hdr, ip6_flow), 4289a570b6dSangelos sizeof(u_int32_t), (caddr_t) &itos32); 4299a570b6dSangelos itos = ntohl(itos32) >> 20; 4309a570b6dSangelos ipo->ip_p = IPPROTO_IPV6; 4319a570b6dSangelos ipo->ip_off = 0; 4329a570b6dSangelos } 4339a570b6dSangelos #endif /* INET6 */ 4346593f73dSangelos else { 43560dafcf9Sjca ipipstat_inc(ipips_family); 436e4b51ed2Sbluhm error = EAFNOSUPPORT; 437e4b51ed2Sbluhm goto drop; 4389a570b6dSangelos } 4399a570b6dSangelos 4409a570b6dSangelos otos = 0; 4419a570b6dSangelos ip_ecn_ingress(ECN_ALLOWED, &otos, &itos); 4429a570b6dSangelos ipo->ip_tos = otos; 443e4b51ed2Sbluhm 444e4b51ed2Sbluhm obytes = m->m_pkthdr.len - sizeof(struct ip); 445e4b51ed2Sbluhm if (tdb->tdb_xform->xf_type == XF_IP4) 446e4b51ed2Sbluhm tdb->tdb_cur_bytes += obytes; 4479a570b6dSangelos break; 4489a570b6dSangelos 4499a570b6dSangelos #ifdef INET6 4509a570b6dSangelos case AF_INET6: 4519a570b6dSangelos if (IN6_IS_ADDR_UNSPECIFIED(&tdb->tdb_dst.sin6.sin6_addr) || 4526593f73dSangelos tdb->tdb_src.sa.sa_family != AF_INET6 || 4536593f73dSangelos IN6_IS_ADDR_UNSPECIFIED(&tdb->tdb_src.sin6.sin6_addr)) { 4546593f73dSangelos 455df8d9afdSjsg DPRINTF("unspecified tunnel endpoint address " 456698a75ddSbluhm "in SA %s/%08x", 4573514aacbSmikeb ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)), 458698a75ddSbluhm ntohl(tdb->tdb_spi)); 4596593f73dSangelos 46060dafcf9Sjca ipipstat_inc(ipips_unspec); 461e4b51ed2Sbluhm error = EINVAL; 462e4b51ed2Sbluhm goto drop; 4639a570b6dSangelos } 4649a570b6dSangelos 465424a21eaStodd /* If the inner protocol is IPv6, clear link local scope */ 466424a21eaStodd if (tp == (IPV6_VERSION >> 4)) { 467d5b56032Sitojun /* scoped address handling */ 468d5b56032Sitojun ip6 = mtod(m, struct ip6_hdr *); 46965b748d4Sitojun if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src)) 470d5b56032Sitojun ip6->ip6_src.s6_addr16[1] = 0; 47165b748d4Sitojun if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst)) 472d5b56032Sitojun ip6->ip6_dst.s6_addr16[1] = 0; 473424a21eaStodd } 474d5b56032Sitojun 475ead5a062Sbluhm M_PREPEND(*mp, sizeof(struct ip6_hdr), M_DONTWAIT); 476ead5a062Sbluhm if (*mp == NULL) { 477698a75ddSbluhm DPRINTF("M_PREPEND failed"); 47860dafcf9Sjca ipipstat_inc(ipips_hdrops); 479e4b51ed2Sbluhm error = ENOBUFS; 480e4b51ed2Sbluhm goto drop; 4819a570b6dSangelos } 482ead5a062Sbluhm m = *mp; 4839a570b6dSangelos 4849a570b6dSangelos /* Initialize IPv6 header */ 4859a570b6dSangelos ip6o = mtod(m, struct ip6_hdr *); 4869a570b6dSangelos ip6o->ip6_flow = 0; 4879a570b6dSangelos ip6o->ip6_vfc &= ~IPV6_VERSION_MASK; 4889a570b6dSangelos ip6o->ip6_vfc |= IPV6_VERSION; 489086d35e9Smarkus ip6o->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6o)); 490b2d46992Sbluhm ip6o->ip6_hlim = ip6_defhlim; 491952c6363Sbluhm in6_embedscope(&ip6o->ip6_src, &tdb->tdb_src.sin6, NULL, NULL); 492952c6363Sbluhm in6_embedscope(&ip6o->ip6_dst, &tdb->tdb_dst.sin6, NULL, NULL); 4939a570b6dSangelos 4946593f73dSangelos if (tp == IPVERSION) { 4959a570b6dSangelos /* Save ECN notification */ 4969a570b6dSangelos m_copydata(m, sizeof(struct ip6_hdr) + 4979a570b6dSangelos offsetof(struct ip, ip_tos), sizeof(u_int8_t), 4989a570b6dSangelos (caddr_t) &itos); 4999a570b6dSangelos 5006593f73dSangelos /* This is really IPVERSION. */ 5016593f73dSangelos ip6o->ip6_nxt = IPPROTO_IPIP; 5029a570b6dSangelos } 5039a570b6dSangelos else 5046593f73dSangelos if (tp == (IPV6_VERSION >> 4)) { 5059a570b6dSangelos u_int32_t itos32; 5066593f73dSangelos 5076593f73dSangelos /* Save ECN notification. */ 5089a570b6dSangelos m_copydata(m, sizeof(struct ip6_hdr) + 5099a570b6dSangelos offsetof(struct ip6_hdr, ip6_flow), 5109a570b6dSangelos sizeof(u_int32_t), (caddr_t) &itos32); 5119a570b6dSangelos itos = ntohl(itos32) >> 20; 5129a570b6dSangelos 5139a570b6dSangelos ip6o->ip6_nxt = IPPROTO_IPV6; 5146593f73dSangelos } else { 51560dafcf9Sjca ipipstat_inc(ipips_family); 516e4b51ed2Sbluhm error = EAFNOSUPPORT; 517e4b51ed2Sbluhm goto drop; 5189a570b6dSangelos } 5199a570b6dSangelos 5209a570b6dSangelos otos = 0; 5219a570b6dSangelos ip_ecn_ingress(ECN_ALLOWED, &otos, &itos); 5229a570b6dSangelos ip6o->ip6_flow |= htonl((u_int32_t) otos << 20); 523e4b51ed2Sbluhm 524e4b51ed2Sbluhm obytes = m->m_pkthdr.len - sizeof(struct ip6_hdr); 525e4b51ed2Sbluhm if (tdb->tdb_xform->xf_type == XF_IP4) 526e4b51ed2Sbluhm tdb->tdb_cur_bytes += obytes; 5279a570b6dSangelos break; 5289a570b6dSangelos #endif /* INET6 */ 5299a570b6dSangelos 5309a570b6dSangelos default: 531698a75ddSbluhm DPRINTF("unsupported protocol family %d", 532698a75ddSbluhm tdb->tdb_dst.sa.sa_family); 533e4b51ed2Sbluhm ipipstat_inc(ipips_family); 534bc489a1cSbluhm error = EPFNOSUPPORT; 535e4b51ed2Sbluhm goto drop; 536e4b51ed2Sbluhm } 537e4b51ed2Sbluhm 538e4b51ed2Sbluhm ipipstat_pkt(ipips_opackets, ipips_obytes, obytes); 539e4b51ed2Sbluhm return 0; 540e4b51ed2Sbluhm 541e4b51ed2Sbluhm drop: 542ead5a062Sbluhm m_freemp(mp); 543e4b51ed2Sbluhm return error; 5449a570b6dSangelos } 5459a570b6dSangelos 5469a570b6dSangelos #ifdef IPSEC 5479a570b6dSangelos int 548c799dc6dSnaddy ipe4_attach(void) 5499a570b6dSangelos { 5509a570b6dSangelos return 0; 5519a570b6dSangelos } 5529a570b6dSangelos 5539a570b6dSangelos int 5545e3836acSbluhm ipe4_init(struct tdb *tdbp, const struct xformsw *xsp, struct ipsecinit *ii) 5559a570b6dSangelos { 5569a570b6dSangelos tdbp->tdb_xform = xsp; 5579a570b6dSangelos return 0; 5589a570b6dSangelos } 5599a570b6dSangelos 5609a570b6dSangelos int 5619a570b6dSangelos ipe4_zeroize(struct tdb *tdbp) 5629a570b6dSangelos { 5639a570b6dSangelos return 0; 5649a570b6dSangelos } 5659a570b6dSangelos 566dde15c32Sbluhm int 567d5072c26Sbluhm ipe4_input(struct mbuf **mp, struct tdb *tdb, int hlen, int proto) 5689a570b6dSangelos { 5696593f73dSangelos /* This is a rather serious mistake, so no conditional printing. */ 570698a75ddSbluhm printf("%s: should never be called\n", __func__); 571d5072c26Sbluhm m_freemp(mp); 572dde15c32Sbluhm return EINVAL; 5739a570b6dSangelos } 5749a570b6dSangelos #endif /* IPSEC */ 5759a570b6dSangelos 5769a570b6dSangelos int 57760dafcf9Sjca ipip_sysctl_ipipstat(void *oldp, size_t *oldlenp, void *newp) 57860dafcf9Sjca { 57960dafcf9Sjca struct ipipstat ipipstat; 58060dafcf9Sjca 58160dafcf9Sjca CTASSERT(sizeof(ipipstat) == (ipips_ncounters * sizeof(uint64_t))); 582c8915b1eSderaadt memset(&ipipstat, 0, sizeof ipipstat); 583bf0d449cSmpi counters_read(ipipcounters, (uint64_t *)&ipipstat, ipips_ncounters, 584bf0d449cSmpi NULL); 58560dafcf9Sjca return (sysctl_rdstruct(oldp, oldlenp, newp, 58660dafcf9Sjca &ipipstat, sizeof(ipipstat))); 58760dafcf9Sjca } 58860dafcf9Sjca 58960dafcf9Sjca int 5906593f73dSangelos ipip_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, 5916593f73dSangelos size_t newlen) 5929a570b6dSangelos { 5939a570b6dSangelos /* All sysctl names at this level are terminal. */ 5949a570b6dSangelos if (namelen != 1) 5959a570b6dSangelos return (ENOTDIR); 5969a570b6dSangelos 5979a570b6dSangelos switch (name[0]) { 5989a570b6dSangelos case IPIPCTL_ALLOW: 599*7af0f08fSmvs return (sysctl_int_bounded(oldp, oldlenp, newp, newlen, 600*7af0f08fSmvs &ipip_allow, 0, 2)); 601ab46c28dSderaadt case IPIPCTL_STATS: 60260dafcf9Sjca return (ipip_sysctl_ipipstat(oldp, oldlenp, newp)); 6039a570b6dSangelos default: 6049a570b6dSangelos return (ENOPROTOOPT); 6059a570b6dSangelos } 6069a570b6dSangelos /* NOTREACHED */ 6079a570b6dSangelos } 608