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