Scan /proc/net/dev on Linux regardless of how we get the interface list.
It's a Linuxism, so it's not necessary on other platforms, and is useful even if we have getifaddrs().
This commit is contained in:
parent
fc03e2cbb6
commit
6831a81489
144
fad-gifc.c
144
fad-gifc.c
|
@ -122,136 +122,6 @@ struct rtentry; /* declarations in <net/if.h> */
|
|||
*/
|
||||
#define MAX_SA_LEN 255
|
||||
|
||||
#ifdef HAVE_PROC_NET_DEV
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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 "/proc/net/dev"; we just leave
|
||||
* the list of interfaces as is.
|
||||
*/
|
||||
static int
|
||||
scan_proc_net_dev(pcap_if_t **devlistp, int fd, char *errbuf)
|
||||
{
|
||||
FILE *proc_net_f;
|
||||
char linebuf[512];
|
||||
int linenum;
|
||||
unsigned char *p;
|
||||
char name[512]; /* XXX - pick a size */
|
||||
char *q, *saveq;
|
||||
struct ifreq ifrflags;
|
||||
int ret = 0;
|
||||
|
||||
proc_net_f = fopen("/proc/net/dev", "r");
|
||||
if (proc_net_f == NULL)
|
||||
return (0);
|
||||
|
||||
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 != '\0' && isspace(*p))
|
||||
p++;
|
||||
if (*p == '\0' || *p == '\n')
|
||||
continue; /* blank line */
|
||||
|
||||
/*
|
||||
* Get the interface name.
|
||||
*/
|
||||
q = &name[0];
|
||||
while (*p != '\0' && !isspace(*p)) {
|
||||
if (*p == ':') {
|
||||
/*
|
||||
* This could be the separator between a
|
||||
* name and an alias number, or it could be
|
||||
* the separator between a name with no
|
||||
* alias number and the next field.
|
||||
*
|
||||
* If there's a colon after digits, it
|
||||
* separates the name and the alias number,
|
||||
* otherwise it separates the name and the
|
||||
* next field.
|
||||
*/
|
||||
saveq = q;
|
||||
while (isdigit(*p))
|
||||
*q++ = *p++;
|
||||
if (*p != ':') {
|
||||
/*
|
||||
* That was the next field,
|
||||
* not the alias number.
|
||||
*/
|
||||
q = saveq;
|
||||
}
|
||||
break;
|
||||
} else
|
||||
*q++ = *p++;
|
||||
}
|
||||
*q = '\0';
|
||||
|
||||
/*
|
||||
* Get the flags for this interface, and skip it if
|
||||
* it's not up.
|
||||
*/
|
||||
strncpy(ifrflags.ifr_name, name, sizeof(ifrflags.ifr_name));
|
||||
if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifrflags) < 0) {
|
||||
if (errno == ENXIO)
|
||||
continue;
|
||||
(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
|
||||
"SIOCGIFFLAGS: %.*s: %s",
|
||||
(int)sizeof(ifrflags.ifr_name),
|
||||
ifrflags.ifr_name,
|
||||
pcap_strerror(errno));
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
if (!(ifrflags.ifr_flags & IFF_UP))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Add an entry for this interface, with no addresses.
|
||||
*/
|
||||
if (pcap_add_if(devlistp, name, ifrflags.ifr_flags, NULL,
|
||||
errbuf) == -1) {
|
||||
/*
|
||||
* Failure.
|
||||
*/
|
||||
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)) {
|
||||
(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
|
||||
"Error reading /proc/net/dev: %s",
|
||||
pcap_strerror(errno));
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
(void)fclose(proc_net_f);
|
||||
return (ret);
|
||||
}
|
||||
#endif /* HAVE_PROC_NET_DEV */
|
||||
|
||||
/*
|
||||
* Get a list of all interfaces that are up and that we can open.
|
||||
* Returns -1 on error, 0 otherwise.
|
||||
|
@ -537,20 +407,6 @@ pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf)
|
|||
}
|
||||
}
|
||||
free(buf);
|
||||
|
||||
#ifdef HAVE_PROC_NET_DEV
|
||||
if (ret != -1) {
|
||||
/*
|
||||
* We haven't had any errors yet; now read "/proc/net/dev",
|
||||
* 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,
|
||||
* so you need to read "/proc/net/dev" to get the names of
|
||||
* the rest of the interfaces.
|
||||
*/
|
||||
ret = scan_proc_net_dev(&devlist, fd, errbuf);
|
||||
}
|
||||
#endif
|
||||
(void)close(fd);
|
||||
|
||||
if (ret != -1) {
|
||||
|
|
170
pcap-linux.c
170
pcap-linux.c
|
@ -1774,6 +1774,148 @@ pcap_stats_linux(pcap_t *handle, struct pcap_stat *stats)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PROC_NET_DEV
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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 "/proc/net/dev"; we just leave
|
||||
* the list of interfaces as is.
|
||||
*/
|
||||
static int
|
||||
scan_proc_net_dev(pcap_if_t **devlistp, char *errbuf)
|
||||
{
|
||||
FILE *proc_net_f;
|
||||
int fd;
|
||||
char linebuf[512];
|
||||
int linenum;
|
||||
unsigned char *p;
|
||||
char name[512]; /* XXX - pick a size */
|
||||
char *q, *saveq;
|
||||
struct ifreq ifrflags;
|
||||
int ret = 0;
|
||||
|
||||
proc_net_f = fopen("/proc/net/dev", "r");
|
||||
if (proc_net_f == NULL)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Create a socket from which to fetch interface information.
|
||||
*/
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
|
||||
"socket: %s", pcap_strerror(errno));
|
||||
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 != '\0' && isspace(*p))
|
||||
p++;
|
||||
if (*p == '\0' || *p == '\n')
|
||||
continue; /* blank line */
|
||||
|
||||
/*
|
||||
* Get the interface name.
|
||||
*/
|
||||
q = &name[0];
|
||||
while (*p != '\0' && !isspace(*p)) {
|
||||
if (*p == ':') {
|
||||
/*
|
||||
* This could be the separator between a
|
||||
* name and an alias number, or it could be
|
||||
* the separator between a name with no
|
||||
* alias number and the next field.
|
||||
*
|
||||
* If there's a colon after digits, it
|
||||
* separates the name and the alias number,
|
||||
* otherwise it separates the name and the
|
||||
* next field.
|
||||
*/
|
||||
saveq = q;
|
||||
while (isdigit(*p))
|
||||
*q++ = *p++;
|
||||
if (*p != ':') {
|
||||
/*
|
||||
* That was the next field,
|
||||
* not the alias number.
|
||||
*/
|
||||
q = saveq;
|
||||
}
|
||||
break;
|
||||
} else
|
||||
*q++ = *p++;
|
||||
}
|
||||
*q = '\0';
|
||||
|
||||
/*
|
||||
* Get the flags for this interface, and skip it if
|
||||
* it's not up.
|
||||
*/
|
||||
strncpy(ifrflags.ifr_name, name, sizeof(ifrflags.ifr_name));
|
||||
if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifrflags) < 0) {
|
||||
if (errno == ENXIO)
|
||||
continue;
|
||||
(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
|
||||
"SIOCGIFFLAGS: %.*s: %s",
|
||||
(int)sizeof(ifrflags.ifr_name),
|
||||
ifrflags.ifr_name,
|
||||
pcap_strerror(errno));
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
if (!(ifrflags.ifr_flags & IFF_UP))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Add an entry for this interface, with no addresses.
|
||||
*/
|
||||
if (pcap_add_if(devlistp, name, ifrflags.ifr_flags, NULL,
|
||||
errbuf) == -1) {
|
||||
/*
|
||||
* Failure.
|
||||
*/
|
||||
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)) {
|
||||
(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
|
||||
"Error reading /proc/net/dev: %s",
|
||||
pcap_strerror(errno));
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
(void)close(fd);
|
||||
(void)fclose(proc_net_f);
|
||||
return (ret);
|
||||
}
|
||||
#endif /* HAVE_PROC_NET_DEV */
|
||||
|
||||
/*
|
||||
* Description string for the "any" device.
|
||||
*/
|
||||
|
@ -1782,25 +1924,53 @@ static const char any_descr[] = "Pseudo-device that captures on all interfaces";
|
|||
int
|
||||
pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
|
||||
{
|
||||
#ifdef HAVE_PROC_NET_DEV
|
||||
/*
|
||||
* Read "/proc/net/dev", 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 "/proc/net/dev"
|
||||
* to get the names of the rest of the interfaces.
|
||||
*/
|
||||
if (scan_proc_net_dev(alldevsp, errbuf) == -1)
|
||||
return (-1);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Add the "any" device.
|
||||
*/
|
||||
if (pcap_add_if(alldevsp, "any", 0, any_descr, errbuf) < 0)
|
||||
return (-1);
|
||||
|
||||
#ifdef HAVE_DAG_API
|
||||
/*
|
||||
* Add DAG devices.
|
||||
*/
|
||||
if (dag_platform_finddevs(alldevsp, errbuf) < 0)
|
||||
return (-1);
|
||||
#endif /* HAVE_DAG_API */
|
||||
|
||||
#ifdef HAVE_SEPTEL_API
|
||||
/*
|
||||
* Add Septel devices.
|
||||
*/
|
||||
if (septel_platform_finddevs(alldevsp, errbuf) < 0)
|
||||
return (-1);
|
||||
#endif /* HAVE_SEPTEL_API */
|
||||
|
||||
#ifdef PCAP_SUPPORT_BT
|
||||
/*
|
||||
* Add Bluetooth devices.
|
||||
*/
|
||||
if (bt_platform_finddevs(alldevsp, errbuf) < 0)
|
||||
return (-1);
|
||||
#endif
|
||||
|
||||
#ifdef PCAP_SUPPORT_USB
|
||||
/*
|
||||
* Add USB devices.
|
||||
*/
|
||||
if (usb_platform_finddevs(alldevsp, errbuf) < 0)
|
||||
return (-1);
|
||||
#endif
|
||||
|
|
Reference in New Issue