1c398230bSWarner Losh /*- 2cfa1ca9dSYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 3cfa1ca9dSYoshinobu Inoue * All rights reserved. 4cfa1ca9dSYoshinobu Inoue * 5cfa1ca9dSYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 6cfa1ca9dSYoshinobu Inoue * modification, are permitted provided that the following conditions 7cfa1ca9dSYoshinobu Inoue * are met: 8cfa1ca9dSYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 9cfa1ca9dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 10cfa1ca9dSYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 11cfa1ca9dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 12cfa1ca9dSYoshinobu Inoue * documentation and/or other materials provided with the distribution. 13cfa1ca9dSYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 14cfa1ca9dSYoshinobu Inoue * may be used to endorse or promote products derived from this software 15cfa1ca9dSYoshinobu Inoue * without specific prior written permission. 16cfa1ca9dSYoshinobu Inoue * 17cfa1ca9dSYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 18cfa1ca9dSYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19cfa1ca9dSYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20cfa1ca9dSYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 21cfa1ca9dSYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22cfa1ca9dSYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23cfa1ca9dSYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24cfa1ca9dSYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25cfa1ca9dSYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26cfa1ca9dSYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27cfa1ca9dSYoshinobu Inoue * SUCH DAMAGE. 280b9f5f8aSAndrey V. Elsukov * 290b9f5f8aSAndrey V. Elsukov * $KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $ 30cfa1ca9dSYoshinobu Inoue */ 31cfa1ca9dSYoshinobu Inoue 324b421e2dSMike Silbersack #include <sys/cdefs.h> 334b421e2dSMike Silbersack __FBSDID("$FreeBSD$"); 344b421e2dSMike Silbersack 35686cdd19SJun-ichiro itojun Hagino #include "opt_inet.h" 36cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h" 37cfa1ca9dSYoshinobu Inoue 38cfa1ca9dSYoshinobu Inoue #include <sys/param.h> 390b9f5f8aSAndrey V. Elsukov #include <sys/lock.h> 400b9f5f8aSAndrey V. Elsukov #include <sys/rmlock.h> 41cfa1ca9dSYoshinobu Inoue #include <sys/systm.h> 42cfa1ca9dSYoshinobu Inoue #include <sys/socket.h> 43cfa1ca9dSYoshinobu Inoue #include <sys/sockio.h> 44cfa1ca9dSYoshinobu Inoue #include <sys/mbuf.h> 45cfa1ca9dSYoshinobu Inoue #include <sys/errno.h> 46cfa1ca9dSYoshinobu Inoue #include <sys/kernel.h> 47cfa1ca9dSYoshinobu Inoue #include <sys/sysctl.h> 489426aedfSHajimu UMEMOTO #include <sys/protosw.h> 49686cdd19SJun-ichiro itojun Hagino #include <sys/malloc.h> 50cfa1ca9dSYoshinobu Inoue 51cfa1ca9dSYoshinobu Inoue #include <net/if.h> 5276039bc8SGleb Smirnoff #include <net/if_var.h> 53cfa1ca9dSYoshinobu Inoue #include <net/route.h> 54530c0060SRobert Watson #include <net/vnet.h> 55cfa1ca9dSYoshinobu Inoue 56cfa1ca9dSYoshinobu Inoue #include <netinet/in.h> 57cfa1ca9dSYoshinobu Inoue #include <netinet/in_systm.h> 58cfa1ca9dSYoshinobu Inoue #include <netinet/ip.h> 596a800098SYoshinobu Inoue #include <netinet/ip_var.h> 60686cdd19SJun-ichiro itojun Hagino #include <netinet/in_var.h> 61686cdd19SJun-ichiro itojun Hagino #include <netinet/ip_encap.h> 626a800098SYoshinobu Inoue #include <netinet/ip_ecn.h> 63686cdd19SJun-ichiro itojun Hagino 646a800098SYoshinobu Inoue #ifdef INET6 65686cdd19SJun-ichiro itojun Hagino #include <netinet/ip6.h> 666a800098SYoshinobu Inoue #endif 67cfa1ca9dSYoshinobu Inoue 68cfa1ca9dSYoshinobu Inoue #include <net/if_gif.h> 69cfa1ca9dSYoshinobu Inoue 709426aedfSHajimu UMEMOTO static int gif_validate4(const struct ip *, struct gif_softc *, 719426aedfSHajimu UMEMOTO struct ifnet *); 72132c4490SAndrey V. Elsukov static int in_gif_input(struct mbuf **, int *, int); 739426aedfSHajimu UMEMOTO 749426aedfSHajimu UMEMOTO extern struct domain inetdomain; 75132c4490SAndrey V. Elsukov static struct protosw in_gif_protosw = { 76303989a2SRuslan Ermilov .pr_type = SOCK_RAW, 77303989a2SRuslan Ermilov .pr_domain = &inetdomain, 78303989a2SRuslan Ermilov .pr_protocol = 0/* IPPROTO_IPV[46] */, 79303989a2SRuslan Ermilov .pr_flags = PR_ATOMIC|PR_ADDR, 80303989a2SRuslan Ermilov .pr_input = in_gif_input, 8173d76e77SKevin Lo .pr_output = rip_output, 82303989a2SRuslan Ermilov .pr_ctloutput = rip_ctloutput, 83303989a2SRuslan Ermilov .pr_usrreqs = &rip_usrreqs 849426aedfSHajimu UMEMOTO }; 859426aedfSHajimu UMEMOTO 86132c4490SAndrey V. Elsukov #define GIF_TTL 30 87132c4490SAndrey V. Elsukov static VNET_DEFINE(int, ip_gif_ttl) = GIF_TTL; 8882cea7e6SBjoern A. Zeeb #define V_ip_gif_ttl VNET(ip_gif_ttl) 896df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_VNET | CTLFLAG_RW, 90eddfbb76SRobert Watson &VNET_NAME(ip_gif_ttl), 0, ""); 91cfa1ca9dSYoshinobu Inoue 92cfa1ca9dSYoshinobu Inoue int 930b9f5f8aSAndrey V. Elsukov in_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn) 94cfa1ca9dSYoshinobu Inoue { 950b9f5f8aSAndrey V. Elsukov GIF_RLOCK_TRACKER; 96fc74a9f9SBrooks Davis struct gif_softc *sc = ifp->if_softc; 97cfa1ca9dSYoshinobu Inoue struct ip *ip; 980b9f5f8aSAndrey V. Elsukov int len; 99cfa1ca9dSYoshinobu Inoue 100cfa1ca9dSYoshinobu Inoue /* prepend new IP header */ 101c89c8a10SMarius Strobl len = sizeof(struct ip); 102c89c8a10SMarius Strobl #ifndef __NO_STRICT_ALIGNMENT 1030b9f5f8aSAndrey V. Elsukov if (proto == IPPROTO_ETHERIP) 104c89c8a10SMarius Strobl len += ETHERIP_ALIGN; 105c89c8a10SMarius Strobl #endif 106eb1b1807SGleb Smirnoff M_PREPEND(m, len, M_NOWAIT); 1070b9f5f8aSAndrey V. Elsukov if (m == NULL) 1080b9f5f8aSAndrey V. Elsukov return (ENOBUFS); 109c89c8a10SMarius Strobl #ifndef __NO_STRICT_ALIGNMENT 1100b9f5f8aSAndrey V. Elsukov if (proto == IPPROTO_ETHERIP) { 111c89c8a10SMarius Strobl len = mtod(m, vm_offset_t) & 3; 112c89c8a10SMarius Strobl KASSERT(len == 0 || len == ETHERIP_ALIGN, 113c89c8a10SMarius Strobl ("in_gif_output: unexpected misalignment")); 114c89c8a10SMarius Strobl m->m_data += len; 115c89c8a10SMarius Strobl m->m_len -= ETHERIP_ALIGN; 116c89c8a10SMarius Strobl } 117c89c8a10SMarius Strobl #endif 1180b9f5f8aSAndrey V. Elsukov ip = mtod(m, struct ip *); 1190b9f5f8aSAndrey V. Elsukov GIF_RLOCK(sc); 1200b9f5f8aSAndrey V. Elsukov if (sc->gif_family != AF_INET) { 121cfa1ca9dSYoshinobu Inoue m_freem(m); 1220b9f5f8aSAndrey V. Elsukov GIF_RUNLOCK(sc); 1230b9f5f8aSAndrey V. Elsukov return (ENETDOWN); 124cfa1ca9dSYoshinobu Inoue } 1250b9f5f8aSAndrey V. Elsukov bcopy(sc->gif_iphdr, ip, sizeof(struct ip)); 1260b9f5f8aSAndrey V. Elsukov GIF_RUNLOCK(sc); 127686cdd19SJun-ichiro itojun Hagino 1280b9f5f8aSAndrey V. Elsukov ip->ip_p = proto; 1290b9f5f8aSAndrey V. Elsukov /* version will be set in ip_output() */ 1300b9f5f8aSAndrey V. Elsukov ip->ip_ttl = V_ip_gif_ttl; 1310b9f5f8aSAndrey V. Elsukov ip->ip_len = htons(m->m_pkthdr.len); 1320b9f5f8aSAndrey V. Elsukov ip->ip_tos = ecn; 133cfa1ca9dSYoshinobu Inoue 1340b9f5f8aSAndrey V. Elsukov return (ip_output(m, NULL, NULL, 0, NULL, NULL)); 135cfa1ca9dSYoshinobu Inoue } 136cfa1ca9dSYoshinobu Inoue 137132c4490SAndrey V. Elsukov static int 1388f5a8818SKevin Lo in_gif_input(struct mbuf **mp, int *offp, int proto) 139cfa1ca9dSYoshinobu Inoue { 1400b9f5f8aSAndrey V. Elsukov struct mbuf *m = *mp; 14167df9f38SBjoern A. Zeeb struct gif_softc *sc; 1420b9f5f8aSAndrey V. Elsukov struct ifnet *gifp; 143cfa1ca9dSYoshinobu Inoue struct ip *ip; 1440b9f5f8aSAndrey V. Elsukov uint8_t ecn; 145cfa1ca9dSYoshinobu Inoue 1460b9f5f8aSAndrey V. Elsukov sc = encap_getarg(m); 14767df9f38SBjoern A. Zeeb if (sc == NULL) { 14867df9f38SBjoern A. Zeeb m_freem(m); 149315e3e38SRobert Watson KMOD_IPSTAT_INC(ips_nogif); 1508f5a8818SKevin Lo return (IPPROTO_DONE); 15167df9f38SBjoern A. Zeeb } 15267df9f38SBjoern A. Zeeb gifp = GIF2IFP(sc); 1530b9f5f8aSAndrey V. Elsukov if ((gifp->if_flags & IFF_UP) != 0) { 154cfa1ca9dSYoshinobu Inoue ip = mtod(m, struct ip *); 1550b9f5f8aSAndrey V. Elsukov ecn = ip->ip_tos; 1560b9f5f8aSAndrey V. Elsukov m_adj(m, *offp); 1570b9f5f8aSAndrey V. Elsukov gif_input(m, gifp, proto, ecn); 1580b9f5f8aSAndrey V. Elsukov } else { 15959dfcba4SHajimu UMEMOTO m_freem(m); 160315e3e38SRobert Watson KMOD_IPSTAT_INC(ips_nogif); 161cfa1ca9dSYoshinobu Inoue } 1628f5a8818SKevin Lo return (IPPROTO_DONE); 163cfa1ca9dSYoshinobu Inoue } 164686cdd19SJun-ichiro itojun Hagino 165686cdd19SJun-ichiro itojun Hagino /* 1669426aedfSHajimu UMEMOTO * validate outer address. 167686cdd19SJun-ichiro itojun Hagino */ 1689426aedfSHajimu UMEMOTO static int 169f2565d68SRobert Watson gif_validate4(const struct ip *ip, struct gif_softc *sc, struct ifnet *ifp) 1709426aedfSHajimu UMEMOTO { 171*c1b4f79dSAndrey V. Elsukov int ret; 172686cdd19SJun-ichiro itojun Hagino 1730b9f5f8aSAndrey V. Elsukov GIF_RLOCK_ASSERT(sc); 174686cdd19SJun-ichiro itojun Hagino 175686cdd19SJun-ichiro itojun Hagino /* check for address match */ 176*c1b4f79dSAndrey V. Elsukov if (sc->gif_iphdr->ip_src.s_addr != ip->ip_dst.s_addr) 1770b9f5f8aSAndrey V. Elsukov return (0); 178*c1b4f79dSAndrey V. Elsukov ret = 32; 179*c1b4f79dSAndrey V. Elsukov if (sc->gif_iphdr->ip_dst.s_addr != ip->ip_src.s_addr) { 180*c1b4f79dSAndrey V. Elsukov if ((sc->gif_options & GIF_IGNORE_SOURCE) == 0) 181*c1b4f79dSAndrey V. Elsukov return (0); 182*c1b4f79dSAndrey V. Elsukov } else 183*c1b4f79dSAndrey V. Elsukov ret += 32; 184686cdd19SJun-ichiro itojun Hagino 185686cdd19SJun-ichiro itojun Hagino /* martian filters on outer source - NOT done in ip_input! */ 1869426aedfSHajimu UMEMOTO if (IN_MULTICAST(ntohl(ip->ip_src.s_addr))) 1870b9f5f8aSAndrey V. Elsukov return (0); 1889426aedfSHajimu UMEMOTO switch ((ntohl(ip->ip_src.s_addr) & 0xff000000) >> 24) { 1890b9f5f8aSAndrey V. Elsukov case 0: 1900b9f5f8aSAndrey V. Elsukov case 127: 1910b9f5f8aSAndrey V. Elsukov case 255: 1920b9f5f8aSAndrey V. Elsukov return (0); 193686cdd19SJun-ichiro itojun Hagino } 1942d9cfabaSRobert Watson 195686cdd19SJun-ichiro itojun Hagino /* ingress filters on outer source */ 196fc74a9f9SBrooks Davis if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0 && ifp) { 197686cdd19SJun-ichiro itojun Hagino struct sockaddr_in sin; 198686cdd19SJun-ichiro itojun Hagino struct rtentry *rt; 199686cdd19SJun-ichiro itojun Hagino 200686cdd19SJun-ichiro itojun Hagino bzero(&sin, sizeof(sin)); 201686cdd19SJun-ichiro itojun Hagino sin.sin_family = AF_INET; 202686cdd19SJun-ichiro itojun Hagino sin.sin_len = sizeof(struct sockaddr_in); 2039426aedfSHajimu UMEMOTO sin.sin_addr = ip->ip_src; 2048b07e49aSJulian Elischer /* XXX MRT check for the interface we would use on output */ 2058b07e49aSJulian Elischer rt = in_rtalloc1((struct sockaddr *)&sin, 0, 2068b07e49aSJulian Elischer 0UL, sc->gif_fibnum); 2079426aedfSHajimu UMEMOTO if (!rt || rt->rt_ifp != ifp) { 20833841545SHajimu UMEMOTO if (rt) 209bc60490aSChristian S.J. Peron RTFREE_LOCKED(rt); 2100b9f5f8aSAndrey V. Elsukov return (0); 211686cdd19SJun-ichiro itojun Hagino } 212bc60490aSChristian S.J. Peron RTFREE_LOCKED(rt); 213686cdd19SJun-ichiro itojun Hagino } 214*c1b4f79dSAndrey V. Elsukov return (ret); 215686cdd19SJun-ichiro itojun Hagino } 2169426aedfSHajimu UMEMOTO 2179426aedfSHajimu UMEMOTO /* 2189426aedfSHajimu UMEMOTO * we know that we are in IFF_UP, outer address available, and outer family 2199426aedfSHajimu UMEMOTO * matched the physical addr family. see gif_encapcheck(). 2209426aedfSHajimu UMEMOTO */ 2219426aedfSHajimu UMEMOTO int 2220b9f5f8aSAndrey V. Elsukov in_gif_encapcheck(const struct mbuf *m, int off, int proto, void *arg) 2239426aedfSHajimu UMEMOTO { 2249426aedfSHajimu UMEMOTO struct ip ip; 2259426aedfSHajimu UMEMOTO struct gif_softc *sc; 2269426aedfSHajimu UMEMOTO struct ifnet *ifp; 2279426aedfSHajimu UMEMOTO 2289426aedfSHajimu UMEMOTO /* sanity check done in caller */ 2299426aedfSHajimu UMEMOTO sc = (struct gif_softc *)arg; 2300b9f5f8aSAndrey V. Elsukov GIF_RLOCK_ASSERT(sc); 2319426aedfSHajimu UMEMOTO 2329426aedfSHajimu UMEMOTO m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); 2339426aedfSHajimu UMEMOTO ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL; 2340b9f5f8aSAndrey V. Elsukov return (gif_validate4(&ip, sc, ifp)); 2359426aedfSHajimu UMEMOTO } 2369426aedfSHajimu UMEMOTO 2379426aedfSHajimu UMEMOTO int 238f2565d68SRobert Watson in_gif_attach(struct gif_softc *sc) 2399426aedfSHajimu UMEMOTO { 2400b9f5f8aSAndrey V. Elsukov 2410b9f5f8aSAndrey V. Elsukov KASSERT(sc->gif_ecookie == NULL, ("gif_ecookie isn't NULL")); 2420b9f5f8aSAndrey V. Elsukov sc->gif_ecookie = encap_attach_func(AF_INET, -1, gif_encapcheck, 2439426aedfSHajimu UMEMOTO &in_gif_protosw, sc); 2440b9f5f8aSAndrey V. Elsukov if (sc->gif_ecookie == NULL) 2450b9f5f8aSAndrey V. Elsukov return (EEXIST); 2460b9f5f8aSAndrey V. Elsukov return (0); 2479426aedfSHajimu UMEMOTO } 248