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