/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */1/*2* Copyright (c) 1994, 1995, 1996, 1997, 19983* The Regents of the University of California. All rights reserved.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13* 3. All advertising materials mentioning features or use of this software14* must display the following acknowledgement:15* This product includes software developed by the Computer Systems16* Engineering Group at Lawrence Berkeley Laboratory.17* 4. Neither the name of the University nor of the Laboratory may be used18* to endorse or promote products derived from this software without19* specific prior written permission.20*21* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND22* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE23* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE24* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE25* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL26* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS27* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)28* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT29* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY30* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF31* SUCH DAMAGE.32*/3334#include <config.h>3536#include <sys/param.h>37#include <sys/ioctl.h>38#include <sys/socket.h>39#ifdef HAVE_SYS_SOCKIO_H40#include <sys/sockio.h>41#endif42#include <sys/time.h> /* concession to AIX */4344struct mbuf; /* Squelch compiler warnings on some platforms for */45struct rtentry; /* declarations in <net/if.h> */46#include <net/if.h>47#include <netinet/in.h>4849#include <errno.h>50#include <memory.h>51#include <stdio.h>52#include <stdlib.h>53#include <string.h>54#include <unistd.h>55#include <limits.h>5657#include "pcap-int.h"5859#ifdef HAVE_OS_PROTO_H60#include "os-proto.h"61#endif6263/*64* This is fun.65*66* In older BSD systems, socket addresses were fixed-length, and67* "sizeof (struct sockaddr)" gave the size of the structure.68* All addresses fit within a "struct sockaddr".69*70* In newer BSD systems, the socket address is variable-length, and71* there's an "sa_len" field giving the length of the structure;72* this allows socket addresses to be longer than 2 bytes of family73* and 14 bytes of data.74*75* Some commercial UNIXes use the old BSD scheme, some use the RFC 255376* variant of the old BSD scheme (with "struct sockaddr_storage" rather77* than "struct sockaddr"), and some use the new BSD scheme.78*79* Some versions of GNU libc use neither scheme, but has an "SA_LEN()"80* macro that determines the size based on the address family. Other81* versions don't have "SA_LEN()" (as it was in drafts of RFC 255382* but not in the final version).83*84* We assume that a UNIX that doesn't have "getifaddrs()" and doesn't have85* SIOCGLIFCONF, but has SIOCGIFCONF, uses "struct sockaddr" for the86* address in an entry returned by SIOCGIFCONF.87*88* OSes that use this file are:89* - AIX 7 (SA_LEN() is not defined, HAVE_STRUCT_SOCKADDR_SA_LEN is defined)90* - HP-UX 11 (HAVE_STRUCT_SOCKADDR_SA_LEN is not defined)91*/92#ifndef SA_LEN93#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN94#define SA_LEN(addr) ((addr)->sa_len)95#else /* HAVE_STRUCT_SOCKADDR_SA_LEN */96#define SA_LEN(addr) (sizeof (struct sockaddr))97#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */98#endif /* SA_LEN */99100/*101* This is also fun.102*103* There is no ioctl that returns the amount of space required for all104* the data that SIOCGIFCONF could return, and if a buffer is supplied105* that's not large enough for all the data SIOCGIFCONF could return,106* on at least some platforms it just returns the data that'd fit with107* no indication that there wasn't enough room for all the data, much108* less an indication of how much more room is required.109*110* The only way to ensure that we got all the data is to pass a buffer111* large enough that the amount of space in the buffer *not* filled in112* is greater than the largest possible entry.113*114* We assume that's "sizeof(ifreq.ifr_name)" plus 255, under the assumption115* that no address is more than 255 bytes (on systems where the "sa_len"116* field in a "struct sockaddr" is 1 byte, e.g. newer BSDs, that's the117* case, and addresses are unlikely to be bigger than that in any case).118*/119#define MAX_SA_LEN 255120121/*122* Get a list of all interfaces that are up and that we can open.123* Returns -1 on error, 0 otherwise.124* The list, as returned through "alldevsp", may be null if no interfaces125* were up and could be opened.126*127* This is the implementation used on platforms that have SIOCGIFCONF but128* don't have any other mechanism for getting a list of interfaces.129*130* XXX - or platforms that have other, better mechanisms but for which131* we don't yet have code to use that mechanism; I think there's a better132* way on Linux, for example, but if that better way is "getifaddrs()",133* we already have that.134*/135int136pcapint_findalldevs_interfaces(pcap_if_list_t *devlistp, char *errbuf,137int (*check_usable)(const char *), get_if_flags_func get_flags_func)138{139register int fd;140register struct ifreq *ifrp, *ifend, *ifnext;141size_t n;142struct ifconf ifc;143char *buf = NULL;144unsigned buf_size;145#if defined (HAVE_SOLARIS) || defined (HAVE_HPUX10_20_OR_LATER)146char *p, *q;147#endif148struct ifreq ifrflags, ifrnetmask, ifrbroadaddr, ifrdstaddr;149struct sockaddr *netmask, *broadaddr, *dstaddr;150size_t netmask_size, broadaddr_size, dstaddr_size;151int ret = 0;152153/*154* Create a socket from which to fetch the list of interfaces.155*/156fd = socket(AF_INET, SOCK_DGRAM, 0);157if (fd < 0) {158pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,159errno, "socket");160return (-1);161}162163/*164* Start with an 8K buffer, and keep growing the buffer until165* we have more than "sizeof(ifrp->ifr_name) + MAX_SA_LEN"166* bytes left over in the buffer or we fail to get the167* interface list for some reason other than EINVAL (which is168* presumed here to mean "buffer is too small").169*/170buf_size = 8192;171for (;;) {172/*173* Don't let the buffer size get bigger than INT_MAX.174*/175if (buf_size > INT_MAX) {176(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,177"interface information requires more than %u bytes",178INT_MAX);179(void)close(fd);180return (-1);181}182buf = malloc(buf_size);183if (buf == NULL) {184pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,185errno, "malloc");186(void)close(fd);187return (-1);188}189190ifc.ifc_len = buf_size;191ifc.ifc_buf = buf;192memset(buf, 0, buf_size);193if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0194&& errno != EINVAL) {195pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,196errno, "SIOCGIFCONF");197(void)close(fd);198free(buf);199return (-1);200}201if (ifc.ifc_len < (int)buf_size &&202(buf_size - ifc.ifc_len) > sizeof(ifrp->ifr_name) + MAX_SA_LEN)203break;204free(buf);205buf_size *= 2;206}207208ifrp = (struct ifreq *)buf;209ifend = (struct ifreq *)(buf + ifc.ifc_len);210211for (; ifrp < ifend; ifrp = ifnext) {212/*213* XXX - what if this isn't an IPv4 address? Can214* we still get the netmask, etc. with ioctls on215* an IPv4 socket?216*217* The answer is probably platform-dependent, and218* if the answer is "no" on more than one platform,219* the way you work around it is probably platform-220* dependent as well.221*/222n = SA_LEN(&ifrp->ifr_addr) + sizeof(ifrp->ifr_name);223if (n < sizeof(*ifrp))224ifnext = ifrp + 1;225else226ifnext = (struct ifreq *)((char *)ifrp + n);227228/*229* XXX - The 32-bit compatibility layer for Linux on IA-64230* is slightly broken. It correctly converts the structures231* to and from kernel land from 64 bit to 32 bit but232* doesn't update ifc.ifc_len, leaving it larger than the233* amount really used. This means we read off the end234* of the buffer and encounter an interface with an235* "empty" name. Since this is highly unlikely to ever236* occur in a valid case we can just finish looking for237* interfaces if we see an empty name.238*/239if (!(*ifrp->ifr_name))240break;241242/*243* Skip entries that begin with "dummy".244* XXX - what are these? Is this Linux-specific?245* Are there platforms on which we shouldn't do this?246*/247if (strncmp(ifrp->ifr_name, "dummy", 5) == 0)248continue;249250/*251* Can we capture on this device?252*/253if (!(*check_usable)(ifrp->ifr_name)) {254/*255* No.256*/257continue;258}259260/*261* Get the flags for this interface.262*/263strncpy(ifrflags.ifr_name, ifrp->ifr_name,264sizeof(ifrflags.ifr_name));265if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifrflags) < 0) {266if (errno == ENXIO)267continue;268pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,269errno, "SIOCGIFFLAGS: %.*s",270(int)sizeof(ifrflags.ifr_name),271ifrflags.ifr_name);272ret = -1;273break;274}275276/*277* Get the netmask for this address on this interface.278*/279strncpy(ifrnetmask.ifr_name, ifrp->ifr_name,280sizeof(ifrnetmask.ifr_name));281memcpy(&ifrnetmask.ifr_addr, &ifrp->ifr_addr,282sizeof(ifrnetmask.ifr_addr));283if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifrnetmask) < 0) {284if (errno == EADDRNOTAVAIL) {285/*286* Not available.287*/288netmask = NULL;289netmask_size = 0;290} else {291pcapint_fmt_errmsg_for_errno(errbuf,292PCAP_ERRBUF_SIZE, errno,293"SIOCGIFNETMASK: %.*s",294(int)sizeof(ifrnetmask.ifr_name),295ifrnetmask.ifr_name);296ret = -1;297break;298}299} else {300netmask = &ifrnetmask.ifr_addr;301netmask_size = SA_LEN(netmask);302}303304/*305* Get the broadcast address for this address on this306* interface (if any).307*/308if (ifrflags.ifr_flags & IFF_BROADCAST) {309strncpy(ifrbroadaddr.ifr_name, ifrp->ifr_name,310sizeof(ifrbroadaddr.ifr_name));311memcpy(&ifrbroadaddr.ifr_addr, &ifrp->ifr_addr,312sizeof(ifrbroadaddr.ifr_addr));313if (ioctl(fd, SIOCGIFBRDADDR,314(char *)&ifrbroadaddr) < 0) {315if (errno == EADDRNOTAVAIL) {316/*317* Not available.318*/319broadaddr = NULL;320broadaddr_size = 0;321} else {322pcapint_fmt_errmsg_for_errno(errbuf,323PCAP_ERRBUF_SIZE, errno,324"SIOCGIFBRDADDR: %.*s",325(int)sizeof(ifrbroadaddr.ifr_name),326ifrbroadaddr.ifr_name);327ret = -1;328break;329}330} else {331broadaddr = &ifrbroadaddr.ifr_broadaddr;332broadaddr_size = SA_LEN(broadaddr);333}334} else {335/*336* Not a broadcast interface, so no broadcast337* address.338*/339broadaddr = NULL;340broadaddr_size = 0;341}342343/*344* Get the destination address for this address on this345* interface (if any).346*/347if (ifrflags.ifr_flags & IFF_POINTOPOINT) {348strncpy(ifrdstaddr.ifr_name, ifrp->ifr_name,349sizeof(ifrdstaddr.ifr_name));350memcpy(&ifrdstaddr.ifr_addr, &ifrp->ifr_addr,351sizeof(ifrdstaddr.ifr_addr));352if (ioctl(fd, SIOCGIFDSTADDR,353(char *)&ifrdstaddr) < 0) {354if (errno == EADDRNOTAVAIL) {355/*356* Not available.357*/358dstaddr = NULL;359dstaddr_size = 0;360} else {361pcapint_fmt_errmsg_for_errno(errbuf,362PCAP_ERRBUF_SIZE, errno,363"SIOCGIFDSTADDR: %.*s",364(int)sizeof(ifrdstaddr.ifr_name),365ifrdstaddr.ifr_name);366ret = -1;367break;368}369} else {370dstaddr = &ifrdstaddr.ifr_dstaddr;371dstaddr_size = SA_LEN(dstaddr);372}373} else {374/*375* Not a point-to-point interface, so no destination376* address.377*/378dstaddr = NULL;379dstaddr_size = 0;380}381382#if defined (HAVE_SOLARIS) || defined (HAVE_HPUX10_20_OR_LATER)383/*384* If this entry has a colon followed by a number at385* the end, it's a logical interface. Those are just386* the way you assign multiple IP addresses to a real387* interface, so an entry for a logical interface should388* be treated like the entry for the real interface;389* we do that by stripping off the ":" and the number.390*/391p = strchr(ifrp->ifr_name, ':');392if (p != NULL) {393/*394* We have a ":"; is it followed by a number?395*/396q = p + 1;397while (PCAP_ISDIGIT(*q))398q++;399if (*q == '\0') {400/*401* All digits after the ":" until the end.402* Strip off the ":" and everything after403* it.404*/405*p = '\0';406}407}408#endif409410/*411* Add information for this address to the list.412*/413if (pcapint_add_addr_to_if(devlistp, ifrp->ifr_name,414ifrflags.ifr_flags, get_flags_func,415&ifrp->ifr_addr, SA_LEN(&ifrp->ifr_addr),416netmask, netmask_size, broadaddr, broadaddr_size,417dstaddr, dstaddr_size, errbuf) < 0) {418ret = -1;419break;420}421}422free(buf);423(void)close(fd);424425return (ret);426}427428429