diff options
author | Guy Harris <guy@alum.mit.edu> | 2019-11-08 19:56:53 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-11-08 19:56:53 -0800 |
commit | ca73e1eb38426d78f72a574774008f9d9fc179aa (patch) | |
tree | 95ee96d564cd70437cab8cf7fc5ab1f1c3512150 /pcap-linux.c | |
parent | 108b0eecc5c876c4ce93e60207146add85fc978e (diff) | |
parent | 1548ff3a6af09e4abfc91900bacb3d278530ae7e (diff) |
Merge pull request #880 from Oppen/linux-simplify_dev_detection
Linux: remove procfs and sysfs crawling for interface detection.
Diffstat (limited to 'pcap-linux.c')
-rw-r--r-- | pcap-linux.c | 255 |
1 files changed, 1 insertions, 254 deletions
diff --git a/pcap-linux.c b/pcap-linux.c index 004bc91b..444d509c 100644 --- a/pcap-linux.c +++ b/pcap-linux.c @@ -2284,220 +2284,6 @@ add_linux_if(pcap_if_list_t *devlistp, const char *ifname, int fd, char *errbuf) } /* - * Get from "/sys/class/net" all interfaces listed there; if they're - * already in the list of interfaces we have, that won't add another - * instance, but if they're not, that'll add them. - * - * We don't bother getting any addresses for them; it appears you can't - * use SIOCGIFADDR on Linux to get IPv6 addresses for interfaces, and, - * although some other types of addresses can be fetched with SIOCGIFADDR, - * we don't bother with them for now. - * - * We also don't fail if we couldn't open "/sys/class/net"; we just leave - * the list of interfaces as is, and return 0, so that we can try - * scanning /proc/net/dev. - * - * Otherwise, we return 1 if we don't get an error and -1 if we do. - */ -static int -scan_sys_class_net(pcap_if_list_t *devlistp, char *errbuf) -{ - DIR *sys_class_net_d; - int fd; - struct dirent *ent; - char subsystem_path[PATH_MAX+1]; - struct stat statb; - int ret = 1; - - sys_class_net_d = opendir("/sys/class/net"); - if (sys_class_net_d == NULL) { - /* - * Don't fail if it doesn't exist at all. - */ - if (errno == ENOENT) - return (0); - - /* - * Fail if we got some other error. - */ - pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, - errno, "Can't open /sys/class/net"); - return (-1); - } - - /* - * Create a socket from which to fetch interface information. - */ - fd = socket(PF_UNIX, SOCK_RAW, 0); - if (fd < 0) { - pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, - errno, "socket"); - (void)closedir(sys_class_net_d); - return (-1); - } - - for (;;) { - errno = 0; - ent = readdir(sys_class_net_d); - if (ent == NULL) { - /* - * Error or EOF; if errno != 0, it's an error. - */ - break; - } - - /* - * Ignore "." and "..". - */ - if (strcmp(ent->d_name, ".") == 0 || - strcmp(ent->d_name, "..") == 0) - continue; - - /* - * Ignore plain files; they do not have subdirectories - * and thus have no attributes. - */ - if (ent->d_type == DT_REG) - continue; - - /* - * Is there an "ifindex" file under that name? - * (We don't care whether it's a directory or - * a symlink; older kernels have directories - * for devices, newer kernels have symlinks to - * directories.) - */ - snprintf(subsystem_path, sizeof subsystem_path, - "/sys/class/net/%s/ifindex", ent->d_name); - if (lstat(subsystem_path, &statb) != 0) { - /* - * Stat failed. Either there was an error - * other than ENOENT, and we don't know if - * this is an interface, or it's ENOENT, - * and either some part of "/sys/class/net/{if_name}" - * disappeared, in which case it probably means - * the interface disappeared, or there's no - * "ifindex" file, which means it's not a - * network interface. - */ - continue; - } - - /* - * Attempt to add the interface. - */ - if (add_linux_if(devlistp, &ent->d_name[0], fd, errbuf) == -1) { - /* Fail. */ - ret = -1; - break; - } - } - if (ret != -1) { - /* - * Well, we didn't fail for any other reason; did we - * fail due to an error reading the directory? - */ - if (errno != 0) { - pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, - errno, "Error reading /sys/class/net"); - ret = -1; - } - } - - (void)close(fd); - (void)closedir(sys_class_net_d); - return (ret); -} - -/* - * Get from "/proc/net/dev" all interfaces listed there; if they're - * already in the list of interfaces we have, that won't add another - * instance, but if they're not, that'll add them. - * - * See comments from scan_sys_class_net(). - */ -static int -scan_proc_net_dev(pcap_if_list_t *devlistp, char *errbuf) -{ - FILE *proc_net_f; - int fd; - char linebuf[512]; - int linenum; - char *p; - int ret = 0; - - proc_net_f = fopen("/proc/net/dev", "r"); - if (proc_net_f == NULL) { - /* - * Don't fail if it doesn't exist at all. - */ - if (errno == ENOENT) - return (0); - - /* - * Fail if we got some other error. - */ - pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, - errno, "Can't open /proc/net/dev"); - return (-1); - } - - /* - * Create a socket from which to fetch interface information. - */ - fd = socket(PF_UNIX, SOCK_RAW, 0); - if (fd < 0) { - pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, - errno, "socket"); - (void)fclose(proc_net_f); - return (-1); - } - - for (linenum = 1; - fgets(linebuf, sizeof linebuf, proc_net_f) != NULL; linenum++) { - /* - * Skip the first two lines - they're headers. - */ - if (linenum <= 2) - continue; - - p = &linebuf[0]; - - /* - * Skip leading white space. - */ - while (*p == ' ' || *p == '\t') - p++; - if (*p == '\0' || *p == '\n') - continue; /* blank line */ - - /* - * Attempt to add the interface. - */ - if (add_linux_if(devlistp, p, fd, errbuf) == -1) { - /* Fail. */ - ret = -1; - break; - } - } - if (ret != -1) { - /* - * Well, we didn't fail for any other reason; did we - * fail due to an error reading the file? - */ - if (ferror(proc_net_f)) { - pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, - errno, "Error reading /proc/net/dev"); - ret = -1; - } - } - - (void)close(fd); - (void)fclose(proc_net_f); - return (ret); -} - -/* * Description string for the "any" device. */ static const char any_descr[] = "Pseudo-device that captures on all interfaces"; @@ -2685,46 +2471,7 @@ get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf) int pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) { - int ret; - - /* - * Get the list of regular interfaces first. - */ - if (pcap_findalldevs_interfaces(devlistp, errbuf, can_be_bound, - get_if_flags) == -1) - return (-1); /* failure */ - - /* - * Read "/sys/class/net", and add to the list of interfaces all - * interfaces listed there that we don't already have, because, - * on Linux, SIOCGIFCONF reports only interfaces with IPv4 addresses, - * and even getifaddrs() won't return information about - * interfaces with no addresses, so you need to read "/sys/class/net" - * to get the names of the rest of the interfaces. - */ - ret = scan_sys_class_net(devlistp, errbuf); - if (ret == -1) - return (-1); /* failed */ - if (ret == 0) { - /* - * No /sys/class/net; try reading /proc/net/dev instead. - */ - if (scan_proc_net_dev(devlistp, errbuf) == -1) - return (-1); - } - - /* - * Add the "any" device. - * As it refers to all network devices, not to any particular - * network device, the notion of "connected" vs. "disconnected" - * doesn't apply. - */ - if (add_dev(devlistp, "any", - PCAP_IF_UP|PCAP_IF_RUNNING|PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, - any_descr, errbuf) == NULL) - return (-1); - - return (0); + return pcap_findalldevs_interfaces(devlistp, errbuf, can_be_bound, get_if_flags); } /* |