inet.c revision 75107
1/* 2 * Copyright (c) 1994, 1995, 1996, 1997, 1998 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the Computer Systems 16 * Engineering Group at Lawrence Berkeley Laboratory. 17 * 4. Neither the name of the University nor of the Laboratory may be used 18 * to endorse or promote products derived from this software without 19 * specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35static const char rcsid[] = 36 "@(#) $Header: /tcpdump/master/libpcap/inet.c,v 1.36 2000/09/20 15:10:29 torsten Exp $ (LBL)"; 37#endif 38 39#ifdef HAVE_CONFIG_H 40#include "config.h" 41#endif 42 43#include <sys/param.h> 44#include <sys/file.h> 45#include <sys/ioctl.h> 46#include <sys/socket.h> 47#ifdef HAVE_SYS_SOCKIO_H 48#include <sys/sockio.h> 49#endif 50#include <sys/time.h> /* concession to AIX */ 51 52struct mbuf; 53struct rtentry; 54#include <net/if.h> 55#include <netinet/in.h> 56 57#include <ctype.h> 58#include <errno.h> 59#include <memory.h> 60#include <stdio.h> 61#include <stdlib.h> 62#include <string.h> 63#include <unistd.h> 64#ifdef HAVE_IFADDRS_H 65#include <ifaddrs.h> 66#endif 67 68#include "pcap-int.h" 69 70#ifdef HAVE_OS_PROTO_H 71#include "os-proto.h" 72#endif 73 74/* Not all systems have IFF_LOOPBACK */ 75#ifdef IFF_LOOPBACK 76#define ISLOOPBACK(p) ((p)->ifr_flags & IFF_LOOPBACK) 77#define ISLOOPBACK_IFA(p) ((p)->ifa_flags & IFF_LOOPBACK) 78#else 79#define ISLOOPBACK(p) ((p)->ifr_name[0] == 'l' && (p)->ifr_name[1] == 'o' && \ 80 (isdigit((p)->ifr_name[2]) || (p)->ifr_name[2] == '\0')) 81#define ISLOOPBACK_IFA(p) ((p)->ifa_name[0] == 'l' && (p)->ifa_name[1] == 'o' && \ 82 (isdigit((p)->ifa_name[2]) || (p)->ifa_name[2] == '\0')) 83#endif 84 85/* 86 * Return the name of a network interface attached to the system, or NULL 87 * if none can be found. The interface must be configured up; the 88 * lowest unit number is preferred; loopback is ignored. 89 */ 90char * 91pcap_lookupdev(errbuf) 92 register char *errbuf; 93{ 94#ifdef HAVE_IFADDRS_H 95 struct ifaddrs *ifap, *ifa, *mp; 96 int n, minunit; 97 char *cp; 98 static char device[IF_NAMESIZE + 1]; 99 100 if (getifaddrs(&ifap) != 0) { 101 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 102 "getifaddrs: %s", pcap_strerror(errno)); 103 return NULL; 104 } 105 106 mp = NULL; 107 minunit = 666; 108 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 109 const char *endcp; 110 111 if ((ifa->ifa_flags & IFF_UP) == 0 || ISLOOPBACK_IFA(ifa)) 112 continue; 113 114 endcp = ifa->ifa_name + strlen(ifa->ifa_name); 115 for (cp = ifa->ifa_name; cp < endcp && !isdigit(*cp); ++cp) 116 continue; 117 118 if (isdigit (*cp)) { 119 n = atoi(cp); 120 } else { 121 n = 0; 122 } 123 if (n < minunit) { 124 minunit = n; 125 mp = ifa; 126 } 127 } 128 if (mp == NULL) { 129 (void)strlcpy(errbuf, "no suitable device found", 130 PCAP_ERRBUF_SIZE); 131#ifdef HAVE_FREEIFADDRS 132 freeifaddrs(ifap); 133#else 134 free(ifap); 135#endif 136 return (NULL); 137 } 138 139 (void)strlcpy(device, mp->ifa_name, sizeof(device)); 140#ifdef HAVE_FREEIFADDRS 141 freeifaddrs(ifap); 142#else 143 free(ifap); 144#endif 145 return (device); 146#else 147 register int fd, minunit, n; 148 register char *cp; 149 register struct ifreq *ifrp, *ifend, *ifnext, *mp; 150 struct ifconf ifc; 151 char *buf; 152 struct ifreq ifr; 153 static char device[sizeof(ifrp->ifr_name) + 1]; 154 unsigned buf_size; 155 156 fd = socket(AF_INET, SOCK_DGRAM, 0); 157 if (fd < 0) { 158 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 159 "socket: %s", pcap_strerror(errno)); 160 return (NULL); 161 } 162 163 buf_size = 8192; 164 165 for (;;) { 166 buf = malloc (buf_size); 167 if (buf == NULL) { 168 close (fd); 169 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 170 "out of memory"); 171 return (NULL); 172 } 173 174 ifc.ifc_len = buf_size; 175 ifc.ifc_buf = buf; 176 memset (buf, 0, buf_size); 177 if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 178 && errno != EINVAL) { 179 free (buf); 180 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 181 "SIOCGIFCONF: %s", pcap_strerror(errno)); 182 (void)close(fd); 183 return (NULL); 184 } 185 if (ifc.ifc_len < buf_size) 186 break; 187 free (buf); 188 buf_size *= 2; 189 } 190 191 ifrp = (struct ifreq *)buf; 192 ifend = (struct ifreq *)(buf + ifc.ifc_len); 193 194 mp = NULL; 195 minunit = 666; 196 for (; ifrp < ifend; ifrp = ifnext) { 197 const char *endcp; 198 199#ifdef HAVE_SOCKADDR_SA_LEN 200 n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name); 201 if (n < sizeof(*ifrp)) 202 ifnext = ifrp + 1; 203 else 204 ifnext = (struct ifreq *)((char *)ifrp + n); 205 if (ifrp->ifr_addr.sa_family != AF_INET) 206 continue; 207#else 208 ifnext = ifrp + 1; 209#endif 210 /* 211 * Need a template to preserve address info that is 212 * used below to locate the next entry. (Otherwise, 213 * SIOCGIFFLAGS stomps over it because the requests 214 * are returned in a union.) 215 */ 216 strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name)); 217 if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) { 218 if (errno == ENXIO) 219 continue; 220 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 221 "SIOCGIFFLAGS: %.*s: %s", 222 (int)sizeof(ifr.ifr_name), ifr.ifr_name, 223 pcap_strerror(errno)); 224 (void)close(fd); 225 free (buf); 226 return (NULL); 227 } 228 229 /* Must be up and not the loopback */ 230 if ((ifr.ifr_flags & IFF_UP) == 0 || ISLOOPBACK(&ifr)) 231 continue; 232 233 endcp = ifrp->ifr_name + strlen(ifrp->ifr_name); 234 for (cp = ifrp->ifr_name; cp < endcp && !isdigit(*cp); ++cp) 235 continue; 236 237 if (isdigit (*cp)) { 238 n = atoi(cp); 239 } else { 240 n = 0; 241 } 242 if (n < minunit) { 243 minunit = n; 244 mp = ifrp; 245 } 246 } 247 (void)close(fd); 248 if (mp == NULL) { 249 (void)strlcpy(errbuf, "no suitable device found", 250 PCAP_ERRBUF_SIZE); 251 free(buf); 252 return (NULL); 253 } 254 255 (void)strlcpy(device, mp->ifr_name, sizeof(device)); 256 free(buf); 257 return (device); 258#endif 259} 260 261int 262pcap_lookupnet(device, netp, maskp, errbuf) 263 register char *device; 264 register bpf_u_int32 *netp, *maskp; 265 register char *errbuf; 266{ 267 register int fd; 268 register struct sockaddr_in *sin; 269 struct ifreq ifr; 270 271 /* 272 * The pseudo-device "any" listens on all interfaces and therefore 273 * has the network address and -mask "0.0.0.0" therefore catching 274 * all traffic. Using NULL for the interface is the same as "any". 275 */ 276 if (!device || strcmp(device, "any") == 0) { 277 *netp = *maskp = 0; 278 return 0; 279 } 280 281 fd = socket(AF_INET, SOCK_DGRAM, 0); 282 if (fd < 0) { 283 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "socket: %s", 284 pcap_strerror(errno)); 285 return (-1); 286 } 287 memset(&ifr, 0, sizeof(ifr)); 288#ifdef linux 289 /* XXX Work around Linux kernel bug */ 290 ifr.ifr_addr.sa_family = AF_INET; 291#endif 292 (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); 293 if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) { 294 if (errno == EADDRNOTAVAIL) { 295 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 296 "%s: no IPv4 address assigned", device); 297 } else { 298 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 299 "SIOCGIFADDR: %s: %s", 300 device, pcap_strerror(errno)); 301 } 302 (void)close(fd); 303 return (-1); 304 } 305 sin = (struct sockaddr_in *)&ifr.ifr_addr; 306 *netp = sin->sin_addr.s_addr; 307 if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) { 308 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 309 "SIOCGIFNETMASK: %s: %s", device, pcap_strerror(errno)); 310 (void)close(fd); 311 return (-1); 312 } 313 (void)close(fd); 314 *maskp = sin->sin_addr.s_addr; 315 if (*maskp == 0) { 316 if (IN_CLASSA(*netp)) 317 *maskp = IN_CLASSA_NET; 318 else if (IN_CLASSB(*netp)) 319 *maskp = IN_CLASSB_NET; 320 else if (IN_CLASSC(*netp)) 321 *maskp = IN_CLASSC_NET; 322 else { 323 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 324 "inet class for 0x%x unknown", *netp); 325 return (-1); 326 } 327 } 328 *netp &= *maskp; 329 return (0); 330} 331