1127664Sbms/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ 2127664Sbms/* 3127664Sbms * Copyright (c) 1994, 1995, 1996, 1997, 1998 4127664Sbms * The Regents of the University of California. All rights reserved. 5127664Sbms * 6127664Sbms * Redistribution and use in source and binary forms, with or without 7127664Sbms * modification, are permitted provided that the following conditions 8127664Sbms * are met: 9127664Sbms * 1. Redistributions of source code must retain the above copyright 10127664Sbms * notice, this list of conditions and the following disclaimer. 11127664Sbms * 2. Redistributions in binary form must reproduce the above copyright 12127664Sbms * notice, this list of conditions and the following disclaimer in the 13127664Sbms * documentation and/or other materials provided with the distribution. 14127664Sbms * 3. All advertising materials mentioning features or use of this software 15127664Sbms * must display the following acknowledgement: 16127664Sbms * This product includes software developed by the Computer Systems 17127664Sbms * Engineering Group at Lawrence Berkeley Laboratory. 18127664Sbms * 4. Neither the name of the University nor of the Laboratory may be used 19127664Sbms * to endorse or promote products derived from this software without 20127664Sbms * specific prior written permission. 21127664Sbms * 22127664Sbms * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23127664Sbms * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24127664Sbms * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25127664Sbms * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26127664Sbms * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27127664Sbms * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28127664Sbms * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29127664Sbms * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30127664Sbms * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31127664Sbms * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32127664Sbms * SUCH DAMAGE. 33127664Sbms */ 34127664Sbms 35127664Sbms#ifndef lint 36127664Sbmsstatic const char rcsid[] _U_ = 37214518Srpaulo "@(#) $Header: /tcpdump/master/libpcap/fad-gifc.c,v 1.12 2008-08-06 07:34:09 guy Exp $ (LBL)"; 38127664Sbms#endif 39127664Sbms 40127664Sbms#ifdef HAVE_CONFIG_H 41127664Sbms#include "config.h" 42127664Sbms#endif 43127664Sbms 44127664Sbms#include <sys/param.h> 45127664Sbms#include <sys/ioctl.h> 46127664Sbms#include <sys/socket.h> 47127664Sbms#ifdef HAVE_SYS_SOCKIO_H 48127664Sbms#include <sys/sockio.h> 49127664Sbms#endif 50127664Sbms#include <sys/time.h> /* concession to AIX */ 51127664Sbms 52127664Sbmsstruct mbuf; /* Squelch compiler warnings on some platforms for */ 53127664Sbmsstruct rtentry; /* declarations in <net/if.h> */ 54127664Sbms#include <net/if.h> 55127664Sbms#include <netinet/in.h> 56127664Sbms 57127664Sbms#include <ctype.h> 58127664Sbms#include <errno.h> 59127664Sbms#include <memory.h> 60127664Sbms#include <stdio.h> 61127664Sbms#include <stdlib.h> 62127664Sbms#include <string.h> 63127664Sbms#include <unistd.h> 64127664Sbms 65127664Sbms#include "pcap-int.h" 66127664Sbms 67127664Sbms#ifdef HAVE_OS_PROTO_H 68127664Sbms#include "os-proto.h" 69127664Sbms#endif 70127664Sbms 71127664Sbms/* 72127664Sbms * This is fun. 73127664Sbms * 74127664Sbms * In older BSD systems, socket addresses were fixed-length, and 75127664Sbms * "sizeof (struct sockaddr)" gave the size of the structure. 76127664Sbms * All addresses fit within a "struct sockaddr". 77127664Sbms * 78127664Sbms * In newer BSD systems, the socket address is variable-length, and 79127664Sbms * there's an "sa_len" field giving the length of the structure; 80127664Sbms * this allows socket addresses to be longer than 2 bytes of family 81127664Sbms * and 14 bytes of data. 82127664Sbms * 83127664Sbms * Some commercial UNIXes use the old BSD scheme, some use the RFC 2553 84127664Sbms * variant of the old BSD scheme (with "struct sockaddr_storage" rather 85127664Sbms * than "struct sockaddr"), and some use the new BSD scheme. 86127664Sbms * 87127664Sbms * Some versions of GNU libc use neither scheme, but has an "SA_LEN()" 88127664Sbms * macro that determines the size based on the address family. Other 89127664Sbms * versions don't have "SA_LEN()" (as it was in drafts of RFC 2553 90127664Sbms * but not in the final version). 91127664Sbms * 92127664Sbms * We assume that a UNIX that doesn't have "getifaddrs()" and doesn't have 93127664Sbms * SIOCGLIFCONF, but has SIOCGIFCONF, uses "struct sockaddr" for the 94127664Sbms * address in an entry returned by SIOCGIFCONF. 95127664Sbms */ 96127664Sbms#ifndef SA_LEN 97127664Sbms#ifdef HAVE_SOCKADDR_SA_LEN 98127664Sbms#define SA_LEN(addr) ((addr)->sa_len) 99127664Sbms#else /* HAVE_SOCKADDR_SA_LEN */ 100127664Sbms#define SA_LEN(addr) (sizeof (struct sockaddr)) 101127664Sbms#endif /* HAVE_SOCKADDR_SA_LEN */ 102127664Sbms#endif /* SA_LEN */ 103127664Sbms 104147894Ssam/* 105147894Ssam * This is also fun. 106147894Ssam * 107147894Ssam * There is no ioctl that returns the amount of space required for all 108147894Ssam * the data that SIOCGIFCONF could return, and if a buffer is supplied 109147894Ssam * that's not large enough for all the data SIOCGIFCONF could return, 110147894Ssam * on at least some platforms it just returns the data that'd fit with 111147894Ssam * no indication that there wasn't enough room for all the data, much 112147894Ssam * less an indication of how much more room is required. 113147894Ssam * 114147894Ssam * The only way to ensure that we got all the data is to pass a buffer 115147894Ssam * large enough that the amount of space in the buffer *not* filled in 116147894Ssam * is greater than the largest possible entry. 117147894Ssam * 118147894Ssam * We assume that's "sizeof(ifreq.ifr_name)" plus 255, under the assumption 119147894Ssam * that no address is more than 255 bytes (on systems where the "sa_len" 120147894Ssam * field in a "struct sockaddr" is 1 byte, e.g. newer BSDs, that's the 121147894Ssam * case, and addresses are unlikely to be bigger than that in any case). 122147894Ssam */ 123147894Ssam#define MAX_SA_LEN 255 124147894Ssam 125127664Sbms/* 126127664Sbms * Get a list of all interfaces that are up and that we can open. 127127664Sbms * Returns -1 on error, 0 otherwise. 128127664Sbms * The list, as returned through "alldevsp", may be null if no interfaces 129127664Sbms * were up and could be opened. 130127664Sbms * 131127664Sbms * This is the implementation used on platforms that have SIOCGIFCONF but 132127664Sbms * don't have any other mechanism for getting a list of interfaces. 133127664Sbms * 134127664Sbms * XXX - or platforms that have other, better mechanisms but for which 135127664Sbms * we don't yet have code to use that mechanism; I think there's a better 136251129Sdelphij * way on Linux, for example, but if that better way is "getifaddrs()", 137251129Sdelphij * we already have that. 138127664Sbms */ 139127664Sbmsint 140251129Sdelphijpcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf) 141127664Sbms{ 142127664Sbms pcap_if_t *devlist = NULL; 143127664Sbms register int fd; 144127664Sbms register struct ifreq *ifrp, *ifend, *ifnext; 145127664Sbms int n; 146127664Sbms struct ifconf ifc; 147127664Sbms char *buf = NULL; 148127664Sbms unsigned buf_size; 149147894Ssam#if defined (HAVE_SOLARIS) || defined (HAVE_HPUX10_20_OR_LATER) 150146768Ssam char *p, *q; 151146768Ssam#endif 152127664Sbms struct ifreq ifrflags, ifrnetmask, ifrbroadaddr, ifrdstaddr; 153127664Sbms struct sockaddr *netmask, *broadaddr, *dstaddr; 154127664Sbms size_t netmask_size, broadaddr_size, dstaddr_size; 155127664Sbms int ret = 0; 156127664Sbms 157127664Sbms /* 158127664Sbms * Create a socket from which to fetch the list of interfaces. 159127664Sbms */ 160127664Sbms fd = socket(AF_INET, SOCK_DGRAM, 0); 161127664Sbms if (fd < 0) { 162127664Sbms (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 163127664Sbms "socket: %s", pcap_strerror(errno)); 164127664Sbms return (-1); 165127664Sbms } 166127664Sbms 167127664Sbms /* 168127664Sbms * Start with an 8K buffer, and keep growing the buffer until 169147894Ssam * we have more than "sizeof(ifrp->ifr_name) + MAX_SA_LEN" 170147894Ssam * bytes left over in the buffer or we fail to get the 171147894Ssam * interface list for some reason other than EINVAL (which is 172147894Ssam * presumed here to mean "buffer is too small"). 173127664Sbms */ 174127664Sbms buf_size = 8192; 175127664Sbms for (;;) { 176127664Sbms buf = malloc(buf_size); 177127664Sbms if (buf == NULL) { 178127664Sbms (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 179127664Sbms "malloc: %s", pcap_strerror(errno)); 180127664Sbms (void)close(fd); 181127664Sbms return (-1); 182127664Sbms } 183127664Sbms 184127664Sbms ifc.ifc_len = buf_size; 185127664Sbms ifc.ifc_buf = buf; 186127664Sbms memset(buf, 0, buf_size); 187127664Sbms if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 188127664Sbms && errno != EINVAL) { 189127664Sbms (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 190127664Sbms "SIOCGIFCONF: %s", pcap_strerror(errno)); 191127664Sbms (void)close(fd); 192127664Sbms free(buf); 193127664Sbms return (-1); 194127664Sbms } 195147894Ssam if (ifc.ifc_len < buf_size && 196147894Ssam (buf_size - ifc.ifc_len) > sizeof(ifrp->ifr_name) + MAX_SA_LEN) 197127664Sbms break; 198127664Sbms free(buf); 199127664Sbms buf_size *= 2; 200127664Sbms } 201127664Sbms 202127664Sbms ifrp = (struct ifreq *)buf; 203127664Sbms ifend = (struct ifreq *)(buf + ifc.ifc_len); 204127664Sbms 205127664Sbms for (; ifrp < ifend; ifrp = ifnext) { 206127664Sbms /* 207127664Sbms * XXX - what if this isn't an IPv4 address? Can 208127664Sbms * we still get the netmask, etc. with ioctls on 209127664Sbms * an IPv4 socket? 210127664Sbms * 211127664Sbms * The answer is probably platform-dependent, and 212127664Sbms * if the answer is "no" on more than one platform, 213127664Sbms * the way you work around it is probably platform- 214127664Sbms * dependent as well. 215127664Sbms */ 216127664Sbms n = SA_LEN(&ifrp->ifr_addr) + sizeof(ifrp->ifr_name); 217127664Sbms if (n < sizeof(*ifrp)) 218127664Sbms ifnext = ifrp + 1; 219127664Sbms else 220127664Sbms ifnext = (struct ifreq *)((char *)ifrp + n); 221127664Sbms 222127664Sbms /* 223146768Ssam * XXX - The 32-bit compatibility layer for Linux on IA-64 224146768Ssam * is slightly broken. It correctly converts the structures 225146768Ssam * to and from kernel land from 64 bit to 32 bit but 226146768Ssam * doesn't update ifc.ifc_len, leaving it larger than the 227146768Ssam * amount really used. This means we read off the end 228146768Ssam * of the buffer and encounter an interface with an 229146768Ssam * "empty" name. Since this is highly unlikely to ever 230146768Ssam * occur in a valid case we can just finish looking for 231146768Ssam * interfaces if we see an empty name. 232146768Ssam */ 233146768Ssam if (!(*ifrp->ifr_name)) 234146768Ssam break; 235146768Ssam 236146768Ssam /* 237146768Ssam * Skip entries that begin with "dummy". 238146768Ssam * XXX - what are these? Is this Linux-specific? 239146768Ssam * Are there platforms on which we shouldn't do this? 240146768Ssam */ 241146768Ssam if (strncmp(ifrp->ifr_name, "dummy", 5) == 0) 242146768Ssam continue; 243146768Ssam 244146768Ssam /* 245127664Sbms * Get the flags for this interface, and skip it if it's 246127664Sbms * not up. 247127664Sbms */ 248127664Sbms strncpy(ifrflags.ifr_name, ifrp->ifr_name, 249127664Sbms sizeof(ifrflags.ifr_name)); 250127664Sbms if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifrflags) < 0) { 251127664Sbms if (errno == ENXIO) 252127664Sbms continue; 253127664Sbms (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 254127664Sbms "SIOCGIFFLAGS: %.*s: %s", 255127664Sbms (int)sizeof(ifrflags.ifr_name), 256127664Sbms ifrflags.ifr_name, 257127664Sbms pcap_strerror(errno)); 258127664Sbms ret = -1; 259127664Sbms break; 260127664Sbms } 261127664Sbms if (!(ifrflags.ifr_flags & IFF_UP)) 262127664Sbms continue; 263127664Sbms 264127664Sbms /* 265127664Sbms * Get the netmask for this address on this interface. 266127664Sbms */ 267127664Sbms strncpy(ifrnetmask.ifr_name, ifrp->ifr_name, 268127664Sbms sizeof(ifrnetmask.ifr_name)); 269127664Sbms memcpy(&ifrnetmask.ifr_addr, &ifrp->ifr_addr, 270127664Sbms sizeof(ifrnetmask.ifr_addr)); 271127664Sbms if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifrnetmask) < 0) { 272127664Sbms if (errno == EADDRNOTAVAIL) { 273127664Sbms /* 274127664Sbms * Not available. 275127664Sbms */ 276127664Sbms netmask = NULL; 277127664Sbms netmask_size = 0; 278127664Sbms } else { 279127664Sbms (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 280127664Sbms "SIOCGIFNETMASK: %.*s: %s", 281127664Sbms (int)sizeof(ifrnetmask.ifr_name), 282127664Sbms ifrnetmask.ifr_name, 283127664Sbms pcap_strerror(errno)); 284127664Sbms ret = -1; 285127664Sbms break; 286127664Sbms } 287127664Sbms } else { 288127664Sbms netmask = &ifrnetmask.ifr_addr; 289127664Sbms netmask_size = SA_LEN(netmask); 290127664Sbms } 291127664Sbms 292127664Sbms /* 293127664Sbms * Get the broadcast address for this address on this 294127664Sbms * interface (if any). 295127664Sbms */ 296127664Sbms if (ifrflags.ifr_flags & IFF_BROADCAST) { 297127664Sbms strncpy(ifrbroadaddr.ifr_name, ifrp->ifr_name, 298127664Sbms sizeof(ifrbroadaddr.ifr_name)); 299127664Sbms memcpy(&ifrbroadaddr.ifr_addr, &ifrp->ifr_addr, 300127664Sbms sizeof(ifrbroadaddr.ifr_addr)); 301127664Sbms if (ioctl(fd, SIOCGIFBRDADDR, 302127664Sbms (char *)&ifrbroadaddr) < 0) { 303127664Sbms if (errno == EADDRNOTAVAIL) { 304127664Sbms /* 305127664Sbms * Not available. 306127664Sbms */ 307127664Sbms broadaddr = NULL; 308127664Sbms broadaddr_size = 0; 309127664Sbms } else { 310127664Sbms (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 311127664Sbms "SIOCGIFBRDADDR: %.*s: %s", 312127664Sbms (int)sizeof(ifrbroadaddr.ifr_name), 313127664Sbms ifrbroadaddr.ifr_name, 314127664Sbms pcap_strerror(errno)); 315127664Sbms ret = -1; 316127664Sbms break; 317127664Sbms } 318127664Sbms } else { 319127664Sbms broadaddr = &ifrbroadaddr.ifr_broadaddr; 320127664Sbms broadaddr_size = SA_LEN(broadaddr); 321127664Sbms } 322127664Sbms } else { 323127664Sbms /* 324127664Sbms * Not a broadcast interface, so no broadcast 325127664Sbms * address. 326127664Sbms */ 327127664Sbms broadaddr = NULL; 328127664Sbms broadaddr_size = 0; 329127664Sbms } 330127664Sbms 331127664Sbms /* 332127664Sbms * Get the destination address for this address on this 333127664Sbms * interface (if any). 334127664Sbms */ 335127664Sbms if (ifrflags.ifr_flags & IFF_POINTOPOINT) { 336127664Sbms strncpy(ifrdstaddr.ifr_name, ifrp->ifr_name, 337127664Sbms sizeof(ifrdstaddr.ifr_name)); 338127664Sbms memcpy(&ifrdstaddr.ifr_addr, &ifrp->ifr_addr, 339127664Sbms sizeof(ifrdstaddr.ifr_addr)); 340127664Sbms if (ioctl(fd, SIOCGIFDSTADDR, 341127664Sbms (char *)&ifrdstaddr) < 0) { 342127664Sbms if (errno == EADDRNOTAVAIL) { 343127664Sbms /* 344127664Sbms * Not available. 345127664Sbms */ 346127664Sbms dstaddr = NULL; 347127664Sbms dstaddr_size = 0; 348127664Sbms } else { 349127664Sbms (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 350127664Sbms "SIOCGIFDSTADDR: %.*s: %s", 351127664Sbms (int)sizeof(ifrdstaddr.ifr_name), 352127664Sbms ifrdstaddr.ifr_name, 353127664Sbms pcap_strerror(errno)); 354127664Sbms ret = -1; 355127664Sbms break; 356127664Sbms } 357127664Sbms } else { 358127664Sbms dstaddr = &ifrdstaddr.ifr_dstaddr; 359127664Sbms dstaddr_size = SA_LEN(dstaddr); 360127664Sbms } 361127664Sbms } else { 362127664Sbms /* 363127664Sbms * Not a point-to-point interface, so no destination 364127664Sbms * address. 365127664Sbms */ 366127664Sbms dstaddr = NULL; 367127664Sbms dstaddr_size = 0; 368127664Sbms } 369127664Sbms 370147894Ssam#if defined (HAVE_SOLARIS) || defined (HAVE_HPUX10_20_OR_LATER) 371127664Sbms /* 372146768Ssam * If this entry has a colon followed by a number at 373146768Ssam * the end, it's a logical interface. Those are just 374146768Ssam * the way you assign multiple IP addresses to a real 375146768Ssam * interface, so an entry for a logical interface should 376146768Ssam * be treated like the entry for the real interface; 377146768Ssam * we do that by stripping off the ":" and the number. 378146768Ssam */ 379146768Ssam p = strchr(ifrp->ifr_name, ':'); 380146768Ssam if (p != NULL) { 381146768Ssam /* 382146768Ssam * We have a ":"; is it followed by a number? 383146768Ssam */ 384146768Ssam q = p + 1; 385146768Ssam while (isdigit((unsigned char)*q)) 386146768Ssam q++; 387146768Ssam if (*q == '\0') { 388146768Ssam /* 389146768Ssam * All digits after the ":" until the end. 390146768Ssam * Strip off the ":" and everything after 391146768Ssam * it. 392146768Ssam */ 393146768Ssam *p = '\0'; 394146768Ssam } 395146768Ssam } 396146768Ssam#endif 397146768Ssam 398146768Ssam /* 399127664Sbms * Add information for this address to the list. 400127664Sbms */ 401127664Sbms if (add_addr_to_iflist(&devlist, ifrp->ifr_name, 402127664Sbms ifrflags.ifr_flags, &ifrp->ifr_addr, 403127664Sbms SA_LEN(&ifrp->ifr_addr), netmask, netmask_size, 404127664Sbms broadaddr, broadaddr_size, dstaddr, dstaddr_size, 405127664Sbms errbuf) < 0) { 406127664Sbms ret = -1; 407127664Sbms break; 408127664Sbms } 409127664Sbms } 410127664Sbms free(buf); 411127664Sbms (void)close(fd); 412127664Sbms 413127664Sbms if (ret == -1) { 414127664Sbms /* 415127664Sbms * We had an error; free the list we've been constructing. 416127664Sbms */ 417127664Sbms if (devlist != NULL) { 418127664Sbms pcap_freealldevs(devlist); 419127664Sbms devlist = NULL; 420127664Sbms } 421127664Sbms } 422127664Sbms 423127664Sbms *alldevsp = devlist; 424127664Sbms return (ret); 425127664Sbms} 426