]> git.ipfire.org Git - thirdparty/dhcp.git/blob - common/lpf.c
1e4deff6310274907bec5d357e12efc0c650f4cb
[thirdparty/dhcp.git] / common / lpf.c
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 * PO Box 360
24 * Newmarket, NH 03857 USA
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
55 void if_reinitialize_send (info)
56 struct interface_info *info;
57 {
58 }
59 #endif
60
61 #ifdef USE_LPF_RECEIVE
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
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
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
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
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
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
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)
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
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
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
488 int can_unicast_without_arp (ip)
489 struct interface_info *ip;
490 {
491 return 1;
492 }
493
494 int can_receive_unicast_unconfigured (ip)
495 struct interface_info *ip;
496 {
497 return 1;
498 }
499
500 int supports_multiple_interfaces (ip)
501 struct interface_info *ip;
502 {
503 return 1;
504 }
505
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
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