X-Git-Url: https://git.tcpdump.org/libpcap/blobdiff_plain/03cc04a438588623a351705d1ca900362786929c..cc3ca65d6519faf3a0e4609b5150757c14af36e9:/inet.c diff --git a/inet.c b/inet.c index 961032b2..2109e4fd 100644 --- a/inet.c +++ b/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. @@ -31,53 +32,46 @@ * SUCH DAMAGE. */ -#ifndef lint -static const char rcsid[] = - "@(#) $Header: /tcpdump/master/libpcap/inet.c,v 1.27 2000-02-23 11:39:45 itojun Exp $ (LBL)"; +#ifdef HAVE_CONFIG_H +#include "config.h" #endif +#ifdef _WIN32 +#include +#else /* _WIN32 */ + #include +#ifndef MSDOS #include +#endif #include #include #ifdef HAVE_SYS_SOCKIO_H #include #endif -#include /* concession to AIX */ - -#if __STDC__ -struct mbuf; -struct rtentry; -#endif +struct mbuf; /* Squelch compiler warnings on some platforms for */ +struct rtentry; /* declarations in */ #include #include +#endif /* _WIN32 */ -#include #include #include #include #include #include +#if !defined(_WIN32) && !defined(__BORLANDC__) #include -#ifdef HAVE_IFADDRS_H -#include -#endif +#endif /* !_WIN32 && !__BORLANDC__ */ #include "pcap-int.h" -#include "gnuc.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" #endif -/* Not all systems have IFF_LOOPBACK */ -#ifdef IFF_LOOPBACK -#define ISLOOPBACK(p) ((p)->ifr_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')) -#endif +#if !defined(_WIN32) && !defined(MSDOS) /* * Return the name of a network interface attached to the system, or NULL @@ -88,164 +82,84 @@ char * pcap_lookupdev(errbuf) register char *errbuf; { -#ifdef HAVE_IFADDRS_H - struct ifaddrs *ifap, *ifa, *mp; - int n, minunit; - char *cp; - static char device[IF_NAMESIZE + 1]; - - if (getifaddrs(&ifap) != 0) { - (void)sprintf(errbuf, "getifaddrs: %s", pcap_strerror(errno)); - return NULL; - } - - mp = NULL; - minunit = 666; - for (ifa = ifap; ifa; ifa = ifa->ifa_next) { - if ((ifa->ifa_flags & IFF_UP) == 0) - continue; -#ifdef IFF_LOOPBACK - if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) - continue; -#else - if (strcmp(ifa->ifa_name, "lo0") == 0) - continue; + 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; - for (cp = ifa->ifa_name; !isdigit(*cp); ++cp) - continue; - n = atoi(cp); - if (n < minunit) { - minunit = n; - mp = ifa; - } - } - if (mp == NULL) { - (void)strcpy(errbuf, "no suitable device found"); - free(ifap); - return (NULL); - } - - (void)strncpy(device, mp->ifa_name, sizeof(device) - 1); - device[sizeof(device) - 1] = '\0'; - free(ifap); - 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)sprintf(errbuf, "socket: %s", pcap_strerror(errno)); + if (pcap_findalldevs(&alldevs, errbuf) == -1) return (NULL); - } - - buf_size = 8192; - - for (;;) { - buf = malloc (buf_size); - if (buf == NULL) { - close (fd); - (void)sprintf(errbuf, "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) { - free (buf); - (void)sprintf(errbuf, "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) { -#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->flags & PCAP_IF_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)sprintf(errbuf, "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; - - for (cp = ifrp->ifr_name; !isdigit(*cp); ++cp) - continue; - n = atoi(cp); - if (n < minunit) { - minunit = n; - mp = ifrp; - } - } - (void)close(fd); - if (mp == NULL) { - (void)strcpy(errbuf, "no suitable device found"); - free(buf); - return (NULL); + (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; } - (void)strncpy(device, mp->ifr_name, sizeof(device) - 1); - device[sizeof(device) - 1] = '\0'; - free(buf); - return (device); -#endif + pcap_freealldevs(alldevs); + return (ret); } int pcap_lookupnet(device, netp, maskp, errbuf) - register char *device; + register const char *device; register bpf_u_int32 *netp, *maskp; register char *errbuf; { register int fd; - register struct sockaddr_in *sin; + 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 HAVE_SNF_API + || strstr(device, "snf") != NULL +#endif + ) { + *netp = *maskp = 0; + return 0; + } + fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { - (void)sprintf(errbuf, "socket: %s", pcap_strerror(errno)); + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "socket: %s", + pcap_strerror(errno)); return (-1); } memset(&ifr, 0, sizeof(ifr)); @@ -253,28 +167,35 @@ pcap_lookupnet(device, netp, maskp, errbuf) /* XXX Work around Linux kernel bug */ ifr.ifr_addr.sa_family = AF_INET; #endif - (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + (void)strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) { if (errno == EADDRNOTAVAIL) { - (void)sprintf(errbuf, "%s: no IPv4 address assigned", - device); + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "%s: no IPv4 address assigned", device); } else { - (void)sprintf(errbuf, "SIOCGIFADDR: %s: %s", + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "SIOCGIFADDR: %s: %s", device, pcap_strerror(errno)); } (void)close(fd); return (-1); } - sin = (struct sockaddr_in *)&ifr.ifr_addr; - *netp = sin->sin_addr.s_addr; + 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)sprintf(errbuf, "SIOCGIFNETMASK: %s: %s", - device, pcap_strerror(errno)); + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "SIOCGIFNETMASK: %s: %s", device, pcap_strerror(errno)); (void)close(fd); return (-1); } (void)close(fd); - *maskp = sin->sin_addr.s_addr; + *maskp = sin4->sin_addr.s_addr; if (*maskp == 0) { if (IN_CLASSA(*netp)) *maskp = IN_CLASSA_NET; @@ -283,11 +204,147 @@ pcap_lookupnet(device, netp, maskp, errbuf) else if (IN_CLASSC(*netp)) *maskp = IN_CLASSC_NET; else { - (void)sprintf(errbuf, "inet class for 0x%x unknown", - *netp); + (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. + */ +char * +pcap_lookupdev(errbuf) + register char *errbuf; +{ + DWORD dwVersion; + DWORD dwWindowsMajorVersion; + char our_errbuf[PCAP_ERRBUF_SIZE+1]; + + dwVersion = GetVersion(); /* get the OS version */ + dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion))); + + if (dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4) { + /* + * Windows 95, 98, ME. + */ + ULONG NameLength = 8192; + static char AdaptersName[8192]; + + if (PacketGetAdapterNames(AdaptersName,&NameLength) ) + return (AdaptersName); + else + return NULL; + } else { + /* + * Windows NT (NT 4.0, W2K, WXP). Convert the names to UNICODE for backward compatibility + */ + ULONG NameLength = 8192; + static WCHAR AdaptersName[8192]; + char *tAstr; + WCHAR *tUstr; + WCHAR *TAdaptersName = (WCHAR*)malloc(8192 * 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; + } + + + tAstr = (char*)TAdaptersName; + tUstr = (WCHAR*)AdaptersName; + + /* + * Convert and copy the device names + */ + while(sscanf(tAstr, "%S", tUstr) > 0) + { + tAstr += strlen(tAstr) + 1; + tUstr += wcslen(tUstr) + 1; + NAdapts ++; + } + + tAstr++; + *tUstr = 0; + tUstr++; + + /* + * Copy the descriptions + */ + while(NAdapts--) + { + char* tmp = (char*)tUstr; + strcpy(tmp, tAstr); + tmp += strlen(tAstr) + 1; + tUstr = (WCHAR*)tmp; + tAstr += strlen(tAstr) + 1; + } + + 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; isin_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 */