1 /*	$OpenBSD: ip_ether.c,v 1.46 2003/12/03 14:51:05 markus Exp $  */
2 /*
3  * The author of this code is Angelos D. Keromytis (kermit@adk.gr)
4  *
5  * This code was written by Angelos D. Keromytis for OpenBSD in October 1999.
6  *
7  * Copyright (C) 1999-2001 Angelos D. Keromytis.
8  *
9  * Permission to use, copy, and modify this software with or without fee
10  * is hereby granted, provided that this entire notice is included in
11  * all copies of any software which is or includes a copy or
12  * modification of this software.
13  * You may use this code under the GNU public license if you so wish. Please
14  * contribute changes back to the authors under this freer than GPL license
15  * so that we may further the use of strong encryption without limitations to
16  * all.
17  *
18  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
19  * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
20  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
21  * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
22  * PURPOSE.
23  */
24 
25 /*
26  * Ethernet-inside-IP processing (RFC3378).
27  */
28 
29 #include "bridge.h"
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/mbuf.h>
34 #include <sys/socket.h>
35 #include <sys/sysctl.h>
36 
37 #include <net/if.h>
38 #include <net/route.h>
39 #include <net/bpf.h>
40 
41 #ifdef INET
42 #include <netinet/in.h>
43 #include <netinet/in_systm.h>
44 #include <netinet/ip.h>
45 #include <netinet/in_pcb.h>
46 #include <netinet/ip_var.h>
47 #endif /* INET */
48 
49 #include <netinet/ip_ether.h>
50 #include <netinet/if_ether.h>
51 #include <net/if_bridge.h>
52 #include <net/if_gif.h>
53 
54 #include "gif.h"
55 #include "bpfilter.h"
56 
57 #ifdef ENCDEBUG
58 #define DPRINTF(x)	if (encdebug) printf x
59 #else
60 #define DPRINTF(x)
61 #endif
62 
63 /*
64  * We can control the acceptance of EtherIP packets by altering the sysctl
65  * net.inet.etherip.allow value. Zero means drop them, all else is acceptance.
66  */
67 int etherip_allow = 0;
68 
69 struct etheripstat etheripstat;
70 
71 /*
72  * etherip_input gets called when we receive an encapsulated packet,
73  * either because we got it at a real interface, or because AH or ESP
74  * were being used in tunnel mode (in which case the rcvif element will
75  * contain the address of the encX interface associated with the tunnel.
76  */
77 
78 void
etherip_input(struct mbuf * m,...)79 etherip_input(struct mbuf *m, ...)
80 {
81 	union sockaddr_union ssrc, sdst;
82 	struct ether_header eh;
83 	int iphlen;
84 	struct etherip_header eip;
85 	u_int8_t v;
86 	va_list ap;
87 
88 #if NGIF > 0
89 	struct gif_softc *sc;
90 #if NBRIDGE > 0
91 	int s;
92 #endif /* NBRIDGE */
93 #endif /* NGIF */
94 
95 	va_start(ap, m);
96 	iphlen = va_arg(ap, int);
97 	va_end(ap);
98 
99 	etheripstat.etherip_ipackets++;
100 
101 	/* If we do not accept EtherIP explicitly, drop. */
102 	if (!etherip_allow && (m->m_flags & (M_AUTH|M_CONF)) == 0) {
103 		DPRINTF(("etherip_input(): dropped due to policy\n"));
104 		etheripstat.etherip_pdrops++;
105 		m_freem(m);
106 		return;
107 	}
108 
109 	/*
110 	 * Make sure there's at least an ethernet header's and an EtherIP
111 	 * header's of worth of data after the outer IP header.
112 	 */
113 	if (m->m_pkthdr.len < iphlen + sizeof(struct ether_header) +
114 	    sizeof(struct etherip_header)) {
115 		DPRINTF(("etherip_input(): encapsulated packet too short\n"));
116 		etheripstat.etherip_hdrops++;
117 		m_freem(m);
118 		return;
119 	}
120 
121 	/* Verify EtherIP version number */
122 	m_copydata(m, iphlen, sizeof(struct etherip_header), (caddr_t)&eip);
123 	if ((eip.eip_ver & ETHERIP_VER_VERS_MASK) != ETHERIP_VERSION) {
124 		DPRINTF(("etherip_input(): received EtherIP version number "
125 		    "%d not suppoorted\n", (v >> 4) & 0xff));
126 		etheripstat.etherip_adrops++;
127 		m_freem(m);
128 		return;
129 	}
130 
131 	/*
132 	 * Note that the other potential failure of the above check is that the
133 	 * second nibble of the EtherIP header (the reserved part) is not
134 	 * zero; this is also invalid protocol behaviour.
135 	 */
136 	if (eip.eip_ver & ETHERIP_VER_RSVD_MASK) {
137 		DPRINTF(("etherip_input(): received EtherIP invalid EtherIP "
138 		    "header (reserved field non-zero\n"));
139 		etheripstat.etherip_adrops++;
140 		m_freem(m);
141 		return;
142 	}
143 
144 	/* Finally, the pad value must be zero. */
145 	if (eip.eip_pad) {
146 		DPRINTF(("etherip_input(): received EtherIP invalid "
147 		    "pad value\n"));
148 		etheripstat.etherip_adrops++;
149 		m_freem(m);
150 		return;
151 	}
152 
153 	/* Make sure the ethernet header at least is in the first mbuf. */
154 	if (m->m_len < iphlen + sizeof(struct ether_header) +
155 	    sizeof(struct etherip_header)) {
156 		if ((m = m_pullup(m, iphlen + sizeof(struct ether_header) +
157 		    sizeof(struct etherip_header))) == NULL) {
158 			DPRINTF(("etherip_input(): m_pullup() failed\n"));
159 			etheripstat.etherip_adrops++;
160 			return;
161 		}
162 	}
163 
164 	/* Copy the addresses for use later. */
165 	bzero(&ssrc, sizeof(ssrc));
166 	bzero(&sdst, sizeof(sdst));
167 
168 	v = *mtod(m, u_int8_t *);
169 	switch (v >> 4) {
170 #ifdef INET
171 	case 4:
172 		ssrc.sa.sa_len = sdst.sa.sa_len = sizeof(struct sockaddr_in);
173 		ssrc.sa.sa_family = sdst.sa.sa_family = AF_INET;
174 		m_copydata(m, offsetof(struct ip, ip_src),
175 		    sizeof(struct in_addr),
176 		    (caddr_t) &ssrc.sin.sin_addr);
177 		m_copydata(m, offsetof(struct ip, ip_dst),
178 		    sizeof(struct in_addr),
179 		    (caddr_t) &sdst.sin.sin_addr);
180 		break;
181 #endif /* INET */
182 #ifdef INET6
183 	case 6:
184 		ssrc.sa.sa_len = sdst.sa.sa_len = sizeof(struct sockaddr_in6);
185 		ssrc.sa.sa_family = sdst.sa.sa_family = AF_INET6;
186 		m_copydata(m, offsetof(struct ip6_hdr, ip6_src),
187 		    sizeof(struct in6_addr),
188 		    (caddr_t) &ssrc.sin6.sin6_addr);
189 		m_copydata(m, offsetof(struct ip6_hdr, ip6_dst),
190 		    sizeof(struct in6_addr),
191 		    (caddr_t) &sdst.sin6.sin6_addr);
192 		break;
193 #endif /* INET6 */
194 	default:
195 		DPRINTF(("etherip_input(): invalid protocol %d\n", v));
196 		m_freem(m);
197 		etheripstat.etherip_hdrops++;
198 		return /* EAFNOSUPPORT */;
199 	}
200 
201 	/* Chop off the `outer' IP and EtherIP headers and reschedule. */
202 	m_adj(m, iphlen + sizeof(struct etherip_header));
203 
204 	/* Statistics */
205 	etheripstat.etherip_ibytes += m->m_pkthdr.len;
206 
207 	/* Copy ethernet header */
208 	m_copydata(m, 0, sizeof(eh), (void *) &eh);
209 
210 	/* Reset the flags based on the inner packet */
211 	m->m_flags &= ~(M_BCAST|M_MCAST|M_AUTH|M_CONF|M_AUTH_AH);
212 	if (eh.ether_dhost[0] & 1) {
213 		if (bcmp((caddr_t) etherbroadcastaddr,
214 		    (caddr_t)eh.ether_dhost, sizeof(etherbroadcastaddr)) == 0)
215 			m->m_flags |= M_BCAST;
216 		else
217 			m->m_flags |= M_MCAST;
218 	}
219 
220 	/* Trim the beginning of the mbuf, to remove the ethernet header. */
221 	m_adj(m, sizeof(struct ether_header));
222 
223 #if NGIF > 0
224 	/* Find appropriate gif(4) interface */
225 	LIST_FOREACH(sc, &gif_softc_list, gif_list) {
226 		if ((sc->gif_psrc == NULL) ||
227 		    (sc->gif_pdst == NULL) ||
228 		    !(sc->gif_if.if_flags & (IFF_UP|IFF_RUNNING)))
229 			continue;
230 
231 		if (!bcmp(sc->gif_psrc, &sdst, sc->gif_psrc->sa_len) &&
232 		    !bcmp(sc->gif_pdst, &ssrc, sc->gif_pdst->sa_len) &&
233 		    sc->gif_if.if_bridge != NULL)
234 			break;
235 	}
236 
237 	/* None found. */
238 	if (sc == NULL) {
239 		DPRINTF(("etherip_input(): no interface found\n"));
240 		etheripstat.etherip_noifdrops++;
241 		m_freem(m);
242 		return;
243 	}
244 #if NBPFILTER > 0
245 	if (sc->gif_if.if_bpf) {
246 		struct mbuf m0;
247 		u_int32_t af = sdst.sa.sa_family;
248 
249 		m0.m_flags = 0;
250 		m0.m_next = m;
251 		m0.m_len = 4;
252 		m0.m_data = (char *)&af;
253 
254 		bpf_mtap(sc->gif_if.if_bpf, &m0);
255 	}
256 #endif
257 
258 #if NBRIDGE > 0
259 	/*
260 	 * Tap the packet off here for a bridge. bridge_input() returns
261 	 * NULL if it has consumed the packet.  In the case of gif's,
262 	 * bridge_input() returns non-NULL when an error occurs.
263 	 */
264 	m->m_pkthdr.rcvif = &sc->gif_if;
265 	if (m->m_flags & (M_BCAST|M_MCAST))
266 		sc->gif_if.if_imcasts++;
267 
268 	s = splnet();
269 	m = bridge_input(&sc->gif_if, &eh, m);
270 	splx(s);
271 	if (m == NULL)
272 		return;
273 #endif /* NBRIDGE */
274 #endif /* NGIF */
275 
276 	etheripstat.etherip_noifdrops++;
277 	m_freem(m);
278 	return;
279 }
280 
281 int
etherip_output(struct mbuf * m,struct tdb * tdb,struct mbuf ** mp,int skip,int protoff)282 etherip_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip,
283 	       int protoff)
284 {
285 #ifdef INET
286 	struct ip *ipo;
287 #endif /* INET */
288 
289 #ifdef INET6
290 	struct ip6_hdr *ip6;
291 #endif /* INET6 */
292 
293 	struct etherip_header eip;
294 	struct mbuf *m0;
295 	ushort hlen;
296 
297 	/* Some address family sanity checks. */
298 	if ((tdb->tdb_src.sa.sa_family != 0) &&
299 	    (tdb->tdb_src.sa.sa_family != AF_INET) &&
300 	    (tdb->tdb_src.sa.sa_family != AF_INET6)) {
301 		DPRINTF(("etherip_output(): IP in protocol-family <%d> "
302 		    "attempted, aborting", tdb->tdb_src.sa.sa_family));
303 		etheripstat.etherip_adrops++;
304 		m_freem(m);
305 		return EINVAL;
306 	}
307 
308 	if ((tdb->tdb_dst.sa.sa_family != AF_INET) &&
309 	    (tdb->tdb_dst.sa.sa_family != AF_INET6)) {
310 		DPRINTF(("etherip_output(): IP in protocol-family <%d> "
311 		    "attempted, aborting", tdb->tdb_dst.sa.sa_family));
312 		etheripstat.etherip_adrops++;
313 		m_freem(m);
314 		return EINVAL;
315 	}
316 
317 	if (tdb->tdb_dst.sa.sa_family != tdb->tdb_src.sa.sa_family) {
318 		DPRINTF(("etherip_output(): mismatch in tunnel source and "
319 		    "destination address protocol families (%d/%d), aborting",
320 		    tdb->tdb_src.sa.sa_family, tdb->tdb_dst.sa.sa_family));
321 		etheripstat.etherip_adrops++;
322 		m_freem(m);
323 		return EINVAL;
324 	}
325 
326 	switch (tdb->tdb_dst.sa.sa_family) {
327 #ifdef INET
328 	case AF_INET:
329 		hlen = sizeof(struct ip);
330 		break;
331 #endif /* INET */
332 #ifdef INET6
333 	case AF_INET6:
334 		hlen = sizeof(struct ip6_hdr);
335 		break;
336 #endif /* INET6 */
337 	default:
338 		DPRINTF(("etherip_output(): unsupported tunnel protocol "
339 		    "family <%d>, aborting", tdb->tdb_dst.sa.sa_family));
340 		etheripstat.etherip_adrops++;
341 		m_freem(m);
342 		return EINVAL;
343 	}
344 
345 	/* Don't forget the EtherIP header. */
346 	hlen += sizeof(struct etherip_header);
347 
348 	if (!(m->m_flags & M_PKTHDR)) {
349 		DPRINTF(("etherip_output(): mbuf is not a header\n"));
350 		m_freem(m);
351 		return (ENOBUFS);
352 	}
353 
354 	MGETHDR(m0, M_DONTWAIT, MT_DATA);
355 	if (m0 == NULL) {
356 		DPRINTF(("etherip_output(): M_GETHDR failed\n"));
357 		etheripstat.etherip_adrops++;
358 		m_freem(m);
359 		return ENOBUFS;
360 	}
361 	M_MOVE_PKTHDR(m0, m);
362 	m0->m_next = m;
363 	m0->m_len = hlen;
364 	m0->m_pkthdr.len += hlen;
365 	m = m0;
366 
367 	/* Statistics */
368 	etheripstat.etherip_opackets++;
369 	etheripstat.etherip_obytes += m->m_pkthdr.len - hlen;
370 
371 	switch (tdb->tdb_dst.sa.sa_family) {
372 #ifdef INET
373 	case AF_INET:
374 		ipo = mtod(m, struct ip *);
375 
376 		ipo->ip_v = IPVERSION;
377 		ipo->ip_hl = 5;
378 		ipo->ip_len = htons(m->m_pkthdr.len);
379 		ipo->ip_ttl = ip_defttl;
380 		ipo->ip_p = IPPROTO_ETHERIP;
381 		ipo->ip_tos = 0;
382 		ipo->ip_off = 0;
383 		ipo->ip_sum = 0;
384 		ipo->ip_id = htons(ip_randomid());
385 
386 		/*
387 		 * We should be keeping tunnel soft-state and send back
388 		 * ICMPs as needed.
389 		 */
390 
391 		ipo->ip_src = tdb->tdb_src.sin.sin_addr;
392 		ipo->ip_dst = tdb->tdb_dst.sin.sin_addr;
393 		break;
394 #endif /* INET */
395 #ifdef INET6
396 	case AF_INET6:
397 		ip6 = mtod(m, struct ip6_hdr *);
398 
399 		ip6->ip6_flow = 0;
400 		ip6->ip6_nxt = IPPROTO_ETHERIP;
401 		ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
402 		ip6->ip6_vfc |= IPV6_VERSION;
403 		ip6->ip6_plen = htons(m->m_pkthdr.len);
404 		ip6->ip6_hlim = ip_defttl;
405 		ip6->ip6_dst = tdb->tdb_dst.sin6.sin6_addr;
406 		ip6->ip6_src = tdb->tdb_src.sin6.sin6_addr;
407 		break;
408 #endif /* INET6 */
409 	}
410 
411 	/* Set the version number */
412 	eip.eip_ver = ETHERIP_VERSION & ETHERIP_VER_VERS_MASK;
413 	eip.eip_pad = 0;
414 	m_copyback(m, hlen - sizeof(struct etherip_header),
415 	    sizeof(struct etherip_header), &eip);
416 
417 	*mp = m;
418 
419 	return 0;
420 }
421 
422 int
etherip_sysctl(name,namelen,oldp,oldlenp,newp,newlen)423 etherip_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
424 	int *name;
425 	u_int namelen;
426 	void *oldp, *newp;
427 	size_t *oldlenp, newlen;
428 {
429 	/* All sysctl names at this level are terminal. */
430 	if (namelen != 1)
431 		return (ENOTDIR);
432 
433 	switch (name[0]) {
434 	case ETHERIPCTL_ALLOW:
435 		return (sysctl_int(oldp, oldlenp, newp, newlen,
436 		    &etherip_allow));
437 	default:
438 		return (ENOPROTOOPT);
439 	}
440 	/* NOTREACHED */
441 }
442