1105197Ssam/* $FreeBSD$ */ 2105197Ssam/* $OpenBSD: ip_ipip.c,v 1.25 2002/06/10 18:04:55 itojun Exp $ */ 3139823Simp/*- 4105197Ssam * The authors of this code are John Ioannidis (ji@tla.org), 5105197Ssam * Angelos D. Keromytis (kermit@csd.uch.gr) and 6105197Ssam * Niels Provos (provos@physnet.uni-hamburg.de). 7105197Ssam * 8105197Ssam * The original version of this code was written by John Ioannidis 9105197Ssam * for BSD/OS in Athens, Greece, in November 1995. 10105197Ssam * 11105197Ssam * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996, 12105197Ssam * by Angelos D. Keromytis. 13105197Ssam * 14105197Ssam * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis 15105197Ssam * and Niels Provos. 16105197Ssam * 17105197Ssam * Additional features in 1999 by Angelos D. Keromytis. 18105197Ssam * 19105197Ssam * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis, 20105197Ssam * Angelos D. Keromytis and Niels Provos. 21105197Ssam * Copyright (c) 2001, Angelos D. Keromytis. 22105197Ssam * 23105197Ssam * Permission to use, copy, and modify this software with or without fee 24105197Ssam * is hereby granted, provided that this entire notice is included in 25105197Ssam * all copies of any software which is or includes a copy or 26105197Ssam * modification of this software. 27105197Ssam * You may use this code under the GNU public license if you so wish. Please 28105197Ssam * contribute changes back to the authors under this freer than GPL license 29105197Ssam * so that we may further the use of strong encryption without limitations to 30105197Ssam * all. 31105197Ssam * 32105197Ssam * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR 33105197Ssam * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY 34105197Ssam * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE 35105197Ssam * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR 36105197Ssam * PURPOSE. 37105197Ssam */ 38105197Ssam 39105197Ssam/* 40105197Ssam * IP-inside-IP processing 41105197Ssam */ 42105197Ssam#include "opt_inet.h" 43105197Ssam#include "opt_inet6.h" 44159965Sthompsa#include "opt_enc.h" 45105197Ssam 46105197Ssam#include <sys/param.h> 47105197Ssam#include <sys/systm.h> 48105197Ssam#include <sys/mbuf.h> 49105197Ssam#include <sys/socket.h> 50105197Ssam#include <sys/kernel.h> 51105197Ssam#include <sys/protosw.h> 52105197Ssam#include <sys/sysctl.h> 53105197Ssam 54105197Ssam#include <net/if.h> 55171497Sbz#include <net/pfil.h> 56105197Ssam#include <net/netisr.h> 57185571Sbz#include <net/vnet.h> 58105197Ssam 59105197Ssam#include <netinet/in.h> 60105197Ssam#include <netinet/in_systm.h> 61105197Ssam#include <netinet/in_var.h> 62105197Ssam#include <netinet/ip.h> 63105197Ssam#include <netinet/ip_ecn.h> 64105197Ssam#include <netinet/ip_var.h> 65105197Ssam#include <netinet/ip_encap.h> 66105197Ssam 67105197Ssam#include <netipsec/ipsec.h> 68105197Ssam#include <netipsec/xform.h> 69105197Ssam 70105197Ssam#include <netipsec/ipip_var.h> 71105197Ssam 72105197Ssam#ifdef INET6 73105197Ssam#include <netinet/ip6.h> 74105197Ssam#include <netipsec/ipsec6.h> 75105197Ssam#include <netinet6/ip6_ecn.h> 76105197Ssam#include <netinet6/in6_var.h> 77105197Ssam#include <netinet6/ip6protosw.h> 78105197Ssam#endif 79105197Ssam 80105197Ssam#include <netipsec/key.h> 81105197Ssam#include <netipsec/key_debug.h> 82105197Ssam 83105197Ssam#include <machine/stdarg.h> 84105197Ssam 85105197Ssam/* 86105197Ssam * We can control the acceptance of IP4 packets by altering the sysctl 87105197Ssam * net.inet.ipip.allow value. Zero means drop them, all else is acceptance. 88105197Ssam */ 89195699SrwatsonVNET_DEFINE(int, ipip_allow) = 0; 90253088SaeVNET_PCPUSTAT_DEFINE(struct ipipstat, ipipstat); 91253088SaeVNET_PCPUSTAT_SYSINIT(ipipstat); 92105197Ssam 93253088Sae#ifdef VIMAGE 94253088SaeVNET_PCPUSTAT_SYSUNINIT(ipipstat); 95253088Sae#endif /* VIMAGE */ 96253088Sae 97105197SsamSYSCTL_DECL(_net_inet_ipip); 98195699SrwatsonSYSCTL_VNET_INT(_net_inet_ipip, OID_AUTO, 99195699Srwatson ipip_allow, CTLFLAG_RW, &VNET_NAME(ipip_allow), 0, ""); 100253088SaeSYSCTL_VNET_PCPUSTAT(_net_inet_ipip, IPSECCTL_STATS, stats, 101253088Sae struct ipipstat, ipipstat, 102253088Sae "IPIP statistics (struct ipipstat, netipsec/ipip_var.h)"); 103105197Ssam 104105197Ssam/* XXX IPCOMP */ 105105197Ssam#define M_IPSEC (M_AUTHIPHDR|M_AUTHIPDGM|M_DECRYPTED) 106105197Ssam 107105197Ssamstatic void _ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp); 108105197Ssam 109105197Ssam#ifdef INET6 110105197Ssam/* 111105197Ssam * Really only a wrapper for ipip_input(), for use with IPv6. 112105197Ssam */ 113105197Ssamint 114105197Ssamip4_input6(struct mbuf **m, int *offp, int proto) 115105197Ssam{ 116105197Ssam#if 0 117105197Ssam /* If we do not accept IP-in-IP explicitly, drop. */ 118181803Sbz if (!V_ipip_allow && ((*m)->m_flags & M_IPSEC) == 0) { 119120585Ssam DPRINTF(("%s: dropped due to policy\n", __func__)); 120252028Sae IPIPSTAT_INC(ipips_pdrops); 121105197Ssam m_freem(*m); 122105197Ssam return IPPROTO_DONE; 123105197Ssam } 124105197Ssam#endif 125105197Ssam _ipip_input(*m, *offp, NULL); 126105197Ssam return IPPROTO_DONE; 127105197Ssam} 128105197Ssam#endif /* INET6 */ 129105197Ssam 130105197Ssam#ifdef INET 131105197Ssam/* 132105197Ssam * Really only a wrapper for ipip_input(), for use with IPv4. 133105197Ssam */ 134105197Ssamvoid 135157306Sbzip4_input(struct mbuf *m, int off) 136105197Ssam{ 137105197Ssam#if 0 138105197Ssam /* If we do not accept IP-in-IP explicitly, drop. */ 139181803Sbz if (!V_ipip_allow && (m->m_flags & M_IPSEC) == 0) { 140120585Ssam DPRINTF(("%s: dropped due to policy\n", __func__)); 141252028Sae IPIPSTAT_INC(ipips_pdrops); 142105197Ssam m_freem(m); 143105197Ssam return; 144105197Ssam } 145105197Ssam#endif 146157306Sbz _ipip_input(m, off, NULL); 147105197Ssam} 148105197Ssam#endif /* INET */ 149105197Ssam 150105197Ssam/* 151105197Ssam * ipip_input gets called when we receive an IP{46} encapsulated packet, 152105197Ssam * either because we got it at a real interface, or because AH or ESP 153105197Ssam * were being used in tunnel mode (in which case the rcvif element will 154105197Ssam * contain the address of the encX interface associated with the tunnel. 155105197Ssam */ 156105197Ssam 157105197Ssamstatic void 158105197Ssam_ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp) 159105197Ssam{ 160105197Ssam struct ip *ipo; 161105197Ssam#ifdef INET6 162105197Ssam struct ip6_hdr *ip6 = NULL; 163105197Ssam u_int8_t itos; 164105197Ssam#endif 165105197Ssam int isr; 166105197Ssam u_int8_t otos; 167105197Ssam u_int8_t v; 168105197Ssam int hlen; 169105197Ssam 170252028Sae IPIPSTAT_INC(ipips_ipackets); 171105197Ssam 172105197Ssam m_copydata(m, 0, 1, &v); 173105197Ssam 174105197Ssam switch (v >> 4) { 175105197Ssam#ifdef INET 176105197Ssam case 4: 177105197Ssam hlen = sizeof(struct ip); 178105197Ssam break; 179105197Ssam#endif /* INET */ 180105197Ssam#ifdef INET6 181105197Ssam case 6: 182105197Ssam hlen = sizeof(struct ip6_hdr); 183105197Ssam break; 184105197Ssam#endif 185105197Ssam default: 186252028Sae IPIPSTAT_INC(ipips_family); 187105197Ssam m_freem(m); 188105197Ssam return /* EAFNOSUPPORT */; 189105197Ssam } 190105197Ssam 191105197Ssam /* Bring the IP header in the first mbuf, if not there already */ 192105197Ssam if (m->m_len < hlen) { 193105197Ssam if ((m = m_pullup(m, hlen)) == NULL) { 194120585Ssam DPRINTF(("%s: m_pullup (1) failed\n", __func__)); 195252028Sae IPIPSTAT_INC(ipips_hdrops); 196105197Ssam return; 197105197Ssam } 198105197Ssam } 199105197Ssam ipo = mtod(m, struct ip *); 200105197Ssam 201105197Ssam /* Keep outer ecn field. */ 202105197Ssam switch (v >> 4) { 203105197Ssam#ifdef INET 204105197Ssam case 4: 205105197Ssam otos = ipo->ip_tos; 206105197Ssam break; 207105197Ssam#endif /* INET */ 208105197Ssam#ifdef INET6 209105197Ssam case 6: 210105197Ssam otos = (ntohl(mtod(m, struct ip6_hdr *)->ip6_flow) >> 20) & 0xff; 211105197Ssam break; 212105197Ssam#endif 213105197Ssam default: 214105197Ssam panic("ipip_input: unknown ip version %u (outer)", v>>4); 215105197Ssam } 216105197Ssam 217105197Ssam /* Remove outer IP header */ 218105197Ssam m_adj(m, iphlen); 219105197Ssam 220105197Ssam /* Sanity check */ 221105197Ssam if (m->m_pkthdr.len < sizeof(struct ip)) { 222252028Sae IPIPSTAT_INC(ipips_hdrops); 223105197Ssam m_freem(m); 224105197Ssam return; 225105197Ssam } 226105197Ssam 227105197Ssam m_copydata(m, 0, 1, &v); 228105197Ssam 229105197Ssam switch (v >> 4) { 230105197Ssam#ifdef INET 231105197Ssam case 4: 232105197Ssam hlen = sizeof(struct ip); 233105197Ssam break; 234105197Ssam#endif /* INET */ 235105197Ssam 236105197Ssam#ifdef INET6 237105197Ssam case 6: 238105197Ssam hlen = sizeof(struct ip6_hdr); 239105197Ssam break; 240105197Ssam#endif 241105197Ssam default: 242252028Sae IPIPSTAT_INC(ipips_family); 243105197Ssam m_freem(m); 244105197Ssam return; /* EAFNOSUPPORT */ 245105197Ssam } 246105197Ssam 247105197Ssam /* 248105197Ssam * Bring the inner IP header in the first mbuf, if not there already. 249105197Ssam */ 250105197Ssam if (m->m_len < hlen) { 251105197Ssam if ((m = m_pullup(m, hlen)) == NULL) { 252120585Ssam DPRINTF(("%s: m_pullup (2) failed\n", __func__)); 253252028Sae IPIPSTAT_INC(ipips_hdrops); 254105197Ssam return; 255105197Ssam } 256105197Ssam } 257105197Ssam 258105197Ssam /* 259105197Ssam * RFC 1853 specifies that the inner TTL should not be touched on 260105197Ssam * decapsulation. There's no reason this comment should be here, but 261105197Ssam * this is as good as any a position. 262105197Ssam */ 263105197Ssam 264105197Ssam /* Some sanity checks in the inner IP header */ 265105197Ssam switch (v >> 4) { 266105197Ssam#ifdef INET 267105197Ssam case 4: 268105197Ssam ipo = mtod(m, struct ip *); 269181803Sbz ip_ecn_egress(V_ip4_ipsec_ecn, &otos, &ipo->ip_tos); 270105197Ssam break; 271105197Ssam#endif /* INET */ 272105197Ssam#ifdef INET6 273105197Ssam case 6: 274105197Ssam ip6 = (struct ip6_hdr *) ipo; 275105197Ssam itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 276181803Sbz ip_ecn_egress(V_ip6_ipsec_ecn, &otos, &itos); 277105197Ssam ip6->ip6_flow &= ~htonl(0xff << 20); 278105197Ssam ip6->ip6_flow |= htonl((u_int32_t) itos << 20); 279105197Ssam break; 280105197Ssam#endif 281105197Ssam default: 282105197Ssam panic("ipip_input: unknown ip version %u (inner)", v>>4); 283105197Ssam } 284105197Ssam 285105197Ssam /* Check for local address spoofing. */ 286105197Ssam if ((m->m_pkthdr.rcvif == NULL || 287105197Ssam !(m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK)) && 288181803Sbz V_ipip_allow != 2) { 289105197Ssam#ifdef INET 290264814Sae if ((v >> 4) == IPVERSION && 291264814Sae in_localip(ipo->ip_src) != 0) { 292264814Sae IPIPSTAT_INC(ipips_spoof); 293264814Sae m_freem(m); 294264814Sae return; 295264814Sae } 296264814Sae#endif 297105197Ssam#ifdef INET6 298264814Sae if ((v & IPV6_VERSION_MASK) == IPV6_VERSION && 299264814Sae in6_localip(&ip6->ip6_src) != 0) { 300264814Sae IPIPSTAT_INC(ipips_spoof); 301264814Sae m_freem(m); 302264814Sae return; 303105197Ssam } 304264814Sae#endif 305105197Ssam } 306105197Ssam 307105197Ssam /* Statistics */ 308252028Sae IPIPSTAT_ADD(ipips_ibytes, m->m_pkthdr.len - iphlen); 309105197Ssam 310105197Ssam /* 311105197Ssam * Interface pointer stays the same; if no IPsec processing has 312105197Ssam * been done (or will be done), this will point to a normal 313105197Ssam * interface. Otherwise, it'll point to an enc interface, which 314105197Ssam * will allow a packet filter to distinguish between secure and 315105197Ssam * untrusted packets. 316105197Ssam */ 317105197Ssam 318105197Ssam switch (v >> 4) { 319105197Ssam#ifdef INET 320105197Ssam case 4: 321105197Ssam isr = NETISR_IP; 322105197Ssam break; 323105197Ssam#endif 324105197Ssam#ifdef INET6 325105197Ssam case 6: 326105197Ssam isr = NETISR_IPV6; 327105197Ssam break; 328105197Ssam#endif 329105197Ssam default: 330120585Ssam panic("%s: bogus ip version %u", __func__, v>>4); 331105197Ssam } 332105197Ssam 333134391Sandre if (netisr_queue(isr, m)) { /* (0) on success. */ 334252028Sae IPIPSTAT_INC(ipips_qfull); 335120585Ssam DPRINTF(("%s: packet dropped because of full queue\n", 336120585Ssam __func__)); 337105197Ssam } 338105197Ssam} 339105197Ssam 340105197Ssamint 341105197Ssamipip_output( 342105197Ssam struct mbuf *m, 343105197Ssam struct ipsecrequest *isr, 344105197Ssam struct mbuf **mp, 345105197Ssam int skip, 346105197Ssam int protoff 347105197Ssam) 348105197Ssam{ 349105197Ssam struct secasvar *sav; 350105197Ssam u_int8_t tp, otos; 351105197Ssam struct secasindex *saidx; 352105197Ssam int error; 353221129Sbz#if defined(INET) || defined(INET6) 354221129Sbz u_int8_t itos; 355221129Sbz#endif 356105197Ssam#ifdef INET 357105197Ssam struct ip *ipo; 358105197Ssam#endif /* INET */ 359105197Ssam#ifdef INET6 360105197Ssam struct ip6_hdr *ip6, *ip6o; 361105197Ssam#endif /* INET6 */ 362105197Ssam 363105197Ssam sav = isr->sav; 364120585Ssam IPSEC_ASSERT(sav != NULL, ("null SA")); 365120585Ssam IPSEC_ASSERT(sav->sah != NULL, ("null SAH")); 366105197Ssam 367105197Ssam /* XXX Deal with empty TDB source/destination addresses. */ 368105197Ssam 369105197Ssam m_copydata(m, 0, 1, &tp); 370105197Ssam tp = (tp >> 4) & 0xff; /* Get the IP version number. */ 371105197Ssam 372105197Ssam saidx = &sav->sah->saidx; 373105197Ssam switch (saidx->dst.sa.sa_family) { 374105197Ssam#ifdef INET 375105197Ssam case AF_INET: 376105197Ssam if (saidx->src.sa.sa_family != AF_INET || 377105197Ssam saidx->src.sin.sin_addr.s_addr == INADDR_ANY || 378105197Ssam saidx->dst.sin.sin_addr.s_addr == INADDR_ANY) { 379120585Ssam DPRINTF(("%s: unspecified tunnel endpoint " 380120585Ssam "address in SA %s/%08lx\n", __func__, 381105197Ssam ipsec_address(&saidx->dst), 382105197Ssam (u_long) ntohl(sav->spi))); 383252028Sae IPIPSTAT_INC(ipips_unspec); 384105197Ssam error = EINVAL; 385105197Ssam goto bad; 386105197Ssam } 387105197Ssam 388243882Sglebius M_PREPEND(m, sizeof(struct ip), M_NOWAIT); 389105197Ssam if (m == 0) { 390120585Ssam DPRINTF(("%s: M_PREPEND failed\n", __func__)); 391252028Sae IPIPSTAT_INC(ipips_hdrops); 392105197Ssam error = ENOBUFS; 393105197Ssam goto bad; 394105197Ssam } 395105197Ssam 396105197Ssam ipo = mtod(m, struct ip *); 397105197Ssam 398105197Ssam ipo->ip_v = IPVERSION; 399105197Ssam ipo->ip_hl = 5; 400105197Ssam ipo->ip_len = htons(m->m_pkthdr.len); 401181803Sbz ipo->ip_ttl = V_ip_defttl; 402105197Ssam ipo->ip_sum = 0; 403105197Ssam ipo->ip_src = saidx->src.sin.sin_addr; 404105197Ssam ipo->ip_dst = saidx->dst.sin.sin_addr; 405105197Ssam 406133720Sdwmalone ipo->ip_id = ip_newid(); 407105197Ssam 408105197Ssam /* If the inner protocol is IP... */ 409221129Sbz switch (tp) { 410221129Sbz case IPVERSION: 411105197Ssam /* Save ECN notification */ 412105197Ssam m_copydata(m, sizeof(struct ip) + 413105197Ssam offsetof(struct ip, ip_tos), 414105197Ssam sizeof(u_int8_t), (caddr_t) &itos); 415105197Ssam 416105197Ssam ipo->ip_p = IPPROTO_IPIP; 417105197Ssam 418105197Ssam /* 419105197Ssam * We should be keeping tunnel soft-state and 420105197Ssam * send back ICMPs if needed. 421105197Ssam */ 422105197Ssam m_copydata(m, sizeof(struct ip) + 423105197Ssam offsetof(struct ip, ip_off), 424105197Ssam sizeof(u_int16_t), (caddr_t) &ipo->ip_off); 425105197Ssam ipo->ip_off = ntohs(ipo->ip_off); 426105197Ssam ipo->ip_off &= ~(IP_DF | IP_MF | IP_OFFMASK); 427105197Ssam ipo->ip_off = htons(ipo->ip_off); 428221129Sbz break; 429105197Ssam#ifdef INET6 430221129Sbz case (IPV6_VERSION >> 4): 431221129Sbz { 432105197Ssam u_int32_t itos32; 433105197Ssam 434105197Ssam /* Save ECN notification. */ 435105197Ssam m_copydata(m, sizeof(struct ip) + 436105197Ssam offsetof(struct ip6_hdr, ip6_flow), 437105197Ssam sizeof(u_int32_t), (caddr_t) &itos32); 438105197Ssam itos = ntohl(itos32) >> 20; 439105197Ssam ipo->ip_p = IPPROTO_IPV6; 440105197Ssam ipo->ip_off = 0; 441221129Sbz break; 442105197Ssam } 443105197Ssam#endif /* INET6 */ 444221129Sbz default: 445105197Ssam goto nofamily; 446105197Ssam } 447105197Ssam 448105197Ssam otos = 0; 449105197Ssam ip_ecn_ingress(ECN_ALLOWED, &otos, &itos); 450105197Ssam ipo->ip_tos = otos; 451105197Ssam break; 452105197Ssam#endif /* INET */ 453105197Ssam 454105197Ssam#ifdef INET6 455105197Ssam case AF_INET6: 456105197Ssam if (IN6_IS_ADDR_UNSPECIFIED(&saidx->dst.sin6.sin6_addr) || 457105197Ssam saidx->src.sa.sa_family != AF_INET6 || 458105197Ssam IN6_IS_ADDR_UNSPECIFIED(&saidx->src.sin6.sin6_addr)) { 459120585Ssam DPRINTF(("%s: unspecified tunnel endpoint " 460120585Ssam "address in SA %s/%08lx\n", __func__, 461105197Ssam ipsec_address(&saidx->dst), 462105197Ssam (u_long) ntohl(sav->spi))); 463252028Sae IPIPSTAT_INC(ipips_unspec); 464105197Ssam error = ENOBUFS; 465105197Ssam goto bad; 466105197Ssam } 467105197Ssam 468105197Ssam /* scoped address handling */ 469105197Ssam ip6 = mtod(m, struct ip6_hdr *); 470105197Ssam if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) 471105197Ssam ip6->ip6_src.s6_addr16[1] = 0; 472105197Ssam if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) 473105197Ssam ip6->ip6_dst.s6_addr16[1] = 0; 474105197Ssam 475243882Sglebius M_PREPEND(m, sizeof(struct ip6_hdr), M_NOWAIT); 476105197Ssam if (m == 0) { 477120585Ssam DPRINTF(("%s: M_PREPEND failed\n", __func__)); 478252028Sae IPIPSTAT_INC(ipips_hdrops); 479105197Ssam error = ENOBUFS; 480105197Ssam goto bad; 481105197Ssam } 482105197Ssam 483105197Ssam /* Initialize IPv6 header */ 484105197Ssam ip6o = mtod(m, struct ip6_hdr *); 485105197Ssam ip6o->ip6_flow = 0; 486105197Ssam ip6o->ip6_vfc &= ~IPV6_VERSION_MASK; 487105197Ssam ip6o->ip6_vfc |= IPV6_VERSION; 488274132Sae ip6o->ip6_hlim = IPV6_DEFHLIM; 489105197Ssam ip6o->ip6_dst = saidx->dst.sin6.sin6_addr; 490105197Ssam ip6o->ip6_src = saidx->src.sin6.sin6_addr; 491274132Sae ip6o->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6)); 492274132Sae 493221129Sbz switch (tp) { 494105197Ssam#ifdef INET 495221129Sbz case IPVERSION: 496105197Ssam /* Save ECN notification */ 497105197Ssam m_copydata(m, sizeof(struct ip6_hdr) + 498105197Ssam offsetof(struct ip, ip_tos), sizeof(u_int8_t), 499105197Ssam (caddr_t) &itos); 500105197Ssam 501105197Ssam /* This is really IPVERSION. */ 502105197Ssam ip6o->ip6_nxt = IPPROTO_IPIP; 503221129Sbz break; 504105197Ssam#endif /* INET */ 505221129Sbz case (IPV6_VERSION >> 4): 506221129Sbz { 507221129Sbz u_int32_t itos32; 508105197Ssam 509221129Sbz /* Save ECN notification. */ 510221129Sbz m_copydata(m, sizeof(struct ip6_hdr) + 511221129Sbz offsetof(struct ip6_hdr, ip6_flow), 512221129Sbz sizeof(u_int32_t), (caddr_t) &itos32); 513221129Sbz itos = ntohl(itos32) >> 20; 514105197Ssam 515221129Sbz ip6o->ip6_nxt = IPPROTO_IPV6; 516240630Skevlo break; 517221129Sbz } 518221129Sbz default: 519221129Sbz goto nofamily; 520221129Sbz } 521105197Ssam 522105197Ssam otos = 0; 523274132Sae ip_ecn_ingress(V_ip6_ipsec_ecn, &otos, &itos); 524105197Ssam ip6o->ip6_flow |= htonl((u_int32_t) otos << 20); 525105197Ssam break; 526105197Ssam#endif /* INET6 */ 527105197Ssam 528105197Ssam default: 529105197Ssamnofamily: 530120585Ssam DPRINTF(("%s: unsupported protocol family %u\n", __func__, 531105197Ssam saidx->dst.sa.sa_family)); 532252028Sae IPIPSTAT_INC(ipips_family); 533105197Ssam error = EAFNOSUPPORT; /* XXX diffs from openbsd */ 534105197Ssam goto bad; 535105197Ssam } 536105197Ssam 537252028Sae IPIPSTAT_INC(ipips_opackets); 538105197Ssam *mp = m; 539105197Ssam 540105197Ssam#ifdef INET 541105197Ssam if (saidx->dst.sa.sa_family == AF_INET) { 542105197Ssam#if 0 543105197Ssam if (sav->tdb_xform->xf_type == XF_IP4) 544105197Ssam tdb->tdb_cur_bytes += 545105197Ssam m->m_pkthdr.len - sizeof(struct ip); 546105197Ssam#endif 547252028Sae IPIPSTAT_ADD(ipips_obytes, 548252028Sae m->m_pkthdr.len - sizeof(struct ip)); 549105197Ssam } 550105197Ssam#endif /* INET */ 551105197Ssam 552105197Ssam#ifdef INET6 553105197Ssam if (saidx->dst.sa.sa_family == AF_INET6) { 554105197Ssam#if 0 555105197Ssam if (sav->tdb_xform->xf_type == XF_IP4) 556105197Ssam tdb->tdb_cur_bytes += 557105197Ssam m->m_pkthdr.len - sizeof(struct ip6_hdr); 558105197Ssam#endif 559252028Sae IPIPSTAT_ADD(ipips_obytes, 560252028Sae m->m_pkthdr.len - sizeof(struct ip6_hdr)); 561105197Ssam } 562105197Ssam#endif /* INET6 */ 563105197Ssam 564105197Ssam return 0; 565105197Ssambad: 566105197Ssam if (m) 567124765Ssam m_freem(m); 568124765Ssam *mp = NULL; 569105197Ssam return (error); 570105197Ssam} 571105197Ssam 572171167Sgnn#ifdef IPSEC 573221129Sbz#if defined(INET) || defined(INET6) 574105197Ssamstatic int 575105197Ssamipe4_init(struct secasvar *sav, struct xformsw *xsp) 576105197Ssam{ 577105197Ssam sav->tdb_xform = xsp; 578105197Ssam return 0; 579105197Ssam} 580105197Ssam 581105197Ssamstatic int 582105197Ssamipe4_zeroize(struct secasvar *sav) 583105197Ssam{ 584105197Ssam sav->tdb_xform = NULL; 585105197Ssam return 0; 586105197Ssam} 587105197Ssam 588105197Ssamstatic int 589105197Ssamipe4_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff) 590105197Ssam{ 591105197Ssam /* This is a rather serious mistake, so no conditional printing. */ 592120585Ssam printf("%s: should never be called\n", __func__); 593105197Ssam if (m) 594105197Ssam m_freem(m); 595105197Ssam return EOPNOTSUPP; 596105197Ssam} 597105197Ssam 598105197Ssamstatic struct xformsw ipe4_xformsw = { 599105197Ssam XF_IP4, 0, "IPv4 Simple Encapsulation", 600105197Ssam ipe4_init, ipe4_zeroize, ipe4_input, ipip_output, 601105197Ssam}; 602105197Ssam 603105197Ssamextern struct domain inetdomain; 604221129Sbz#endif /* INET || INET6 */ 605221129Sbz#ifdef INET 606186791Sbzstatic struct protosw ipe4_protosw = { 607186791Sbz .pr_type = SOCK_RAW, 608186791Sbz .pr_domain = &inetdomain, 609186791Sbz .pr_protocol = IPPROTO_IPV4, 610186791Sbz .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, 611186791Sbz .pr_input = ip4_input, 612186791Sbz .pr_ctloutput = rip_ctloutput, 613186791Sbz .pr_usrreqs = &rip_usrreqs 614157306Sbz}; 615221129Sbz#endif /* INET */ 616221129Sbz#if defined(INET6) && defined(INET) 617186791Sbzstatic struct ip6protosw ipe6_protosw = { 618186791Sbz .pr_type = SOCK_RAW, 619186791Sbz .pr_domain = &inetdomain, 620186791Sbz .pr_protocol = IPPROTO_IPV6, 621186791Sbz .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, 622186791Sbz .pr_input = ip4_input6, 623186791Sbz .pr_ctloutput = rip_ctloutput, 624186791Sbz .pr_usrreqs = &rip_usrreqs 625157306Sbz}; 626221129Sbz#endif /* INET6 && INET */ 627105197Ssam 628230442Sbz#ifdef INET 629105197Ssam/* 630105197Ssam * Check the encapsulated packet to see if we want it 631105197Ssam */ 632105197Ssamstatic int 633105197Ssamipe4_encapcheck(const struct mbuf *m, int off, int proto, void *arg) 634105197Ssam{ 635105197Ssam /* 636105197Ssam * Only take packets coming from IPSEC tunnels; the rest 637105197Ssam * must be handled by the gif tunnel code. Note that we 638105197Ssam * also return a minimum priority when we want the packet 639105197Ssam * so any explicit gif tunnels take precedence. 640105197Ssam */ 641105197Ssam return ((m->m_flags & M_IPSEC) != 0 ? 1 : 0); 642105197Ssam} 643221129Sbz#endif /* INET */ 644105197Ssam 645105197Ssamstatic void 646105197Ssamipe4_attach(void) 647105197Ssam{ 648185088Szec 649105197Ssam xform_register(&ipe4_xformsw); 650105197Ssam /* attach to encapsulation framework */ 651105197Ssam /* XXX save return cookie for detach on module remove */ 652221129Sbz#ifdef INET 653105197Ssam (void) encap_attach_func(AF_INET, -1, 654157306Sbz ipe4_encapcheck, &ipe4_protosw, NULL); 655221129Sbz#endif 656221129Sbz#if defined(INET6) && defined(INET) 657105197Ssam (void) encap_attach_func(AF_INET6, -1, 658157306Sbz ipe4_encapcheck, (struct protosw *)&ipe6_protosw, NULL); 659105197Ssam#endif 660105197Ssam} 661105197SsamSYSINIT(ipe4_xform_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE, ipe4_attach, NULL); 662171167Sgnn#endif /* IPSEC */ 663