fad-glifc.c revision 127664
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 12146768Ssam * notice, this list of conditions and the following disclaimer in the 13162012Ssam * documentation and/or other materials provided with the distribution. 14162012Ssam * 3. All advertising materials mentioning features or use of this software 15162012Ssam * 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 20214518Srpaulo * 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_ = 37127664Sbms "@(#) $Header: /tcpdump/master/libpcap/fad-glifc.c,v 1.2.2.1 2003/11/15 23:26:39 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> 46146768Ssam#include <sys/ioctl.h> 47146768Ssam#include <sys/socket.h> 48127664Sbms#ifdef HAVE_SYS_SOCKIO_H 49190225Srpaulo#include <sys/sockio.h> 50190225Srpaulo#endif 51251129Sdelphij#include <sys/time.h> /* concession to AIX */ 52251129Sdelphij 53251129Sdelphijstruct mbuf; /* Squelch compiler warnings on some platforms for */ 54251129Sdelphijstruct rtentry; /* declarations in <net/if.h> */ 55251129Sdelphij#include <net/if.h> 56251129Sdelphij#include <netinet/in.h> 57146768Ssam 58146768Ssam#include <ctype.h> 59127664Sbms#include <errno.h> 60172677Smlaier#include <memory.h> 61172677Smlaier#include <stdio.h> 62172677Smlaier#include <stdlib.h> 63172677Smlaier#include <string.h> 64172677Smlaier#include <unistd.h> 65172677Smlaier 66172677Smlaier#include "pcap-int.h" 67172677Smlaier 68172677Smlaier#ifdef HAVE_OS_PROTO_H 69172677Smlaier#include "os-proto.h" 70172677Smlaier#endif 71172677Smlaier 72146768Ssam/* 73146768Ssam * Get a list of all interfaces that are up and that we can open. 74146768Ssam * Returns -1 on error, 0 otherwise. 75146768Ssam * The list, as returned through "alldevsp", may be null if no interfaces 76146768Ssam * were up and could be opened. 77146768Ssam * 78146768Ssam * This is the implementation used on platforms that have SIOCLGIFCONF 79127664Sbms * but don't have "getifaddrs()". (Solaris 8 and later; we use 80146768Ssam * SIOCLGIFCONF rather than SIOCGIFCONF in order to get IPv6 addresses.) 81146768Ssam */ 82146768Ssamint 83127664Sbmspcap_findalldevs(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; 91172677Smlaier unsigned buf_size; 92172677Smlaier struct lifreq ifrflags, ifrnetmask, ifrbroadaddr, ifrdstaddr; 93172677Smlaier struct sockaddr *netmask, *broadaddr, *dstaddr; 94172677Smlaier int ret = 0; 95127664Sbms 96127664Sbms /* 97127664Sbms * Create a socket from which to fetch the list of interfaces, 98127664Sbms * and from which to fetch IPv4 information. 99127664Sbms */ 100127664Sbms fd4 = socket(AF_INET, SOCK_DGRAM, 0); 101146768Ssam if (fd4 < 0) { 102146768Ssam (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 103146768Ssam "socket: %s", pcap_strerror(errno)); 104146768Ssam return (-1); 105127664Sbms } 106146768Ssam 107146768Ssam /* 108146768Ssam * Create a socket from which to fetch IPv6 information. 109127664Sbms */ 110146768Ssam fd6 = socket(AF_INET6, SOCK_DGRAM, 0); 111146768Ssam if (fd6 < 0) { 112146768Ssam (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 113146768Ssam "socket: %s", pcap_strerror(errno)); 114146768Ssam (void)close(fd4); 115146768Ssam return (-1); 116146768Ssam } 117127664Sbms 118127664Sbms /* 119127664Sbms * How many entries will SIOCGLIFCONF return? 120127664Sbms */ 121127664Sbms ifn.lifn_family = AF_UNSPEC; 122127664Sbms ifn.lifn_flags = 0; 123127664Sbms ifn.lifn_count = 0; 124146768Ssam if (ioctl(fd4, SIOCGLIFNUM, (char *)&ifn) < 0) { 125190225Srpaulo (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 126146768Ssam "SIOCGLIFNUM: %s", pcap_strerror(errno)); 127162012Ssam (void)close(fd6); 128162012Ssam (void)close(fd4); 129162012Ssam return (-1); 130162012Ssam } 131162012Ssam 132146768Ssam /* 133162012Ssam * Allocate a buffer for those entries. 134162012Ssam */ 135127664Sbms buf_size = ifn.lifn_count * sizeof (struct lifreq); 136146768Ssam buf = malloc(buf_size); 137146768Ssam if (buf == NULL) { 138162012Ssam (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 139190225Srpaulo "malloc: %s", pcap_strerror(errno)); 140190225Srpaulo (void)close(fd6); 141190225Srpaulo (void)close(fd4); 142190225Srpaulo return (-1); 143190225Srpaulo } 144190225Srpaulo 145190225Srpaulo /* 146146768Ssam * Get the entries. 147146768Ssam */ 148127664Sbms ifc.lifc_len = buf_size; 149127664Sbms ifc.lifc_buf = buf; 150146768Ssam ifc.lifc_family = AF_UNSPEC; 151146768Ssam ifc.lifc_flags = 0; 152146768Ssam memset(buf, 0, buf_size); 153146768Ssam if (ioctl(fd4, SIOCGLIFCONF, (char *)&ifc) < 0) { 154146768Ssam (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 155190225Srpaulo "SIOCGLIFCONF: %s", pcap_strerror(errno)); 156146768Ssam (void)close(fd6); 157146768Ssam (void)close(fd4); 158146768Ssam free(buf); 159146768Ssam return (-1); 160127664Sbms } 161127664Sbms 162146768Ssam /* 163146768Ssam * Loop over the entries. 164146768Ssam */ 165146768Ssam ifrp = (struct lifreq *)buf; 166127664Sbms ifend = (struct lifreq *)(buf + ifc.lifc_len); 167146768Ssam 168146768Ssam for (; ifrp < ifend; ifrp++) { 169146768Ssam /* 170127664Sbms * IPv6 or not? 171146768Ssam */ 172146768Ssam if (((struct sockaddr *)&ifrp->lifr_addr)->sa_family == AF_INET6) 173146768Ssam fd = fd6; 174146768Ssam else 175127664Sbms fd = fd4; 176146768Ssam 177146768Ssam /* 178146768Ssam * Get the flags for this interface, and skip it if it's 179127664Sbms * not up. 180146768Ssam */ 181127664Sbms strncpy(ifrflags.lifr_name, ifrp->lifr_name, 182146768Ssam sizeof(ifrflags.lifr_name)); 183127664Sbms if (ioctl(fd, SIOCGLIFFLAGS, (char *)&ifrflags) < 0) { 184127664Sbms if (errno == ENXIO) 185190225Srpaulo continue; 186190225Srpaulo (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 187190225Srpaulo "SIOCGLIFFLAGS: %.*s: %s", 188190225Srpaulo (int)sizeof(ifrflags.lifr_name), 189190225Srpaulo ifrflags.lifr_name, 190190225Srpaulo pcap_strerror(errno)); 191190225Srpaulo ret = -1; 192190225Srpaulo break; 193190225Srpaulo } 194190225Srpaulo if (!(ifrflags.lifr_flags & IFF_UP)) 195190225Srpaulo continue; 196190225Srpaulo 197190225Srpaulo /* 198190225Srpaulo * Get the netmask for this address on this interface. 199190225Srpaulo */ 200190225Srpaulo strncpy(ifrnetmask.lifr_name, ifrp->lifr_name, 201190225Srpaulo sizeof(ifrnetmask.lifr_name)); 202190225Srpaulo memcpy(&ifrnetmask.lifr_addr, &ifrp->lifr_addr, 203190225Srpaulo sizeof(ifrnetmask.lifr_addr)); 204190225Srpaulo if (ioctl(fd, SIOCGLIFNETMASK, (char *)&ifrnetmask) < 0) { 205190225Srpaulo if (errno == EADDRNOTAVAIL) { 206190225Srpaulo /* 207190225Srpaulo * Not available. 208190225Srpaulo */ 209190225Srpaulo netmask = NULL; 210190225Srpaulo } else { 211190225Srpaulo (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 212190225Srpaulo "SIOCGLIFNETMASK: %.*s: %s", 213190225Srpaulo (int)sizeof(ifrnetmask.lifr_name), 214190225Srpaulo ifrnetmask.lifr_name, 215190225Srpaulo pcap_strerror(errno)); 216190225Srpaulo ret = -1; 217127664Sbms break; 218127664Sbms } 219127664Sbms } else 220127664Sbms netmask = (struct sockaddr *)&ifrnetmask.lifr_addr; 221127664Sbms 222146768Ssam /* 223146768Ssam * Get the broadcast address for this address on this 224146768Ssam * interface (if any). 225127664Sbms */ 226127664Sbms if (ifrflags.lifr_flags & IFF_BROADCAST) { 227127664Sbms strncpy(ifrbroadaddr.lifr_name, ifrp->lifr_name, 228190225Srpaulo sizeof(ifrbroadaddr.lifr_name)); 229127664Sbms memcpy(&ifrbroadaddr.lifr_addr, &ifrp->lifr_addr, 230162012Ssam sizeof(ifrbroadaddr.lifr_addr)); 231162012Ssam if (ioctl(fd, SIOCGLIFBRDADDR, 232127664Sbms (char *)&ifrbroadaddr) < 0) { 233162012Ssam if (errno == EADDRNOTAVAIL) { 234162012Ssam /* 235162012Ssam * Not available. 236162012Ssam */ 237127664Sbms broadaddr = NULL; 238162012Ssam } else { 239162012Ssam (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 240162012Ssam "SIOCGLIFBRDADDR: %.*s: %s", 241127664Sbms (int)sizeof(ifrbroadaddr.lifr_name), 242162012Ssam ifrbroadaddr.lifr_name, 243162012Ssam pcap_strerror(errno)); 244162012Ssam ret = -1; 245127664Sbms break; 246162012Ssam } 247162012Ssam } else 248162012Ssam broadaddr = (struct sockaddr *)&ifrbroadaddr.lifr_broadaddr; 249162012Ssam } else { 250162012Ssam /* 251162012Ssam * Not a broadcast interface, so no broadcast 252162012Ssam * address. 253162012Ssam */ 254162012Ssam broadaddr = NULL; 255162012Ssam } 256162012Ssam 257162012Ssam /* 258190225Srpaulo * Get the destination address for this address on this 259190225Srpaulo * interface (if any). 260190225Srpaulo */ 261162012Ssam if (ifrflags.lifr_flags & IFF_POINTOPOINT) { 262162012Ssam strncpy(ifrdstaddr.lifr_name, ifrp->lifr_name, 263162012Ssam sizeof(ifrdstaddr.lifr_name)); 264162012Ssam memcpy(&ifrdstaddr.lifr_addr, &ifrp->lifr_addr, 265162012Ssam sizeof(ifrdstaddr.lifr_addr)); 266162012Ssam if (ioctl(fd, SIOCGLIFDSTADDR, 267162012Ssam (char *)&ifrdstaddr) < 0) { 268162012Ssam if (errno == EADDRNOTAVAIL) { 269162012Ssam /* 270127664Sbms * Not available. 271162012Ssam */ 272162012Ssam dstaddr = NULL; 273162012Ssam } else { 274162012Ssam (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 275162012Ssam "SIOCGLIFDSTADDR: %.*s: %s", 276162012Ssam (int)sizeof(ifrdstaddr.lifr_name), 277162012Ssam ifrdstaddr.lifr_name, 278162012Ssam pcap_strerror(errno)); 279162012Ssam ret = -1; 280162012Ssam break; 281146768Ssam } 282162012Ssam } else 283162012Ssam dstaddr = (struct sockaddr *)&ifrdstaddr.lifr_dstaddr; 284190225Srpaulo } else 285162012Ssam dstaddr = NULL; 286162012Ssam 287162012Ssam /* 288190225Srpaulo * Add information for this address to the list. 289162012Ssam */ 290162012Ssam if (add_addr_to_iflist(&devlist, ifrp->lifr_name, 291162012Ssam ifrflags.lifr_flags, (struct sockaddr *)&ifrp->lifr_addr, 292162012Ssam sizeof (struct sockaddr_storage), 293162012Ssam netmask, sizeof (struct sockaddr_storage), 294162012Ssam broadaddr, sizeof (struct sockaddr_storage), 295190225Srpaulo dstaddr, sizeof (struct sockaddr_storage), errbuf) < 0) { 296162012Ssam ret = -1; 297127664Sbms break; 298162012Ssam } 299162012Ssam } 300162012Ssam free(buf); 301162012Ssam (void)close(fd6); 302127664Sbms (void)close(fd4); 303162012Ssam 304162012Ssam if (ret != -1) { 305162012Ssam /* 306127664Sbms * We haven't had any errors yet; do any platform-specific 307162012Ssam * operations to add devices. 308162012Ssam */ 309162012Ssam if (pcap_platform_finddevs(&devlist, errbuf) < 0) 310127664Sbms ret = -1; 311162012Ssam } 312162012Ssam 313162012Ssam if (ret == -1) { 314162012Ssam /* 315162012Ssam * We had an error; free the list we've been constructing. 316162012Ssam */ 317162012Ssam if (devlist != NULL) { 318162012Ssam pcap_freealldevs(devlist); 319162012Ssam devlist = NULL; 320190225Srpaulo } 321190225Srpaulo } 322162012Ssam 323162012Ssam *alldevsp = devlist; 324172677Smlaier return (ret); 325172677Smlaier} 326172677Smlaier