source: npl/internetserver/dhcp/dhcommon-getifaddrs.patch @ 929bb42

Last change on this file since 929bb42 was ebc5ae5, checked in by Edwin Eefting <edwin@datux.nl>, 8 years ago

upgraded dhcpd to 4.3.6 for better ipv6 support

  • Property mode set to 100644
File size: 10.5 KB
  • common/discover.c

    description: use getifaddrs() system call, rather than parsing /proc/net on linux
    author: Jiri Popelka <jpopelka@redhat.com>
    origin: http://pkgs.fedoraproject.org/cgit/dhcp.git/tree/dhcp-getifaddrs.patch?id=d12e0eb05e510268ce9b8dcb839e27d5eca9aff5
    bug-debian: https://bugs.debian.org/605657
    bug-ubuntu: https://bugs.launchpad.net/ubuntu/+source/isc-dhcp/+bug/1446767
    bug-fedora: https://bugzilla.redhat.com/show_bug.cgi?id=449946
    
    a b end_iface_scan(struct iface_conf_list *i 
    373373        ifaces->sock = -1;
    374374}
    375375
    376 #elif __linux /* !HAVE_SIOCGLIFCONF */
    377 /*
    378  * Linux support
    379  * -------------
    380  *
    381  * In Linux, we use the /proc pseudo-filesystem to get information
    382  * about interfaces, along with selected ioctl() calls.
    383  *
    384  * Linux low level access is documented in the netdevice man page.
    385  */
    386 
    387 /*
    388  * Structure holding state about the scan.
    389  */
    390 struct iface_conf_list {
    391         int sock;       /* file descriptor used to get information */
    392         FILE *fp;       /* input from /proc/net/dev */
    393 #ifdef DHCPv6
    394         FILE *fp6;      /* input from /proc/net/if_inet6 */
    395 #endif
    396 };
    397 
    398 /*
    399  * Structure used to return information about a specific interface.
    400  */
    401 struct iface_info {
    402         char name[IFNAMSIZ];            /* name of the interface, e.g. "eth0" */
    403         struct sockaddr_storage addr;   /* address information */
    404         isc_uint64_t flags;             /* interface flags, e.g. IFF_LOOPBACK */
    405 };
    406 
    407 /*
    408  * Start a scan of interfaces.
    409  *
    410  * The iface_conf_list structure maintains state for this process.
    411  */
    412 int
    413 begin_iface_scan(struct iface_conf_list *ifaces) {
    414         char buf[IF_LINE_LENGTH];
    415         int len;
    416         int i;
    417 
    418         ifaces->fp = fopen("/proc/net/dev", "r");
    419         if (ifaces->fp == NULL) {
    420                 log_error("Error opening '/proc/net/dev' to list interfaces");
    421                 return 0;
    422         }
    423 
    424         /*
    425          * The first 2 lines are header information, so read and ignore them.
    426          */
    427         for (i=0; i<2; i++) {
    428                 if (fgets(buf, sizeof(buf), ifaces->fp) == NULL) {
    429                         log_error("Error reading headers from '/proc/net/dev'");
    430                         fclose(ifaces->fp);
    431                         ifaces->fp = NULL;
    432                         return 0;
    433                 }
    434                 len = strlen(buf);
    435                 if ((len <= 0) || (buf[len-1] != '\n')) {
    436                         log_error("Bad header line in '/proc/net/dev'");
    437                         fclose(ifaces->fp);
    438                         ifaces->fp = NULL;
    439                         return 0;
    440                 }
    441         }
    442 
    443         ifaces->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    444         if (ifaces->sock < 0) {
    445                 log_error("Error creating socket to list interfaces; %m");
    446                 fclose(ifaces->fp);
    447                 ifaces->fp = NULL;
    448                 return 0;
    449         }
    450 
    451 #ifdef DHCPv6
    452         if (local_family == AF_INET6) {
    453                 ifaces->fp6 = fopen("/proc/net/if_inet6", "r");
    454                 if (ifaces->fp6 == NULL) {
    455                         log_error("Error opening '/proc/net/if_inet6' to "
    456                                   "list IPv6 interfaces; %m");
    457                         close(ifaces->sock);
    458                         ifaces->sock = -1;
    459                         fclose(ifaces->fp);
    460                         ifaces->fp = NULL;
    461                         return 0;
    462                 }
    463         }
    464 #endif
    465 
    466         return 1;
    467 }
    468 
    469 /*
    470  * Read our IPv4 interfaces from /proc/net/dev.
    471  *
    472  * The file looks something like this:
    473  *
    474  * Inter-|   Receive ...
    475  *  face |bytes    packets errs drop fifo frame ...
    476  *     lo: 1580562    4207    0    0    0     0 ...
    477  *   eth0:       0       0    0    0    0     0 ...
    478  *   eth1:1801552440   37895    0   14    0     ...
    479  *
    480  * We only care about the interface name, which is at the start of
    481  * each line.
    482  *
    483  * We use an ioctl() to get the address and flags for each interface.
    484  */
    485 static int
    486 next_iface4(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
    487         char buf[IF_LINE_LENGTH];
    488         int len;
    489         char *p;
    490         char *name;
    491         struct ifreq tmp;
    492 
    493         /*
    494          * Loop exits when we find an interface that has an address, or
    495          * when we run out of interfaces.
    496          */
    497         for (;;) {
    498                 do {
    499                         /*
    500                          *  Read the next line in the file.
    501                          */
    502                         if (fgets(buf, sizeof(buf), ifaces->fp) == NULL) {
    503                                 if (ferror(ifaces->fp)) {
    504                                         *err = 1;
    505                                         log_error("Error reading interface "
    506                                                 "information");
    507                                 } else {
    508                                         *err = 0;
    509                                 }
    510                                 return 0;
    511                         }
    512 
    513                         /*
    514                          * Make sure the line is a nice,
    515                          * newline-terminated line.
    516                          */
    517                         len = strlen(buf);
    518                         if ((len <= 0) || (buf[len-1] != '\n')) {
    519                                 log_error("Bad line reading interface "
    520                                           "information");
    521                                 *err = 1;
    522                                 return 0;
    523                         }
    524 
    525                         /*
    526                          * Figure out our name.
    527                          */
    528                         p = strrchr(buf, ':');
    529                         if (p == NULL) {
    530                                 log_error("Bad line reading interface "
    531                                           "information (no colon)");
    532                                 *err = 1;
    533                                 return 0;
    534                         }
    535                         *p = '\0';
    536                         name = buf;
    537                         while (isspace(*name)) {
    538                                 name++;
    539                         }
    540 
    541                         /*
    542                          * Copy our name into our interface structure.
    543                          */
    544                         len = p - name;
    545                         if (len >= sizeof(info->name)) {
    546                                 *err = 1;
    547                                 log_error("Interface name '%s' too long", name);
    548                                 return 0;
    549                         }
    550                         strncpy(info->name, name, sizeof(info->name) - 1);
    551 
    552 #ifdef ALIAS_NAMED_PERMUTED
    553                         /* interface aliases look like "eth0:1" or "wlan1:3" */
    554                         s = strchr(info->name, ':');
    555                         if (s != NULL) {
    556                                 *s = '\0';
    557                         }
    558 #endif
    559 
    560 #ifdef SKIP_DUMMY_INTERFACES
    561                 } while (strncmp(info->name, "dummy", 5) == 0);
    562 #else
    563                 } while (0);
    564 #endif
    565 
    566                 memset(&tmp, 0, sizeof(tmp));
    567                 strncpy(tmp.ifr_name, name, sizeof(tmp.ifr_name) - 1);
    568                 if (ioctl(ifaces->sock, SIOCGIFADDR, &tmp) < 0) {
    569                         if (errno == EADDRNOTAVAIL) {
    570                                 continue;
    571                         }
    572                         log_error("Error getting interface address "
    573                                   "for '%s'; %m", name);
    574                         *err = 1;
    575                         return 0;
    576                 }
    577                 memcpy(&info->addr, &tmp.ifr_addr, sizeof(tmp.ifr_addr));
    578 
    579                 memset(&tmp, 0, sizeof(tmp));
    580                 strncpy(tmp.ifr_name, name, sizeof(tmp.ifr_name) - 1);
    581                 if (ioctl(ifaces->sock, SIOCGIFFLAGS, &tmp) < 0) {
    582                         log_error("Error getting interface flags for '%s'; %m",
    583                                 name);
    584                         *err = 1;
    585                         return 0;
    586                 }
    587                 info->flags = tmp.ifr_flags;
    588 
    589                 *err = 0;
    590                 return 1;
    591         }
    592 }
    593 
    594 #ifdef DHCPv6
    595 /*
    596  * Read our IPv6 interfaces from /proc/net/if_inet6.
    597  *
    598  * The file looks something like this:
    599  *
    600  * fe80000000000000025056fffec00008 05 40 20 80   vmnet8
    601  * 00000000000000000000000000000001 01 80 10 80       lo
    602  * fe80000000000000025056fffec00001 06 40 20 80   vmnet1
    603  * 200108881936000202166ffffe497d9b 03 40 00 00     eth1
    604  * fe8000000000000002166ffffe497d9b 03 40 20 80     eth1
    605  *
    606  * We get IPv6 address from the start, the interface name from the end,
    607  * and ioctl() to get flags.
    608  */
    609 static int
    610 next_iface6(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
    611         char buf[IF_LINE_LENGTH];
    612         int len;
    613         char *p;
    614         char *name;
    615         int i;
    616         struct sockaddr_in6 addr;
    617         struct ifreq tmp;
    618 
    619         do {
    620                 /*
    621                  *  Read the next line in the file.
    622                  */
    623                 if (fgets(buf, sizeof(buf), ifaces->fp6) == NULL) {
    624                         if (ferror(ifaces->fp6)) {
    625                                 *err = 1;
    626                                 log_error("Error reading IPv6 "
    627                                           "interface information");
    628                         } else {
    629                                 *err = 0;
    630                         }
    631                         return 0;
    632                 }
    633 
    634                 /*
    635                  * Make sure the line is a nice, newline-terminated line.
    636                  */
    637                 len = strlen(buf);
    638                 if ((len <= 0) || (buf[len-1] != '\n')) {
    639                         log_error("Bad line reading IPv6 "
    640                                   "interface information");
    641                         *err = 1;
    642                         return 0;
    643                 }
    644 
    645                 /*
    646                  * Figure out our name.
    647                  */
    648                 buf[--len] = '\0';
    649                 p = strrchr(buf, ' ');
    650                 if (p == NULL) {
    651                         log_error("Bad line reading IPv6 interface "
    652                                   "information (no space)");
    653                         *err = 1;
    654                         return 0;
    655                 }
    656                 name = p+1;
    657 
    658                 /*
    659                  * Copy our name into our interface structure.
    660                  */
    661                 len = strlen(name);
    662                 if (len >= sizeof(info->name)) {
    663                         *err = 1;
    664                         log_error("IPv6 interface name '%s' too long", name);
    665                         return 0;
    666                 }
    667                 strncpy(info->name, name, sizeof(info->name) - 1);
    668 
    669 #ifdef SKIP_DUMMY_INTERFACES
    670         } while (strncmp(info->name, "dummy", 5) == 0);
    671 #else
    672         } while (0);
    673 #endif
    674 
    675         /*
    676          * Double-check we start with the IPv6 address.
    677          */
    678         for (i=0; i<32; i++) {
    679                 if (!isxdigit(buf[i]) || isupper(buf[i])) {
    680                         *err = 1;
    681                         log_error("Bad line reading IPv6 interface address "
    682                                   "for '%s'", name);
    683                         return 0;
    684                 }
    685         }
    686 
    687         /*
    688          * Load our socket structure.
    689          */
    690         memset(&addr, 0, sizeof(addr));
    691         addr.sin6_family = AF_INET6;
    692         for (i=0; i<16; i++) {
    693                 unsigned char byte;
    694                 static const char hex[] = "0123456789abcdef";
    695                 byte = ((index(hex, buf[i * 2]) - hex) << 4) |
    696                         (index(hex, buf[i * 2 + 1]) - hex);
    697                 addr.sin6_addr.s6_addr[i] = byte;
    698         }
    699         memcpy(&info->addr, &addr, sizeof(addr));
    700 
    701         /*
    702          * Get our flags.
    703          */
    704         memset(&tmp, 0, sizeof(tmp));
    705         strncpy(tmp.ifr_name, name, sizeof(tmp.ifr_name) - 1);
    706         if (ioctl(ifaces->sock, SIOCGIFFLAGS, &tmp) < 0) {
    707                 log_error("Error getting interface flags for '%s'; %m", name);
    708                 *err = 1;
    709                 return 0;
    710         }
    711         info->flags = tmp.ifr_flags;
    712 
    713         *err = 0;
    714         return 1;
    715 }
    716 #endif /* DHCPv6 */
    717 
    718 /*
    719  * Retrieve the next interface.
    720  *
    721  * Returns information in the info structure.
    722  * Sets err to 1 if there is an error, otherwise 0.
    723  */
    724 int
    725 next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
    726         memset(info, 0, sizeof(struct iface_info));
    727         if (next_iface4(info, err, ifaces)) {
    728                 return 1;
    729         }
    730 #ifdef DHCPv6
    731         if (!(*err)) {
    732                 if (local_family == AF_INET6)
    733                         return next_iface6(info, err, ifaces);
    734         }
    735 #endif
    736         return 0;
    737 }
    738 
    739 /*
    740  * End scan of interfaces.
    741  */
    742 void
    743 end_iface_scan(struct iface_conf_list *ifaces) {
    744         fclose(ifaces->fp);
    745         ifaces->fp = NULL;
    746         close(ifaces->sock);
    747         ifaces->sock = -1;
    748 #ifdef DHCPv6
    749         if (local_family == AF_INET6) {
    750                 fclose(ifaces->fp6);
    751                 ifaces->fp6 = NULL;
    752         }
    753 #endif
    754 }
    755376#else
    756377
    757378/*
    758  * BSD support
     379 * Unix support
    759380 * -----------
    760381 *
    761  * FreeBSD, NetBSD, OpenBSD, and OS X all have the getifaddrs()
     382 * FreeBSD, NetBSD, OpenBSD, Linux, and OS X all have the getifaddrs()
    762383 * function.
    763384 *
    764385 * The getifaddrs() man page describes the use.
    begin_iface_scan(struct iface_conf_list 
    806427 */
    807428int
    808429next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
     430        size_t sa_len = 0;
     431
    809432        if (ifaces->next == NULL) {
    810433                *err = 0;
    811434                return 0;
    next_iface(struct iface_info *info, int 
    818441        }
    819442        memset(info, 0, sizeof(struct iface_info));
    820443        strncpy(info->name, ifaces->next->ifa_name, sizeof(info->name) - 1);
    821         memcpy(&info->addr, ifaces->next->ifa_addr,
    822                ifaces->next->ifa_addr->sa_len);
     444
     445        memset(&info->addr, 0 , sizeof(info->addr));
     446
     447        if (ifaces->next->ifa_addr != NULL) {
     448#ifdef HAVE_SA_LEN
     449                sa_len = ifaces->next->ifa_addr->sa_len;
     450#else
     451                if (ifaces->next->ifa_addr->sa_family == AF_INET)
     452                        sa_len = sizeof(struct sockaddr_in);
     453                else if (ifaces->next->ifa_addr->sa_family == AF_INET6)
     454                        sa_len = sizeof(struct sockaddr_in6);
     455#endif
     456                memcpy(&info->addr, ifaces->next->ifa_addr, sa_len);
     457        }
    823458        info->flags = ifaces->next->ifa_flags;
    824459        ifaces->next = ifaces->next->ifa_next;
    825460        *err = 0;
Note: See TracBrowser for help on using the repository browser.