f719d5d44f
MFC after: 1 month
408 lines
11 KiB
C
408 lines
11 KiB
C
/* -*- 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.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by the Computer Systems
|
|
* Engineering Group at Lawrence Berkeley Laboratory.
|
|
* 4. Neither the name of the University nor of the Laboratory may be used
|
|
* to endorse or promote products derived from this software without
|
|
* specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
#include <pcap-stdinc.h>
|
|
#else /* _WIN32 */
|
|
|
|
#include <sys/param.h>
|
|
#ifndef MSDOS
|
|
#include <sys/file.h>
|
|
#endif
|
|
#include <sys/ioctl.h>
|
|
#include <sys/socket.h>
|
|
#ifdef HAVE_SYS_SOCKIO_H
|
|
#include <sys/sockio.h>
|
|
#endif
|
|
|
|
struct mbuf; /* Squelch compiler warnings on some platforms for */
|
|
struct rtentry; /* declarations in <net/if.h> */
|
|
#include <net/if.h>
|
|
#include <netinet/in.h>
|
|
#endif /* _WIN32 */
|
|
|
|
#include <errno.h>
|
|
#include <memory.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#if !defined(_WIN32) && !defined(__BORLANDC__)
|
|
#include <unistd.h>
|
|
#endif /* !_WIN32 && !__BORLANDC__ */
|
|
|
|
#include "pcap-int.h"
|
|
|
|
#ifdef HAVE_OS_PROTO_H
|
|
#include "os-proto.h"
|
|
#endif
|
|
|
|
#if !defined(_WIN32) && !defined(MSDOS)
|
|
|
|
/*
|
|
* 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
|
|
* lowest unit number is preferred; loopback is ignored.
|
|
*/
|
|
char *
|
|
pcap_lookupdev(errbuf)
|
|
register char *errbuf;
|
|
{
|
|
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 (pcap_findalldevs(&alldevs, errbuf) == -1)
|
|
return (NULL);
|
|
|
|
if (alldevs == NULL || (alldevs->flags & PCAP_IF_LOOPBACK)) {
|
|
/*
|
|
* 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?
|
|
*/
|
|
(void)strlcpy(errbuf, "no suitable device found",
|
|
PCAP_ERRBUF_SIZE);
|
|
ret = NULL;
|
|
} else {
|
|
/*
|
|
* Return the name of the first device on the list.
|
|
*/
|
|
(void)strlcpy(device, alldevs->name, sizeof(device));
|
|
ret = device;
|
|
}
|
|
|
|
pcap_freealldevs(alldevs);
|
|
return (ret);
|
|
}
|
|
|
|
int
|
|
pcap_lookupnet(device, netp, maskp, errbuf)
|
|
register const char *device;
|
|
register bpf_u_int32 *netp, *maskp;
|
|
register char *errbuf;
|
|
{
|
|
register int fd;
|
|
register struct sockaddr_in *sin4;
|
|
struct ifreq ifr;
|
|
|
|
/*
|
|
* The pseudo-device "any" listens on all interfaces and therefore
|
|
* has the network address and -mask "0.0.0.0" therefore catching
|
|
* all traffic. Using NULL for the interface is the same as "any".
|
|
*/
|
|
if (!device || strcmp(device, "any") == 0
|
|
#ifdef HAVE_DAG_API
|
|
|| strstr(device, "dag") != NULL
|
|
#endif
|
|
#ifdef HAVE_SEPTEL_API
|
|
|| strstr(device, "septel") != NULL
|
|
#endif
|
|
#ifdef PCAP_SUPPORT_BT
|
|
|| strstr(device, "bluetooth") != NULL
|
|
#endif
|
|
#ifdef PCAP_SUPPORT_USB
|
|
|| strstr(device, "usbmon") != NULL
|
|
#endif
|
|
#ifdef PCAP_SUPPORT_NETMAP
|
|
|| !strncmp(device, "netmap:", 7)
|
|
|| !strncmp(device, "vale", 4)
|
|
#endif
|
|
#ifdef HAVE_SNF_API
|
|
|| strstr(device, "snf") != NULL
|
|
#endif
|
|
) {
|
|
*netp = *maskp = 0;
|
|
return 0;
|
|
}
|
|
|
|
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
|
if (fd < 0) {
|
|
(void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "socket: %s",
|
|
pcap_strerror(errno));
|
|
return (-1);
|
|
}
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
#ifdef linux
|
|
/* XXX Work around Linux kernel bug */
|
|
ifr.ifr_addr.sa_family = AF_INET;
|
|
#endif
|
|
(void)strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
|
|
if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
|
|
if (errno == EADDRNOTAVAIL) {
|
|
(void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
|
|
"%s: no IPv4 address assigned", device);
|
|
} else {
|
|
(void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
|
|
"SIOCGIFADDR: %s: %s",
|
|
device, pcap_strerror(errno));
|
|
}
|
|
(void)close(fd);
|
|
return (-1);
|
|
}
|
|
sin4 = (struct sockaddr_in *)&ifr.ifr_addr;
|
|
*netp = sin4->sin_addr.s_addr;
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
#ifdef linux
|
|
/* XXX Work around Linux kernel bug */
|
|
ifr.ifr_addr.sa_family = AF_INET;
|
|
#endif
|
|
(void)strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
|
|
if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) {
|
|
(void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
|
|
"SIOCGIFNETMASK: %s: %s", device, pcap_strerror(errno));
|
|
(void)close(fd);
|
|
return (-1);
|
|
}
|
|
(void)close(fd);
|
|
*maskp = sin4->sin_addr.s_addr;
|
|
if (*maskp == 0) {
|
|
if (IN_CLASSA(*netp))
|
|
*maskp = IN_CLASSA_NET;
|
|
else if (IN_CLASSB(*netp))
|
|
*maskp = IN_CLASSB_NET;
|
|
else if (IN_CLASSC(*netp))
|
|
*maskp = IN_CLASSC_NET;
|
|
else {
|
|
(void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
|
|
"inet class for 0x%x unknown", *netp);
|
|
return (-1);
|
|
}
|
|
}
|
|
*netp &= *maskp;
|
|
return (0);
|
|
}
|
|
|
|
#elif defined(_WIN32)
|
|
|
|
/*
|
|
* 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
|
|
* lowest unit number is preferred; loopback is ignored.
|
|
*
|
|
* In the best of all possible worlds, this would be the same as on
|
|
* UN*X, but there may be software that expects this to return a
|
|
* full list of devices after the first device.
|
|
*/
|
|
#define ADAPTERSNAME_LEN 8192
|
|
char *
|
|
pcap_lookupdev(errbuf)
|
|
register char *errbuf;
|
|
{
|
|
DWORD dwVersion;
|
|
DWORD dwWindowsMajorVersion;
|
|
char our_errbuf[PCAP_ERRBUF_SIZE+1];
|
|
|
|
#pragma warning (push)
|
|
#pragma warning (disable: 4996) /* disable MSVC's GetVersion() deprecated warning here */
|
|
dwVersion = GetVersion(); /* get the OS version */
|
|
#pragma warning (pop)
|
|
dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
|
|
|
|
if (dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4) {
|
|
/*
|
|
* Windows 95, 98, ME.
|
|
*/
|
|
ULONG NameLength = ADAPTERSNAME_LEN;
|
|
static char AdaptersName[ADAPTERSNAME_LEN];
|
|
|
|
if (PacketGetAdapterNames(AdaptersName,&NameLength) )
|
|
return (AdaptersName);
|
|
else
|
|
return NULL;
|
|
} else {
|
|
/*
|
|
* Windows NT (NT 4.0 and later).
|
|
* Convert the names to Unicode for backward compatibility.
|
|
*/
|
|
ULONG NameLength = ADAPTERSNAME_LEN;
|
|
static WCHAR AdaptersName[ADAPTERSNAME_LEN];
|
|
size_t BufferSpaceLeft;
|
|
char *tAstr;
|
|
WCHAR *Unameptr;
|
|
char *Adescptr;
|
|
size_t namelen, i;
|
|
WCHAR *TAdaptersName = (WCHAR*)malloc(ADAPTERSNAME_LEN * sizeof(WCHAR));
|
|
int NAdapts = 0;
|
|
|
|
if(TAdaptersName == NULL)
|
|
{
|
|
(void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "memory allocation failure");
|
|
return NULL;
|
|
}
|
|
|
|
if ( !PacketGetAdapterNames((PTSTR)TAdaptersName,&NameLength) )
|
|
{
|
|
pcap_win32_err_to_str(GetLastError(), our_errbuf);
|
|
(void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
|
|
"PacketGetAdapterNames: %s", our_errbuf);
|
|
free(TAdaptersName);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
BufferSpaceLeft = ADAPTERSNAME_LEN * sizeof(WCHAR);
|
|
tAstr = (char*)TAdaptersName;
|
|
Unameptr = AdaptersName;
|
|
|
|
/*
|
|
* Convert the device names to Unicode into AdapterName.
|
|
*/
|
|
do {
|
|
/*
|
|
* Length of the name, including the terminating
|
|
* NUL.
|
|
*/
|
|
namelen = strlen(tAstr) + 1;
|
|
|
|
/*
|
|
* Do we have room for the name in the Unicode
|
|
* buffer?
|
|
*/
|
|
if (BufferSpaceLeft < namelen * sizeof(WCHAR)) {
|
|
/*
|
|
* No.
|
|
*/
|
|
goto quit;
|
|
}
|
|
BufferSpaceLeft -= namelen * sizeof(WCHAR);
|
|
|
|
/*
|
|
* Copy the name, converting ASCII to Unicode.
|
|
* namelen includes the NUL, so we copy it as
|
|
* well.
|
|
*/
|
|
for (i = 0; i < namelen; i++)
|
|
*Unameptr++ = *tAstr++;
|
|
|
|
/*
|
|
* Count this adapter.
|
|
*/
|
|
NAdapts++;
|
|
} while (namelen != 1);
|
|
|
|
/*
|
|
* Copy the descriptions, but don't convert them from
|
|
* ASCII to Unicode.
|
|
*/
|
|
Adescptr = (char *)Unameptr;
|
|
while(NAdapts--)
|
|
{
|
|
size_t desclen;
|
|
|
|
desclen = strlen(tAstr) + 1;
|
|
|
|
/*
|
|
* Do we have room for the name in the Unicode
|
|
* buffer?
|
|
*/
|
|
if (BufferSpaceLeft < desclen) {
|
|
/*
|
|
* No.
|
|
*/
|
|
goto quit;
|
|
}
|
|
|
|
/*
|
|
* Just copy the ASCII string.
|
|
* namelen includes the NUL, so we copy it as
|
|
* well.
|
|
*/
|
|
memcpy(Adescptr, tAstr, desclen);
|
|
Adescptr += desclen;
|
|
tAstr += desclen;
|
|
BufferSpaceLeft -= desclen;
|
|
}
|
|
|
|
quit:
|
|
free(TAdaptersName);
|
|
return (char *)(AdaptersName);
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
pcap_lookupnet(device, netp, maskp, errbuf)
|
|
register const char *device;
|
|
register bpf_u_int32 *netp, *maskp;
|
|
register char *errbuf;
|
|
{
|
|
/*
|
|
* We need only the first IPv4 address, so we must scan the array returned by PacketGetNetInfo()
|
|
* in order to skip non IPv4 (i.e. IPv6 addresses)
|
|
*/
|
|
npf_if_addr if_addrs[MAX_NETWORK_ADDRESSES];
|
|
LONG if_addr_size = 1;
|
|
struct sockaddr_in *t_addr;
|
|
unsigned int i;
|
|
|
|
if (!PacketGetNetInfoEx((void *)device, if_addrs, &if_addr_size)) {
|
|
*netp = *maskp = 0;
|
|
return (0);
|
|
}
|
|
|
|
for(i=0; i<MAX_NETWORK_ADDRESSES; i++)
|
|
{
|
|
if(if_addrs[i].IPAddress.ss_family == AF_INET)
|
|
{
|
|
t_addr = (struct sockaddr_in *) &(if_addrs[i].IPAddress);
|
|
*netp = t_addr->sin_addr.S_un.S_addr;
|
|
t_addr = (struct sockaddr_in *) &(if_addrs[i].SubnetMask);
|
|
*maskp = t_addr->sin_addr.S_un.S_addr;
|
|
|
|
*netp &= *maskp;
|
|
return (0);
|
|
}
|
|
|
|
}
|
|
|
|
*netp = *maskp = 0;
|
|
return (0);
|
|
}
|
|
|
|
#endif /* !_WIN32 && !MSDOS */
|