xref: /freebsd/sys/netinet/in_gif.c (revision 721351876cd4d3a8a700f62d2061331fa951a488)
1 /*	$KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $	*/
2 
3 /*-
4  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the project nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 
35 #include "opt_mrouting.h"
36 #include "opt_inet.h"
37 #include "opt_inet6.h"
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/socket.h>
42 #include <sys/sockio.h>
43 #include <sys/mbuf.h>
44 #include <sys/errno.h>
45 #include <sys/kernel.h>
46 #include <sys/sysctl.h>
47 #include <sys/protosw.h>
48 
49 #include <sys/malloc.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 #include <netinet/ip.h>
57 #include <netinet/ip_var.h>
58 #include <netinet/in_gif.h>
59 #include <netinet/in_var.h>
60 #include <netinet/ip_encap.h>
61 #include <netinet/ip_ecn.h>
62 
63 #ifdef INET6
64 #include <netinet/ip6.h>
65 #endif
66 
67 #ifdef MROUTING
68 #include <netinet/ip_mroute.h>
69 #endif /* MROUTING */
70 
71 #include <net/if_gif.h>
72 
73 static int gif_validate4(const struct ip *, struct gif_softc *,
74 	struct ifnet *);
75 
76 extern  struct domain inetdomain;
77 struct protosw in_gif_protosw = {
78 	.pr_type =		SOCK_RAW,
79 	.pr_domain =		&inetdomain,
80 	.pr_protocol =		0/* IPPROTO_IPV[46] */,
81 	.pr_flags =		PR_ATOMIC|PR_ADDR,
82 	.pr_input =		in_gif_input,
83 	.pr_output =		(pr_output_t*)rip_output,
84 	.pr_ctloutput =		rip_ctloutput,
85 	.pr_usrreqs =		&rip_usrreqs
86 };
87 
88 static int ip_gif_ttl = GIF_TTL;
89 SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW,
90 	&ip_gif_ttl,	0, "");
91 
92 int
93 in_gif_output(struct ifnet *ifp, int family, struct mbuf *m)
94 {
95 	struct gif_softc *sc = ifp->if_softc;
96 	struct sockaddr_in *dst = (struct sockaddr_in *)&sc->gif_ro.ro_dst;
97 	struct sockaddr_in *sin_src = (struct sockaddr_in *)sc->gif_psrc;
98 	struct sockaddr_in *sin_dst = (struct sockaddr_in *)sc->gif_pdst;
99 	struct ip iphdr;	/* capsule IP header, host byte ordered */
100 	struct etherip_header eiphdr;
101 	int proto, error;
102 	u_int8_t tos;
103 
104 	GIF_LOCK_ASSERT(sc);
105 
106 	if (sin_src == NULL || sin_dst == NULL ||
107 	    sin_src->sin_family != AF_INET ||
108 	    sin_dst->sin_family != AF_INET) {
109 		m_freem(m);
110 		return EAFNOSUPPORT;
111 	}
112 
113 	switch (family) {
114 #ifdef INET
115 	case AF_INET:
116 	    {
117 		struct ip *ip;
118 
119 		proto = IPPROTO_IPV4;
120 		if (m->m_len < sizeof(*ip)) {
121 			m = m_pullup(m, sizeof(*ip));
122 			if (!m)
123 				return ENOBUFS;
124 		}
125 		ip = mtod(m, struct ip *);
126 		tos = ip->ip_tos;
127 		break;
128 	    }
129 #endif /* INET */
130 #ifdef INET6
131 	case AF_INET6:
132 	    {
133 		struct ip6_hdr *ip6;
134 		proto = IPPROTO_IPV6;
135 		if (m->m_len < sizeof(*ip6)) {
136 			m = m_pullup(m, sizeof(*ip6));
137 			if (!m)
138 				return ENOBUFS;
139 		}
140 		ip6 = mtod(m, struct ip6_hdr *);
141 		tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
142 		break;
143 	    }
144 #endif /* INET6 */
145 	case AF_LINK:
146  		proto = IPPROTO_ETHERIP;
147  		eiphdr.eip_ver = ETHERIP_VERSION & ETHERIP_VER_VERS_MASK;
148  		eiphdr.eip_pad = 0;
149  		/* prepend Ethernet-in-IP header */
150  		M_PREPEND(m, sizeof(struct etherip_header), M_DONTWAIT);
151  		if (m && m->m_len < sizeof(struct etherip_header))
152  			m = m_pullup(m, sizeof(struct etherip_header));
153  		if (m == NULL)
154  			return ENOBUFS;
155  		bcopy(&eiphdr, mtod(m, struct etherip_header *),
156 		    sizeof(struct etherip_header));
157 		break;
158 
159 	default:
160 #ifdef DEBUG
161 		printf("in_gif_output: warning: unknown family %d passed\n",
162 			family);
163 #endif
164 		m_freem(m);
165 		return EAFNOSUPPORT;
166 	}
167 
168 	bzero(&iphdr, sizeof(iphdr));
169 	iphdr.ip_src = sin_src->sin_addr;
170 	/* bidirectional configured tunnel mode */
171 	if (sin_dst->sin_addr.s_addr != INADDR_ANY)
172 		iphdr.ip_dst = sin_dst->sin_addr;
173 	else {
174 		m_freem(m);
175 		return ENETUNREACH;
176 	}
177 	iphdr.ip_p = proto;
178 	/* version will be set in ip_output() */
179 	iphdr.ip_ttl = ip_gif_ttl;
180 	iphdr.ip_len = m->m_pkthdr.len + sizeof(struct ip);
181 	ip_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED : ECN_NOCARE,
182 		       &iphdr.ip_tos, &tos);
183 
184 	/* prepend new IP header */
185 	M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
186 	if (m && m->m_len < sizeof(struct ip))
187 		m = m_pullup(m, sizeof(struct ip));
188 	if (m == NULL) {
189 		printf("ENOBUFS in in_gif_output %d\n", __LINE__);
190 		return ENOBUFS;
191 	}
192 	bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip));
193 
194 	M_SETFIB(m, sc->gif_fibnum);
195 
196 	if (dst->sin_family != sin_dst->sin_family ||
197 	    dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr) {
198 		/* cache route doesn't match */
199 		bzero(dst, sizeof(*dst));
200 		dst->sin_family = sin_dst->sin_family;
201 		dst->sin_len = sizeof(struct sockaddr_in);
202 		dst->sin_addr = sin_dst->sin_addr;
203 		if (sc->gif_ro.ro_rt) {
204 			RTFREE(sc->gif_ro.ro_rt);
205 			sc->gif_ro.ro_rt = NULL;
206 		}
207 #if 0
208 		GIF2IFP(sc)->if_mtu = GIF_MTU;
209 #endif
210 	}
211 
212 	if (sc->gif_ro.ro_rt == NULL) {
213 		in_rtalloc_ign(&sc->gif_ro, 0, sc->gif_fibnum);
214 		if (sc->gif_ro.ro_rt == NULL) {
215 			m_freem(m);
216 			return ENETUNREACH;
217 		}
218 
219 		/* if it constitutes infinite encapsulation, punt. */
220 		if (sc->gif_ro.ro_rt->rt_ifp == ifp) {
221 			m_freem(m);
222 			return ENETUNREACH;	/* XXX */
223 		}
224 #if 0
225 		ifp->if_mtu = sc->gif_ro.ro_rt->rt_ifp->if_mtu
226 			- sizeof(struct ip);
227 #endif
228 	}
229 
230 	error = ip_output(m, NULL, &sc->gif_ro, 0, NULL, NULL);
231 
232 	if (!(GIF2IFP(sc)->if_flags & IFF_LINK0) &&
233 	    sc->gif_ro.ro_rt != NULL) {
234 		RTFREE(sc->gif_ro.ro_rt);
235 		sc->gif_ro.ro_rt = NULL;
236 	}
237 
238 	return (error);
239 }
240 
241 void
242 in_gif_input(struct mbuf *m, int off)
243 {
244 	struct ifnet *gifp = NULL;
245 	struct gif_softc *sc;
246 	struct ip *ip;
247 	int af;
248 	u_int8_t otos;
249 	int proto;
250 
251 	ip = mtod(m, struct ip *);
252 	proto = ip->ip_p;
253 
254 	sc = (struct gif_softc *)encap_getarg(m);
255 	if (sc == NULL) {
256 		m_freem(m);
257 		ipstat.ips_nogif++;
258 		return;
259 	}
260 
261 	gifp = GIF2IFP(sc);
262 	if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
263 		m_freem(m);
264 		ipstat.ips_nogif++;
265 		return;
266 	}
267 
268 	otos = ip->ip_tos;
269 	m_adj(m, off);
270 
271 	switch (proto) {
272 #ifdef INET
273 	case IPPROTO_IPV4:
274 	    {
275 		struct ip *ip;
276 		af = AF_INET;
277 		if (m->m_len < sizeof(*ip)) {
278 			m = m_pullup(m, sizeof(*ip));
279 			if (!m)
280 				return;
281 		}
282 		ip = mtod(m, struct ip *);
283 		if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ?
284 				  ECN_ALLOWED : ECN_NOCARE,
285 				  &otos, &ip->ip_tos) == 0) {
286 			m_freem(m);
287 			return;
288 		}
289 		break;
290 	    }
291 #endif
292 #ifdef INET6
293 	case IPPROTO_IPV6:
294 	    {
295 		struct ip6_hdr *ip6;
296 		u_int8_t itos, oitos;
297 
298 		af = AF_INET6;
299 		if (m->m_len < sizeof(*ip6)) {
300 			m = m_pullup(m, sizeof(*ip6));
301 			if (!m)
302 				return;
303 		}
304 		ip6 = mtod(m, struct ip6_hdr *);
305 		itos = oitos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
306 		if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ?
307 				  ECN_ALLOWED : ECN_NOCARE,
308 				  &otos, &itos) == 0) {
309 			m_freem(m);
310 			return;
311 		}
312 		if (itos != oitos) {
313 			ip6->ip6_flow &= ~htonl(0xff << 20);
314 			ip6->ip6_flow |= htonl((u_int32_t)itos << 20);
315 		}
316 		break;
317 	    }
318 #endif /* INET6 */
319  	case IPPROTO_ETHERIP:
320  		af = AF_LINK;
321  		break;
322 
323 	default:
324 		ipstat.ips_nogif++;
325 		m_freem(m);
326 		return;
327 	}
328 	gif_input(m, af, gifp);
329 	return;
330 }
331 
332 /*
333  * validate outer address.
334  */
335 static int
336 gif_validate4(const struct ip *ip, struct gif_softc *sc, struct ifnet *ifp)
337 {
338 	struct sockaddr_in *src, *dst;
339 	struct in_ifaddr *ia4;
340 
341 	src = (struct sockaddr_in *)sc->gif_psrc;
342 	dst = (struct sockaddr_in *)sc->gif_pdst;
343 
344 	/* check for address match */
345 	if (src->sin_addr.s_addr != ip->ip_dst.s_addr ||
346 	    dst->sin_addr.s_addr != ip->ip_src.s_addr)
347 		return 0;
348 
349 	/* martian filters on outer source - NOT done in ip_input! */
350 	if (IN_MULTICAST(ntohl(ip->ip_src.s_addr)))
351 		return 0;
352 	switch ((ntohl(ip->ip_src.s_addr) & 0xff000000) >> 24) {
353 	case 0: case 127: case 255:
354 		return 0;
355 	}
356 	/* reject packets with broadcast on source */
357 	TAILQ_FOREACH(ia4, &in_ifaddrhead, ia_link) {
358 		if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0)
359 			continue;
360 		if (ip->ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr)
361 			return 0;
362 	}
363 
364 	/* ingress filters on outer source */
365 	if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0 && ifp) {
366 		struct sockaddr_in sin;
367 		struct rtentry *rt;
368 
369 		bzero(&sin, sizeof(sin));
370 		sin.sin_family = AF_INET;
371 		sin.sin_len = sizeof(struct sockaddr_in);
372 		sin.sin_addr = ip->ip_src;
373 		/* XXX MRT  check for the interface we would use on output */
374 		rt = in_rtalloc1((struct sockaddr *)&sin, 0,
375 		    0UL, sc->gif_fibnum);
376 		if (!rt || rt->rt_ifp != ifp) {
377 #if 0
378 			log(LOG_WARNING, "%s: packet from 0x%x dropped "
379 			    "due to ingress filter\n", if_name(GIF2IFP(sc)),
380 			    (u_int32_t)ntohl(sin.sin_addr.s_addr));
381 #endif
382 			if (rt)
383 				RTFREE_LOCKED(rt);
384 			return 0;
385 		}
386 		RTFREE_LOCKED(rt);
387 	}
388 
389 	return 32 * 2;
390 }
391 
392 /*
393  * we know that we are in IFF_UP, outer address available, and outer family
394  * matched the physical addr family.  see gif_encapcheck().
395  */
396 int
397 gif_encapcheck4(const struct mbuf *m, int off, int proto, void *arg)
398 {
399 	struct ip ip;
400 	struct gif_softc *sc;
401 	struct ifnet *ifp;
402 
403 	/* sanity check done in caller */
404 	sc = (struct gif_softc *)arg;
405 
406 	/* LINTED const cast */
407 	m_copydata(m, 0, sizeof(ip), (caddr_t)&ip);
408 	ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL;
409 
410 	return gif_validate4(&ip, sc, ifp);
411 }
412 
413 int
414 in_gif_attach(struct gif_softc *sc)
415 {
416 	sc->encap_cookie4 = encap_attach_func(AF_INET, -1, gif_encapcheck,
417 	    &in_gif_protosw, sc);
418 	if (sc->encap_cookie4 == NULL)
419 		return EEXIST;
420 	return 0;
421 }
422 
423 int
424 in_gif_detach(struct gif_softc *sc)
425 {
426 	int error;
427 
428 	error = encap_detach(sc->encap_cookie4);
429 	if (error == 0)
430 		sc->encap_cookie4 = NULL;
431 	return error;
432 }
433