xref: /netbsd/sys/netinet6/in6_gif.c (revision 38ddb41f)
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
in6_gif_output(struct gif_variant * var,int family,struct mbuf * m)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
in6_gif_input(struct mbuf ** mp,int * offp,int proto,void * eparg)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
gif_validate6(const struct ip6_hdr * ip6,struct gif_variant * var,struct ifnet * ifp)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
gif_encapcheck6(struct mbuf * m,int off,int proto,struct gif_variant * var)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
in6_gif_attach(struct gif_variant * var)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
in6_gif_detach(struct gif_variant * var)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 *
in6_gif_ctlinput(int cmd,const struct sockaddr * sa,void * d,void * eparg)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