Annotation of embedaddon/dhcp/common/discover.c, revision 1.1
1.1 ! misho 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>