1: /* nit.c
2:
3: Network Interface Tap (NIT) network interface code, by Ted Lemon
4: with one crucial tidbit of help from Stu Grossmen. */
5:
6: /*
7: * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC")
8: * Copyright (c) 1996-2003 by Internet Software Consortium
9: *
10: * Permission to use, copy, modify, and distribute this software for any
11: * purpose with or without fee is hereby granted, provided that the above
12: * copyright notice and this permission notice appear in all copies.
13: *
14: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20: * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21: *
22: * Internet Systems Consortium, Inc.
23: * 950 Charter Street
24: * Redwood City, CA 94063
25: * <info@isc.org>
26: * https://www.isc.org/
27: *
28: * This software has been written for Internet Systems Consortium
29: * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
30: * To learn more about Internet Systems Consortium, see
31: * ``https://www.isc.org/''. To learn more about Vixie Enterprises,
32: * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
33: * ``http://www.nominum.com''.
34: */
35:
36: #include "dhcpd.h"
37: #if defined (USE_NIT_SEND) || defined (USE_NIT_RECEIVE)
38: #include <sys/ioctl.h>
39: #include <sys/uio.h>
40:
41: #include <sys/time.h>
42: #include <net/nit.h>
43: #include <net/nit_if.h>
44: #include <net/nit_pf.h>
45: #include <net/nit_buf.h>
46: #include <sys/stropts.h>
47: #include <net/packetfilt.h>
48:
49: #include <netinet/in_systm.h>
50: #include "includes/netinet/ip.h"
51: #include "includes/netinet/udp.h"
52: #include "includes/netinet/if_ether.h"
53:
54: /* Reinitializes the specified interface after an address change. This
55: is not required for packet-filter APIs. */
56:
57: #ifdef USE_NIT_SEND
58: void if_reinitialize_send (info)
59: struct interface_info *info;
60: {
61: }
62: #endif
63:
64: #ifdef USE_NIT_RECEIVE
65: void if_reinitialize_receive (info)
66: struct interface_info *info;
67: {
68: }
69: #endif
70:
71: /* Called by get_interface_list for each interface that's discovered.
72: Opens a packet filter for each interface and adds it to the select
73: mask. */
74:
75: int if_register_nit (info)
76: struct interface_info *info;
77: {
78: int sock;
79: char filename[50];
80: struct ifreq ifr;
81: struct strioctl sio;
82:
83: /* Open a NIT device */
84: sock = open ("/dev/nit", O_RDWR);
85: if (sock < 0)
86: log_fatal ("Can't open NIT device for %s: %m", info -> name);
87:
88: /* Set the NIT device to point at this interface. */
89: sio.ic_cmd = NIOCBIND;
90: sio.ic_len = sizeof *(info -> ifp);
91: sio.ic_dp = (char *)(info -> ifp);
92: sio.ic_timout = INFTIM;
93: if (ioctl (sock, I_STR, &sio) < 0)
94: log_fatal ("Can't attach interface %s to nit device: %m",
95: info -> name);
96:
97: /* Get the low-level address... */
98: sio.ic_cmd = SIOCGIFADDR;
99: sio.ic_len = sizeof ifr;
100: sio.ic_dp = (char *)𝔦
101: sio.ic_timout = INFTIM;
102: if (ioctl (sock, I_STR, &sio) < 0)
103: log_fatal ("Can't get physical layer address for %s: %m",
104: info -> name);
105:
106: /* XXX code below assumes ethernet interface! */
107: info -> hw_address.hlen = 7;
108: info -> hw_address.hbuf [0] = ARPHRD_ETHER;
109: memcpy (&info -> hw_address.hbuf [1],
110: ifr.ifr_ifru.ifru_addr.sa_data, 6);
111:
112: if (ioctl (sock, I_PUSH, "pf") < 0)
113: log_fatal ("Can't push packet filter onto NIT for %s: %m",
114: info -> name);
115:
116: return sock;
117: }
118: #endif /* USE_NIT_SEND || USE_NIT_RECEIVE */
119:
120: #ifdef USE_NIT_SEND
121: void if_register_send (info)
122: struct interface_info *info;
123: {
124: /* If we're using the nit API for sending and receiving,
125: we don't need to register this interface twice. */
126: #ifndef USE_NIT_RECEIVE
127: struct packetfilt pf;
128: struct strioctl sio;
129:
130: info -> wfdesc = if_register_nit (info);
131:
132: pf.Pf_Priority = 0;
133: pf.Pf_FilterLen = 1;
134: pf.Pf_Filter [0] = ENF_PUSHZERO;
135:
136: /* Set up an NIT filter that rejects everything... */
137: sio.ic_cmd = NIOCSETF;
138: sio.ic_len = sizeof pf;
139: sio.ic_dp = (char *)&pf;
140: sio.ic_timout = INFTIM;
141: if (ioctl (info -> wfdesc, I_STR, &sio) < 0)
142: log_fatal ("Can't set NIT filter: %m");
143: #else
144: info -> wfdesc = info -> rfdesc;
145: #endif
146: if (!quiet_interface_discovery)
147: log_info ("Sending on NIT/%s%s%s",
148: print_hw_addr (info -> hw_address.hbuf [0],
149: info -> hw_address.hlen - 1,
150: &info -> hw_address.hbuf [1]),
151: (info -> shared_network ? "/" : ""),
152: (info -> shared_network ?
153: info -> shared_network -> name : ""));
154: }
155:
156: void if_deregister_send (info)
157: struct interface_info *info;
158: {
159: /* If we're using the nit API for sending and receiving,
160: we don't need to register this interface twice. */
161: #ifndef USE_NIT_RECEIVE
162: close (info -> wfdesc);
163: #endif
164: info -> wfdesc = -1;
165: if (!quiet_interface_discovery)
166: log_info ("Disabling output on NIT/%s%s%s",
167: print_hw_addr (info -> hw_address.hbuf [0],
168: info -> hw_address.hlen - 1,
169: &info -> hw_address.hbuf [1]),
170: (info -> shared_network ? "/" : ""),
171: (info -> shared_network ?
172: info -> shared_network -> name : ""));
173: }
174: #endif /* USE_NIT_SEND */
175:
176: #ifdef USE_NIT_RECEIVE
177: /* Packet filter program...
178: XXX Changes to the filter program may require changes to the constant
179: offsets used in if_register_send to patch the NIT program! XXX */
180:
181: void if_register_receive (info)
182: struct interface_info *info;
183: {
184: int flag = 1;
185: u_int32_t x;
186: struct packetfilt pf;
187: struct strioctl sio;
188: u_int16_t addr [2];
189: struct timeval t;
190:
191: /* Open a NIT device and hang it on this interface... */
192: info -> rfdesc = if_register_nit (info);
193:
194: /* Set the snap length to 0, which means always take the whole
195: packet. */
196: x = 0;
197: if (ioctl (info -> rfdesc, NIOCSSNAP, &x) < 0)
198: log_fatal ("Can't set NIT snap length on %s: %m", info -> name);
199:
200: /* Set the stream to byte stream mode */
201: if (ioctl (info -> rfdesc, I_SRDOPT, RMSGN) != 0)
202: log_info ("I_SRDOPT failed on %s: %m", info -> name);
203:
204: #if 0
205: /* Push on the chunker... */
206: if (ioctl (info -> rfdesc, I_PUSH, "nbuf") < 0)
207: log_fatal ("Can't push chunker onto NIT STREAM: %m");
208:
209: /* Set the timeout to zero. */
210: t.tv_sec = 0;
211: t.tv_usec = 0;
212: if (ioctl (info -> rfdesc, NIOCSTIME, &t) < 0)
213: log_fatal ("Can't set chunk timeout: %m");
214: #endif
215:
216: /* Ask for no header... */
217: x = 0;
218: if (ioctl (info -> rfdesc, NIOCSFLAGS, &x) < 0)
219: log_fatal ("Can't set NIT flags on %s: %m", info -> name);
220:
221: /* Set up the NIT filter program. */
222: /* XXX Unlike the BPF filter program, this one won't work if the
223: XXX IP packet is fragmented or if there are options on the IP
224: XXX header. */
225: pf.Pf_Priority = 0;
226: pf.Pf_FilterLen = 0;
227:
228: pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 6;
229: pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
230: pf.Pf_Filter [pf.Pf_FilterLen++] = htons (ETHERTYPE_IP);
231: pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT;
232: pf.Pf_Filter [pf.Pf_FilterLen++] = htons (IPPROTO_UDP);
233: pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 11;
234: pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_AND;
235: pf.Pf_Filter [pf.Pf_FilterLen++] = htons (0xFF);
236: pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_CAND;
237: pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 18;
238: pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
239: pf.Pf_Filter [pf.Pf_FilterLen++] = local_port;
240:
241: /* Install the filter... */
242: sio.ic_cmd = NIOCSETF;
243: sio.ic_len = sizeof pf;
244: sio.ic_dp = (char *)&pf;
245: sio.ic_timout = INFTIM;
246: if (ioctl (info -> rfdesc, I_STR, &sio) < 0)
247: log_fatal ("Can't set NIT filter on %s: %m", info -> name);
248:
249: if (!quiet_interface_discovery)
250: log_info ("Listening on NIT/%s%s%s",
251: print_hw_addr (info -> hw_address.hbuf [0],
252: info -> hw_address.hlen - 1,
253: &info -> hw_address.hbuf [1]),
254: (info -> shared_network ? "/" : ""),
255: (info -> shared_network ?
256: info -> shared_network -> name : ""));
257: }
258:
259: void if_deregister_receive (info)
260: struct interface_info *info;
261: {
262: /* If we're using the nit API for sending and receiving,
263: we don't need to register this interface twice. */
264: close (info -> rfdesc);
265: info -> rfdesc = -1;
266:
267: if (!quiet_interface_discovery)
268: log_info ("Disabling input on NIT/%s%s%s",
269: print_hw_addr (info -> hw_address.hbuf [0],
270: info -> hw_address.hlen - 1,
271: &info -> hw_address.hbuf [1]),
272: (info -> shared_network ? "/" : ""),
273: (info -> shared_network ?
274: info -> shared_network -> name : ""));
275: }
276: #endif /* USE_NIT_RECEIVE */
277:
278: #ifdef USE_NIT_SEND
279: ssize_t send_packet (interface, packet, raw, len, from, to, hto)
280: struct interface_info *interface;
281: struct packet *packet;
282: struct dhcp_packet *raw;
283: size_t len;
284: struct in_addr from;
285: struct sockaddr_in *to;
286: struct hardware *hto;
287: {
288: unsigned hbufp, ibufp;
289: double hh [16];
290: double ih [1536 / sizeof (double)];
291: unsigned char *buf = (unsigned char *)ih;
292: struct sockaddr *junk;
293: struct strbuf ctl, data;
294: struct sockaddr_in foo;
295: int result;
296:
297: if (!strcmp (interface -> name, "fallback"))
298: return send_fallback (interface, packet, raw,
299: len, from, to, hto);
300:
301: /* Start with the sockaddr struct... */
302: junk = (struct sockaddr *)&hh [0];
303: hbufp = (((unsigned char *)&junk -> sa_data [0]) -
304: (unsigned char *)&hh[0]);
305: ibufp = 0;
306:
307: /* Assemble the headers... */
308: assemble_hw_header (interface, (unsigned char *)junk, &hbufp, hto);
309: assemble_udp_ip_header (interface, buf, &ibufp,
310: from.s_addr, to -> sin_addr.s_addr,
311: to -> sin_port, (unsigned char *)raw, len);
312:
313: /* Copy the data into the buffer (yuk). */
314: memcpy (buf + ibufp, raw, len);
315:
316: /* Set up the sockaddr structure... */
317: #if USE_SIN_LEN
318: junk -> sa_len = hbufp - 2; /* XXX */
319: #endif
320: junk -> sa_family = AF_UNSPEC;
321:
322: /* Set up the msg_buf structure... */
323: ctl.buf = (char *)&hh [0];
324: ctl.maxlen = ctl.len = hbufp;
325: data.buf = (char *)&ih [0];
326: data.maxlen = data.len = ibufp + len;
327:
328: result = putmsg (interface -> wfdesc, &ctl, &data, 0);
329: if (result < 0)
330: log_error ("send_packet: %m");
331: return result;
332: }
333: #endif /* USE_NIT_SEND */
334:
335: #ifdef USE_NIT_RECEIVE
336: ssize_t receive_packet (interface, buf, len, from, hfrom)
337: struct interface_info *interface;
338: unsigned char *buf;
339: size_t len;
340: struct sockaddr_in *from;
341: struct hardware *hfrom;
342: {
343: int nread;
344: int length = 0;
345: int offset = 0;
346: unsigned char ibuf [1536];
347: int bufix = 0;
348: unsigned paylen;
349:
350: length = read (interface -> rfdesc, ibuf, sizeof ibuf);
351: if (length <= 0)
352: return length;
353:
354: /* Decode the physical header... */
355: offset = decode_hw_header (interface, ibuf, bufix, hfrom);
356:
357: /* If a physical layer checksum failed (dunno of any
358: physical layer that supports this, but WTH), skip this
359: packet. */
360: if (offset < 0) {
361: return 0;
362: }
363:
364: bufix += offset;
365: length -= offset;
366:
367: /* Decode the IP and UDP headers... */
368: offset = decode_udp_ip_header (interface, ibuf, bufix,
369: from, length, &paylen);
370:
371: /* If the IP or UDP checksum was bad, skip the packet... */
372: if (offset < 0)
373: return 0;
374:
375: bufix += offset;
376: length -= offset;
377:
378: if (length < paylen)
379: log_fatal("Internal inconsistency at %s:%d.", MDL);
380:
381: /* Copy out the data in the packet... */
382: memcpy(buf, &ibuf[bufix], paylen);
383: return paylen;
384: }
385:
386: int can_unicast_without_arp (ip)
387: struct interface_info *ip;
388: {
389: return 1;
390: }
391:
392: int can_receive_unicast_unconfigured (ip)
393: struct interface_info *ip;
394: {
395: return 1;
396: }
397:
398: int supports_multiple_interfaces (ip)
399: struct interface_info *ip;
400: {
401: return 1;
402: }
403:
404: void maybe_setup_fallback ()
405: {
406: isc_result_t status;
407: struct interface_info *fbi = (struct interface_info *)0;
408: if (setup_fallback (&fbi, MDL)) {
409: if_register_fallback (fbi);
410: status = omapi_register_io_object ((omapi_object_t *)fbi,
411: if_readsocket, 0,
412: fallback_discard, 0, 0);
413: if (status != ISC_R_SUCCESS)
414: log_fatal ("Can't register I/O handle for %s: %s",
415: fbi -> name, isc_result_totext (status));
416: interface_dereference (&fbi, MDL);
417: }
418: }
419: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>