1*99d1c811Sop /* $OpenBSD: inet.c,v 1.28 2024/08/28 11:41:42 op Exp $ */ 2df930be7Sderaadt 3df930be7Sderaadt /* 401efc7efSderaadt * Copyright (c) 1994, 1995, 1996, 1997, 1998 5df930be7Sderaadt * The Regents of the University of California. All rights reserved. 6df930be7Sderaadt * 7df930be7Sderaadt * Redistribution and use in source and binary forms, with or without 8df930be7Sderaadt * modification, are permitted provided that the following conditions 9df930be7Sderaadt * are met: 10df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright 11df930be7Sderaadt * notice, this list of conditions and the following disclaimer. 12df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 13df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the 14df930be7Sderaadt * documentation and/or other materials provided with the distribution. 15df930be7Sderaadt * 3. All advertising materials mentioning features or use of this software 16df930be7Sderaadt * must display the following acknowledgement: 17df930be7Sderaadt * This product includes software developed by the Computer Systems 18df930be7Sderaadt * Engineering Group at Lawrence Berkeley Laboratory. 19df930be7Sderaadt * 4. Neither the name of the University nor of the Laboratory may be used 20df930be7Sderaadt * to endorse or promote products derived from this software without 21df930be7Sderaadt * specific prior written permission. 22df930be7Sderaadt * 23df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33df930be7Sderaadt * SUCH DAMAGE. 34df930be7Sderaadt */ 35df930be7Sderaadt 36df930be7Sderaadt 37df930be7Sderaadt #include <sys/file.h> 38df930be7Sderaadt #include <sys/ioctl.h> 39df930be7Sderaadt #include <sys/socket.h> 409b113833Smickey #ifdef HAVE_SYS_SOCKIO_H 41df930be7Sderaadt #include <sys/sockio.h> 42df930be7Sderaadt #endif 4301efc7efSderaadt #include <sys/time.h> /* concession to AIX */ 44df930be7Sderaadt 45df930be7Sderaadt #include <net/if.h> 46df930be7Sderaadt #include <netinet/in.h> 47df930be7Sderaadt 48df930be7Sderaadt #include <ctype.h> 49df930be7Sderaadt #include <errno.h> 50*99d1c811Sop #include <limits.h> 51df930be7Sderaadt #include <stdio.h> 52df930be7Sderaadt #include <stdlib.h> 53df930be7Sderaadt #include <string.h> 54df930be7Sderaadt #include <unistd.h> 55b85261abSitojun #ifdef HAVE_IFADDRS_H 56b85261abSitojun #include <ifaddrs.h> 57b85261abSitojun #endif 5801efc7efSderaadt 5901efc7efSderaadt #include "pcap-int.h" 60df930be7Sderaadt 619b113833Smickey #ifdef HAVE_OS_PROTO_H 629b113833Smickey #include "os-proto.h" 639b113833Smickey #endif 649b113833Smickey 65a878b819Sdjm /* 66a878b819Sdjm * Free a list of interfaces. 67a878b819Sdjm */ 68a878b819Sdjm void 69a878b819Sdjm pcap_freealldevs(pcap_if_t *alldevs) 70a878b819Sdjm { 71a878b819Sdjm pcap_if_t *curdev, *nextdev; 72a878b819Sdjm pcap_addr_t *curaddr, *nextaddr; 73a878b819Sdjm 74a878b819Sdjm for (curdev = alldevs; curdev != NULL; curdev = nextdev) { 75a878b819Sdjm nextdev = curdev->next; 76a878b819Sdjm 77a878b819Sdjm /* 78a878b819Sdjm * Free all addresses. 79a878b819Sdjm */ 80a878b819Sdjm for (curaddr = curdev->addresses; curaddr != NULL; 81a878b819Sdjm curaddr = nextaddr) { 82a878b819Sdjm nextaddr = curaddr->next; 83a878b819Sdjm free(curaddr->addr); 84a878b819Sdjm free(curaddr->netmask); 85a878b819Sdjm free(curaddr->broadaddr); 86a878b819Sdjm free(curaddr->dstaddr); 87a878b819Sdjm free(curaddr); 88a878b819Sdjm } 89a878b819Sdjm 90a878b819Sdjm /* 91a878b819Sdjm * Free the name string. 92a878b819Sdjm */ 93a878b819Sdjm free(curdev->name); 94a878b819Sdjm 95a878b819Sdjm /* 96a878b819Sdjm * Free the description string, if any. 97a878b819Sdjm */ 98a878b819Sdjm free(curdev->description); 99a878b819Sdjm 100a878b819Sdjm /* 101a878b819Sdjm * Free the interface. 102a878b819Sdjm */ 103a878b819Sdjm free(curdev); 104a878b819Sdjm } 105a878b819Sdjm } 106df930be7Sderaadt 107df930be7Sderaadt /* 108df930be7Sderaadt * Return the name of a network interface attached to the system, or NULL 109df930be7Sderaadt * if none can be found. The interface must be configured up; the 110df930be7Sderaadt * lowest unit number is preferred; loopback is ignored. 111df930be7Sderaadt */ 112df930be7Sderaadt char * 11319fef815Sderaadt pcap_lookupdev(char *errbuf) 114df930be7Sderaadt { 115b85261abSitojun #ifdef HAVE_IFADDRS_H 116b85261abSitojun struct ifaddrs *ifap, *ifa, *mp; 117b85261abSitojun int n, minunit; 118b85261abSitojun char *cp; 119*99d1c811Sop const char *errstr; 120b85261abSitojun static char device[IF_NAMESIZE + 1]; 121b85261abSitojun 122b85261abSitojun if (getifaddrs(&ifap) != 0) { 123b85261abSitojun (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 124b85261abSitojun "getifaddrs: %s", pcap_strerror(errno)); 125b85261abSitojun return NULL; 126b85261abSitojun } 127b85261abSitojun 128b85261abSitojun mp = NULL; 129b85261abSitojun minunit = 666; 130b85261abSitojun for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 131b85261abSitojun if ((ifa->ifa_flags & IFF_UP) == 0) 132b85261abSitojun continue; 133a878b819Sdjm if (ISLOOPBACK(ifa->ifa_name, ifa->ifa_flags)) 134b85261abSitojun continue; 135404d8ac4Smmcc for (cp = ifa->ifa_name; !isdigit((unsigned char)*cp); ++cp) 136b85261abSitojun continue; 137*99d1c811Sop n = strtonum(cp, 0, INT_MAX, &errstr); 138*99d1c811Sop if (errstr != NULL) 139*99d1c811Sop continue; 140b85261abSitojun if (n < minunit) { 141b85261abSitojun minunit = n; 142b85261abSitojun mp = ifa; 143b85261abSitojun } 144b85261abSitojun } 145b85261abSitojun if (mp == NULL) { 146f9ba639dSjfb (void)strlcpy(errbuf, "no suitable device found", 147b85261abSitojun PCAP_ERRBUF_SIZE); 148b85261abSitojun freeifaddrs(ifap); 149b85261abSitojun return (NULL); 150b85261abSitojun } 151b85261abSitojun 152f9ba639dSjfb (void)strlcpy(device, mp->ifa_name, sizeof(device)); 153b85261abSitojun freeifaddrs(ifap); 154b85261abSitojun return (device); 155b85261abSitojun #else 156d0438536Smmcc int fd, minunit, n; 157d0438536Smmcc char *cp; 158*99d1c811Sop const char *errstr; 159d0438536Smmcc struct ifreq *ifrp, *ifend, *ifnext, *mp; 160df930be7Sderaadt struct ifconf ifc; 161a9b0695fSjakob struct ifreq ibuf[16], ifr; 162df930be7Sderaadt static char device[sizeof(ifrp->ifr_name) + 1]; 163df930be7Sderaadt 164df930be7Sderaadt fd = socket(AF_INET, SOCK_DGRAM, 0); 165df69c215Sderaadt if (fd == -1) { 16613c7aa11Sderaadt (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "socket: %s", 16713c7aa11Sderaadt pcap_strerror(errno)); 168df930be7Sderaadt return (NULL); 169df930be7Sderaadt } 170a9b0695fSjakob ifc.ifc_len = sizeof ibuf; 171a9b0695fSjakob ifc.ifc_buf = (caddr_t)ibuf; 172665d6cf7Sderaadt 173a9b0695fSjakob memset((char *)ibuf, 0, sizeof(ibuf)); 174df69c215Sderaadt if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) == -1 || 175a9b0695fSjakob ifc.ifc_len < sizeof(struct ifreq)) { 176a9b0695fSjakob (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFCONF: %s", 177a9b0695fSjakob pcap_strerror(errno)); 178a9b0695fSjakob (void)close(fd); 179a9b0695fSjakob return (NULL); 180a9b0695fSjakob } 181a9b0695fSjakob ifrp = ibuf; 182df930be7Sderaadt ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len); 183df930be7Sderaadt 184df930be7Sderaadt mp = NULL; 185df930be7Sderaadt minunit = 666; 186df930be7Sderaadt for (; ifrp < ifend; ifrp = ifnext) { 187a9b0695fSjakob #ifdef HAVE_SOCKADDR_SA_LEN 188df930be7Sderaadt n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name); 189df930be7Sderaadt if (n < sizeof(*ifrp)) 190df930be7Sderaadt ifnext = ifrp + 1; 191df930be7Sderaadt else 192df930be7Sderaadt ifnext = (struct ifreq *)((char *)ifrp + n); 193df930be7Sderaadt if (ifrp->ifr_addr.sa_family != AF_INET) 194df930be7Sderaadt continue; 195df930be7Sderaadt #else 196df930be7Sderaadt ifnext = ifrp + 1; 197df930be7Sderaadt #endif 198df930be7Sderaadt /* 199df930be7Sderaadt * Need a template to preserve address info that is 200df930be7Sderaadt * used below to locate the next entry. (Otherwise, 201df930be7Sderaadt * SIOCGIFFLAGS stomps over it because the requests 202df930be7Sderaadt * are returned in a union.) 203df930be7Sderaadt */ 204f9ba639dSjfb (void)strlcpy(ifr.ifr_name, ifrp->ifr_name, 205f9ba639dSjfb sizeof(ifr.ifr_name)); 206df69c215Sderaadt if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) == -1) { 20701efc7efSderaadt if (errno == ENXIO) 20801efc7efSderaadt continue; 20913c7aa11Sderaadt (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 21001efc7efSderaadt "SIOCGIFFLAGS: %.*s: %s", 21101efc7efSderaadt (int)sizeof(ifr.ifr_name), ifr.ifr_name, 21201efc7efSderaadt pcap_strerror(errno)); 213df930be7Sderaadt (void)close(fd); 214df930be7Sderaadt return (NULL); 215df930be7Sderaadt } 216df930be7Sderaadt 217df930be7Sderaadt /* Must be up and not the loopback */ 218a878b819Sdjm if ((ifr.ifr_flags & IFF_UP) == 0 || 21922f31d87Skrw ISLOOPBACK(ifr.ifr_name, ifr.ifr_flags)) 220df930be7Sderaadt continue; 221df930be7Sderaadt 222404d8ac4Smmcc for (cp = ifrp->ifr_name; !isdigit((unsigned char)*cp); ++cp) 223df930be7Sderaadt continue; 224*99d1c811Sop n = strtonum(cp, 0, INT_MAX, &errstr); 225*99d1c811Sop if (errstr != NULL) 226*99d1c811Sop continue; 227df930be7Sderaadt if (n < minunit) { 228df930be7Sderaadt minunit = n; 229df930be7Sderaadt mp = ifrp; 230df930be7Sderaadt } 231df930be7Sderaadt } 232df930be7Sderaadt (void)close(fd); 233df930be7Sderaadt if (mp == NULL) { 23401efc7efSderaadt (void)strlcpy(errbuf, "no suitable device found", 23501efc7efSderaadt PCAP_ERRBUF_SIZE); 236df930be7Sderaadt return (NULL); 237df930be7Sderaadt } 238df930be7Sderaadt 239f9ba639dSjfb (void)strlcpy(device, mp->ifr_name, sizeof(device)); 240df930be7Sderaadt return (device); 241b85261abSitojun #endif 242df930be7Sderaadt } 243df930be7Sderaadt 244df930be7Sderaadt int 245c1bf1209Sdjm pcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp, 246c1bf1209Sdjm char *errbuf) 247df930be7Sderaadt { 248c1bf1209Sdjm int fd; 249c1bf1209Sdjm struct sockaddr_in *sin; 250df930be7Sderaadt struct ifreq ifr; 251df930be7Sderaadt 252df930be7Sderaadt fd = socket(AF_INET, SOCK_DGRAM, 0); 253df69c215Sderaadt if (fd == -1) { 25413c7aa11Sderaadt (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "socket: %s", 25513c7aa11Sderaadt pcap_strerror(errno)); 256df930be7Sderaadt return (-1); 257df930be7Sderaadt } 2589b113833Smickey memset(&ifr, 0, sizeof(ifr)); 2599b113833Smickey #ifdef linux 2609b113833Smickey /* XXX Work around Linux kernel bug */ 2619b113833Smickey ifr.ifr_addr.sa_family = AF_INET; 2629b113833Smickey #endif 263f9ba639dSjfb (void)strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); 264df69c215Sderaadt if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) == -1) { 265a9b0695fSjakob if (errno == EADDRNOTAVAIL) { 266a9b0695fSjakob (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 267a9b0695fSjakob "%s: no IPv4 address assigned", device); 268a9b0695fSjakob } else { 269a9b0695fSjakob (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 270a9b0695fSjakob "SIOCGIFADDR: %s: %s", 271df930be7Sderaadt device, pcap_strerror(errno)); 272a9b0695fSjakob } 273df930be7Sderaadt (void)close(fd); 274df930be7Sderaadt return (-1); 275df930be7Sderaadt } 276df930be7Sderaadt sin = (struct sockaddr_in *)&ifr.ifr_addr; 277df930be7Sderaadt *netp = sin->sin_addr.s_addr; 278df69c215Sderaadt if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) == -1) { 279a9b0695fSjakob (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 280a9b0695fSjakob "SIOCGIFNETMASK: %s: %s", device, pcap_strerror(errno)); 281df930be7Sderaadt (void)close(fd); 282df930be7Sderaadt return (-1); 283df930be7Sderaadt } 284df930be7Sderaadt (void)close(fd); 285df930be7Sderaadt *maskp = sin->sin_addr.s_addr; 286df930be7Sderaadt if (*maskp == 0) { 287df930be7Sderaadt if (IN_CLASSA(*netp)) 288df930be7Sderaadt *maskp = IN_CLASSA_NET; 289df930be7Sderaadt else if (IN_CLASSB(*netp)) 290df930be7Sderaadt *maskp = IN_CLASSB_NET; 291df930be7Sderaadt else if (IN_CLASSC(*netp)) 292df930be7Sderaadt *maskp = IN_CLASSC_NET; 293df930be7Sderaadt else { 29413c7aa11Sderaadt (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 29513c7aa11Sderaadt "inet class for 0x%x unknown", *netp); 296df930be7Sderaadt return (-1); 297df930be7Sderaadt } 298df930be7Sderaadt } 299df930be7Sderaadt *netp &= *maskp; 300df930be7Sderaadt return (0); 301df930be7Sderaadt } 302