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