in_gif.c revision 152242
143543Swollman/* $FreeBSD: head/sys/netinet/in_gif.c 152242 2005-11-09 13:29:16Z ru $ */ 22742Swollman/* $KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $ */ 32742Swollman 42742Swollman/*- 52742Swollman * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 62742Swollman * All rights reserved. 72742Swollman * 82742Swollman * Redistribution and use in source and binary forms, with or without 92742Swollman * modification, are permitted provided that the following conditions 102742Swollman * are met: 112742Swollman * 1. Redistributions of source code must retain the above copyright 122742Swollman * notice, this list of conditions and the following disclaimer. 132742Swollman * 2. Redistributions in binary form must reproduce the above copyright 142742Swollman * notice, this list of conditions and the following disclaimer in the 152742Swollman * documentation and/or other materials provided with the distribution. 162742Swollman * 3. Neither the name of the project nor the names of its contributors 172742Swollman * may be used to endorse or promote products derived from this software 182742Swollman * without specific prior written permission. 192742Swollman * 202742Swollman * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 212742Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 222742Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 239908Swollman * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 242742Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2530711Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 262742Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 272742Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 289908Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 292742Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 302742Swollman * SUCH DAMAGE. 3114343Swollman */ 3214343Swollman 3314343Swollman#include "opt_mrouting.h" 3414343Swollman#include "opt_inet.h" 3514343Swollman#include "opt_inet6.h" 3614343Swollman 372742Swollman#include <sys/param.h> 389908Swollman#include <sys/systm.h> 3920094Swollman#include <sys/socket.h> 4020094Swollman#include <sys/sockio.h> 4120094Swollman#include <sys/mbuf.h> 4220094Swollman#include <sys/errno.h> 4320094Swollman#include <sys/kernel.h> 4420094Swollman#include <sys/sysctl.h> 4520094Swollman#include <sys/protosw.h> 4620094Swollman 4720094Swollman#include <sys/malloc.h> 4820094Swollman 4920094Swollman#include <net/if.h> 5020094Swollman#include <net/route.h> 5120094Swollman 5221217Swollman#include <netinet/in.h> 5321217Swollman#include <netinet/in_systm.h> 5420094Swollman#include <netinet/ip.h> 5520094Swollman#include <netinet/ip_var.h> 562742Swollman#include <netinet/in_gif.h> 572742Swollman#include <netinet/in_var.h> 5814343Swollman#include <netinet/ip_encap.h> 5914343Swollman#include <netinet/ip_ecn.h> 6021217Swollman 6120094Swollman#ifdef INET6 6220094Swollman#include <netinet/ip6.h> 6320094Swollman#endif 6420094Swollman 6520094Swollman#ifdef MROUTING 662742Swollman#include <netinet/ip_mroute.h> 679908Swollman#endif /* MROUTING */ 682742Swollman 6914343Swollman#include <net/if_gif.h> 7014343Swollman 7114343Swollman#include <net/net_osdep.h> 7214343Swollman 7314343Swollmanstatic int gif_validate4(const struct ip *, struct gif_softc *, 7414343Swollman struct ifnet *); 7514343Swollman 7614343Swollmanextern struct domain inetdomain; 7714343Swollmanstruct protosw in_gif_protosw = { 782742Swollman .pr_type = SOCK_RAW, 792742Swollman .pr_domain = &inetdomain, 802742Swollman .pr_protocol = 0/* IPPROTO_IPV[46] */, 812742Swollman .pr_flags = PR_ATOMIC|PR_ADDR, 8214343Swollman .pr_input = in_gif_input, 832742Swollman .pr_output = (pr_output_t*)rip_output, 842742Swollman .pr_ctloutput = rip_ctloutput, 859908Swollman .pr_usrreqs = &rip_usrreqs 862742Swollman}; 8714343Swollman 8814343Swollmanstatic int ip_gif_ttl = GIF_TTL; 8914343SwollmanSYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW, 9014343Swollman &ip_gif_ttl, 0, ""); 9114343Swollman 9214343Swollmanint 9314343Swollmanin_gif_output(ifp, family, m) 9414343Swollman struct ifnet *ifp; 9514343Swollman int family; 9614343Swollman struct mbuf *m; 9714343Swollman{ 9814343Swollman struct gif_softc *sc = ifp->if_softc; 9914343Swollman struct sockaddr_in *dst = (struct sockaddr_in *)&sc->gif_ro.ro_dst; 1002742Swollman struct sockaddr_in *sin_src = (struct sockaddr_in *)sc->gif_psrc; 1012742Swollman struct sockaddr_in *sin_dst = (struct sockaddr_in *)sc->gif_pdst; 1022742Swollman struct ip iphdr; /* capsule IP header, host byte ordered */ 10314343Swollman int proto, error; 1042742Swollman u_int8_t tos; 1052742Swollman 1069908Swollman if (sin_src == NULL || sin_dst == NULL || 1072742Swollman sin_src->sin_family != AF_INET || 10814343Swollman sin_dst->sin_family != AF_INET) { 10914343Swollman m_freem(m); 11014343Swollman return EAFNOSUPPORT; 11114343Swollman } 11214343Swollman 11343543Swollman switch (family) { 11414343Swollman#ifdef INET 11514343Swollman case AF_INET: 11643543Swollman { 11743543Swollman struct ip *ip; 1182742Swollman 1192742Swollman proto = IPPROTO_IPV4; 1202742Swollman if (m->m_len < sizeof(*ip)) { 12114343Swollman m = m_pullup(m, sizeof(*ip)); 1222742Swollman if (!m) 1232742Swollman return ENOBUFS; 1249908Swollman } 1252742Swollman ip = mtod(m, struct ip *); 12614343Swollman tos = ip->ip_tos; 12714343Swollman break; 12814343Swollman } 12914343Swollman#endif /* INET */ 13014343Swollman#ifdef INET6 13114343Swollman case AF_INET6: 13214343Swollman { 13343543Swollman struct ip6_hdr *ip6; 13414343Swollman proto = IPPROTO_IPV6; 13514343Swollman if (m->m_len < sizeof(*ip6)) { 13643543Swollman m = m_pullup(m, sizeof(*ip6)); 13743543Swollman if (!m) 1382742Swollman return ENOBUFS; 1392742Swollman } 1402742Swollman ip6 = mtod(m, struct ip6_hdr *); 14114343Swollman tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 1422742Swollman break; 1432742Swollman } 1442742Swollman#endif /* INET6 */ 1452742Swollman default: 1462742Swollman#ifdef DEBUG 14714343Swollman printf("in_gif_output: warning: unknown family %d passed\n", 1482742Swollman family); 1498029Swollman#endif 15014343Swollman m_freem(m); 15114343Swollman return EAFNOSUPPORT; 15214343Swollman } 15314343Swollman 15414343Swollman bzero(&iphdr, sizeof(iphdr)); 15514343Swollman iphdr.ip_src = sin_src->sin_addr; 15614343Swollman /* bidirectional configured tunnel mode */ 15714343Swollman if (sin_dst->sin_addr.s_addr != INADDR_ANY) 15814343Swollman iphdr.ip_dst = sin_dst->sin_addr; 15914343Swollman else { 1602742Swollman m_freem(m); 1612742Swollman return ENETUNREACH; 16214343Swollman } 1638029Swollman iphdr.ip_p = proto; 16414343Swollman /* version will be set in ip_output() */ 1652742Swollman iphdr.ip_ttl = ip_gif_ttl; 1662742Swollman iphdr.ip_len = m->m_pkthdr.len + sizeof(struct ip); 16714343Swollman ip_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED : ECN_NOCARE, 1682742Swollman &iphdr.ip_tos, &tos); 1692742Swollman 17014343Swollman /* prepend new IP header */ 17114343Swollman M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); 17214343Swollman if (m && m->m_len < sizeof(struct ip)) 17314343Swollman m = m_pullup(m, sizeof(struct ip)); 17430711Swollman if (m == NULL) { 17530711Swollman printf("ENOBUFS in in_gif_output %d\n", __LINE__); 17630711Swollman return ENOBUFS; 1772742Swollman } 17830711Swollman bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip)); 17930711Swollman 18030711Swollman if (dst->sin_family != sin_dst->sin_family || 1812742Swollman dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr) { 18243014Swollman /* cache route doesn't match */ 18343014Swollman bzero(dst, sizeof(*dst)); 18443014Swollman dst->sin_family = sin_dst->sin_family; 18543014Swollman dst->sin_len = sizeof(struct sockaddr_in); 1862742Swollman dst->sin_addr = sin_dst->sin_addr; 1872742Swollman if (sc->gif_ro.ro_rt) { 18843014Swollman RTFREE(sc->gif_ro.ro_rt); 1892742Swollman sc->gif_ro.ro_rt = NULL; 19019878Swollman } 19143014Swollman#if 0 19243014Swollman GIF2IFP(sc)->if_mtu = GIF_MTU; 1932742Swollman#endif 1942742Swollman } 19519878Swollman 19619878Swollman if (sc->gif_ro.ro_rt == NULL) { 1972742Swollman rtalloc_ign(&sc->gif_ro, 0); 1982742Swollman if (sc->gif_ro.ro_rt == NULL) { 1992742Swollman m_freem(m); 2002742Swollman return ENETUNREACH; 20119878Swollman } 2022742Swollman 2032742Swollman /* if it constitutes infinite encapsulation, punt. */ 20443543Swollman if (sc->gif_ro.ro_rt->rt_ifp == ifp) { 20543543Swollman m_freem(m); 20643543Swollman return ENETUNREACH; /* XXX */ 2072742Swollman } 2082742Swollman#if 0 20943543Swollman ifp->if_mtu = sc->gif_ro.ro_rt->rt_ifp->if_mtu 2102742Swollman - sizeof(struct ip); 2112742Swollman#endif 2122742Swollman } 2132742Swollman 21419878Swollman error = ip_output(m, NULL, &sc->gif_ro, 0, NULL, NULL); 2152742Swollman 21619878Swollman if (!(GIF2IFP(sc)->if_flags & IFF_LINK0) && 2172742Swollman sc->gif_ro.ro_rt != NULL) { 21819878Swollman RTFREE(sc->gif_ro.ro_rt); 21943014Swollman sc->gif_ro.ro_rt = NULL; 22043014Swollman } 2212742Swollman 2222742Swollman return (error); 2232742Swollman} 2242742Swollman 2252742Swollmanvoid 2262742Swollmanin_gif_input(m, off) 2272742Swollman struct mbuf *m; 2282742Swollman int off; 2292742Swollman{ 23019878Swollman struct ifnet *gifp = NULL; 2312742Swollman struct gif_softc *sc; 23219878Swollman struct ip *ip; 23319878Swollman int af; 23419878Swollman u_int8_t otos; 2352742Swollman int proto; 23619878Swollman 23719878Swollman ip = mtod(m, struct ip *); 23819878Swollman proto = ip->ip_p; 2392742Swollman 24014343Swollman sc = (struct gif_softc *)encap_getarg(m); 24114343Swollman if (sc == NULL) { 24214343Swollman m_freem(m); 24319878Swollman ipstat.ips_nogif++; 24419878Swollman return; 24514343Swollman } 24614343Swollman 24714343Swollman gifp = GIF2IFP(sc); 24814343Swollman if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) { 24919878Swollman m_freem(m); 25019878Swollman ipstat.ips_nogif++; 25114343Swollman return; 25219878Swollman } 25319878Swollman 25419878Swollman otos = ip->ip_tos; 25514343Swollman m_adj(m, off); 25614343Swollman 25714343Swollman switch (proto) { 25814343Swollman#ifdef INET 25919878Swollman case IPPROTO_IPV4: 26019878Swollman { 26114343Swollman struct ip *ip; 26219878Swollman af = AF_INET; 26314343Swollman if (m->m_len < sizeof(*ip)) { 26419878Swollman m = m_pullup(m, sizeof(*ip)); 26514343Swollman if (!m) 26619878Swollman return; 26719878Swollman } 26814343Swollman ip = mtod(m, struct ip *); 2692742Swollman if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ? 2702742Swollman ECN_ALLOWED : ECN_NOCARE, 2712742Swollman &otos, &ip->ip_tos) == 0) { 27219878Swollman m_freem(m); 2732742Swollman return; 27419878Swollman } 27519878Swollman break; 2762742Swollman } 2772742Swollman#endif 2782742Swollman#ifdef INET6 27919878Swollman case IPPROTO_IPV6: 28019878Swollman { 28143014Swollman struct ip6_hdr *ip6; 28243014Swollman u_int8_t itos, oitos; 2832742Swollman 2842742Swollman af = AF_INET6; 2852742Swollman if (m->m_len < sizeof(*ip6)) { 2862742Swollman m = m_pullup(m, sizeof(*ip6)); 2872742Swollman if (!m) 2882742Swollman return; 2892742Swollman } 2902742Swollman ip6 = mtod(m, struct ip6_hdr *); 2912742Swollman itos = oitos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 2922742Swollman if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ? 2932742Swollman ECN_ALLOWED : ECN_NOCARE, 2942742Swollman &otos, &itos) == 0) { 29514343Swollman m_freem(m); 2962742Swollman return; 29714343Swollman } 29814343Swollman if (itos != oitos) { 2992742Swollman ip6->ip6_flow &= ~htonl(0xff << 20); 30014343Swollman ip6->ip6_flow |= htonl((u_int32_t)itos << 20); 30143014Swollman } 30214343Swollman break; 30314343Swollman } 30414343Swollman#endif /* INET6 */ 3059908Swollman default: 3069908Swollman ipstat.ips_nogif++; 3079908Swollman m_freem(m); 3089908Swollman return; 3099908Swollman } 3109908Swollman gif_input(m, af, gifp); 3119908Swollman return; 31220094Swollman} 31320094Swollman 3142742Swollman/* 3152742Swollman * validate outer address. 31614343Swollman */ 3172742Swollmanstatic int 31820094Swollmangif_validate4(ip, sc, ifp) 3192742Swollman const struct ip *ip; 3208029Swollman struct gif_softc *sc; 32130711Swollman struct ifnet *ifp; 32230711Swollman{ 3232742Swollman struct sockaddr_in *src, *dst; 32430711Swollman struct in_ifaddr *ia4; 32530711Swollman 32630711Swollman src = (struct sockaddr_in *)sc->gif_psrc; 32730711Swollman dst = (struct sockaddr_in *)sc->gif_pdst; 32830711Swollman 3292742Swollman /* check for address match */ 3302742Swollman if (src->sin_addr.s_addr != ip->ip_dst.s_addr || 3312742Swollman dst->sin_addr.s_addr != ip->ip_src.s_addr) 3322742Swollman return 0; 3332742Swollman 3342742Swollman /* martian filters on outer source - NOT done in ip_input! */ 33519878Swollman if (IN_MULTICAST(ntohl(ip->ip_src.s_addr))) 33619878Swollman return 0; 33719878Swollman switch ((ntohl(ip->ip_src.s_addr) & 0xff000000) >> 24) { 3382742Swollman case 0: case 127: case 255: 3392742Swollman return 0; 3402742Swollman } 3412742Swollman /* reject packets with broadcast on source */ 34219878Swollman TAILQ_FOREACH(ia4, &in_ifaddrhead, ia_link) { 34319878Swollman if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0) 3442742Swollman continue; 3459908Swollman if (ip->ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr) 3469908Swollman return 0; 3479908Swollman } 34819878Swollman 3499908Swollman /* ingress filters on outer source */ 3502742Swollman if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0 && ifp) { 3512742Swollman struct sockaddr_in sin; 3522742Swollman struct rtentry *rt; 35319878Swollman 35419878Swollman bzero(&sin, sizeof(sin)); 3552742Swollman sin.sin_family = AF_INET; 3562742Swollman sin.sin_len = sizeof(struct sockaddr_in); 3572742Swollman sin.sin_addr = ip->ip_src; 3582742Swollman rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL); 35919878Swollman if (!rt || rt->rt_ifp != ifp) { 3602742Swollman#if 0 36114343Swollman log(LOG_WARNING, "%s: packet from 0x%x dropped " 36214343Swollman "due to ingress filter\n", if_name(GIF2IFP(sc)), 36314343Swollman (u_int32_t)ntohl(sin.sin_addr.s_addr)); 36419878Swollman#endif 36514343Swollman if (rt) 36614343Swollman rtfree(rt); 36714343Swollman return 0; 36814343Swollman } 36914343Swollman rtfree(rt); 37014343Swollman } 37114343Swollman 37219878Swollman return 32 * 2; 37319878Swollman} 37414343Swollman 3752742Swollman/* 3762742Swollman * we know that we are in IFF_UP, outer address available, and outer family 3772742Swollman * matched the physical addr family. see gif_encapcheck(). 3782742Swollman */ 37919878Swollmanint 3802742Swollmangif_encapcheck4(m, off, proto, arg) 3812742Swollman const struct mbuf *m; 3822742Swollman int off; 3832742Swollman int proto; 38419878Swollman void *arg; 3852742Swollman{ 3862742Swollman struct ip ip; 3872742Swollman struct gif_softc *sc; 3882742Swollman struct ifnet *ifp; 38919878Swollman 39019878Swollman /* sanity check done in caller */ 3912742Swollman sc = (struct gif_softc *)arg; 3922742Swollman 3932742Swollman /* LINTED const cast */ 3942742Swollman m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); 39519878Swollman ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL; 3962742Swollman 39743014Swollman return gif_validate4(&ip, sc, ifp); 39843014Swollman} 39943014Swollman 40043014Swollmanint 40143014Swollmanin_gif_attach(sc) 40243014Swollman struct gif_softc *sc; 40343014Swollman{ 40443014Swollman sc->encap_cookie4 = encap_attach_func(AF_INET, -1, gif_encapcheck, 40543014Swollman &in_gif_protosw, sc); 40643014Swollman if (sc->encap_cookie4 == NULL) 40743014Swollman return EEXIST; 40843014Swollman return 0; 40943014Swollman} 41043014Swollman 41143014Swollmanint 41243014Swollmanin_gif_detach(sc) 41343014Swollman struct gif_softc *sc; 41443014Swollman{ 41543014Swollman int error; 41643014Swollman 41743014Swollman error = encap_detach(sc->encap_cookie4); 41843014Swollman if (error == 0) 41943014Swollman sc->encap_cookie4 = NULL; 42043014Swollman return error; 42143014Swollman} 42243014Swollman