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.7 2008-01-30 09:35:48 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 SIOCGLIFCONF 79 * but don't have "getifaddrs()". (Solaris 8 and later; we use 80 * SIOCGLIFCONF rather than SIOCGIFCONF in order to get IPv6 addresses.) 81 */ 82 int 83 pcap_findalldevs_interfaces(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 #ifdef HAVE_SOLARIS 93 char *p, *q; 94 #endif 95 struct lifreq ifrflags, ifrnetmask, ifrbroadaddr, ifrdstaddr; 96 struct sockaddr *netmask, *broadaddr, *dstaddr; 97 int ret = 0; 98 99 /* 100 * Create a socket from which to fetch the list of interfaces, 101 * and from which to fetch IPv4 information. 102 */ 103 fd4 = socket(AF_INET, SOCK_DGRAM, 0); 104 if (fd4 < 0) { 105 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 106 "socket: %s", pcap_strerror(errno)); 107 return (-1); 108 } 109 110 /* 111 * Create a socket from which to fetch IPv6 information. 112 */ 113 fd6 = socket(AF_INET6, SOCK_DGRAM, 0); 114 if (fd6 < 0) { 115 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 116 "socket: %s", pcap_strerror(errno)); 117 (void)close(fd4); 118 return (-1); 119 } 120 121 /* 122 * How many entries will SIOCGLIFCONF return? 123 */ 124 ifn.lifn_family = AF_UNSPEC; 125 ifn.lifn_flags = 0; 126 ifn.lifn_count = 0; 127 if (ioctl(fd4, SIOCGLIFNUM, (char *)&ifn) < 0) { 128 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 129 "SIOCGLIFNUM: %s", pcap_strerror(errno)); 130 (void)close(fd6); 131 (void)close(fd4); 132 return (-1); 133 } 134 135 /* 136 * Allocate a buffer for those entries. 137 */ 138 buf_size = ifn.lifn_count * sizeof (struct lifreq); 139 buf = malloc(buf_size); 140 if (buf == NULL) { 141 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 142 "malloc: %s", pcap_strerror(errno)); 143 (void)close(fd6); 144 (void)close(fd4); 145 return (-1); 146 } 147 148 /* 149 * Get the entries. 150 */ 151 ifc.lifc_len = buf_size; 152 ifc.lifc_buf = buf; 153 ifc.lifc_family = AF_UNSPEC; 154 ifc.lifc_flags = 0; 155 memset(buf, 0, buf_size); 156 if (ioctl(fd4, SIOCGLIFCONF, (char *)&ifc) < 0) { 157 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 158 "SIOCGLIFCONF: %s", pcap_strerror(errno)); 159 (void)close(fd6); 160 (void)close(fd4); 161 free(buf); 162 return (-1); 163 } 164 165 /* 166 * Loop over the entries. 167 */ 168 ifrp = (struct lifreq *)buf; 169 ifend = (struct lifreq *)(buf + ifc.lifc_len); 170 171 for (; ifrp < ifend; ifrp++) { 172 /* 173 * IPv6 or not? 174 */ 175 if (((struct sockaddr *)&ifrp->lifr_addr)->sa_family == AF_INET6) 176 fd = fd6; 177 else 178 fd = fd4; 179 180 /* 181 * Skip entries that begin with "dummy". 182 * XXX - what are these? Is this Linux-specific? 183 * Are there platforms on which we shouldn't do this? 184 */ 185 if (strncmp(ifrp->lifr_name, "dummy", 5) == 0) 186 continue; 187 188 #ifdef HAVE_SOLARIS 189 /* 190 * Skip entries that have a ":" followed by a number 191 * at the end - those are Solaris virtual interfaces 192 * on which you can't capture. 193 */ 194 p = strchr(ifrp->lifr_name, ':'); 195 if (p != NULL) { 196 /* 197 * We have a ":"; is it followed by a number? 198 */ 199 while (isdigit((unsigned char)*p)) 200 p++; 201 if (*p == '\0') { 202 /* 203 * All digits after the ":" until the end. 204 */ 205 continue; 206 } 207 } 208 #endif 209 210 /* 211 * Get the flags for this interface, and skip it if it's 212 * not up. 213 */ 214 strncpy(ifrflags.lifr_name, ifrp->lifr_name, 215 sizeof(ifrflags.lifr_name)); 216 if (ioctl(fd, SIOCGLIFFLAGS, (char *)&ifrflags) < 0) { 217 if (errno == ENXIO) 218 continue; 219 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 220 "SIOCGLIFFLAGS: %.*s: %s", 221 (int)sizeof(ifrflags.lifr_name), 222 ifrflags.lifr_name, 223 pcap_strerror(errno)); 224 ret = -1; 225 break; 226 } 227 if (!(ifrflags.lifr_flags & IFF_UP)) 228 continue; 229 230 /* 231 * Get the netmask for this address on this interface. 232 */ 233 strncpy(ifrnetmask.lifr_name, ifrp->lifr_name, 234 sizeof(ifrnetmask.lifr_name)); 235 memcpy(&ifrnetmask.lifr_addr, &ifrp->lifr_addr, 236 sizeof(ifrnetmask.lifr_addr)); 237 if (ioctl(fd, SIOCGLIFNETMASK, (char *)&ifrnetmask) < 0) { 238 if (errno == EADDRNOTAVAIL) { 239 /* 240 * Not available. 241 */ 242 netmask = NULL; 243 } else { 244 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 245 "SIOCGLIFNETMASK: %.*s: %s", 246 (int)sizeof(ifrnetmask.lifr_name), 247 ifrnetmask.lifr_name, 248 pcap_strerror(errno)); 249 ret = -1; 250 break; 251 } 252 } else 253 netmask = (struct sockaddr *)&ifrnetmask.lifr_addr; 254 255 /* 256 * Get the broadcast address for this address on this 257 * interface (if any). 258 */ 259 if (ifrflags.lifr_flags & IFF_BROADCAST) { 260 strncpy(ifrbroadaddr.lifr_name, ifrp->lifr_name, 261 sizeof(ifrbroadaddr.lifr_name)); 262 memcpy(&ifrbroadaddr.lifr_addr, &ifrp->lifr_addr, 263 sizeof(ifrbroadaddr.lifr_addr)); 264 if (ioctl(fd, SIOCGLIFBRDADDR, 265 (char *)&ifrbroadaddr) < 0) { 266 if (errno == EADDRNOTAVAIL) { 267 /* 268 * Not available. 269 */ 270 broadaddr = NULL; 271 } else { 272 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 273 "SIOCGLIFBRDADDR: %.*s: %s", 274 (int)sizeof(ifrbroadaddr.lifr_name), 275 ifrbroadaddr.lifr_name, 276 pcap_strerror(errno)); 277 ret = -1; 278 break; 279 } 280 } else 281 broadaddr = (struct sockaddr *)&ifrbroadaddr.lifr_broadaddr; 282 } else { 283 /* 284 * Not a broadcast interface, so no broadcast 285 * address. 286 */ 287 broadaddr = NULL; 288 } 289 290 /* 291 * Get the destination address for this address on this 292 * interface (if any). 293 */ 294 if (ifrflags.lifr_flags & IFF_POINTOPOINT) { 295 strncpy(ifrdstaddr.lifr_name, ifrp->lifr_name, 296 sizeof(ifrdstaddr.lifr_name)); 297 memcpy(&ifrdstaddr.lifr_addr, &ifrp->lifr_addr, 298 sizeof(ifrdstaddr.lifr_addr)); 299 if (ioctl(fd, SIOCGLIFDSTADDR, 300 (char *)&ifrdstaddr) < 0) { 301 if (errno == EADDRNOTAVAIL) { 302 /* 303 * Not available. 304 */ 305 dstaddr = NULL; 306 } else { 307 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 308 "SIOCGLIFDSTADDR: %.*s: %s", 309 (int)sizeof(ifrdstaddr.lifr_name), 310 ifrdstaddr.lifr_name, 311 pcap_strerror(errno)); 312 ret = -1; 313 break; 314 } 315 } else 316 dstaddr = (struct sockaddr *)&ifrdstaddr.lifr_dstaddr; 317 } else 318 dstaddr = NULL; 319 320 #ifdef HAVE_SOLARIS 321 /* 322 * If this entry has a colon followed by a number at 323 * the end, it's a logical interface. Those are just 324 * the way you assign multiple IP addresses to a real 325 * interface, so an entry for a logical interface should 326 * be treated like the entry for the real interface; 327 * we do that by stripping off the ":" and the number. 328 */ 329 p = strchr(ifrp->lifr_name, ':'); 330 if (p != NULL) { 331 /* 332 * We have a ":"; is it followed by a number? 333 */ 334 q = p + 1; 335 while (isdigit((unsigned char)*q)) 336 q++; 337 if (*q == '\0') { 338 /* 339 * All digits after the ":" until the end. 340 * Strip off the ":" and everything after 341 * it. 342 */ 343 *p = '\0'; 344 } 345 } 346 #endif 347 348 /* 349 * Add information for this address to the list. 350 */ 351 if (add_addr_to_iflist(&devlist, ifrp->lifr_name, 352 ifrflags.lifr_flags, (struct sockaddr *)&ifrp->lifr_addr, 353 sizeof (struct sockaddr_storage), 354 netmask, sizeof (struct sockaddr_storage), 355 broadaddr, sizeof (struct sockaddr_storage), 356 dstaddr, sizeof (struct sockaddr_storage), errbuf) < 0) { 357 ret = -1; 358 break; 359 } 360 } 361 free(buf); 362 (void)close(fd6); 363 (void)close(fd4); 364 365 if (ret == -1) { 366 /* 367 * We had an error; free the list we've been constructing. 368 */ 369 if (devlist != NULL) { 370 pcap_freealldevs(devlist); 371 devlist = NULL; 372 } 373 } 374 375 *alldevsp = devlist; 376 return (ret); 377 } 378