/* -*- 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/file.h>38#include <sys/ioctl.h>39#include <sys/socket.h>40#ifdef HAVE_SYS_SOCKIO_H41#include <sys/sockio.h>42#endif43#include <sys/time.h> /* concession to AIX */4445struct mbuf; /* Squelch compiler warnings on some platforms for */46struct rtentry; /* declarations in <net/if.h> */47#include <net/if.h>48#include <netinet/in.h>4950#include <errno.h>51#include <memory.h>52#include <stdio.h>53#include <stdlib.h>54#include <string.h>55#include <unistd.h>5657#include "pcap-int.h"5859#ifdef HAVE_OS_PROTO_H60#include "os-proto.h"61#endif6263/*64* Only Solaris 10 uses this file.65*/6667/*68* Get a list of all interfaces that are up and that we can open.69* Returns -1 on error, 0 otherwise.70* The list, as returned through "alldevsp", may be null if no interfaces71* were up and could be opened.72*73* This is the implementation used on platforms that have SIOCGLIFCONF74* but don't have "getifaddrs()". (Solaris 8 and later; we use75* SIOCGLIFCONF rather than SIOCGIFCONF in order to get IPv6 addresses.)76*/77int78pcapint_findalldevs_interfaces(pcap_if_list_t *devlistp, char *errbuf,79int (*check_usable)(const char *), get_if_flags_func get_flags_func)80{81register int fd4, fd6, fd;82register struct lifreq *ifrp, *ifend;83struct lifnum ifn;84struct lifconf ifc;85char *buf = NULL;86unsigned buf_size;87#ifdef HAVE_SOLARIS88char *p, *q;89#endif90struct lifreq ifrflags, ifrnetmask, ifrbroadaddr, ifrdstaddr;91struct sockaddr *netmask, *broadaddr, *dstaddr;92int ret = 0;9394/*95* Create a socket from which to fetch the list of interfaces,96* and from which to fetch IPv4 information.97*/98fd4 = socket(AF_INET, SOCK_DGRAM, 0);99if (fd4 < 0) {100pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,101errno, "socket: AF_INET");102return (-1);103}104105/*106* Create a socket from which to fetch IPv6 information.107*/108fd6 = socket(AF_INET6, SOCK_DGRAM, 0);109if (fd6 < 0) {110pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,111errno, "socket: AF_INET6");112(void)close(fd4);113return (-1);114}115116/*117* How many entries will SIOCGLIFCONF return?118*/119ifn.lifn_family = AF_UNSPEC;120ifn.lifn_flags = 0;121ifn.lifn_count = 0;122if (ioctl(fd4, SIOCGLIFNUM, (char *)&ifn) < 0) {123pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,124errno, "SIOCGLIFNUM");125(void)close(fd6);126(void)close(fd4);127return (-1);128}129130/*131* Allocate a buffer for those entries.132*/133buf_size = ifn.lifn_count * sizeof (struct lifreq);134buf = malloc(buf_size);135if (buf == NULL) {136pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,137errno, "malloc");138(void)close(fd6);139(void)close(fd4);140return (-1);141}142143/*144* Get the entries.145*/146ifc.lifc_len = buf_size;147ifc.lifc_buf = buf;148ifc.lifc_family = AF_UNSPEC;149ifc.lifc_flags = 0;150memset(buf, 0, buf_size);151if (ioctl(fd4, SIOCGLIFCONF, (char *)&ifc) < 0) {152pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,153errno, "SIOCGLIFCONF");154(void)close(fd6);155(void)close(fd4);156free(buf);157return (-1);158}159160/*161* Loop over the entries.162*/163ifrp = (struct lifreq *)buf;164ifend = (struct lifreq *)(buf + ifc.lifc_len);165166for (; ifrp < ifend; ifrp++) {167/*168* Skip entries that begin with "dummy".169* XXX - what are these? Is this Linux-specific?170* Are there platforms on which we shouldn't do this?171*/172if (strncmp(ifrp->lifr_name, "dummy", 5) == 0)173continue;174175/*176* Can we capture on this device?177*/178if (!(*check_usable)(ifrp->lifr_name)) {179/*180* No.181*/182continue;183}184185/*186* IPv6 or not?187*/188if (((struct sockaddr *)&ifrp->lifr_addr)->sa_family == AF_INET6)189fd = fd6;190else191fd = fd4;192193/*194* Get the flags for this interface.195*/196strncpy(ifrflags.lifr_name, ifrp->lifr_name,197sizeof(ifrflags.lifr_name));198if (ioctl(fd, SIOCGLIFFLAGS, (char *)&ifrflags) < 0) {199if (errno == ENXIO)200continue;201pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,202errno, "SIOCGLIFFLAGS: %.*s",203(int)sizeof(ifrflags.lifr_name),204ifrflags.lifr_name);205ret = -1;206break;207}208209/*210* Get the netmask for this address on this interface.211*/212strncpy(ifrnetmask.lifr_name, ifrp->lifr_name,213sizeof(ifrnetmask.lifr_name));214memcpy(&ifrnetmask.lifr_addr, &ifrp->lifr_addr,215sizeof(ifrnetmask.lifr_addr));216if (ioctl(fd, SIOCGLIFNETMASK, (char *)&ifrnetmask) < 0) {217if (errno == EADDRNOTAVAIL) {218/*219* Not available.220*/221netmask = NULL;222} else {223pcapint_fmt_errmsg_for_errno(errbuf,224PCAP_ERRBUF_SIZE, errno,225"SIOCGLIFNETMASK: %.*s",226(int)sizeof(ifrnetmask.lifr_name),227ifrnetmask.lifr_name);228ret = -1;229break;230}231} else232netmask = (struct sockaddr *)&ifrnetmask.lifr_addr;233234/*235* Get the broadcast address for this address on this236* interface (if any).237*/238if (ifrflags.lifr_flags & IFF_BROADCAST) {239strncpy(ifrbroadaddr.lifr_name, ifrp->lifr_name,240sizeof(ifrbroadaddr.lifr_name));241memcpy(&ifrbroadaddr.lifr_addr, &ifrp->lifr_addr,242sizeof(ifrbroadaddr.lifr_addr));243if (ioctl(fd, SIOCGLIFBRDADDR,244(char *)&ifrbroadaddr) < 0) {245if (errno == EADDRNOTAVAIL) {246/*247* Not available.248*/249broadaddr = NULL;250} else {251pcapint_fmt_errmsg_for_errno(errbuf,252PCAP_ERRBUF_SIZE, errno,253"SIOCGLIFBRDADDR: %.*s",254(int)sizeof(ifrbroadaddr.lifr_name),255ifrbroadaddr.lifr_name);256ret = -1;257break;258}259} else260broadaddr = (struct sockaddr *)&ifrbroadaddr.lifr_broadaddr;261} else {262/*263* Not a broadcast interface, so no broadcast264* address.265*/266broadaddr = NULL;267}268269/*270* Get the destination address for this address on this271* interface (if any).272*/273if (ifrflags.lifr_flags & IFF_POINTOPOINT) {274strncpy(ifrdstaddr.lifr_name, ifrp->lifr_name,275sizeof(ifrdstaddr.lifr_name));276memcpy(&ifrdstaddr.lifr_addr, &ifrp->lifr_addr,277sizeof(ifrdstaddr.lifr_addr));278if (ioctl(fd, SIOCGLIFDSTADDR,279(char *)&ifrdstaddr) < 0) {280if (errno == EADDRNOTAVAIL) {281/*282* Not available.283*/284dstaddr = NULL;285} else {286pcapint_fmt_errmsg_for_errno(errbuf,287PCAP_ERRBUF_SIZE, errno,288"SIOCGLIFDSTADDR: %.*s",289(int)sizeof(ifrdstaddr.lifr_name),290ifrdstaddr.lifr_name);291ret = -1;292break;293}294} else295dstaddr = (struct sockaddr *)&ifrdstaddr.lifr_dstaddr;296} else297dstaddr = NULL;298299#ifdef HAVE_SOLARIS300/*301* If this entry has a colon followed by a number at302* the end, it's a logical interface. Those are just303* the way you assign multiple IP addresses to a real304* interface, so an entry for a logical interface should305* be treated like the entry for the real interface;306* we do that by stripping off the ":" and the number.307*/308p = strchr(ifrp->lifr_name, ':');309if (p != NULL) {310/*311* We have a ":"; is it followed by a number?312*/313q = p + 1;314while (PCAP_ISDIGIT(*q))315q++;316if (*q == '\0') {317/*318* All digits after the ":" until the end.319* Strip off the ":" and everything after320* it.321*/322*p = '\0';323}324}325#endif326327/*328* Add information for this address to the list.329*/330if (pcapint_add_addr_to_if(devlistp, ifrp->lifr_name,331ifrflags.lifr_flags, get_flags_func,332(struct sockaddr *)&ifrp->lifr_addr,333sizeof (struct sockaddr_storage),334netmask, sizeof (struct sockaddr_storage),335broadaddr, sizeof (struct sockaddr_storage),336dstaddr, sizeof (struct sockaddr_storage), errbuf) < 0) {337ret = -1;338break;339}340}341free(buf);342(void)close(fd6);343(void)close(fd4);344345return (ret);346}347348349