1 /* $NetBSD: fad-glifc.c,v 1.2 2014/11/19 19:33:30 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 #include <sys/cdefs.h> 38 __RCSID("$NetBSD: fad-glifc.c,v 1.2 2014/11/19 19:33:30 christos Exp $"); 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. 212 */ 213 strncpy(ifrflags.lifr_name, ifrp->lifr_name, 214 sizeof(ifrflags.lifr_name)); 215 if (ioctl(fd, SIOCGLIFFLAGS, (char *)&ifrflags) < 0) { 216 if (errno == ENXIO) 217 continue; 218 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 219 "SIOCGLIFFLAGS: %.*s: %s", 220 (int)sizeof(ifrflags.lifr_name), 221 ifrflags.lifr_name, 222 pcap_strerror(errno)); 223 ret = -1; 224 break; 225 } 226 227 /* 228 * Get the netmask for this address on this interface. 229 */ 230 strncpy(ifrnetmask.lifr_name, ifrp->lifr_name, 231 sizeof(ifrnetmask.lifr_name)); 232 memcpy(&ifrnetmask.lifr_addr, &ifrp->lifr_addr, 233 sizeof(ifrnetmask.lifr_addr)); 234 if (ioctl(fd, SIOCGLIFNETMASK, (char *)&ifrnetmask) < 0) { 235 if (errno == EADDRNOTAVAIL) { 236 /* 237 * Not available. 238 */ 239 netmask = NULL; 240 } else { 241 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 242 "SIOCGLIFNETMASK: %.*s: %s", 243 (int)sizeof(ifrnetmask.lifr_name), 244 ifrnetmask.lifr_name, 245 pcap_strerror(errno)); 246 ret = -1; 247 break; 248 } 249 } else 250 netmask = (struct sockaddr *)&ifrnetmask.lifr_addr; 251 252 /* 253 * Get the broadcast address for this address on this 254 * interface (if any). 255 */ 256 if (ifrflags.lifr_flags & IFF_BROADCAST) { 257 strncpy(ifrbroadaddr.lifr_name, ifrp->lifr_name, 258 sizeof(ifrbroadaddr.lifr_name)); 259 memcpy(&ifrbroadaddr.lifr_addr, &ifrp->lifr_addr, 260 sizeof(ifrbroadaddr.lifr_addr)); 261 if (ioctl(fd, SIOCGLIFBRDADDR, 262 (char *)&ifrbroadaddr) < 0) { 263 if (errno == EADDRNOTAVAIL) { 264 /* 265 * Not available. 266 */ 267 broadaddr = NULL; 268 } else { 269 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 270 "SIOCGLIFBRDADDR: %.*s: %s", 271 (int)sizeof(ifrbroadaddr.lifr_name), 272 ifrbroadaddr.lifr_name, 273 pcap_strerror(errno)); 274 ret = -1; 275 break; 276 } 277 } else 278 broadaddr = (struct sockaddr *)&ifrbroadaddr.lifr_broadaddr; 279 } else { 280 /* 281 * Not a broadcast interface, so no broadcast 282 * address. 283 */ 284 broadaddr = NULL; 285 } 286 287 /* 288 * Get the destination address for this address on this 289 * interface (if any). 290 */ 291 if (ifrflags.lifr_flags & IFF_POINTOPOINT) { 292 strncpy(ifrdstaddr.lifr_name, ifrp->lifr_name, 293 sizeof(ifrdstaddr.lifr_name)); 294 memcpy(&ifrdstaddr.lifr_addr, &ifrp->lifr_addr, 295 sizeof(ifrdstaddr.lifr_addr)); 296 if (ioctl(fd, SIOCGLIFDSTADDR, 297 (char *)&ifrdstaddr) < 0) { 298 if (errno == EADDRNOTAVAIL) { 299 /* 300 * Not available. 301 */ 302 dstaddr = NULL; 303 } else { 304 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 305 "SIOCGLIFDSTADDR: %.*s: %s", 306 (int)sizeof(ifrdstaddr.lifr_name), 307 ifrdstaddr.lifr_name, 308 pcap_strerror(errno)); 309 ret = -1; 310 break; 311 } 312 } else 313 dstaddr = (struct sockaddr *)&ifrdstaddr.lifr_dstaddr; 314 } else 315 dstaddr = NULL; 316 317 #ifdef HAVE_SOLARIS 318 /* 319 * If this entry has a colon followed by a number at 320 * the end, it's a logical interface. Those are just 321 * the way you assign multiple IP addresses to a real 322 * interface, so an entry for a logical interface should 323 * be treated like the entry for the real interface; 324 * we do that by stripping off the ":" and the number. 325 */ 326 p = strchr(ifrp->lifr_name, ':'); 327 if (p != NULL) { 328 /* 329 * We have a ":"; is it followed by a number? 330 */ 331 q = p + 1; 332 while (isdigit((unsigned char)*q)) 333 q++; 334 if (*q == '\0') { 335 /* 336 * All digits after the ":" until the end. 337 * Strip off the ":" and everything after 338 * it. 339 */ 340 *p = '\0'; 341 } 342 } 343 #endif 344 345 /* 346 * Add information for this address to the list. 347 */ 348 if (add_addr_to_iflist(&devlist, ifrp->lifr_name, 349 ifrflags.lifr_flags, (struct sockaddr *)&ifrp->lifr_addr, 350 sizeof (struct sockaddr_storage), 351 netmask, sizeof (struct sockaddr_storage), 352 broadaddr, sizeof (struct sockaddr_storage), 353 dstaddr, sizeof (struct sockaddr_storage), errbuf) < 0) { 354 ret = -1; 355 break; 356 } 357 } 358 free(buf); 359 (void)close(fd6); 360 (void)close(fd4); 361 362 if (ret == -1) { 363 /* 364 * We had an error; free the list we've been constructing. 365 */ 366 if (devlist != NULL) { 367 pcap_freealldevs(devlist); 368 devlist = NULL; 369 } 370 } 371 372 *alldevsp = devlist; 373 return (ret); 374 } 375