xref: /openbsd/sys/net/if_gre.c (revision 133306f0)
1 /*      $OpenBSD: if_gre.c,v 1.7 2001/01/17 19:50:14 angelos Exp $ */
2 /*	$NetBSD: if_gre.c,v 1.9 1999/10/25 19:18:11 drochner Exp $ */
3 
4 /*
5  * Copyright (c) 1998 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Heiko W.Rupp <hwr@pilhuhn.de>
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *        This product includes software developed by the NetBSD
22  *        Foundation, Inc. and its contributors.
23  * 4. Neither the name of The NetBSD Foundation nor the names of its
24  *    contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 
40 /*
41  * Encapsulate L3 protocols into IP, per RFC 1701 and 1702.
42  * See gre(4) for more details.
43  * Also supported: IP in IP encapsulation (proto 55) per RFC 2004.
44  */
45 
46 #include "gre.h"
47 #if NGRE > 0
48 
49 #include "bpfilter.h"
50 
51 #include <sys/param.h>
52 #include <sys/proc.h>
53 #include <sys/mbuf.h>
54 #include <sys/socket.h>
55 #include <sys/sockio.h>
56 #include <sys/kernel.h>
57 #include <sys/systm.h>
58 
59 #include <net/if.h>
60 #include <net/if_types.h>
61 #include <net/netisr.h>
62 #include <net/route.h>
63 
64 #ifdef INET
65 #include <netinet/in.h>
66 #include <netinet/in_systm.h>
67 #include <netinet/in_var.h>
68 #include <netinet/ip.h>
69 #include <netinet/ip_var.h>
70 #include <netinet/if_ether.h>
71 #else
72 #error "if_gre used without inet"
73 #endif
74 
75 #ifdef NS
76 #include <netns/ns.h>
77 #include <netns/ns_if.h>
78 #endif
79 
80 #ifdef NETATALK
81 #include <netatalk/at.h>
82 #include <netatalk/at_var.h>
83 #include <netatalk/at_extern.h>
84 #endif
85 
86 #if NBPFILTER > 0
87 #include <net/bpf.h>
88 #endif
89 
90 #include <net/if_gre.h>
91 
92 #ifndef GRE_RECURSION_LIMIT
93 #define GRE_RECURSION_LIMIT	3   /* How many levels of recursion allowed */
94 #endif /* GRE_RECURSION_LIMIT */
95 
96 #define GREMTU 1450	/* XXX this is below the standard MTU of
97                          1500 Bytes, allowing for headers,
98                          but we should possibly do path mtu discovery
99                          before changing if state to up to find the
100                          correct value */
101 
102 #define LINK_MASK (IFF_LINK0|IFF_LINK1|IFF_LINK2)
103 
104 struct gre_softc gre_softc[NGRE];
105 
106 /*
107  * We can control the acceptance of GRE and MobileIP packets by
108  * altering the sysctl net.inet.gre.allow and net.inet.mobileip.allow values
109  * respectively. Zero means drop them, all else is acceptance.
110  */
111 int gre_allow = 0;
112 int ip_mobile_allow = 0;
113 
114 static void gre_compute_route(struct gre_softc *sc);
115 
116 void
117 greattach(void)
118 {
119 	struct gre_softc *sc;
120 	int i;
121 
122 	for (i = 0, sc = gre_softc ; i < NGRE ; sc++ ) {
123 		snprintf(sc->sc_if.if_xname, sizeof(sc->sc_if.if_xname),
124 			 "gre%d", i++);
125 		sc->sc_if.if_softc = sc;
126 		sc->sc_if.if_type =  IFT_OTHER;
127 		sc->sc_if.if_addrlen = 4;
128 		sc->sc_if.if_hdrlen = 24; /* IP + GRE */
129 		sc->sc_if.if_mtu = GREMTU;
130 		sc->sc_if.if_flags = IFF_POINTOPOINT|IFF_MULTICAST;
131 		sc->sc_if.if_output = gre_output;
132 		sc->sc_if.if_ioctl = gre_ioctl;
133 		sc->sc_if.if_collisions = 0;
134 		sc->sc_if.if_ierrors = 0;
135 		sc->sc_if.if_oerrors = 0;
136 		sc->sc_if.if_ipackets = 0;
137 		sc->sc_if.if_opackets = 0;
138 		sc->g_dst.s_addr = sc->g_src.s_addr = INADDR_ANY;
139 		sc->g_proto = IPPROTO_GRE;
140 
141 		if_attach(&sc->sc_if);
142 
143 #if NBPFILTER > 0
144 		bpfattach(&sc->sc_if.if_bpf, &sc->sc_if, DLT_RAW,
145 			  sizeof(u_int32_t) );
146 #endif
147 	}
148 }
149 
150 /*
151  * The output routine. Takes a packet and encapsulates it in the protocol
152  * given by sc->g_proto. See also RFC 1701 and RFC 2004.
153  */
154 
155 int
156 gre_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
157 	   struct rtentry *rt)
158 {
159 	int error = 0;
160 	struct gre_softc *sc = (struct gre_softc *) (ifp->if_softc);
161 	struct greip *gh = NULL;
162 	struct ip *inp = NULL;
163 	u_short etype = 0;
164 	struct mobile_h mob_h;
165 	static int recursions = 0;	/* XXX MUTEX */
166 
167 	/* Try to limit infinite recursion through misconfiguration */
168 	if (++recursions >= GRE_RECURSION_LIMIT) {
169 		IF_DROP(&ifp->if_snd);
170 		m_freem(m);
171 		recursions = 0;
172 		return (EIO);	/* Use the same as in if_gif.c */
173 	}
174 
175 #if NBPFILTER >0
176 	if (ifp->if_bpf)
177 		bpf_mtap(ifp->if_bpf, m);
178 #endif
179 
180 	if (sc->g_proto == IPPROTO_MOBILE) {
181 	        if (ip_mobile_allow == 0) {
182 		        IF_DROP(&ifp->if_snd);
183 			m_freem(m);
184 			recursions = 0;
185 			return (EACCES);
186 		}
187 
188 		if (dst->sa_family == AF_INET) {
189 			struct mbuf *m0;
190 			int msiz;
191 
192 			/*
193 			 * Make sure the complete IP header (with options)
194 			 * is in the first mbuf.
195 			 */
196 			if (m->m_len < sizeof(struct ip))
197 			{
198 			        m = m_pullup(m, sizeof(struct ip));
199 			        if (m == 0) {
200 					IF_DROP(&ifp->if_snd);
201 					recursions = 0;
202 					return (ENOBUFS);
203 				}
204 				else
205 				        inp = mtod(m, struct ip *);
206 
207 				if (m->m_len < inp->ip_hl << 2) {
208 				        m = m_pullup(m,
209 						     sizeof(inp->ip_hl << 2));
210 					if (m == 0) {
211 					        IF_DROP(&ifp->if_snd);
212 						recursions = 0;
213 						return (ENOBUFS);
214 					}
215 				}
216 			}
217 
218 			inp = mtod(m, struct ip *);
219 
220 			bzero(&mob_h, MOB_H_SIZ_L);
221 			mob_h.proto = (inp->ip_p) << 8;
222 			mob_h.odst = inp->ip_dst.s_addr;
223 			inp->ip_dst.s_addr = sc->g_dst.s_addr;
224 
225 			/*
226 			 * If the packet comes from our host, we only change
227 			 * the destination address in the IP header.
228 			 * Otherwise we need to save and change the source.
229 			 */
230 			if (inp->ip_src.s_addr == sc->g_src.s_addr) {
231 				msiz = MOB_H_SIZ_S;
232 			} else {
233 				mob_h.proto |= MOB_H_SBIT;
234 				mob_h.osrc = inp->ip_src.s_addr;
235 				inp->ip_src.s_addr = sc->g_src.s_addr;
236 				msiz = MOB_H_SIZ_L;
237 			}
238 
239 			HTONS(mob_h.proto);
240 			mob_h.hcrc = gre_in_cksum((u_short *) &mob_h, msiz);
241 
242 			/* Squeeze in the mobility header */
243 			if ((m->m_data - msiz) < m->m_pktdat) {
244 				/* Need new mbuf */
245 				MGETHDR(m0, M_DONTWAIT, MT_HEADER);
246 				if (m0 == NULL) {
247 					IF_DROP(&ifp->if_snd);
248 					m_freem(m);
249 					recursions = 0;
250 					return (ENOBUFS);
251 				}
252 
253 				m0->m_len = msiz + (inp->ip_hl << 2);
254 				m0->m_data += max_linkhdr;
255 				m0->m_pkthdr.len = m->m_pkthdr.len + msiz;
256 				m->m_data += inp->ip_hl << 2;
257 				m->m_len -= inp->ip_hl << 2;
258 
259 				bcopy((caddr_t) inp, mtod(m0, caddr_t),
260 				       sizeof(struct ip));
261 
262 				m0->m_next = m;
263 				m = m0;
264 			} else {  /* we have some space left in the old one */
265 				m->m_data -= msiz;
266 				m->m_len += msiz;
267 				m->m_pkthdr.len += msiz;
268 				bcopy(inp, mtod(m, caddr_t),
269 				      inp->ip_hl << 2);
270 			}
271 
272 			/* Copy Mobility header */
273 			inp = mtod(m, struct ip *);
274 			bcopy(&mob_h, (caddr_t)(inp + 1), (unsigned) msiz);
275 			NTOHS(inp->ip_len);
276 			inp->ip_len += msiz;
277 		} else {  /* AF_INET */
278 			IF_DROP(&ifp->if_snd);
279 			m_freem(m);
280 			recursions = 0;
281 			return (EINVAL);
282 		}
283 	} else if (sc->g_proto == IPPROTO_GRE) {
284 	        if (gre_allow == 0) {
285 		        IF_DROP(&ifp->if_snd);
286 			m_freem(m);
287 			recursions = 0;
288 			return (EACCES);
289 		}
290 
291 		switch(dst->sa_family) {
292 		case AF_INET:
293 		        if (m->m_len < sizeof(struct ip)) {
294 			        m = m_pullup(m, sizeof(struct ip));
295 				if (m == 0) {
296 				        IF_DROP(&ifp->if_snd);
297 					recursions = 0;
298 					return (ENOBUFS);
299 				}
300 			}
301 
302 			inp = mtod(m, struct ip *);
303 			etype = ETHERTYPE_IP;
304 			break;
305 #ifdef NETATALK
306 		case AF_APPLETALK:
307 			etype = ETHERTYPE_AT;
308 			break;
309 #endif
310 #ifdef NS
311 		case AF_NS:
312 			etype = ETHERTYPE_NS;
313 			break;
314 #endif
315 		default:
316 			IF_DROP(&ifp->if_snd);
317 			m_freem(m);
318 			recursions = 0;
319 			return (EAFNOSUPPORT);
320 		}
321 
322 		M_PREPEND(m, sizeof(struct greip), M_DONTWAIT);
323 	} else {
324 		error = EINVAL;
325 		IF_DROP(&ifp->if_snd);
326 		m_freem(m);
327 		recursions = 0;
328 		return (error);
329 	}
330 
331 	if (m == NULL) {
332 		IF_DROP(&ifp->if_snd);
333 		recursions = 0;
334 		return (ENOBUFS);
335 	}
336 
337 	gh = mtod(m, struct greip *);
338 	if (sc->g_proto == IPPROTO_GRE) {
339 		/* We don't support any GRE flags for now */
340 
341 		bzero((void *) &gh->gi_g, sizeof(struct gre_h));
342 		gh->gi_ptype = htons(etype);
343 	}
344 
345 	gh->gi_pr = sc->g_proto;
346 	if (sc->g_proto != IPPROTO_MOBILE) {
347 		gh->gi_src = sc->g_src;
348 		gh->gi_dst = sc->g_dst;
349 		((struct ip *) gh)->ip_hl = (sizeof(struct ip)) >> 2;
350 		((struct ip *) gh)->ip_ttl = ip_defttl;
351 		((struct ip *) gh)->ip_tos = inp->ip_tos;
352 		gh->gi_len = m->m_pkthdr.len;
353 	}
354 
355 	ifp->if_opackets++;
356 	ifp->if_obytes += m->m_pkthdr.len;
357 
358 	/* Send it off */
359 	error = ip_output(m, NULL, &sc->route, 0, NULL, NULL);
360 	if (error)
361 		ifp->if_oerrors++;
362 	recursions = 0;
363 	return (error);
364 }
365 
366 int
367 gre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
368 {
369 
370 	struct ifaddr *ifa = (struct ifaddr *) data;
371 	struct ifreq *ifr = (struct ifreq *) data;
372 	struct in_ifaddr *ia = (struct in_ifaddr *) data;
373 	struct gre_softc *sc = ifp->if_softc;
374 	int s;
375 	struct sockaddr_in si;
376 	struct sockaddr *sa = NULL;
377 	int error = 0;
378 	struct proc *prc = curproc;             /* XXX */
379 
380 	s = splimp();
381 	switch(cmd) {
382 	case SIOCSIFADDR:
383 	case SIOCSIFDSTADDR:
384 		/*
385                  * set tunnel endpoints in case that we "only"
386                  * have ip over ip encapsulation. This allows to
387                  * set tunnel endpoints with ifconfig.
388                  */
389 		if (ifa->ifa_addr->sa_family == AF_INET) {
390 			sa = ifa->ifa_addr;
391 			sc->g_src = (satosin(sa))->sin_addr;
392 			sc->g_dst = ia->ia_dstaddr.sin_addr;
393 			if ((sc->g_src.s_addr != INADDR_ANY) &&
394 			    (sc->g_dst.s_addr != INADDR_ANY)) {
395 				if (sc->route.ro_rt != 0) {
396                                         /* free old route */
397 					RTFREE(sc->route.ro_rt);
398 					sc->route.ro_rt = (struct rtentry *) 0;
399 				}
400 
401 				gre_compute_route(sc);
402 				if (sc->route.ro_rt == 0) {
403 					sc->g_src.s_addr = INADDR_ANY;
404 					sc->g_dst.s_addr = INADDR_ANY;
405 					return EIO; /* Is this is good ? */
406 				}
407 
408 				ifp->if_flags |= IFF_UP;
409 			}
410 		}
411 		break;
412 	case SIOCSIFFLAGS:
413 		if ((sc->g_dst.s_addr == INADDR_ANY) ||
414 		    (sc->g_src.s_addr == INADDR_ANY))
415 			ifp->if_flags &= ~IFF_UP;
416 
417 		switch(ifr->ifr_flags & LINK_MASK) {
418 			case IFF_LINK0:
419 				sc->g_proto = IPPROTO_GRE;
420 				ifp->if_flags |= IFF_LINK0;
421 				ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2);
422 				break;
423 			case IFF_LINK2:
424 				sc->g_proto = IPPROTO_MOBILE;
425 				ifp->if_flags |= IFF_LINK2;
426 				ifp->if_flags &= ~(IFF_LINK0|IFF_LINK1);
427 				break;
428 		}
429 		break;
430 	case SIOCADDMULTI:
431 	case SIOCDELMULTI:
432 		if (ifr == 0) {
433 			error = EAFNOSUPPORT;
434 			break;
435 		}
436 		switch (ifr->ifr_addr.sa_family) {
437 #ifdef INET
438 		case AF_INET:
439 			break;
440 #endif
441 		default:
442 			error = EAFNOSUPPORT;
443 			break;
444 		}
445 		break;
446 	case GRESPROTO:
447 	        /* Check for superuser */
448 	        if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
449 		        break;
450 
451 		sc->g_proto = ifr->ifr_flags;
452 		switch (sc->g_proto) {
453 		case IPPROTO_GRE :
454 			ifp->if_flags |= IFF_LINK0;
455 			ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2);
456 			break;
457 		case IPPROTO_MOBILE :
458 			ifp->if_flags |= IFF_LINK2;
459 			ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2);
460 			break;
461 		default:
462 			ifp->if_flags &= ~(IFF_LINK0|IFF_LINK1|IFF_LINK2);
463 		}
464 		break;
465 	case GREGPROTO:
466 		ifr->ifr_flags = sc->g_proto;
467 		break;
468 	case GRESADDRS:
469 	case GRESADDRD:
470 	        /* Check for superuser */
471 	        if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
472 		        break;
473 
474 		/*
475 	         * set tunnel endpoints, compute a less specific route
476 	         * to the remote end and mark if as up
477                  */
478 		sa = &ifr->ifr_addr;
479 		if (cmd == GRESADDRS )
480 			sc->g_src = (satosin(sa))->sin_addr;
481 		if (cmd == GRESADDRD )
482 			sc->g_dst = (satosin(sa))->sin_addr;
483 		if ((sc->g_src.s_addr != INADDR_ANY) &&
484 		    (sc->g_dst.s_addr != INADDR_ANY)) {
485 			if (sc->route.ro_rt != 0) {
486 			        /* free old route */
487 				RTFREE(sc->route.ro_rt);
488 				sc->route.ro_rt = (struct rtentry *) 0;
489 			}
490 
491 			gre_compute_route(sc);
492 			if (sc->route.ro_rt == 0)
493 			{
494 				sc->g_src.s_addr = INADDR_ANY;
495 				sc->g_dst.s_addr = INADDR_ANY;
496 				return EIO; /* Is this is good ? */
497 			}
498 			ifp->if_flags |= IFF_UP;
499 		}
500 		break;
501 	case GREGADDRS:
502 		si.sin_addr.s_addr = sc->g_src.s_addr;
503 		sa = sintosa(&si);
504 		ifr->ifr_addr = *sa;
505 		break;
506 	case GREGADDRD:
507 		si.sin_addr.s_addr = sc->g_dst.s_addr;
508 		sa = sintosa(&si);
509 		ifr->ifr_addr = *sa;
510 		break;
511 	default:
512 		error = EINVAL;
513 	}
514 
515 	splx(s);
516 	return (error);
517 }
518 
519 /*
520  * computes a route to our destination that is not the one
521  * which would be taken by ip_output(), as this one will loop back to
522  * us. If the interface is p2p as  a--->b, then a routing entry exists
523  * If we now send a packet to b (e.g. ping b), this will come down here
524  * gets src=a, dst=b tacked on and would from ip_ouput() sent back to
525  * if_gre.
526  * Goal here is to compute a route to b that is less specific than
527  * a-->b. We know that this one exists as in normal operation we have
528  * at least a default route which matches.
529  */
530 
531 static void
532 gre_compute_route(struct gre_softc *sc)
533 {
534 	struct route *ro;
535 	u_int32_t a, b, c;
536 
537 	ro = &sc->route;
538 
539 	bzero(ro, sizeof(struct route));
540 	((struct sockaddr_in *) &ro->ro_dst)->sin_addr = sc->g_dst;
541 	ro->ro_dst.sa_family = AF_INET;
542 	ro->ro_dst.sa_len = sizeof(ro->ro_dst);
543 
544 	/*
545 	 * toggle last bit, so our interface is not found, but a less
546          * specific route. I'd rather like to specify a shorter mask,
547  	 * but this is not possible. Should work though. XXX
548 	 * there is a simpler way ...
549          */
550 	if ((sc->sc_if.if_flags & IFF_LINK1) == 0) {
551 		a = ntohl(sc->g_dst.s_addr);
552 		b = a & 0x01;
553 		c = a & 0xfffffffe;
554 		b = b ^ 0x01;
555 		a = b | c;
556 		((struct sockaddr_in *) &ro->ro_dst)->sin_addr.s_addr = htonl(a);
557 	}
558 
559 	rtalloc(ro);
560 	if (ro->ro_rt == 0)
561 		return;
562 
563 	/*
564 	 * Check whether we just created a loop. An even more paranoid
565 	 * check would be against all GRE interfaces, but that would
566 	 * not allow people to link GRE tunnels.
567 	 */
568 	if (ro->ro_rt->rt_ifp == &sc->sc_if) {
569                 RTFREE(ro->ro_rt);
570                 ro->ro_rt = (struct rtentry *) 0;
571 		return;
572 	}
573 
574 	/*
575 	 * now change it back - else ip_output will just drop
576          * the route and search one to this interface ...
577          */
578 	if ((sc->sc_if.if_flags & IFF_LINK1) == 0)
579 		((struct sockaddr_in *) &ro->ro_dst)->sin_addr = sc->g_dst;
580 }
581 
582 /*
583  * do a checksum of a buffer - much like in_cksum, which operates on
584  * mbufs.
585  */
586 
587 u_short
588 gre_in_cksum(u_short *p, u_int len)
589 {
590 	u_int sum = 0;
591 	int nwords = len >> 1;
592 
593 	while (nwords-- != 0)
594 		sum += *p++;
595 
596 		if (len & 1) {
597 			union {
598 				u_short w;
599 				u_char c[2];
600 			} u;
601 			u.c[0] = *(u_char *) p;
602 			u.c[1] = 0;
603 			sum += u.w;
604 		}
605 
606 		/* end-around-carry */
607 		sum = (sum >> 16) + (sum & 0xffff);
608 		sum += (sum >> 16);
609 		return (~sum);
610 }
611 #endif
612