dect
/
libpcap
Archived
13
0
Fork 0

From Scott Gifford:

Add a new "pcap_findalldevs()" routine to get a list of all
	interfaces that can be opened with "pcap_open_live()", and a
	"pcap_freealldevs()" routine to free the list.

	Make "pcap_lookupdev()" use it, which also arranges that it will
	not return a device that cannot be opened by "pcap_open_live()".

	Allow the "any" device to be opened, on Linux, with "promisc"
	non-zero; ignore the request for promiscuity, and return a
	warning message indicating that promiscuous mode isn't supported
	on the "any" device.

Document "pcap_findalldevs()" and "pcap_lookupdev()", and clean up some
items in the libpcap man page.
This commit is contained in:
guy 2001-10-08 01:06:20 +00:00
parent 2de302a362
commit 9c0a593a2e
5 changed files with 847 additions and 175 deletions

View File

@ -39,6 +39,7 @@ Additional people who have contributed patches:
Rafal Maszkowski <rzm@icm.edu.pl>
Rick Jones <raj@cup.hp.com>
Scott Barron <sb125499@ohiou.edu>
Scott Gifford <sgifford@tir.com>
Stefan Hudson <hudson@mbay.net>
Tony Li <tli@jnx.com>
Uns Lider <unslider@miranda.org>

865
inet.c
View File

@ -1,3 +1,4 @@
/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
/*
* Copyright (c) 1994, 1995, 1996, 1997, 1998
* The Regents of the University of California. All rights reserved.
@ -33,7 +34,7 @@
#ifndef lint
static const char rcsid[] =
"@(#) $Header: /tcpdump/master/libpcap/inet.c,v 1.38 2001-07-28 22:56:34 guy Exp $ (LBL)";
"@(#) $Header: /tcpdump/master/libpcap/inet.c,v 1.39 2001-10-08 01:06:20 guy Exp $ (LBL)";
#endif
#ifdef HAVE_CONFIG_H
@ -73,15 +74,685 @@ struct rtentry;
/* Not all systems have IFF_LOOPBACK */
#ifdef IFF_LOOPBACK
#define ISLOOPBACK(p) ((p)->ifr_flags & IFF_LOOPBACK)
#define ISLOOPBACK_IFA(p) ((p)->ifa_flags & IFF_LOOPBACK)
#define ISLOOPBACK(name, flags) ((flags) & IFF_LOOPBACK)
#else
#define ISLOOPBACK(p) ((p)->ifr_name[0] == 'l' && (p)->ifr_name[1] == 'o' && \
(isdigit((p)->ifr_name[2]) || (p)->ifr_name[2] == '\0'))
#define ISLOOPBACK_IFA(p) ((p)->ifa_name[0] == 'l' && (p)->ifa_name[1] == 'o' && \
(isdigit((p)->ifa_name[2]) || (p)->ifa_name[2] == '\0'))
#define ISLOOPBACK(name, flags) ((name)[0] == 'l' && (name)[1] == 'o' && \
(isdigit((unsigned char)((name)[2])) || (name)[2] == '\0'))
#endif
/*
* This is fun.
*
* In older BSD systems, socket addresses were fixed-length, and
* "sizeof (struct sockaddr)" gave the size of the structure.
* All addresses fit within a "struct sockaddr".
*
* In newer BSD systems, the socket address is variable-length, and
* there's an "sa_len" field giving the length of the structure;
* this allows socket addresses to be longer than 2 bytes of family
* and 14 bytes of data.
*
* Some commercial UNIXes use the old BSD scheme, and some might use
* the new BSD scheme.
*
* GNU libc uses neither scheme, but has an "SA_LEN()" macro that
* determines the size based on the address family.
*/
#ifndef SA_LEN
#ifdef HAVE_SOCKADDR_SA_LEN
#define SA_LEN(addr) ((addr)->sa_len)
#else /* HAVE_SOCKADDR_SA_LEN */
#define SA_LEN(addr) (sizeof (struct sockaddr))
#endif /* HAVE_SOCKADDR_SA_LEN */
#endif /* SA_LEN */
static struct sockaddr *
dup_sockaddr(struct sockaddr *sa)
{
struct sockaddr *newsa;
unsigned int size;
size = SA_LEN(sa);
if ((newsa = malloc(size)) == NULL)
return (NULL);
return (memcpy(newsa, sa, size));
}
static int
get_instance(char *name)
{
char *cp, *endcp;
int n;
endcp = name + strlen(name);
for (cp = name; cp < endcp && !isdigit((unsigned char)*cp); ++cp)
continue;
if (isdigit((unsigned char)*cp))
n = atoi(cp);
else
n = 0;
return (n);
}
static int
add_or_find_if(pcap_if_t **curdev_ret, pcap_if_t **alldevs, char *name,
u_int flags, char *errbuf)
{
pcap_t *p;
pcap_if_t *curdev, *prevdev, *nextdev;
int this_instance;
/*
* Can we open this interface for live capture?
*/
p = pcap_open_live(name, 68, 0, 0, errbuf);
if (p == NULL) {
/*
* No. Don't bother including it.
* Don't treat this as an error, though.
*/
*curdev_ret = NULL;
return (0);
}
pcap_close(p);
/*
* Is there already an entry in the list for this interface?
*/
for (curdev = *alldevs; curdev != NULL; curdev = curdev->next) {
if (strcmp(name, curdev->name) == 0)
break; /* yes, we found it */
}
if (curdev == NULL) {
/*
* No, we didn't find it.
* Allocate a new entry.
*/
curdev = malloc(sizeof(pcap_if_t));
if (curdev == NULL) {
(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"malloc: %s", pcap_strerror(errno));
return (-1);
}
/*
* Fill in the entry.
*/
curdev->next = NULL;
curdev->name = malloc(strlen(name) + 1);
strcpy(curdev->name, name);
curdev->description = NULL; /* not available */
curdev->addresses = NULL; /* list starts out as empty */
curdev->is_loopback = ISLOOPBACK(name, flags);
/*
* Add it to the list, in the appropriate location.
* First, get the instance number of this interface.
*/
this_instance = get_instance(name);
/*
* Now look for the last interface with an instance number
* less than or equal to the new interface's instance
* number - except that non-loopback interfaces are
* arbitrarily treated as having interface numbers less
* than those of loopback interfaces, so the loopback
* interfaces are put at the end of the list.
*
* We start with "prevdev" being NULL, meaning we're before
* the first element in the list.
*/
prevdev = NULL;
for (;;) {
/*
* Get the interface after this one.
*/
if (prevdev == NULL) {
/*
* The next element is the first element.
*/
nextdev = *alldevs;
} else
nextdev = prevdev->next;
/*
* Are we at the end of the list?
*/
if (nextdev == NULL) {
/*
* Yes - we have to put the new entry
* after "prevdev".
*/
break;
}
/*
* Is the new interface a non-loopback interface
* and the next interface a loopback interface?
*/
if (!curdev->is_loopback && nextdev->is_loopback) {
/*
* Yes, we should put the new entry
* before "nextdev", i.e. after "prevdev".
*/
break;
}
/*
* Is the new interface's instance number less
* than the next interface's instance number,
* and is it the case that the new interface is a
* non-loopback interface or the next interface is
* a loopback interface?
*
* (The goal of both loopback tests is to make
* sure that we never put a loopback interface
* before any non-loopback interface and that we
* always put a non-loopback interface before all
* loopback interfaces.)
*/
if (this_instance < get_instance(nextdev->name) &&
(!curdev->is_loopback || nextdev->is_loopback)) {
/*
* Yes - we should put the new entry
* before "nextdev", i.e. after "prevdev".
*/
break;
}
prevdev = nextdev;
}
/*
* Insert before "nextdev".
*/
curdev->next = nextdev;
/*
* Insert after "prevdev" - unless "prevdev" is null,
* in which case this is the first interface.
*/
if (prevdev == NULL) {
/*
* This is the first interface. Pass back a
* pointer to it, and put "curdev" before
* "nextdev".
*/
*alldevs = curdev;
} else
prevdev->next = curdev;
}
*curdev_ret = curdev;
return (0);
}
static int
add_addr_to_iflist(pcap_if_t **alldevs, char *name, u_int flags,
struct sockaddr *addr, struct sockaddr *netmask,
struct sockaddr *broadaddr, struct sockaddr *dstaddr, char *errbuf)
{
pcap_if_t *curdev;
pcap_addr_t *curaddr, *prevaddr, *nextaddr;
if (add_or_find_if(&curdev, alldevs, name, flags, errbuf) == -1) {
/*
* Error - give up.
*/
return (-1);
}
if (curdev == NULL) {
/*
* Device wasn't added because it can't be opened.
* Not a fatal error.
*/
return (0);
}
/*
* "curdev" is an entry for this interface; add an entry for this
* address to its list of addresses.
*
* Allocate the new entry and fill it in.
*/
curaddr = malloc(sizeof(pcap_addr_t));
if (curaddr == NULL) {
(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"malloc: %s", pcap_strerror(errno));
return (-1);
}
curaddr->next = NULL;
if (addr != NULL) {
curaddr->addr = dup_sockaddr(addr);
if (curaddr->addr == NULL) {
(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"malloc: %s", pcap_strerror(errno));
free(curaddr);
return (-1);
}
} else
curaddr->addr = NULL;
if (netmask != NULL) {
curaddr->netmask = dup_sockaddr(netmask);
if (curaddr->netmask == NULL) {
(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"malloc: %s", pcap_strerror(errno));
free(curaddr);
return (-1);
}
} else
curaddr->netmask = NULL;
if (broadaddr != NULL) {
curaddr->broadaddr = dup_sockaddr(broadaddr);
if (curaddr->broadaddr == NULL) {
(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"malloc: %s", pcap_strerror(errno));
free(curaddr);
return (-1);
}
} else
curaddr->broadaddr = NULL;
if (dstaddr != NULL) {
curaddr->dstaddr = dup_sockaddr(dstaddr);
if (curaddr->dstaddr == NULL) {
(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"malloc: %s", pcap_strerror(errno));
free(curaddr);
return (-1);
}
} else
curaddr->dstaddr = NULL;
/*
* Find the end of the list of addresses.
*/
for (prevaddr = curdev->addresses; prevaddr != NULL; prevaddr = nextaddr) {
nextaddr = prevaddr->next;
if (nextaddr == NULL) {
/*
* This is the end of the list.
*/
break;
}
}
if (prevaddr == NULL) {
/*
* The list was empty; this is the first member.
*/
curdev->addresses = curaddr;
} else {
/*
* "prevaddr" is the last member of the list; append
* this member to it.
*/
prevaddr->next = curaddr;
}
return (0);
}
static int
pcap_addanydev(pcap_if_t **devlist, char *errbuf)
{
pcap_if_t *curdev;
return (add_or_find_if(&curdev, devlist, "any", 0, errbuf));
}
/*
* Get a list of all interfaces that are up and that we can open.
* Returns -1 on error, 0 otherwise.
* The list, as returned through "alldevsp", may be null if no interfaces
* were up and could be opened.
*/
#ifdef HAVE_IFADDRS_H
int
pcap_findalldevs(alldevsp, errbuf)
pcap_if_t **alldevsp;
register char *errbuf;
{
pcap_if_t *devlist = NULL;
struct ifaddrs *ifap, *ifa;
int ret = 0;
/*
* Get the list of interface addresses.
*/
if (getifaddrs(&ifap) != 0) {
(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"getifaddrs: %s", pcap_strerror(errno));
return (-1);
}
for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
/*
* Is this interface up?
*/
if (!(ifa->ifa_flags & IFF_UP)) {
/*
* No, so don't add it to the list.
*/
continue;
}
/*
* Add information for this address to the list.
*/
if (add_addr_to_iflist(&devlist, ifa->ifa_name,
ifa->ifa_flags, ifa->ifa_addr, ifa->ifa_netmask,
ifa->ifa_broadaddr, ifa->ifa_dstaddr, errbuf) < 0) {
/*
* Oops, we had a fatal error.
* Free the list we've been constructing, and fail.
*/
if (devlist != NULL) {
pcap_freealldevs(devlist);
devlist = NULL;
}
ret = -1;
break;
}
}
freeifaddrs(ifap);
if (pcap_addanydev(&devlist, errbuf) < 0) {
if (devlist != NULL) {
pcap_freealldevs(devlist);
devlist = NULL;
}
return -1;
}
*alldevsp = devlist;
return (ret);
}
#else /* HAVE_IFADDRS_H */
int
pcap_findalldevs(alldevsp, errbuf)
pcap_if_t **alldevsp;
register char *errbuf;
{
pcap_if_t *devlist = NULL;
register int fd;
register struct ifreq *ifrp, *ifend, *ifnext;
int n;
struct ifconf ifc;
char *buf = NULL;
unsigned buf_size;
struct ifreq ifrflags, ifrnetmask, ifrbroadaddr, ifrdstaddr;
struct sockaddr *netmask, *broadaddr, *dstaddr;
int ret = 0;
/*
* Create a socket from which to fetch the list of interfaces.
*
* XXX - on Linux, SIOCGIFCONF reports only interfaces with
* IPv4 addresses; you need to read "/proc/net/dev" to get
* the names of all the interfaces.
*/
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"socket: %s", pcap_strerror(errno));
return (-1);
}
/*
* Start with an 8K buffer, and keep growing the buffer until
* we get the entire interface list or fail to get it for some
* reason other than EINVAL (which is presumed here to mean
* "buffer is too small").
*/
buf_size = 8192;
for (;;) {
buf = malloc(buf_size);
if (buf == NULL) {
(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"malloc: %s", pcap_strerror(errno));
return (-1);
}
ifc.ifc_len = buf_size;
ifc.ifc_buf = buf;
memset(buf, 0, buf_size);
if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0
&& errno != EINVAL) {
(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"SIOCGIFCONF: %s", pcap_strerror(errno));
close(fd);
free(buf);
return (-1);
}
if (ifc.ifc_len < buf_size)
break;
free(buf);
buf_size *= 2;
}
ifrp = (struct ifreq *)buf;
ifend = (struct ifreq *)(buf + ifc.ifc_len);
for (; ifrp < ifend; ifrp = ifnext) {
n = SA_LEN(&ifrp->ifr_addr) + sizeof(ifrp->ifr_name);
if (n < sizeof(*ifrp))
ifnext = ifrp + 1;
else
ifnext = (struct ifreq *)((char *)ifrp + n);
/*
* Get the flags for this interface, and skip it if it's
* not up.
*/
strncpy(ifrflags.ifr_name, ifrp->ifr_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));
if (devlist != NULL) {
pcap_freealldevs(devlist);
devlist = NULL;
}
ret = -1;
break;
}
if (!(ifrflags.ifr_flags & IFF_UP))
continue;
/*
* Get the netmask for this address on this interface.
*/
strncpy(ifrnetmask.ifr_name, ifrp->ifr_name,
sizeof(ifrnetmask.ifr_name));
memcpy(&ifrnetmask.ifr_addr, &ifrp->ifr_addr,
sizeof(ifrnetmask.ifr_addr));
if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifrnetmask) < 0) {
if (errno == EADDRNOTAVAIL) {
/*
* Not available.
*/
netmask = NULL;
} else {
(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"SIOCGIFNETMASK: %.*s: %s",
(int)sizeof(ifrnetmask.ifr_name),
ifrnetmask.ifr_name,
pcap_strerror(errno));
if (devlist != NULL) {
pcap_freealldevs(devlist);
devlist = NULL;
}
ret = -1;
break;
}
} else
netmask = &ifrnetmask.ifr_addr;
/*
* Get the broadcast address for this address on this
* interface (if any).
*/
if (ifrflags.ifr_flags & IFF_BROADCAST) {
strncpy(ifrbroadaddr.ifr_name, ifrp->ifr_name,
sizeof(ifrbroadaddr.ifr_name));
memcpy(&ifrbroadaddr.ifr_addr, &ifrp->ifr_addr,
sizeof(ifrbroadaddr.ifr_addr));
if (ioctl(fd, SIOCGIFBRDADDR,
(char *)&ifrbroadaddr) < 0) {
if (errno == EADDRNOTAVAIL) {
/*
* Not available.
*/
broadaddr = NULL;
} else {
(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"SIOCGIFBRDADDR: %.*s: %s",
(int)sizeof(ifrbroadaddr.ifr_name),
ifrbroadaddr.ifr_name,
pcap_strerror(errno));
if (devlist != NULL) {
pcap_freealldevs(devlist);
devlist = NULL;
}
ret = -1;
break;
}
} else
broadaddr = &ifrbroadaddr.ifr_broadaddr;
} else {
/*
* Not a broadcast interface, so no broadcast
* address.
*/
broadaddr = NULL;
}
/*
* Get the destination address for this address on this
* interface (if any).
*/
if (ifrflags.ifr_flags & IFF_POINTOPOINT) {
strncpy(ifrdstaddr.ifr_name, ifrp->ifr_name,
sizeof(ifrdstaddr.ifr_name));
memcpy(&ifrdstaddr.ifr_addr, &ifrp->ifr_addr,
sizeof(ifrdstaddr.ifr_addr));
if (ioctl(fd, SIOCGIFDSTADDR,
(char *)&ifrdstaddr) < 0) {
if (errno == EADDRNOTAVAIL) {
/*
* Not available.
*/
dstaddr = NULL;
} else {
(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"SIOCGIFDSTADDR: %.*s: %s",
(int)sizeof(ifrdstaddr.ifr_name),
ifrdstaddr.ifr_name,
pcap_strerror(errno));
if (devlist != NULL) {
pcap_freealldevs(devlist);
devlist = NULL;
}
ret = -1;
break;
}
} else
dstaddr = &ifrdstaddr.ifr_dstaddr;
} else
dstaddr = NULL;
/*
* Add information for this address to the list.
*/
if (add_addr_to_iflist(&devlist, ifrp->ifr_name,
ifrflags.ifr_flags, &ifrp->ifr_addr,
netmask, broadaddr, dstaddr, errbuf) < 0) {
/*
* Oops, we had a fatal error.
* Free the list we've been constructing, and fail.
*/
if (devlist != NULL) {
pcap_freealldevs(devlist);
devlist = NULL;
}
ret = -1;
break;
}
}
(void)close(fd);
free(buf);
if (pcap_addanydev(&devlist, errbuf) < 0) {
if (devlist != NULL) {
pcap_freealldevs(devlist);
devlist = NULL;
}
return -1;
}
*alldevsp = devlist;
return (ret);
}
#endif /* HAVE_IFADDRS_H */
/*
* Free a list of interfaces.
*/
void
pcap_freealldevs(pcap_if_t *alldevs)
{
pcap_if_t *curdev, *nextdev;
pcap_addr_t *curaddr, *nextaddr;
for (curdev = alldevs; curdev != NULL; curdev = nextdev) {
nextdev = curdev->next;
/*
* Free all addresses.
*/
for (curaddr = curdev->addresses; curaddr != NULL; curaddr = nextaddr) {
nextaddr = curaddr->next;
if (curaddr->addr)
free(curaddr->addr);
if (curaddr->netmask)
free(curaddr->netmask);
if (curaddr->broadaddr)
free(curaddr->broadaddr);
if (curaddr->dstaddr)
free(curaddr->dstaddr);
free(curaddr);
}
/*
* Free the name string.
*/
free(curdev->name);
/*
* Free the description string, if any.
*/
if (curdev->description != NULL)
free(curdev->description);
/*
* Free the interface.
*/
free(curdev);
}
}
/*
* Return the name of a network interface attached to the system, or NULL
* if none can be found. The interface must be configured up; the
@ -91,176 +762,42 @@ char *
pcap_lookupdev(errbuf)
register char *errbuf;
{
#ifdef HAVE_IFADDRS_H
struct ifaddrs *ifap, *ifa, *mp;
int n, minunit;
char *cp;
pcap_if_t *alldevs;
/* for old BSD systems, including bsdi3 */
#ifndef IF_NAMESIZE
#define IF_NAMESIZE IFNAMSIZ
#endif
static char device[IF_NAMESIZE + 1];
char *ret;
if (getifaddrs(&ifap) != 0) {
(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"getifaddrs: %s", pcap_strerror(errno));
return NULL;
}
mp = NULL;
minunit = 666;
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
const char *endcp;
if ((ifa->ifa_flags & IFF_UP) == 0 || ISLOOPBACK_IFA(ifa))
continue;
endcp = ifa->ifa_name + strlen(ifa->ifa_name);
for (cp = ifa->ifa_name; cp < endcp && !isdigit(*cp); ++cp)
continue;
if (isdigit (*cp)) {
n = atoi(cp);
} else {
n = 0;
}
if (n < minunit) {
minunit = n;
mp = ifa;
}
}
if (mp == NULL) {
(void)strlcpy(errbuf, "no suitable device found",
PCAP_ERRBUF_SIZE);
#ifdef HAVE_FREEIFADDRS
freeifaddrs(ifap);
#else
free(ifap);
#endif
if (pcap_findalldevs(&alldevs, errbuf) == -1)
return (NULL);
}
(void)strlcpy(device, mp->ifa_name, sizeof(device));
#ifdef HAVE_FREEIFADDRS
freeifaddrs(ifap);
#else
free(ifap);
#endif
return (device);
#else
register int fd, minunit, n;
register char *cp;
register struct ifreq *ifrp, *ifend, *ifnext, *mp;
struct ifconf ifc;
char *buf;
struct ifreq ifr;
static char device[sizeof(ifrp->ifr_name) + 1];
unsigned buf_size;
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"socket: %s", pcap_strerror(errno));
return (NULL);
}
buf_size = 8192;
for (;;) {
buf = malloc (buf_size);
if (buf == NULL) {
close (fd);
(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"out of memory");
return (NULL);
}
ifc.ifc_len = buf_size;
ifc.ifc_buf = buf;
memset (buf, 0, buf_size);
if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0
&& errno != EINVAL) {
free (buf);
(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"SIOCGIFCONF: %s", pcap_strerror(errno));
(void)close(fd);
return (NULL);
}
if (ifc.ifc_len < buf_size)
break;
free (buf);
buf_size *= 2;
}
ifrp = (struct ifreq *)buf;
ifend = (struct ifreq *)(buf + ifc.ifc_len);
mp = NULL;
minunit = 666;
for (; ifrp < ifend; ifrp = ifnext) {
const char *endcp;
#ifdef HAVE_SOCKADDR_SA_LEN
n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
if (n < sizeof(*ifrp))
ifnext = ifrp + 1;
else
ifnext = (struct ifreq *)((char *)ifrp + n);
if (ifrp->ifr_addr.sa_family != AF_INET)
continue;
#else
ifnext = ifrp + 1;
#endif
if (alldevs == NULL || alldevs->is_loopback) {
/*
* Need a template to preserve address info that is
* used below to locate the next entry. (Otherwise,
* SIOCGIFFLAGS stomps over it because the requests
* are returned in a union.)
* There are no devices on the list, or the first device
* on the list is a loopback device, which means there
* are no non-loopback devices on the list. This means
* we can't return any device.
*
* XXX - why not return a loopback device? If we can't
* capture on it, it won't be on the list, and if it's
* on the list, there aren't any non-loopback devices,
* so why not just supply it as the default device?
*/
strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name));
if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
if (errno == ENXIO)
continue;
(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
"SIOCGIFFLAGS: %.*s: %s",
(int)sizeof(ifr.ifr_name), ifr.ifr_name,
pcap_strerror(errno));
(void)close(fd);
free (buf);
return (NULL);
}
/* Must be up and not the loopback */
if ((ifr.ifr_flags & IFF_UP) == 0 || ISLOOPBACK(&ifr))
continue;
endcp = ifrp->ifr_name + strlen(ifrp->ifr_name);
for (cp = ifrp->ifr_name;
cp < endcp && !isdigit((unsigned char)*cp); ++cp)
continue;
if (isdigit ((unsigned char)*cp)) {
n = atoi(cp);
} else {
n = 0;
}
if (n < minunit) {
minunit = n;
mp = ifrp;
}
}
(void)close(fd);
if (mp == NULL) {
(void)strlcpy(errbuf, "no suitable device found",
PCAP_ERRBUF_SIZE);
free(buf);
return (NULL);
ret = NULL;
} else {
/*
* Return the name of the first device on the list.
*/
(void)strlcpy(device, alldevs->name, sizeof(device));
ret = device;
}
(void)strlcpy(device, mp->ifr_name, sizeof(device));
free(buf);
return (device);
#endif
pcap_freealldevs(alldevs);
return (ret);
}
int

View File

@ -26,7 +26,7 @@
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.67 2001-09-23 22:43:57 guy Exp $ (LBL)";
"@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.68 2001-10-08 01:06:21 guy Exp $ (LBL)";
#endif
/*
@ -237,6 +237,13 @@ pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
if (!device || strcmp(device, "any") == 0) {
device = NULL;
handle->md.device = strdup("any");
if (promisc) {
promisc = 0;
/* Just a warning. */
snprintf(ebuf, PCAP_ERRBUF_SIZE,
"Promiscuous mode not supported on the \"any\" device");
}
} else
handle->md.device = strdup(device);

117
pcap.3
View File

@ -1,4 +1,4 @@
.\" @(#) $Header: /tcpdump/master/libpcap/Attic/pcap.3,v 1.22 2001-07-04 07:34:50 guy Exp $
.\" @(#) $Header: /tcpdump/master/libpcap/Attic/pcap.3,v 1.23 2001-10-08 01:06:21 guy Exp $
.\"
.\" Copyright (c) 1994, 1996, 1997
.\" The Regents of the University of California. All rights reserved.
@ -28,17 +28,23 @@ pcap \- Packet Capture library
#include <pcap.h>
.ft
.LP
.nf
.ft B
char errbuf[PCAP_ERRBUF_SIZE];
.ft
.LP
.ft B
pcap_t *pcap_open_live(char *device, int snaplen,
.ti +8
int promisc, int to_ms, char *ebuf)
int promisc, int to_ms, char *errbuf)
pcap_t *pcap_open_dead(int linktype, int snaplen)
pcap_t *pcap_open_offline(char *fname, char *ebuf)
pcap_t *pcap_open_offline(char *fname, char *errbuf)
pcap_dumper_t *pcap_dump_open(pcap_t *p, char *fname)
.ft
.LP
.ft B
char errbuf[PCAP_ERRBUF_SIZE];
int pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf)
void pcap_freealldevs(pcap_if_t *)
char *pcap_lookupdev(char *errbuf)
int pcap_lookupnet(char *device, bpf_u_int32 *netp,
.ti +8
@ -99,7 +105,9 @@ NOTE:
.I errbuf
in
.B pcap_open_live(),
.B pcap_open_dead(),
.B pcap_open_offline(),
.B pcap_findalldevs(),
.B pcap_lookupdev(),
and
.B pcap_lookupnet()
@ -134,20 +142,20 @@ is seen, but that it wait for some amount of time to allow more packets
to arrive and to read multiple packets from the OS kernel in one
operation. Not all platforms support a read timeout; on platforms that
don't, the read timeout is ignored.
.I ebuf
.I errbuf
is used to return error or warning text. It will be set to error text when
.B pcap_open_live()
fails and returns
.BR NULL .
.I ebuf
.I errbuf
may also be set to warning text when
.B pcap_open_live()
succeds; to detect this case the caller should store a zero-length string in
.I ebuf
.I errbuf
before calling
.B pcap_open_live()
and display the warning to the user if
.I ebuf
.I errbuf
is no longer a zero-length string.
.PP
.B pcap_open_dead()
@ -166,7 +174,7 @@ and
.BR tcpslice(1) .
The name "-" in a synonym for
.BR stdin .
.I ebuf
.I errbuf
is used to return error text and is only set when
.B pcap_open_offline()
fails and returns
@ -193,6 +201,97 @@ is returned,
.B pcap_geterr()
can be used to get the error text.
.PP
.B pcap_findalldevs()
constructs a list of network devices that can be opened with
.BR pcap_open_live() .
(Note that there may be network devices that cannot be opened with
.BR pcap_open_live()
by the
process calling
.BR pcap_findalldevs() ,
because, for example, that process might not have sufficient privileges
to open them for capturing; if so, those devices will not appear on the
list.)
.I alldevsp
is set to point to the first element of the list; each element of the
list is of type
.BR pcap_if_t ,
and has the following members:
.RS
.TP
.B next
if not
.BR NULL ,
a pointer to the next element in the list;
.B NULL
for the last element of the list
.TP
.B name
a pointer to a string giving a name for the device to pass to
.B pcap_open_live()
.TP
.B description
if not
.BR NULL ,
a pointer to a string giving a human-readable description of the device
.TP
.B addresses
a pointer to the first element of a list of addresses for the interface
.TP
.B is_loopback
non-zero if the interface is a loopback interface
.RE
.PP
Each element of the list of addresses is of type
.BR pcap_addr_t ,
and has the following members:
.RS
.TP
.B next
if not
.BR NULL ,
a pointer to the next element in the list;
.B NULL
for the last element of the list
.TP
.B addr
a pointer to a
.B "struct sockaddr"
containing an address
.TP
.B netmask
if not
.BR NULL ,
a pointer to a
.B "struct sockaddr"
that contains the netmask corresponding to the address pointed to by
.B addr
.TP
.B broadaddr
if not
.BR NULL ,
a pointer to a
.B "struct sockaddr"
that contains the broadcast address corresponding to the address pointed
to by
.BR addr ;
may be null if the interface doesn't support broadcasts
.TP
.B dstaddr
if not
.BR NULL ,
a pointer to a
.B "struct sockaddr"
that contains the destination address corresponding to the address pointed
to by
.BR addr ;
may be null if the interface isn't a point-to-point interface
.RE
.PP
.B pcap_freealldevs()
is used to free a list allocated by
.BR pcap_findalldevs() .
.PP
.B pcap_lookupdev()
returns a pointer to a network device suitable for use with
.B pcap_open_live()

30
pcap.h
View File

@ -1,3 +1,4 @@
/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
/*
* Copyright (c) 1993, 1994, 1995, 1996, 1997
* The Regents of the University of California. All rights reserved.
@ -30,7 +31,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#) $Header: /tcpdump/master/libpcap/pcap.h,v 1.31 2000-10-28 00:01:31 guy Exp $ (LBL)
* @(#) $Header: /tcpdump/master/libpcap/pcap.h,v 1.32 2001-10-08 01:06:22 guy Exp $ (LBL)
*/
#ifndef lib_pcap_h
@ -63,6 +64,8 @@ typedef u_int bpf_u_int32;
typedef struct pcap pcap_t;
typedef struct pcap_dumper pcap_dumper_t;
typedef struct pcap_if pcap_if_t;
typedef struct pcap_addr pcap_addr_t;
/*
* The first record in the file contains saved values for some
@ -128,6 +131,28 @@ struct pcap_stat {
u_int ps_ifdrop; /* drops by interface XXX not yet supported */
};
/*
* Item in a list of interfaces.
*/
struct pcap_if {
struct pcap_if *next;
char *name; /* name to hand to "pcap_open_live()" */
char *description; /* textual description of interface, or NULL */
struct pcap_addr *addresses;
u_int is_loopback; /* non-0 if interface is loopback */
};
/*
* Representation of an interface address.
*/
struct pcap_addr {
struct pcap_addr *next;
struct sockaddr *addr; /* address */
struct sockaddr *netmask; /* netmask for that address */
struct sockaddr *broadaddr; /* broadcast address for that address */
struct sockaddr *dstaddr; /* P2P destination address for that address */
};
typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *,
const u_char *);
@ -165,6 +190,9 @@ pcap_dumper_t *pcap_dump_open(pcap_t *, const char *);
void pcap_dump_close(pcap_dumper_t *);
void pcap_dump(u_char *, const struct pcap_pkthdr *, const u_char *);
int pcap_findalldevs(pcap_if_t **, char *);
void pcap_freealldevs(pcap_if_t *);
/* XXX this guy lives in the bpf tree */
u_int bpf_filter(struct bpf_insn *, u_char *, u_int, u_int);
int bpf_validate(struct bpf_insn *f, int len);