Home | History | Annotate | Line # | Download | only in netinet6
      1 /*	$NetBSD: in6_gif.c,v 1.96 2022/12/07 08:30:15 knakahara Exp $	*/
      2 /*	$KAME: in6_gif.c,v 1.62 2001/07/29 04:27:25 itojun Exp $	*/
      3 
      4 /*
      5  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. Neither the name of the project nor the names of its contributors
     17  *    may be used to endorse or promote products derived from this software
     18  *    without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
     21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
     24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     30  * SUCH DAMAGE.
     31  */
     32 
     33 #include <sys/cdefs.h>
     34 __KERNEL_RCSID(0, "$NetBSD: in6_gif.c,v 1.96 2022/12/07 08:30:15 knakahara Exp $");
     35 
     36 #ifdef _KERNEL_OPT
     37 #include "opt_inet.h"
     38 #endif
     39 
     40 #include <sys/param.h>
     41 #include <sys/systm.h>
     42 #include <sys/socket.h>
     43 #include <sys/sockio.h>
     44 #include <sys/mbuf.h>
     45 #include <sys/errno.h>
     46 #include <sys/ioctl.h>
     47 #include <sys/queue.h>
     48 #include <sys/syslog.h>
     49 #include <sys/kernel.h>
     50 
     51 #include <net/if.h>
     52 #include <net/route.h>
     53 
     54 #include <netinet/in.h>
     55 #include <netinet/in_systm.h>
     56 #ifdef INET
     57 #include <netinet/ip.h>
     58 #endif
     59 #include <netinet/ip_encap.h>
     60 #ifdef INET6
     61 #include <netinet/ip6.h>
     62 #include <netinet6/ip6_var.h>
     63 #include <netinet6/ip6_private.h>
     64 #include <netinet6/in6_gif.h>
     65 #include <netinet6/in6_var.h>
     66 #endif
     67 #include <netinet6/ip6protosw.h> /* for struct ip6ctlparam */
     68 #include <netinet/ip_ecn.h>
     69 
     70 #include <net/if_gif.h>
     71 
     72 static int gif_validate6(const struct ip6_hdr *, struct gif_variant *,
     73 	struct ifnet *);
     74 
     75 int	ip6_gif_hlim = GIF_HLIM;
     76 int	ip6_gif_pmtu = 0;
     77 
     78 static const struct encapsw in6_gif_encapsw;
     79 
     80 /*
     81  * family - family of the packet to be encapsulate.
     82  */
     83 
     84 static int
     85 in6_gif_output(struct gif_variant *var, int family, struct mbuf *m)
     86 {
     87 	struct rtentry *rt;
     88 	struct gif_softc *sc;
     89 	struct sockaddr_in6 *sin6_src;
     90 	struct sockaddr_in6 *sin6_dst;
     91 	struct ifnet *ifp;
     92 	struct ip6_hdr *ip6;
     93 	struct route *ro_pc;
     94 	kmutex_t *lock_pc;
     95 	int proto, error;
     96 	u_int8_t itos, otos;
     97 
     98 	KASSERT(gif_heldref_variant(var));
     99 
    100 	sin6_src = satosin6(var->gv_psrc);
    101 	sin6_dst = satosin6(var->gv_pdst);
    102 	ifp = &var->gv_softc->gif_if;
    103 
    104 	if (sin6_src == NULL || sin6_dst == NULL ||
    105 	    sin6_src->sin6_family != AF_INET6 ||
    106 	    sin6_dst->sin6_family != AF_INET6) {
    107 		m_freem(m);
    108 		return EAFNOSUPPORT;
    109 	}
    110 
    111 	switch (family) {
    112 #ifdef INET
    113 	case AF_INET:
    114 	    {
    115 		struct ip *ip;
    116 
    117 		proto = IPPROTO_IPV4;
    118 		if (m->m_len < sizeof(*ip)) {
    119 			m = m_pullup(m, sizeof(*ip));
    120 			if (!m)
    121 				return ENOBUFS;
    122 		}
    123 		ip = mtod(m, struct ip *);
    124 		itos = ip->ip_tos;
    125 		break;
    126 	    }
    127 #endif
    128 #ifdef INET6
    129 	case AF_INET6:
    130 	    {
    131 		proto = IPPROTO_IPV6;
    132 		if (m->m_len < sizeof(*ip6)) {
    133 			m = m_pullup(m, sizeof(*ip6));
    134 			if (!m)
    135 				return ENOBUFS;
    136 		}
    137 		ip6 = mtod(m, struct ip6_hdr *);
    138 		itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
    139 		break;
    140 	    }
    141 #endif
    142 	default:
    143 #ifdef DEBUG
    144 		printf("in6_gif_output: warning: unknown family %d passed\n",
    145 			family);
    146 #endif
    147 		m_freem(m);
    148 		return EAFNOSUPPORT;
    149 	}
    150 
    151 	/* prepend new IP header */
    152 	M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT);
    153 	if (m && m->m_len < sizeof(struct ip6_hdr))
    154 		m = m_pullup(m, sizeof(struct ip6_hdr));
    155 	if (m == NULL)
    156 		return ENOBUFS;
    157 
    158 	ip6 = mtod(m, struct ip6_hdr *);
    159 	ip6->ip6_flow	= 0;
    160 	ip6->ip6_vfc	&= ~IPV6_VERSION_MASK;
    161 	ip6->ip6_vfc	|= IPV6_VERSION;
    162 #if 0	/* ip6->ip6_plen will be filled by ip6_output */
    163 	ip6->ip6_plen	= htons((u_int16_t)m->m_pkthdr.len);
    164 #endif
    165 	ip6->ip6_nxt	= proto;
    166 	ip6->ip6_hlim	= ip6_gif_hlim;
    167 	ip6->ip6_src	= sin6_src->sin6_addr;
    168 	/* bidirectional configured tunnel mode */
    169 	if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))
    170 		ip6->ip6_dst = sin6_dst->sin6_addr;
    171 	else  {
    172 		m_freem(m);
    173 		return ENETUNREACH;
    174 	}
    175 	if (ifp->if_flags & IFF_LINK1)
    176 		ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);
    177 	else
    178 		ip_ecn_ingress(ECN_NOCARE, &otos, &itos);
    179 	ip6->ip6_flow &= ~ntohl(0xff00000);
    180 	ip6->ip6_flow |= htonl((u_int32_t)otos << 20);
    181 
    182 	sc = ifp->if_softc;
    183 	if_tunnel_get_ro(sc->gif_ro_percpu, &ro_pc, &lock_pc);
    184 	rt = rtcache_lookup(ro_pc, var->gv_pdst);
    185 	if (rt == NULL) {
    186 		if_tunnel_put_ro(sc->gif_ro_percpu, lock_pc);
    187 		m_freem(m);
    188 		return ENETUNREACH;
    189 	}
    190 
    191 	/* If the route constitutes infinite encapsulation, punt. */
    192 	if (rt->rt_ifp == ifp) {
    193 		rtcache_unref(rt, ro_pc);
    194 		rtcache_free(ro_pc);
    195 		if_tunnel_put_ro(sc->gif_ro_percpu, lock_pc);
    196 		m_freem(m);
    197 		return ENETUNREACH;	/* XXX */
    198 	}
    199 	rtcache_unref(rt, ro_pc);
    200 
    201 #ifdef IPV6_MINMTU
    202 	int flags;
    203 
    204 	/*
    205 	 * - GIF_PMTU_MINMTU
    206 	 *   Force fragmentation to minimum MTU to avoid path MTU discovery
    207 	 * - GIF_PMTU_OUTERMTU
    208 	 *   Trust outer MTU is large enough to send all packets
    209 	 *
    210 	 * It is too painful to ask for resend of inner packet, to achieve
    211 	 * path MTU discovery for encapsulated packets.
    212 	 *
    213 	 * See RFC4459.
    214 	 */
    215 	if (sc->gif_pmtu == GIF_PMTU_SYSDEFAULT) {
    216 		switch (ip6_gif_pmtu) {
    217 		case GIF_PMTU_MINMTU:
    218 			flags = IPV6_MINMTU;
    219 			break;
    220 		case GIF_PMTU_OUTERMTU:
    221 			flags = 0;
    222 			break;
    223 		default:
    224 #ifdef DEBUG
    225 			log(LOG_DEBUG, "%s: ignore unexpected ip6_gif_pmtu %d\n",
    226 			    __func__, ip6_gif_pmtu);
    227 #endif
    228 			flags = IPV6_MINMTU;
    229 			break;
    230 		}
    231 	} else {
    232 		switch (sc->gif_pmtu) {
    233 		case GIF_PMTU_MINMTU:
    234 			flags = IPV6_MINMTU;
    235 			break;
    236 		case GIF_PMTU_OUTERMTU:
    237 			flags = 0;
    238 			break;
    239 		default:
    240 #ifdef DEBUG
    241 			log(LOG_DEBUG, "%s: ignore unexpected gif_pmtu of %s %d\n",
    242 			    __func__, ifp->if_xname, sc->gif_pmtu);
    243 #endif
    244 			flags = IPV6_MINMTU;
    245 			break;
    246 		}
    247 	}
    248 
    249 	error = ip6_output(m, 0, ro_pc, flags, NULL, NULL, NULL);
    250 #else
    251 	error = ip6_output(m, 0, ro_pc, 0, NULL, NULL, NULL);
    252 #endif
    253 	if_tunnel_put_ro(sc->gif_ro_percpu, lock_pc);
    254 	return (error);
    255 }
    256 
    257 int
    258 in6_gif_input(struct mbuf **mp, int *offp, int proto, void *eparg)
    259 {
    260 	struct mbuf *m = *mp;
    261 	struct gif_softc *sc = eparg;
    262 	struct ifnet *gifp;
    263 	struct ip6_hdr *ip6;
    264 	int af = 0;
    265 	u_int32_t otos;
    266 
    267 	KASSERT(sc != NULL);
    268 
    269 	ip6 = mtod(m, struct ip6_hdr *);
    270 
    271 	gifp = &sc->gif_if;
    272 	if ((gifp->if_flags & IFF_UP) == 0) {
    273 		m_freem(m);
    274 		IP6_STATINC(IP6_STAT_NOGIF);
    275 		return IPPROTO_DONE;
    276 	}
    277 #ifndef GIF_ENCAPCHECK
    278 	struct psref psref_var;
    279 	struct gif_variant *var = gif_getref_variant(sc, &psref_var);
    280 	/* other CPU do delete_tunnel */
    281 	if (var->gv_psrc == NULL || var->gv_pdst == NULL) {
    282 		gif_putref_variant(var, &psref_var);
    283 		m_freem(m);
    284 		IP6_STATINC(IP6_STAT_NOGIF);
    285 		return IPPROTO_DONE;
    286 	}
    287 
    288 	struct psref psref;
    289 	struct ifnet *rcvif = m_get_rcvif_psref(m, &psref);
    290 	if (rcvif == NULL || !gif_validate6(ip6, var, rcvif)) {
    291 		m_put_rcvif_psref(rcvif, &psref);
    292 		gif_putref_variant(var, &psref_var);
    293 		m_freem(m);
    294 		IP6_STATINC(IP6_STAT_NOGIF);
    295 		return IPPROTO_DONE;
    296 	}
    297 	m_put_rcvif_psref(rcvif, &psref);
    298 	gif_putref_variant(var, &psref_var);
    299 #endif
    300 
    301 	otos = ip6->ip6_flow;
    302 	m_adj(m, *offp);
    303 
    304 	switch (proto) {
    305 #ifdef INET
    306 	case IPPROTO_IPV4:
    307 	    {
    308 		struct ip *ip;
    309 		u_int8_t otos8;
    310 		af = AF_INET;
    311 		otos8 = (ntohl(otos) >> 20) & 0xff;
    312 		if (m->m_len < sizeof(*ip)) {
    313 			m = m_pullup(m, sizeof(*ip));
    314 			if (!m)
    315 				return IPPROTO_DONE;
    316 		}
    317 		ip = mtod(m, struct ip *);
    318 		if (gifp->if_flags & IFF_LINK1)
    319 			ip_ecn_egress(ECN_ALLOWED, &otos8, &ip->ip_tos);
    320 		else
    321 			ip_ecn_egress(ECN_NOCARE, &otos8, &ip->ip_tos);
    322 		break;
    323 	    }
    324 #endif /* INET */
    325 #ifdef INET6
    326 	case IPPROTO_IPV6:
    327 	    {
    328 		struct ip6_hdr *ip6x;
    329 		af = AF_INET6;
    330 		if (m->m_len < sizeof(*ip6x)) {
    331 			m = m_pullup(m, sizeof(*ip6x));
    332 			if (!m)
    333 				return IPPROTO_DONE;
    334 		}
    335 		ip6x = mtod(m, struct ip6_hdr *);
    336 		if (gifp->if_flags & IFF_LINK1)
    337 			ip6_ecn_egress(ECN_ALLOWED, &otos, &ip6x->ip6_flow);
    338 		else
    339 			ip6_ecn_egress(ECN_NOCARE, &otos, &ip6x->ip6_flow);
    340 		break;
    341 	    }
    342 #endif
    343 	default:
    344 		IP6_STATINC(IP6_STAT_NOGIF);
    345 		m_freem(m);
    346 		return IPPROTO_DONE;
    347 	}
    348 
    349 	gif_input(m, af, gifp);
    350 	return IPPROTO_DONE;
    351 }
    352 
    353 /*
    354  * validate outer address.
    355  */
    356 static int
    357 gif_validate6(const struct ip6_hdr *ip6, struct gif_variant *var,
    358 	struct ifnet *ifp)
    359 {
    360 	const struct sockaddr_in6 *src, *dst;
    361 	int ret;
    362 
    363 	src = satosin6(var->gv_psrc);
    364 	dst = satosin6(var->gv_pdst);
    365 
    366 	ret = in6_tunnel_validate(ip6, &src->sin6_addr, &dst->sin6_addr);
    367 	if (ret == 0)
    368 		return 0;
    369 
    370 	/* ingress filters on outer source */
    371 	if ((var->gv_softc->gif_if.if_flags & IFF_LINK2) == 0 && ifp) {
    372 		union {
    373 			struct sockaddr sa;
    374 			struct sockaddr_in6 sin6;
    375 		} u;
    376 		struct rtentry *rt;
    377 
    378 		/* XXX scopeid */
    379 		sockaddr_in6_init(&u.sin6, &ip6->ip6_src, 0, 0, 0);
    380 		rt = rtalloc1(&u.sa, 0);
    381 		if (rt == NULL || rt->rt_ifp != ifp) {
    382 #if 0
    383 			char ip6buf[INET6_ADDRSTRLEN];
    384 			log(LOG_WARNING, "%s: packet from %s dropped "
    385 			    "due to ingress filter\n",
    386 			    if_name(&var->gv_softc->gif_if),
    387 			    IN6_PRINT(ip6buf, &u.sin6.sin6_addr));
    388 #endif
    389 			if (rt != NULL)
    390 				rt_unref(rt);
    391 			return 0;
    392 		}
    393 		rt_unref(rt);
    394 	}
    395 
    396 	return ret;
    397 }
    398 
    399 #ifdef GIF_ENCAPCHECK
    400 /*
    401  * we know that we are in IFF_UP, outer address available, and outer family
    402  * matched the physical addr family.  see gif_encapcheck().
    403  */
    404 int
    405 gif_encapcheck6(struct mbuf *m, int off, int proto, struct gif_variant *var)
    406 {
    407 	struct ip6_hdr ip6;
    408 	struct ifnet *ifp = NULL;
    409 	int r;
    410 	struct psref psref;
    411 
    412 	m_copydata(m, 0, sizeof(ip6), (void *)&ip6);
    413 	if ((m->m_flags & M_PKTHDR) != 0)
    414 		ifp = m_get_rcvif_psref(m, &psref);
    415 
    416 	r = gif_validate6(&ip6, var, ifp);
    417 
    418 	m_put_rcvif_psref(ifp, &psref);
    419 	return r;
    420 }
    421 #endif
    422 
    423 int
    424 in6_gif_attach(struct gif_variant *var)
    425 {
    426 #ifndef GIF_ENCAPCHECK
    427 	struct sockaddr_in6 mask6;
    428 
    429 	memset(&mask6, 0, sizeof(mask6));
    430 	mask6.sin6_len = sizeof(struct sockaddr_in6);
    431 	mask6.sin6_addr.s6_addr32[0] = mask6.sin6_addr.s6_addr32[1] =
    432 	    mask6.sin6_addr.s6_addr32[2] = mask6.sin6_addr.s6_addr32[3] = ~0;
    433 
    434 	if (!var->gv_psrc || !var->gv_pdst)
    435 		return EINVAL;
    436 
    437 	var->gv_encap_cookie6 = encap_attach_addr(AF_INET6, -1, var->gv_psrc,
    438 	    var->gv_pdst, NULL, &in6_gif_encapsw, var->gv_softc);
    439 #else
    440 	var->gv_encap_cookie6 = encap_attach_addr(AF_INET6, -1, var->gv_psrc,
    441 	    var->gv_pdst, gif_encapcheck, &in6_gif_encapsw, var->gv_softc);
    442 #endif
    443 	if (var->gv_encap_cookie6 == NULL)
    444 		return EEXIST;
    445 
    446 	var->gv_output = in6_gif_output;
    447 	return 0;
    448 }
    449 
    450 int
    451 in6_gif_detach(struct gif_variant *var)
    452 {
    453 	int error;
    454 	struct gif_softc *sc = var->gv_softc;
    455 
    456 	error = encap_detach(var->gv_encap_cookie6);
    457 	if (error == 0)
    458 		var->gv_encap_cookie6 = NULL;
    459 
    460 	if_tunnel_ro_percpu_rtcache_free(sc->gif_ro_percpu);
    461 
    462 	return error;
    463 }
    464 
    465 void *
    466 in6_gif_ctlinput(int cmd, const struct sockaddr *sa, void *d, void *eparg)
    467 {
    468 	struct gif_softc *sc = eparg;
    469 	struct gif_variant *var;
    470 	struct ip6ctlparam *ip6cp = NULL;
    471 	struct ip6_hdr *ip6;
    472 	const struct sockaddr_in6 *dst6;
    473 	struct route *ro_pc;
    474 	kmutex_t *lock_pc;
    475 	struct psref psref;
    476 
    477 	if (sa->sa_family != AF_INET6 ||
    478 	    sa->sa_len != sizeof(struct sockaddr_in6))
    479 		return NULL;
    480 
    481 	if ((unsigned)cmd >= PRC_NCMDS)
    482 		return NULL;
    483 	if (cmd == PRC_HOSTDEAD)
    484 		d = NULL;
    485 	else if (inet6ctlerrmap[cmd] == 0)
    486 		return NULL;
    487 
    488 	/* if the parameter is from icmp6, decode it. */
    489 	if (d != NULL) {
    490 		ip6cp = (struct ip6ctlparam *)d;
    491 		ip6 = ip6cp->ip6c_ip6;
    492 	} else {
    493 		ip6 = NULL;
    494 	}
    495 
    496 	if (!ip6)
    497 		return NULL;
    498 
    499 	var = gif_getref_variant(sc, &psref);
    500 	if (var->gv_psrc == NULL || var->gv_pdst == NULL) {
    501 		gif_putref_variant(var, &psref);
    502 		return NULL;
    503 	}
    504 	if (var->gv_psrc->sa_family != AF_INET6) {
    505 		gif_putref_variant(var, &psref);
    506 		return NULL;
    507 	}
    508 	gif_putref_variant(var, &psref);
    509 
    510 	if_tunnel_get_ro(sc->gif_ro_percpu, &ro_pc, &lock_pc);
    511 	dst6 = satocsin6(rtcache_getdst(ro_pc));
    512 	/* XXX scope */
    513 	if (dst6 == NULL)
    514 		;
    515 	else if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst6->sin6_addr))
    516 		rtcache_free(ro_pc);
    517 
    518 	if_tunnel_put_ro(sc->gif_ro_percpu, lock_pc);
    519 	return NULL;
    520 }
    521 
    522 ENCAP_PR_WRAP_CTLINPUT(in6_gif_ctlinput)
    523 #define	in6_gif_ctlinput	in6_gif_ctlinput_wrapper
    524 
    525 static const struct encapsw in6_gif_encapsw = {
    526 	.encapsw6 = {
    527 		.pr_input	= in6_gif_input,
    528 		.pr_ctlinput	= in6_gif_ctlinput,
    529 	}
    530 };
    531