]> git.ipfire.org Git - thirdparty/dhcp.git/blame - common/discover.c
- The v6 BSD socket method was updated to use a single UDP BSD socket
[thirdparty/dhcp.git] / common / discover.c
CommitLineData
98bd7ca0 1/* discover.c
fa226d8f 2
98bd7ca0 3 Find and identify the network interfaces. */
fa226d8f
TL
4
5/*
dccb6edf 6 * Copyright (c) 2004-2008 by Internet Systems Consortium, Inc. ("ISC")
98311e4b 7 * Copyright (c) 1995-2003 by Internet Software Consortium
fa226d8f 8 *
98311e4b
DH
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
fa226d8f 12 *
98311e4b
DH
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.
fa226d8f 20 *
98311e4b
DH
21 * Internet Systems Consortium, Inc.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
25 * http://www.isc.org/
49733f31 26 *
98311e4b 27 * This software has been written for Internet Systems Consortium
49733f31 28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
98311e4b 29 * To learn more about Internet Systems Consortium, see
49733f31
TL
30 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
31 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
fa226d8f
TL
33 */
34
fa226d8f 35#include "dhcpd.h"
fe5b0fdd
DH
36
37#define BSD_COMP /* needed on Solaris for SIOCGLIFNUM */
fa226d8f 38#include <sys/ioctl.h>
fe5b0fdd 39#include <errno.h>
fa226d8f 40
8da06bb1
DH
41#ifdef HAVE_NET_IF6_H
42# include <net/if6.h>
43#endif
44
d2bc90bd 45struct interface_info *interfaces, *dummy_interfaces, *fallback_interface;
d758ad8c 46int interfaces_invalidated;
fa226d8f 47int quiet_interface_discovery;
38287932
TL
48u_int16_t local_port;
49u_int16_t remote_port;
20916cae
TL
50int (*dhcp_interface_setup_hook) (struct interface_info *, struct iaddr *);
51int (*dhcp_interface_discovery_hook) (struct interface_info *);
cf75fef2 52isc_result_t (*dhcp_interface_startup_hook) (struct interface_info *);
a034015f 53int (*dhcp_interface_shutdown_hook) (struct interface_info *);
38287932
TL
54
55struct in_addr limited_broadcast;
98bd7ca0 56
4ba58919 57int local_family = AF_INET;
38287932 58struct in_addr local_address;
fe5b0fdd
DH
59
60#ifdef DHCPv6
98bd7ca0 61struct in6_addr local_address6;
fe5b0fdd 62#endif /* DHCPv6 */
fa226d8f
TL
63
64void (*bootp_packet_handler) PROTO ((struct interface_info *,
b1b7b521
TL
65 struct dhcp_packet *, unsigned,
66 unsigned int,
fa226d8f 67 struct iaddr, struct hardware *));
fe5b0fdd
DH
68
69#ifdef DHCPv6
98bd7ca0
DH
70void (*dhcpv6_packet_handler)(struct interface_info *,
71 const char *, int,
72 int, const struct iaddr *,
73 isc_boolean_t);
fe5b0fdd 74#endif /* DHCPv6 */
98bd7ca0 75
fa226d8f 76
acc21512 77omapi_object_type_t *dhcp_type_interface;
fc33f8c5
TL
78#if defined (TRACING)
79trace_type_t *interface_trace;
80trace_type_t *inpacket_trace;
81trace_type_t *outpacket_trace;
82#endif
83struct interface_info **interface_vector;
84int interface_count;
85int interface_max;
acc21512 86
20916cae
TL
87OMAPI_OBJECT_ALLOC (interface, struct interface_info, dhcp_type_interface)
88
a034015f
TL
89isc_result_t interface_setup ()
90{
91 isc_result_t status;
92 status = omapi_object_type_register (&dhcp_type_interface,
93 "interface",
94 dhcp_interface_set_value,
95 dhcp_interface_get_value,
96 dhcp_interface_destroy,
97 dhcp_interface_signal_handler,
98 dhcp_interface_stuff_values,
99 dhcp_interface_lookup,
100 dhcp_interface_create,
101 dhcp_interface_remove,
102 0, 0, 0,
103 sizeof (struct interface_info),
98311e4b 104 interface_initialize, RC_MISC);
a034015f
TL
105 if (status != ISC_R_SUCCESS)
106 log_fatal ("Can't register interface object type: %s",
107 isc_result_totext (status));
fc33f8c5 108
a034015f
TL
109 return status;
110}
111
fc33f8c5
TL
112#if defined (TRACING)
113void interface_trace_setup ()
114{
115 interface_trace = trace_type_register ("interface", (void *)0,
116 trace_interface_input,
117 trace_interface_stop, MDL);
118 inpacket_trace = trace_type_register ("inpacket", (void *)0,
119 trace_inpacket_input,
120 trace_inpacket_stop, MDL);
121 outpacket_trace = trace_type_register ("outpacket", (void *)0,
122 trace_outpacket_input,
123 trace_outpacket_stop, MDL);
124}
125#endif
126
08921fe0
TL
127isc_result_t interface_initialize (omapi_object_t *ipo,
128 const char *file, int line)
129{
130 struct interface_info *ip = (struct interface_info *)ipo;
131 ip -> rfdesc = ip -> wfdesc = -1;
132 return ISC_R_SUCCESS;
133}
134
fa226d8f 135
98bd7ca0
DH
136/*
137 * Scanning for Interfaces
138 * -----------------------
139 *
140 * To find interfaces, we create an iterator that abstracts out most
141 * of the platform specifics. Use is fairly straightforward:
142 *
143 * - begin_iface_scan() starts the process.
144 * - Use next_iface() until it returns 0.
145 * - end_iface_scan() performs any necessary cleanup.
146 *
147 * We check for errors on each call to next_iface(), which returns a
148 * description of the error as a string if any occurs.
149 *
150 * We currently have code for Solaris and Linux. Other systems need
151 * to have code written.
152 *
153 * NOTE: the long-term goal is to use the interface code from BIND 9.
154 */
155
8da06bb1
DH
156#if defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && defined(SIOCGLIFFLAGS)
157
158/* HP/UX doesn't define struct lifconf, instead they define struct
159 * if_laddrconf. Similarly, 'struct lifreq' and 'struct lifaddrreq'.
160 */
161#ifdef ISC_PLATFORM_HAVEIF_LADDRCONF
162# define lifc_len iflc_len
163# define lifc_buf iflc_buf
164# define lifc_req iflc_req
165# define LIFCONF if_laddrconf
166#else
167# define ISC_HAVE_LIFC_FAMILY 1
168# define ISC_HAVE_LIFC_FLAGS 1
169# define LIFCONF lifconf
170#endif
171
172#ifdef ISC_PLATFORM_HAVEIF_LADDRREQ
173# define lifr_addr iflr_addr
174# define lifr_name iflr_name
175# define lifr_dstaddr iflr_dstaddr
176# define lifr_flags iflr_flags
177# define sockaddr_storage sockaddr_ext
178# define ss_family sa_family
179# define LIFREQ if_laddrreq
180#else
181# define LIFREQ lifreq
182#endif
183
184#ifndef IF_NAMESIZE
185# if defined(LIFNAMSIZ)
186# define IF_NAMESIZE LIFNAMSIZ
187# elseif defined(IFNAMSIZ)
188# define IF_NAMESIZE IFNAMSIZ
189# else
190# define IF_NAMESIZE 16
191# endif
192#endif
b8c0eda0
MA
193#elif !defined(__linux) && !defined(HAVE_IFADDRS_H)
194# define SIOCGLIFCONF SIOCGIFCONF
195# define SIOCGLIFFLAGS SIOCGIFFLAGS
196# define LIFREQ ifreq
197# define LIFCONF ifconf
198# define lifr_name ifr_name
199# define lifr_addr ifr_addr
200# define lifr_flags ifr_flags
201# define lifc_len ifc_len
202# define lifc_buf ifc_buf
203# define lifc_req ifc_req
204#ifdef _AIX
205# define ss_family __ss_family
206#endif
207#endif
8da06bb1 208
b8c0eda0 209#if defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS)
98bd7ca0
DH
210/*
211 * Solaris support
212 * ---------------
213 *
214 * The SIOCGLIFCONF ioctl() are the extension that you need to use
215 * on Solaris to get information about IPv6 addresses.
216 *
217 * Solaris' extended interface is documented in the if_tcp man page.
218 */
219
220/*
221 * Structure holding state about the scan.
222 */
223struct iface_conf_list {
224 int sock; /* file descriptor used to get information */
225 int num; /* total number of interfaces */
8da06bb1 226 struct LIFCONF conf; /* structure used to get information */
98bd7ca0
DH
227 int next; /* next interface to retrieve when iterating */
228};
229
230/*
231 * Structure used to return information about a specific interface.
232 */
233struct iface_info {
8da06bb1 234 char name[IF_NAMESIZE+1]; /* name of the interface, e.g. "bge0" */
98bd7ca0
DH
235 struct sockaddr_storage addr; /* address information */
236 isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */
237};
238
239/*
240 * Start a scan of interfaces.
241 *
242 * The iface_conf_list structure maintains state for this process.
243 */
244int
245begin_iface_scan(struct iface_conf_list *ifaces) {
8da06bb1 246#ifdef ISC_PLATFORM_HAVELIFNUM
98bd7ca0 247 struct lifnum lifnum;
8da06bb1
DH
248#else
249 int lifnum;
250#endif
98bd7ca0 251
97050349 252 ifaces->sock = socket(local_family, SOCK_DGRAM, IPPROTO_UDP);
98bd7ca0
DH
253 if (ifaces->sock < 0) {
254 log_error("Error creating socket to list interfaces; %m");
255 return 0;
256 }
257
258 memset(&lifnum, 0, sizeof(lifnum));
8da06bb1 259#ifdef ISC_PLATFORM_HAVELIFNUM
98bd7ca0 260 lifnum.lifn_family = AF_UNSPEC;
8da06bb1 261#endif
b8c0eda0 262#ifdef SIOCGLIFNUM
98bd7ca0
DH
263 if (ioctl(ifaces->sock, SIOCGLIFNUM, &lifnum) < 0) {
264 log_error("Error finding total number of interfaces; %m");
265 close(ifaces->sock);
266 ifaces->sock = -1;
267 return 0;
268 }
269
8da06bb1 270#ifdef ISC_PLATFORM_HAVELIFNUM
98bd7ca0 271 ifaces->num = lifnum.lifn_count;
8da06bb1
DH
272#else
273 ifaces->num = lifnum;
274#endif
b8c0eda0
MA
275#else
276 ifaces->num = 64;
277#endif /* SIOCGLIFNUM */
8da06bb1 278
98bd7ca0 279 memset(&ifaces->conf, 0, sizeof(ifaces->conf));
8da06bb1 280#ifdef ISC_HAVE_LIFC_FAMILY
98bd7ca0 281 ifaces->conf.lifc_family = AF_UNSPEC;
8da06bb1
DH
282#endif
283 ifaces->conf.lifc_len = ifaces->num * sizeof(struct LIFREQ);
98bd7ca0
DH
284 ifaces->conf.lifc_buf = dmalloc(ifaces->conf.lifc_len, MDL);
285 if (ifaces->conf.lifc_buf == NULL) {
286 log_fatal("Out of memory getting interface list.");
287 }
288
289 if (ioctl(ifaces->sock, SIOCGLIFCONF, &ifaces->conf) < 0) {
290 log_error("Error getting interfaces configuration list; %m");
291 dfree(ifaces->conf.lifc_buf, MDL);
292 close(ifaces->sock);
293 ifaces->sock = -1;
294 return 0;
295 }
296
297 ifaces->next = 0;
298
299 return 1;
300}
301
302/*
303 * Retrieve the next interface.
304 *
305 * Returns information in the info structure.
99fe695e 306 * Sets err to 1 if there is an error, otherwise 0.
98bd7ca0
DH
307 */
308int
309next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
8da06bb1
DH
310 struct LIFREQ *p;
311 struct LIFREQ tmp;
7285af30
DH
312#if defined(sun) || defined(__linux)
313 /* Pointer used to remove interface aliases. */
fa226d8f 314 char *s;
7285af30 315#endif
acc21512 316
98bd7ca0
DH
317 do {
318 if (ifaces->next >= ifaces->num) {
319 *err = 0;
320 return 0;
321 }
fa226d8f 322
98bd7ca0
DH
323 p = ifaces->conf.lifc_req;
324 p += ifaces->next;
c73ced69 325
98bd7ca0
DH
326 if (strlen(p->lifr_name) >= sizeof(info->name)) {
327 *err = 1;
328 log_error("Interface name '%s' too long", p->lifr_name);
329 return 0;
330 }
331 strcpy(info->name, p->lifr_name);
b8c0eda0
MA
332 memset(&info->addr, 0, sizeof(info->addr));
333 memcpy(&info->addr, &p->lifr_addr, sizeof(p->lifr_addr));
c73ced69 334
fe5b0fdd 335#if defined(sun) || defined(__linux)
98bd7ca0
DH
336 /* interface aliases look like "eth0:1" or "wlan1:3" */
337 s = strchr(info->name, ':');
338 if (s != NULL) {
339 *s = '\0';
340 }
fe5b0fdd 341#endif /* defined(sun) || defined(__linux) */
98bd7ca0 342
98bd7ca0 343 } while (strncmp(info->name, "dummy", 5) == 0);
98bd7ca0
DH
344
345 memset(&tmp, 0, sizeof(tmp));
346 strcpy(tmp.lifr_name, info->name);
347 if (ioctl(ifaces->sock, SIOCGLIFFLAGS, &tmp) < 0) {
348 log_error("Error getting interface flags for '%s'; %m",
349 p->lifr_name);
350 *err = 1;
351 return 0;
352 }
353 info->flags = tmp.lifr_flags;
354
355 ifaces->next++;
356 *err = 0;
357 return 1;
358}
359
360/*
361 * End scan of interfaces.
362 */
363void
364end_iface_scan(struct iface_conf_list *ifaces) {
365 dfree(ifaces->conf.lifc_buf, MDL);
366 close(ifaces->sock);
367 ifaces->sock = -1;
368}
369
370#elif __linux /* !HAVE_SIOCGLIFCONF */
371/*
372 * Linux support
373 * -------------
374 *
375 * In Linux, we use the /proc pseudo-filesystem to get information
376 * about interfaces, along with selected ioctl() calls.
377 *
378 * Linux low level access is documented in the netdevice man page.
379 */
c73ced69 380
98bd7ca0
DH
381/*
382 * Structure holding state about the scan.
383 */
384struct iface_conf_list {
385 int sock; /* file descriptor used to get information */
386 FILE *fp; /* input from /proc/net/dev */
387#ifdef DHCPv6
388 FILE *fp6; /* input from /proc/net/if_inet6 */
615a574a 389#endif
98bd7ca0 390};
c73ced69 391
98bd7ca0
DH
392/*
393 * Structure used to return information about a specific interface.
394 */
395struct iface_info {
396 char name[IFNAMSIZ]; /* name of the interface, e.g. "eth0" */
397 struct sockaddr_storage addr; /* address information */
398 isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */
399};
400
401/*
402 * Start a scan of interfaces.
403 *
404 * The iface_conf_list structure maintains state for this process.
405 */
406int
407begin_iface_scan(struct iface_conf_list *ifaces) {
408 char buf[256];
409 int len;
410 int i;
fa226d8f 411
fe5b0fdd 412 ifaces->fp = fopen("/proc/net/dev", "r");
98bd7ca0 413 if (ifaces->fp == NULL) {
fe5b0fdd 414 log_error("Error opening '/proc/net/dev' to list interfaces");
98bd7ca0
DH
415 return 0;
416 }
fa226d8f 417
98bd7ca0
DH
418 /*
419 * The first 2 lines are header information, so read and ignore them.
420 */
421 for (i=0; i<2; i++) {
422 if (fgets(buf, sizeof(buf), ifaces->fp) == NULL) {
fe5b0fdd 423 log_error("Error reading headers from '/proc/net/dev'");
98bd7ca0
DH
424 fclose(ifaces->fp);
425 ifaces->fp = NULL;
426 return 0;
427 }
428 len = strlen(buf);
429 if ((len <= 0) || (buf[len-1] != '\n')) {
fe5b0fdd 430 log_error("Bad header line in '/proc/net/dev'");
98bd7ca0
DH
431 fclose(ifaces->fp);
432 ifaces->fp = NULL;
433 return 0;
434 }
435 }
436
437 ifaces->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
438 if (ifaces->sock < 0) {
439 log_error("Error creating socket to list interfaces; %m");
440 fclose(ifaces->fp);
441 ifaces->fp = NULL;
442 return 0;
443 }
444
445#ifdef DHCPv6
446 ifaces->fp6 = fopen("/proc/net/if_inet6", "r");
447 if (ifaces->fp6 == NULL) {
448 log_error("Error opening '/proc/net/if_inet6' to "
449 "list IPv6 interfaces; %m");
450 close(ifaces->sock);
451 ifaces->sock = -1;
452 fclose(ifaces->fp);
453 ifaces->fp = NULL;
454 return 0;
31bbee78
TL
455 }
456#endif
457
98bd7ca0
DH
458 return 1;
459}
460
461/*
462 * Read our IPv4 interfaces from /proc/net/dev.
463 *
464 * The file looks something like this:
465 *
466 * Inter-| Receive ...
467 * face |bytes packets errs drop fifo frame ...
468 * lo: 1580562 4207 0 0 0 0 ...
469 * eth0: 0 0 0 0 0 0 ...
470 * eth1:1801552440 37895 0 14 0 ...
471 *
472 * We only care about the interface name, which is at the start of
473 * each line.
474 *
475 * We use an ioctl() to get the address and flags for each interface.
476 */
477static int
478next_iface4(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
479 char buf[256];
480 int len;
481 char *p;
482 char *name;
483 struct ifreq tmp;
484
485 /*
486 * Loop exits when we find an interface that has an address, or
487 * when we run out of interfaces.
488 */
489 for (;;) {
490 do {
491 /*
492 * Read the next line in the file.
493 */
494 if (fgets(buf, sizeof(buf), ifaces->fp) == NULL) {
495 if (ferror(ifaces->fp)) {
496 *err = 1;
497 log_error("Error reading interface "
498 "information");
499 } else {
500 *err = 0;
501 }
502 return 0;
503 }
504
505 /*
506 * Make sure the line is a nice,
507 * newline-terminated line.
508 */
509 len = strlen(buf);
510 if ((len <= 0) || (buf[len-1] != '\n')) {
511 log_error("Bad line reading interface "
512 "information");
513 *err = 1;
514 return 0;
515 }
516
517 /*
518 * Figure out our name.
519 */
520 p = strrchr(buf, ':');
521 if (p == NULL) {
522 log_error("Bad line reading interface "
523 "information (no colon)");
524 *err = 1;
525 return 0;
526 }
527 *p = '\0';
528 name = buf;
529 while (isspace(*name)) {
530 name++;
531 }
532
533 /*
534 * Copy our name into our interface structure.
535 */
536 len = p - name;
537 if (len >= sizeof(info->name)) {
538 *err = 1;
539 log_error("Interface name '%s' too long", name);
540 return 0;
541 }
542 strcpy(info->name, name);
543
544#ifdef ALIAS_NAMED_PERMUTED
545 /* interface aliases look like "eth0:1" or "wlan1:3" */
546 s = strchr(info->name, ':');
547 if (s != NULL) {
548 *s = '\0';
549 }
615a574a 550#endif
98bd7ca0
DH
551
552#ifdef SKIP_DUMMY_INTERFACES
553 } while (strncmp(info->name, "dummy", 5) == 0);
554#else
555 } while (0);
615a574a 556#endif
98bd7ca0
DH
557
558 memset(&tmp, 0, sizeof(tmp));
559 strcpy(tmp.ifr_name, name);
560 if (ioctl(ifaces->sock, SIOCGIFADDR, &tmp) < 0) {
561 if (errno == EADDRNOTAVAIL) {
562 continue;
563 }
564 log_error("Error getting interface address "
565 "for '%s'; %m", name);
566 *err = 1;
567 return 0;
568 }
569 memcpy(&info->addr, &tmp.ifr_addr, sizeof(tmp.ifr_addr));
570
571 memset(&tmp, 0, sizeof(tmp));
572 strcpy(tmp.ifr_name, name);
573 if (ioctl(ifaces->sock, SIOCGIFFLAGS, &tmp) < 0) {
574 log_error("Error getting interface flags for '%s'; %m",
575 name);
576 *err = 1;
577 return 0;
578 }
579 info->flags = tmp.ifr_flags;
580
581 *err = 0;
582 return 1;
583 }
584}
585
586#ifdef DHCPv6
587/*
588 * Read our IPv6 interfaces from /proc/net/if_inet6.
589 *
590 * The file looks something like this:
591 *
592 * fe80000000000000025056fffec00008 05 40 20 80 vmnet8
593 * 00000000000000000000000000000001 01 80 10 80 lo
594 * fe80000000000000025056fffec00001 06 40 20 80 vmnet1
595 * 200108881936000202166ffffe497d9b 03 40 00 00 eth1
596 * fe8000000000000002166ffffe497d9b 03 40 20 80 eth1
597 *
598 * We get IPv6 address from the start, the interface name from the end,
599 * and ioctl() to get flags.
600 */
601static int
602next_iface6(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
603 char buf[256];
604 int len;
605 char *p;
606 char *name;
607 int i;
608 struct sockaddr_in6 addr;
609 struct ifreq tmp;
610
611 do {
612 /*
613 * Read the next line in the file.
614 */
615 if (fgets(buf, sizeof(buf), ifaces->fp6) == NULL) {
616 if (ferror(ifaces->fp6)) {
617 *err = 1;
618 log_error("Error reading IPv6 "
619 "interface information");
620 } else {
621 *err = 0;
622 }
623 return 0;
624 }
625
626 /*
627 * Make sure the line is a nice, newline-terminated line.
628 */
629 len = strlen(buf);
630 if ((len <= 0) || (buf[len-1] != '\n')) {
631 log_error("Bad line reading IPv6 "
632 "interface information");
633 *err = 1;
634 return 0;
635 }
636
637 /*
638 * Figure out our name.
639 */
640 buf[--len] = '\0';
641 p = strrchr(buf, ' ');
642 if (p == NULL) {
643 log_error("Bad line reading IPv6 interface "
644 "information (no space)");
645 *err = 1;
646 return 0;
647 }
648 name = p+1;
649
650 /*
651 * Copy our name into our interface structure.
652 */
653 len = strlen(name);
654 if (len >= sizeof(info->name)) {
655 *err = 1;
656 log_error("IPv6 interface name '%s' too long", name);
657 return 0;
658 }
659 strcpy(info->name, name);
660
661#ifdef SKIP_DUMMY_INTERFACES
662 } while (strncmp(info->name, "dummy", 5) == 0);
663#else
664 } while (0);
665#endif
666
667 /*
668 * Double-check we start with the IPv6 address.
669 */
670 for (i=0; i<32; i++) {
671 if (!isxdigit(buf[i]) || isupper(buf[i])) {
672 *err = 1;
673 log_error("Bad line reading IPv6 interface address "
674 "for '%s'", name);
675 return 0;
676 }
677 }
678
679 /*
680 * Load our socket structure.
681 */
682 memset(&addr, 0, sizeof(addr));
683 addr.sin6_family = AF_INET6;
684 for (i=0; i<16; i++) {
685 unsigned char byte;
686 static const char hex[] = "0123456789abcdef";
687 byte = ((index(hex, buf[i * 2]) - hex) << 4) |
688 (index(hex, buf[i * 2 + 1]) - hex);
689 addr.sin6_addr.s6_addr[i] = byte;
690 }
691 memcpy(&info->addr, &addr, sizeof(addr));
692
693 /*
694 * Get our flags.
695 */
696 memset(&tmp, 0, sizeof(tmp));
697 strcpy(tmp.ifr_name, name);
698 if (ioctl(ifaces->sock, SIOCGIFFLAGS, &tmp) < 0) {
699 log_error("Error getting interface flags for '%s'; %m", name);
700 *err = 1;
701 return 0;
702 }
703 info->flags = tmp.ifr_flags;
704
705 *err = 0;
706 return 1;
707}
708#endif /* DHCPv6 */
709
710/*
711 * Retrieve the next interface.
712 *
713 * Returns information in the info structure.
99fe695e 714 * Sets err to 1 if there is an error, otherwise 0.
98bd7ca0
DH
715 */
716int
717next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
718 if (next_iface4(info, err, ifaces)) {
719 return 1;
720 }
721#ifdef DHCPv6
722 if (!(*err)) {
723 return next_iface6(info, err, ifaces);
724 }
725#endif
726 return 0;
727}
728
729/*
730 * End scan of interfaces.
731 */
732void
733end_iface_scan(struct iface_conf_list *ifaces) {
734 fclose(ifaces->fp);
735 ifaces->fp = NULL;
736 close(ifaces->sock);
737 ifaces->sock = -1;
738#ifdef DHCPv6
739 fclose(ifaces->fp6);
740 ifaces->fp6 = NULL;
741#endif
742}
b8c0eda0 743#else
99fe695e
SK
744
745/*
746 * BSD support
747 * -----------
748 *
749 * FreeBSD, NetBSD, OpenBSD, and OS X all have the getifaddrs()
750 * function.
751 *
752 * The getifaddrs() man page describes the use.
753 */
754
755#include <ifaddrs.h>
756
757/*
758 * Structure holding state about the scan.
759 */
760struct iface_conf_list {
761 struct ifaddrs *head; /* beginning of the list */
762 struct ifaddrs *next; /* current position in the list */
763};
764
765/*
766 * Structure used to return information about a specific interface.
767 */
768struct iface_info {
769 char name[IFNAMSIZ]; /* name of the interface, e.g. "bge0" */
770 struct sockaddr_storage addr; /* address information */
771 isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */
772};
773
774/*
775 * Start a scan of interfaces.
776 *
777 * The iface_conf_list structure maintains state for this process.
778 */
779int
780begin_iface_scan(struct iface_conf_list *ifaces) {
781 if (getifaddrs(&ifaces->head) != 0) {
782 log_error("Error getting interfaces; %m");
783 return 0;
784 }
785 ifaces->next = ifaces->head;
786 return 1;
787}
788
789/*
790 * Retrieve the next interface.
791 *
792 * Returns information in the info structure.
793 * Sets err to 1 if there is an error, otherwise 0.
794 */
795int
796next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
797 if (ifaces->next == NULL) {
798 *err = 0;
799 return 0;
800 }
801 if (strlen(ifaces->next->ifa_name) >= sizeof(info->name)) {
802 log_error("Interface name '%s' too long",
803 ifaces->next->ifa_name);
804 *err = 1;
805 return 0;
806 }
807 strcpy(info->name, ifaces->next->ifa_name);
808 memcpy(&info->addr, ifaces->next->ifa_addr,
809 ifaces->next->ifa_addr->sa_len);
810 info->flags = ifaces->next->ifa_flags;
811 ifaces->next = ifaces->next->ifa_next;
812 *err = 0;
813 return 1;
814}
815
816/*
817 * End scan of interfaces.
818 */
819void
820end_iface_scan(struct iface_conf_list *ifaces) {
821 freeifaddrs(ifaces->head);
822 ifaces->head = NULL;
823 ifaces->next = NULL;
824}
98bd7ca0
DH
825#endif
826
827/* XXX: perhaps create drealloc() rather than do it manually */
828void
829add_ipv4_addr_to_interface(struct interface_info *iface,
830 const struct in_addr *addr) {
831 /*
832 * We don't expect a lot of addresses per IPv4 interface, so
833 * we use 4, as our "chunk size" for collecting addresses.
834 */
835 if (iface->addresses == NULL) {
836 iface->addresses = dmalloc(4 * sizeof(struct in_addr), MDL);
837 if (iface->addresses == NULL) {
838 log_fatal("Out of memory saving IPv4 address "
839 "on interface.");
840 }
841 iface->address_count = 0;
842 iface->address_max = 4;
843 } else if (iface->address_count >= iface->address_max) {
844 struct in_addr *tmp;
845 int new_max;
846
847 new_max = iface->address_max + 4;
848 tmp = dmalloc(new_max * sizeof(struct in_addr), MDL);
849 if (tmp == NULL) {
850 log_fatal("Out of memory saving IPv4 address "
851 "on interface.");
852 }
853 memcpy(tmp,
854 iface->addresses,
855 iface->address_max * sizeof(struct in_addr));
856 dfree(iface->addresses, MDL);
857 iface->addresses = tmp;
858 iface->address_max = new_max;
859 }
860 iface->addresses[iface->address_count++] = *addr;
861}
862
fe5b0fdd 863#ifdef DHCPv6
98bd7ca0
DH
864/* XXX: perhaps create drealloc() rather than do it manually */
865void
866add_ipv6_addr_to_interface(struct interface_info *iface,
867 const struct in6_addr *addr) {
868 /*
869 * Each IPv6 interface will have at least two IPv6 addresses,
870 * and likely quite a few more. So we use 8, as our "chunk size" for
871 * collecting addresses.
872 */
873 if (iface->v6addresses == NULL) {
874 iface->v6addresses = dmalloc(8 * sizeof(struct in6_addr), MDL);
875 if (iface->v6addresses == NULL) {
876 log_fatal("Out of memory saving IPv6 address "
877 "on interface.");
878 }
879 iface->v6address_count = 0;
880 iface->v6address_max = 8;
881 } else if (iface->v6address_count >= iface->v6address_max) {
882 struct in6_addr *tmp;
883 int new_max;
884
885 new_max = iface->v6address_max + 8;
886 tmp = dmalloc(new_max * sizeof(struct in6_addr), MDL);
887 if (tmp == NULL) {
888 log_fatal("Out of memory saving IPv6 address "
889 "on interface.");
890 }
891 memcpy(tmp,
892 iface->v6addresses,
893 iface->v6address_max * sizeof(struct in6_addr));
894 dfree(iface->v6addresses, MDL);
895 iface->v6addresses = tmp;
896 iface->v6address_max = new_max;
897 }
898 iface->v6addresses[iface->v6address_count++] = *addr;
899}
fe5b0fdd 900#endif /* DHCPv6 */
98bd7ca0
DH
901
902/* Use the SIOCGIFCONF ioctl to get a list of all the attached interfaces.
903 For each interface that's of type INET and not the loopback interface,
904 register that interface with the network I/O software, figure out what
905 subnet it's on, and add it to the list of interfaces. */
906
907void
908discover_interfaces(int state) {
909 struct iface_conf_list ifaces;
910 struct iface_info info;
911 int err;
912
28868515 913 struct interface_info *tmp;
98bd7ca0
DH
914 struct interface_info *last, *next;
915
28868515
SK
916#ifdef DHCPv6
917 char abuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
918#endif /* DHCPv6 */
919
98bd7ca0
DH
920
921 struct subnet *subnet;
922 int ir;
923 isc_result_t status;
924 int wifcount = 0;
925
926 static int setup_fallback = 0;
927
928 if (!begin_iface_scan(&ifaces)) {
929 log_fatal("Can't get list of interfaces.");
d902d52e 930 }
615a574a 931
fa226d8f
TL
932 /* If we already have a list of interfaces, and we're running as
933 a DHCP server, the interfaces were requested. */
934 if (interfaces && (state == DISCOVER_SERVER ||
935 state == DISCOVER_RELAY ||
936 state == DISCOVER_REQUESTED))
937 ir = 0;
938 else if (state == DISCOVER_UNCONFIGURED)
939 ir = INTERFACE_REQUESTED | INTERFACE_AUTOMATIC;
940 else
941 ir = INTERFACE_REQUESTED;
942
d2bc90bd 943 /* Cycle through the list of interfaces looking for IP addresses. */
98bd7ca0 944 while (next_iface(&info, &err, &ifaces)) {
fa226d8f 945
5c0ba9a1 946 /* See if we've seen an interface that matches this one. */
98bd7ca0
DH
947 for (tmp = interfaces; tmp; tmp = tmp->next) {
948 if (!strcmp(tmp->name, info.name))
5c0ba9a1 949 break;
98bd7ca0 950 }
5c0ba9a1 951
98311e4b
DH
952 /* Skip non broadcast interfaces (plus loopback and
953 point-to-point in case an OS incorrectly marks them
954 as broadcast). Also skip down interfaces unless we're
955 trying to get a list of configurable interfaces. */
98bd7ca0
DH
956 if (((!(info.flags & IFF_BROADCAST) ||
957 info.flags & IFF_LOOPBACK ||
958 info.flags & IFF_POINTOPOINT) && !tmp) ||
959 (!(info.flags & IFF_UP) &&
fa226d8f
TL
960 state != DISCOVER_UNCONFIGURED))
961 continue;
962
fa226d8f
TL
963 /* If there isn't already an interface by this name,
964 allocate one. */
98bd7ca0
DH
965 if (tmp == NULL) {
966 status = interface_allocate(&tmp, MDL);
967 if (status != ISC_R_SUCCESS) {
968 log_fatal("Error allocating interface %s: %s",
969 info.name, isc_result_totext(status));
970 }
971 strcpy(tmp->name, info.name);
972 interface_snorf(tmp, ir);
973 interface_dereference(&tmp, MDL);
fc33f8c5 974 tmp = interfaces; /* XXX */
347de8bd
TL
975 }
976
98bd7ca0
DH
977 if (dhcp_interface_discovery_hook) {
978 (*dhcp_interface_discovery_hook)(tmp);
979 }
20916cae 980
98bd7ca0
DH
981 if ((info.addr.ss_family == AF_INET) &&
982 (local_family == AF_INET)) {
983 struct sockaddr_in *a = (struct sockaddr_in*)&info.addr;
fa226d8f
TL
984 struct iaddr addr;
985
98bd7ca0
DH
986 /* We don't want the loopback interface. */
987 if (a->sin_addr.s_addr == htonl(INADDR_LOOPBACK) &&
988 ((tmp->flags & INTERFACE_AUTOMATIC) &&
989 state == DISCOVER_SERVER))
990 continue;
991
992 /* If the only address we have is 0.0.0.0, we
993 shouldn't consider the interface configured. */
994 if (a->sin_addr.s_addr != htonl(INADDR_ANY))
995 tmp->configured = 1;
996
997 add_ipv4_addr_to_interface(tmp, &a->sin_addr);
998
98bd7ca0
DH
999 /* invoke the setup hook */
1000 addr.len = 4;
1001 memcpy(addr.iabuf, &a->sin_addr.s_addr, addr.len);
1002 if (dhcp_interface_setup_hook) {
1003 (*dhcp_interface_setup_hook)(tmp, &addr);
1004 }
1005 }
fe5b0fdd 1006#ifdef DHCPv6
98bd7ca0
DH
1007 else if ((info.addr.ss_family == AF_INET6) &&
1008 (local_family == AF_INET6)) {
1009 struct sockaddr_in6 *a =
1010 (struct sockaddr_in6*)&info.addr;
1011 struct iaddr addr;
fa226d8f
TL
1012
1013 /* We don't want the loopback interface. */
98bd7ca0
DH
1014 if (IN6_IS_ADDR_LOOPBACK(&a->sin6_addr) &&
1015 ((tmp->flags & INTERFACE_AUTOMATIC) &&
acc21512 1016 state == DISCOVER_SERVER))
78c553c4 1017 continue;
fa226d8f 1018
98bd7ca0
DH
1019 /* If the only address we have is 0.0.0.0, we
1020 shouldn't consider the interface configured. */
1021 if (IN6_IS_ADDR_UNSPECIFIED(&a->sin6_addr))
1022 tmp->configured = 1;
fa226d8f 1023
98bd7ca0
DH
1024 add_ipv6_addr_to_interface(tmp, &a->sin6_addr);
1025
98bd7ca0
DH
1026 /* invoke the setup hook */
1027 addr.len = 16;
1028 memcpy(addr.iabuf, &a->sin6_addr, addr.len);
1029 if (dhcp_interface_setup_hook) {
1030 (*dhcp_interface_setup_hook)(tmp, &addr);
1031 }
fa226d8f 1032 }
fe5b0fdd 1033#endif /* DHCPv6 */
fa226d8f
TL
1034 }
1035
98bd7ca0
DH
1036 if (err) {
1037 log_fatal("Error getting interface information.");
1038 }
1039
1040 end_iface_scan(&ifaces);
d902d52e 1041
d2bc90bd 1042
4ba58919
DH
1043 /* Mock-up an 'ifp' structure which is no longer used in the
1044 * new interface-sensing code, but is used in higher layers
1045 * (for example to sense fallback interfaces).
1046 */
1047 for (tmp = interfaces ; tmp != NULL ; tmp = tmp->next) {
1048 if (tmp->ifp == NULL) {
1049 struct ifreq *tif;
1050
1051 tif = (struct ifreq *)dmalloc(sizeof(struct ifreq),
1052 MDL);
1053 if (tif == NULL)
1054 log_fatal("no space for ifp mockup.");
1055 strcpy(tif->ifr_name, tmp->name);
1056 tmp->ifp = tif;
1057 }
1058 }
1059
1060
fa226d8f
TL
1061 /* If we're just trying to get a list of interfaces that we might
1062 be able to configure, we can quit now. */
bdcaf7b9 1063 if (state == DISCOVER_UNCONFIGURED) {
fa226d8f 1064 return;
bdcaf7b9 1065 }
fa226d8f
TL
1066
1067 /* Weed out the interfaces that did not have IP addresses. */
98bd7ca0 1068 tmp = last = next = NULL;
20916cae
TL
1069 if (interfaces)
1070 interface_reference (&tmp, interfaces, MDL);
1071 while (tmp) {
1072 if (next)
1073 interface_dereference (&next, MDL);
1074 if (tmp -> next)
1075 interface_reference (&next, tmp -> next, MDL);
347de8bd 1076 /* skip interfaces that are running already */
98311e4b
DH
1077 if (tmp -> flags & INTERFACE_RUNNING) {
1078 interface_dereference(&tmp, MDL);
1079 if(next)
1080 interface_reference(&tmp, next, MDL);
347de8bd 1081 continue;
98311e4b 1082 }
fa226d8f
TL
1083 if ((tmp -> flags & INTERFACE_AUTOMATIC) &&
1084 state == DISCOVER_REQUESTED)
1085 tmp -> flags &= ~(INTERFACE_AUTOMATIC |
1086 INTERFACE_REQUESTED);
fe5b0fdd
DH
1087
1088#ifdef DHCPv6
98bd7ca0 1089 if (!(tmp->flags & INTERFACE_REQUESTED)) {
fe5b0fdd
DH
1090#else
1091 if (!tmp -> ifp || !(tmp -> flags & INTERFACE_REQUESTED)) {
1092#endif /* DHCPv6 */
fa226d8f 1093 if ((tmp -> flags & INTERFACE_REQUESTED) != ir)
8ae2d595 1094 log_fatal ("%s: not found", tmp -> name);
20916cae
TL
1095 if (!last) {
1096 if (interfaces)
1097 interface_dereference (&interfaces,
1098 MDL);
fc33f8c5 1099 if (next)
20916cae
TL
1100 interface_reference (&interfaces, next, MDL);
1101 } else {
1102 interface_dereference (&last -> next, MDL);
fc33f8c5
TL
1103 if (next)
1104 interface_reference (&last -> next,
1105 next, MDL);
20916cae
TL
1106 }
1107 if (tmp -> next)
1108 interface_dereference (&tmp -> next, MDL);
fa226d8f
TL
1109
1110 /* Remember the interface in case we need to know
1111 about it later. */
20916cae
TL
1112 if (dummy_interfaces) {
1113 interface_reference (&tmp -> next,
1114 dummy_interfaces, MDL);
1115 interface_dereference (&dummy_interfaces, MDL);
1116 }
1117 interface_reference (&dummy_interfaces, tmp, MDL);
1118 interface_dereference (&tmp, MDL);
1119 if (next)
1120 interface_reference (&tmp, next, MDL);
fa226d8f
TL
1121 continue;
1122 }
1123 last = tmp;
1124
fa226d8f 1125 /* We must have a subnet declaration for each interface. */
98bd7ca0
DH
1126 if (!tmp->shared_network && (state == DISCOVER_SERVER)) {
1127 log_error("%s", "");
1128 if (local_family == AF_INET) {
1129 log_error("No subnet declaration for %s (%s).",
1130 tmp->name,
f796f70a
DH
1131 (tmp->addresses == NULL) ?
1132 "no IPv4 addresses" :
1133 inet_ntoa(tmp->addresses[0]));
fe5b0fdd 1134#ifdef DHCPv6
98bd7ca0
DH
1135 } else {
1136 if (tmp->v6addresses != NULL) {
1137 inet_ntop(AF_INET6,
1138 &tmp->v6addresses[0],
1139 abuf,
1140 sizeof(abuf));
1141 } else {
f796f70a 1142 strcpy(abuf, "no IPv6 addresses");
98bd7ca0 1143 }
00a002fc 1144 log_error("No subnet6 declaration for %s (%s).",
98bd7ca0
DH
1145 tmp->name,
1146 abuf);
fe5b0fdd 1147#endif /* DHCPv6 */
98bd7ca0
DH
1148 }
1149 if (supports_multiple_interfaces(tmp)) {
21fd88ea
TL
1150 log_error ("** Ignoring requests on %s. %s",
1151 tmp -> name, "If this is not what");
1152 log_error (" you want, please write %s",
00a002fc
MA
1153#ifdef DHCPv6
1154 (local_family != AF_INET) ?
1155 "a subnet6 declaration" :
1156#endif
21fd88ea
TL
1157 "a subnet declaration");
1158 log_error (" in your dhcpd.conf file %s",
1159 "for the network segment");
1160 log_error (" to %s %s %s",
5cefe5e5 1161 "which interface",
21fd88ea
TL
1162 tmp -> name, "is attached. **");
1163 log_error ("%s", "");
5cefe5e5
TL
1164 goto next;
1165 } else {
00a002fc
MA
1166 log_error ("You must write a %s",
1167#ifdef DHCPv6
1168 (local_family != AF_INET) ?
1169 "subnet6 declaration for this" :
1170#endif
1171 "subnet declaration for this");
5cefe5e5
TL
1172 log_error ("subnet. You cannot prevent %s",
1173 "the DHCP server");
1174 log_error ("from listening on this subnet %s",
1175 "because your");
1176 log_fatal ("operating system does not %s.",
1177 "support this capability");
1178 }
74f45f96 1179 }
fa226d8f
TL
1180
1181 /* Find subnets that don't have valid interface
1182 addresses... */
1183 for (subnet = (tmp -> shared_network
1184 ? tmp -> shared_network -> subnets
1185 : (struct subnet *)0);
1186 subnet; subnet = subnet -> next_sibling) {
97050349
SK
1187 /* Set the interface address for this subnet
1188 to the first address we found. */
1189 if (subnet->interface_address.len == 0) {
1190 if (tmp->address_count > 0) {
1191 subnet->interface_address.len = 4;
1192 memcpy(subnet->interface_address.iabuf,
1193 &tmp->addresses[0].s_addr, 4);
1194 } else if (tmp->v6address_count > 0) {
1195 subnet->interface_address.len = 16;
1196 memcpy(subnet->interface_address.iabuf,
1197 &tmp->v6addresses[0].s6_addr,
1198 16);
1199 } else {
1200 /* XXX: should be one */
1201 log_error("%s missing an interface "
1202 "address", tmp->name);
1203 continue;
1204 }
fa226d8f
TL
1205 }
1206 }
1207
fc33f8c5
TL
1208 /* Flag the index as not having been set, so that the
1209 interface registerer can set it or not as it chooses. */
1210 tmp -> index = -1;
1211
fa226d8f 1212 /* Register the interface... */
98bd7ca0
DH
1213 if (local_family == AF_INET) {
1214 if_register_receive(tmp);
1215 if_register_send(tmp);
fe5b0fdd 1216#ifdef DHCPv6
98bd7ca0 1217 } else {
7de20a95
EH
1218 if ((state == DISCOVER_SERVER) ||
1219 (state == DISCOVER_RELAY)) {
98bd7ca0
DH
1220 if_register6(tmp, 1);
1221 } else {
1222 if_register6(tmp, 0);
1223 }
fe5b0fdd 1224#endif /* DHCPv6 */
98bd7ca0 1225 }
fc33f8c5
TL
1226
1227 interface_stash (tmp);
d902d52e 1228 wifcount++;
fe5b0fdd 1229#if defined (F_SETFD)
d4417aa1
TL
1230 if (fcntl (tmp -> rfdesc, F_SETFD, 1) < 0)
1231 log_error ("Can't set close-on-exec on %s: %m",
1232 tmp -> name);
1233 if (tmp -> rfdesc != tmp -> wfdesc) {
1234 if (fcntl (tmp -> wfdesc, F_SETFD, 1) < 0)
1235 log_error ("Can't set close-on-exec on %s: %m",
1236 tmp -> name);
1237 }
1238#endif
5cefe5e5 1239 next:
20916cae
TL
1240 interface_dereference (&tmp, MDL);
1241 if (next)
1242 interface_reference (&tmp, next, MDL);
fa226d8f
TL
1243 }
1244
1245 /* Now register all the remaining interfaces as protocols. */
acc21512 1246 for (tmp = interfaces; tmp; tmp = tmp -> next) {
347de8bd
TL
1247 /* not if it's been registered before */
1248 if (tmp -> flags & INTERFACE_RUNNING)
1249 continue;
08921fe0
TL
1250 if (tmp -> rfdesc == -1)
1251 continue;
06eb8bab
SK
1252#ifdef DHCPv6
1253 if (local_family == AF_INET6) {
98bd7ca0
DH
1254 status = omapi_register_io_object((omapi_object_t *)tmp,
1255 if_readsocket,
06eb8bab 1256 0, got_one_v6, 0, 0);
98bd7ca0 1257 } else {
06eb8bab
SK
1258#else
1259 {
1260#endif /* DHCPv6 */
98bd7ca0
DH
1261 status = omapi_register_io_object((omapi_object_t *)tmp,
1262 if_readsocket,
06eb8bab 1263 0, got_one, 0, 0);
98bd7ca0 1264 }
acc21512
TL
1265 if (status != ISC_R_SUCCESS)
1266 log_fatal ("Can't register I/O handle for %s: %s",
1267 tmp -> name, isc_result_totext (status));
ecddae64
DH
1268
1269#if defined(DHCPv6)
1270 /* Only register the first interface for V6, since they all
1271 * use the same socket. XXX: This has some messy side
1272 * effects if we start dynamically adding and removing
1273 * interfaces, but we're well beyond that point in terms of
1274 * mess.
1275 */
1276 if (local_family == AF_INET6)
1277 break;
1278#endif
acc21512 1279 }
fa226d8f 1280
d902d52e
TL
1281 if (state == DISCOVER_SERVER && wifcount == 0) {
1282 log_info ("%s", "");
1283 log_fatal ("Not configured to listen on any interfaces!");
1284 }
1285
98bd7ca0 1286 if ((local_family == AF_INET) && !setup_fallback) {
bdcaf7b9 1287 setup_fallback = 1;
98bd7ca0 1288 maybe_setup_fallback();
bdcaf7b9
TL
1289 }
1290
fe5b0fdd 1291#if defined (F_SETFD)
d4417aa1
TL
1292 if (fallback_interface) {
1293 if (fcntl (fallback_interface -> rfdesc, F_SETFD, 1) < 0)
1294 log_error ("Can't set close-on-exec on fallback: %m");
1295 if (fallback_interface -> rfdesc != fallback_interface -> wfdesc) {
1296 if (fcntl (fallback_interface -> wfdesc, F_SETFD, 1) < 0)
1297 log_error ("Can't set close-on-exec on fallback: %m");
1298 }
1299 }
fe5b0fdd 1300#endif /* F_SETFD */
d2bc90bd
TL
1301}
1302
acc21512
TL
1303int if_readsocket (h)
1304 omapi_object_t *h;
1305{
1306 struct interface_info *ip;
1307
1308 if (h -> type != dhcp_type_interface)
0a759381 1309 return -1;
acc21512
TL
1310 ip = (struct interface_info *)h;
1311 return ip -> rfdesc;
1312}
1313
20916cae 1314int setup_fallback (struct interface_info **fp, const char *file, int line)
d2bc90bd 1315{
20916cae
TL
1316 isc_result_t status;
1317
1318 status = interface_allocate (&fallback_interface, file, line);
1319 if (status != ISC_R_SUCCESS)
1320 log_fatal ("Error allocating fallback interface: %s",
1321 isc_result_totext (status));
d2bc90bd 1322 strcpy (fallback_interface -> name, "fallback");
20916cae
TL
1323 if (dhcp_interface_setup_hook)
1324 (*dhcp_interface_setup_hook) (fallback_interface,
1325 (struct iaddr *)0);
1326 status = interface_reference (fp, fallback_interface, file, line);
fc33f8c5 1327
fbd9c67b 1328 fallback_interface -> index = -1;
fc33f8c5 1329 interface_stash (fallback_interface);
20916cae 1330 return status == ISC_R_SUCCESS;
fa226d8f
TL
1331}
1332
1333void reinitialize_interfaces ()
1334{
1335 struct interface_info *ip;
1336
1337 for (ip = interfaces; ip; ip = ip -> next) {
1338 if_reinitialize_receive (ip);
1339 if_reinitialize_send (ip);
1340 }
1341
d2bc90bd
TL
1342 if (fallback_interface)
1343 if_reinitialize_send (fallback_interface);
fa226d8f
TL
1344
1345 interfaces_invalidated = 1;
1346}
d2bc90bd 1347
acc21512
TL
1348isc_result_t got_one (h)
1349 omapi_object_t *h;
fa226d8f
TL
1350{
1351 struct sockaddr_in from;
1352 struct hardware hfrom;
1353 struct iaddr ifrom;
1354 int result;
1355 union {
1356 unsigned char packbuf [4095]; /* Packet input buffer.
1357 Must be as large as largest
1358 possible MTU. */
1359 struct dhcp_packet packet;
1360 } u;
acc21512
TL
1361 struct interface_info *ip;
1362
1363 if (h -> type != dhcp_type_interface)
1364 return ISC_R_INVALIDARG;
1365 ip = (struct interface_info *)h;
fa226d8f 1366
a034015f 1367 again:
fa226d8f
TL
1368 if ((result =
1369 receive_packet (ip, u.packbuf, sizeof u, &from, &hfrom)) < 0) {
8ae2d595 1370 log_error ("receive_packet failed on %s: %m", ip -> name);
acc21512 1371 return ISC_R_UNEXPECTED;
fa226d8f
TL
1372 }
1373 if (result == 0)
acc21512 1374 return ISC_R_UNEXPECTED;
fa226d8f 1375
bb404b74
TL
1376 /* If we didn't at least get the fixed portion of the BOOTP
1377 packet, drop the packet. We're allowing packets with no
1378 sname or filename, because we're aware of at least one
1379 client that sends such packets, but this definitely falls
1380 into the category of being forgiving. */
1381 if (result < DHCP_FIXED_NON_UDP - DHCP_SNAME_LEN - DHCP_FILE_LEN)
1382 return ISC_R_UNEXPECTED;
1383
fa226d8f
TL
1384 if (bootp_packet_handler) {
1385 ifrom.len = 4;
1386 memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len);
1387
b1b7b521 1388 (*bootp_packet_handler) (ip, &u.packet, (unsigned)result,
fa226d8f
TL
1389 from.sin_port, ifrom, &hfrom);
1390 }
a034015f
TL
1391
1392 /* If there is buffered data, read again. This is for, e.g.,
1393 bpf, which may return two packets at once. */
1394 if (ip -> rbuf_offset != ip -> rbuf_len)
1395 goto again;
acc21512
TL
1396 return ISC_R_SUCCESS;
1397}
1398
fe5b0fdd 1399#ifdef DHCPv6
98bd7ca0
DH
1400isc_result_t
1401got_one_v6(omapi_object_t *h) {
1402 struct sockaddr_in6 from;
1403 struct in6_addr to;
1404 struct iaddr ifrom;
1405 int result;
1406 char buf[65536]; /* maximum size for a UDP packet is 65536 */
1407 struct interface_info *ip;
1408 int is_unicast;
ecddae64 1409 unsigned int if_idx = 0;
98bd7ca0
DH
1410
1411 if (h->type != dhcp_type_interface) {
1412 return ISC_R_INVALIDARG;
1413 }
1414 ip = (struct interface_info *)h;
1415
28868515 1416 result = receive_packet6(ip, (unsigned char *)buf, sizeof(buf),
ecddae64 1417 &from, &to, &if_idx);
98bd7ca0
DH
1418 if (result < 0) {
1419 log_error("receive_packet6() failed on %s: %m", ip->name);
1420 return ISC_R_UNEXPECTED;
1421 }
1422
ecddae64
DH
1423 /* 0 is 'any' interface. */
1424 if (if_idx == 0)
1425 return ISC_R_NOTFOUND;
1426
98bd7ca0
DH
1427 if (dhcpv6_packet_handler != NULL) {
1428 /*
1429 * If a packet is not multicast, we assume it is unicast.
1430 */
1431 if (IN6_IS_ADDR_MULTICAST(&to)) {
1432 is_unicast = ISC_FALSE;
1433 } else {
1434 is_unicast = ISC_TRUE;
1435 }
1436
1437 ifrom.len = 16;
1438 memcpy(ifrom.iabuf, &from.sin6_addr, ifrom.len);
1439
ecddae64
DH
1440 /* Seek forward to find the matching source interface. */
1441 while ((ip != NULL) && (if_nametoindex(ip->name) != if_idx))
1442 ip = ip->next;
1443
1444 if (ip == NULL)
1445 return ISC_R_NOTFOUND;
1446
98bd7ca0
DH
1447 (*dhcpv6_packet_handler)(ip, buf,
1448 result, from.sin6_port,
1449 &ifrom, is_unicast);
1450 }
1451
1452 return ISC_R_SUCCESS;
1453}
fe5b0fdd 1454#endif /* DHCPv6 */
98bd7ca0 1455
a034015f
TL
1456isc_result_t dhcp_interface_set_value (omapi_object_t *h,
1457 omapi_object_t *id,
1458 omapi_data_string_t *name,
1459 omapi_typed_data_t *value)
acc21512 1460{
a034015f
TL
1461 struct interface_info *interface;
1462 isc_result_t status;
a034015f 1463
acc21512
TL
1464 if (h -> type != dhcp_type_interface)
1465 return ISC_R_INVALIDARG;
a034015f
TL
1466 interface = (struct interface_info *)h;
1467
1468 if (!omapi_ds_strcmp (name, "name")) {
1469 if ((value -> type == omapi_datatype_data ||
1470 value -> type == omapi_datatype_string) &&
1471 value -> u.buffer.len < sizeof interface -> name) {
1472 memcpy (interface -> name,
1473 value -> u.buffer.value,
1474 value -> u.buffer.len);
1475 interface -> name [value -> u.buffer.len] = 0;
1476 } else
1477 return ISC_R_INVALIDARG;
1478 return ISC_R_SUCCESS;
1479 }
1480
1481 /* Try to find some inner object that can take the value. */
1482 if (h -> inner && h -> inner -> type -> set_value) {
1483 status = ((*(h -> inner -> type -> set_value))
1484 (h -> inner, id, name, value));
1485 if (status == ISC_R_SUCCESS || status == ISC_R_UNCHANGED)
1486 return status;
1487 }
1488
acc21512
TL
1489 return ISC_R_NOTFOUND;
1490}
1491
a034015f
TL
1492
1493isc_result_t dhcp_interface_get_value (omapi_object_t *h,
1494 omapi_object_t *id,
1495 omapi_data_string_t *name,
1496 omapi_value_t **value)
acc21512 1497{
a034015f
TL
1498 return ISC_R_NOTIMPLEMENTED;
1499}
1500
1501isc_result_t dhcp_interface_destroy (omapi_object_t *h,
1502 const char *file, int line)
1503{
1504 struct interface_info *interface;
a034015f 1505
acc21512
TL
1506 if (h -> type != dhcp_type_interface)
1507 return ISC_R_INVALIDARG;
a034015f
TL
1508 interface = (struct interface_info *)h;
1509
d758ad8c 1510 if (interface -> ifp) {
a034015f 1511 dfree (interface -> ifp, file, line);
d758ad8c
TL
1512 interface -> ifp = 0;
1513 }
1514 if (interface -> next)
1515 interface_dereference (&interface -> next, file, line);
1516 if (interface -> rbuf) {
1517 dfree (interface -> rbuf, file, line);
1518 interface -> rbuf = (unsigned char *)0;
1519 }
1520 if (interface -> client)
1521 interface -> client = (struct client_state *)0;
1522
1523 if (interface -> shared_network)
1524 omapi_object_dereference ((omapi_object_t **)
1525 &interface -> shared_network, MDL);
1526
a034015f 1527 return ISC_R_SUCCESS;
acc21512
TL
1528}
1529
a034015f
TL
1530isc_result_t dhcp_interface_signal_handler (omapi_object_t *h,
1531 const char *name, va_list ap)
acc21512 1532{
a034015f 1533 struct interface_info *ip, *interface;
a034015f
TL
1534 isc_result_t status;
1535
1536 if (h -> type != dhcp_type_interface)
acc21512 1537 return ISC_R_INVALIDARG;
a034015f
TL
1538 interface = (struct interface_info *)h;
1539
cf75fef2
TL
1540 /* If it's an update signal, see if the interface is dead right
1541 now, or isn't known at all, and if that's the case, revive it. */
1542 if (!strcmp (name, "update")) {
1543 for (ip = dummy_interfaces; ip; ip = ip -> next)
1544 if (ip == interface)
1545 break;
1546 if (ip && dhcp_interface_startup_hook)
1547 return (*dhcp_interface_startup_hook) (ip);
a034015f 1548
cf75fef2
TL
1549 for (ip = interfaces; ip; ip = ip -> next)
1550 if (ip == interface)
1551 break;
1552 if (!ip && dhcp_interface_startup_hook)
1553 return (*dhcp_interface_startup_hook) (ip);
a034015f 1554 }
a034015f 1555
a034015f
TL
1556 /* Try to find some inner object that can take the value. */
1557 if (h -> inner && h -> inner -> type -> get_value) {
1558 status = ((*(h -> inner -> type -> signal_handler))
1559 (h -> inner, name, ap));
1560 if (status == ISC_R_SUCCESS)
1561 return status;
1562 }
acc21512
TL
1563 return ISC_R_NOTFOUND;
1564}
1565
a034015f
TL
1566isc_result_t dhcp_interface_stuff_values (omapi_object_t *c,
1567 omapi_object_t *id,
1568 omapi_object_t *h)
acc21512 1569{
a034015f
TL
1570 struct interface_info *interface;
1571 isc_result_t status;
acc21512 1572
acc21512
TL
1573 if (h -> type != dhcp_type_interface)
1574 return ISC_R_INVALIDARG;
a034015f
TL
1575 interface = (struct interface_info *)h;
1576
1577 /* Write out all the values. */
1578
1579 status = omapi_connection_put_name (c, "state");
1580 if (status != ISC_R_SUCCESS)
1581 return status;
c1e6c832 1582 if ((interface->flags & INTERFACE_REQUESTED) != 0)
a034015f
TL
1583 status = omapi_connection_put_string (c, "up");
1584 else
1585 status = omapi_connection_put_string (c, "down");
1586 if (status != ISC_R_SUCCESS)
1587 return status;
1588
1589 /* Write out the inner object, if any. */
1590 if (h -> inner && h -> inner -> type -> stuff_values) {
1591 status = ((*(h -> inner -> type -> stuff_values))
1592 (c, id, h -> inner));
1593 if (status == ISC_R_SUCCESS)
1594 return status;
1595 }
1596
acc21512
TL
1597 return ISC_R_SUCCESS;
1598}
1599
a034015f
TL
1600isc_result_t dhcp_interface_lookup (omapi_object_t **ip,
1601 omapi_object_t *id,
1602 omapi_object_t *ref)
acc21512 1603{
a034015f
TL
1604 omapi_value_t *tv = (omapi_value_t *)0;
1605 isc_result_t status;
1606 struct interface_info *interface;
1607
d758ad8c
TL
1608 if (!ref)
1609 return ISC_R_NOKEYS;
1610
a034015f
TL
1611 /* First see if we were sent a handle. */
1612 status = omapi_get_value_str (ref, id, "handle", &tv);
1613 if (status == ISC_R_SUCCESS) {
1614 status = omapi_handle_td_lookup (ip, tv -> value);
1615
1616 omapi_value_dereference (&tv, MDL);
1617 if (status != ISC_R_SUCCESS)
1618 return status;
1619
1620 /* Don't return the object if the type is wrong. */
1621 if ((*ip) -> type != dhcp_type_interface) {
1622 omapi_object_dereference (ip, MDL);
1623 return ISC_R_INVALIDARG;
1624 }
1625 }
1626
1627 /* Now look for an interface name. */
1628 status = omapi_get_value_str (ref, id, "name", &tv);
1629 if (status == ISC_R_SUCCESS) {
cf75fef2
TL
1630 char *s;
1631 unsigned len;
a034015f
TL
1632 for (interface = interfaces; interface;
1633 interface = interface -> next) {
cf75fef2
TL
1634 s = memchr (interface -> name, 0, IFNAMSIZ);
1635 if (s)
1636 len = s - &interface -> name [0];
1637 else
1638 len = IFNAMSIZ;
1639 if ((tv -> value -> u.buffer.len == len &&
1640 !memcmp (interface -> name,
1641 (char *)tv -> value -> u.buffer.value,
1642 len)))
a034015f
TL
1643 break;
1644 }
cf75fef2
TL
1645 if (!interface) {
1646 for (interface = dummy_interfaces;
1647 interface; interface = interface -> next) {
1648 s = memchr (interface -> name, 0, IFNAMSIZ);
1649 if (s)
1650 len = s - &interface -> name [0];
1651 else
1652 len = IFNAMSIZ;
1653 if ((tv -> value -> u.buffer.len == len &&
1654 !memcmp (interface -> name,
1655 (char *)
1656 tv -> value -> u.buffer.value,
1657 len)))
1658 break;
1659 }
1660 }
1661
a034015f
TL
1662 omapi_value_dereference (&tv, MDL);
1663 if (*ip && *ip != (omapi_object_t *)interface) {
1664 omapi_object_dereference (ip, MDL);
1665 return ISC_R_KEYCONFLICT;
1666 } else if (!interface) {
1667 if (*ip)
1668 omapi_object_dereference (ip, MDL);
1669 return ISC_R_NOTFOUND;
1670 } else if (!*ip)
a034015f
TL
1671 omapi_object_reference (ip,
1672 (omapi_object_t *)interface,
1673 MDL);
1674 }
1675
1676 /* If we get to here without finding an interface, no valid key was
1677 specified. */
1678 if (!*ip)
1679 return ISC_R_NOKEYS;
1680 return ISC_R_SUCCESS;
1681}
1682
1683/* actually just go discover the interface */
1684isc_result_t dhcp_interface_create (omapi_object_t **lp,
1685 omapi_object_t *id)
1686{
1687 struct interface_info *hp;
1688 isc_result_t status;
acc21512 1689
a034015f
TL
1690 hp = (struct interface_info *)0;
1691 status = interface_allocate (&hp, MDL);
1692 if (status != ISC_R_SUCCESS)
1693 return status;
1694 hp -> flags = INTERFACE_REQUESTED;
1695 status = interface_reference ((struct interface_info **)lp, hp, MDL);
1696 interface_dereference (&hp, MDL);
1697 return status;
fa226d8f
TL
1698}
1699
a034015f
TL
1700isc_result_t dhcp_interface_remove (omapi_object_t *lp,
1701 omapi_object_t *id)
1702{
1703 struct interface_info *interface, *ip, *last;
1704
1705 interface = (struct interface_info *)lp;
1706
1707 /* remove from interfaces */
1708 last = 0;
1709 for (ip = interfaces; ip; ip = ip -> next) {
1710 if (ip == interface) {
1711 if (last) {
1712 interface_dereference (&last -> next, MDL);
1713 if (ip -> next)
1714 interface_reference (&last -> next,
1715 ip -> next, MDL);
1716 } else {
1717 interface_dereference (&interfaces, MDL);
1718 if (ip -> next)
1719 interface_reference (&interfaces,
1720 ip -> next, MDL);
1721 }
1722 if (ip -> next)
1723 interface_dereference (&ip -> next, MDL);
1724 break;
1725 }
1726 last = ip;
1727 }
1728 if (!ip)
1729 return ISC_R_NOTFOUND;
1730
1731 /* add the interface to the dummy_interface list */
1732 if (dummy_interfaces) {
1733 interface_reference (&interface -> next,
1734 dummy_interfaces, MDL);
1735 interface_dereference (&dummy_interfaces, MDL);
1736 }
1737 interface_reference (&dummy_interfaces, interface, MDL);
1738
1739 /* do a DHCPRELEASE */
1740 if (dhcp_interface_shutdown_hook)
1741 (*dhcp_interface_shutdown_hook) (interface);
1742
1743 /* remove the io object */
1744 omapi_unregister_io_object ((omapi_object_t *)interface);
1745
98bd7ca0
DH
1746 if (local_family == AF_INET) {
1747 if_deregister_send(interface);
1748 if_deregister_receive(interface);
fe5b0fdd 1749#ifdef DHCPv6
98bd7ca0
DH
1750 } else {
1751 if_deregister6(interface);
fe5b0fdd 1752#endif /* DHCPv6 */
98bd7ca0 1753 }
a034015f
TL
1754
1755 return ISC_R_SUCCESS;
1756}
fc33f8c5
TL
1757
1758void interface_stash (struct interface_info *tptr)
1759{
1760 struct interface_info **vec;
1761 int delta;
1762
1763 /* If the registerer didn't assign an index, assign one now. */
1764 if (tptr -> index == -1) {
1765 tptr -> index = interface_count++;
1766 while (tptr -> index < interface_max &&
1767 interface_vector [tptr -> index])
1768 tptr -> index = interface_count++;
1769 }
1770
1771 if (interface_max <= tptr -> index) {
1772 delta = tptr -> index - interface_max + 10;
1773 vec = dmalloc ((interface_max + delta) *
1774 sizeof (struct interface_info *), MDL);
1775 if (!vec)
1776 return;
1777 memset (&vec [interface_max], 0,
1778 (sizeof (struct interface_info *)) * delta);
1779 interface_max += delta;
1780 if (interface_vector) {
1781 memcpy (vec, interface_vector,
1782 (interface_count *
1783 sizeof (struct interface_info *)));
1784 dfree (interface_vector, MDL);
1785 }
1786 interface_vector = vec;
1787 }
d758ad8c 1788 interface_reference (&interface_vector [tptr -> index], tptr, MDL);
fc33f8c5
TL
1789 if (tptr -> index >= interface_count)
1790 interface_count = tptr -> index + 1;
1791#if defined (TRACING)
1792 trace_interface_register (interface_trace, tptr);
1793#endif
1794}
1795
1796void interface_snorf (struct interface_info *tmp, int ir)
1797{
1798 tmp -> circuit_id = (u_int8_t *)tmp -> name;
1799 tmp -> circuit_id_len = strlen (tmp -> name);
1800 tmp -> remote_id = 0;
1801 tmp -> remote_id_len = 0;
1802 tmp -> flags = ir;
1803 if (interfaces) {
1804 interface_reference (&tmp -> next,
1805 interfaces, MDL);
1806 interface_dereference (&interfaces, MDL);
1807 }
1808 interface_reference (&interfaces, tmp, MDL);
1809}