1*952c6363Sbluhm /* $OpenBSD: ip_ipip.c,v 1.100 2023/11/28 13:23:20 bluhm 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 75698a75ddSbluhm #define DPRINTF(fmt, args...) \ 76698a75ddSbluhm do { \ 77698a75ddSbluhm if (encdebug) \ 78698a75ddSbluhm printf("%s: " fmt "\n", __func__, ## args); \ 79698a75ddSbluhm } while (0) 809a570b6dSangelos #else 81698a75ddSbluhm #define DPRINTF(fmt, args...) \ 82698a75ddSbluhm do { } while (0) 839a570b6dSangelos #endif 849a570b6dSangelos 859a570b6dSangelos /* 869a570b6dSangelos * We can control the acceptance of IP4 packets by altering the sysctl 879a570b6dSangelos * net.inet.ipip.allow value. Zero means drop them, all else is acceptance. 889a570b6dSangelos */ 899a570b6dSangelos int ipip_allow = 0; 909a570b6dSangelos 9160dafcf9Sjca struct cpumem *ipipcounters; 9260dafcf9Sjca 9360dafcf9Sjca void 9460dafcf9Sjca ipip_init(void) 9560dafcf9Sjca { 9660dafcf9Sjca ipipcounters = counters_alloc(ipips_ncounters); 9760dafcf9Sjca } 989a570b6dSangelos 999a570b6dSangelos /* 100ab2f8295Sbluhm * Really only a wrapper for ipip_input_if(), for use with pr_input. 1019a570b6dSangelos */ 1029a570b6dSangelos int 103ab2f8295Sbluhm ipip_input(struct mbuf **mp, int *offp, int nxt, int af) 1049a570b6dSangelos { 105ab2f8295Sbluhm struct ifnet *ifp; 106ab2f8295Sbluhm 107ae26b3edSitojun /* If we do not accept IP-in-IP explicitly, drop. */ 108f0c13189Sderaadt if (!ipip_allow && ((*mp)->m_flags & (M_AUTH|M_CONF)) == 0) { 109698a75ddSbluhm DPRINTF("dropped due to policy"); 11060dafcf9Sjca ipipstat_inc(ipips_pdrops); 11136c0109eSbluhm m_freemp(mp); 1129a570b6dSangelos return IPPROTO_DONE; 1139a570b6dSangelos } 1149a570b6dSangelos 115ab2f8295Sbluhm ifp = if_get((*mp)->m_pkthdr.ph_ifidx); 116ab2f8295Sbluhm if (ifp == NULL) { 117ab2f8295Sbluhm m_freemp(mp); 118ab2f8295Sbluhm return IPPROTO_DONE; 119ab2f8295Sbluhm } 120ab2f8295Sbluhm nxt = ipip_input_if(mp, offp, nxt, af, ifp); 121ab2f8295Sbluhm if_put(ifp); 122ab2f8295Sbluhm 123ab2f8295Sbluhm return nxt; 1249a570b6dSangelos } 1259a570b6dSangelos 1269a570b6dSangelos /* 1279a570b6dSangelos * ipip_input gets called when we receive an IP{46} encapsulated packet, 1289a570b6dSangelos * either because we got it at a real interface, or because AH or ESP 129fb492c37Smpi * were being used in tunnel mode (in which case the ph_ifidx element 130fb492c37Smpi * will contain the index of the encX interface associated with the 131fb492c37Smpi * tunnel. 1329a570b6dSangelos */ 1339a570b6dSangelos 13496be3d96Sbluhm int 135ab2f8295Sbluhm ipip_input_if(struct mbuf **mp, int *offp, int proto, int oaf, 136ab2f8295Sbluhm struct ifnet *ifp) 1379a570b6dSangelos { 13896be3d96Sbluhm struct mbuf *m = *mp; 13964aa4cc7Sitojun struct sockaddr_in *sin; 1401bcb5a76Sbluhm struct ip *ip; 1419a570b6dSangelos #ifdef INET6 14264aa4cc7Sitojun struct sockaddr_in6 *sin6; 14321579e10Sclaudio struct ip6_hdr *ip6; 1449a570b6dSangelos #endif 14598a920fdSdlg int mode, hlen; 146c9857360Smarkus u_int8_t itos, otos; 147ea784840Sbluhm sa_family_t iaf; 1489a570b6dSangelos 14960dafcf9Sjca ipipstat_inc(ipips_ipackets); 1509a570b6dSangelos 151289a9ae9Sbluhm switch (oaf) { 152289a9ae9Sbluhm case AF_INET: 1539a570b6dSangelos hlen = sizeof(struct ip); 1549a570b6dSangelos break; 1559a570b6dSangelos #ifdef INET6 156289a9ae9Sbluhm case AF_INET6: 1579a570b6dSangelos hlen = sizeof(struct ip6_hdr); 1589a570b6dSangelos break; 1599a570b6dSangelos #endif 160795830a0Sangelos default: 161289a9ae9Sbluhm unhandled_af(oaf); 1629a570b6dSangelos } 1639a570b6dSangelos 1649a570b6dSangelos /* Bring the IP header in the first mbuf, if not there already */ 1656593f73dSangelos if (m->m_len < hlen) { 166eabae73bSbluhm if ((m = *mp = m_pullup(m, hlen)) == NULL) { 167698a75ddSbluhm DPRINTF("m_pullup() failed"); 16860dafcf9Sjca ipipstat_inc(ipips_hdrops); 169458cfda4Sbluhm goto bad; 1709a570b6dSangelos } 1719a570b6dSangelos } 1729a570b6dSangelos 1736593f73dSangelos /* Keep outer ecn field. */ 174289a9ae9Sbluhm switch (oaf) { 175289a9ae9Sbluhm case AF_INET: 1761bcb5a76Sbluhm ip = mtod(m, struct ip *); 1771bcb5a76Sbluhm otos = ip->ip_tos; 178ae26b3edSitojun break; 1799a570b6dSangelos #ifdef INET6 180289a9ae9Sbluhm case AF_INET6: 18121579e10Sclaudio ip6 = mtod(m, struct ip6_hdr *); 18221579e10Sclaudio otos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 183ae26b3edSitojun break; 1849a570b6dSangelos #endif 185ae26b3edSitojun } 1869a570b6dSangelos 1872b1f9644Sangelos /* Remove outer IP header */ 1881bcb5a76Sbluhm KASSERT(*offp > 0); 1891bcb5a76Sbluhm m_adj(m, *offp); 1901bcb5a76Sbluhm *offp = 0; 1911bcb5a76Sbluhm ip = NULL; 1921bcb5a76Sbluhm #ifdef INET6 1931bcb5a76Sbluhm ip6 = NULL; 1941bcb5a76Sbluhm #endif 1956d386255Sangelos 19621579e10Sclaudio switch (proto) { 19721579e10Sclaudio case IPPROTO_IPV4: 1989a570b6dSangelos hlen = sizeof(struct ip); 1999a570b6dSangelos break; 2009a570b6dSangelos 2019a570b6dSangelos #ifdef INET6 20221579e10Sclaudio case IPPROTO_IPV6: 2039a570b6dSangelos hlen = sizeof(struct ip6_hdr); 2049a570b6dSangelos break; 2059a570b6dSangelos #endif 206ae26b3edSitojun default: 20760dafcf9Sjca ipipstat_inc(ipips_family); 208458cfda4Sbluhm goto bad; 2099a570b6dSangelos } 2109a570b6dSangelos 2111bcb5a76Sbluhm /* Sanity check */ 2121bcb5a76Sbluhm if (m->m_pkthdr.len < hlen) { 2131bcb5a76Sbluhm ipipstat_inc(ipips_hdrops); 214458cfda4Sbluhm goto bad; 2151bcb5a76Sbluhm } 2161bcb5a76Sbluhm 2176593f73dSangelos /* 21821579e10Sclaudio * Bring the inner header into the first mbuf, if not there already. 2196593f73dSangelos */ 2206593f73dSangelos if (m->m_len < hlen) { 221eabae73bSbluhm if ((m = *mp = m_pullup(m, hlen)) == NULL) { 222698a75ddSbluhm DPRINTF("m_pullup() failed"); 22360dafcf9Sjca ipipstat_inc(ipips_hdrops); 224458cfda4Sbluhm goto bad; 2259a570b6dSangelos } 2269a570b6dSangelos } 2279a570b6dSangelos 2289a570b6dSangelos /* 2299a570b6dSangelos * RFC 1853 specifies that the inner TTL should not be touched on 2309a570b6dSangelos * decapsulation. There's no reason this comment should be here, but 2319a570b6dSangelos * this is as good as any a position. 2329a570b6dSangelos */ 2339a570b6dSangelos 234ae26b3edSitojun /* Some sanity checks in the inner IP header */ 23521579e10Sclaudio switch (proto) { 23621579e10Sclaudio case IPPROTO_IPV4: 237ca37dd6cSbluhm iaf = AF_INET; 2381bcb5a76Sbluhm ip = mtod(m, struct ip *); 2391bcb5a76Sbluhm hlen = ip->ip_hl << 2; 2401bcb5a76Sbluhm if (m->m_pkthdr.len < hlen) { 2411bcb5a76Sbluhm ipipstat_inc(ipips_hdrops); 242ab2f8295Sbluhm goto bad; 2431bcb5a76Sbluhm } 2441bcb5a76Sbluhm itos = ip->ip_tos; 245c9857360Smarkus mode = m->m_flags & (M_AUTH|M_CONF) ? 246c9857360Smarkus ECN_ALLOWED_IPSEC : ECN_ALLOWED; 247412c1a0aSdlg if (!ip_ecn_egress(mode, &otos, &itos)) { 248698a75ddSbluhm DPRINTF("ip_ecn_egress() failed"); 24960dafcf9Sjca ipipstat_inc(ipips_pdrops); 250458cfda4Sbluhm goto bad; 25174e8fb40Skjc } 252c9857360Smarkus /* re-calculate the checksum if ip_tos was changed */ 253412c1a0aSdlg if (itos != ip->ip_tos) 254412c1a0aSdlg ip_tos_patch(ip, itos); 2559a570b6dSangelos break; 2569a570b6dSangelos #ifdef INET6 25721579e10Sclaudio case IPPROTO_IPV6: 258ca37dd6cSbluhm iaf = AF_INET6; 25921579e10Sclaudio ip6 = mtod(m, struct ip6_hdr *); 2609a570b6dSangelos itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 26174e8fb40Skjc if (!ip_ecn_egress(ECN_ALLOWED, &otos, &itos)) { 262698a75ddSbluhm DPRINTF("ip_ecn_egress() failed"); 26360dafcf9Sjca ipipstat_inc(ipips_pdrops); 264458cfda4Sbluhm goto bad; 26574e8fb40Skjc } 2669a570b6dSangelos ip6->ip6_flow &= ~htonl(0xff << 20); 2679a570b6dSangelos ip6->ip6_flow |= htonl((u_int32_t) itos << 20); 2689a570b6dSangelos break; 2699a570b6dSangelos #endif 2709a570b6dSangelos } 2719a570b6dSangelos 2729a570b6dSangelos /* Check for local address spoofing. */ 273ab2f8295Sbluhm if (!(ifp->if_flags & IFF_LOOPBACK) && ipip_allow != 2) { 274d33580a9Smpi struct sockaddr_storage ss; 275d33580a9Smpi struct rtentry *rt; 276d33580a9Smpi 277d33580a9Smpi memset(&ss, 0, sizeof(ss)); 278d33580a9Smpi 2791bcb5a76Sbluhm if (ip) { 280d33580a9Smpi sin = (struct sockaddr_in *)&ss; 281d33580a9Smpi sin->sin_family = AF_INET; 282d33580a9Smpi sin->sin_len = sizeof(*sin); 2831bcb5a76Sbluhm sin->sin_addr = ip->ip_src; 2849a570b6dSangelos #ifdef INET6 285d33580a9Smpi } else if (ip6) { 286d33580a9Smpi sin6 = (struct sockaddr_in6 *)&ss; 287d33580a9Smpi sin6->sin6_family = AF_INET6; 288d33580a9Smpi sin6->sin6_len = sizeof(*sin6); 289d33580a9Smpi sin6->sin6_addr = ip6->ip6_src; 2909a570b6dSangelos #endif /* INET6 */ 2919a570b6dSangelos } 2929c681c75Sbluhm rt = rtalloc(sstosa(&ss), 0, m->m_pkthdr.ph_rtableid); 293d33580a9Smpi if ((rt != NULL) && (rt->rt_flags & RTF_LOCAL)) { 29460dafcf9Sjca ipipstat_inc(ipips_spoof); 295d33580a9Smpi rtfree(rt); 296458cfda4Sbluhm goto bad; 2979a570b6dSangelos } 298d33580a9Smpi rtfree(rt); 2999a570b6dSangelos } 3009a570b6dSangelos 3019a570b6dSangelos /* Statistics */ 3021bcb5a76Sbluhm ipipstat_add(ipips_ibytes, m->m_pkthdr.len - hlen); 3039a570b6dSangelos 304ab2f8295Sbluhm #if NBPFILTER > 0 && NGIF > 0 305ab2f8295Sbluhm if (ifp->if_type == IFT_GIF && ifp->if_bpf != NULL) 306ab2f8295Sbluhm bpf_mtap_af(ifp->if_bpf, iaf, m, BPF_DIRECTION_IN); 307ca37dd6cSbluhm #endif 308ca37dd6cSbluhm #if NPF > 0 309ca37dd6cSbluhm pf_pkt_addr_changed(m); 310ca37dd6cSbluhm #endif 311ca37dd6cSbluhm 3129a570b6dSangelos /* 3139a570b6dSangelos * Interface pointer stays the same; if no IPsec processing has 3149a570b6dSangelos * been done (or will be done), this will point to a normal 3159a570b6dSangelos * interface. Otherwise, it'll point to an enc interface, which 3169a570b6dSangelos * will allow a packet filter to distinguish between secure and 3179a570b6dSangelos * untrusted packets. 3189a570b6dSangelos */ 3199a570b6dSangelos 32021579e10Sclaudio switch (proto) { 32121579e10Sclaudio case IPPROTO_IPV4: 322bb24c526Sbluhm return ip_input_if(mp, offp, proto, oaf, ifp); 3239a570b6dSangelos #ifdef INET6 32421579e10Sclaudio case IPPROTO_IPV6: 325bb24c526Sbluhm return ip6_input_if(mp, offp, proto, oaf, ifp); 326ae26b3edSitojun #endif 3279a570b6dSangelos } 328458cfda4Sbluhm bad: 32936c0109eSbluhm m_freemp(mp); 33096be3d96Sbluhm return IPPROTO_DONE; 3319a570b6dSangelos } 3329a570b6dSangelos 3339a570b6dSangelos int 334ead5a062Sbluhm ipip_output(struct mbuf **mp, struct tdb *tdb) 3359a570b6dSangelos { 336ead5a062Sbluhm struct mbuf *m = *mp; 3372edaa7baSmpi u_int8_t tp, otos, itos; 3382edaa7baSmpi u_int64_t obytes; 3399a570b6dSangelos struct ip *ipo; 3409a570b6dSangelos #ifdef INET6 341d5b56032Sitojun struct ip6_hdr *ip6, *ip6o; 3429a570b6dSangelos #endif /* INET6 */ 3433514aacbSmikeb #ifdef ENCDEBUG 3443514aacbSmikeb char buf[INET6_ADDRSTRLEN]; 3453514aacbSmikeb #endif 346e4b51ed2Sbluhm int error; 3479a570b6dSangelos 3486593f73dSangelos /* XXX Deal with empty TDB source/destination addresses. */ 3499a570b6dSangelos 3509a570b6dSangelos m_copydata(m, 0, 1, &tp); 3516593f73dSangelos tp = (tp >> 4) & 0xff; /* Get the IP version number. */ 3529a570b6dSangelos 3536593f73dSangelos switch (tdb->tdb_dst.sa.sa_family) { 3549a570b6dSangelos case AF_INET: 3556593f73dSangelos if (tdb->tdb_src.sa.sa_family != AF_INET || 3566593f73dSangelos tdb->tdb_src.sin.sin_addr.s_addr == INADDR_ANY || 3576593f73dSangelos tdb->tdb_dst.sin.sin_addr.s_addr == INADDR_ANY) { 3586593f73dSangelos 359df8d9afdSjsg DPRINTF("unspecified tunnel endpoint address " 360698a75ddSbluhm "in SA %s/%08x", 3613514aacbSmikeb ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)), 362698a75ddSbluhm ntohl(tdb->tdb_spi)); 3636593f73dSangelos 36460dafcf9Sjca ipipstat_inc(ipips_unspec); 365e4b51ed2Sbluhm error = EINVAL; 366e4b51ed2Sbluhm goto drop; 3679a570b6dSangelos } 3689a570b6dSangelos 369ead5a062Sbluhm M_PREPEND(*mp, sizeof(struct ip), M_DONTWAIT); 370ead5a062Sbluhm if (*mp == NULL) { 371698a75ddSbluhm DPRINTF("M_PREPEND failed"); 37260dafcf9Sjca ipipstat_inc(ipips_hdrops); 373e4b51ed2Sbluhm error = ENOBUFS; 374e4b51ed2Sbluhm goto drop; 3759a570b6dSangelos } 376ead5a062Sbluhm m = *mp; 3779a570b6dSangelos 3789a570b6dSangelos ipo = mtod(m, struct ip *); 3799a570b6dSangelos 3809a570b6dSangelos ipo->ip_v = IPVERSION; 3819a570b6dSangelos ipo->ip_hl = 5; 3829a570b6dSangelos ipo->ip_len = htons(m->m_pkthdr.len); 3839a570b6dSangelos ipo->ip_ttl = ip_defttl; 3849a570b6dSangelos ipo->ip_sum = 0; 3859a570b6dSangelos ipo->ip_src = tdb->tdb_src.sin.sin_addr; 3869a570b6dSangelos ipo->ip_dst = tdb->tdb_dst.sin.sin_addr; 3879a570b6dSangelos 3889a570b6dSangelos /* 3899a570b6dSangelos * We do the htons() to prevent snoopers from determining our 3909a570b6dSangelos * endianness. 3919a570b6dSangelos */ 3929a570b6dSangelos ipo->ip_id = htons(ip_randomid()); 3939a570b6dSangelos 3946593f73dSangelos /* If the inner protocol is IP... */ 3956593f73dSangelos if (tp == IPVERSION) { 3969a570b6dSangelos /* Save ECN notification */ 3976593f73dSangelos m_copydata(m, sizeof(struct ip) + 3986593f73dSangelos offsetof(struct ip, ip_tos), 3999a570b6dSangelos sizeof(u_int8_t), (caddr_t) &itos); 4009a570b6dSangelos 4019a570b6dSangelos ipo->ip_p = IPPROTO_IPIP; 4029a570b6dSangelos 4039a570b6dSangelos /* 4046593f73dSangelos * We should be keeping tunnel soft-state and 4056593f73dSangelos * send back ICMPs if needed. 4069a570b6dSangelos */ 4076593f73dSangelos m_copydata(m, sizeof(struct ip) + 4086593f73dSangelos offsetof(struct ip, ip_off), 4099a570b6dSangelos sizeof(u_int16_t), (caddr_t) &ipo->ip_off); 410faf7e06fSmpi ipo->ip_off = ntohs(ipo->ip_off); 41170d36f83Sangelos ipo->ip_off &= ~(IP_DF | IP_MF | IP_OFFMASK); 412faf7e06fSmpi ipo->ip_off = htons(ipo->ip_off); 4139a570b6dSangelos } 4149a570b6dSangelos #ifdef INET6 4156593f73dSangelos else if (tp == (IPV6_VERSION >> 4)) { 4169a570b6dSangelos u_int32_t itos32; 4176593f73dSangelos 4186593f73dSangelos /* Save ECN notification. */ 4199a570b6dSangelos m_copydata(m, sizeof(struct ip) + 4209a570b6dSangelos offsetof(struct ip6_hdr, ip6_flow), 4219a570b6dSangelos sizeof(u_int32_t), (caddr_t) &itos32); 4229a570b6dSangelos itos = ntohl(itos32) >> 20; 4239a570b6dSangelos ipo->ip_p = IPPROTO_IPV6; 4249a570b6dSangelos ipo->ip_off = 0; 4259a570b6dSangelos } 4269a570b6dSangelos #endif /* INET6 */ 4276593f73dSangelos else { 42860dafcf9Sjca ipipstat_inc(ipips_family); 429e4b51ed2Sbluhm error = EAFNOSUPPORT; 430e4b51ed2Sbluhm goto drop; 4319a570b6dSangelos } 4329a570b6dSangelos 4339a570b6dSangelos otos = 0; 4349a570b6dSangelos ip_ecn_ingress(ECN_ALLOWED, &otos, &itos); 4359a570b6dSangelos ipo->ip_tos = otos; 436e4b51ed2Sbluhm 437e4b51ed2Sbluhm obytes = m->m_pkthdr.len - sizeof(struct ip); 438e4b51ed2Sbluhm if (tdb->tdb_xform->xf_type == XF_IP4) 439e4b51ed2Sbluhm tdb->tdb_cur_bytes += obytes; 4409a570b6dSangelos break; 4419a570b6dSangelos 4429a570b6dSangelos #ifdef INET6 4439a570b6dSangelos case AF_INET6: 4449a570b6dSangelos if (IN6_IS_ADDR_UNSPECIFIED(&tdb->tdb_dst.sin6.sin6_addr) || 4456593f73dSangelos tdb->tdb_src.sa.sa_family != AF_INET6 || 4466593f73dSangelos IN6_IS_ADDR_UNSPECIFIED(&tdb->tdb_src.sin6.sin6_addr)) { 4476593f73dSangelos 448df8d9afdSjsg DPRINTF("unspecified tunnel endpoint address " 449698a75ddSbluhm "in SA %s/%08x", 4503514aacbSmikeb ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)), 451698a75ddSbluhm ntohl(tdb->tdb_spi)); 4526593f73dSangelos 45360dafcf9Sjca ipipstat_inc(ipips_unspec); 454e4b51ed2Sbluhm error = EINVAL; 455e4b51ed2Sbluhm goto drop; 4569a570b6dSangelos } 4579a570b6dSangelos 458424a21eaStodd /* If the inner protocol is IPv6, clear link local scope */ 459424a21eaStodd if (tp == (IPV6_VERSION >> 4)) { 460d5b56032Sitojun /* scoped address handling */ 461d5b56032Sitojun ip6 = mtod(m, struct ip6_hdr *); 46265b748d4Sitojun if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src)) 463d5b56032Sitojun ip6->ip6_src.s6_addr16[1] = 0; 46465b748d4Sitojun if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst)) 465d5b56032Sitojun ip6->ip6_dst.s6_addr16[1] = 0; 466424a21eaStodd } 467d5b56032Sitojun 468ead5a062Sbluhm M_PREPEND(*mp, sizeof(struct ip6_hdr), M_DONTWAIT); 469ead5a062Sbluhm if (*mp == NULL) { 470698a75ddSbluhm DPRINTF("M_PREPEND failed"); 47160dafcf9Sjca ipipstat_inc(ipips_hdrops); 472e4b51ed2Sbluhm error = ENOBUFS; 473e4b51ed2Sbluhm goto drop; 4749a570b6dSangelos } 475ead5a062Sbluhm m = *mp; 4769a570b6dSangelos 4779a570b6dSangelos /* Initialize IPv6 header */ 4789a570b6dSangelos ip6o = mtod(m, struct ip6_hdr *); 4799a570b6dSangelos ip6o->ip6_flow = 0; 4809a570b6dSangelos ip6o->ip6_vfc &= ~IPV6_VERSION_MASK; 4819a570b6dSangelos ip6o->ip6_vfc |= IPV6_VERSION; 482086d35e9Smarkus ip6o->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6o)); 4839a570b6dSangelos ip6o->ip6_hlim = ip_defttl; 484*952c6363Sbluhm in6_embedscope(&ip6o->ip6_src, &tdb->tdb_src.sin6, NULL, NULL); 485*952c6363Sbluhm in6_embedscope(&ip6o->ip6_dst, &tdb->tdb_dst.sin6, NULL, NULL); 4869a570b6dSangelos 4876593f73dSangelos if (tp == IPVERSION) { 4889a570b6dSangelos /* Save ECN notification */ 4899a570b6dSangelos m_copydata(m, sizeof(struct ip6_hdr) + 4909a570b6dSangelos offsetof(struct ip, ip_tos), sizeof(u_int8_t), 4919a570b6dSangelos (caddr_t) &itos); 4929a570b6dSangelos 4936593f73dSangelos /* This is really IPVERSION. */ 4946593f73dSangelos ip6o->ip6_nxt = IPPROTO_IPIP; 4959a570b6dSangelos } 4969a570b6dSangelos else 4976593f73dSangelos if (tp == (IPV6_VERSION >> 4)) { 4989a570b6dSangelos u_int32_t itos32; 4996593f73dSangelos 5006593f73dSangelos /* Save ECN notification. */ 5019a570b6dSangelos m_copydata(m, sizeof(struct ip6_hdr) + 5029a570b6dSangelos offsetof(struct ip6_hdr, ip6_flow), 5039a570b6dSangelos sizeof(u_int32_t), (caddr_t) &itos32); 5049a570b6dSangelos itos = ntohl(itos32) >> 20; 5059a570b6dSangelos 5069a570b6dSangelos ip6o->ip6_nxt = IPPROTO_IPV6; 5076593f73dSangelos } else { 50860dafcf9Sjca ipipstat_inc(ipips_family); 509e4b51ed2Sbluhm error = EAFNOSUPPORT; 510e4b51ed2Sbluhm goto drop; 5119a570b6dSangelos } 5129a570b6dSangelos 5139a570b6dSangelos otos = 0; 5149a570b6dSangelos ip_ecn_ingress(ECN_ALLOWED, &otos, &itos); 5159a570b6dSangelos ip6o->ip6_flow |= htonl((u_int32_t) otos << 20); 516e4b51ed2Sbluhm 517e4b51ed2Sbluhm obytes = m->m_pkthdr.len - sizeof(struct ip6_hdr); 518e4b51ed2Sbluhm if (tdb->tdb_xform->xf_type == XF_IP4) 519e4b51ed2Sbluhm tdb->tdb_cur_bytes += obytes; 5209a570b6dSangelos break; 5219a570b6dSangelos #endif /* INET6 */ 5229a570b6dSangelos 5239a570b6dSangelos default: 524698a75ddSbluhm DPRINTF("unsupported protocol family %d", 525698a75ddSbluhm tdb->tdb_dst.sa.sa_family); 526e4b51ed2Sbluhm ipipstat_inc(ipips_family); 527bc489a1cSbluhm error = EPFNOSUPPORT; 528e4b51ed2Sbluhm goto drop; 529e4b51ed2Sbluhm } 530e4b51ed2Sbluhm 531e4b51ed2Sbluhm ipipstat_pkt(ipips_opackets, ipips_obytes, obytes); 532e4b51ed2Sbluhm return 0; 533e4b51ed2Sbluhm 534e4b51ed2Sbluhm drop: 535ead5a062Sbluhm m_freemp(mp); 536e4b51ed2Sbluhm return error; 5379a570b6dSangelos } 5389a570b6dSangelos 5399a570b6dSangelos #ifdef IPSEC 5409a570b6dSangelos int 541c799dc6dSnaddy ipe4_attach(void) 5429a570b6dSangelos { 5439a570b6dSangelos return 0; 5449a570b6dSangelos } 5459a570b6dSangelos 5469a570b6dSangelos int 5475e3836acSbluhm ipe4_init(struct tdb *tdbp, const struct xformsw *xsp, struct ipsecinit *ii) 5489a570b6dSangelos { 5499a570b6dSangelos tdbp->tdb_xform = xsp; 5509a570b6dSangelos return 0; 5519a570b6dSangelos } 5529a570b6dSangelos 5539a570b6dSangelos int 5549a570b6dSangelos ipe4_zeroize(struct tdb *tdbp) 5559a570b6dSangelos { 5569a570b6dSangelos return 0; 5579a570b6dSangelos } 5589a570b6dSangelos 559dde15c32Sbluhm int 560d5072c26Sbluhm ipe4_input(struct mbuf **mp, struct tdb *tdb, int hlen, int proto) 5619a570b6dSangelos { 5626593f73dSangelos /* This is a rather serious mistake, so no conditional printing. */ 563698a75ddSbluhm printf("%s: should never be called\n", __func__); 564d5072c26Sbluhm m_freemp(mp); 565dde15c32Sbluhm return EINVAL; 5669a570b6dSangelos } 5679a570b6dSangelos #endif /* IPSEC */ 5689a570b6dSangelos 5699a570b6dSangelos int 57060dafcf9Sjca ipip_sysctl_ipipstat(void *oldp, size_t *oldlenp, void *newp) 57160dafcf9Sjca { 57260dafcf9Sjca struct ipipstat ipipstat; 57360dafcf9Sjca 57460dafcf9Sjca CTASSERT(sizeof(ipipstat) == (ipips_ncounters * sizeof(uint64_t))); 575c8915b1eSderaadt memset(&ipipstat, 0, sizeof ipipstat); 576bf0d449cSmpi counters_read(ipipcounters, (uint64_t *)&ipipstat, ipips_ncounters, 577bf0d449cSmpi NULL); 57860dafcf9Sjca return (sysctl_rdstruct(oldp, oldlenp, newp, 57960dafcf9Sjca &ipipstat, sizeof(ipipstat))); 58060dafcf9Sjca } 58160dafcf9Sjca 58260dafcf9Sjca int 5836593f73dSangelos ipip_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, 5846593f73dSangelos size_t newlen) 5859a570b6dSangelos { 586df4a15bcSmpi int error; 587df4a15bcSmpi 5889a570b6dSangelos /* All sysctl names at this level are terminal. */ 5899a570b6dSangelos if (namelen != 1) 5909a570b6dSangelos return (ENOTDIR); 5919a570b6dSangelos 5929a570b6dSangelos switch (name[0]) { 5939a570b6dSangelos case IPIPCTL_ALLOW: 594df4a15bcSmpi NET_LOCK(); 59570464ff2Sgnezdo error = sysctl_int_bounded(oldp, oldlenp, newp, newlen, 59670464ff2Sgnezdo &ipip_allow, 0, 2); 597df4a15bcSmpi NET_UNLOCK(); 598df4a15bcSmpi return (error); 599ab46c28dSderaadt case IPIPCTL_STATS: 60060dafcf9Sjca return (ipip_sysctl_ipipstat(oldp, oldlenp, newp)); 6019a570b6dSangelos default: 6029a570b6dSangelos return (ENOPROTOOPT); 6039a570b6dSangelos } 6049a570b6dSangelos /* NOTREACHED */ 6059a570b6dSangelos } 606