in_gif.c revision 121684
162587Sitojun/* $FreeBSD: head/sys/netinet/in_gif.c 121684 2003-10-29 15:07:04Z ume $ */ 278064Sume/* $KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $ */ 362587Sitojun 454263Sshin/* 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 */ 18054263Sshin dst->sin_family = sin_dst->sin_family; 18154263Sshin dst->sin_len = sizeof(struct sockaddr_in); 18254263Sshin dst->sin_addr = sin_dst->sin_addr; 18354263Sshin if (sc->gif_ro.ro_rt) { 18454263Sshin RTFREE(sc->gif_ro.ro_rt); 18554263Sshin sc->gif_ro.ro_rt = NULL; 18654263Sshin } 18762587Sitojun#if 0 18862587Sitojun sc->gif_if.if_mtu = GIF_MTU; 18962587Sitojun#endif 19054263Sshin } 19154263Sshin 19254263Sshin if (sc->gif_ro.ro_rt == NULL) { 19354263Sshin rtalloc(&sc->gif_ro); 19454263Sshin if (sc->gif_ro.ro_rt == NULL) { 19554263Sshin m_freem(m); 19654263Sshin return ENETUNREACH; 19754263Sshin } 19862587Sitojun 19962587Sitojun /* if it constitutes infinite encapsulation, punt. */ 20062587Sitojun if (sc->gif_ro.ro_rt->rt_ifp == ifp) { 20162587Sitojun m_freem(m); 20295023Ssuz return ENETUNREACH; /* XXX */ 20362587Sitojun } 20462587Sitojun#if 0 20562587Sitojun ifp->if_mtu = sc->gif_ro.ro_rt->rt_ifp->if_mtu 20662587Sitojun - sizeof(struct ip); 20762587Sitojun#endif 20854263Sshin } 20954263Sshin 210105194Ssam error = ip_output(m, NULL, &sc->gif_ro, 0, NULL, NULL); 211120885Sume return (error); 21254263Sshin} 21354263Sshin 21454263Sshinvoid 21582884Sjulianin_gif_input(m, off) 21662587Sitojun struct mbuf *m; 21779106Sbrooks int off; 21854263Sshin{ 21954263Sshin struct ifnet *gifp = NULL; 22054263Sshin struct ip *ip; 22162587Sitojun int af; 22255009Sshin u_int8_t otos; 22382884Sjulian int proto; 22454263Sshin 22554263Sshin ip = mtod(m, struct ip *); 22682884Sjulian proto = ip->ip_p; 22754263Sshin 22862587Sitojun gifp = (struct ifnet *)encap_getarg(m); 22954263Sshin 23062587Sitojun if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) { 23154263Sshin m_freem(m); 23254263Sshin ipstat.ips_nogif++; 23354263Sshin return; 23454263Sshin } 23554263Sshin 23655009Sshin otos = ip->ip_tos; 23754263Sshin m_adj(m, off); 23854263Sshin 23954263Sshin switch (proto) { 24062587Sitojun#ifdef INET 24154263Sshin case IPPROTO_IPV4: 24254263Sshin { 24354263Sshin struct ip *ip; 24454263Sshin af = AF_INET; 24554263Sshin if (m->m_len < sizeof(*ip)) { 24654263Sshin m = m_pullup(m, sizeof(*ip)); 24754263Sshin if (!m) 24854263Sshin return; 24954263Sshin } 25054263Sshin ip = mtod(m, struct ip *); 251121684Sume if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ? 252121684Sume ECN_ALLOWED : ECN_NOCARE, 253121684Sume &otos, &ip->ip_tos) == 0) { 254121684Sume m_freem(m); 255121684Sume return; 256121684Sume } 25754263Sshin break; 25854263Sshin } 25962587Sitojun#endif 26054263Sshin#ifdef INET6 26154263Sshin case IPPROTO_IPV6: 26254263Sshin { 26354263Sshin struct ip6_hdr *ip6; 264121684Sume u_int8_t itos, oitos; 265121684Sume 26654263Sshin af = AF_INET6; 26754263Sshin if (m->m_len < sizeof(*ip6)) { 26854263Sshin m = m_pullup(m, sizeof(*ip6)); 26954263Sshin if (!m) 27054263Sshin return; 27154263Sshin } 27254263Sshin ip6 = mtod(m, struct ip6_hdr *); 273121684Sume itos = oitos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 274121684Sume if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ? 275121684Sume ECN_ALLOWED : ECN_NOCARE, 276121684Sume &otos, &itos) == 0) { 277121684Sume m_freem(m); 278121684Sume return; 279121684Sume } 280121684Sume if (itos != oitos) { 281121684Sume ip6->ip6_flow &= ~htonl(0xff << 20); 282121684Sume ip6->ip6_flow |= htonl((u_int32_t)itos << 20); 283121684Sume } 28454263Sshin break; 28554263Sshin } 28654263Sshin#endif /* INET6 */ 28754263Sshin default: 28854263Sshin ipstat.ips_nogif++; 28954263Sshin m_freem(m); 29054263Sshin return; 29154263Sshin } 29254263Sshin gif_input(m, af, gifp); 29354263Sshin return; 29454263Sshin} 29562587Sitojun 29662587Sitojun/* 297105293Sume * validate outer address. 29862587Sitojun */ 299105293Sumestatic int 300105293Sumegif_validate4(ip, sc, ifp) 301105293Sume const struct ip *ip; 302105293Sume struct gif_softc *sc; 303105293Sume struct ifnet *ifp; 30462587Sitojun{ 30562587Sitojun struct sockaddr_in *src, *dst; 30662587Sitojun struct in_ifaddr *ia4; 30762587Sitojun 30862587Sitojun src = (struct sockaddr_in *)sc->gif_psrc; 30962587Sitojun dst = (struct sockaddr_in *)sc->gif_pdst; 31062587Sitojun 31162587Sitojun /* check for address match */ 312105293Sume if (src->sin_addr.s_addr != ip->ip_dst.s_addr || 313105293Sume dst->sin_addr.s_addr != ip->ip_src.s_addr) 31462587Sitojun return 0; 31562587Sitojun 31662587Sitojun /* martian filters on outer source - NOT done in ip_input! */ 317105293Sume if (IN_MULTICAST(ntohl(ip->ip_src.s_addr))) 31862587Sitojun return 0; 319105293Sume switch ((ntohl(ip->ip_src.s_addr) & 0xff000000) >> 24) { 32062587Sitojun case 0: case 127: case 255: 32162587Sitojun return 0; 32262587Sitojun } 32362587Sitojun /* reject packets with broadcast on source */ 324120891Sume TAILQ_FOREACH(ia4, &in_ifaddrhead, ia_link) { 32562587Sitojun if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0) 32662587Sitojun continue; 327105293Sume if (ip->ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr) 32862587Sitojun return 0; 32962587Sitojun } 33062587Sitojun 33162587Sitojun /* ingress filters on outer source */ 332105293Sume if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && ifp) { 33362587Sitojun struct sockaddr_in sin; 33462587Sitojun struct rtentry *rt; 33562587Sitojun 33662587Sitojun bzero(&sin, sizeof(sin)); 33762587Sitojun sin.sin_family = AF_INET; 33862587Sitojun sin.sin_len = sizeof(struct sockaddr_in); 339105293Sume sin.sin_addr = ip->ip_src; 34062587Sitojun rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL); 341105293Sume if (!rt || rt->rt_ifp != ifp) { 34278064Sume#if 0 34378064Sume log(LOG_WARNING, "%s: packet from 0x%x dropped " 34478064Sume "due to ingress filter\n", if_name(&sc->gif_if), 34578064Sume (u_int32_t)ntohl(sin.sin_addr.s_addr)); 34678064Sume#endif 34778064Sume if (rt) 34878064Sume rtfree(rt); 34962587Sitojun return 0; 35062587Sitojun } 35162587Sitojun rtfree(rt); 35262587Sitojun } 35362587Sitojun 35478064Sume return 32 * 2; 35562587Sitojun} 356105293Sume 357105293Sume/* 358105293Sume * we know that we are in IFF_UP, outer address available, and outer family 359105293Sume * matched the physical addr family. see gif_encapcheck(). 360105293Sume */ 361105293Sumeint 362105293Sumegif_encapcheck4(m, off, proto, arg) 363105293Sume const struct mbuf *m; 364105293Sume int off; 365105293Sume int proto; 366105293Sume void *arg; 367105293Sume{ 368105293Sume struct ip ip; 369105293Sume struct gif_softc *sc; 370105293Sume struct ifnet *ifp; 371105293Sume 372105293Sume /* sanity check done in caller */ 373105293Sume sc = (struct gif_softc *)arg; 374105293Sume 375105293Sume /* LINTED const cast */ 376105293Sume m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); 377105293Sume ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL; 378105293Sume 379105293Sume return gif_validate4(&ip, sc, ifp); 380105293Sume} 381105293Sume 382105293Sumeint 383105293Sumein_gif_attach(sc) 384105293Sume struct gif_softc *sc; 385105293Sume{ 386105293Sume sc->encap_cookie4 = encap_attach_func(AF_INET, -1, gif_encapcheck, 387105293Sume &in_gif_protosw, sc); 388105293Sume if (sc->encap_cookie4 == NULL) 389105293Sume return EEXIST; 390105293Sume return 0; 391105293Sume} 392105293Sume 393105293Sumeint 394105293Sumein_gif_detach(sc) 395105293Sume struct gif_softc *sc; 396105293Sume{ 397105293Sume int error; 398105293Sume 399105293Sume error = encap_detach(sc->encap_cookie4); 400105293Sume if (error == 0) 401105293Sume sc->encap_cookie4 = NULL; 402105293Sume return error; 403105293Sume} 404