ISC DHCP  4.4.2b1
A reference DHCPv4 and DHCPv6 implementation
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-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"
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 */
51 static 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
66 void if_reinitialize_send (info)
67  struct interface_info *info;
68 {
69 }
70 #endif
71 
72 #ifdef USE_LPF_RECEIVE
73 void if_reinitialize_receive (info)
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 
83 int 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
150 void 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 
171 void 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... */
197 extern struct sock_filter dhcp_bpf_filter [];
198 extern int dhcp_bpf_filter_len;
199 extern struct sock_filter dhcp_ib_bpf_filter [];
200 extern int dhcp_ib_bpf_filter_len;
201 
202 #if defined(RELAY_PORT)
203 extern struct sock_filter dhcp_bpf_relay_filter [];
204 extern int dhcp_bpf_relay_filter_len;
205 #endif
206 
207 #if defined (HAVE_TR_SUPPORT)
208 extern struct sock_filter dhcp_bpf_tr_filter [];
209 extern int dhcp_bpf_tr_filter_len;
210 static void lpf_tr_filter_setup (struct interface_info *);
211 #endif
212 
213 static void lpf_gen_filter_setup (struct interface_info *);
214 
215 void 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 
254 void 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 
272 static 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)
332 static 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
370 ssize_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 
418 ssize_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
463 ssize_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 
499 ssize_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 
636 void maybe_setup_fallback ()
637 {
638  isc_result_t status;
639  struct interface_info *fbi = (struct interface_info *)0;
640  if (setup_fallback (&fbi, MDL)) {
641  if_register_fallback (fbi);
642  status = omapi_register_io_object ((omapi_object_t *)fbi,
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)
654 struct sockaddr_ll *
655 get_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 
674 struct sockaddr_ll *
675 ioctl_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 ?
717 void try_hw_addr(struct interface_info *info){
718  get_hw_addr2(info);
719 };
720 
721 void
722 get_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 
730 isc_result_t
731 get_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 
804  hw->hlen = HARDWARE_ADDR_LEN_IOCTL + 1;
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: dhclient.c:96
#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:47
int local_family
Definition: discover.c:56
int setup_fallback(struct interface_info **fp, const char *file, int line)
Definition: discover.c:1056
int quiet_interface_discovery
Definition: discover.c:44
int if_readsocket(omapi_object_t *h)
Definition: discover.c:1045
#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
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:1403
struct hardware anycast_mac_addr
Definition: dhcpd.h:1433
struct hardware hw_address
Definition: dhcpd.h:1381
u_int8_t bcast_addr[20]
Definition: dhcpd.h:1382
Definition: ip.h:47
Definition: dhcpd.h:405