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-glifc.c,v 1.7 2008-01-30 09:35:48 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/file.h> 46127664Sbms#include <sys/ioctl.h> 47127664Sbms#include <sys/socket.h> 48127664Sbms#ifdef HAVE_SYS_SOCKIO_H 49127664Sbms#include <sys/sockio.h> 50127664Sbms#endif 51127664Sbms#include <sys/time.h> /* concession to AIX */ 52127664Sbms 53127664Sbmsstruct mbuf; /* Squelch compiler warnings on some platforms for */ 54127664Sbmsstruct rtentry; /* declarations in <net/if.h> */ 55127664Sbms#include <net/if.h> 56127664Sbms#include <netinet/in.h> 57127664Sbms 58127664Sbms#include <ctype.h> 59127664Sbms#include <errno.h> 60127664Sbms#include <memory.h> 61127664Sbms#include <stdio.h> 62127664Sbms#include <stdlib.h> 63127664Sbms#include <string.h> 64127664Sbms#include <unistd.h> 65127664Sbms 66127664Sbms#include "pcap-int.h" 67127664Sbms 68127664Sbms#ifdef HAVE_OS_PROTO_H 69127664Sbms#include "os-proto.h" 70127664Sbms#endif 71127664Sbms 72127664Sbms/* 73127664Sbms * Get a list of all interfaces that are up and that we can open. 74127664Sbms * Returns -1 on error, 0 otherwise. 75127664Sbms * The list, as returned through "alldevsp", may be null if no interfaces 76127664Sbms * were up and could be opened. 77127664Sbms * 78190225Srpaulo * This is the implementation used on platforms that have SIOCGLIFCONF 79127664Sbms * but don't have "getifaddrs()". (Solaris 8 and later; we use 80190225Srpaulo * SIOCGLIFCONF rather than SIOCGIFCONF in order to get IPv6 addresses.) 81127664Sbms */ 82127664Sbmsint 83251129Sdelphijpcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf) 84127664Sbms{ 85127664Sbms pcap_if_t *devlist = NULL; 86127664Sbms register int fd4, fd6, fd; 87127664Sbms register struct lifreq *ifrp, *ifend; 88127664Sbms struct lifnum ifn; 89127664Sbms struct lifconf ifc; 90127664Sbms char *buf = NULL; 91127664Sbms unsigned buf_size; 92146768Ssam#ifdef HAVE_SOLARIS 93146768Ssam char *p, *q; 94146768Ssam#endif 95127664Sbms struct lifreq ifrflags, ifrnetmask, ifrbroadaddr, ifrdstaddr; 96127664Sbms struct sockaddr *netmask, *broadaddr, *dstaddr; 97127664Sbms int ret = 0; 98127664Sbms 99127664Sbms /* 100127664Sbms * Create a socket from which to fetch the list of interfaces, 101127664Sbms * and from which to fetch IPv4 information. 102127664Sbms */ 103127664Sbms fd4 = socket(AF_INET, SOCK_DGRAM, 0); 104127664Sbms if (fd4 < 0) { 105127664Sbms (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 106127664Sbms "socket: %s", pcap_strerror(errno)); 107127664Sbms return (-1); 108127664Sbms } 109127664Sbms 110127664Sbms /* 111127664Sbms * Create a socket from which to fetch IPv6 information. 112127664Sbms */ 113127664Sbms fd6 = socket(AF_INET6, SOCK_DGRAM, 0); 114127664Sbms if (fd6 < 0) { 115127664Sbms (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 116127664Sbms "socket: %s", pcap_strerror(errno)); 117127664Sbms (void)close(fd4); 118127664Sbms return (-1); 119127664Sbms } 120127664Sbms 121127664Sbms /* 122127664Sbms * How many entries will SIOCGLIFCONF return? 123127664Sbms */ 124127664Sbms ifn.lifn_family = AF_UNSPEC; 125127664Sbms ifn.lifn_flags = 0; 126127664Sbms ifn.lifn_count = 0; 127127664Sbms if (ioctl(fd4, SIOCGLIFNUM, (char *)&ifn) < 0) { 128127664Sbms (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 129127664Sbms "SIOCGLIFNUM: %s", pcap_strerror(errno)); 130127664Sbms (void)close(fd6); 131127664Sbms (void)close(fd4); 132127664Sbms return (-1); 133127664Sbms } 134127664Sbms 135127664Sbms /* 136127664Sbms * Allocate a buffer for those entries. 137127664Sbms */ 138127664Sbms buf_size = ifn.lifn_count * sizeof (struct lifreq); 139127664Sbms buf = malloc(buf_size); 140127664Sbms if (buf == NULL) { 141127664Sbms (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 142127664Sbms "malloc: %s", pcap_strerror(errno)); 143127664Sbms (void)close(fd6); 144127664Sbms (void)close(fd4); 145127664Sbms return (-1); 146127664Sbms } 147127664Sbms 148127664Sbms /* 149127664Sbms * Get the entries. 150127664Sbms */ 151127664Sbms ifc.lifc_len = buf_size; 152127664Sbms ifc.lifc_buf = buf; 153127664Sbms ifc.lifc_family = AF_UNSPEC; 154127664Sbms ifc.lifc_flags = 0; 155127664Sbms memset(buf, 0, buf_size); 156127664Sbms if (ioctl(fd4, SIOCGLIFCONF, (char *)&ifc) < 0) { 157127664Sbms (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 158127664Sbms "SIOCGLIFCONF: %s", pcap_strerror(errno)); 159127664Sbms (void)close(fd6); 160127664Sbms (void)close(fd4); 161127664Sbms free(buf); 162127664Sbms return (-1); 163127664Sbms } 164127664Sbms 165127664Sbms /* 166127664Sbms * Loop over the entries. 167127664Sbms */ 168127664Sbms ifrp = (struct lifreq *)buf; 169127664Sbms ifend = (struct lifreq *)(buf + ifc.lifc_len); 170127664Sbms 171127664Sbms for (; ifrp < ifend; ifrp++) { 172127664Sbms /* 173127664Sbms * IPv6 or not? 174127664Sbms */ 175127664Sbms if (((struct sockaddr *)&ifrp->lifr_addr)->sa_family == AF_INET6) 176127664Sbms fd = fd6; 177127664Sbms else 178127664Sbms fd = fd4; 179127664Sbms 180127664Sbms /* 181146768Ssam * Skip entries that begin with "dummy". 182146768Ssam * XXX - what are these? Is this Linux-specific? 183146768Ssam * Are there platforms on which we shouldn't do this? 184146768Ssam */ 185146768Ssam if (strncmp(ifrp->lifr_name, "dummy", 5) == 0) 186146768Ssam continue; 187146768Ssam 188146768Ssam#ifdef HAVE_SOLARIS 189146768Ssam /* 190146768Ssam * Skip entries that have a ":" followed by a number 191146768Ssam * at the end - those are Solaris virtual interfaces 192146768Ssam * on which you can't capture. 193146768Ssam */ 194146768Ssam p = strchr(ifrp->lifr_name, ':'); 195146768Ssam if (p != NULL) { 196146768Ssam /* 197146768Ssam * We have a ":"; is it followed by a number? 198146768Ssam */ 199146768Ssam while (isdigit((unsigned char)*p)) 200146768Ssam p++; 201146768Ssam if (*p == '\0') { 202146768Ssam /* 203146768Ssam * All digits after the ":" until the end. 204146768Ssam */ 205146768Ssam continue; 206146768Ssam } 207146768Ssam } 208146768Ssam#endif 209146768Ssam 210146768Ssam /* 211127664Sbms * Get the flags for this interface, and skip it if it's 212127664Sbms * not up. 213127664Sbms */ 214127664Sbms strncpy(ifrflags.lifr_name, ifrp->lifr_name, 215127664Sbms sizeof(ifrflags.lifr_name)); 216127664Sbms if (ioctl(fd, SIOCGLIFFLAGS, (char *)&ifrflags) < 0) { 217127664Sbms if (errno == ENXIO) 218127664Sbms continue; 219127664Sbms (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 220127664Sbms "SIOCGLIFFLAGS: %.*s: %s", 221127664Sbms (int)sizeof(ifrflags.lifr_name), 222127664Sbms ifrflags.lifr_name, 223127664Sbms pcap_strerror(errno)); 224127664Sbms ret = -1; 225127664Sbms break; 226127664Sbms } 227127664Sbms if (!(ifrflags.lifr_flags & IFF_UP)) 228127664Sbms continue; 229127664Sbms 230127664Sbms /* 231127664Sbms * Get the netmask for this address on this interface. 232127664Sbms */ 233127664Sbms strncpy(ifrnetmask.lifr_name, ifrp->lifr_name, 234127664Sbms sizeof(ifrnetmask.lifr_name)); 235127664Sbms memcpy(&ifrnetmask.lifr_addr, &ifrp->lifr_addr, 236127664Sbms sizeof(ifrnetmask.lifr_addr)); 237127664Sbms if (ioctl(fd, SIOCGLIFNETMASK, (char *)&ifrnetmask) < 0) { 238127664Sbms if (errno == EADDRNOTAVAIL) { 239127664Sbms /* 240127664Sbms * Not available. 241127664Sbms */ 242127664Sbms netmask = NULL; 243127664Sbms } else { 244127664Sbms (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 245127664Sbms "SIOCGLIFNETMASK: %.*s: %s", 246127664Sbms (int)sizeof(ifrnetmask.lifr_name), 247127664Sbms ifrnetmask.lifr_name, 248127664Sbms pcap_strerror(errno)); 249127664Sbms ret = -1; 250127664Sbms break; 251127664Sbms } 252127664Sbms } else 253127664Sbms netmask = (struct sockaddr *)&ifrnetmask.lifr_addr; 254127664Sbms 255127664Sbms /* 256127664Sbms * Get the broadcast address for this address on this 257127664Sbms * interface (if any). 258127664Sbms */ 259127664Sbms if (ifrflags.lifr_flags & IFF_BROADCAST) { 260127664Sbms strncpy(ifrbroadaddr.lifr_name, ifrp->lifr_name, 261127664Sbms sizeof(ifrbroadaddr.lifr_name)); 262127664Sbms memcpy(&ifrbroadaddr.lifr_addr, &ifrp->lifr_addr, 263127664Sbms sizeof(ifrbroadaddr.lifr_addr)); 264127664Sbms if (ioctl(fd, SIOCGLIFBRDADDR, 265127664Sbms (char *)&ifrbroadaddr) < 0) { 266127664Sbms if (errno == EADDRNOTAVAIL) { 267127664Sbms /* 268127664Sbms * Not available. 269127664Sbms */ 270127664Sbms broadaddr = NULL; 271127664Sbms } else { 272127664Sbms (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 273127664Sbms "SIOCGLIFBRDADDR: %.*s: %s", 274127664Sbms (int)sizeof(ifrbroadaddr.lifr_name), 275127664Sbms ifrbroadaddr.lifr_name, 276127664Sbms pcap_strerror(errno)); 277127664Sbms ret = -1; 278127664Sbms break; 279127664Sbms } 280127664Sbms } else 281127664Sbms broadaddr = (struct sockaddr *)&ifrbroadaddr.lifr_broadaddr; 282127664Sbms } else { 283127664Sbms /* 284127664Sbms * Not a broadcast interface, so no broadcast 285127664Sbms * address. 286127664Sbms */ 287127664Sbms broadaddr = NULL; 288127664Sbms } 289127664Sbms 290127664Sbms /* 291127664Sbms * Get the destination address for this address on this 292127664Sbms * interface (if any). 293127664Sbms */ 294127664Sbms if (ifrflags.lifr_flags & IFF_POINTOPOINT) { 295127664Sbms strncpy(ifrdstaddr.lifr_name, ifrp->lifr_name, 296127664Sbms sizeof(ifrdstaddr.lifr_name)); 297127664Sbms memcpy(&ifrdstaddr.lifr_addr, &ifrp->lifr_addr, 298127664Sbms sizeof(ifrdstaddr.lifr_addr)); 299127664Sbms if (ioctl(fd, SIOCGLIFDSTADDR, 300127664Sbms (char *)&ifrdstaddr) < 0) { 301127664Sbms if (errno == EADDRNOTAVAIL) { 302127664Sbms /* 303127664Sbms * Not available. 304127664Sbms */ 305127664Sbms dstaddr = NULL; 306127664Sbms } else { 307127664Sbms (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 308127664Sbms "SIOCGLIFDSTADDR: %.*s: %s", 309127664Sbms (int)sizeof(ifrdstaddr.lifr_name), 310127664Sbms ifrdstaddr.lifr_name, 311127664Sbms pcap_strerror(errno)); 312127664Sbms ret = -1; 313127664Sbms break; 314127664Sbms } 315127664Sbms } else 316127664Sbms dstaddr = (struct sockaddr *)&ifrdstaddr.lifr_dstaddr; 317127664Sbms } else 318127664Sbms dstaddr = NULL; 319127664Sbms 320146768Ssam#ifdef HAVE_SOLARIS 321127664Sbms /* 322146768Ssam * If this entry has a colon followed by a number at 323146768Ssam * the end, it's a logical interface. Those are just 324146768Ssam * the way you assign multiple IP addresses to a real 325146768Ssam * interface, so an entry for a logical interface should 326146768Ssam * be treated like the entry for the real interface; 327146768Ssam * we do that by stripping off the ":" and the number. 328146768Ssam */ 329147894Ssam p = strchr(ifrp->lifr_name, ':'); 330146768Ssam if (p != NULL) { 331146768Ssam /* 332146768Ssam * We have a ":"; is it followed by a number? 333146768Ssam */ 334146768Ssam q = p + 1; 335146768Ssam while (isdigit((unsigned char)*q)) 336146768Ssam q++; 337146768Ssam if (*q == '\0') { 338146768Ssam /* 339146768Ssam * All digits after the ":" until the end. 340146768Ssam * Strip off the ":" and everything after 341146768Ssam * it. 342146768Ssam */ 343146768Ssam *p = '\0'; 344146768Ssam } 345146768Ssam } 346146768Ssam#endif 347146768Ssam 348146768Ssam /* 349127664Sbms * Add information for this address to the list. 350127664Sbms */ 351127664Sbms if (add_addr_to_iflist(&devlist, ifrp->lifr_name, 352127664Sbms ifrflags.lifr_flags, (struct sockaddr *)&ifrp->lifr_addr, 353127664Sbms sizeof (struct sockaddr_storage), 354127664Sbms netmask, sizeof (struct sockaddr_storage), 355127664Sbms broadaddr, sizeof (struct sockaddr_storage), 356127664Sbms dstaddr, sizeof (struct sockaddr_storage), errbuf) < 0) { 357127664Sbms ret = -1; 358127664Sbms break; 359127664Sbms } 360127664Sbms } 361127664Sbms free(buf); 362127664Sbms (void)close(fd6); 363127664Sbms (void)close(fd4); 364127664Sbms 365127664Sbms if (ret == -1) { 366127664Sbms /* 367127664Sbms * We had an error; free the list we've been constructing. 368127664Sbms */ 369127664Sbms if (devlist != NULL) { 370127664Sbms pcap_freealldevs(devlist); 371127664Sbms devlist = NULL; 372127664Sbms } 373127664Sbms } 374127664Sbms 375127664Sbms *alldevsp = devlist; 376127664Sbms return (ret); 377127664Sbms} 378