in_gif.c revision 120885
162587Sitojun/* $FreeBSD: head/sys/netinet/in_gif.c 120885 2003-10-07 15:02:29Z 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 = 78105293Sume{ SOCK_RAW, &inetdomain, 0/*IPPROTO_IPV[46]*/, PR_ATOMIC|PR_ADDR, 79105293Sume 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); 16455009Sshin if (ifp->if_flags & IFF_LINK1) 16555009Sshin ip_ecn_ingress(ECN_ALLOWED, &iphdr.ip_tos, &tos); 16678064Sume else 16778064Sume ip_ecn_ingress(ECN_NOCARE, &iphdr.ip_tos, &tos); 16854263Sshin 16954263Sshin /* prepend new IP header */ 170111119Simp M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); 17154263Sshin if (m && m->m_len < sizeof(struct ip)) 17254263Sshin m = m_pullup(m, sizeof(struct ip)); 17354263Sshin if (m == NULL) { 17454263Sshin printf("ENOBUFS in in_gif_output %d\n", __LINE__); 17554263Sshin return ENOBUFS; 17654263Sshin } 17762587Sitojun bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip)); 17854263Sshin 17954263Sshin if (dst->sin_family != sin_dst->sin_family || 18054263Sshin dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr) { 18154263Sshin /* cache route doesn't match */ 18254263Sshin dst->sin_family = sin_dst->sin_family; 18354263Sshin dst->sin_len = sizeof(struct sockaddr_in); 18454263Sshin dst->sin_addr = sin_dst->sin_addr; 18554263Sshin if (sc->gif_ro.ro_rt) { 18654263Sshin RTFREE(sc->gif_ro.ro_rt); 18754263Sshin sc->gif_ro.ro_rt = NULL; 18854263Sshin } 18962587Sitojun#if 0 19062587Sitojun sc->gif_if.if_mtu = GIF_MTU; 19162587Sitojun#endif 19254263Sshin } 19354263Sshin 19454263Sshin if (sc->gif_ro.ro_rt == NULL) { 19554263Sshin rtalloc(&sc->gif_ro); 19654263Sshin if (sc->gif_ro.ro_rt == NULL) { 19754263Sshin m_freem(m); 19854263Sshin return ENETUNREACH; 19954263Sshin } 20062587Sitojun 20162587Sitojun /* if it constitutes infinite encapsulation, punt. */ 20262587Sitojun if (sc->gif_ro.ro_rt->rt_ifp == ifp) { 20362587Sitojun m_freem(m); 20495023Ssuz return ENETUNREACH; /* XXX */ 20562587Sitojun } 20662587Sitojun#if 0 20762587Sitojun ifp->if_mtu = sc->gif_ro.ro_rt->rt_ifp->if_mtu 20862587Sitojun - sizeof(struct ip); 20962587Sitojun#endif 21054263Sshin } 21154263Sshin 212105194Ssam error = ip_output(m, NULL, &sc->gif_ro, 0, NULL, NULL); 213120885Sume return (error); 21454263Sshin} 21554263Sshin 21654263Sshinvoid 21782884Sjulianin_gif_input(m, off) 21862587Sitojun struct mbuf *m; 21979106Sbrooks int off; 22054263Sshin{ 22154263Sshin struct ifnet *gifp = NULL; 22254263Sshin struct ip *ip; 22362587Sitojun int af; 22455009Sshin u_int8_t otos; 22582884Sjulian int proto; 22654263Sshin 22754263Sshin ip = mtod(m, struct ip *); 22882884Sjulian proto = ip->ip_p; 22954263Sshin 23062587Sitojun gifp = (struct ifnet *)encap_getarg(m); 23154263Sshin 23262587Sitojun if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) { 23354263Sshin m_freem(m); 23454263Sshin ipstat.ips_nogif++; 23554263Sshin return; 23654263Sshin } 23754263Sshin 23855009Sshin otos = ip->ip_tos; 23954263Sshin m_adj(m, off); 24054263Sshin 24154263Sshin switch (proto) { 24262587Sitojun#ifdef INET 24354263Sshin case IPPROTO_IPV4: 24454263Sshin { 24554263Sshin struct ip *ip; 24654263Sshin af = AF_INET; 24754263Sshin if (m->m_len < sizeof(*ip)) { 24854263Sshin m = m_pullup(m, sizeof(*ip)); 24954263Sshin if (!m) 25054263Sshin return; 25154263Sshin } 25254263Sshin ip = mtod(m, struct ip *); 25355009Sshin if (gifp->if_flags & IFF_LINK1) 25455009Sshin ip_ecn_egress(ECN_ALLOWED, &otos, &ip->ip_tos); 25578064Sume else 25678064Sume ip_ecn_egress(ECN_NOCARE, &otos, &ip->ip_tos); 25754263Sshin break; 25854263Sshin } 25962587Sitojun#endif 26054263Sshin#ifdef INET6 26154263Sshin case IPPROTO_IPV6: 26254263Sshin { 26354263Sshin struct ip6_hdr *ip6; 26455009Sshin u_int8_t itos; 26554263Sshin af = AF_INET6; 26654263Sshin if (m->m_len < sizeof(*ip6)) { 26754263Sshin m = m_pullup(m, sizeof(*ip6)); 26854263Sshin if (!m) 26954263Sshin return; 27054263Sshin } 27154263Sshin ip6 = mtod(m, struct ip6_hdr *); 27255009Sshin itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 27355009Sshin if (gifp->if_flags & IFF_LINK1) 27455009Sshin ip_ecn_egress(ECN_ALLOWED, &otos, &itos); 27578064Sume else 27678064Sume ip_ecn_egress(ECN_NOCARE, &otos, &itos); 27754263Sshin ip6->ip6_flow &= ~htonl(0xff << 20); 27855009Sshin ip6->ip6_flow |= htonl((u_int32_t)itos << 20); 27954263Sshin break; 28054263Sshin } 28154263Sshin#endif /* INET6 */ 28254263Sshin default: 28354263Sshin ipstat.ips_nogif++; 28454263Sshin m_freem(m); 28554263Sshin return; 28654263Sshin } 28754263Sshin gif_input(m, af, gifp); 28854263Sshin return; 28954263Sshin} 29062587Sitojun 29162587Sitojun/* 292105293Sume * validate outer address. 29362587Sitojun */ 294105293Sumestatic int 295105293Sumegif_validate4(ip, sc, ifp) 296105293Sume const struct ip *ip; 297105293Sume struct gif_softc *sc; 298105293Sume struct ifnet *ifp; 29962587Sitojun{ 30062587Sitojun struct sockaddr_in *src, *dst; 30162587Sitojun struct in_ifaddr *ia4; 30262587Sitojun 30362587Sitojun src = (struct sockaddr_in *)sc->gif_psrc; 30462587Sitojun dst = (struct sockaddr_in *)sc->gif_pdst; 30562587Sitojun 30662587Sitojun /* check for address match */ 307105293Sume if (src->sin_addr.s_addr != ip->ip_dst.s_addr || 308105293Sume dst->sin_addr.s_addr != ip->ip_src.s_addr) 30962587Sitojun return 0; 31062587Sitojun 31162587Sitojun /* martian filters on outer source - NOT done in ip_input! */ 312105293Sume if (IN_MULTICAST(ntohl(ip->ip_src.s_addr))) 31362587Sitojun return 0; 314105293Sume switch ((ntohl(ip->ip_src.s_addr) & 0xff000000) >> 24) { 31562587Sitojun case 0: case 127: case 255: 31662587Sitojun return 0; 31762587Sitojun } 31862587Sitojun /* reject packets with broadcast on source */ 31972012Sphk TAILQ_FOREACH(ia4, &in_ifaddrhead, ia_link) 32062587Sitojun { 32162587Sitojun if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0) 32262587Sitojun continue; 323105293Sume if (ip->ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr) 32462587Sitojun return 0; 32562587Sitojun } 32662587Sitojun 32762587Sitojun /* ingress filters on outer source */ 328105293Sume if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && ifp) { 32962587Sitojun struct sockaddr_in sin; 33062587Sitojun struct rtentry *rt; 33162587Sitojun 33262587Sitojun bzero(&sin, sizeof(sin)); 33362587Sitojun sin.sin_family = AF_INET; 33462587Sitojun sin.sin_len = sizeof(struct sockaddr_in); 335105293Sume sin.sin_addr = ip->ip_src; 33662587Sitojun rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL); 337105293Sume if (!rt || rt->rt_ifp != ifp) { 33878064Sume#if 0 33978064Sume log(LOG_WARNING, "%s: packet from 0x%x dropped " 34078064Sume "due to ingress filter\n", if_name(&sc->gif_if), 34178064Sume (u_int32_t)ntohl(sin.sin_addr.s_addr)); 34278064Sume#endif 34378064Sume if (rt) 34478064Sume rtfree(rt); 34562587Sitojun return 0; 34662587Sitojun } 34762587Sitojun rtfree(rt); 34862587Sitojun } 34962587Sitojun 35078064Sume return 32 * 2; 35162587Sitojun} 352105293Sume 353105293Sume/* 354105293Sume * we know that we are in IFF_UP, outer address available, and outer family 355105293Sume * matched the physical addr family. see gif_encapcheck(). 356105293Sume */ 357105293Sumeint 358105293Sumegif_encapcheck4(m, off, proto, arg) 359105293Sume const struct mbuf *m; 360105293Sume int off; 361105293Sume int proto; 362105293Sume void *arg; 363105293Sume{ 364105293Sume struct ip ip; 365105293Sume struct gif_softc *sc; 366105293Sume struct ifnet *ifp; 367105293Sume 368105293Sume /* sanity check done in caller */ 369105293Sume sc = (struct gif_softc *)arg; 370105293Sume 371105293Sume /* LINTED const cast */ 372105293Sume m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); 373105293Sume ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL; 374105293Sume 375105293Sume return gif_validate4(&ip, sc, ifp); 376105293Sume} 377105293Sume 378105293Sumeint 379105293Sumein_gif_attach(sc) 380105293Sume struct gif_softc *sc; 381105293Sume{ 382105293Sume sc->encap_cookie4 = encap_attach_func(AF_INET, -1, gif_encapcheck, 383105293Sume &in_gif_protosw, sc); 384105293Sume if (sc->encap_cookie4 == NULL) 385105293Sume return EEXIST; 386105293Sume return 0; 387105293Sume} 388105293Sume 389105293Sumeint 390105293Sumein_gif_detach(sc) 391105293Sume struct gif_softc *sc; 392105293Sume{ 393105293Sume int error; 394105293Sume 395105293Sume error = encap_detach(sc->encap_cookie4); 396105293Sume if (error == 0) 397105293Sume sc->encap_cookie4 = NULL; 398105293Sume return error; 399105293Sume} 400