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