in_gif.c revision 139823
162587Sitojun/* $FreeBSD: head/sys/netinet/in_gif.c 139823 2005-01-07 01:45:51Z imp $ */ 278064Sume/* $KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $ */ 362587Sitojun 4139823Simp/*- 554263Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 654263Sshin * All rights reserved. 754263Sshin * 854263Sshin * Redistribution and use in source and binary forms, with or without 954263Sshin * modification, are permitted provided that the following conditions 1054263Sshin * are met: 1154263Sshin * 1. Redistributions of source code must retain the above copyright 1254263Sshin * notice, this list of conditions and the following disclaimer. 1354263Sshin * 2. Redistributions in binary form must reproduce the above copyright 1454263Sshin * notice, this list of conditions and the following disclaimer in the 1554263Sshin * documentation and/or other materials provided with the distribution. 1654263Sshin * 3. Neither the name of the project nor the names of its contributors 1754263Sshin * may be used to endorse or promote products derived from this software 1854263Sshin * without specific prior written permission. 1954263Sshin * 2054263Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2154263Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2254263Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2354263Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2454263Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2554263Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2654263Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2754263Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2854263Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2954263Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3054263Sshin * SUCH DAMAGE. 3154263Sshin */ 3254263Sshin 3354263Sshin#include "opt_mrouting.h" 3462587Sitojun#include "opt_inet.h" 3554263Sshin#include "opt_inet6.h" 3654263Sshin 3754263Sshin#include <sys/param.h> 3854263Sshin#include <sys/systm.h> 3954263Sshin#include <sys/socket.h> 4054263Sshin#include <sys/sockio.h> 4154263Sshin#include <sys/mbuf.h> 4254263Sshin#include <sys/errno.h> 4354263Sshin#include <sys/kernel.h> 4454263Sshin#include <sys/sysctl.h> 45105293Sume#include <sys/protosw.h> 4654263Sshin 4762587Sitojun#include <sys/malloc.h> 4862587Sitojun 4954263Sshin#include <net/if.h> 5054263Sshin#include <net/route.h> 5154263Sshin 5254263Sshin#include <netinet/in.h> 5354263Sshin#include <netinet/in_systm.h> 5454263Sshin#include <netinet/ip.h> 5554263Sshin#include <netinet/ip_var.h> 5654263Sshin#include <netinet/in_gif.h> 5762587Sitojun#include <netinet/in_var.h> 5862587Sitojun#include <netinet/ip_encap.h> 5955009Sshin#include <netinet/ip_ecn.h> 6062587Sitojun 6154263Sshin#ifdef INET6 6262587Sitojun#include <netinet/ip6.h> 6354263Sshin#endif 6454263Sshin 6554263Sshin#ifdef MROUTING 6654263Sshin#include <netinet/ip_mroute.h> 6754263Sshin#endif /* MROUTING */ 6854263Sshin 6962587Sitojun#include <net/if_gif.h> 7054263Sshin 7154263Sshin#include <net/net_osdep.h> 7254263Sshin 73105293Sumestatic int gif_validate4(const struct ip *, struct gif_softc *, 74105293Sume struct ifnet *); 75105293Sume 76105293Sumeextern struct domain inetdomain; 77105293Sumestruct protosw in_gif_protosw = 78120891Sume{ SOCK_RAW, &inetdomain, 0/* IPPROTO_IPV[46] */, PR_ATOMIC|PR_ADDR, 79120891Sume in_gif_input, (pr_output_t*)rip_output, 0, rip_ctloutput, 80105293Sume 0, 81105293Sume 0, 0, 0, 0, 82105293Sume &rip_usrreqs 83105293Sume}; 84105293Sume 8591324Sbrooksstatic int ip_gif_ttl = GIF_TTL; 8654263SshinSYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW, 8754263Sshin &ip_gif_ttl, 0, ""); 8854263Sshin 8954263Sshinint 90105340Sumein_gif_output(ifp, family, m) 9154263Sshin struct ifnet *ifp; 9254263Sshin int family; 9354263Sshin struct mbuf *m; 9454263Sshin{ 9578064Sume struct gif_softc *sc = (struct gif_softc*)ifp; 9654263Sshin struct sockaddr_in *dst = (struct sockaddr_in *)&sc->gif_ro.ro_dst; 9754263Sshin struct sockaddr_in *sin_src = (struct sockaddr_in *)sc->gif_psrc; 9854263Sshin struct sockaddr_in *sin_dst = (struct sockaddr_in *)sc->gif_pdst; 9954263Sshin struct ip iphdr; /* capsule IP header, host byte ordered */ 10054263Sshin int proto, error; 10154263Sshin u_int8_t tos; 10254263Sshin 10354263Sshin if (sin_src == NULL || sin_dst == NULL || 10454263Sshin sin_src->sin_family != AF_INET || 10554263Sshin sin_dst->sin_family != AF_INET) { 10654263Sshin m_freem(m); 10754263Sshin return EAFNOSUPPORT; 10854263Sshin } 10954263Sshin 11054263Sshin switch (family) { 11162587Sitojun#ifdef INET 11254263Sshin case AF_INET: 11354263Sshin { 11454263Sshin struct ip *ip; 11554263Sshin 11654263Sshin proto = IPPROTO_IPV4; 11754263Sshin if (m->m_len < sizeof(*ip)) { 11854263Sshin m = m_pullup(m, sizeof(*ip)); 11954263Sshin if (!m) 12054263Sshin return ENOBUFS; 12154263Sshin } 12254263Sshin ip = mtod(m, struct ip *); 12354263Sshin tos = ip->ip_tos; 12454263Sshin break; 12554263Sshin } 12695023Ssuz#endif /* INET */ 12754263Sshin#ifdef INET6 12854263Sshin case AF_INET6: 12954263Sshin { 13062587Sitojun struct ip6_hdr *ip6; 13154263Sshin proto = IPPROTO_IPV6; 13254263Sshin if (m->m_len < sizeof(*ip6)) { 13354263Sshin m = m_pullup(m, sizeof(*ip6)); 13454263Sshin if (!m) 13554263Sshin return ENOBUFS; 13654263Sshin } 13754263Sshin ip6 = mtod(m, struct ip6_hdr *); 13854263Sshin tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 13954263Sshin break; 14054263Sshin } 14195023Ssuz#endif /* INET6 */ 14254263Sshin default: 14362587Sitojun#ifdef DEBUG 14454263Sshin printf("in_gif_output: warning: unknown family %d passed\n", 14554263Sshin family); 14654263Sshin#endif 14754263Sshin m_freem(m); 14854263Sshin return EAFNOSUPPORT; 14954263Sshin } 15054263Sshin 15154263Sshin bzero(&iphdr, sizeof(iphdr)); 15254263Sshin iphdr.ip_src = sin_src->sin_addr; 15378064Sume /* bidirectional configured tunnel mode */ 15478064Sume if (sin_dst->sin_addr.s_addr != INADDR_ANY) 15578064Sume iphdr.ip_dst = sin_dst->sin_addr; 15678064Sume else { 15778064Sume m_freem(m); 15878064Sume return ENETUNREACH; 15954263Sshin } 16054263Sshin iphdr.ip_p = proto; 16154263Sshin /* version will be set in ip_output() */ 16254263Sshin iphdr.ip_ttl = ip_gif_ttl; 16354263Sshin iphdr.ip_len = m->m_pkthdr.len + sizeof(struct ip); 164121684Sume ip_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED : ECN_NOCARE, 165121684Sume &iphdr.ip_tos, &tos); 16654263Sshin 16754263Sshin /* prepend new IP header */ 168111119Simp M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); 16954263Sshin if (m && m->m_len < sizeof(struct ip)) 17054263Sshin m = m_pullup(m, sizeof(struct ip)); 17154263Sshin if (m == NULL) { 17254263Sshin printf("ENOBUFS in in_gif_output %d\n", __LINE__); 17354263Sshin return ENOBUFS; 17454263Sshin } 17562587Sitojun bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip)); 17654263Sshin 17754263Sshin if (dst->sin_family != sin_dst->sin_family || 17854263Sshin dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr) { 17954263Sshin /* cache route doesn't match */ 180130662Sbms bzero(dst, sizeof(*dst)); 18154263Sshin dst->sin_family = sin_dst->sin_family; 18254263Sshin dst->sin_len = sizeof(struct sockaddr_in); 18354263Sshin dst->sin_addr = sin_dst->sin_addr; 18454263Sshin if (sc->gif_ro.ro_rt) { 18554263Sshin RTFREE(sc->gif_ro.ro_rt); 18654263Sshin sc->gif_ro.ro_rt = NULL; 18754263Sshin } 18862587Sitojun#if 0 18962587Sitojun sc->gif_if.if_mtu = GIF_MTU; 19062587Sitojun#endif 19154263Sshin } 19254263Sshin 19354263Sshin if (sc->gif_ro.ro_rt == NULL) { 194128210Sluigi rtalloc_ign(&sc->gif_ro, 0); 19554263Sshin if (sc->gif_ro.ro_rt == NULL) { 19654263Sshin m_freem(m); 19754263Sshin return ENETUNREACH; 19854263Sshin } 19962587Sitojun 20062587Sitojun /* if it constitutes infinite encapsulation, punt. */ 20162587Sitojun if (sc->gif_ro.ro_rt->rt_ifp == ifp) { 20262587Sitojun m_freem(m); 20395023Ssuz return ENETUNREACH; /* XXX */ 20462587Sitojun } 20562587Sitojun#if 0 20662587Sitojun ifp->if_mtu = sc->gif_ro.ro_rt->rt_ifp->if_mtu 20762587Sitojun - sizeof(struct ip); 20862587Sitojun#endif 20954263Sshin } 21054263Sshin 211105194Ssam error = ip_output(m, NULL, &sc->gif_ro, 0, NULL, NULL); 212138470Sglebius 213138653Sglebius if (!(sc->gif_if.if_flags & IFF_LINK0) && 214138653Sglebius sc->gif_ro.ro_rt != NULL) { 215138470Sglebius RTFREE(sc->gif_ro.ro_rt); 216138470Sglebius sc->gif_ro.ro_rt = NULL; 217138470Sglebius } 218138470Sglebius 219120885Sume return (error); 22054263Sshin} 22154263Sshin 22254263Sshinvoid 22382884Sjulianin_gif_input(m, off) 22462587Sitojun struct mbuf *m; 22579106Sbrooks int off; 22654263Sshin{ 22754263Sshin struct ifnet *gifp = NULL; 22854263Sshin struct ip *ip; 22962587Sitojun int af; 23055009Sshin u_int8_t otos; 23182884Sjulian int proto; 23254263Sshin 23354263Sshin ip = mtod(m, struct ip *); 23482884Sjulian proto = ip->ip_p; 23554263Sshin 23662587Sitojun gifp = (struct ifnet *)encap_getarg(m); 23754263Sshin 23862587Sitojun if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) { 23954263Sshin m_freem(m); 24054263Sshin ipstat.ips_nogif++; 24154263Sshin return; 24254263Sshin } 24354263Sshin 24455009Sshin otos = ip->ip_tos; 24554263Sshin m_adj(m, off); 24654263Sshin 24754263Sshin switch (proto) { 24862587Sitojun#ifdef INET 24954263Sshin case IPPROTO_IPV4: 25054263Sshin { 25154263Sshin struct ip *ip; 25254263Sshin af = AF_INET; 25354263Sshin if (m->m_len < sizeof(*ip)) { 25454263Sshin m = m_pullup(m, sizeof(*ip)); 25554263Sshin if (!m) 25654263Sshin return; 25754263Sshin } 25854263Sshin ip = mtod(m, struct ip *); 259121684Sume if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ? 260121684Sume ECN_ALLOWED : ECN_NOCARE, 261121684Sume &otos, &ip->ip_tos) == 0) { 262121684Sume m_freem(m); 263121684Sume return; 264121684Sume } 26554263Sshin break; 26654263Sshin } 26762587Sitojun#endif 26854263Sshin#ifdef INET6 26954263Sshin case IPPROTO_IPV6: 27054263Sshin { 27154263Sshin struct ip6_hdr *ip6; 272121684Sume u_int8_t itos, oitos; 273121684Sume 27454263Sshin af = AF_INET6; 27554263Sshin if (m->m_len < sizeof(*ip6)) { 27654263Sshin m = m_pullup(m, sizeof(*ip6)); 27754263Sshin if (!m) 27854263Sshin return; 27954263Sshin } 28054263Sshin ip6 = mtod(m, struct ip6_hdr *); 281121684Sume itos = oitos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 282121684Sume if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ? 283121684Sume ECN_ALLOWED : ECN_NOCARE, 284121684Sume &otos, &itos) == 0) { 285121684Sume m_freem(m); 286121684Sume return; 287121684Sume } 288121684Sume if (itos != oitos) { 289121684Sume ip6->ip6_flow &= ~htonl(0xff << 20); 290121684Sume ip6->ip6_flow |= htonl((u_int32_t)itos << 20); 291121684Sume } 29254263Sshin break; 29354263Sshin } 29454263Sshin#endif /* INET6 */ 29554263Sshin default: 29654263Sshin ipstat.ips_nogif++; 29754263Sshin m_freem(m); 29854263Sshin return; 29954263Sshin } 30054263Sshin gif_input(m, af, gifp); 30154263Sshin return; 30254263Sshin} 30362587Sitojun 30462587Sitojun/* 305105293Sume * validate outer address. 30662587Sitojun */ 307105293Sumestatic int 308105293Sumegif_validate4(ip, sc, ifp) 309105293Sume const struct ip *ip; 310105293Sume struct gif_softc *sc; 311105293Sume struct ifnet *ifp; 31262587Sitojun{ 31362587Sitojun struct sockaddr_in *src, *dst; 31462587Sitojun struct in_ifaddr *ia4; 31562587Sitojun 31662587Sitojun src = (struct sockaddr_in *)sc->gif_psrc; 31762587Sitojun dst = (struct sockaddr_in *)sc->gif_pdst; 31862587Sitojun 31962587Sitojun /* check for address match */ 320105293Sume if (src->sin_addr.s_addr != ip->ip_dst.s_addr || 321105293Sume dst->sin_addr.s_addr != ip->ip_src.s_addr) 32262587Sitojun return 0; 32362587Sitojun 32462587Sitojun /* martian filters on outer source - NOT done in ip_input! */ 325105293Sume if (IN_MULTICAST(ntohl(ip->ip_src.s_addr))) 32662587Sitojun return 0; 327105293Sume switch ((ntohl(ip->ip_src.s_addr) & 0xff000000) >> 24) { 32862587Sitojun case 0: case 127: case 255: 32962587Sitojun return 0; 33062587Sitojun } 33162587Sitojun /* reject packets with broadcast on source */ 332120891Sume TAILQ_FOREACH(ia4, &in_ifaddrhead, ia_link) { 33362587Sitojun if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0) 33462587Sitojun continue; 335105293Sume if (ip->ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr) 33662587Sitojun return 0; 33762587Sitojun } 33862587Sitojun 33962587Sitojun /* ingress filters on outer source */ 340105293Sume if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && ifp) { 34162587Sitojun struct sockaddr_in sin; 34262587Sitojun struct rtentry *rt; 34362587Sitojun 34462587Sitojun bzero(&sin, sizeof(sin)); 34562587Sitojun sin.sin_family = AF_INET; 34662587Sitojun sin.sin_len = sizeof(struct sockaddr_in); 347105293Sume sin.sin_addr = ip->ip_src; 34862587Sitojun rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL); 349105293Sume if (!rt || rt->rt_ifp != ifp) { 35078064Sume#if 0 35178064Sume log(LOG_WARNING, "%s: packet from 0x%x dropped " 35278064Sume "due to ingress filter\n", if_name(&sc->gif_if), 35378064Sume (u_int32_t)ntohl(sin.sin_addr.s_addr)); 35478064Sume#endif 35578064Sume if (rt) 35678064Sume rtfree(rt); 35762587Sitojun return 0; 35862587Sitojun } 35962587Sitojun rtfree(rt); 36062587Sitojun } 36162587Sitojun 36278064Sume return 32 * 2; 36362587Sitojun} 364105293Sume 365105293Sume/* 366105293Sume * we know that we are in IFF_UP, outer address available, and outer family 367105293Sume * matched the physical addr family. see gif_encapcheck(). 368105293Sume */ 369105293Sumeint 370105293Sumegif_encapcheck4(m, off, proto, arg) 371105293Sume const struct mbuf *m; 372105293Sume int off; 373105293Sume int proto; 374105293Sume void *arg; 375105293Sume{ 376105293Sume struct ip ip; 377105293Sume struct gif_softc *sc; 378105293Sume struct ifnet *ifp; 379105293Sume 380105293Sume /* sanity check done in caller */ 381105293Sume sc = (struct gif_softc *)arg; 382105293Sume 383105293Sume /* LINTED const cast */ 384105293Sume m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); 385105293Sume ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL; 386105293Sume 387105293Sume return gif_validate4(&ip, sc, ifp); 388105293Sume} 389105293Sume 390105293Sumeint 391105293Sumein_gif_attach(sc) 392105293Sume struct gif_softc *sc; 393105293Sume{ 394105293Sume sc->encap_cookie4 = encap_attach_func(AF_INET, -1, gif_encapcheck, 395105293Sume &in_gif_protosw, sc); 396105293Sume if (sc->encap_cookie4 == NULL) 397105293Sume return EEXIST; 398105293Sume return 0; 399105293Sume} 400105293Sume 401105293Sumeint 402105293Sumein_gif_detach(sc) 403105293Sume struct gif_softc *sc; 404105293Sume{ 405105293Sume int error; 406105293Sume 407105293Sume error = encap_detach(sc->encap_cookie4); 408105293Sume if (error == 0) 409105293Sume sc->encap_cookie4 = NULL; 410105293Sume return error; 411105293Sume} 412