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