ISC DHCP  4.4.1
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-2017 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 *,
76  isc_boolean_t);
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  strncpy(tmp->name, info.name, sizeof(tmp->name) - 1);
647  interface_snorf(tmp, ir);
648  interface_dereference(&tmp, MDL);
649  tmp = interfaces; /* XXX */
650  }
651  if (tmp != NULL)
652  try_hw_addr(tmp);
653 
655  (*dhcp_interface_discovery_hook)(tmp);
656  }
657 
658  if ((info.addr.ss_family == AF_INET) &&
659  (local_family == AF_INET)) {
660  struct sockaddr_in *a = (struct sockaddr_in*)&info.addr;
661  struct iaddr addr;
662 
663  /* We don't want the loopback interface. */
664  if (a->sin_addr.s_addr == htonl(INADDR_LOOPBACK) &&
665  ((tmp->flags & INTERFACE_AUTOMATIC) &&
666  ((state == DISCOVER_SERVER) ||
667  (state == DISCOVER_SERVER46))))
668  continue;
669 
670  /* If the only address we have is 0.0.0.0, we
671  shouldn't consider the interface configured. */
672  if (a->sin_addr.s_addr != htonl(INADDR_ANY))
673  tmp->configured = 1;
674 
675  add_ipv4_addr_to_interface(tmp, &a->sin_addr);
676 
677  /* invoke the setup hook */
678  addr.len = 4;
679  memcpy(addr.iabuf, &a->sin_addr.s_addr, addr.len);
681  (*dhcp_interface_setup_hook)(tmp, &addr);
682  }
683  }
684 #ifdef DHCPv6
685  else if ((info.addr.ss_family == AF_INET6) &&
686  (local_family == AF_INET6)) {
687  struct sockaddr_in6 *a =
688  (struct sockaddr_in6*)&info.addr;
689  struct iaddr addr;
690 
691  /* We don't want the loopback interface. */
692  if (IN6_IS_ADDR_LOOPBACK(&a->sin6_addr) &&
693  ((tmp->flags & INTERFACE_AUTOMATIC) &&
694  ((state == DISCOVER_SERVER) ||
695  (state == DISCOVER_SERVER46))))
696  continue;
697 
698  /* If the only address we have is 0.0.0.0, we
699  shouldn't consider the interface configured. */
700  if (IN6_IS_ADDR_UNSPECIFIED(&a->sin6_addr))
701  tmp->configured = 1;
702 
703  add_ipv6_addr_to_interface(tmp, &a->sin6_addr);
704 
705  /* invoke the setup hook */
706  addr.len = 16;
707  memcpy(addr.iabuf, &a->sin6_addr, addr.len);
709  (*dhcp_interface_setup_hook)(tmp, &addr);
710  }
711  }
712 #endif /* DHCPv6 */
713  }
714 
715  if (err) {
716  log_fatal("Error getting interface information.");
717  }
718 
719  end_iface_scan(&ifaces);
720 
721 
722  /* Mock-up an 'ifp' structure which is no longer used in the
723  * new interface-sensing code, but is used in higher layers
724  * (for example to sense fallback interfaces).
725  */
726  for (tmp = interfaces ; tmp != NULL ; tmp = tmp->next) {
727  if (tmp->ifp == NULL) {
728  struct ifreq *tif;
729 
730  tif = (struct ifreq *)dmalloc(sizeof(struct ifreq),
731  MDL);
732  if (tif == NULL)
733  log_fatal("no space for ifp mockup.");
734  strcpy(tif->ifr_name, tmp->name);
735  tmp->ifp = tif;
736  }
737  }
738 
739 
740  /* If we're just trying to get a list of interfaces that we might
741  be able to configure, we can quit now. */
742  if (state == DISCOVER_UNCONFIGURED) {
743  return;
744  }
745 
746  /* Weed out the interfaces that did not have IP addresses. */
747  tmp = last = next = NULL;
748  if (interfaces)
749  interface_reference (&tmp, interfaces, MDL);
750  while (tmp) {
751  if (next)
752  interface_dereference (&next, MDL);
753  if (tmp -> next)
754  interface_reference (&next, tmp -> next, MDL);
755  /* skip interfaces that are running already */
756  if (tmp -> flags & INTERFACE_RUNNING) {
757  interface_dereference(&tmp, MDL);
758  if(next)
759  interface_reference(&tmp, next, MDL);
760  continue;
761  }
762  if ((tmp -> flags & INTERFACE_AUTOMATIC) &&
763  state == DISCOVER_REQUESTED)
764  tmp -> flags &= ~(INTERFACE_AUTOMATIC |
766 
767 #ifdef DHCPv6
768  if (!(tmp->flags & INTERFACE_REQUESTED)) {
769 #else
770  if (!tmp -> ifp || !(tmp -> flags & INTERFACE_REQUESTED)) {
771 #endif /* DHCPv6 */
772  if ((tmp -> flags & INTERFACE_REQUESTED) != ir)
773  log_fatal ("%s: not found", tmp -> name);
774  if (!last) {
775  if (interfaces)
776  interface_dereference (&interfaces,
777  MDL);
778  if (next)
779  interface_reference (&interfaces, next, MDL);
780  } else {
781  interface_dereference (&last -> next, MDL);
782  if (next)
783  interface_reference (&last -> next,
784  next, MDL);
785  }
786  if (tmp -> next)
787  interface_dereference (&tmp -> next, MDL);
788 
789  /* Remember the interface in case we need to know
790  about it later. */
791  if (dummy_interfaces) {
792  interface_reference (&tmp -> next,
794  interface_dereference (&dummy_interfaces, MDL);
795  }
796  interface_reference (&dummy_interfaces, tmp, MDL);
797  interface_dereference (&tmp, MDL);
798  if (next)
799  interface_reference (&tmp, next, MDL);
800  continue;
801  }
802  last = tmp;
803 
804  /* We must have a subnet declaration for each interface. */
805  if (!tmp->shared_network && (state == DISCOVER_SERVER)) {
806  log_info("%s", "");
807  if (local_family == AF_INET) {
808  log_info("No subnet declaration for %s (%s).",
809  tmp->name,
810  (tmp->addresses == NULL) ?
811  "no IPv4 addresses" :
812  inet_ntoa(tmp->addresses[0]));
813 #ifdef DHCPv6
814  } else {
815  if (tmp->v6addresses != NULL) {
816  inet_ntop(AF_INET6,
817  &tmp->v6addresses[0],
818  abuf,
819  sizeof(abuf));
820  } else {
821  strcpy(abuf, "no IPv6 addresses");
822  }
823  log_info("No subnet6 declaration for %s (%s).",
824  tmp->name,
825  abuf);
826 #endif /* DHCPv6 */
827  }
828  if (supports_multiple_interfaces(tmp)) {
829  log_info ("** Ignoring requests on %s. %s",
830  tmp -> name, "If this is not what");
831  log_info (" you want, please write %s",
832 #ifdef DHCPv6
833  (local_family != AF_INET) ?
834  "a subnet6 declaration" :
835 #endif
836  "a subnet declaration");
837  log_info (" in your dhcpd.conf file %s",
838  "for the network segment");
839  log_info (" to %s %s %s",
840  "which interface",
841  tmp -> name, "is attached. **");
842  log_info ("%s", "");
843  goto next;
844  } else {
845  log_error ("You must write a %s",
846 #ifdef DHCPv6
847  (local_family != AF_INET) ?
848  "subnet6 declaration for this" :
849 #endif
850  "subnet declaration for this");
851  log_error ("subnet. You cannot prevent %s",
852  "the DHCP server");
853  log_error ("from listening on this subnet %s",
854  "because your");
855  log_fatal ("operating system does not %s.",
856  "support this capability");
857  }
858  }
859 
860  /* Find subnets that don't have valid interface
861  addresses... */
862  for (subnet = (tmp -> shared_network
863  ? tmp -> shared_network -> subnets
864  : (struct subnet *)0);
865  subnet; subnet = subnet -> next_sibling) {
866  /* Set the interface address for this subnet
867  to the first address we found. */
868  if (subnet->interface_address.len == 0) {
869  if (tmp->address_count > 0) {
872  &tmp->addresses[0].s_addr, 4);
873  } else if (tmp->v6address_count > 0) {
876  &tmp->v6addresses[0].s6_addr,
877  16);
878  } else {
879  /* XXX: should be one */
880  log_error("%s missing an interface "
881  "address", tmp->name);
882  continue;
883  }
884  }
885  }
886 
887  /* Flag the index as not having been set, so that the
888  interface registerer can set it or not as it chooses. */
889  tmp -> index = -1;
890 
891  /* Register the interface... */
892  switch (local_family) {
893  case AF_INET:
894  if (!dhcpv4_over_dhcpv6) {
895  if_register_receive(tmp);
896  if_register_send(tmp);
897  } else {
898  /* get_hw_addr() was called by register. */
899  get_hw_addr(tmp);
900  }
901  break;
902 #ifdef DHCPv6
903  case AF_INET6:
904  if ((state == DISCOVER_SERVER) ||
905  (state == DISCOVER_RELAY)) {
906  if_register6(tmp, 1);
907  } else if (state == DISCOVER_SERVER46) {
908  /* get_hw_addr() was called by if_register*6
909  so now we have to call it explicitly
910  to not leave the hardware address unknown
911  (some code expects it cannot be. */
912  get_hw_addr(tmp);
913  } else {
915  }
916  break;
917 #endif /* DHCPv6 */
918  }
919 
920  interface_stash (tmp);
921  wifcount++;
922 #if defined (F_SETFD)
923  /* if_register*() are no longer always called so
924  descriptors must be checked. */
925  if ((tmp -> rfdesc >= 0) &&
926  (fcntl (tmp -> rfdesc, F_SETFD, 1) < 0))
927  log_error ("Can't set close-on-exec on %s: %m",
928  tmp -> name);
929  if ((tmp -> wfdesc != tmp -> rfdesc) &&
930  (tmp -> wfdesc >= 0) &&
931  (fcntl (tmp -> wfdesc, F_SETFD, 1) < 0))
932  log_error ("Can't set close-on-exec on %s: %m",
933  tmp -> name);
934 #endif
935  next:
936  interface_dereference (&tmp, MDL);
937  if (next)
938  interface_reference (&tmp, next, MDL);
939  }
940 
941  /*
942  * Now register all the remaining interfaces as protocols.
943  * We register with omapi to allow for control of the interface,
944  * we've already registered the fd or socket with the socket
945  * manager as part of if_register_receive().
946  */
947  for (tmp = interfaces; tmp; tmp = tmp -> next) {
948  /* not if it's been registered before */
949  if (tmp -> flags & INTERFACE_RUNNING)
950  continue;
951  if (tmp -> rfdesc == -1)
952  continue;
953  switch (local_family) {
954 #ifdef DHCPv6
955  case AF_INET6:
956 #ifdef RELAY_PORT
957 #define UPSTREAM(ifp) \
958  ((ifp->flags & INTERFACE_STREAMS) == INTERFACE_UPSTREAM)
959 #define DOWNSTREAM(ifp) \
960  ((ifp->flags & INTERFACE_STREAMS) == INTERFACE_DOWNSTREAM)
961 
962  if (relay_port) {
963  /*
964  * The normal IPv6 relay only needs one
965  * socket as long as we find an interface.
966  * When user relay port is defined, and we
967  * have two different UDP ports. One to
968  * receive from DHCP client with port 547,
969  * and the other is user defined for sending
970  * to the server or upstream relay agent.
971  * Thus we need to register sockets for one
972  * upstream and one downstream interfaces.
973  */
974  if (updone && UPSTREAM(tmp))
975  continue;
976  if (downdone && DOWNSTREAM(tmp))
977  continue;
978  }
979 #endif
981  if_readsocket,
982  0, got_one_v6, 0, 0);
983 #ifdef RELAY_PORT
984  if (UPSTREAM(tmp))
985  updone++;
986  else
987  downdone++;
988 #endif
989  break;
990 #endif /* DHCPv6 */
991  case AF_INET:
992  default:
994  if_readsocket,
995  0, got_one, 0, 0);
996  break;
997  }
998 
999  if (status != ISC_R_SUCCESS)
1000  log_fatal ("Can't register I/O handle for %s: %s",
1001  tmp -> name, isc_result_totext (status));
1002 
1003 #if defined(DHCPv6)
1004  /* Only register the first interface for V6, since
1005  * servers and relays all use the same socket.
1006  * XXX: This has some messy side effects if we start
1007  * dynamically adding and removing interfaces, but
1008  * we're well beyond that point in terms of mess.
1009  */
1010  if (((state == DISCOVER_SERVER) || (state == DISCOVER_RELAY))
1011  && (local_family == AF_INET6)
1012 #if defined(RELAY_PORT)
1013  && ((relay_port == 0) || (updone && downdone))
1014 #endif
1015  )
1016  break;
1017 #endif
1018  } /* for (tmp = interfaces; ... */
1019 
1020  if (state == DISCOVER_SERVER && wifcount == 0) {
1021  log_info ("%s", "");
1022  log_fatal ("Not configured to listen on any interfaces!");
1023  }
1024 
1025  if ((local_family == AF_INET) &&
1027  setup_fallback = 1;
1029  }
1030 
1031 #if defined (F_SETFD)
1032  if (fallback_interface) {
1033  if (fcntl (fallback_interface -> rfdesc, F_SETFD, 1) < 0)
1034  log_error ("Can't set close-on-exec on fallback: %m");
1035  if (fallback_interface -> rfdesc != fallback_interface -> wfdesc) {
1036  if (fcntl (fallback_interface -> wfdesc, F_SETFD, 1) < 0)
1037  log_error ("Can't set close-on-exec on fallback: %m");
1038  }
1039  }
1040 #endif /* F_SETFD */
1041 }
1042 
1044  omapi_object_t *h;
1045 {
1046  struct interface_info *ip;
1047 
1048  if (h -> type != dhcp_type_interface)
1049  return -1;
1050  ip = (struct interface_info *)h;
1051  return ip -> rfdesc;
1052 }
1053 
1054 int setup_fallback (struct interface_info **fp, const char *file, int line)
1055 {
1056  isc_result_t status;
1057 
1058  status = interface_allocate (&fallback_interface, file, line);
1059  if (status != ISC_R_SUCCESS)
1060  log_fatal ("Error allocating fallback interface: %s",
1061  isc_result_totext (status));
1062  strcpy (fallback_interface -> name, "fallback");
1064  (*dhcp_interface_setup_hook) (fallback_interface,
1065  (struct iaddr *)0);
1066  status = interface_reference (fp, fallback_interface, file, line);
1067 
1068  fallback_interface -> index = -1;
1070  return status == ISC_R_SUCCESS;
1071 }
1072 
1074 {
1075  struct interface_info *ip;
1076 
1077  for (ip = interfaces; ip; ip = ip -> next) {
1080  }
1081 
1082  if (fallback_interface)
1084 
1086 }
1087 
1088 isc_result_t got_one (h)
1089  omapi_object_t *h;
1090 {
1091  struct sockaddr_in from;
1092  struct hardware hfrom;
1093  struct iaddr ifrom;
1094  int result;
1095  union {
1096  unsigned char packbuf [4095]; /* Packet input buffer.
1097  Must be as large as largest
1098  possible MTU. */
1099  struct dhcp_packet packet;
1100  } u;
1101  struct interface_info *ip;
1102 
1103  if (h -> type != dhcp_type_interface)
1104  return DHCP_R_INVALIDARG;
1105  ip = (struct interface_info *)h;
1106 
1107  again:
1108  if ((result =
1109  receive_packet (ip, u.packbuf, sizeof u, &from, &hfrom)) < 0) {
1110  log_error ("receive_packet failed on %s: %m", ip -> name);
1111  return ISC_R_UNEXPECTED;
1112  }
1113  if (result == 0)
1114  return ISC_R_UNEXPECTED;
1115 
1116  /*
1117  * If we didn't at least get the fixed portion of the BOOTP
1118  * packet, drop the packet.
1119  * Previously we allowed packets with no sname or filename
1120  * as we were aware of at least one client that did. But
1121  * a bug caused short packets to not work and nobody has
1122  * complained, it seems rational to tighten up that
1123  * restriction.
1124  */
1125  if (result < DHCP_FIXED_NON_UDP)
1126  return ISC_R_UNEXPECTED;
1127 
1128 #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
1129  {
1130  /* We retrieve the ifindex from the unused hfrom variable */
1131  unsigned int ifindex;
1132 
1133  memcpy(&ifindex, hfrom.hbuf, sizeof (ifindex));
1134 
1135  /*
1136  * Seek forward from the first interface to find the matching
1137  * source interface by interface index.
1138  */
1139  ip = interfaces;
1140  while ((ip != NULL) && (if_nametoindex(ip->name) != ifindex))
1141  ip = ip->next;
1142  if (ip == NULL)
1143  return ISC_R_NOTFOUND;
1144  }
1145 #endif
1146 
1147  if (bootp_packet_handler) {
1148  ifrom.len = 4;
1149  memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len);
1150 
1151  (*bootp_packet_handler) (ip, &u.packet, (unsigned)result,
1152  from.sin_port, ifrom, &hfrom);
1153  }
1154 
1155  /* If there is buffered data, read again. This is for, e.g.,
1156  bpf, which may return two packets at once. */
1157  if (ip -> rbuf_offset != ip -> rbuf_len)
1158  goto again;
1159  return ISC_R_SUCCESS;
1160 }
1161 
1162 #ifdef DHCPv6
1163 isc_result_t
1165  struct sockaddr_in6 from;
1166  struct in6_addr to;
1167  struct iaddr ifrom;
1168  int result;
1169  char buf[65536]; /* maximum size for a UDP packet is 65536 */
1170  struct interface_info *ip;
1171  int is_unicast;
1172  unsigned int if_idx = 0;
1173 
1174  if (h->type != dhcp_type_interface) {
1175  return DHCP_R_INVALIDARG;
1176  }
1177  ip = (struct interface_info *)h;
1178 
1179  result = receive_packet6(ip, (unsigned char *)buf, sizeof(buf),
1180  &from, &to, &if_idx);
1181  if (result < 0) {
1182  log_error("receive_packet6() failed on %s: %m", ip->name);
1183  return ISC_R_UNEXPECTED;
1184  }
1185 
1186  /* 0 is 'any' interface. */
1187  if (if_idx == 0)
1188  return ISC_R_NOTFOUND;
1189 
1190  if (dhcpv6_packet_handler != NULL) {
1191  /*
1192  * If a packet is not multicast, we assume it is unicast.
1193  */
1194  if (IN6_IS_ADDR_MULTICAST(&to)) {
1195  is_unicast = ISC_FALSE;
1196  } else {
1197  is_unicast = ISC_TRUE;
1198  }
1199 
1200  ifrom.len = 16;
1201  memcpy(ifrom.iabuf, &from.sin6_addr, ifrom.len);
1202 
1203  /* Seek forward to find the matching source interface. */
1204  ip = interfaces;
1205  while ((ip != NULL) && (if_nametoindex(ip->name) != if_idx))
1206  ip = ip->next;
1207 
1208  if (ip == NULL)
1209  return ISC_R_NOTFOUND;
1210 
1211  (*dhcpv6_packet_handler)(ip, buf,
1212  result, from.sin6_port,
1213  &ifrom, is_unicast);
1214  }
1215 
1216  return ISC_R_SUCCESS;
1217 }
1218 #endif /* DHCPv6 */
1219 
1221  omapi_object_t *id,
1223  omapi_typed_data_t *value)
1224 {
1225  struct interface_info *interface;
1226  isc_result_t status;
1227 
1228  if (h -> type != dhcp_type_interface)
1229  return DHCP_R_INVALIDARG;
1230  interface = (struct interface_info *)h;
1231 
1232  if (!omapi_ds_strcmp (name, "name")) {
1233  if ((value -> type == omapi_datatype_data ||
1234  value -> type == omapi_datatype_string) &&
1235  value -> u.buffer.len < sizeof interface -> name) {
1236  memcpy (interface -> name,
1237  value -> u.buffer.value,
1238  value -> u.buffer.len);
1239  interface -> name [value -> u.buffer.len] = 0;
1240  } else
1241  return DHCP_R_INVALIDARG;
1242  return ISC_R_SUCCESS;
1243  }
1244 
1245  /* Try to find some inner object that can take the value. */
1246  if (h -> inner && h -> inner -> type -> set_value) {
1247  status = ((*(h -> inner -> type -> set_value))
1248  (h -> inner, id, name, value));
1249  if (status == ISC_R_SUCCESS || status == DHCP_R_UNCHANGED)
1250  return status;
1251  }
1252 
1253  return ISC_R_NOTFOUND;
1254 }
1255 
1256 
1258  omapi_object_t *id,
1259  omapi_data_string_t *name,
1260  omapi_value_t **value)
1261 {
1262  return ISC_R_NOTIMPLEMENTED;
1263 }
1264 
1266  const char *file, int line)
1267 {
1268  struct interface_info *interface;
1269 
1270  if (h -> type != dhcp_type_interface)
1271  return DHCP_R_INVALIDARG;
1272  interface = (struct interface_info *)h;
1273 
1274  if (interface -> ifp) {
1275  dfree (interface -> ifp, file, line);
1276  interface -> ifp = 0;
1277  }
1278  if (interface -> next)
1279  interface_dereference (&interface -> next, file, line);
1280  if (interface -> rbuf) {
1281  dfree (interface -> rbuf, file, line);
1282  interface -> rbuf = (unsigned char *)0;
1283  }
1284  if (interface -> client)
1285  interface -> client = (struct client_state *)0;
1286 
1287  if (interface -> shared_network)
1290 
1291  return ISC_R_SUCCESS;
1292 }
1293 
1295  const char *name, va_list ap)
1296 {
1297  struct interface_info *ip, *interface;
1298  isc_result_t status;
1299 
1300  if (h -> type != dhcp_type_interface)
1301  return DHCP_R_INVALIDARG;
1302  interface = (struct interface_info *)h;
1303 
1304  /* If it's an update signal, see if the interface is dead right
1305  now, or isn't known at all, and if that's the case, revive it. */
1306  if (!strcmp (name, "update")) {
1307  for (ip = dummy_interfaces; ip; ip = ip -> next)
1308  if (ip == interface)
1309  break;
1311  return (*dhcp_interface_startup_hook) (ip);
1312 
1313  for (ip = interfaces; ip; ip = ip -> next)
1314  if (ip == interface)
1315  break;
1317  return (*dhcp_interface_startup_hook) (ip);
1318  }
1319 
1320  /* Try to find some inner object that can take the value. */
1321  if (h -> inner && h -> inner -> type -> signal_handler) {
1322  status = ((*(h -> inner -> type -> signal_handler))
1323  (h -> inner, name, ap));
1324  if (status == ISC_R_SUCCESS)
1325  return status;
1326  }
1327  return ISC_R_NOTFOUND;
1328 }
1329 
1331  omapi_object_t *id,
1332  omapi_object_t *h)
1333 {
1334  struct interface_info *interface;
1335  isc_result_t status;
1336 
1337  if (h -> type != dhcp_type_interface)
1338  return DHCP_R_INVALIDARG;
1339  interface = (struct interface_info *)h;
1340 
1341  /* Write out all the values. */
1342 
1343  status = omapi_connection_put_name (c, "state");
1344  if (status != ISC_R_SUCCESS)
1345  return status;
1346  if ((interface->flags & INTERFACE_REQUESTED) != 0)
1347  status = omapi_connection_put_string (c, "up");
1348  else
1349  status = omapi_connection_put_string (c, "down");
1350  if (status != ISC_R_SUCCESS)
1351  return status;
1352 
1353  /* Write out the inner object, if any. */
1354  if (h -> inner && h -> inner -> type -> stuff_values) {
1355  status = ((*(h -> inner -> type -> stuff_values))
1356  (c, id, h -> inner));
1357  if (status == ISC_R_SUCCESS)
1358  return status;
1359  }
1360 
1361  return ISC_R_SUCCESS;
1362 }
1363 
1365  omapi_object_t *id,
1366  omapi_object_t *ref)
1367 {
1368  omapi_value_t *tv = (omapi_value_t *)0;
1369  isc_result_t status;
1370  struct interface_info *interface;
1371 
1372  if (!ref)
1373  return DHCP_R_NOKEYS;
1374 
1375  /* First see if we were sent a handle. */
1376  status = omapi_get_value_str (ref, id, "handle", &tv);
1377  if (status == ISC_R_SUCCESS) {
1378  status = omapi_handle_td_lookup (ip, tv -> value);
1379 
1381  if (status != ISC_R_SUCCESS)
1382  return status;
1383 
1384  /* Don't return the object if the type is wrong. */
1385  if ((*ip) -> type != dhcp_type_interface) {
1387  return DHCP_R_INVALIDARG;
1388  }
1389  }
1390 
1391  /* Now look for an interface name. */
1392  status = omapi_get_value_str (ref, id, "name", &tv);
1393  if (status == ISC_R_SUCCESS) {
1394  char *s;
1395  unsigned len;
1396  for (interface = interfaces; interface;
1397  interface = interface -> next) {
1398  s = memchr (interface -> name, 0, IFNAMSIZ);
1399  if (s)
1400  len = s - &interface -> name [0];
1401  else
1402  len = IFNAMSIZ;
1403  if ((tv -> value -> u.buffer.len == len &&
1404  !memcmp (interface -> name,
1405  (char *)tv -> value -> u.buffer.value,
1406  len)))
1407  break;
1408  }
1409  if (!interface) {
1410  for (interface = dummy_interfaces;
1411  interface; interface = interface -> next) {
1412  s = memchr (interface -> name, 0, IFNAMSIZ);
1413  if (s)
1414  len = s - &interface -> name [0];
1415  else
1416  len = IFNAMSIZ;
1417  if ((tv -> value -> u.buffer.len == len &&
1418  !memcmp (interface -> name,
1419  (char *)
1420  tv -> value -> u.buffer.value,
1421  len)))
1422  break;
1423  }
1424  }
1425 
1427  if (*ip && *ip != (omapi_object_t *)interface) {
1429  return DHCP_R_KEYCONFLICT;
1430  } else if (!interface) {
1431  if (*ip)
1433  return ISC_R_NOTFOUND;
1434  } else if (!*ip)
1436  (omapi_object_t *)interface,
1437  MDL);
1438  }
1439 
1440  /* If we get to here without finding an interface, no valid key was
1441  specified. */
1442  if (!*ip)
1443  return DHCP_R_NOKEYS;
1444  return ISC_R_SUCCESS;
1445 }
1446 
1447 /* actually just go discover the interface */
1449  omapi_object_t *id)
1450 {
1451  struct interface_info *hp;
1452  isc_result_t status;
1453 
1454  hp = (struct interface_info *)0;
1455  status = interface_allocate (&hp, MDL);
1456  if (status != ISC_R_SUCCESS)
1457  return status;
1458  hp -> flags = INTERFACE_REQUESTED;
1459  status = interface_reference ((struct interface_info **)lp, hp, MDL);
1460  interface_dereference (&hp, MDL);
1461  return status;
1462 }
1463 
1465  omapi_object_t *id)
1466 {
1467  struct interface_info *interface, *ip, *last;
1468 
1469  interface = (struct interface_info *)lp;
1470 
1471  /* remove from interfaces */
1472  last = 0;
1473  for (ip = interfaces; ip; ip = ip -> next) {
1474  if (ip == interface) {
1475  if (last) {
1476  interface_dereference (&last -> next, MDL);
1477  if (ip -> next)
1478  interface_reference (&last -> next,
1479  ip -> next, MDL);
1480  } else {
1481  interface_dereference (&interfaces, MDL);
1482  if (ip -> next)
1483  interface_reference (&interfaces,
1484  ip -> next, MDL);
1485  }
1486  if (ip -> next)
1487  interface_dereference (&ip -> next, MDL);
1488  break;
1489  }
1490  last = ip;
1491  }
1492  if (!ip)
1493  return ISC_R_NOTFOUND;
1494 
1495  /* add the interface to the dummy_interface list */
1496  if (dummy_interfaces) {
1497  interface_reference (&interface -> next,
1499  interface_dereference (&dummy_interfaces, MDL);
1500  }
1501  interface_reference (&dummy_interfaces, interface, MDL);
1502 
1503  /* do a DHCPRELEASE */
1505  (*dhcp_interface_shutdown_hook) (interface);
1506 
1507  /* remove the io object */
1509 
1510  switch(local_family) {
1511 #ifdef DHCPv6
1512  case AF_INET6:
1513  if_deregister6(interface);
1514  break;
1515 #endif /* DHCPv6 */
1516  case AF_INET:
1517  default:
1518  if_deregister_send(interface);
1519  if_deregister_receive(interface);
1520  break;
1521  }
1522 
1523  return ISC_R_SUCCESS;
1524 }
1525 
1526 void interface_stash (struct interface_info *tptr)
1527 {
1528  struct interface_info **vec;
1529  int delta;
1530 
1531  /* If the registerer didn't assign an index, assign one now. */
1532  if (tptr -> index == -1) {
1533  tptr -> index = interface_count++;
1534  while (tptr -> index < interface_max &&
1535  interface_vector [tptr -> index])
1536  tptr -> index = interface_count++;
1537  }
1538 
1539  if (interface_max <= tptr -> index) {
1540  delta = tptr -> index - interface_max + 10;
1541  vec = dmalloc ((interface_max + delta) *
1542  sizeof (struct interface_info *), MDL);
1543  if (!vec) {
1544  log_error ("interface_stash: allocation failed ");
1545  return;
1546  }
1547 
1548  memset (&vec [interface_max], 0,
1549  (sizeof (struct interface_info *)) * delta);
1550  interface_max += delta;
1551  if (interface_vector) {
1552  memcpy (vec, interface_vector,
1553  (interface_count *
1554  sizeof (struct interface_info *)));
1556  }
1557 
1558  interface_vector = vec;
1559  }
1560 
1561  interface_reference (&interface_vector [tptr -> index], tptr, MDL);
1562  if (tptr -> index >= interface_count)
1563  interface_count = tptr -> index + 1;
1564 #if defined (TRACING)
1566 #endif
1567 }
1568 
1569 void interface_snorf (struct interface_info *tmp, int ir)
1570 {
1571  tmp -> circuit_id = (u_int8_t *)tmp -> name;
1572  tmp -> circuit_id_len = strlen (tmp -> name);
1573  tmp -> remote_id = 0;
1574  tmp -> remote_id_len = 0;
1575  tmp -> flags = ir;
1576  if (interfaces) {
1577  interface_reference (&tmp -> next,
1578  interfaces, MDL);
1579  interface_dereference (&interfaces, MDL);
1580  }
1581  interface_reference (&interfaces, tmp, MDL);
1582 }
#define LIFCONF
Definition: discover.c:200
void if_register_send(struct interface_info *)
#define DHCP_FIXED_NON_UDP
Definition: dhcp.h:36
void(* dhcpv6_packet_handler)(struct interface_info *, const char *, int, int, const struct iaddr *, isc_boolean_t)
u_int16_t local_port
Definition: discover.c:45
const char int line
Definition: dhcpd.h:3782
void try_hw_addr(struct interface_info *info)
char name[IF_NAMESIZE+1]
Definition: discover.c:237
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
#define SIOCGLIFFLAGS
Definition: discover.c:198
void end_iface_scan(struct iface_conf_list *ifaces)
Definition: discover.c:379
isc_result_t omapi_object_reference(omapi_object_t **, omapi_object_t *, const char *, int)
Definition: alloc.c:571
struct shared_network * shared_network
Definition: dhcpd.h:1369
isc_result_t dhcp_interface_destroy(omapi_object_t *h, const char *file, int line)
Definition: discover.c:1265
int if_readsocket(omapi_object_t *h)
Definition: discover.c:1043
char name[IFNAMSIZ]
Definition: dhcpd.h:1393
void if_reinitialize_send(struct interface_info *)
void(* bootp_packet_handler)(struct interface_info *, struct dhcp_packet *, unsigned, unsigned int, struct iaddr, struct hardware *)
Definition: discover.c:67
Definition: dhcpd.h:1061
u_int16_t remote_port
Definition: discover.c:46
void trace_interface_register(trace_type_t *, struct interface_info *)
trace_type_t * interface_trace
#define MDL
Definition: omapip.h:567
isc_result_t dhcp_interface_stuff_values(omapi_object_t *c, omapi_object_t *id, omapi_object_t *h)
Definition: discover.c:1330
unsigned char iabuf[16]
Definition: inet.h:33
#define DHCP_R_INVALIDARG
Definition: result.h:48
omapi_typed_data_t * value
Definition: omapip.h:90
#define DISCOVER_REQUESTED
Definition: dhcpd.h:701
void reinitialize_interfaces()
Definition: discover.c:1073
void trace_outpacket_input(trace_type_t *, unsigned, char *)
isc_result_t dhcp_interface_remove(omapi_object_t *lp, omapi_object_t *id)
Definition: discover.c:1464
struct in_addr * addresses
Definition: dhcpd.h:1373
int dhcpv4_over_dhcpv6
Definition: discover.c:48
int setup_fallback(struct interface_info **fp, const char *file, int line)
Definition: discover.c:1054
#define INTERFACE_RUNNING
Definition: dhcpd.h:1410
int log_error(const char *,...) __attribute__((__format__(__printf__
void add_ipv4_addr_to_interface(struct interface_info *iface, const struct in_addr *addr)
Definition: discover.c:489
struct subnet * subnets
Definition: mdb.c:32
unsigned len
Definition: inet.h:32
#define OMAPI_OBJECT_ALLOC(name, stype, type)
Definition: omapip.h:160
int interface_max
Definition: discover.c:88
void if_deregister_receive(struct interface_info *)
#define DHCP_R_KEYCONFLICT
Definition: result.h:52
void get_hw_addr(struct interface_info *info)
void maybe_setup_fallback(void)
void if_deregister_send(struct interface_info *)
void log_fatal(const char *,...) __attribute__((__format__(__printf__
size_t rbuf_len
Definition: dhcpd.h:1401
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:1257
#define DISCOVER_RELAY
Definition: dhcpd.h:699
#define INTERFACE_AUTOMATIC
Definition: dhcpd.h:1409
void interface_trace_setup(void)
struct omapi_typed_data_t::@3::@4 buffer
int bind_local_address6
size_t rbuf_offset
Definition: dhcpd.h:1400
int interface_count
Definition: discover.c:87
struct LIFCONF conf
Definition: discover.c:229
#define SIOCGLIFCONF
Definition: discover.c:197
void if_deregister6(struct interface_info *info)
char * name
Definition: dhcpd.h:1286
struct interface_info * fallback_interface
Definition: discover.c:42
void trace_outpacket_stop(trace_type_t *)
void trace_inpacket_stop(trace_type_t *)
void if_register_linklocal6(struct interface_info *info)
#define DISCOVER_SERVER
Definition: dhcpd.h:697
isc_result_t omapi_get_value_str(omapi_object_t *, omapi_object_t *, const char *, omapi_value_t **)
Definition: support.c:482
struct iaddr interface_address
Definition: dhcpd.h:1067
isc_result_t dhcp_interface_create(omapi_object_t **lp, omapi_object_t *id)
Definition: discover.c:1448
void trace_inpacket_input(trace_type_t *, unsigned, char *)
trace_type_t * trace_type_register(const char *, void *, void(*)(trace_type_t *, unsigned, char *), void(*)(trace_type_t *), const char *, int)
unsigned circuit_id_len
Definition: dhcpd.h:1387
trace_type_t * inpacket_trace
Definition: dhcpd.h:405
isc_result_t omapi_object_dereference(omapi_object_t **, const char *, int)
Definition: alloc.c:593
Definition: ip.h:47
isc_result_t got_one_v6(omapi_object_t *)
void dfree(void *, const char *, int)
Definition: alloc.c:145
omapi_object_type_t * dhcp_type_interface
Definition: discover.c:80
isc_result_t omapi_handle_td_lookup(omapi_object_t **, omapi_typed_data_t *)
Definition: handle.c:282
int begin_iface_scan(struct iface_conf_list *ifaces)
Definition: discover.c:248
struct in_addr limited_broadcast
Definition: discover.c:54
int int log_info(const char *,...) __attribute__((__format__(__printf__
void * dmalloc(size_t, const char *, int)
Definition: alloc.c:57
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:1220
struct interface_info * interfaces
Definition: discover.c:42
u_int32_t flags
Definition: dhcpd.h:1407
isc_result_t omapi_connection_put_string(omapi_object_t *, const char *)
Definition: buffer.c:689
int interfaces_invalidated
Definition: discover.c:43
void interface_snorf(struct interface_info *tmp, int ir)
Definition: discover.c:1569
int v6address_count
Definition: dhcpd.h:1380
int address_max
Definition: dhcpd.h:1377
int(* dhcp_interface_setup_hook)(struct interface_info *, struct iaddr *)
Definition: discover.c:49
Definition: inet.h:31
isc_result_t omapi_value_dereference(omapi_value_t **, const char *, int)
Definition: alloc.c:1060
u_int8_t * circuit_id
Definition: dhcpd.h:1385
void if_register6(struct interface_info *info, int do_multicast)
int local_family
Definition: discover.c:56
int quiet_interface_discovery
Definition: discover.c:44
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
isc_result_t(* dhcp_interface_startup_hook)(struct interface_info *)
Definition: discover.c:51
#define DISCOVER_UNCONFIGURED
Definition: dhcpd.h:698
struct sockaddr_storage addr
Definition: discover.c:238
#define DHCP_R_NOKEYS
Definition: result.h:54
#define DHCP_R_UNCHANGED
Definition: result.h:50
isc_result_t dhcp_interface_signal_handler(omapi_object_t *h, const char *name, va_list ap)
Definition: discover.c:1294
struct interface_info * next
Definition: dhcpd.h:1368
isc_uint64_t flags
Definition: discover.c:239
const char int
Definition: omapip.h:442
struct interface_info * dummy_interfaces
Definition: discover.c:42
int omapi_ds_strcmp(omapi_data_string_t *, const char *)
Definition: support.c:581
isc_result_t got_one(omapi_object_t *h)
Definition: discover.c:1088
isc_result_t omapi_unregister_io_object(omapi_object_t *)
Definition: dispatch.c:355
isc_result_t interface_initialize(omapi_object_t *ipo, const char *file, int line)
Definition: discover.c:130
Definition: tree.h:60
#define DISCOVER_SERVER46
Definition: dhcpd.h:700
int supports_multiple_interfaces(struct interface_info *)
u_int8_t * remote_id
Definition: dhcpd.h:1389
isc_result_t interface_setup()
Definition: discover.c:92
u_int8_t hbuf[HARDWARE_ADDR_LEN+1]
Definition: dhcpd.h:493
int address_count
Definition: dhcpd.h:1376
unsigned remote_id_len
Definition: dhcpd.h:1391
struct in_addr local_address
Definition: discover.c:57
int(* dhcp_interface_discovery_hook)(struct interface_info *)
Definition: discover.c:50
ssize_t receive_packet(struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *)
u_int16_t relay_port
Definition: discover.c:47
void trace_interface_input(trace_type_t *, unsigned, char *)
const char * file
Definition: dhcpd.h:3782
isc_result_t omapi_connection_put_name(omapi_object_t *, const char *)
Definition: buffer.c:678
int configured
Definition: dhcpd.h:1404
void if_reinitialize_receive(struct interface_info *)
void if_register_receive(struct interface_info *)
struct interface_info ** interface_vector
Definition: discover.c:86
void interface_stash(struct interface_info *tptr)
Definition: discover.c:1526
struct interface_info * interface
Definition: dhcpd.h:1285
trace_type_t * outpacket_trace
#define DHCPv6
Definition: config.h:24
#define LIFREQ
Definition: discover.c:199
int v6address_max
Definition: dhcpd.h:1382
struct in6_addr local_address6
#define INTERFACE_STREAMS
Definition: dhcpd.h:1413
struct ifreq * ifp
Definition: dhcpd.h:1403
void trace_interface_stop(trace_type_t *)
#define RC_MISC
Definition: alloc.h:56
int(* dhcp_interface_shutdown_hook)(struct interface_info *)
Definition: discover.c:52
void discover_interfaces(int state)
Definition: discover.c:568
int next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces)
Definition: discover.c:312
isc_result_t dhcp_interface_lookup(omapi_object_t **ip, omapi_object_t *id, omapi_object_t *ref)
Definition: discover.c:1364
#define INTERFACE_REQUESTED
Definition: dhcpd.h:1408
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)
struct in6_addr * v6addresses
Definition: dhcpd.h:1378