1 /* $NetBSD: fad-glifc.c,v 1.4 2018/09/03 15:26:43 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.4 2018/09/03 15:26:43 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_list_t *devlistp, char *errbuf, 84 int (*check_usable)(const char *), get_if_flags_func get_flags_func) 85 { 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 pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, 106 errno, "socket: AF_INET"); 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 pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, 116 errno, "socket: AF_INET6"); 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 pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, 129 errno, "SIOCGLIFNUM"); 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 pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, 142 errno, "malloc"); 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 pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, 158 errno, "SIOCGLIFCONF"); 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 * Skip entries that begin with "dummy". 174 * XXX - what are these? Is this Linux-specific? 175 * Are there platforms on which we shouldn't do this? 176 */ 177 if (strncmp(ifrp->lifr_name, "dummy", 5) == 0) 178 continue; 179 180 /* 181 * Can we capture on this device? 182 */ 183 if (!(*check_usable)(ifrp->lifr_name)) { 184 /* 185 * No. 186 */ 187 continue; 188 } 189 190 /* 191 * IPv6 or not? 192 */ 193 if (((struct sockaddr *)&ifrp->lifr_addr)->sa_family == AF_INET6) 194 fd = fd6; 195 else 196 fd = fd4; 197 198 /* 199 * Get the flags for this interface. 200 */ 201 strncpy(ifrflags.lifr_name, ifrp->lifr_name, 202 sizeof(ifrflags.lifr_name)); 203 if (ioctl(fd, SIOCGLIFFLAGS, (char *)&ifrflags) < 0) { 204 if (errno == ENXIO) 205 continue; 206 pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, 207 errno, "SIOCGLIFFLAGS: %.*s", 208 (int)sizeof(ifrflags.lifr_name), 209 ifrflags.lifr_name); 210 ret = -1; 211 break; 212 } 213 214 /* 215 * Get the netmask for this address on this interface. 216 */ 217 strncpy(ifrnetmask.lifr_name, ifrp->lifr_name, 218 sizeof(ifrnetmask.lifr_name)); 219 memcpy(&ifrnetmask.lifr_addr, &ifrp->lifr_addr, 220 sizeof(ifrnetmask.lifr_addr)); 221 if (ioctl(fd, SIOCGLIFNETMASK, (char *)&ifrnetmask) < 0) { 222 if (errno == EADDRNOTAVAIL) { 223 /* 224 * Not available. 225 */ 226 netmask = NULL; 227 } else { 228 pcap_fmt_errmsg_for_errno(errbuf, 229 PCAP_ERRBUF_SIZE, errno, 230 "SIOCGLIFNETMASK: %.*s", 231 (int)sizeof(ifrnetmask.lifr_name), 232 ifrnetmask.lifr_name); 233 ret = -1; 234 break; 235 } 236 } else 237 netmask = (struct sockaddr *)&ifrnetmask.lifr_addr; 238 239 /* 240 * Get the broadcast address for this address on this 241 * interface (if any). 242 */ 243 if (ifrflags.lifr_flags & IFF_BROADCAST) { 244 strncpy(ifrbroadaddr.lifr_name, ifrp->lifr_name, 245 sizeof(ifrbroadaddr.lifr_name)); 246 memcpy(&ifrbroadaddr.lifr_addr, &ifrp->lifr_addr, 247 sizeof(ifrbroadaddr.lifr_addr)); 248 if (ioctl(fd, SIOCGLIFBRDADDR, 249 (char *)&ifrbroadaddr) < 0) { 250 if (errno == EADDRNOTAVAIL) { 251 /* 252 * Not available. 253 */ 254 broadaddr = NULL; 255 } else { 256 pcap_fmt_errmsg_for_errno(errbuf, 257 PCAP_ERRBUF_SIZE, errno, 258 "SIOCGLIFBRDADDR: %.*s", 259 (int)sizeof(ifrbroadaddr.lifr_name), 260 ifrbroadaddr.lifr_name); 261 ret = -1; 262 break; 263 } 264 } else 265 broadaddr = (struct sockaddr *)&ifrbroadaddr.lifr_broadaddr; 266 } else { 267 /* 268 * Not a broadcast interface, so no broadcast 269 * address. 270 */ 271 broadaddr = NULL; 272 } 273 274 /* 275 * Get the destination address for this address on this 276 * interface (if any). 277 */ 278 if (ifrflags.lifr_flags & IFF_POINTOPOINT) { 279 strncpy(ifrdstaddr.lifr_name, ifrp->lifr_name, 280 sizeof(ifrdstaddr.lifr_name)); 281 memcpy(&ifrdstaddr.lifr_addr, &ifrp->lifr_addr, 282 sizeof(ifrdstaddr.lifr_addr)); 283 if (ioctl(fd, SIOCGLIFDSTADDR, 284 (char *)&ifrdstaddr) < 0) { 285 if (errno == EADDRNOTAVAIL) { 286 /* 287 * Not available. 288 */ 289 dstaddr = NULL; 290 } else { 291 pcap_fmt_errmsg_for_errno(errbuf, 292 PCAP_ERRBUF_SIZE, errno, 293 "SIOCGLIFDSTADDR: %.*s", 294 (int)sizeof(ifrdstaddr.lifr_name), 295 ifrdstaddr.lifr_name); 296 ret = -1; 297 break; 298 } 299 } else 300 dstaddr = (struct sockaddr *)&ifrdstaddr.lifr_dstaddr; 301 } else 302 dstaddr = NULL; 303 304 #ifdef HAVE_SOLARIS 305 /* 306 * If this entry has a colon followed by a number at 307 * the end, it's a logical interface. Those are just 308 * the way you assign multiple IP addresses to a real 309 * interface, so an entry for a logical interface should 310 * be treated like the entry for the real interface; 311 * we do that by stripping off the ":" and the number. 312 */ 313 p = strchr(ifrp->lifr_name, ':'); 314 if (p != NULL) { 315 /* 316 * We have a ":"; is it followed by a number? 317 */ 318 q = p + 1; 319 while (isdigit((unsigned char)*q)) 320 q++; 321 if (*q == '\0') { 322 /* 323 * All digits after the ":" until the end. 324 * Strip off the ":" and everything after 325 * it. 326 */ 327 *p = '\0'; 328 } 329 } 330 #endif 331 332 /* 333 * Add information for this address to the list. 334 */ 335 if (add_addr_to_if(devlistp, ifrp->lifr_name, 336 ifrflags.lifr_flags, get_flags_func, 337 (struct sockaddr *)&ifrp->lifr_addr, 338 sizeof (struct sockaddr_storage), 339 netmask, sizeof (struct sockaddr_storage), 340 broadaddr, sizeof (struct sockaddr_storage), 341 dstaddr, sizeof (struct sockaddr_storage), errbuf) < 0) { 342 ret = -1; 343 break; 344 } 345 } 346 free(buf); 347 (void)close(fd6); 348 (void)close(fd4); 349 350 return (ret); 351 } 352