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
|
#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.
|
* Get a list of all interfaces that are up and that we can open.
|
||||||
* Returns -1 on error, 0 otherwise.
|
* Returns -1 on error, 0 otherwise.
|
||||||
|
@ -537,20 +407,6 @@ pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(buf);
|
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);
|
(void)close(fd);
|
||||||
|
|
||||||
if (ret != -1) {
|
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;
|
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.
|
* Description string for the "any" device.
|
||||||
*/
|
*/
|
||||||
|
@ -1782,25 +1924,53 @@ static const char any_descr[] = "Pseudo-device that captures on all interfaces";
|
||||||
int
|
int
|
||||||
pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
|
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)
|
if (pcap_add_if(alldevsp, "any", 0, any_descr, errbuf) < 0)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
#ifdef HAVE_DAG_API
|
#ifdef HAVE_DAG_API
|
||||||
|
/*
|
||||||
|
* Add DAG devices.
|
||||||
|
*/
|
||||||
if (dag_platform_finddevs(alldevsp, errbuf) < 0)
|
if (dag_platform_finddevs(alldevsp, errbuf) < 0)
|
||||||
return (-1);
|
return (-1);
|
||||||
#endif /* HAVE_DAG_API */
|
#endif /* HAVE_DAG_API */
|
||||||
|
|
||||||
#ifdef HAVE_SEPTEL_API
|
#ifdef HAVE_SEPTEL_API
|
||||||
|
/*
|
||||||
|
* Add Septel devices.
|
||||||
|
*/
|
||||||
if (septel_platform_finddevs(alldevsp, errbuf) < 0)
|
if (septel_platform_finddevs(alldevsp, errbuf) < 0)
|
||||||
return (-1);
|
return (-1);
|
||||||
#endif /* HAVE_SEPTEL_API */
|
#endif /* HAVE_SEPTEL_API */
|
||||||
|
|
||||||
#ifdef PCAP_SUPPORT_BT
|
#ifdef PCAP_SUPPORT_BT
|
||||||
|
/*
|
||||||
|
* Add Bluetooth devices.
|
||||||
|
*/
|
||||||
if (bt_platform_finddevs(alldevsp, errbuf) < 0)
|
if (bt_platform_finddevs(alldevsp, errbuf) < 0)
|
||||||
return (-1);
|
return (-1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef PCAP_SUPPORT_USB
|
#ifdef PCAP_SUPPORT_USB
|
||||||
|
/*
|
||||||
|
* Add USB devices.
|
||||||
|
*/
|
||||||
if (usb_platform_finddevs(alldevsp, errbuf) < 0)
|
if (usb_platform_finddevs(alldevsp, errbuf) < 0)
|
||||||
return (-1);
|
return (-1);
|
||||||
#endif
|
#endif
|
||||||
|
|
Reference in New Issue