ISC DHCP 4.4.3-P1
A reference DHCPv4 and DHCPv6 implementation
 
Loading...
Searching...
No Matches
lpf.c
Go to the documentation of this file.
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-2022 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"
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#include <ifaddrs.h>
49
50/* Default broadcast address for IPoIB */
51static unsigned char default_ib_bcast_addr[20] = {
52 0x00, 0xff, 0xff, 0xff,
53 0xff, 0x12, 0x40, 0x1b,
54 0x00, 0x00, 0x00, 0x00,
55 0x00, 0x00, 0x00, 0x00,
56 0xff, 0xff, 0xff, 0xff
57};
58
59#endif
60
61#if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE)
62/* Reinitializes the specified interface after an address change. This
63 is not required for packet-filter APIs. */
64
65#ifdef USE_LPF_SEND
66void if_reinitialize_send (info)
67 struct interface_info *info;
68{
69}
70#endif
71
72#ifdef USE_LPF_RECEIVE
74 struct interface_info *info;
75{
76}
77#endif
78
79/* Called by get_interface_list for each interface that's discovered.
80 Opens a packet filter for each interface and adds it to the select
81 mask. */
82
83int if_register_lpf (info)
84 struct interface_info *info;
85{
86 int sock;
87 union {
88 struct sockaddr_ll ll;
89 struct sockaddr common;
90 } sa;
91 struct ifreq ifr;
92 int type;
93 int protocol;
94
95 get_hw_addr(info);
96 if (info->hw_address.hbuf[0] == HTYPE_INFINIBAND) {
97 type = SOCK_DGRAM;
99 } else {
100 type = SOCK_RAW;
101 protocol = ETH_P_ALL;
102 }
103
104 /* Make an LPF socket. */
105 if ((sock = socket(PF_PACKET, type, htons((short)protocol))) < 0) {
106 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
107 errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
108 errno == EAFNOSUPPORT || errno == EINVAL) {
109 log_error ("socket: %m - make sure");
110 log_error ("CONFIG_PACKET (Packet socket) %s",
111 "and CONFIG_FILTER");
112 log_error ("(Socket Filtering) are enabled %s",
113 "in your kernel");
114 log_fatal ("configuration!");
115 }
116 log_fatal ("Open a socket for LPF: %m");
117 }
118
119 memset (&ifr, 0, sizeof ifr);
120 strncpy (ifr.ifr_name, (const char *)info -> ifp, sizeof ifr.ifr_name);
121 ifr.ifr_name[IFNAMSIZ-1] = '\0';
122 if (ioctl (sock, SIOCGIFINDEX, &ifr))
123 log_fatal ("Failed to get interface index: %m");
124
125 /* Bind to the interface name */
126 memset (&sa, 0, sizeof sa);
127 sa.ll.sll_family = AF_PACKET;
128 sa.ll.sll_protocol = htons(protocol);
129 sa.ll.sll_ifindex = ifr.ifr_ifindex;
130 if (bind (sock, &sa.common, sizeof sa)) {
131 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
132 errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
133 errno == EAFNOSUPPORT || errno == EINVAL) {
134 log_error ("socket: %m - make sure");
135 log_error ("CONFIG_PACKET (Packet socket) %s",
136 "and CONFIG_FILTER");
137 log_error ("(Socket Filtering) are enabled %s",
138 "in your kernel");
139 log_fatal ("configuration!");
140 }
141 log_fatal ("Bind socket to interface: %m");
142
143 }
144
145 return sock;
146}
147#endif /* USE_LPF_SEND || USE_LPF_RECEIVE */
148
149#ifdef USE_LPF_SEND
150void if_register_send (info)
151 struct interface_info *info;
152{
153 /* If we're using the lpf API for sending and receiving,
154 we don't need to register this interface twice. */
155#ifndef USE_LPF_RECEIVE
156 info -> wfdesc = if_register_lpf (info);
157#else
158 info -> wfdesc = info -> rfdesc;
159#endif
161 log_info ("Sending on LPF/%s/%s%s%s",
162 info -> name,
163 print_hw_addr (info -> hw_address.hbuf [0],
164 info -> hw_address.hlen - 1,
165 &info -> hw_address.hbuf [1]),
166 (info -> shared_network ? "/" : ""),
167 (info -> shared_network ?
168 info -> shared_network -> name : ""));
169}
170
171void if_deregister_send (info)
172 struct interface_info *info;
173{
174 /* don't need to close twice if we are using lpf for sending and
175 receiving */
176#ifndef USE_LPF_RECEIVE
177 /* for LPF this is simple, packet filters are removed when sockets
178 are closed */
179 close (info -> wfdesc);
180#endif
181 info -> wfdesc = -1;
183 log_info ("Disabling output on LPF/%s/%s%s%s",
184 info -> name,
185 print_hw_addr (info -> hw_address.hbuf [0],
186 info -> hw_address.hlen - 1,
187 &info -> hw_address.hbuf [1]),
188 (info -> shared_network ? "/" : ""),
189 (info -> shared_network ?
190 info -> shared_network -> name : ""));
191}
192#endif /* USE_LPF_SEND */
193
194#ifdef USE_LPF_RECEIVE
195/* Defined in bpf.c. We can't extern these in dhcpd.h without pulling
196 in bpf includes... */
197extern struct sock_filter dhcp_bpf_filter [];
198extern int dhcp_bpf_filter_len;
199extern struct sock_filter dhcp_ib_bpf_filter [];
200extern int dhcp_ib_bpf_filter_len;
201
202#if defined(RELAY_PORT)
203extern struct sock_filter dhcp_bpf_relay_filter [];
204extern int dhcp_bpf_relay_filter_len;
205#endif
206
207#if defined (HAVE_TR_SUPPORT)
208extern struct sock_filter dhcp_bpf_tr_filter [];
209extern int dhcp_bpf_tr_filter_len;
210static void lpf_tr_filter_setup (struct interface_info *);
211#endif
212
213static void lpf_gen_filter_setup (struct interface_info *);
214
215void if_register_receive (info)
216 struct interface_info *info;
217{
218 /* Open a LPF device and hang it on this interface... */
219 info -> rfdesc = if_register_lpf (info);
220
221#ifdef PACKET_AUXDATA
222 {
223 int val = 1;
224 if (info->hw_address.hbuf[0] != HTYPE_INFINIBAND) {
225 if (setsockopt(info->rfdesc, SOL_PACKET, PACKET_AUXDATA,
226 &val, sizeof(val)) < 0) {
227 if (errno != ENOPROTOOPT) {
228 log_fatal ("Failed to set auxiliary packet data: %m");
229 }
230 }
231 }
232 }
233#endif
234
235
236#if defined (HAVE_TR_SUPPORT)
237 if (info -> hw_address.hbuf [0] == HTYPE_IEEE802)
238 lpf_tr_filter_setup (info);
239 else
240#endif
241 lpf_gen_filter_setup (info);
242
244 log_info ("Listening 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
254void if_deregister_receive (info)
255 struct interface_info *info;
256{
257 /* for LPF this is simple, packet filters are removed when sockets
258 are closed */
259 close (info -> rfdesc);
260 info -> rfdesc = -1;
262 log_info ("Disabling input on LPF/%s/%s%s%s",
263 info -> name,
264 print_hw_addr (info -> hw_address.hbuf [0],
265 info -> hw_address.hlen - 1,
266 &info -> hw_address.hbuf [1]),
267 (info -> shared_network ? "/" : ""),
268 (info -> shared_network ?
269 info -> shared_network -> name : ""));
270}
271
272static void lpf_gen_filter_setup (info)
273 struct interface_info *info;
274{
275 struct sock_fprog p;
276
277 memset(&p, 0, sizeof(p));
278
279 if (info->hw_address.hbuf[0] == HTYPE_INFINIBAND) {
280 p.len = dhcp_ib_bpf_filter_len;
281 p.filter = dhcp_ib_bpf_filter;
282
283 /* Patch the server port into the LPF program...
284 XXX
285 changes to filter program may require changes
286 to the insn number(s) used below!
287 XXX */
288 dhcp_ib_bpf_filter[6].k = ntohs (local_port);
289 } else {
290
291 /* Set up the bpf filter program structure. This is defined in
292 bpf.c */
293 p.len = dhcp_bpf_filter_len;
294 p.filter = dhcp_bpf_filter;
295
296 /* Patch the server port into the LPF program...
297 XXX changes to filter program may require changes
298 to the insn number(s) used below! XXX */
299#if defined(RELAY_PORT)
300 if (relay_port) {
301 /*
302 * If user defined relay UDP port, we need to filter
303 * also on the user UDP port.
304 */
305 p.len = dhcp_bpf_relay_filter_len;
306 p.filter = dhcp_bpf_relay_filter;
307
308 dhcp_bpf_relay_filter [10].k = ntohs (relay_port);
309 }
310#endif
311 dhcp_bpf_filter [8].k = ntohs (local_port);
312
313 }
314
315 if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
316 sizeof p) < 0) {
317 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
318 errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
319 errno == EAFNOSUPPORT) {
320 log_error ("socket: %m - make sure");
321 log_error ("CONFIG_PACKET (Packet socket) %s",
322 "and CONFIG_FILTER");
323 log_error ("(Socket Filtering) are enabled %s",
324 "in your kernel");
325 log_fatal ("configuration!");
326 }
327 log_fatal ("Can't install packet filter program: %m");
328 }
329}
330
331#if defined (HAVE_TR_SUPPORT)
332static void lpf_tr_filter_setup (info)
333 struct interface_info *info;
334{
335 struct sock_fprog p;
336
337 memset(&p, 0, sizeof(p));
338
339 /* Set up the bpf filter program structure. This is defined in
340 bpf.c */
341 p.len = dhcp_bpf_tr_filter_len;
342 p.filter = dhcp_bpf_tr_filter;
343
344 /* Patch the server port into the LPF program...
345 XXX changes to filter program may require changes
346 XXX to the insn number(s) used below!
347 XXX Token ring filter is null - when/if we have a filter
348 XXX that's not, we'll need this code.
349 XXX dhcp_bpf_filter [?].k = ntohs (local_port); */
350
351 if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
352 sizeof p) < 0) {
353 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
354 errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
355 errno == EAFNOSUPPORT) {
356 log_error ("socket: %m - make sure");
357 log_error ("CONFIG_PACKET (Packet socket) %s",
358 "and CONFIG_FILTER");
359 log_error ("(Socket Filtering) are enabled %s",
360 "in your kernel");
361 log_fatal ("configuration!");
362 }
363 log_fatal ("Can't install packet filter program: %m");
364 }
365}
366#endif /* HAVE_TR_SUPPORT */
367#endif /* USE_LPF_RECEIVE */
368
369#ifdef USE_LPF_SEND
370ssize_t send_packet_ib(interface, packet, raw, len, from, to, hto)
371 struct interface_info *interface;
372 struct packet *packet;
373 struct dhcp_packet *raw;
374 size_t len;
375 struct in_addr from;
376 struct sockaddr_in *to;
377 struct hardware *hto;
378{
379 unsigned ibufp = 0;
380 double ih [1536 / sizeof (double)];
381 unsigned char *buf = (unsigned char *)ih;
382 ssize_t result;
383
384 union sockunion {
385 struct sockaddr sa;
386 struct sockaddr_ll sll;
387 struct sockaddr_storage ss;
388 } su;
389
390 assemble_udp_ip_header (interface, buf, &ibufp, from.s_addr,
391 to->sin_addr.s_addr, to->sin_port,
392 (unsigned char *)raw, len);
393 memcpy (buf + ibufp, raw, len);
394
395 memset(&su, 0, sizeof(su));
396 su.sll.sll_family = AF_PACKET;
397 su.sll.sll_protocol = htons(ETHERTYPE_IP);
398
399 if (!(su.sll.sll_ifindex = if_nametoindex(interface->name))) {
400 errno = ENOENT;
401 log_error ("send_packet_ib: %m - failed to get if index");
402 return -1;
403 }
404
405 su.sll.sll_hatype = htons(HTYPE_INFINIBAND);
406 su.sll.sll_halen = sizeof(interface->bcast_addr);
407 memcpy(&su.sll.sll_addr, interface->bcast_addr, 20);
408
409 result = sendto(interface->wfdesc, buf, ibufp + len, 0,
410 &su.sa, sizeof(su));
411
412 if (result < 0)
413 log_error ("send_packet_ib: %m");
414
415 return result;
416}
417
418ssize_t send_packet (interface, packet, raw, len, from, to, hto)
419 struct interface_info *interface;
420 struct packet *packet;
421 struct dhcp_packet *raw;
422 size_t len;
423 struct in_addr from;
424 struct sockaddr_in *to;
425 struct hardware *hto;
426{
427 unsigned hbufp = 0, ibufp = 0;
428 double hh [16];
429 double ih [1536 / sizeof (double)];
430 unsigned char *buf = (unsigned char *)ih;
431 int result;
432 int fudge;
433
434 if (!strcmp (interface -> name, "fallback"))
435 return send_fallback (interface, packet, raw,
436 len, from, to, hto);
437
438 if (interface->hw_address.hbuf[0] == HTYPE_INFINIBAND) {
439 return send_packet_ib(interface, packet, raw, len, from,
440 to, hto);
441 }
442
443 if (hto == NULL && interface->anycast_mac_addr.hlen)
444 hto = &interface->anycast_mac_addr;
445
446 /* Assemble the headers... */
447 assemble_hw_header (interface, (unsigned char *)hh, &hbufp, hto);
448 fudge = hbufp % 4; /* IP header must be word-aligned. */
449 memcpy (buf + fudge, (unsigned char *)hh, hbufp);
450 ibufp = hbufp + fudge;
451 assemble_udp_ip_header (interface, buf, &ibufp, from.s_addr,
452 to -> sin_addr.s_addr, to -> sin_port,
453 (unsigned char *)raw, len);
454 memcpy (buf + ibufp, raw, len);
455 result = write(interface->wfdesc, buf + fudge, ibufp + len - fudge);
456 if (result < 0)
457 log_error ("send_packet: %m");
458 return result;
459}
460#endif /* USE_LPF_SEND */
461
462#ifdef USE_LPF_RECEIVE
463ssize_t receive_packet_ib (interface, buf, len, from, hfrom)
464 struct interface_info *interface;
465 unsigned char *buf;
466 size_t len;
467 struct sockaddr_in *from;
468 struct hardware *hfrom;
469{
470 int length = 0;
471 int offset = 0;
472 unsigned char ibuf [1536];
473 unsigned bufix = 0;
474 unsigned paylen;
475
476 length = read(interface->rfdesc, ibuf, sizeof(ibuf));
477
478 if (length <= 0)
479 return length;
480
481 offset = decode_udp_ip_header(interface, ibuf, bufix, from,
482 (unsigned)length, &paylen, 0);
483
484 if (offset < 0)
485 return 0;
486
487 bufix += offset;
488 length -= offset;
489
490 if (length < paylen)
491 log_fatal("Internal inconsistency at %s:%d.", MDL);
492
493 /* Copy out the data in the packet... */
494 memcpy(buf, &ibuf[bufix], paylen);
495
496 return (ssize_t)paylen;
497}
498
499ssize_t receive_packet (interface, buf, len, from, hfrom)
500 struct interface_info *interface;
501 unsigned char *buf;
502 size_t len;
503 struct sockaddr_in *from;
504 struct hardware *hfrom;
505{
506 int length = 0;
507 int offset = 0;
508 int csum_ready = 1;
509 unsigned char ibuf [1536];
510 unsigned bufix = 0;
511 unsigned paylen;
512 struct iovec iov = {
513 .iov_base = ibuf,
514 .iov_len = sizeof ibuf,
515 };
516#ifdef PACKET_AUXDATA
517 /*
518 * We only need cmsgbuf if we are getting the aux data and we
519 * only get the auxdata if it is actually defined
520 */
521 unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
522 struct msghdr msg = {
523 .msg_iov = &iov,
524 .msg_iovlen = 1,
525 .msg_control = cmsgbuf,
526 .msg_controllen = sizeof(cmsgbuf),
527 };
528#else
529 struct msghdr msg = {
530 .msg_iov = &iov,
531 .msg_iovlen = 1,
532 .msg_control = NULL,
533 .msg_controllen = 0,
534 };
535#endif /* PACKET_AUXDATA */
536
537 if (interface->hw_address.hbuf[0] == HTYPE_INFINIBAND) {
538 return receive_packet_ib(interface, buf, len, from, hfrom);
539 }
540
541 length = recvmsg (interface->rfdesc, &msg, 0);
542 if (length <= 0)
543 return length;
544
545#ifdef PACKET_AUXDATA
546 {
547 /* Use auxiliary packet data to:
548 *
549 * a. Weed out extraneous VLAN-tagged packets - If the NIC driver is
550 * handling VLAN encapsulation (i.e. stripping/adding VLAN tags),
551 * then an inbound VLAN packet will be seen twice: Once by
552 * the parent interface (e.g. eth0) with a VLAN tag != 0; and once
553 * by the vlan interface (e.g. eth0.n) with a VLAN tag of 0 (i.e none).
554 * We want to discard the packet sent to the parent and thus respond
555 * only over the vlan interface. (Drivers for Intel PRO/1000 series
556 * NICs perform VLAN encapsulation, while drivers for PCnet series
557 * do not, for example. The linux kernel makes stripped vlan info
558 * visible to user space via CMSG/auxdata, this appears to not be
559 * true for BSD OSs.). NOTE: this is only supported on linux flavors
560 * which define the tpacket_auxdata.tp_vlan_tci.
561 *
562 * b. Determine if checksum is valid for use. It may not be if
563 * checksum offloading is enabled on the interface. */
564 struct cmsghdr *cmsg;
565
566 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
567 if (cmsg->cmsg_level == SOL_PACKET &&
568 cmsg->cmsg_type == PACKET_AUXDATA) {
569 struct tpacket_auxdata *aux = (void *)CMSG_DATA(cmsg);
570#ifdef VLAN_TCI_PRESENT
571 /* Discard packets with stripped vlan id */
572 /* VLAN ID is only bottom 12-bits of TCI */
573 if (aux->tp_vlan_tci & 0x0fff)
574 return 0;
575#endif
576
577 csum_ready = ((aux->tp_status & TP_STATUS_CSUMNOTREADY)
578 ? 0 : 1);
579 }
580 }
581
582 }
583#endif /* PACKET_AUXDATA */
584
585 bufix = 0;
586 /* Decode the physical header... */
587 offset = decode_hw_header (interface, ibuf, bufix, hfrom);
588
589 /* If a physical layer checksum failed (dunno of any
590 physical layer that supports this, but WTH), skip this
591 packet. */
592 if (offset < 0) {
593 return 0;
594 }
595
596 bufix += offset;
597 length -= offset;
598
599 /* Decode the IP and UDP headers... */
600 offset = decode_udp_ip_header (interface, ibuf, bufix, from,
601 (unsigned)length, &paylen, csum_ready);
602
603 /* If the IP or UDP checksum was bad, skip the packet... */
604 if (offset < 0)
605 return 0;
606
607 bufix += offset;
608 length -= offset;
609
610 if (length < paylen)
611 log_fatal("Internal inconsistency at %s:%d.", MDL);
612
613 /* Copy out the data in the packet... */
614 memcpy(buf, &ibuf[bufix], paylen);
615 return paylen;
616}
617
619 struct interface_info *ip;
620{
621 return 1;
622}
623
625 struct interface_info *ip;
626{
627 return 1;
628}
629
631 struct interface_info *ip;
632{
633 return 1;
634}
635
637{
638 isc_result_t status;
639 struct interface_info *fbi = (struct interface_info *)0;
640 if (setup_fallback (&fbi, MDL)) {
643 if_readsocket, 0,
644 fallback_discard, 0, 0);
645 if (status != ISC_R_SUCCESS)
646 log_fatal ("Can't register I/O handle for \"%s\": %s",
647 fbi -> name, isc_result_totext (status));
648 interface_dereference (&fbi, MDL);
649 }
650}
651#endif
652
653#if defined (USE_LPF_RECEIVE) || defined (USE_LPF_HWADDR)
654struct sockaddr_ll *
655get_ll (struct ifaddrs *ifaddrs, struct ifaddrs **ifa, char *name)
656{
657 for (*ifa = ifaddrs; *ifa != NULL; *ifa = (*ifa)->ifa_next) {
658 if ((*ifa)->ifa_addr == NULL)
659 continue;
660
661 if ((*ifa)->ifa_addr->sa_family != AF_PACKET)
662 continue;
663
664 if ((*ifa)->ifa_flags & IFF_LOOPBACK)
665 continue;
666
667 if (strcmp((*ifa)->ifa_name, name) == 0)
668 return (struct sockaddr_ll *)(void *)(*ifa)->ifa_addr;
669 }
670 *ifa = NULL;
671 return NULL;
672}
673
674struct sockaddr_ll *
675ioctl_get_ll(char *name)
676{
677 int sock;
678 struct ifreq tmp;
679 struct sockaddr *sa = NULL;
680 struct sockaddr_ll *sll = NULL;
681
682 if (strlen(name) >= sizeof(tmp.ifr_name)) {
683 log_fatal("Device name too long: \"%s\"", name);
684 }
685
686 sock = socket(AF_INET, SOCK_DGRAM, 0);
687 if (sock < 0) {
688 log_fatal("Can't create socket for \"%s\": %m", name);
689 }
690
691 memset(&tmp, 0, sizeof(tmp));
692 strcpy(tmp.ifr_name, name);
693 if (ioctl(sock, SIOCGIFHWADDR, &tmp) < 0) {
694 log_fatal("Error getting hardware address for \"%s\": %m",
695 name);
696 }
697 close(sock);
698
699 sa = &tmp.ifr_hwaddr;
700 // needs to be freed outside this function
701 sll = dmalloc (sizeof (struct sockaddr_ll), MDL);
702 if (!sll)
703 log_fatal("Unable to allocate memory for link layer address");
704 memcpy(&sll->sll_hatype, &sa->sa_family, sizeof (sll->sll_hatype));
705 memcpy(sll->sll_addr, sa->sa_data, sizeof (sll->sll_addr));
706 switch (sll->sll_hatype) {
707 case ARPHRD_INFINIBAND:
708 sll->sll_halen = HARDWARE_ADDR_LEN_IOCTL;
709 break;
710 default:
711 break;
712 }
713 return sll;
714}
715
716// define ?
717void try_hw_addr(struct interface_info *info){
718 get_hw_addr2(info);
719};
720
721void
722get_hw_addr(struct interface_info *info)
723{
724 if (get_hw_addr2(info) == ISC_R_NOTFOUND){
725 log_fatal("Unsupported device type for \"%s\"",
726 info->name);
727 }
728}
729
730isc_result_t
731get_hw_addr2(struct interface_info *info)
732{
733 struct hardware *hw = &info->hw_address;
734 char *name = info->name;
735 struct ifaddrs *ifaddrs = NULL;
736 struct ifaddrs *ifa = NULL;
737 struct sockaddr_ll *sll = NULL;
738 int sll_allocated = 0;
739 char *dup = NULL;
740 char *colon = NULL;
741 isc_result_t result = ISC_R_SUCCESS;
742
743 if (getifaddrs(&ifaddrs) == -1)
744 log_fatal("Failed to get interfaces");
745
746 if ((sll = get_ll(ifaddrs, &ifa, name)) == NULL) {
747 /*
748 * We were unable to get link-layer address for name.
749 * Fall back to ioctl(SIOCGIFHWADDR).
750 */
751 sll = ioctl_get_ll(name);
752 if (sll != NULL)
753 sll_allocated = 1;
754 else
755 // shouldn't happen
756 log_fatal("Unexpected internal error");
757 }
758
759 switch (sll->sll_hatype) {
760 case ARPHRD_ETHER:
761 hw->hlen = 7;
762 hw->hbuf[0] = HTYPE_ETHER;
763 memcpy(&hw->hbuf[1], sll->sll_addr, 6);
764 break;
765 case ARPHRD_IEEE802:
766#ifdef ARPHRD_IEEE802_TR
767 case ARPHRD_IEEE802_TR:
768#endif /* ARPHRD_IEEE802_TR */
769 hw->hlen = 7;
770 hw->hbuf[0] = HTYPE_IEEE802;
771 memcpy(&hw->hbuf[1], sll->sll_addr, 6);
772 break;
773 case ARPHRD_FDDI:
774 hw->hlen = 7;
775 hw->hbuf[0] = HTYPE_FDDI;
776 memcpy(&hw->hbuf[1], sll->sll_addr, 6);
777 break;
778 case ARPHRD_INFINIBAND:
779 dup = strdup(name);
780 /* Aliased infiniband interface is special case where
781 * neither get_ll() nor ioctl_get_ll() get's correct hw
782 * address, so we have to truncate the :0 and run
783 * get_ll() again for the rest.
784 */
785 if ((colon = strchr(dup, ':')) != NULL) {
786 *colon = '\0';
787 if ((sll = get_ll(ifaddrs, &ifa, dup)) == NULL)
788 log_fatal("Error getting hardware address for \"%s\": %m", name);
789 }
790 free (dup);
791 /* For Infiniband, save the broadcast address and store
792 * the port GUID into the hardware address.
793 */
794 if (ifa && (ifa->ifa_flags & IFF_BROADCAST)) {
795 struct sockaddr_ll *bll;
796
797 bll = (struct sockaddr_ll *)ifa->ifa_broadaddr;
798 memcpy(&info->bcast_addr, bll->sll_addr, 20);
799 } else {
800 memcpy(&info->bcast_addr, default_ib_bcast_addr,
801 20);
802 }
803
805 hw->hbuf[0] = HTYPE_INFINIBAND;
806 memcpy(&hw->hbuf[1],
807 &sll->sll_addr[sll->sll_halen - HARDWARE_ADDR_LEN_IOCTL],
809 break;
810#if defined(ARPHRD_PPP)
811 case ARPHRD_PPP:
812 if (local_family != AF_INET6)
813 log_fatal("local_family != AF_INET6 for \"%s\"",
814 name);
815 hw->hlen = 0;
816 hw->hbuf[0] = HTYPE_RESERVED;
817 /* 0xdeadbeef should never occur on the wire,
818 * and is a signature that something went wrong.
819 */
820 hw->hbuf[1] = 0xde;
821 hw->hbuf[2] = 0xad;
822 hw->hbuf[3] = 0xbe;
823 hw->hbuf[4] = 0xef;
824 break;
825#endif
826 default:
827 log_error("Unsupported device type %hu for \"%s\"",
828 sll->sll_hatype, name);
829 result = ISC_R_NOTFOUND;
830
831 }
832
833 if (sll_allocated)
834 dfree(sll, MDL);
835 freeifaddrs(ifaddrs);
836 return result;
837}
838#endif
char * print_hw_addr(int htype, const int hlen, const unsigned char *data) const
Definition print.c:171
u_int16_t local_port
Definition discover.c:48
#define HTYPE_RESERVED
Definition dhcp.h:81
#define HTYPE_IEEE802
Definition dhcp.h:76
#define HTYPE_FDDI
Definition dhcp.h:77
#define HTYPE_ETHER
Definition dhcp.h:75
#define HTYPE_INFINIBAND
Definition dhcp.h:78
void if_reinitialize_receive(struct interface_info *)
void maybe_setup_fallback(void)
int supports_multiple_interfaces(struct interface_info *)
void if_deregister_send(struct interface_info *)
#define HARDWARE_ADDR_LEN_IOCTL
Definition dhcpd.h:489
void assemble_hw_header(struct interface_info *, unsigned char *, unsigned *, struct hardware *)
void try_hw_addr(struct interface_info *info)
ssize_t decode_udp_ip_header(struct interface_info *, unsigned char *, unsigned, struct sockaddr_in *, unsigned, unsigned *, int)
void if_reinitialize_send(struct interface_info *)
isc_result_t fallback_discard(omapi_object_t *)
ssize_t send_packet(struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *)
void assemble_udp_ip_header(struct interface_info *, unsigned char *, unsigned *, u_int32_t, u_int32_t, u_int32_t, unsigned char *, unsigned)
int if_register_lpf(struct interface_info *)
int can_receive_unicast_unconfigured(struct interface_info *)
ssize_t receive_packet(struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *)
void get_hw_addr(struct interface_info *info)
void if_register_receive(struct interface_info *)
isc_result_t get_hw_addr2(struct interface_info *info)
ssize_t send_fallback(struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *)
int can_unicast_without_arp(struct interface_info *)
void if_deregister_receive(struct interface_info *)
void if_register_fallback(struct interface_info *)
ssize_t decode_hw_header(struct interface_info *, unsigned char *, unsigned, struct hardware *)
void if_register_send(struct interface_info *)
u_int16_t relay_port
Definition discover.c:50
int local_family
Definition discover.c:59
int setup_fallback(struct interface_info **fp, const char *file, int line)
Definition discover.c:1059
int quiet_interface_discovery
Definition discover.c:47
int if_readsocket(omapi_object_t *h)
Definition discover.c:1048
#define ETHERTYPE_IP
Definition if_ether.h:57
#define ISC_R_SUCCESS
#define MDL
Definition omapip.h:567
isc_result_t omapi_register_io_object(omapi_object_t *, int(*)(omapi_object_t *), int(*)(omapi_object_t *), isc_result_t(*)(omapi_object_t *), isc_result_t(*)(omapi_object_t *), isc_result_t(*)(omapi_object_t *))
Definition dispatch.c:198
struct __omapi_object omapi_object_t
Definition omapip.h:39
void * dmalloc(size_t, const char *, int)
Definition alloc.c:57
void dfree(void *, const char *, int)
Definition alloc.c:145
int log_error(const char *,...) __attribute__((__format__(__printf__
void log_fatal(const char *,...) __attribute__((__format__(__printf__
int int log_info(const char *,...) __attribute__((__format__(__printf__
u_int8_t hlen
Definition dhcpd.h:492
u_int8_t hbuf[HARDWARE_ADDR_LEN+1]
Definition dhcpd.h:493
char name[IFNAMSIZ]
Definition dhcpd.h:1408
struct hardware anycast_mac_addr
Definition dhcpd.h:1438
struct hardware hw_address
Definition dhcpd.h:1386
u_int8_t bcast_addr[20]
Definition dhcpd.h:1387
Definition ip.h:47