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