ISC DHCP  4.4.3
A reference DHCPv4 and DHCPv6 implementation
discover.c
Go to the documentation of this file.
1 /* discover.c
2 
3  Find and identify the network interfaces. */
4 
5 /*
6  * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
7  * Copyright (c) 1995-2003 by Internet Software Consortium
8  *
9  * This Source Code Form is subject to the terms of the Mozilla Public
10  * License, v. 2.0. If a copy of the MPL was not distributed with this
11  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  *
21  * Internet Systems Consortium, Inc.
22  * PO Box 360
23  * Newmarket, NH 03857 USA
24  * <info@isc.org>
25  * https://www.isc.org/
26  *
27  */
28 
29 #include "dhcpd.h"
30 
31 /* length of line we can read from the IF file, 256 is too small in some cases */
32 #define IF_LINE_LENGTH 1024
33 
34 #define BSD_COMP /* needed on Solaris for SIOCGLIFNUM */
35 #include <sys/ioctl.h>
36 #include <errno.h>
37 
38 #ifdef HAVE_NET_IF6_H
39 # include <net/if6.h>
40 #endif
41 
45 
48 u_int16_t local_port = 0;
49 u_int16_t remote_port = 0;
50 u_int16_t relay_port = 0;
54 isc_result_t (*dhcp_interface_startup_hook) (struct interface_info *);
56 
57 struct in_addr limited_broadcast;
58 
59 int local_family = AF_INET;
60 struct in_addr local_address;
61 
62 #ifdef DHCPv6
63 /*
64  * Another clear abuse of the fact that undefined IP addresses are all zeroes.
65  */
66 struct in6_addr local_address6;
67 int bind_local_address6 = 0;
68 #endif /* DHCPv6 */
69 
71  struct dhcp_packet *, unsigned,
72  unsigned int,
73  struct iaddr, struct hardware *);
74 
75 #ifdef DHCPv6
76 void (*dhcpv6_packet_handler)(struct interface_info *,
77  const char *, int,
78  int, const struct iaddr *,
80 #endif /* DHCPv6 */
81 
82 
84 #if defined (TRACING)
88 #endif
92 
94 
95 isc_result_t interface_setup ()
96 {
97  isc_result_t status;
99  "interface",
108  0, 0, 0,
109  sizeof (struct interface_info),
111  if (status != ISC_R_SUCCESS)
112  log_fatal ("Can't register interface object type: %s",
113  isc_result_totext (status));
114 
115  return status;
116 }
117 
118 #if defined (TRACING)
119 void interface_trace_setup ()
120 {
121  interface_trace = trace_type_register ("interface", (void *)0,
124  inpacket_trace = trace_type_register ("inpacket", (void *)0,
127  outpacket_trace = trace_type_register ("outpacket", (void *)0,
130 }
131 #endif
132 
134  const char *file, int line)
135 {
136  struct interface_info *ip = (struct interface_info *)ipo;
137  ip -> rfdesc = ip -> wfdesc = -1;
138  return ISC_R_SUCCESS;
139 }
140 
141 
142 /*
143  * Scanning for Interfaces
144  * -----------------------
145  *
146  * To find interfaces, we create an iterator that abstracts out most
147  * of the platform specifics. Use is fairly straightforward:
148  *
149  * - begin_iface_scan() starts the process.
150  * - Use next_iface() until it returns 0.
151  * - end_iface_scan() performs any necessary cleanup.
152  *
153  * We check for errors on each call to next_iface(), which returns a
154  * description of the error as a string if any occurs.
155  *
156  * We currently have code for Solaris and Linux. Other systems need
157  * to have code written.
158  *
159  * NOTE: the long-term goal is to use the interface code from BIND 9.
160  */
161 
162 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && defined(SIOCGLIFFLAGS)
163 
164 /* HP/UX doesn't define struct lifconf, instead they define struct
165  * if_laddrconf. Similarly, 'struct lifreq' and 'struct lifaddrreq'.
166  */
167 #ifdef ISC_PLATFORM_HAVEIF_LADDRCONF
168 # define lifc_len iflc_len
169 # define lifc_buf iflc_buf
170 # define lifc_req iflc_req
171 # define LIFCONF if_laddrconf
172 #else
173 # define ISC_HAVE_LIFC_FAMILY 1
174 # define ISC_HAVE_LIFC_FLAGS 1
175 # define LIFCONF lifconf
176 #endif
177 
178 #ifdef ISC_PLATFORM_HAVEIF_LADDRREQ
179 # define lifr_addr iflr_addr
180 # define lifr_name iflr_name
181 # define lifr_dstaddr iflr_dstaddr
182 # define lifr_flags iflr_flags
183 # define sockaddr_storage sockaddr_ext
184 # define ss_family sa_family
185 # define LIFREQ if_laddrreq
186 #else
187 # define LIFREQ lifreq
188 #endif
189 
190 #ifndef IF_NAMESIZE
191 # if defined(LIFNAMSIZ)
192 # define IF_NAMESIZE LIFNAMSIZ
193 # elif defined(IFNAMSIZ)
194 # define IF_NAMESIZE IFNAMSIZ
195 # else
196 # define IF_NAMESIZE 16
197 # endif
198 #endif
199 #elif !defined(__linux) && !defined(HAVE_IFADDRS_H)
200 # define SIOCGLIFCONF SIOCGIFCONF
201 # define SIOCGLIFFLAGS SIOCGIFFLAGS
202 # define LIFREQ ifreq
203 # define LIFCONF ifconf
204 # define lifr_name ifr_name
205 # define lifr_addr ifr_addr
206 # define lifr_flags ifr_flags
207 # define lifc_len ifc_len
208 # define lifc_buf ifc_buf
209 # define lifc_req ifc_req
210 #ifdef _AIX
211 # define ss_family __ss_family
212 #endif
213 #endif
214 
215 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS)
216 /*
217  * Solaris support
218  * ---------------
219  *
220  * The SIOCGLIFCONF ioctl() are the extension that you need to use
221  * on Solaris to get information about IPv6 addresses.
222  *
223  * Solaris' extended interface is documented in the if_tcp man page.
224  */
225 
226 /*
227  * Structure holding state about the scan.
228  */
230  int sock; /* file descriptor used to get information */
231  int num; /* total number of interfaces */
232  struct LIFCONF conf; /* structure used to get information */
233  int next; /* next interface to retrieve when iterating */
234 };
235 
236 /*
237  * Structure used to return information about a specific interface.
238  */
239 struct iface_info {
240  char name[IF_NAMESIZE+1]; /* name of the interface, e.g. "bge0" */
241  struct sockaddr_storage addr; /* address information */
242  isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */
243 };
244 
245 /*
246  * Start a scan of interfaces.
247  *
248  * The iface_conf_list structure maintains state for this process.
249  */
250 int
252 #ifdef ISC_PLATFORM_HAVELIFNUM
253  struct lifnum lifnum;
254 #else
255  int lifnum;
256 #endif
257 
258  ifaces->sock = socket(local_family, SOCK_DGRAM, IPPROTO_UDP);
259  if (ifaces->sock < 0) {
260  log_error("Error creating socket to list interfaces; %m");
261  return 0;
262  }
263 
264  memset(&lifnum, 0, sizeof(lifnum));
265 #ifdef ISC_PLATFORM_HAVELIFNUM
266  lifnum.lifn_family = AF_UNSPEC;
267 #endif
268 #ifdef SIOCGLIFNUM
269  if (ioctl(ifaces->sock, SIOCGLIFNUM, &lifnum) < 0) {
270  log_error("Error finding total number of interfaces; %m");
271  close(ifaces->sock);
272  ifaces->sock = -1;
273  return 0;
274  }
275 
276 #ifdef ISC_PLATFORM_HAVELIFNUM
277  ifaces->num = lifnum.lifn_count;
278 #else
279  ifaces->num = lifnum;
280 #endif
281 #else
282  ifaces->num = 64;
283 #endif /* SIOCGLIFNUM */
284 
285  memset(&ifaces->conf, 0, sizeof(ifaces->conf));
286 #ifdef ISC_HAVE_LIFC_FAMILY
287  ifaces->conf.lifc_family = AF_UNSPEC;
288 #endif
289  ifaces->conf.lifc_len = ifaces->num * sizeof(struct LIFREQ);
290  ifaces->conf.lifc_buf = dmalloc(ifaces->conf.lifc_len, MDL);
291  if (ifaces->conf.lifc_buf == NULL) {
292  log_fatal("Out of memory getting interface list.");
293  }
294 
295  if (ioctl(ifaces->sock, SIOCGLIFCONF, &ifaces->conf) < 0) {
296  log_error("Error getting interfaces configuration list; %m");
297  dfree(ifaces->conf.lifc_buf, MDL);
298  close(ifaces->sock);
299  ifaces->sock = -1;
300  return 0;
301  }
302 
303  ifaces->next = 0;
304 
305  return 1;
306 }
307 
308 /*
309  * Retrieve the next interface.
310  *
311  * Returns information in the info structure.
312  * Sets err to 1 if there is an error, otherwise 0.
313  */
314 int
315 next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
316  struct LIFREQ *p;
317  struct LIFREQ tmp;
318  isc_boolean_t foundif;
319 #if defined(sun) || defined(__linux)
320  /* Pointer used to remove interface aliases. */
321  char *s;
322 #endif
323 
324  do {
325  foundif = ISC_FALSE;
326 
327  if (ifaces->next >= ifaces->num) {
328  *err = 0;
329  return 0;
330  }
331 
332  p = ifaces->conf.lifc_req;
333  p += ifaces->next;
334 
335  if (strlen(p->lifr_name) >= sizeof(info->name)) {
336  *err = 1;
337  log_error("Interface name '%s' too long", p->lifr_name);
338  return 0;
339  }
340 
341  /* Reject if interface address family does not match */
342  if (p->lifr_addr.ss_family != local_family) {
343  ifaces->next++;
344  continue;
345  }
346 
347  memset(info, 0, sizeof(struct iface_info));
348  strncpy(info->name, p->lifr_name, sizeof(info->name) - 1);
349  memcpy(&info->addr, &p->lifr_addr, sizeof(p->lifr_addr));
350 
351 #if defined(sun) || defined(__linux)
352  /* interface aliases look like "eth0:1" or "wlan1:3" */
353  s = strchr(info->name, ':');
354  if (s != NULL) {
355  *s = '\0';
356  }
357 #endif /* defined(sun) || defined(__linux) */
358 
359  foundif = ISC_TRUE;
360  } while ((foundif == ISC_FALSE) ||
361  (strncmp(info->name, "dummy", 5) == 0));
362 
363  memset(&tmp, 0, sizeof(tmp));
364  strncpy(tmp.lifr_name, info->name, sizeof(tmp.lifr_name) - 1);
365  if (ioctl(ifaces->sock, SIOCGLIFFLAGS, &tmp) < 0) {
366  log_error("Error getting interface flags for '%s'; %m",
367  p->lifr_name);
368  *err = 1;
369  return 0;
370  }
371  info->flags = tmp.lifr_flags;
372 
373  ifaces->next++;
374  *err = 0;
375  return 1;
376 }
377 
378 /*
379  * End scan of interfaces.
380  */
381 void
383  dfree(ifaces->conf.lifc_buf, MDL);
384  close(ifaces->sock);
385  ifaces->sock = -1;
386 }
387 
388 #else
389 
390 /*
391  * BSD/Linux support
392  * -----------
393  *
394  * FreeBSD, NetBSD, OpenBSD, OS X/macOS and Linux all have the getifaddrs()
395  * function.
396  *
397  * The getifaddrs() man page describes the use.
398  */
399 
400 #include <ifaddrs.h>
401 
402 /*
403  * Structure holding state about the scan.
404  */
405 struct iface_conf_list {
406  struct ifaddrs *head; /* beginning of the list */
407  struct ifaddrs *next; /* current position in the list */
408 };
409 
410 /*
411  * Structure used to return information about a specific interface.
412  */
413 struct iface_info {
414  char name[IFNAMSIZ]; /* name of the interface, e.g. "bge0" */
415  struct sockaddr_storage addr; /* address information */
416  isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */
417 };
418 
419 /*
420  * Start a scan of interfaces.
421  *
422  * The iface_conf_list structure maintains state for this process.
423  */
424 int
425 begin_iface_scan(struct iface_conf_list *ifaces) {
426  if (getifaddrs(&ifaces->head) != 0) {
427  log_error("Error getting interfaces; %m");
428  return 0;
429  }
430  ifaces->next = ifaces->head;
431  return 1;
432 }
433 
434 /*
435  * Retrieve the next interface.
436  *
437  * Returns information in the info structure.
438  * Sets err to 1 if there is an error, otherwise 0.
439  */
440 int
441 next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
442  size_t sa_len = 0;
443 
444  if (ifaces->next == NULL) {
445  *err = 0;
446  return 0;
447  }
448  if (strlen(ifaces->next->ifa_name) >= sizeof(info->name)) {
449  log_error("Interface name '%s' too long",
450  ifaces->next->ifa_name);
451  *err = 1;
452  return 0;
453  }
454  memset(info, 0, sizeof(struct iface_info));
455  strncpy(info->name, ifaces->next->ifa_name, sizeof(info->name) - 1);
456  memset(&info->addr, 0 , sizeof(info->addr));
457  /*
458  * getifaddrs() can on Linux with some interfaces like PPP or TEQL
459  * result in a record with no address (ifa_addr).
460  */
461  if (ifaces->next->ifa_addr != NULL) {
462 /* Linux lacks the sa_len member in struct sockaddr. */
463 #if defined(__linux)
464  if (ifaces->next->ifa_addr->sa_family == AF_INET)
465  sa_len = sizeof(struct sockaddr_in);
466  else if (ifaces->next->ifa_addr->sa_family == AF_INET6)
467  sa_len = sizeof(struct sockaddr_in6);
468 #else
469  sa_len = ifaces->next->ifa_addr->sa_len;
470 #endif
471  memcpy(&info->addr, ifaces->next->ifa_addr, sa_len);
472  }
473  info->flags = ifaces->next->ifa_flags;
474  ifaces->next = ifaces->next->ifa_next;
475  *err = 0;
476  return 1;
477 }
478 
479 /*
480  * End scan of interfaces.
481  */
482 void
483 end_iface_scan(struct iface_conf_list *ifaces) {
484  freeifaddrs(ifaces->head);
485  ifaces->head = NULL;
486  ifaces->next = NULL;
487 }
488 #endif
489 
490 /* XXX: perhaps create drealloc() rather than do it manually */
491 void
493  const struct in_addr *addr) {
494  /*
495  * We don't expect a lot of addresses per IPv4 interface, so
496  * we use 4, as our "chunk size" for collecting addresses.
497  */
498  if (iface->addresses == NULL) {
499  iface->addresses = dmalloc(4 * sizeof(struct in_addr), MDL);
500  if (iface->addresses == NULL) {
501  log_fatal("Out of memory saving IPv4 address "
502  "on interface.");
503  }
504  iface->address_count = 0;
505  iface->address_max = 4;
506  } else if (iface->address_count >= iface->address_max) {
507  struct in_addr *tmp;
508  int new_max;
509 
510  new_max = iface->address_max + 4;
511  tmp = dmalloc(new_max * sizeof(struct in_addr), MDL);
512  if (tmp == NULL) {
513  log_fatal("Out of memory saving IPv4 address "
514  "on interface.");
515  }
516  memcpy(tmp,
517  iface->addresses,
518  iface->address_max * sizeof(struct in_addr));
519  dfree(iface->addresses, MDL);
520  iface->addresses = tmp;
521  iface->address_max = new_max;
522  }
523  iface->addresses[iface->address_count++] = *addr;
524 }
525 
526 #ifdef DHCPv6
527 /* XXX: perhaps create drealloc() rather than do it manually */
528 void
529 add_ipv6_addr_to_interface(struct interface_info *iface,
530  const struct in6_addr *addr) {
531  /*
532  * Each IPv6 interface will have at least two IPv6 addresses,
533  * and likely quite a few more. So we use 8, as our "chunk size" for
534  * collecting addresses.
535  */
536  if (iface->v6addresses == NULL) {
537  iface->v6addresses = dmalloc(8 * sizeof(struct in6_addr), MDL);
538  if (iface->v6addresses == NULL) {
539  log_fatal("Out of memory saving IPv6 address "
540  "on interface.");
541  }
542  iface->v6address_count = 0;
543  iface->v6address_max = 8;
544  } else if (iface->v6address_count >= iface->v6address_max) {
545  struct in6_addr *tmp;
546  int new_max;
547 
548  new_max = iface->v6address_max + 8;
549  tmp = dmalloc(new_max * sizeof(struct in6_addr), MDL);
550  if (tmp == NULL) {
551  log_fatal("Out of memory saving IPv6 address "
552  "on interface.");
553  }
554  memcpy(tmp,
555  iface->v6addresses,
556  iface->v6address_max * sizeof(struct in6_addr));
557  dfree(iface->v6addresses, MDL);
558  iface->v6addresses = tmp;
559  iface->v6address_max = new_max;
560  }
561  iface->v6addresses[iface->v6address_count++] = *addr;
562 }
563 #endif /* DHCPv6 */
564 
565 /* Use the SIOCGIFCONF ioctl to get a list of all the attached interfaces.
566  For each interface that's of type INET and not the loopback interface,
567  register that interface with the network I/O software, figure out what
568  subnet it's on, and add it to the list of interfaces. */
569 
570 void
572  struct iface_conf_list ifaces;
573  struct iface_info info;
574  int err;
575 
576  struct interface_info *tmp;
577  struct interface_info *last, *next;
578 
579 #ifdef DHCPv6
580  char abuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
581 #endif /* DHCPv6 */
582 
583 
584  struct subnet *subnet;
585  int ir;
586  isc_result_t status;
587  int wifcount = 0;
588 #ifdef RELAY_PORT
589  int updone = 0;
590  int downdone = 0;
591 #endif
592 
593  static int setup_fallback = 0;
594 
595  if (!begin_iface_scan(&ifaces)) {
596  log_fatal("Can't get list of interfaces.");
597  }
598 
599  /* If we already have a list of interfaces, and we're running as
600  a DHCP server, the interfaces were requested. */
601  if (interfaces && (state == DISCOVER_SERVER ||
602  state == DISCOVER_RELAY ||
603  state == DISCOVER_REQUESTED))
604  ir = 0;
605  else if (state == DISCOVER_UNCONFIGURED)
607  else {
608  ir = INTERFACE_REQUESTED;
609  if (state == DISCOVER_RELAY && local_family == AF_INET) {
610  /* We're a v4 relay without specifically requested
611  * interfaces, so mark them all as bidirectional. */
612  ir |= INTERFACE_STREAMS;
613  }
614  }
615 
616  /* Cycle through the list of interfaces looking for IP addresses. */
617  while (next_iface(&info, &err, &ifaces)) {
618 
619  /* See if we've seen an interface that matches this one. */
620  for (tmp = interfaces; tmp; tmp = tmp->next) {
621  if (!strcmp(tmp->name, info.name))
622  break;
623  }
624 
625  /* Skip non broadcast interfaces (plus loopback and
626  point-to-point in case an OS incorrectly marks them
627  as broadcast). Also skip down interfaces unless we're
628  trying to get a list of configurable interfaces. */
629  if ((((local_family == AF_INET &&
630  !(info.flags & IFF_BROADCAST)) ||
631 #ifdef DHCPv6
632  (local_family == AF_INET6 &&
633  !(info.flags & IFF_MULTICAST)) ||
634 #endif
635  info.flags & IFF_LOOPBACK ||
636  info.flags & IFF_POINTOPOINT) && !tmp) ||
637  (!(info.flags & IFF_UP) &&
638  state != DISCOVER_UNCONFIGURED))
639  continue;
640 
641  /* If there isn't already an interface by this name,
642  allocate one. */
643  if (tmp == NULL) {
644  status = interface_allocate(&tmp, MDL);
645  if (status != ISC_R_SUCCESS) {
646  log_fatal("Error allocating interface %s: %s",
647  info.name, isc_result_totext(status));
648  }
649 
650  memcpy(tmp->name, info.name, sizeof(tmp->name));
651 
652  interface_snorf(tmp, ir);
653  interface_dereference(&tmp, MDL);
654  tmp = interfaces; /* XXX */
655  }
656  if (tmp != NULL)
657  try_hw_addr(tmp);
658 
660  (*dhcp_interface_discovery_hook)(tmp);
661  }
662 
663  if ((info.addr.ss_family == AF_INET) &&
664  (local_family == AF_INET)) {
665  struct sockaddr_in *a = (struct sockaddr_in*)&info.addr;
666  struct iaddr addr;
667 
668  /* We don't want the loopback interface. */
669  if (a->sin_addr.s_addr == htonl(INADDR_LOOPBACK) &&
670  ((tmp->flags & INTERFACE_AUTOMATIC) &&
671  ((state == DISCOVER_SERVER) ||
672  (state == DISCOVER_SERVER46))))
673  continue;
674 
675  /* If the only address we have is 0.0.0.0, we
676  shouldn't consider the interface configured. */
677  if (a->sin_addr.s_addr != htonl(INADDR_ANY))
678  tmp->configured = 1;
679 
680  add_ipv4_addr_to_interface(tmp, &a->sin_addr);
681 
682  /* invoke the setup hook */
683  addr.len = 4;
684  memcpy(addr.iabuf, &a->sin_addr.s_addr, addr.len);
686  (*dhcp_interface_setup_hook)(tmp, &addr);
687  }
688  }
689 #ifdef DHCPv6
690  else if ((info.addr.ss_family == AF_INET6) &&
691  (local_family == AF_INET6)) {
692  struct sockaddr_in6 *a =
693  (struct sockaddr_in6*)&info.addr;
694  struct iaddr addr;
695 
696  /* We don't want the loopback interface. */
697  if (IN6_IS_ADDR_LOOPBACK(&a->sin6_addr) &&
698  ((tmp->flags & INTERFACE_AUTOMATIC) &&
699  ((state == DISCOVER_SERVER) ||
700  (state == DISCOVER_SERVER46))))
701  continue;
702 
703  /* If the only address we have is 0.0.0.0, we
704  shouldn't consider the interface configured. */
705  if (IN6_IS_ADDR_UNSPECIFIED(&a->sin6_addr))
706  tmp->configured = 1;
707 
708  add_ipv6_addr_to_interface(tmp, &a->sin6_addr);
709 
710  /* invoke the setup hook */
711  addr.len = 16;
712  memcpy(addr.iabuf, &a->sin6_addr, addr.len);
714  (*dhcp_interface_setup_hook)(tmp, &addr);
715  }
716  }
717 #endif /* DHCPv6 */
718  }
719 
720  if (err) {
721  log_fatal("Error getting interface information.");
722  }
723 
724  end_iface_scan(&ifaces);
725 
726 
727  /* Mock-up an 'ifp' structure which is no longer used in the
728  * new interface-sensing code, but is used in higher layers
729  * (for example to sense fallback interfaces).
730  */
731  for (tmp = interfaces ; tmp != NULL ; tmp = tmp->next) {
732  if (tmp->ifp == NULL) {
733  struct ifreq *tif;
734 
735  tif = (struct ifreq *)dmalloc(sizeof(struct ifreq),
736  MDL);
737  if (tif == NULL)
738  log_fatal("no space for ifp mockup.");
739  strcpy(tif->ifr_name, tmp->name);
740  tmp->ifp = tif;
741  }
742  }
743 
744 
745  /* If we're just trying to get a list of interfaces that we might
746  be able to configure, we can quit now. */
747  if (state == DISCOVER_UNCONFIGURED) {
748  return;
749  }
750 
751  /* Weed out the interfaces that did not have IP addresses. */
752  tmp = last = next = NULL;
753  if (interfaces)
754  interface_reference (&tmp, interfaces, MDL);
755  while (tmp) {
756  if (next)
757  interface_dereference (&next, MDL);
758  if (tmp -> next)
759  interface_reference (&next, tmp -> next, MDL);
760  /* skip interfaces that are running already */
761  if (tmp -> flags & INTERFACE_RUNNING) {
762  interface_dereference(&tmp, MDL);
763  if(next)
764  interface_reference(&tmp, next, MDL);
765  continue;
766  }
767  if ((tmp -> flags & INTERFACE_AUTOMATIC) &&
768  state == DISCOVER_REQUESTED)
769  tmp -> flags &= ~(INTERFACE_AUTOMATIC |
771 
772 #ifdef DHCPv6
773  if (!(tmp->flags & INTERFACE_REQUESTED)) {
774 #else
775  if (!tmp -> ifp || !(tmp -> flags & INTERFACE_REQUESTED)) {
776 #endif /* DHCPv6 */
777  if ((tmp -> flags & INTERFACE_REQUESTED) != ir)
778  log_fatal ("%s: not found", tmp -> name);
779  if (!last) {
780  if (interfaces)
781  interface_dereference (&interfaces,
782  MDL);
783  if (next)
784  interface_reference (&interfaces, next, MDL);
785  } else {
786  interface_dereference (&last -> next, MDL);
787  if (next)
788  interface_reference (&last -> next,
789  next, MDL);
790  }
791  if (tmp -> next)
792  interface_dereference (&tmp -> next, MDL);
793 
794  /* Remember the interface in case we need to know
795  about it later. */
796  if (dummy_interfaces) {
797  interface_reference (&tmp -> next,
799  interface_dereference (&dummy_interfaces, MDL);
800  }
801  interface_reference (&dummy_interfaces, tmp, MDL);
802  interface_dereference (&tmp, MDL);
803  if (next)
804  interface_reference (&tmp, next, MDL);
805  continue;
806  }
807  last = tmp;
808 
809  /* We must have a subnet declaration for each interface. */
810  if (!tmp->shared_network && (state == DISCOVER_SERVER)) {
811  log_info("%s", "");
812  if (local_family == AF_INET) {
813  log_info("No subnet declaration for %s (%s).",
814  tmp->name,
815  (tmp->addresses == NULL) ?
816  "no IPv4 addresses" :
817  inet_ntoa(tmp->addresses[0]));
818 #ifdef DHCPv6
819  } else {
820  if (tmp->v6addresses != NULL) {
821  inet_ntop(AF_INET6,
822  &tmp->v6addresses[0],
823  abuf,
824  sizeof(abuf));
825  } else {
826  strcpy(abuf, "no IPv6 addresses");
827  }
828  log_info("No subnet6 declaration for %s (%s).",
829  tmp->name,
830  abuf);
831 #endif /* DHCPv6 */
832  }
833  if (supports_multiple_interfaces(tmp)) {
834  log_info ("** Ignoring requests on %s. %s",
835  tmp -> name, "If this is not what");
836  log_info (" you want, please write %s",
837 #ifdef DHCPv6
838  (local_family != AF_INET) ?
839  "a subnet6 declaration" :
840 #endif
841  "a subnet declaration");
842  log_info (" in your dhcpd.conf file %s",
843  "for the network segment");
844  log_info (" to %s %s %s",
845  "which interface",
846  tmp -> name, "is attached. **");
847  log_info ("%s", "");
848  goto next;
849  } else {
850  log_error ("You must write a %s",
851 #ifdef DHCPv6
852  (local_family != AF_INET) ?
853  "subnet6 declaration for this" :
854 #endif
855  "subnet declaration for this");
856  log_error ("subnet. You cannot prevent %s",
857  "the DHCP server");
858  log_error ("from listening on this subnet %s",
859  "because your");
860  log_fatal ("operating system does not %s.",
861  "support this capability");
862  }
863  }
864 
865  /* Find subnets that don't have valid interface
866  addresses... */
867  for (subnet = (tmp -> shared_network
868  ? tmp -> shared_network -> subnets
869  : (struct subnet *)0);
870  subnet; subnet = subnet -> next_sibling) {
871  /* Set the interface address for this subnet
872  to the first address we found. */
873  if (subnet->interface_address.len == 0) {
874  if (tmp->address_count > 0) {
877  &tmp->addresses[0].s_addr, 4);
878  } else if (tmp->v6address_count > 0) {
881  &tmp->v6addresses[0].s6_addr,
882  16);
883  } else {
884  /* XXX: should be one */
885  log_error("%s missing an interface "
886  "address", tmp->name);
887  continue;
888  }
889  }
890  }
891 
892  /* Flag the index as not having been set, so that the
893  interface registerer can set it or not as it chooses. */
894  tmp -> index = -1;
895 
896  /* Register the interface... */
897  switch (local_family) {
898  case AF_INET:
899  if (!dhcpv4_over_dhcpv6) {
900  if_register_receive(tmp);
901  if_register_send(tmp);
902  } else {
903  /* get_hw_addr() was called by register. */
904  get_hw_addr(tmp);
905  }
906  break;
907 #ifdef DHCPv6
908  case AF_INET6:
909  if ((state == DISCOVER_SERVER) ||
910  (state == DISCOVER_RELAY)) {
911  if_register6(tmp, 1);
912  } else if (state == DISCOVER_SERVER46) {
913  /* get_hw_addr() was called by if_register*6
914  so now we have to call it explicitly
915  to not leave the hardware address unknown
916  (some code expects it cannot be. */
917  get_hw_addr(tmp);
918  } else {
920  }
921  break;
922 #endif /* DHCPv6 */
923  }
924 
925  interface_stash (tmp);
926  wifcount++;
927 #if defined (F_SETFD)
928  /* if_register*() are no longer always called so
929  descriptors must be checked. */
930  if ((tmp -> rfdesc >= 0) &&
931  (fcntl (tmp -> rfdesc, F_SETFD, 1) < 0))
932  log_error ("Can't set close-on-exec on %s: %m",
933  tmp -> name);
934  if ((tmp -> wfdesc != tmp -> rfdesc) &&
935  (tmp -> wfdesc >= 0) &&
936  (fcntl (tmp -> wfdesc, F_SETFD, 1) < 0))
937  log_error ("Can't set close-on-exec on %s: %m",
938  tmp -> name);
939 #endif
940  next:
941  interface_dereference (&tmp, MDL);
942  if (next)
943  interface_reference (&tmp, next, MDL);
944  }
945 
946  /*
947  * Now register all the remaining interfaces as protocols.
948  * We register with omapi to allow for control of the interface,
949  * we've already registered the fd or socket with the socket
950  * manager as part of if_register_receive().
951  */
952  for (tmp = interfaces; tmp; tmp = tmp -> next) {
953  /* not if it's been registered before */
954  if (tmp -> flags & INTERFACE_RUNNING)
955  continue;
956  if (tmp -> rfdesc == -1)
957  continue;
958  switch (local_family) {
959 #ifdef DHCPv6
960  case AF_INET6:
961 #ifdef RELAY_PORT
962 #define UPSTREAM(ifp) \
963  ((ifp->flags & INTERFACE_STREAMS) == INTERFACE_UPSTREAM)
964 #define DOWNSTREAM(ifp) \
965  ((ifp->flags & INTERFACE_STREAMS) == INTERFACE_DOWNSTREAM)
966 
967  if (relay_port) {
968  /*
969  * The normal IPv6 relay only needs one
970  * socket as long as we find an interface.
971  * When user relay port is defined, and we
972  * have two different UDP ports. One to
973  * receive from DHCP client with port 547,
974  * and the other is user defined for sending
975  * to the server or upstream relay agent.
976  * Thus we need to register sockets for one
977  * upstream and one downstream interfaces.
978  */
979  if (updone && UPSTREAM(tmp))
980  continue;
981  if (downdone && DOWNSTREAM(tmp))
982  continue;
983  }
984 #endif
987  0, got_one_v6, 0, 0);
988 #ifdef RELAY_PORT
989  if (UPSTREAM(tmp))
990  updone++;
991  else
992  downdone++;
993 #endif
994  break;
995 #endif /* DHCPv6 */
996  case AF_INET:
997  default:
1000  0, got_one, 0, 0);
1001  break;
1002  }
1003 
1004  if (status != ISC_R_SUCCESS)
1005  log_fatal ("Can't register I/O handle for %s: %s",
1006  tmp -> name, isc_result_totext (status));
1007 
1008 #if defined(DHCPv6)
1009  /* Only register the first interface for V6, since
1010  * servers and relays all use the same socket.
1011  * XXX: This has some messy side effects if we start
1012  * dynamically adding and removing interfaces, but
1013  * we're well beyond that point in terms of mess.
1014  */
1015  if (((state == DISCOVER_SERVER) || (state == DISCOVER_RELAY))
1016  && (local_family == AF_INET6)
1017 #if defined(RELAY_PORT)
1018  && ((relay_port == 0) || (updone && downdone))
1019 #endif
1020  )
1021  break;
1022 #endif
1023  } /* for (tmp = interfaces; ... */
1024 
1025  if (state == DISCOVER_SERVER && wifcount == 0) {
1026  log_info ("%s", "");
1027  log_fatal ("Not configured to listen on any interfaces!");
1028  }
1029 
1030  if ((local_family == AF_INET) &&
1032  setup_fallback = 1;
1034  }
1035 
1036 #if defined (F_SETFD)
1037  if (fallback_interface) {
1038  if (fcntl (fallback_interface -> rfdesc, F_SETFD, 1) < 0)
1039  log_error ("Can't set close-on-exec on fallback: %m");
1040  if (fallback_interface -> rfdesc != fallback_interface -> wfdesc) {
1041  if (fcntl (fallback_interface -> wfdesc, F_SETFD, 1) < 0)
1042  log_error ("Can't set close-on-exec on fallback: %m");
1043  }
1044  }
1045 #endif /* F_SETFD */
1046 }
1047 
1049  omapi_object_t *h;
1050 {
1051  struct interface_info *ip;
1052 
1053  if (h -> type != dhcp_type_interface)
1054  return -1;
1055  ip = (struct interface_info *)h;
1056  return ip -> rfdesc;
1057 }
1058 
1059 int setup_fallback (struct interface_info **fp, const char *file, int line)
1060 {
1061  isc_result_t status;
1062 
1063  status = interface_allocate (&fallback_interface, file, line);
1064  if (status != ISC_R_SUCCESS)
1065  log_fatal ("Error allocating fallback interface: %s",
1066  isc_result_totext (status));
1067  strcpy (fallback_interface -> name, "fallback");
1069  (*dhcp_interface_setup_hook) (fallback_interface,
1070  (struct iaddr *)0);
1071  status = interface_reference (fp, fallback_interface, file, line);
1072 
1073  fallback_interface -> index = -1;
1075  return status == ISC_R_SUCCESS;
1076 }
1077 
1079 {
1080  struct interface_info *ip;
1081 
1082  for (ip = interfaces; ip; ip = ip -> next) {
1085  }
1086 
1087  if (fallback_interface)
1089 
1091 }
1092 
1093 isc_result_t got_one (h)
1094  omapi_object_t *h;
1095 {
1096  struct sockaddr_in from;
1097  struct hardware hfrom;
1098  struct iaddr ifrom;
1099  int result;
1100  union {
1101  unsigned char packbuf [4095]; /* Packet input buffer.
1102  Must be as large as largest
1103  possible MTU. */
1104  struct dhcp_packet packet;
1105  } u;
1106  struct interface_info *ip;
1107 
1108  if (h -> type != dhcp_type_interface)
1109  return DHCP_R_INVALIDARG;
1110  ip = (struct interface_info *)h;
1111 
1112  again:
1113  if ((result =
1114  receive_packet (ip, u.packbuf, sizeof u, &from, &hfrom)) < 0) {
1115  log_error ("receive_packet failed on %s: %m", ip -> name);
1116  return ISC_R_UNEXPECTED;
1117  }
1118  if (result == 0)
1119  return ISC_R_UNEXPECTED;
1120 
1121  /*
1122  * If we didn't at least get the fixed portion of the BOOTP
1123  * packet, drop the packet.
1124  * Previously we allowed packets with no sname or filename
1125  * as we were aware of at least one client that did. But
1126  * a bug caused short packets to not work and nobody has
1127  * complained, it seems rational to tighten up that
1128  * restriction.
1129  */
1130  if (result < DHCP_FIXED_NON_UDP)
1131  return ISC_R_UNEXPECTED;
1132 
1133 #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
1134  {
1135  /* We retrieve the ifindex from the unused hfrom variable */
1136  unsigned int ifindex;
1137 
1138  memcpy(&ifindex, hfrom.hbuf, sizeof (ifindex));
1139 
1140  /*
1141  * Seek forward from the first interface to find the matching
1142  * source interface by interface index.
1143  */
1144  ip = interfaces;
1145  while ((ip != NULL) && (if_nametoindex(ip->name) != ifindex))
1146  ip = ip->next;
1147  if (ip == NULL)
1148  return ISC_R_NOTFOUND;
1149  }
1150 #endif
1151 
1152  if (bootp_packet_handler) {
1153  ifrom.len = 4;
1154  memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len);
1155 
1156  (*bootp_packet_handler) (ip, &u.packet, (unsigned)result,
1157  from.sin_port, ifrom, &hfrom);
1158  }
1159 
1160  /* If there is buffered data, read again. This is for, e.g.,
1161  bpf, which may return two packets at once. */
1162  if (ip -> rbuf_offset != ip -> rbuf_len)
1163  goto again;
1164  return ISC_R_SUCCESS;
1165 }
1166 
1167 #ifdef DHCPv6
1168 isc_result_t
1170  struct sockaddr_in6 from;
1171  struct in6_addr to;
1172  struct iaddr ifrom;
1173  int result;
1174  char buf[65536]; /* maximum size for a UDP packet is 65536 */
1175  struct interface_info *ip;
1176  int is_unicast;
1177  unsigned int if_idx = 0;
1178 
1179  if (h->type != dhcp_type_interface) {
1180  return DHCP_R_INVALIDARG;
1181  }
1182  ip = (struct interface_info *)h;
1183 
1184  result = receive_packet6(ip, (unsigned char *)buf, sizeof(buf),
1185  &from, &to, &if_idx);
1186  if (result < 0) {
1187  log_error("receive_packet6() failed on %s: %m", ip->name);
1188  return ISC_R_UNEXPECTED;
1189  }
1190 
1191  /* 0 is 'any' interface. */
1192  if (if_idx == 0)
1193  return ISC_R_NOTFOUND;
1194 
1195  if (dhcpv6_packet_handler != NULL) {
1196  /*
1197  * If a packet is not multicast, we assume it is unicast.
1198  */
1199  if (IN6_IS_ADDR_MULTICAST(&to)) {
1200  is_unicast = ISC_FALSE;
1201  } else {
1202  is_unicast = ISC_TRUE;
1203  }
1204 
1205  ifrom.len = 16;
1206  memcpy(ifrom.iabuf, &from.sin6_addr, ifrom.len);
1207 
1208  /* Seek forward to find the matching source interface. */
1209  ip = interfaces;
1210  while ((ip != NULL) && (if_nametoindex(ip->name) != if_idx))
1211  ip = ip->next;
1212 
1213  if (ip == NULL)
1214  return ISC_R_NOTFOUND;
1215 
1216  (*dhcpv6_packet_handler)(ip, buf,
1217  result, from.sin6_port,
1218  &ifrom, is_unicast);
1219  }
1220 
1221  return ISC_R_SUCCESS;
1222 }
1223 #endif /* DHCPv6 */
1224 
1226  omapi_object_t *id,
1229 {
1230  struct interface_info *interface;
1231  isc_result_t status;
1232 
1233  if (h -> type != dhcp_type_interface)
1234  return DHCP_R_INVALIDARG;
1235  interface = (struct interface_info *)h;
1236 
1237  if (!omapi_ds_strcmp (name, "name")) {
1238  if ((value -> type == omapi_datatype_data ||
1239  value -> type == omapi_datatype_string) &&
1240  value -> u.buffer.len < sizeof interface -> name) {
1241  memcpy (interface -> name,
1242  value -> u.buffer.value,
1243  value -> u.buffer.len);
1244  interface -> name [value -> u.buffer.len] = 0;
1245  } else
1246  return DHCP_R_INVALIDARG;
1247  return ISC_R_SUCCESS;
1248  }
1249 
1250  /* Try to find some inner object that can take the value. */
1251  if (h -> inner && h -> inner -> type -> set_value) {
1252  status = ((*(h -> inner -> type -> set_value))
1253  (h -> inner, id, name, value));
1254  if (status == ISC_R_SUCCESS || status == DHCP_R_UNCHANGED)
1255  return status;
1256  }
1257 
1258  return ISC_R_NOTFOUND;
1259 }
1260 
1261 
1263  omapi_object_t *id,
1264  omapi_data_string_t *name,
1265  omapi_value_t **value)
1266 {
1267  return ISC_R_NOTIMPLEMENTED;
1268 }
1269 
1271  const char *file, int line)
1272 {
1273  struct interface_info *interface;
1274 
1275  if (h -> type != dhcp_type_interface)
1276  return DHCP_R_INVALIDARG;
1277  interface = (struct interface_info *)h;
1278 
1279  if (interface -> ifp) {
1280  dfree (interface -> ifp, file, line);
1281  interface -> ifp = 0;
1282  }
1283  if (interface -> next)
1284  interface_dereference (&interface -> next, file, line);
1285  if (interface -> rbuf) {
1286  dfree (interface -> rbuf, file, line);
1287  interface -> rbuf = (unsigned char *)0;
1288  }
1289  if (interface -> client)
1290  interface -> client = (struct client_state *)0;
1291 
1292  if (interface -> shared_network)
1295 
1296  return ISC_R_SUCCESS;
1297 }
1298 
1300  const char *name, va_list ap)
1301 {
1302  struct interface_info *ip, *interface;
1303  isc_result_t status;
1304 
1305  if (h -> type != dhcp_type_interface)
1306  return DHCP_R_INVALIDARG;
1307  interface = (struct interface_info *)h;
1308 
1309  /* If it's an update signal, see if the interface is dead right
1310  now, or isn't known at all, and if that's the case, revive it. */
1311  if (!strcmp (name, "update")) {
1312  for (ip = dummy_interfaces; ip; ip = ip -> next)
1313  if (ip == interface)
1314  break;
1316  return (*dhcp_interface_startup_hook) (ip);
1317 
1318  for (ip = interfaces; ip; ip = ip -> next)
1319  if (ip == interface)
1320  break;
1322  return (*dhcp_interface_startup_hook) (ip);
1323  }
1324 
1325  /* Try to find some inner object that can take the value. */
1326  if (h -> inner && h -> inner -> type -> signal_handler) {
1327  status = ((*(h -> inner -> type -> signal_handler))
1328  (h -> inner, name, ap));
1329  if (status == ISC_R_SUCCESS)
1330  return status;
1331  }
1332  return ISC_R_NOTFOUND;
1333 }
1334 
1336  omapi_object_t *id,
1337  omapi_object_t *h)
1338 {
1339  struct interface_info *interface;
1340  isc_result_t status;
1341 
1342  if (h -> type != dhcp_type_interface)
1343  return DHCP_R_INVALIDARG;
1344  interface = (struct interface_info *)h;
1345 
1346  /* Write out all the values. */
1347 
1348  status = omapi_connection_put_name (c, "state");
1349  if (status != ISC_R_SUCCESS)
1350  return status;
1351  if ((interface->flags & INTERFACE_REQUESTED) != 0)
1352  status = omapi_connection_put_string (c, "up");
1353  else
1354  status = omapi_connection_put_string (c, "down");
1355  if (status != ISC_R_SUCCESS)
1356  return status;
1357 
1358  /* Write out the inner object, if any. */
1359  if (h -> inner && h -> inner -> type -> stuff_values) {
1360  status = ((*(h -> inner -> type -> stuff_values))
1361  (c, id, h -> inner));
1362  if (status == ISC_R_SUCCESS)
1363  return status;
1364  }
1365 
1366  return ISC_R_SUCCESS;
1367 }
1368 
1370  omapi_object_t *id,
1371  omapi_object_t *ref)
1372 {
1373  omapi_value_t *tv = (omapi_value_t *)0;
1374  isc_result_t status;
1375  struct interface_info *interface;
1376 
1377  if (!ref)
1378  return DHCP_R_NOKEYS;
1379 
1380  /* First see if we were sent a handle. */
1381  status = omapi_get_value_str (ref, id, "handle", &tv);
1382  if (status == ISC_R_SUCCESS) {
1383  status = omapi_handle_td_lookup (ip, tv -> value);
1384 
1386  if (status != ISC_R_SUCCESS)
1387  return status;
1388 
1389  /* Don't return the object if the type is wrong. */
1390  if ((*ip) -> type != dhcp_type_interface) {
1392  return DHCP_R_INVALIDARG;
1393  }
1394  }
1395 
1396  /* Now look for an interface name. */
1397  status = omapi_get_value_str (ref, id, "name", &tv);
1398  if (status == ISC_R_SUCCESS) {
1399  char *s;
1400  unsigned len;
1401  for (interface = interfaces; interface;
1402  interface = interface -> next) {
1403  s = memchr (interface -> name, 0, IFNAMSIZ);
1404  if (s)
1405  len = s - &interface -> name [0];
1406  else
1407  len = IFNAMSIZ;
1408  if ((tv -> value -> u.buffer.len == len &&
1409  !memcmp (interface -> name,
1410  (char *)tv -> value -> u.buffer.value,
1411  len)))
1412  break;
1413  }
1414  if (!interface) {
1415  for (interface = dummy_interfaces;
1416  interface; interface = interface -> next) {
1417  s = memchr (interface -> name, 0, IFNAMSIZ);
1418  if (s)
1419  len = s - &interface -> name [0];
1420  else
1421  len = IFNAMSIZ;
1422  if ((tv -> value -> u.buffer.len == len &&
1423  !memcmp (interface -> name,
1424  (char *)
1425  tv -> value -> u.buffer.value,
1426  len)))
1427  break;
1428  }
1429  }
1430 
1432  if (*ip && *ip != (omapi_object_t *)interface) {
1434  return DHCP_R_KEYCONFLICT;
1435  } else if (!interface) {
1436  if (*ip)
1438  return ISC_R_NOTFOUND;
1439  } else if (!*ip)
1441  (omapi_object_t *)interface,
1442  MDL);
1443  }
1444 
1445  /* If we get to here without finding an interface, no valid key was
1446  specified. */
1447  if (!*ip)
1448  return DHCP_R_NOKEYS;
1449  return ISC_R_SUCCESS;
1450 }
1451 
1452 /* actually just go discover the interface */
1454  omapi_object_t *id)
1455 {
1456  struct interface_info *hp;
1457  isc_result_t status;
1458 
1459  hp = (struct interface_info *)0;
1460  status = interface_allocate (&hp, MDL);
1461  if (status != ISC_R_SUCCESS)
1462  return status;
1463  hp -> flags = INTERFACE_REQUESTED;
1464  status = interface_reference ((struct interface_info **)lp, hp, MDL);
1465  interface_dereference (&hp, MDL);
1466  return status;
1467 }
1468 
1470  omapi_object_t *id)
1471 {
1472  struct interface_info *interface, *ip, *last;
1473 
1474  interface = (struct interface_info *)lp;
1475 
1476  /* remove from interfaces */
1477  last = 0;
1478  for (ip = interfaces; ip; ip = ip -> next) {
1479  if (ip == interface) {
1480  if (last) {
1481  interface_dereference (&last -> next, MDL);
1482  if (ip -> next)
1483  interface_reference (&last -> next,
1484  ip -> next, MDL);
1485  } else {
1486  interface_dereference (&interfaces, MDL);
1487  if (ip -> next)
1488  interface_reference (&interfaces,
1489  ip -> next, MDL);
1490  }
1491  if (ip -> next)
1492  interface_dereference (&ip -> next, MDL);
1493  break;
1494  }
1495  last = ip;
1496  }
1497  if (!ip)
1498  return ISC_R_NOTFOUND;
1499 
1500  /* add the interface to the dummy_interface list */
1501  if (dummy_interfaces) {
1502  interface_reference (&interface -> next,
1504  interface_dereference (&dummy_interfaces, MDL);
1505  }
1506  interface_reference (&dummy_interfaces, interface, MDL);
1507 
1508  /* do a DHCPRELEASE */
1510  (*dhcp_interface_shutdown_hook) (interface);
1511 
1512  /* remove the io object */
1514 
1515  switch(local_family) {
1516 #ifdef DHCPv6
1517  case AF_INET6:
1518  if_deregister6(interface);
1519  break;
1520 #endif /* DHCPv6 */
1521  case AF_INET:
1522  default:
1523  if_deregister_send(interface);
1524  if_deregister_receive(interface);
1525  break;
1526  }
1527 
1528  return ISC_R_SUCCESS;
1529 }
1530 
1531 void interface_stash (struct interface_info *tptr)
1532 {
1533  struct interface_info **vec;
1534  int delta;
1535 
1536  /* If the registerer didn't assign an index, assign one now. */
1537  if (tptr -> index == -1) {
1538  tptr -> index = interface_count++;
1539  while (tptr -> index < interface_max &&
1540  interface_vector [tptr -> index])
1541  tptr -> index = interface_count++;
1542  }
1543 
1544  if (interface_max <= tptr -> index) {
1545  delta = tptr -> index - interface_max + 10;
1546  vec = dmalloc ((interface_max + delta) *
1547  sizeof (struct interface_info *), MDL);
1548  if (!vec) {
1549  log_error ("interface_stash: allocation failed ");
1550  return;
1551  }
1552 
1553  memset (&vec [interface_max], 0,
1554  (sizeof (struct interface_info *)) * delta);
1555  interface_max += delta;
1556  if (interface_vector) {
1557  memcpy (vec, interface_vector,
1558  (interface_count *
1559  sizeof (struct interface_info *)));
1561  }
1562 
1563  interface_vector = vec;
1564  }
1565 
1566  interface_reference (&interface_vector [tptr -> index], tptr, MDL);
1567  if (tptr -> index >= interface_count)
1568  interface_count = tptr -> index + 1;
1569 #if defined (TRACING)
1571 #endif
1572 }
1573 
1574 void interface_snorf (struct interface_info *tmp, int ir)
1575 {
1576  tmp -> circuit_id = (u_int8_t *)tmp -> name;
1577  tmp -> circuit_id_len = strlen (tmp -> name);
1578  tmp -> remote_id = 0;
1579  tmp -> remote_id_len = 0;
1580  tmp -> flags = ir;
1581  if (interfaces) {
1582  interface_reference (&tmp -> next,
1583  interfaces, MDL);
1584  interface_dereference (&interfaces, MDL);
1585  }
1586  interface_reference (&interfaces, tmp, MDL);
1587 }
#define RC_MISC
Definition: alloc.h:56
#define DHCPv6
Definition: config.h:24
void trace_interface_input(trace_type_t *, unsigned, char *)
void trace_interface_register(trace_type_t *, struct interface_info *)
void trace_outpacket_input(trace_type_t *, unsigned, char *)
void trace_inpacket_input(trace_type_t *, unsigned, char *)
void trace_interface_stop(trace_type_t *)
void trace_outpacket_stop(trace_type_t *)
void trace_inpacket_stop(trace_type_t *)
isc_boolean_t
Definition: data.h:150
#define ISC_TRUE
Definition: data.h:153
#define ISC_FALSE
Definition: data.h:152
#define DHCP_FIXED_NON_UDP
Definition: dhcp.h:36
void if_reinitialize_receive(struct interface_info *)
void maybe_setup_fallback(void)
#define INTERFACE_RUNNING
Definition: dhcpd.h:1426
#define DISCOVER_REQUESTED
Definition: dhcpd.h:701
trace_type_t * inpacket_trace
#define INTERFACE_REQUESTED
Definition: dhcpd.h:1424
void interface_trace_setup(void)
int supports_multiple_interfaces(struct interface_info *)
void if_deregister_send(struct interface_info *)
trace_type_t * outpacket_trace
#define DISCOVER_SERVER
Definition: dhcpd.h:697
#define DISCOVER_SERVER46
Definition: dhcpd.h:700
#define INTERFACE_STREAMS
Definition: dhcpd.h:1429
void try_hw_addr(struct interface_info *info)
#define DISCOVER_RELAY
Definition: dhcpd.h:699
struct subnet * subnets
Definition: mdb.c:32
void if_reinitialize_send(struct interface_info *)
void if_register_linklocal6(struct interface_info *info)
void if_deregister6(struct interface_info *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(* dhcpv6_packet_handler)(struct interface_info *, const char *, int, int, const struct iaddr *, isc_boolean_t)
struct in6_addr local_address6
void if_register_receive(struct interface_info *)
void if_register6(struct interface_info *info, int do_multicast)
int bind_local_address6
#define INTERFACE_AUTOMATIC
Definition: dhcpd.h:1425
const char int line
Definition: dhcpd.h:3802
#define DISCOVER_UNCONFIGURED
Definition: dhcpd.h:698
void if_deregister_receive(struct interface_info *)
trace_type_t * interface_trace
ssize_t receive_packet6(struct interface_info *interface, unsigned char *buf, size_t len, struct sockaddr_in6 *from, struct in6_addr *to_addr, unsigned int *if_index)
const char * file
Definition: dhcpd.h:3802
void if_register_send(struct interface_info *)
isc_result_t got_one_v6(omapi_object_t *)
u_int16_t relay_port
Definition: discover.c:50
isc_result_t dhcp_interface_get_value(omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value)
Definition: discover.c:1262
void end_iface_scan(struct iface_conf_list *ifaces)
Definition: discover.c:382
#define LIFREQ
Definition: discover.c:202
int local_family
Definition: discover.c:59
struct interface_info * interfaces
Definition: discover.c:42
isc_result_t dhcp_interface_create(omapi_object_t **lp, omapi_object_t *id)
Definition: discover.c:1453
isc_result_t interface_initialize(omapi_object_t *ipo, const char *file, int line)
Definition: discover.c:133
struct interface_info * fallback_interface
Definition: discover.c:44
int setup_fallback(struct interface_info **fp, const char *file, int line)
Definition: discover.c:1059
struct in_addr limited_broadcast
Definition: discover.c:57
void discover_interfaces(int state)
Definition: discover.c:571
void add_ipv4_addr_to_interface(struct interface_info *iface, const struct in_addr *addr)
Definition: discover.c:492
int begin_iface_scan(struct iface_conf_list *ifaces)
Definition: discover.c:251
int dhcpv4_over_dhcpv6
Definition: discover.c:51
isc_result_t dhcp_interface_destroy(omapi_object_t *h, const char *file, int line)
Definition: discover.c:1270
int(* dhcp_interface_discovery_hook)(struct interface_info *)
Definition: discover.c:53
int quiet_interface_discovery
Definition: discover.c:47
int(* dhcp_interface_setup_hook)(struct interface_info *, struct iaddr *)
Definition: discover.c:52
isc_result_t interface_setup()
Definition: discover.c:95
void reinitialize_interfaces()
Definition: discover.c:1078
isc_result_t dhcp_interface_set_value(omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_typed_data_t *value)
Definition: discover.c:1225
struct interface_info ** interface_vector
Definition: discover.c:89
isc_result_t dhcp_interface_stuff_values(omapi_object_t *c, omapi_object_t *id, omapi_object_t *h)
Definition: discover.c:1335
u_int16_t remote_port
Definition: discover.c:49
isc_result_t dhcp_interface_lookup(omapi_object_t **ip, omapi_object_t *id, omapi_object_t *ref)
Definition: discover.c:1369
void(* bootp_packet_handler)(struct interface_info *, struct dhcp_packet *, unsigned, unsigned int, struct iaddr, struct hardware *)
Definition: discover.c:70
u_int16_t local_port
Definition: discover.c:48
void interface_stash(struct interface_info *tptr)
Definition: discover.c:1531
struct in_addr local_address
Definition: discover.c:60
int(* dhcp_interface_shutdown_hook)(struct interface_info *)
Definition: discover.c:55
struct interface_info * dummy_interfaces
Definition: discover.c:43
void interface_snorf(struct interface_info *tmp, int ir)
Definition: discover.c:1574
int interfaces_invalidated
Definition: discover.c:46
#define SIOCGLIFFLAGS
Definition: discover.c:201
omapi_object_type_t * dhcp_type_interface
Definition: discover.c:83
int interface_max
Definition: discover.c:91
isc_result_t got_one(omapi_object_t *h)
Definition: discover.c:1093
#define LIFCONF
Definition: discover.c:203
#define SIOCGLIFCONF
Definition: discover.c:200
int if_readsocket(omapi_object_t *h)
Definition: discover.c:1048
int next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces)
Definition: discover.c:315
int interface_count
Definition: discover.c:90
isc_result_t dhcp_interface_signal_handler(omapi_object_t *h, const char *name, va_list ap)
Definition: discover.c:1299
isc_result_t dhcp_interface_remove(omapi_object_t *lp, omapi_object_t *id)
Definition: discover.c:1469
isc_result_t(* dhcp_interface_startup_hook)(struct interface_info *)
Definition: discover.c:54
#define ISC_R_NOTIMPLEMENTED
#define ISC_R_SUCCESS
isc_result_t omapi_value_dereference(omapi_value_t **, const char *, int)
Definition: alloc.c:1060
#define MDL
Definition: omapip.h:567
isc_result_t omapi_connection_put_string(omapi_object_t *, const char *)
Definition: buffer.c:689
#define OMAPI_OBJECT_ALLOC(name, stype, type)
Definition: omapip.h:160
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
isc_result_t omapi_object_dereference(omapi_object_t **, const char *, int)
Definition: alloc.c:593
isc_result_t omapi_unregister_io_object(omapi_object_t *)
Definition: dispatch.c:355
const char int
Definition: omapip.h:442
isc_result_t omapi_handle_td_lookup(omapi_object_t **, omapi_typed_data_t *)
Definition: handle.c:282
isc_result_t omapi_object_type_register(omapi_object_type_t **, const char *, isc_result_t(*)(omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_typed_data_t *), isc_result_t(*)(omapi_object_t *, omapi_object_t *, omapi_data_string_t *, omapi_value_t **), isc_result_t(*)(omapi_object_t *, const char *, int), isc_result_t(*)(omapi_object_t *, const char *, va_list), isc_result_t(*)(omapi_object_t *, omapi_object_t *, omapi_object_t *), isc_result_t(*)(omapi_object_t **, omapi_object_t *, omapi_object_t *), isc_result_t(*)(omapi_object_t **, omapi_object_t *), isc_result_t(*)(omapi_object_t *, omapi_object_t *), isc_result_t(*)(omapi_object_t *, const char *, int), isc_result_t(*)(omapi_object_t **, const char *, int), isc_result_t(*)(size_t), size_t, isc_result_t(*)(omapi_object_t *, const char *, int), int)
Definition: support.c:193
@ omapi_datatype_string
Definition: omapip.h:43
@ omapi_datatype_data
Definition: omapip.h:44
isc_result_t omapi_object_reference(omapi_object_t **, omapi_object_t *, const char *, int)
Definition: alloc.c:571
void * dmalloc(size_t, const char *, int)
Definition: alloc.c:57
int omapi_ds_strcmp(omapi_data_string_t *, const char *)
Definition: support.c:581
void dfree(void *, const char *, int)
Definition: alloc.c:145
isc_result_t omapi_get_value_str(omapi_object_t *, omapi_object_t *, const char *, omapi_value_t **)
Definition: support.c:482
isc_result_t omapi_connection_put_name(omapi_object_t *, const char *)
Definition: buffer.c:678
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__
#define DHCP_R_UNCHANGED
Definition: result.h:51
#define DHCP_R_INVALIDARG
Definition: result.h:49
#define DHCP_R_NOKEYS
Definition: result.h:55
#define DHCP_R_KEYCONFLICT
Definition: result.h:53
Definition: tree.h:60
char * name
Definition: dhcpd.h:1301
struct interface_info * interface
Definition: dhcpd.h:1300
u_int8_t hbuf[HARDWARE_ADDR_LEN+1]
Definition: dhcpd.h:493
Definition: inet.h:31
unsigned char iabuf[16]
Definition: inet.h:33
unsigned len
Definition: inet.h:32
struct LIFCONF conf
Definition: discover.c:232
char name[IF_NAMESIZE+1]
Definition: discover.c:240
isc_uint64_t flags
Definition: discover.c:242
struct sockaddr_storage addr
Definition: discover.c:241
char name[IFNAMSIZ]
Definition: dhcpd.h:1408
struct interface_info * next
Definition: dhcpd.h:1383
struct in6_addr * v6addresses
Definition: dhcpd.h:1393
size_t rbuf_len
Definition: dhcpd.h:1417
unsigned circuit_id_len
Definition: dhcpd.h:1402
unsigned remote_id_len
Definition: dhcpd.h:1406
struct ifreq * ifp
Definition: dhcpd.h:1419
int address_count
Definition: dhcpd.h:1391
struct shared_network * shared_network
Definition: dhcpd.h:1384
int address_max
Definition: dhcpd.h:1392
int configured
Definition: dhcpd.h:1420
u_int32_t flags
Definition: dhcpd.h:1423
struct in_addr * addresses
Definition: dhcpd.h:1388
int v6address_count
Definition: dhcpd.h:1395
u_int8_t * remote_id
Definition: dhcpd.h:1404
int v6address_max
Definition: dhcpd.h:1397
size_t rbuf_offset
Definition: dhcpd.h:1416
u_int8_t * circuit_id
Definition: dhcpd.h:1400
Definition: ip.h:47
Definition: dhcpd.h:405
Definition: dhcpd.h:1075
struct iaddr interface_address
Definition: dhcpd.h:1081
struct element * subnet
Definition: confparse.c:57
trace_type_t * trace_type_register(const char *, void *, void(*)(trace_type_t *, unsigned, char *), void(*)(trace_type_t *), const char *, int)
Definition: data.h:205