Annotation of sys/netinet/ip_ether.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: ip_ether.c,v 1.50 2007/02/20 19:37:40 claudio 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
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: #if NGIF > 0
221: /* Find appropriate gif(4) interface */
222: LIST_FOREACH(sc, &gif_softc_list, gif_list) {
223: if ((sc->gif_psrc == NULL) ||
224: (sc->gif_pdst == NULL) ||
225: !(sc->gif_if.if_flags & (IFF_UP|IFF_RUNNING)))
226: continue;
227:
228: if (!bcmp(sc->gif_psrc, &sdst, sc->gif_psrc->sa_len) &&
229: !bcmp(sc->gif_pdst, &ssrc, sc->gif_pdst->sa_len) &&
230: sc->gif_if.if_bridge != NULL)
231: break;
232: }
233:
234: /* None found. */
235: if (sc == NULL) {
236: DPRINTF(("etherip_input(): no interface found\n"));
237: etheripstat.etherip_noifdrops++;
238: m_freem(m);
239: return;
240: }
241: #if NBPFILTER > 0
242: if (sc->gif_if.if_bpf)
243: bpf_mtap_af(sc->gif_if.if_bpf, AF_LINK, m, BPF_DIRECTION_IN);
244: #endif
245:
246: /* Trim the beginning of the mbuf, to remove the ethernet header. */
247: m_adj(m, sizeof(struct ether_header));
248:
249: #if NBRIDGE > 0
250: /*
251: * Tap the packet off here for a bridge. bridge_input() returns
252: * NULL if it has consumed the packet. In the case of gif's,
253: * bridge_input() returns non-NULL when an error occurs.
254: */
255: m->m_pkthdr.rcvif = &sc->gif_if;
256: if (m->m_flags & (M_BCAST|M_MCAST))
257: sc->gif_if.if_imcasts++;
258:
259: s = splnet();
260: m = bridge_input(&sc->gif_if, &eh, m);
261: splx(s);
262: if (m == NULL)
263: return;
264: #endif /* NBRIDGE */
265: #endif /* NGIF */
266:
267: etheripstat.etherip_noifdrops++;
268: m_freem(m);
269: return;
270: }
271:
272: int
273: etherip_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip,
274: int protoff)
275: {
276: #ifdef INET
277: struct ip *ipo;
278: #endif /* INET */
279:
280: #ifdef INET6
281: struct ip6_hdr *ip6;
282: #endif /* INET6 */
283:
284: struct etherip_header eip;
285: struct mbuf *m0;
286: ushort hlen;
287:
288: /* Some address family sanity checks. */
289: if ((tdb->tdb_src.sa.sa_family != 0) &&
290: (tdb->tdb_src.sa.sa_family != AF_INET) &&
291: (tdb->tdb_src.sa.sa_family != AF_INET6)) {
292: DPRINTF(("etherip_output(): IP in protocol-family <%d> "
293: "attempted, aborting", tdb->tdb_src.sa.sa_family));
294: etheripstat.etherip_adrops++;
295: m_freem(m);
296: return EINVAL;
297: }
298:
299: if ((tdb->tdb_dst.sa.sa_family != AF_INET) &&
300: (tdb->tdb_dst.sa.sa_family != AF_INET6)) {
301: DPRINTF(("etherip_output(): IP in protocol-family <%d> "
302: "attempted, aborting", tdb->tdb_dst.sa.sa_family));
303: etheripstat.etherip_adrops++;
304: m_freem(m);
305: return EINVAL;
306: }
307:
308: if (tdb->tdb_dst.sa.sa_family != tdb->tdb_src.sa.sa_family) {
309: DPRINTF(("etherip_output(): mismatch in tunnel source and "
310: "destination address protocol families (%d/%d), aborting",
311: tdb->tdb_src.sa.sa_family, tdb->tdb_dst.sa.sa_family));
312: etheripstat.etherip_adrops++;
313: m_freem(m);
314: return EINVAL;
315: }
316:
317: switch (tdb->tdb_dst.sa.sa_family) {
318: #ifdef INET
319: case AF_INET:
320: hlen = sizeof(struct ip);
321: break;
322: #endif /* INET */
323: #ifdef INET6
324: case AF_INET6:
325: hlen = sizeof(struct ip6_hdr);
326: break;
327: #endif /* INET6 */
328: default:
329: DPRINTF(("etherip_output(): unsupported tunnel protocol "
330: "family <%d>, aborting", tdb->tdb_dst.sa.sa_family));
331: etheripstat.etherip_adrops++;
332: m_freem(m);
333: return EINVAL;
334: }
335:
336: /* Don't forget the EtherIP header. */
337: hlen += sizeof(struct etherip_header);
338:
339: if (!(m->m_flags & M_PKTHDR)) {
340: DPRINTF(("etherip_output(): mbuf is not a header\n"));
341: m_freem(m);
342: return (ENOBUFS);
343: }
344:
345: MGETHDR(m0, M_DONTWAIT, MT_DATA);
346: if (m0 == NULL) {
347: DPRINTF(("etherip_output(): M_GETHDR failed\n"));
348: etheripstat.etherip_adrops++;
349: m_freem(m);
350: return ENOBUFS;
351: }
352: M_MOVE_PKTHDR(m0, m);
353: m0->m_next = m;
354: m0->m_len = hlen;
355: m0->m_pkthdr.len += hlen;
356: m = m0;
357:
358: /* Statistics */
359: etheripstat.etherip_opackets++;
360: etheripstat.etherip_obytes += m->m_pkthdr.len - hlen;
361:
362: switch (tdb->tdb_dst.sa.sa_family) {
363: #ifdef INET
364: case AF_INET:
365: ipo = mtod(m, struct ip *);
366:
367: ipo->ip_v = IPVERSION;
368: ipo->ip_hl = 5;
369: ipo->ip_len = htons(m->m_pkthdr.len);
370: ipo->ip_ttl = ip_defttl;
371: ipo->ip_p = IPPROTO_ETHERIP;
372: ipo->ip_tos = 0;
373: ipo->ip_off = 0;
374: ipo->ip_sum = 0;
375: ipo->ip_id = htons(ip_randomid());
376:
377: /*
378: * We should be keeping tunnel soft-state and send back
379: * ICMPs as needed.
380: */
381:
382: ipo->ip_src = tdb->tdb_src.sin.sin_addr;
383: ipo->ip_dst = tdb->tdb_dst.sin.sin_addr;
384: break;
385: #endif /* INET */
386: #ifdef INET6
387: case AF_INET6:
388: ip6 = mtod(m, struct ip6_hdr *);
389:
390: ip6->ip6_flow = 0;
391: ip6->ip6_nxt = IPPROTO_ETHERIP;
392: ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
393: ip6->ip6_vfc |= IPV6_VERSION;
394: ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
395: ip6->ip6_hlim = ip_defttl;
396: ip6->ip6_dst = tdb->tdb_dst.sin6.sin6_addr;
397: ip6->ip6_src = tdb->tdb_src.sin6.sin6_addr;
398: break;
399: #endif /* INET6 */
400: }
401:
402: /* Set the version number */
403: eip.eip_ver = ETHERIP_VERSION & ETHERIP_VER_VERS_MASK;
404: eip.eip_pad = 0;
405: m_copyback(m, hlen - sizeof(struct etherip_header),
406: sizeof(struct etherip_header), &eip);
407:
408: *mp = m;
409:
410: return 0;
411: }
412:
413: int
414: etherip_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
415: int *name;
416: u_int namelen;
417: void *oldp, *newp;
418: size_t *oldlenp, newlen;
419: {
420: /* All sysctl names at this level are terminal. */
421: if (namelen != 1)
422: return (ENOTDIR);
423:
424: switch (name[0]) {
425: case ETHERIPCTL_ALLOW:
426: return (sysctl_int(oldp, oldlenp, newp, newlen,
427: ðerip_allow));
428: default:
429: return (ENOPROTOOPT);
430: }
431: /* NOTREACHED */
432: }
CVSweb