source:
npl/internetserver/dhcp/dhcommon-getifaddrs.patch
@
929bb42
Last change on this file since 929bb42 was ebc5ae5, checked in by , 8 years ago | |
---|---|
|
|
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 373 373 ifaces->sock = -1; 374 374 } 375 375 376 #elif __linux /* !HAVE_SIOCGLIFCONF */377 /*378 * Linux support379 * -------------380 *381 * In Linux, we use the /proc pseudo-filesystem to get information382 * 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 DHCPv6394 FILE *fp6; /* input from /proc/net/if_inet6 */395 #endif396 };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 int413 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 DHCPv6452 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 #endif465 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 of481 * each line.482 *483 * We use an ioctl() to get the address and flags for each interface.484 */485 static int486 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, or495 * 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_PERMUTED553 /* interface aliases look like "eth0:1" or "wlan1:3" */554 s = strchr(info->name, ':');555 if (s != NULL) {556 *s = '\0';557 }558 #endif559 560 #ifdef SKIP_DUMMY_INTERFACES561 } while (strncmp(info->name, "dummy", 5) == 0);562 #else563 } while (0);564 #endif565 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 DHCPv6595 /*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 vmnet8601 * 00000000000000000000000000000001 01 80 10 80 lo602 * fe80000000000000025056fffec00001 06 40 20 80 vmnet1603 * 200108881936000202166ffffe497d9b 03 40 00 00 eth1604 * fe8000000000000002166ffffe497d9b 03 40 20 80 eth1605 *606 * We get IPv6 address from the start, the interface name from the end,607 * and ioctl() to get flags.608 */609 static int610 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_INTERFACES670 } while (strncmp(info->name, "dummy", 5) == 0);671 #else672 } while (0);673 #endif674 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 int725 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 DHCPv6731 if (!(*err)) {732 if (local_family == AF_INET6)733 return next_iface6(info, err, ifaces);734 }735 #endif736 return 0;737 }738 739 /*740 * End scan of interfaces.741 */742 void743 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 DHCPv6749 if (local_family == AF_INET6) {750 fclose(ifaces->fp6);751 ifaces->fp6 = NULL;752 }753 #endif754 }755 376 #else 756 377 757 378 /* 758 * BSDsupport379 * Unix support 759 380 * ----------- 760 381 * 761 * FreeBSD, NetBSD, OpenBSD, and OS X all have the getifaddrs()382 * FreeBSD, NetBSD, OpenBSD, Linux, and OS X all have the getifaddrs() 762 383 * function. 763 384 * 764 385 * The getifaddrs() man page describes the use. … … begin_iface_scan(struct iface_conf_list 806 427 */ 807 428 int 808 429 next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) { 430 size_t sa_len = 0; 431 809 432 if (ifaces->next == NULL) { 810 433 *err = 0; 811 434 return 0; … … next_iface(struct iface_info *info, int 818 441 } 819 442 memset(info, 0, sizeof(struct iface_info)); 820 443 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 } 823 458 info->flags = ifaces->next->ifa_flags; 824 459 ifaces->next = ifaces->next->ifa_next; 825 460 *err = 0;
Note: See TracBrowser
for help on using the repository browser.