1/* 2 * Copyright (c) 1996, 1998-2005, 2007-2010 3 * Todd C. Miller <Todd.Miller@courtesan.com> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * 17 * Sponsored in part by the Defense Advanced Research Projects 18 * Agency (DARPA) and Air Force Research Laboratory, Air Force 19 * Materiel Command, USAF, under agreement number F39502-99-1-0512. 20 */ 21 22/* 23 * Suppress a warning w/ gcc on Digital UN*X. 24 * The system headers should really do this.... 25 */ 26#if defined(__osf__) && !defined(__cplusplus) 27struct mbuf; 28struct rtentry; 29#endif 30 31#include <config.h> 32 33#include <sys/types.h> 34#include <sys/socket.h> 35#include <sys/param.h> 36#include <sys/time.h> 37#include <sys/ioctl.h> 38#if defined(HAVE_SYS_SOCKIO_H) && !defined(SIOCGIFCONF) 39# include <sys/sockio.h> 40#endif 41#include <stdio.h> 42#ifdef STDC_HEADERS 43# include <stdlib.h> 44# include <stddef.h> 45#else 46# ifdef HAVE_STDLIB_H 47# include <stdlib.h> 48# endif 49#endif /* STDC_HEADERS */ 50#ifdef HAVE_STRING_H 51# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS) 52# include <memory.h> 53# endif 54# include <string.h> 55#endif /* HAVE_STRING_H */ 56#ifdef HAVE_STRINGS_H 57# include <strings.h> 58#endif /* HAVE_STRINGS_H */ 59#ifdef HAVE_UNISTD_H 60# include <unistd.h> 61#endif /* HAVE_UNISTD_H */ 62#include <netdb.h> 63#include <errno.h> 64#ifdef _ISC 65# include <sys/stream.h> 66# include <sys/sioctl.h> 67# include <sys/stropts.h> 68# define STRSET(cmd, param, len) {strioctl.ic_cmd=(cmd);\ 69 strioctl.ic_dp=(param);\ 70 strioctl.ic_timout=0;\ 71 strioctl.ic_len=(len);} 72#endif /* _ISC */ 73#ifdef _MIPS 74# include <net/soioctl.h> 75#endif /* _MIPS */ 76#include <netinet/in.h> 77#include <arpa/inet.h> 78#include <net/if.h> 79#ifdef HAVE_GETIFADDRS 80# include <ifaddrs.h> 81#endif 82 83#include "sudo.h" 84#include "interfaces.h" 85 86/* Minix apparently lacks IFF_LOOPBACK */ 87#ifndef IFF_LOOPBACK 88# define IFF_LOOPBACK 0 89#endif 90 91#ifdef HAVE_GETIFADDRS 92 93/* 94 * Allocate and fill in the interfaces global variable with the 95 * machine's ip addresses and netmasks. 96 */ 97void 98load_interfaces() 99{ 100 struct ifaddrs *ifa, *ifaddrs; 101 struct sockaddr_in *sin; 102#ifdef HAVE_STRUCT_IN6_ADDR 103 struct sockaddr_in6 *sin6; 104#endif 105 int i; 106 107 if (getifaddrs(&ifaddrs)) 108 return; 109 110 /* Allocate space for the interfaces list. */ 111 for (ifa = ifaddrs; ifa != NULL; ifa = ifa -> ifa_next) { 112 /* Skip interfaces marked "down" and "loopback". */ 113 if (ifa->ifa_addr == NULL || !ISSET(ifa->ifa_flags, IFF_UP) || 114 ISSET(ifa->ifa_flags, IFF_LOOPBACK)) 115 continue; 116 117 switch(ifa->ifa_addr->sa_family) { 118 case AF_INET: 119#ifdef HAVE_STRUCT_IN6_ADDR 120 case AF_INET6: 121#endif 122 num_interfaces++; 123 break; 124 } 125 } 126 if (num_interfaces == 0) 127 return; 128 interfaces = 129 (struct interface *) emalloc2(num_interfaces, sizeof(struct interface)); 130 131 /* Store the ip addr / netmask pairs. */ 132 for (ifa = ifaddrs, i = 0; ifa != NULL; ifa = ifa -> ifa_next) { 133 /* Skip interfaces marked "down" and "loopback". */ 134 if (ifa->ifa_addr == NULL || !ISSET(ifa->ifa_flags, IFF_UP) || 135 ISSET(ifa->ifa_flags, IFF_LOOPBACK)) 136 continue; 137 138 switch(ifa->ifa_addr->sa_family) { 139 case AF_INET: 140 sin = (struct sockaddr_in *)ifa->ifa_addr; 141 if (sin == NULL) 142 continue; 143 memcpy(&interfaces[i].addr, &sin->sin_addr, 144 sizeof(struct in_addr)); 145 sin = (struct sockaddr_in *)ifa->ifa_netmask; 146 if (sin == NULL) 147 continue; 148 memcpy(&interfaces[i].netmask, &sin->sin_addr, 149 sizeof(struct in_addr)); 150 interfaces[i].family = AF_INET; 151 i++; 152 break; 153#ifdef HAVE_STRUCT_IN6_ADDR 154 case AF_INET6: 155 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 156 if (sin6 == NULL) 157 continue; 158 memcpy(&interfaces[i].addr, &sin6->sin6_addr, 159 sizeof(struct in6_addr)); 160 sin6 = (struct sockaddr_in6 *)ifa->ifa_netmask; 161 if (sin6 == NULL) 162 continue; 163 memcpy(&interfaces[i].netmask, &sin6->sin6_addr, 164 sizeof(struct in6_addr)); 165 interfaces[i].family = AF_INET6; 166 i++; 167 break; 168#endif /* HAVE_STRUCT_IN6_ADDR */ 169 } 170 } 171#ifdef HAVE_FREEIFADDRS 172 freeifaddrs(ifaddrs); 173#else 174 efree(ifaddrs); 175#endif 176} 177 178#elif defined(SIOCGIFCONF) && !defined(STUB_LOAD_INTERFACES) 179 180/* 181 * Allocate and fill in the interfaces global variable with the 182 * machine's ip addresses and netmasks. 183 */ 184void 185load_interfaces() 186{ 187 struct ifconf *ifconf; 188 struct ifreq *ifr, ifr_tmp; 189 struct sockaddr_in *sin; 190 int sock, n, i; 191 size_t len = sizeof(struct ifconf) + BUFSIZ; 192 char *previfname = "", *ifconf_buf = NULL; 193#ifdef _ISC 194 struct strioctl strioctl; 195#endif /* _ISC */ 196 197 sock = socket(AF_INET, SOCK_DGRAM, 0); 198 if (sock < 0) 199 error(1, "cannot open socket"); 200 201 /* 202 * Get interface configuration or return (leaving num_interfaces == 0) 203 */ 204 for (;;) { 205 ifconf_buf = erealloc(ifconf_buf, len); 206 ifconf = (struct ifconf *) ifconf_buf; 207 ifconf->ifc_len = len - sizeof(struct ifconf); 208 ifconf->ifc_buf = (caddr_t) (ifconf_buf + sizeof(struct ifconf)); 209 210#ifdef _ISC 211 STRSET(SIOCGIFCONF, (caddr_t) ifconf, len); 212 if (ioctl(sock, I_STR, (caddr_t) &strioctl) < 0) { 213#else 214 /* Note that some kernels return EINVAL if the buffer is too small */ 215 if (ioctl(sock, SIOCGIFCONF, (caddr_t) ifconf) < 0 && errno != EINVAL) { 216#endif /* _ISC */ 217 efree(ifconf_buf); 218 (void) close(sock); 219 return; 220 } 221 222 /* Break out of loop if we have a big enough buffer. */ 223 if (ifconf->ifc_len + sizeof(struct ifreq) < len) 224 break; 225 len += BUFSIZ; 226 } 227 228 /* Allocate space for the maximum number of interfaces that could exist. */ 229 if ((n = ifconf->ifc_len / sizeof(struct ifreq)) == 0) 230 return; 231 interfaces = (struct interface *) emalloc2(n, sizeof(struct interface)); 232 233 /* For each interface, store the ip address and netmask. */ 234 for (i = 0; i < ifconf->ifc_len; ) { 235 /* Get a pointer to the current interface. */ 236 ifr = (struct ifreq *) &ifconf->ifc_buf[i]; 237 238 /* Set i to the subscript of the next interface. */ 239 i += sizeof(struct ifreq); 240#ifdef HAVE_SA_LEN 241 if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr)) 242 i += ifr->ifr_addr.sa_len - sizeof(struct sockaddr); 243#endif /* HAVE_SA_LEN */ 244 245 /* Skip duplicates and interfaces with NULL addresses. */ 246 sin = (struct sockaddr_in *) &ifr->ifr_addr; 247 if (sin->sin_addr.s_addr == 0 || 248 strncmp(previfname, ifr->ifr_name, sizeof(ifr->ifr_name) - 1) == 0) 249 continue; 250 251 if (ifr->ifr_addr.sa_family != AF_INET) 252 continue; 253 254#ifdef SIOCGIFFLAGS 255 zero_bytes(&ifr_tmp, sizeof(ifr_tmp)); 256 strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1); 257 if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr_tmp) < 0) 258#endif 259 ifr_tmp = *ifr; 260 261 /* Skip interfaces marked "down" and "loopback". */ 262 if (!ISSET(ifr_tmp.ifr_flags, IFF_UP) || 263 ISSET(ifr_tmp.ifr_flags, IFF_LOOPBACK)) 264 continue; 265 266 sin = (struct sockaddr_in *) &ifr->ifr_addr; 267 interfaces[num_interfaces].addr.ip4.s_addr = sin->sin_addr.s_addr; 268 269 /* Stash the name of the interface we saved. */ 270 previfname = ifr->ifr_name; 271 272 /* Get the netmask. */ 273 zero_bytes(&ifr_tmp, sizeof(ifr_tmp)); 274 strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1); 275#ifdef SIOCGIFNETMASK 276#ifdef _ISC 277 STRSET(SIOCGIFNETMASK, (caddr_t) &ifr_tmp, sizeof(ifr_tmp)); 278 if (ioctl(sock, I_STR, (caddr_t) &strioctl) == 0) { 279#else 280 if (ioctl(sock, SIOCGIFNETMASK, (caddr_t) &ifr_tmp) == 0) { 281#endif /* _ISC */ 282 sin = (struct sockaddr_in *) &ifr_tmp.ifr_addr; 283 284 interfaces[num_interfaces].netmask.ip4.s_addr = sin->sin_addr.s_addr; 285 } else { 286#else 287 { 288#endif /* SIOCGIFNETMASK */ 289 if (IN_CLASSC(interfaces[num_interfaces].addr.ip4.s_addr)) 290 interfaces[num_interfaces].netmask.ip4.s_addr = htonl(IN_CLASSC_NET); 291 else if (IN_CLASSB(interfaces[num_interfaces].addr.ip4.s_addr)) 292 interfaces[num_interfaces].netmask.ip4.s_addr = htonl(IN_CLASSB_NET); 293 else 294 interfaces[num_interfaces].netmask.ip4.s_addr = htonl(IN_CLASSA_NET); 295 } 296 297 /* Only now can we be sure it was a good/interesting interface. */ 298 interfaces[num_interfaces].family = AF_INET; 299 num_interfaces++; 300 } 301 302 /* If the expected size < real size, realloc the array. */ 303 if (n != num_interfaces) { 304 if (num_interfaces != 0) 305 interfaces = (struct interface *) erealloc3(interfaces, 306 num_interfaces, sizeof(struct interface)); 307 else 308 efree(interfaces); 309 } 310 efree(ifconf_buf); 311 (void) close(sock); 312} 313 314#else /* !SIOCGIFCONF || STUB_LOAD_INTERFACES */ 315 316/* 317 * Stub function for those without SIOCGIFCONF 318 */ 319void 320load_interfaces() 321{ 322 return; 323} 324 325#endif /* SIOCGIFCONF && !STUB_LOAD_INTERFACES */ 326 327void 328dump_interfaces() 329{ 330 int i; 331#ifdef HAVE_STRUCT_IN6_ADDR 332 char addrbuf[INET6_ADDRSTRLEN], maskbuf[INET6_ADDRSTRLEN]; 333#endif 334 335 puts("Local IP address and netmask pairs:"); 336 for (i = 0; i < num_interfaces; i++) { 337 switch(interfaces[i].family) { 338 case AF_INET: 339 printf("\t%s / ", inet_ntoa(interfaces[i].addr.ip4)); 340 puts(inet_ntoa(interfaces[i].netmask.ip4)); 341 break; 342#ifdef HAVE_STRUCT_IN6_ADDR 343 case AF_INET6: 344 inet_ntop(AF_INET6, &interfaces[i].addr.ip6, 345 addrbuf, sizeof(addrbuf)); 346 inet_ntop(AF_INET6, &interfaces[i].netmask.ip6, 347 maskbuf, sizeof(maskbuf)); 348 printf("\t%s / %s\n", addrbuf, maskbuf); 349 break; 350#endif /* HAVE_STRUCT_IN6_ADDR */ 351 } 352 } 353} 354