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:
parent
2de302a362
commit
9c0a593a2e
1
CREDITS
1
CREDITS
|
@ -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
865
inet.c
|
@ -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
|
||||
|
|
|
@ -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
117
pcap.3
|
@ -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
30
pcap.h
|
@ -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);
|
||||
|
|
Reference in New Issue