in_gif.c revision 282965
1139823Simp/*- 254263Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 354263Sshin * All rights reserved. 454263Sshin * 554263Sshin * Redistribution and use in source and binary forms, with or without 654263Sshin * modification, are permitted provided that the following conditions 754263Sshin * are met: 854263Sshin * 1. Redistributions of source code must retain the above copyright 954263Sshin * notice, this list of conditions and the following disclaimer. 1054263Sshin * 2. Redistributions in binary form must reproduce the above copyright 1154263Sshin * notice, this list of conditions and the following disclaimer in the 1254263Sshin * documentation and/or other materials provided with the distribution. 1354263Sshin * 3. Neither the name of the project nor the names of its contributors 1454263Sshin * may be used to endorse or promote products derived from this software 1554263Sshin * without specific prior written permission. 1654263Sshin * 1754263Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 1854263Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1954263Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2054263Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2154263Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2254263Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2354263Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2454263Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2554263Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2654263Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2754263Sshin * SUCH DAMAGE. 28273087Sae * 29273087Sae * $KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $ 3054263Sshin */ 3154263Sshin 32172467Ssilby#include <sys/cdefs.h> 33172467Ssilby__FBSDID("$FreeBSD: head/sys/netinet/in_gif.c 282965 2015-05-15 12:19:45Z ae $"); 34172467Ssilby 3562587Sitojun#include "opt_inet.h" 3654263Sshin#include "opt_inet6.h" 3754263Sshin 3854263Sshin#include <sys/param.h> 39273087Sae#include <sys/lock.h> 40273087Sae#include <sys/rmlock.h> 4154263Sshin#include <sys/systm.h> 4254263Sshin#include <sys/socket.h> 4354263Sshin#include <sys/sockio.h> 4454263Sshin#include <sys/mbuf.h> 4554263Sshin#include <sys/errno.h> 4654263Sshin#include <sys/kernel.h> 4754263Sshin#include <sys/sysctl.h> 48105293Sume#include <sys/protosw.h> 4962587Sitojun#include <sys/malloc.h> 5062587Sitojun 5154263Sshin#include <net/if.h> 52257176Sglebius#include <net/if_var.h> 5354263Sshin#include <net/route.h> 54196019Srwatson#include <net/vnet.h> 5554263Sshin 5654263Sshin#include <netinet/in.h> 5754263Sshin#include <netinet/in_systm.h> 5854263Sshin#include <netinet/ip.h> 5954263Sshin#include <netinet/ip_var.h> 6062587Sitojun#include <netinet/in_var.h> 6162587Sitojun#include <netinet/ip_encap.h> 6255009Sshin#include <netinet/ip_ecn.h> 6362587Sitojun 6454263Sshin#ifdef INET6 6562587Sitojun#include <netinet/ip6.h> 6654263Sshin#endif 6754263Sshin 68273087Sae#include <net/if_gif.h> 6954263Sshin 70105293Sumestatic int gif_validate4(const struct ip *, struct gif_softc *, 71105293Sume struct ifnet *); 72276148Saestatic int in_gif_input(struct mbuf **, int *, int); 73105293Sume 74105293Sumeextern struct domain inetdomain; 75276148Saestatic struct protosw in_gif_protosw = { 76152242Sru .pr_type = SOCK_RAW, 77152242Sru .pr_domain = &inetdomain, 78152242Sru .pr_protocol = 0/* IPPROTO_IPV[46] */, 79152242Sru .pr_flags = PR_ATOMIC|PR_ADDR, 80152242Sru .pr_input = in_gif_input, 81270008Skevlo .pr_output = rip_output, 82152242Sru .pr_ctloutput = rip_ctloutput, 83152242Sru .pr_usrreqs = &rip_usrreqs 84105293Sume}; 85105293Sume 86276148Sae#define GIF_TTL 30 87276148Saestatic VNET_DEFINE(int, ip_gif_ttl) = GIF_TTL; 88207369Sbz#define V_ip_gif_ttl VNET(ip_gif_ttl) 89274225SglebiusSYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_VNET | CTLFLAG_RW, 90195699Srwatson &VNET_NAME(ip_gif_ttl), 0, ""); 9154263Sshin 9254263Sshinint 93273087Saein_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn) 9454263Sshin{ 95273087Sae GIF_RLOCK_TRACKER; 96147256Sbrooks struct gif_softc *sc = ifp->if_softc; 97273087Sae struct ip *ip; 98273087Sae int len; 9954263Sshin 10054263Sshin /* prepend new IP header */ 101189494Smarius len = sizeof(struct ip); 102189494Smarius#ifndef __NO_STRICT_ALIGNMENT 103273087Sae if (proto == IPPROTO_ETHERIP) 104189494Smarius len += ETHERIP_ALIGN; 105189494Smarius#endif 106243882Sglebius M_PREPEND(m, len, M_NOWAIT); 107273087Sae if (m == NULL) 108273087Sae return (ENOBUFS); 109189494Smarius#ifndef __NO_STRICT_ALIGNMENT 110273087Sae if (proto == IPPROTO_ETHERIP) { 111189494Smarius len = mtod(m, vm_offset_t) & 3; 112189494Smarius KASSERT(len == 0 || len == ETHERIP_ALIGN, 113189494Smarius ("in_gif_output: unexpected misalignment")); 114189494Smarius m->m_data += len; 115189494Smarius m->m_len -= ETHERIP_ALIGN; 116189494Smarius } 117189494Smarius#endif 118273087Sae ip = mtod(m, struct ip *); 119273087Sae GIF_RLOCK(sc); 120273087Sae if (sc->gif_family != AF_INET) { 121273087Sae m_freem(m); 122273087Sae GIF_RUNLOCK(sc); 123273087Sae return (ENETDOWN); 12454263Sshin } 125273087Sae bcopy(sc->gif_iphdr, ip, sizeof(struct ip)); 126273087Sae GIF_RUNLOCK(sc); 12754263Sshin 128273087Sae ip->ip_p = proto; 129273087Sae /* version will be set in ip_output() */ 130273087Sae ip->ip_ttl = V_ip_gif_ttl; 131273087Sae ip->ip_len = htons(m->m_pkthdr.len); 132273087Sae ip->ip_tos = ecn; 13362587Sitojun 134273087Sae return (ip_output(m, NULL, NULL, 0, NULL, NULL)); 13554263Sshin} 13654263Sshin 137276148Saestatic int 138269699Skevloin_gif_input(struct mbuf **mp, int *offp, int proto) 13954263Sshin{ 140273087Sae struct mbuf *m = *mp; 141147503Sbz struct gif_softc *sc; 142273087Sae struct ifnet *gifp; 14354263Sshin struct ip *ip; 144273087Sae uint8_t ecn; 14554263Sshin 146273087Sae sc = encap_getarg(m); 147147503Sbz if (sc == NULL) { 148147503Sbz m_freem(m); 149196039Srwatson KMOD_IPSTAT_INC(ips_nogif); 150269699Skevlo return (IPPROTO_DONE); 151147503Sbz } 152147503Sbz gifp = GIF2IFP(sc); 153273087Sae if ((gifp->if_flags & IFF_UP) != 0) { 154273087Sae ip = mtod(m, struct ip *); 155273087Sae ecn = ip->ip_tos; 156273087Sae m_adj(m, *offp); 157273087Sae gif_input(m, gifp, proto, ecn); 158273087Sae } else { 15954263Sshin m_freem(m); 160196039Srwatson KMOD_IPSTAT_INC(ips_nogif); 16154263Sshin } 162269699Skevlo return (IPPROTO_DONE); 16354263Sshin} 16462587Sitojun 16562587Sitojun/* 166105293Sume * validate outer address. 16762587Sitojun */ 168105293Sumestatic int 169169454Srwatsongif_validate4(const struct ip *ip, struct gif_softc *sc, struct ifnet *ifp) 17062587Sitojun{ 171282965Sae int ret; 17262587Sitojun 173273087Sae GIF_RLOCK_ASSERT(sc); 17462587Sitojun 17562587Sitojun /* check for address match */ 176282965Sae if (sc->gif_iphdr->ip_src.s_addr != ip->ip_dst.s_addr) 177273087Sae return (0); 178282965Sae ret = 32; 179282965Sae if (sc->gif_iphdr->ip_dst.s_addr != ip->ip_src.s_addr) { 180282965Sae if ((sc->gif_options & GIF_IGNORE_SOURCE) == 0) 181282965Sae return (0); 182282965Sae } else 183282965Sae ret += 32; 18462587Sitojun 18562587Sitojun /* martian filters on outer source - NOT done in ip_input! */ 186105293Sume if (IN_MULTICAST(ntohl(ip->ip_src.s_addr))) 187273087Sae return (0); 188105293Sume switch ((ntohl(ip->ip_src.s_addr) & 0xff000000) >> 24) { 189273087Sae case 0: 190273087Sae case 127: 191273087Sae case 255: 192273087Sae return (0); 19362587Sitojun } 194194951Srwatson 19562587Sitojun /* ingress filters on outer source */ 196147256Sbrooks if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0 && ifp) { 19762587Sitojun struct sockaddr_in sin; 19862587Sitojun struct rtentry *rt; 19962587Sitojun 20062587Sitojun bzero(&sin, sizeof(sin)); 20162587Sitojun sin.sin_family = AF_INET; 20262587Sitojun sin.sin_len = sizeof(struct sockaddr_in); 203105293Sume sin.sin_addr = ip->ip_src; 204178888Sjulian /* XXX MRT check for the interface we would use on output */ 205178888Sjulian rt = in_rtalloc1((struct sockaddr *)&sin, 0, 206178888Sjulian 0UL, sc->gif_fibnum); 207105293Sume if (!rt || rt->rt_ifp != ifp) { 20878064Sume if (rt) 209172307Scsjp RTFREE_LOCKED(rt); 210273087Sae return (0); 21162587Sitojun } 212172307Scsjp RTFREE_LOCKED(rt); 21362587Sitojun } 214282965Sae return (ret); 21562587Sitojun} 216105293Sume 217105293Sume/* 218105293Sume * we know that we are in IFF_UP, outer address available, and outer family 219105293Sume * matched the physical addr family. see gif_encapcheck(). 220105293Sume */ 221105293Sumeint 222273087Saein_gif_encapcheck(const struct mbuf *m, int off, int proto, void *arg) 223105293Sume{ 224105293Sume struct ip ip; 225105293Sume struct gif_softc *sc; 226105293Sume struct ifnet *ifp; 227105293Sume 228105293Sume /* sanity check done in caller */ 229105293Sume sc = (struct gif_softc *)arg; 230273087Sae GIF_RLOCK_ASSERT(sc); 231105293Sume 232105293Sume m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); 233105293Sume ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL; 234273087Sae return (gif_validate4(&ip, sc, ifp)); 235105293Sume} 236105293Sume 237105293Sumeint 238169454Srwatsonin_gif_attach(struct gif_softc *sc) 239105293Sume{ 240273087Sae 241273087Sae KASSERT(sc->gif_ecookie == NULL, ("gif_ecookie isn't NULL")); 242273087Sae sc->gif_ecookie = encap_attach_func(AF_INET, -1, gif_encapcheck, 243105293Sume &in_gif_protosw, sc); 244273087Sae if (sc->gif_ecookie == NULL) 245273087Sae return (EEXIST); 246273087Sae return (0); 247105293Sume} 248