xref: /netbsd-src/sys/netinet6/in6_gif.c (revision a24efa7dea9f1f56c3bdb15a927d3516792ace1c)
1 /*	$NetBSD: in6_gif.c,v 1.73 2016/02/29 01:29: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.73 2016/02/29 01:29: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 #include <net/net_osdep.h>
73 
74 static int gif_validate6(const struct ip6_hdr *, struct gif_softc *,
75 	struct ifnet *);
76 
77 int	ip6_gif_hlim = GIF_HLIM;
78 
79 static const struct encapsw in6_gif_encapsw;
80 
81 /*
82  * family - family of the packet to be encapsulate.
83  */
84 
85 int
86 in6_gif_output(struct ifnet *ifp, int family, struct mbuf *m)
87 {
88 	struct rtentry *rt;
89 	struct gif_softc *sc = ifp->if_softc;
90 	struct sockaddr_in6 *sin6_src = satosin6(sc->gif_psrc);
91 	struct sockaddr_in6 *sin6_dst = satosin6(sc->gif_pdst);
92 	struct ip6_hdr *ip6;
93 	int proto, error;
94 	u_int8_t itos, otos;
95 	union {
96 		struct sockaddr		dst;
97 		struct sockaddr_in6	dst6;
98 	} u;
99 
100 	if (sin6_src == NULL || sin6_dst == NULL ||
101 	    sin6_src->sin6_family != AF_INET6 ||
102 	    sin6_dst->sin6_family != AF_INET6) {
103 		m_freem(m);
104 		return EAFNOSUPPORT;
105 	}
106 
107 	switch (family) {
108 #ifdef INET
109 	case AF_INET:
110 	    {
111 		struct ip *ip;
112 
113 		proto = IPPROTO_IPV4;
114 		if (m->m_len < sizeof(*ip)) {
115 			m = m_pullup(m, sizeof(*ip));
116 			if (!m)
117 				return ENOBUFS;
118 		}
119 		ip = mtod(m, struct ip *);
120 		itos = ip->ip_tos;
121 		break;
122 	    }
123 #endif
124 #ifdef INET6
125 	case AF_INET6:
126 	    {
127 		proto = IPPROTO_IPV6;
128 		if (m->m_len < sizeof(*ip6)) {
129 			m = m_pullup(m, sizeof(*ip6));
130 			if (!m)
131 				return ENOBUFS;
132 		}
133 		ip6 = mtod(m, struct ip6_hdr *);
134 		itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
135 		break;
136 	    }
137 #endif
138 	default:
139 #ifdef DEBUG
140 		printf("in6_gif_output: warning: unknown family %d passed\n",
141 			family);
142 #endif
143 		m_freem(m);
144 		return EAFNOSUPPORT;
145 	}
146 
147 	/* prepend new IP header */
148 	M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT);
149 	if (m && m->m_len < sizeof(struct ip6_hdr))
150 		m = m_pullup(m, sizeof(struct ip6_hdr));
151 	if (m == NULL)
152 		return ENOBUFS;
153 
154 	ip6 = mtod(m, struct ip6_hdr *);
155 	ip6->ip6_flow	= 0;
156 	ip6->ip6_vfc	&= ~IPV6_VERSION_MASK;
157 	ip6->ip6_vfc	|= IPV6_VERSION;
158 #if 0	/* ip6->ip6_plen will be filled by ip6_output */
159 	ip6->ip6_plen	= htons((u_int16_t)m->m_pkthdr.len);
160 #endif
161 	ip6->ip6_nxt	= proto;
162 	ip6->ip6_hlim	= ip6_gif_hlim;
163 	ip6->ip6_src	= sin6_src->sin6_addr;
164 	/* bidirectional configured tunnel mode */
165 	if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))
166 		ip6->ip6_dst = sin6_dst->sin6_addr;
167 	else  {
168 		m_freem(m);
169 		return ENETUNREACH;
170 	}
171 	if (ifp->if_flags & IFF_LINK1)
172 		ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);
173 	else
174 		ip_ecn_ingress(ECN_NOCARE, &otos, &itos);
175 	ip6->ip6_flow &= ~ntohl(0xff00000);
176 	ip6->ip6_flow |= htonl((u_int32_t)otos << 20);
177 
178 	sockaddr_in6_init(&u.dst6, &sin6_dst->sin6_addr, 0, 0, 0);
179 	if ((rt = rtcache_lookup(&sc->gif_ro, &u.dst)) == NULL) {
180 		m_freem(m);
181 		return ENETUNREACH;
182 	}
183 
184 	/* If the route constitutes infinite encapsulation, punt. */
185 	if (rt->rt_ifp == ifp) {
186 		rtcache_free(&sc->gif_ro);
187 		m_freem(m);
188 		return ENETUNREACH;	/* XXX */
189 	}
190 
191 #ifdef IPV6_MINMTU
192 	/*
193 	 * force fragmentation to minimum MTU, to avoid path MTU discovery.
194 	 * it is too painful to ask for resend of inner packet, to achieve
195 	 * path MTU discovery for encapsulated packets.
196 	 */
197 	error = ip6_output(m, 0, &sc->gif_ro, IPV6_MINMTU, NULL, NULL, NULL);
198 #else
199 	error = ip6_output(m, 0, &sc->gif_ro, 0, NULL, NULL, NULL);
200 #endif
201 
202 	return (error);
203 }
204 
205 int
206 in6_gif_input(struct mbuf **mp, int *offp, int proto)
207 {
208 	struct mbuf *m = *mp;
209 	struct ifnet *gifp = NULL;
210 	struct ip6_hdr *ip6;
211 	int af = 0;
212 	u_int32_t otos;
213 
214 	ip6 = mtod(m, struct ip6_hdr *);
215 
216 	gifp = (struct ifnet *)encap_getarg(m);
217 
218 	if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
219 		m_freem(m);
220 		IP6_STATINC(IP6_STAT_NOGIF);
221 		return IPPROTO_DONE;
222 	}
223 #ifndef GIF_ENCAPCHECK
224 	struct gif_softc *sc = (struct gif_softc *)gifp->if_softc;
225 	/* other CPU do delete_tunnel */
226 	if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
227 		m_freem(m);
228 		IP6_STATINC(IP6_STAT_NOGIF);
229 		return IPPROTO_DONE;
230 	}
231 
232 	if (!gif_validate6(ip6, sc, m->m_pkthdr.rcvif)) {
233 		m_freem(m);
234 		IP6_STATINC(IP6_STAT_NOGIF);
235 		return IPPROTO_DONE;
236 	}
237 #endif
238 
239 	otos = ip6->ip6_flow;
240 	m_adj(m, *offp);
241 
242 	switch (proto) {
243 #ifdef INET
244 	case IPPROTO_IPV4:
245 	    {
246 		struct ip *ip;
247 		u_int8_t otos8;
248 		af = AF_INET;
249 		otos8 = (ntohl(otos) >> 20) & 0xff;
250 		if (m->m_len < sizeof(*ip)) {
251 			m = m_pullup(m, sizeof(*ip));
252 			if (!m)
253 				return IPPROTO_DONE;
254 		}
255 		ip = mtod(m, struct ip *);
256 		if (gifp->if_flags & IFF_LINK1)
257 			ip_ecn_egress(ECN_ALLOWED, &otos8, &ip->ip_tos);
258 		else
259 			ip_ecn_egress(ECN_NOCARE, &otos8, &ip->ip_tos);
260 		break;
261 	    }
262 #endif /* INET */
263 #ifdef INET6
264 	case IPPROTO_IPV6:
265 	    {
266 		struct ip6_hdr *ip6x;
267 		af = AF_INET6;
268 		if (m->m_len < sizeof(*ip6x)) {
269 			m = m_pullup(m, sizeof(*ip6x));
270 			if (!m)
271 				return IPPROTO_DONE;
272 		}
273 		ip6x = mtod(m, struct ip6_hdr *);
274 		if (gifp->if_flags & IFF_LINK1)
275 			ip6_ecn_egress(ECN_ALLOWED, &otos, &ip6x->ip6_flow);
276 		else
277 			ip6_ecn_egress(ECN_NOCARE, &otos, &ip6x->ip6_flow);
278 		break;
279 	    }
280 #endif
281 	default:
282 		IP6_STATINC(IP6_STAT_NOGIF);
283 		m_freem(m);
284 		return IPPROTO_DONE;
285 	}
286 
287 	gif_input(m, af, gifp);
288 	return IPPROTO_DONE;
289 }
290 
291 /*
292  * validate outer address.
293  */
294 static int
295 gif_validate6(const struct ip6_hdr *ip6, struct gif_softc *sc,
296 	struct ifnet *ifp)
297 {
298 	const struct sockaddr_in6 *src, *dst;
299 
300 	src = satosin6(sc->gif_psrc);
301 	dst = satosin6(sc->gif_pdst);
302 
303 	/* check for address match */
304 	if (!IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6->ip6_dst) ||
305 	    !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_src))
306 		return 0;
307 
308 	/* martian filters on outer source - done in ip6_input */
309 
310 	/* ingress filters on outer source */
311 	if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && ifp) {
312 		union {
313 			struct sockaddr sa;
314 			struct sockaddr_in6 sin6;
315 		} u;
316 		struct rtentry *rt;
317 
318 		/* XXX scopeid */
319 		sockaddr_in6_init(&u.sin6, &ip6->ip6_src, 0, 0, 0);
320 		rt = rtalloc1(&u.sa, 0);
321 		if (rt == NULL || rt->rt_ifp != ifp) {
322 #if 0
323 			log(LOG_WARNING, "%s: packet from %s dropped "
324 			    "due to ingress filter\n", if_name(&sc->gif_if),
325 			    ip6_sprintf(&u.sin6.sin6_addr));
326 #endif
327 			if (rt != NULL)
328 				rtfree(rt);
329 			return 0;
330 		}
331 		rtfree(rt);
332 	}
333 
334 	return 128 * 2;
335 }
336 
337 #ifdef GIF_ENCAPCHECK
338 /*
339  * we know that we are in IFF_UP, outer address available, and outer family
340  * matched the physical addr family.  see gif_encapcheck().
341  */
342 int
343 gif_encapcheck6(struct mbuf *m, int off, int proto, void *arg)
344 {
345 	struct ip6_hdr ip6;
346 	struct gif_softc *sc;
347 	struct ifnet *ifp;
348 
349 	/* sanity check done in caller */
350 	sc = arg;
351 
352 	m_copydata(m, 0, sizeof(ip6), (void *)&ip6);
353 	ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL;
354 
355 	return gif_validate6(&ip6, sc, ifp);
356 }
357 #endif
358 
359 int
360 in6_gif_attach(struct gif_softc *sc)
361 {
362 #ifndef GIF_ENCAPCHECK
363 	struct sockaddr_in6 mask6;
364 
365 	memset(&mask6, 0, sizeof(mask6));
366 	mask6.sin6_len = sizeof(struct sockaddr_in6);
367 	mask6.sin6_addr.s6_addr32[0] = mask6.sin6_addr.s6_addr32[1] =
368 	    mask6.sin6_addr.s6_addr32[2] = mask6.sin6_addr.s6_addr32[3] = ~0;
369 
370 	if (!sc->gif_psrc || !sc->gif_pdst)
371 		return EINVAL;
372 	sc->encap_cookie6 = encap_attach(AF_INET6, -1, sc->gif_psrc,
373 	    (struct sockaddr *)&mask6, sc->gif_pdst, (struct sockaddr *)&mask6,
374 	    (const void *)&in6_gif_encapsw, sc);
375 #else
376 	sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, gif_encapcheck,
377 	    &in6_gif_encapsw, sc);
378 #endif
379 	if (sc->encap_cookie6 == NULL)
380 		return EEXIST;
381 	return 0;
382 }
383 
384 int
385 in6_gif_detach(struct gif_softc *sc)
386 {
387 	int error;
388 
389 	error = encap_detach(sc->encap_cookie6);
390 	if (error == 0)
391 		sc->encap_cookie6 = NULL;
392 
393 	rtcache_free(&sc->gif_ro);
394 
395 	return error;
396 }
397 
398 void *
399 in6_gif_ctlinput(int cmd, const struct sockaddr *sa, void *d, void *eparg)
400 {
401 	struct gif_softc *sc = eparg;
402 	struct ip6ctlparam *ip6cp = NULL;
403 	struct ip6_hdr *ip6;
404 	const struct sockaddr_in6 *dst6;
405 
406 	if (sa->sa_family != AF_INET6 ||
407 	    sa->sa_len != sizeof(struct sockaddr_in6))
408 		return NULL;
409 
410 	if ((unsigned)cmd >= PRC_NCMDS)
411 		return NULL;
412 	if (cmd == PRC_HOSTDEAD)
413 		d = NULL;
414 	else if (inet6ctlerrmap[cmd] == 0)
415 		return NULL;
416 
417 	/* if the parameter is from icmp6, decode it. */
418 	if (d != NULL) {
419 		ip6cp = (struct ip6ctlparam *)d;
420 		ip6 = ip6cp->ip6c_ip6;
421 	} else {
422 		ip6 = NULL;
423 	}
424 
425 	if (!ip6)
426 		return NULL;
427 
428 	if ((sc->gif_if.if_flags & IFF_RUNNING) == 0)
429 		return NULL;
430 	if (sc->gif_psrc->sa_family != AF_INET6)
431 		return NULL;
432 
433 	dst6 = satocsin6(rtcache_getdst(&sc->gif_ro));
434 	/* XXX scope */
435 	if (dst6 == NULL)
436 		;
437 	else if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst6->sin6_addr))
438 		rtcache_free(&sc->gif_ro);
439 
440 	return NULL;
441 }
442 
443 ENCAP_PR_WRAP_CTLINPUT(in6_gif_ctlinput)
444 #define	in6_gif_ctlinput	in6_gif_ctlinput_wrapper
445 
446 static const struct encapsw in6_gif_encapsw = {
447 	.encapsw6 = {
448 		.pr_input	= in6_gif_input,
449 		.pr_ctlinput	= in6_gif_ctlinput,
450 	}
451 };
452