1 /* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ 2 /* 3 * Copyright (c) 1994, 1995, 1996, 1997, 1998 4 * The Regents of the University of California. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by the Computer Systems 17 * Engineering Group at Lawrence Berkeley Laboratory. 18 * 4. Neither the name of the University nor of the Laboratory may be used 19 * to endorse or promote products derived from this software without 20 * specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #ifndef lint 36 static const char rcsid[] _U_ = 37 "@(#) $Header: /tcpdump/master/libpcap/fad-glifc.c,v 1.2.2.1 2003/11/15 23:26:39 guy Exp $ (LBL)"; 38 #endif 39 40 #ifdef HAVE_CONFIG_H 41 #include "config.h" 42 #endif 43 44 #include <sys/param.h> 45 #include <sys/file.h> 46 #include <sys/ioctl.h> 47 #include <sys/socket.h> 48 #ifdef HAVE_SYS_SOCKIO_H 49 #include <sys/sockio.h> 50 #endif 51 #include <sys/time.h> /* concession to AIX */ 52 53 struct mbuf; /* Squelch compiler warnings on some platforms for */ 54 struct rtentry; /* declarations in <net/if.h> */ 55 #include <net/if.h> 56 #include <netinet/in.h> 57 58 #include <ctype.h> 59 #include <errno.h> 60 #include <memory.h> 61 #include <stdio.h> 62 #include <stdlib.h> 63 #include <string.h> 64 #include <unistd.h> 65 66 #include "pcap-int.h" 67 68 #ifdef HAVE_OS_PROTO_H 69 #include "os-proto.h" 70 #endif 71 72 /* 73 * Get a list of all interfaces that are up and that we can open. 74 * Returns -1 on error, 0 otherwise. 75 * The list, as returned through "alldevsp", may be null if no interfaces 76 * were up and could be opened. 77 * 78 * This is the implementation used on platforms that have SIOCLGIFCONF 79 * but don't have "getifaddrs()". (Solaris 8 and later; we use 80 * SIOCLGIFCONF rather than SIOCGIFCONF in order to get IPv6 addresses.) 81 */ 82 int 83 pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf) 84 { 85 pcap_if_t *devlist = NULL; 86 register int fd4, fd6, fd; 87 register struct lifreq *ifrp, *ifend; 88 struct lifnum ifn; 89 struct lifconf ifc; 90 char *buf = NULL; 91 unsigned buf_size; 92 struct lifreq ifrflags, ifrnetmask, ifrbroadaddr, ifrdstaddr; 93 struct sockaddr *netmask, *broadaddr, *dstaddr; 94 int ret = 0; 95 96 /* 97 * Create a socket from which to fetch the list of interfaces, 98 * and from which to fetch IPv4 information. 99 */ 100 fd4 = socket(AF_INET, SOCK_DGRAM, 0); 101 if (fd4 < 0) { 102 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 103 "socket: %s", pcap_strerror(errno)); 104 return (-1); 105 } 106 107 /* 108 * Create a socket from which to fetch IPv6 information. 109 */ 110 fd6 = socket(AF_INET6, SOCK_DGRAM, 0); 111 if (fd6 < 0) { 112 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 113 "socket: %s", pcap_strerror(errno)); 114 (void)close(fd4); 115 return (-1); 116 } 117 118 /* 119 * How many entries will SIOCGLIFCONF return? 120 */ 121 ifn.lifn_family = AF_UNSPEC; 122 ifn.lifn_flags = 0; 123 ifn.lifn_count = 0; 124 if (ioctl(fd4, SIOCGLIFNUM, (char *)&ifn) < 0) { 125 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 126 "SIOCGLIFNUM: %s", pcap_strerror(errno)); 127 (void)close(fd6); 128 (void)close(fd4); 129 return (-1); 130 } 131 132 /* 133 * Allocate a buffer for those entries. 134 */ 135 buf_size = ifn.lifn_count * sizeof (struct lifreq); 136 buf = malloc(buf_size); 137 if (buf == NULL) { 138 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 139 "malloc: %s", pcap_strerror(errno)); 140 (void)close(fd6); 141 (void)close(fd4); 142 return (-1); 143 } 144 145 /* 146 * Get the entries. 147 */ 148 ifc.lifc_len = buf_size; 149 ifc.lifc_buf = buf; 150 ifc.lifc_family = AF_UNSPEC; 151 ifc.lifc_flags = 0; 152 memset(buf, 0, buf_size); 153 if (ioctl(fd4, SIOCGLIFCONF, (char *)&ifc) < 0) { 154 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 155 "SIOCGLIFCONF: %s", pcap_strerror(errno)); 156 (void)close(fd6); 157 (void)close(fd4); 158 free(buf); 159 return (-1); 160 } 161 162 /* 163 * Loop over the entries. 164 */ 165 ifrp = (struct lifreq *)buf; 166 ifend = (struct lifreq *)(buf + ifc.lifc_len); 167 168 for (; ifrp < ifend; ifrp++) { 169 /* 170 * IPv6 or not? 171 */ 172 if (((struct sockaddr *)&ifrp->lifr_addr)->sa_family == AF_INET6) 173 fd = fd6; 174 else 175 fd = fd4; 176 177 /* 178 * Get the flags for this interface, and skip it if it's 179 * not up. 180 */ 181 strncpy(ifrflags.lifr_name, ifrp->lifr_name, 182 sizeof(ifrflags.lifr_name)); 183 if (ioctl(fd, SIOCGLIFFLAGS, (char *)&ifrflags) < 0) { 184 if (errno == ENXIO) 185 continue; 186 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 187 "SIOCGLIFFLAGS: %.*s: %s", 188 (int)sizeof(ifrflags.lifr_name), 189 ifrflags.lifr_name, 190 pcap_strerror(errno)); 191 ret = -1; 192 break; 193 } 194 if (!(ifrflags.lifr_flags & IFF_UP)) 195 continue; 196 197 /* 198 * Get the netmask for this address on this interface. 199 */ 200 strncpy(ifrnetmask.lifr_name, ifrp->lifr_name, 201 sizeof(ifrnetmask.lifr_name)); 202 memcpy(&ifrnetmask.lifr_addr, &ifrp->lifr_addr, 203 sizeof(ifrnetmask.lifr_addr)); 204 if (ioctl(fd, SIOCGLIFNETMASK, (char *)&ifrnetmask) < 0) { 205 if (errno == EADDRNOTAVAIL) { 206 /* 207 * Not available. 208 */ 209 netmask = NULL; 210 } else { 211 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 212 "SIOCGLIFNETMASK: %.*s: %s", 213 (int)sizeof(ifrnetmask.lifr_name), 214 ifrnetmask.lifr_name, 215 pcap_strerror(errno)); 216 ret = -1; 217 break; 218 } 219 } else 220 netmask = (struct sockaddr *)&ifrnetmask.lifr_addr; 221 222 /* 223 * Get the broadcast address for this address on this 224 * interface (if any). 225 */ 226 if (ifrflags.lifr_flags & IFF_BROADCAST) { 227 strncpy(ifrbroadaddr.lifr_name, ifrp->lifr_name, 228 sizeof(ifrbroadaddr.lifr_name)); 229 memcpy(&ifrbroadaddr.lifr_addr, &ifrp->lifr_addr, 230 sizeof(ifrbroadaddr.lifr_addr)); 231 if (ioctl(fd, SIOCGLIFBRDADDR, 232 (char *)&ifrbroadaddr) < 0) { 233 if (errno == EADDRNOTAVAIL) { 234 /* 235 * Not available. 236 */ 237 broadaddr = NULL; 238 } else { 239 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 240 "SIOCGLIFBRDADDR: %.*s: %s", 241 (int)sizeof(ifrbroadaddr.lifr_name), 242 ifrbroadaddr.lifr_name, 243 pcap_strerror(errno)); 244 ret = -1; 245 break; 246 } 247 } else 248 broadaddr = (struct sockaddr *)&ifrbroadaddr.lifr_broadaddr; 249 } else { 250 /* 251 * Not a broadcast interface, so no broadcast 252 * address. 253 */ 254 broadaddr = NULL; 255 } 256 257 /* 258 * Get the destination address for this address on this 259 * interface (if any). 260 */ 261 if (ifrflags.lifr_flags & IFF_POINTOPOINT) { 262 strncpy(ifrdstaddr.lifr_name, ifrp->lifr_name, 263 sizeof(ifrdstaddr.lifr_name)); 264 memcpy(&ifrdstaddr.lifr_addr, &ifrp->lifr_addr, 265 sizeof(ifrdstaddr.lifr_addr)); 266 if (ioctl(fd, SIOCGLIFDSTADDR, 267 (char *)&ifrdstaddr) < 0) { 268 if (errno == EADDRNOTAVAIL) { 269 /* 270 * Not available. 271 */ 272 dstaddr = NULL; 273 } else { 274 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 275 "SIOCGLIFDSTADDR: %.*s: %s", 276 (int)sizeof(ifrdstaddr.lifr_name), 277 ifrdstaddr.lifr_name, 278 pcap_strerror(errno)); 279 ret = -1; 280 break; 281 } 282 } else 283 dstaddr = (struct sockaddr *)&ifrdstaddr.lifr_dstaddr; 284 } else 285 dstaddr = NULL; 286 287 /* 288 * Add information for this address to the list. 289 */ 290 if (add_addr_to_iflist(&devlist, ifrp->lifr_name, 291 ifrflags.lifr_flags, (struct sockaddr *)&ifrp->lifr_addr, 292 sizeof (struct sockaddr_storage), 293 netmask, sizeof (struct sockaddr_storage), 294 broadaddr, sizeof (struct sockaddr_storage), 295 dstaddr, sizeof (struct sockaddr_storage), errbuf) < 0) { 296 ret = -1; 297 break; 298 } 299 } 300 free(buf); 301 (void)close(fd6); 302 (void)close(fd4); 303 304 if (ret != -1) { 305 /* 306 * We haven't had any errors yet; do any platform-specific 307 * operations to add devices. 308 */ 309 if (pcap_platform_finddevs(&devlist, errbuf) < 0) 310 ret = -1; 311 } 312 313 if (ret == -1) { 314 /* 315 * We had an error; free the list we've been constructing. 316 */ 317 if (devlist != NULL) { 318 pcap_freealldevs(devlist); 319 devlist = NULL; 320 } 321 } 322 323 *alldevsp = devlist; 324 return (ret); 325 } 326