1 /* lpf.c
2 
3    Linux packet filter code, contributed by Brian Murrel at Interlinx
4    Support Services in Vancouver, B.C. */
5 
6 /*
7  * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
8  * Copyright (c) 1996-2003 by Internet Software Consortium
9  *
10  * This Source Code Form is subject to the terms of the Mozilla Public
11  * License, v. 2.0. If a copy of the MPL was not distributed with this
12  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
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 
29 #include "dhcpd.h"
30 #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE)
31 #include <sys/uio.h>
32 #include <errno.h>
33 
34 #include <asm/types.h>
35 #include <linux/filter.h>
36 #include <linux/if_ether.h>
37 #include <linux/if_packet.h>
38 #include <netinet/in_systm.h>
39 #include "includes/netinet/ip.h"
40 #include "includes/netinet/udp.h"
41 #include "includes/netinet/if_ether.h"
42 #endif
43 
44 #if defined (USE_LPF_RECEIVE) || defined (USE_LPF_HWADDR)
45 #include <sys/ioctl.h>
46 #include <sys/socket.h>
47 #include <net/if.h>
48 #endif
49 
50 #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE)
51 /* Reinitializes the specified interface after an address change.   This
52    is not required for packet-filter APIs. */
53 
54 #ifdef USE_LPF_SEND
if_reinitialize_send(info)55 void if_reinitialize_send (info)
56 	struct interface_info *info;
57 {
58 }
59 #endif
60 
61 #ifdef USE_LPF_RECEIVE
if_reinitialize_receive(info)62 void if_reinitialize_receive (info)
63 	struct interface_info *info;
64 {
65 }
66 #endif
67 
68 /* Called by get_interface_list for each interface that's discovered.
69    Opens a packet filter for each interface and adds it to the select
70    mask. */
71 
if_register_lpf(info)72 int if_register_lpf (info)
73 	struct interface_info *info;
74 {
75 	int sock;
76 	union {
77 		struct sockaddr_ll ll;
78 		struct sockaddr common;
79 		} sa;
80 	struct ifreq ifr;
81 
82 	/* Make an LPF socket. */
83 	if ((sock = socket(PF_PACKET, SOCK_RAW,
84 			   htons((short)ETH_P_ALL))) < 0) {
85 		if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
86 		    errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
87 		    errno == EAFNOSUPPORT || errno == EINVAL) {
88 			log_error ("socket: %m - make sure");
89 			log_error ("CONFIG_PACKET (Packet socket) %s",
90 				   "and CONFIG_FILTER");
91 			log_error ("(Socket Filtering) are enabled %s",
92 				   "in your kernel");
93 			log_fatal ("configuration!");
94 		}
95 		log_fatal ("Open a socket for LPF: %m");
96 	}
97 
98 	memset (&ifr, 0, sizeof ifr);
99 	strncpy (ifr.ifr_name, (const char *)info -> ifp, sizeof ifr.ifr_name);
100 	ifr.ifr_name[IFNAMSIZ-1] = '\0';
101 	if (ioctl (sock, SIOCGIFINDEX, &ifr))
102 		log_fatal ("Failed to get interface index: %m");
103 
104 	/* Bind to the interface name */
105 	memset (&sa, 0, sizeof sa);
106 	sa.ll.sll_family = AF_PACKET;
107 	sa.ll.sll_ifindex = ifr.ifr_ifindex;
108 	if (bind (sock, &sa.common, sizeof sa)) {
109 		if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
110 		    errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
111 		    errno == EAFNOSUPPORT || errno == EINVAL) {
112 			log_error ("socket: %m - make sure");
113 			log_error ("CONFIG_PACKET (Packet socket) %s",
114 				   "and CONFIG_FILTER");
115 			log_error ("(Socket Filtering) are enabled %s",
116 				   "in your kernel");
117 			log_fatal ("configuration!");
118 		}
119 		log_fatal ("Bind socket to interface: %m");
120 
121 	}
122 
123 	get_hw_addr(info->name, &info->hw_address);
124 
125 	return sock;
126 }
127 #endif /* USE_LPF_SEND || USE_LPF_RECEIVE */
128 
129 #ifdef USE_LPF_SEND
if_register_send(info)130 void if_register_send (info)
131 	struct interface_info *info;
132 {
133 	/* If we're using the lpf API for sending and receiving,
134 	   we don't need to register this interface twice. */
135 #ifndef USE_LPF_RECEIVE
136 	info -> wfdesc = if_register_lpf (info);
137 #else
138 	info -> wfdesc = info -> rfdesc;
139 #endif
140 	if (!quiet_interface_discovery)
141 		log_info ("Sending on   LPF/%s/%s%s%s",
142 		      info -> name,
143 		      print_hw_addr (info -> hw_address.hbuf [0],
144 				     info -> hw_address.hlen - 1,
145 				     &info -> hw_address.hbuf [1]),
146 		      (info -> shared_network ? "/" : ""),
147 		      (info -> shared_network ?
148 		       info -> shared_network -> name : ""));
149 }
150 
if_deregister_send(info)151 void if_deregister_send (info)
152 	struct interface_info *info;
153 {
154 	/* don't need to close twice if we are using lpf for sending and
155 	   receiving */
156 #ifndef USE_LPF_RECEIVE
157 	/* for LPF this is simple, packet filters are removed when sockets
158 	   are closed */
159 	close (info -> wfdesc);
160 #endif
161 	info -> wfdesc = -1;
162 	if (!quiet_interface_discovery)
163 		log_info ("Disabling output on LPF/%s/%s%s%s",
164 		      info -> name,
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_LPF_SEND */
173 
174 #ifdef USE_LPF_RECEIVE
175 /* Defined in bpf.c.   We can't extern these in dhcpd.h without pulling
176    in bpf includes... */
177 extern struct sock_filter dhcp_bpf_filter [];
178 extern int dhcp_bpf_filter_len;
179 
180 #if defined(RELAY_PORT)
181 extern struct sock_filter dhcp_bpf_relay_filter [];
182 extern int dhcp_bpf_relay_filter_len;
183 #endif
184 
185 #if defined (HAVE_TR_SUPPORT)
186 extern struct sock_filter dhcp_bpf_tr_filter [];
187 extern int dhcp_bpf_tr_filter_len;
188 static void lpf_tr_filter_setup (struct interface_info *);
189 #endif
190 
191 static void lpf_gen_filter_setup (struct interface_info *);
192 
if_register_receive(info)193 void if_register_receive (info)
194 	struct interface_info *info;
195 {
196 	/* Open a LPF device and hang it on this interface... */
197 	info -> rfdesc = if_register_lpf (info);
198 
199 #ifdef PACKET_AUXDATA
200 	{
201 	int val = 1;
202 
203 	if (setsockopt(info->rfdesc, SOL_PACKET, PACKET_AUXDATA,
204 		       &val, sizeof(val)) < 0) {
205 		if (errno != ENOPROTOOPT) {
206 			log_fatal ("Failed to set auxiliary packet data: %m");
207 		}
208 	}
209 	}
210 #endif
211 
212 
213 #if defined (HAVE_TR_SUPPORT)
214 	if (info -> hw_address.hbuf [0] == HTYPE_IEEE802)
215 		lpf_tr_filter_setup (info);
216 	else
217 #endif
218 		lpf_gen_filter_setup (info);
219 
220 	if (!quiet_interface_discovery)
221 		log_info ("Listening on LPF/%s/%s%s%s",
222 			  info -> name,
223 			  print_hw_addr (info -> hw_address.hbuf [0],
224 					 info -> hw_address.hlen - 1,
225 					 &info -> hw_address.hbuf [1]),
226 			  (info -> shared_network ? "/" : ""),
227 			  (info -> shared_network ?
228 			   info -> shared_network -> name : ""));
229 }
230 
if_deregister_receive(info)231 void if_deregister_receive (info)
232 	struct interface_info *info;
233 {
234 	/* for LPF this is simple, packet filters are removed when sockets
235 	   are closed */
236 	close (info -> rfdesc);
237 	info -> rfdesc = -1;
238 	if (!quiet_interface_discovery)
239 		log_info ("Disabling input on LPF/%s/%s%s%s",
240 			  info -> name,
241 			  print_hw_addr (info -> hw_address.hbuf [0],
242 					 info -> hw_address.hlen - 1,
243 					 &info -> hw_address.hbuf [1]),
244 			  (info -> shared_network ? "/" : ""),
245 			  (info -> shared_network ?
246 			   info -> shared_network -> name : ""));
247 }
248 
lpf_gen_filter_setup(info)249 static void lpf_gen_filter_setup (info)
250 	struct interface_info *info;
251 {
252 	struct sock_fprog p;
253 
254 	memset(&p, 0, sizeof(p));
255 
256 	/* Set up the bpf filter program structure.    This is defined in
257 	   bpf.c */
258 	p.len = dhcp_bpf_filter_len;
259 	p.filter = dhcp_bpf_filter;
260 
261         /* Patch the server port into the LPF  program...
262 	   XXX changes to filter program may require changes
263 	   to the insn number(s) used below! XXX */
264 #if defined(RELAY_PORT)
265 	if (relay_port) {
266 		/*
267 		 * If user defined relay UDP port, we need to filter
268 		 * also on the user UDP port.
269 		 */
270 		p.len = dhcp_bpf_relay_filter_len;
271 		p.filter = dhcp_bpf_relay_filter;
272 
273 		dhcp_bpf_relay_filter [10].k = ntohs (relay_port);
274 	}
275 #endif
276 	dhcp_bpf_filter [8].k = ntohs (local_port);
277 
278 	if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
279 			sizeof p) < 0) {
280 		if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
281 		    errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
282 		    errno == EAFNOSUPPORT) {
283 			log_error ("socket: %m - make sure");
284 			log_error ("CONFIG_PACKET (Packet socket) %s",
285 				   "and CONFIG_FILTER");
286 			log_error ("(Socket Filtering) are enabled %s",
287 				   "in your kernel");
288 			log_fatal ("configuration!");
289 		}
290 		log_fatal ("Can't install packet filter program: %m");
291 	}
292 }
293 
294 #if defined (HAVE_TR_SUPPORT)
lpf_tr_filter_setup(info)295 static void lpf_tr_filter_setup (info)
296 	struct interface_info *info;
297 {
298 	struct sock_fprog p;
299 
300 	memset(&p, 0, sizeof(p));
301 
302 	/* Set up the bpf filter program structure.    This is defined in
303 	   bpf.c */
304 	p.len = dhcp_bpf_tr_filter_len;
305 	p.filter = dhcp_bpf_tr_filter;
306 
307         /* Patch the server port into the LPF  program...
308 	   XXX changes to filter program may require changes
309 	   XXX to the insn number(s) used below!
310 	   XXX Token ring filter is null - when/if we have a filter
311 	   XXX that's not, we'll need this code.
312 	   XXX dhcp_bpf_filter [?].k = ntohs (local_port); */
313 
314 	if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
315 			sizeof p) < 0) {
316 		if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
317 		    errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
318 		    errno == EAFNOSUPPORT) {
319 			log_error ("socket: %m - make sure");
320 			log_error ("CONFIG_PACKET (Packet socket) %s",
321 				   "and CONFIG_FILTER");
322 			log_error ("(Socket Filtering) are enabled %s",
323 				   "in your kernel");
324 			log_fatal ("configuration!");
325 		}
326 		log_fatal ("Can't install packet filter program: %m");
327 	}
328 }
329 #endif /* HAVE_TR_SUPPORT */
330 #endif /* USE_LPF_RECEIVE */
331 
332 #ifdef USE_LPF_SEND
send_packet(interface,packet,raw,len,from,to,hto)333 ssize_t send_packet (interface, packet, raw, len, from, to, hto)
334 	struct interface_info *interface;
335 	struct packet *packet;
336 	struct dhcp_packet *raw;
337 	size_t len;
338 	struct in_addr from;
339 	struct sockaddr_in *to;
340 	struct hardware *hto;
341 {
342 	unsigned hbufp = 0, ibufp = 0;
343 	double hh [16];
344 	double ih [1536 / sizeof (double)];
345 	unsigned char *buf = (unsigned char *)ih;
346 	int result;
347 	int fudge;
348 
349 	if (!strcmp (interface -> name, "fallback"))
350 		return send_fallback (interface, packet, raw,
351 				      len, from, to, hto);
352 
353 	if (hto == NULL && interface->anycast_mac_addr.hlen)
354 		hto = &interface->anycast_mac_addr;
355 
356 	/* Assemble the headers... */
357 	assemble_hw_header (interface, (unsigned char *)hh, &hbufp, hto);
358 	fudge = hbufp % 4;	/* IP header must be word-aligned. */
359 	memcpy (buf + fudge, (unsigned char *)hh, hbufp);
360 	ibufp = hbufp + fudge;
361 	assemble_udp_ip_header (interface, buf, &ibufp, from.s_addr,
362 				to -> sin_addr.s_addr, to -> sin_port,
363 				(unsigned char *)raw, len);
364 	memcpy (buf + ibufp, raw, len);
365 	result = write(interface->wfdesc, buf + fudge, ibufp + len - fudge);
366 	if (result < 0)
367 		log_error ("send_packet: %m");
368 	return result;
369 }
370 #endif /* USE_LPF_SEND */
371 
372 #ifdef USE_LPF_RECEIVE
receive_packet(interface,buf,len,from,hfrom)373 ssize_t receive_packet (interface, buf, len, from, hfrom)
374 	struct interface_info *interface;
375 	unsigned char *buf;
376 	size_t len;
377 	struct sockaddr_in *from;
378 	struct hardware *hfrom;
379 {
380 	int length = 0;
381 	int offset = 0;
382 	int csum_ready = 1;
383 	unsigned char ibuf [1536];
384 	unsigned bufix = 0;
385 	unsigned paylen;
386 	struct iovec iov = {
387 		.iov_base = ibuf,
388 		.iov_len = sizeof ibuf,
389 	};
390 #ifdef PACKET_AUXDATA
391 	/*
392 	 * We only need cmsgbuf if we are getting the aux data and we
393 	 * only get the auxdata if it is actually defined
394 	 */
395 	unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
396 	struct msghdr msg = {
397 		.msg_iov = &iov,
398 		.msg_iovlen = 1,
399 		.msg_control = cmsgbuf,
400 		.msg_controllen = sizeof(cmsgbuf),
401 	};
402 #else
403 	struct msghdr msg = {
404 		.msg_iov = &iov,
405 		.msg_iovlen = 1,
406 		.msg_control = NULL,
407 		.msg_controllen = 0,
408 	};
409 #endif /* PACKET_AUXDATA */
410 
411 	length = recvmsg (interface->rfdesc, &msg, 0);
412 	if (length <= 0)
413 		return length;
414 
415 #ifdef PACKET_AUXDATA
416 	{
417 	/*  Use auxiliary packet data to:
418 	 *
419 	 *  a. Weed out extraneous VLAN-tagged packets - If the NIC driver is
420 	 *  handling VLAN encapsulation (i.e. stripping/adding VLAN tags),
421 	 *  then an inbound VLAN packet will be seen twice: Once by
422 	 *  the parent interface (e.g. eth0) with a VLAN tag != 0; and once
423 	 *  by the vlan interface (e.g. eth0.n) with a VLAN tag of 0 (i.e none).
424 	 *  We want to discard the packet sent to the parent and thus respond
425 	 *  only over the vlan interface.  (Drivers for Intel PRO/1000 series
426 	 *  NICs perform VLAN encapsulation, while drivers for PCnet series
427 	 *  do not, for example. The linux kernel makes stripped vlan info
428 	 *  visible to user space via CMSG/auxdata, this appears to not be
429 	 *  true for BSD OSs.).  NOTE: this is only supported on linux flavors
430 	 *  which define the tpacket_auxdata.tp_vlan_tci.
431 	 *
432 	 *  b. Determine if checksum is valid for use. It may not be if
433 	 *  checksum offloading is enabled on the interface.  */
434 	struct cmsghdr *cmsg;
435 
436 	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
437 		if (cmsg->cmsg_level == SOL_PACKET &&
438 		    cmsg->cmsg_type == PACKET_AUXDATA) {
439 			struct tpacket_auxdata *aux = (void *)CMSG_DATA(cmsg);
440 #ifdef VLAN_TCI_PRESENT
441 			/* Discard packets with stripped vlan id */
442 			/* VLAN ID is only bottom 12-bits of TCI */
443 			if (aux->tp_vlan_tci & 0x0fff)
444 				return 0;
445 #endif
446 
447 			csum_ready = ((aux->tp_status & TP_STATUS_CSUMNOTREADY)
448 				      ? 0 : 1);
449 		}
450 	}
451 
452 	}
453 #endif /* PACKET_AUXDATA */
454 
455 	bufix = 0;
456 	/* Decode the physical header... */
457 	offset = decode_hw_header (interface, ibuf, bufix, hfrom);
458 
459 	/* If a physical layer checksum failed (dunno of any
460 	   physical layer that supports this, but WTH), skip this
461 	   packet. */
462 	if (offset < 0) {
463 		return 0;
464 	}
465 
466 	bufix += offset;
467 	length -= offset;
468 
469 	/* Decode the IP and UDP headers... */
470 	offset = decode_udp_ip_header (interface, ibuf, bufix, from,
471 				       (unsigned)length, &paylen, csum_ready);
472 
473 	/* If the IP or UDP checksum was bad, skip the packet... */
474 	if (offset < 0)
475 		return 0;
476 
477 	bufix += offset;
478 	length -= offset;
479 
480 	if (length < paylen)
481 		log_fatal("Internal inconsistency at %s:%d.", MDL);
482 
483 	/* Copy out the data in the packet... */
484 	memcpy(buf, &ibuf[bufix], paylen);
485 	return paylen;
486 }
487 
can_unicast_without_arp(ip)488 int can_unicast_without_arp (ip)
489 	struct interface_info *ip;
490 {
491 	return 1;
492 }
493 
can_receive_unicast_unconfigured(ip)494 int can_receive_unicast_unconfigured (ip)
495 	struct interface_info *ip;
496 {
497 	return 1;
498 }
499 
supports_multiple_interfaces(ip)500 int supports_multiple_interfaces (ip)
501 	struct interface_info *ip;
502 {
503 	return 1;
504 }
505 
maybe_setup_fallback()506 void maybe_setup_fallback ()
507 {
508 	isc_result_t status;
509 	struct interface_info *fbi = (struct interface_info *)0;
510 	if (setup_fallback (&fbi, MDL)) {
511 		if_register_fallback (fbi);
512 		status = omapi_register_io_object ((omapi_object_t *)fbi,
513 						   if_readsocket, 0,
514 						   fallback_discard, 0, 0);
515 		if (status != ISC_R_SUCCESS)
516 			log_fatal ("Can't register I/O handle for \"%s\": %s",
517 				   fbi -> name, isc_result_totext (status));
518 		interface_dereference (&fbi, MDL);
519 	}
520 }
521 #endif
522 
523 #if defined (USE_LPF_RECEIVE) || defined (USE_LPF_HWADDR)
524 void
get_hw_addr(const char * name,struct hardware * hw)525 get_hw_addr(const char *name, struct hardware *hw) {
526 	int sock;
527 	struct ifreq tmp;
528 	struct sockaddr *sa;
529 
530 	if (strlen(name) >= sizeof(tmp.ifr_name)) {
531 		log_fatal("Device name too long: \"%s\"", name);
532 	}
533 
534 	sock = socket(AF_INET, SOCK_DGRAM, 0);
535 	if (sock < 0) {
536 		log_fatal("Can't create socket for \"%s\": %m", name);
537 	}
538 
539 	memset(&tmp, 0, sizeof(tmp));
540 	strcpy(tmp.ifr_name, name);
541 	if (ioctl(sock, SIOCGIFHWADDR, &tmp) < 0) {
542 		log_fatal("Error getting hardware address for \"%s\": %m",
543 			  name);
544 	}
545 
546 	sa = &tmp.ifr_hwaddr;
547 	switch (sa->sa_family) {
548 		case ARPHRD_ETHER:
549 			hw->hlen = 7;
550 			hw->hbuf[0] = HTYPE_ETHER;
551 			memcpy(&hw->hbuf[1], sa->sa_data, 6);
552 			break;
553 		case ARPHRD_IEEE802:
554 #ifdef ARPHRD_IEEE802_TR
555 		case ARPHRD_IEEE802_TR:
556 #endif /* ARPHRD_IEEE802_TR */
557 			hw->hlen = 7;
558 			hw->hbuf[0] = HTYPE_IEEE802;
559 			memcpy(&hw->hbuf[1], sa->sa_data, 6);
560 			break;
561 		case ARPHRD_FDDI:
562 			hw->hlen = 7;
563 			hw->hbuf[0] = HTYPE_FDDI;
564 			memcpy(&hw->hbuf[1], sa->sa_data, 6);
565 			break;
566 		default:
567 			log_fatal("Unsupported device type %ld for \"%s\"",
568 				  (long int)sa->sa_family, name);
569 	}
570 
571 	close(sock);
572 }
573 #endif
574