2 * Copyright (c) 1996, 1998-2005, 2007-2008
3 * Todd C. Miller <Todd.Miller@courtesan.com>
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.
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.
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.
23 * Suppress a warning w/ gcc on Digital UN*X.
24 * The system headers should really do this....
26 #if defined(__osf__) && !defined(__cplusplus)
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/param.h>
37 #include <sys/ioctl.h>
38 #if defined(HAVE_SYS_SOCKIO_H) && !defined(SIOCGIFCONF)
39 # include <sys/sockio.h>
49 #endif /* STDC_HEADERS */
51 # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
56 # ifdef HAVE_STRINGS_H
59 #endif /* HAVE_STRING_H */
62 #endif /* HAVE_UNISTD_H */
66 # include <sys/stream.h>
67 # include <sys/sioctl.h>
68 # include <sys/stropts.h>
69 # define STRSET(cmd, param, len) {strioctl.ic_cmd=(cmd);\
70 strioctl.ic_dp=(param);\
71 strioctl.ic_timout=0;\
72 strioctl.ic_len=(len);}
75 # include <net/soioctl.h>
77 #include <netinet/in.h>
78 #include <arpa/inet.h>
80 #ifdef HAVE_GETIFADDRS
85 #include "interfaces.h"
88 __unused static const char rcsid[] = "$Sudo: interfaces.c,v 1.84 2008/11/09 14:13:12 millert Exp $";
92 #ifdef HAVE_GETIFADDRS
95 * Allocate and fill in the interfaces global variable with the
96 * machine's ip addresses and netmasks.
101 struct ifaddrs *ifa, *ifaddrs;
102 struct sockaddr_in *sin;
104 struct sockaddr_in6 *sin6;
108 if (getifaddrs(&ifaddrs))
111 /* Allocate space for the interfaces list. */
112 for (ifa = ifaddrs; ifa != NULL; ifa = ifa -> ifa_next) {
113 /* Skip interfaces marked "down" and "loopback". */
114 if (ifa->ifa_addr == NULL || !ISSET(ifa->ifa_flags, IFF_UP) ||
115 ISSET(ifa->ifa_flags, IFF_LOOPBACK))
118 switch(ifa->ifa_addr->sa_family) {
127 if (num_interfaces == 0)
130 (struct interface *) emalloc2(num_interfaces, sizeof(struct interface));
132 /* Store the ip addr / netmask pairs. */
133 for (ifa = ifaddrs, i = 0; ifa != NULL; ifa = ifa -> ifa_next) {
134 /* Skip interfaces marked "down" and "loopback". */
135 if (ifa->ifa_addr == NULL || !ISSET(ifa->ifa_flags, IFF_UP) ||
136 ISSET(ifa->ifa_flags, IFF_LOOPBACK))
139 switch(ifa->ifa_addr->sa_family) {
141 sin = (struct sockaddr_in *)ifa->ifa_addr;
142 memcpy(&interfaces[i].addr, &sin->sin_addr,
143 sizeof(struct in_addr));
144 sin = (struct sockaddr_in *)ifa->ifa_netmask;
145 memcpy(&interfaces[i].netmask, &sin->sin_addr,
146 sizeof(struct in_addr));
147 interfaces[i].family = AF_INET;
152 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
153 memcpy(&interfaces[i].addr, &sin6->sin6_addr,
154 sizeof(struct in6_addr));
155 sin6 = (struct sockaddr_in6 *)ifa->ifa_netmask;
156 memcpy(&interfaces[i].netmask, &sin6->sin6_addr,
157 sizeof(struct in6_addr));
158 interfaces[i].family = AF_INET6;
161 #endif /* HAVE_IN6_ADDR */
164 #ifdef HAVE_FREEIFADDRS
165 freeifaddrs(ifaddrs);
171 #elif defined(SIOCGIFCONF) && !defined(STUB_LOAD_INTERFACES)
174 * Allocate and fill in the interfaces global variable with the
175 * machine's ip addresses and netmasks.
180 struct ifconf *ifconf;
181 struct ifreq *ifr, ifr_tmp;
182 struct sockaddr_in *sin;
184 size_t len = sizeof(struct ifconf) + BUFSIZ;
185 char *previfname = "", *ifconf_buf = NULL;
187 struct strioctl strioctl;
190 sock = socket(AF_INET, SOCK_DGRAM, 0);
192 error(1, "cannot open socket");
195 * Get interface configuration or return (leaving num_interfaces == 0)
198 ifconf_buf = erealloc(ifconf_buf, len);
199 ifconf = (struct ifconf *) ifconf_buf;
200 ifconf->ifc_len = len - sizeof(struct ifconf);
201 ifconf->ifc_buf = (caddr_t) (ifconf_buf + sizeof(struct ifconf));
204 STRSET(SIOCGIFCONF, (caddr_t) ifconf, len);
205 if (ioctl(sock, I_STR, (caddr_t) &strioctl) < 0) {
207 /* Note that some kernels return EINVAL if the buffer is too small */
208 if (ioctl(sock, SIOCGIFCONF, (caddr_t) ifconf) < 0 && errno != EINVAL) {
215 /* Break out of loop if we have a big enough buffer. */
216 if (ifconf->ifc_len + sizeof(struct ifreq) < len)
221 /* Allocate space for the maximum number of interfaces that could exist. */
222 if ((n = ifconf->ifc_len / sizeof(struct ifreq)) == 0)
224 interfaces = (struct interface *) emalloc2(n, sizeof(struct interface));
226 /* For each interface, store the ip address and netmask. */
227 for (i = 0; i < ifconf->ifc_len; ) {
228 /* Get a pointer to the current interface. */
229 ifr = (struct ifreq *) &ifconf->ifc_buf[i];
231 /* Set i to the subscript of the next interface. */
232 i += sizeof(struct ifreq);
234 if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr))
235 i += ifr->ifr_addr.sa_len - sizeof(struct sockaddr);
236 #endif /* HAVE_SA_LEN */
238 /* Skip duplicates and interfaces with NULL addresses. */
239 sin = (struct sockaddr_in *) &ifr->ifr_addr;
240 if (sin->sin_addr.s_addr == 0 ||
241 strncmp(previfname, ifr->ifr_name, sizeof(ifr->ifr_name) - 1) == 0)
244 if (ifr->ifr_addr.sa_family != AF_INET)
248 zero_bytes(&ifr_tmp, sizeof(ifr_tmp));
249 strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1);
250 if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr_tmp) < 0)
254 /* Skip interfaces marked "down" and "loopback". */
255 if (!ISSET(ifr_tmp.ifr_flags, IFF_UP) ||
256 ISSET(ifr_tmp.ifr_flags, IFF_LOOPBACK))
259 sin = (struct sockaddr_in *) &ifr->ifr_addr;
260 interfaces[num_interfaces].addr.ip4.s_addr = sin->sin_addr.s_addr;
262 /* Stash the name of the interface we saved. */
263 previfname = ifr->ifr_name;
265 /* Get the netmask. */
266 zero_bytes(&ifr_tmp, sizeof(ifr_tmp));
267 strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1);
268 #ifdef SIOCGIFNETMASK
270 STRSET(SIOCGIFNETMASK, (caddr_t) &ifr_tmp, sizeof(ifr_tmp));
271 if (ioctl(sock, I_STR, (caddr_t) &strioctl) == 0) {
273 if (ioctl(sock, SIOCGIFNETMASK, (caddr_t) &ifr_tmp) == 0) {
275 sin = (struct sockaddr_in *) &ifr_tmp.ifr_addr;
277 interfaces[num_interfaces].netmask.ip4.s_addr = sin->sin_addr.s_addr;
281 #endif /* SIOCGIFNETMASK */
282 if (IN_CLASSC(interfaces[num_interfaces].addr.ip4.s_addr))
283 interfaces[num_interfaces].netmask.ip4.s_addr = htonl(IN_CLASSC_NET);
284 else if (IN_CLASSB(interfaces[num_interfaces].addr.ip4.s_addr))
285 interfaces[num_interfaces].netmask.ip4.s_addr = htonl(IN_CLASSB_NET);
287 interfaces[num_interfaces].netmask.ip4.s_addr = htonl(IN_CLASSA_NET);
290 /* Only now can we be sure it was a good/interesting interface. */
291 interfaces[num_interfaces].family = AF_INET;
295 /* If the expected size < real size, realloc the array. */
296 if (n != num_interfaces) {
297 if (num_interfaces != 0)
298 interfaces = (struct interface *) erealloc3(interfaces,
299 num_interfaces, sizeof(struct interface));
307 #else /* !SIOCGIFCONF || STUB_LOAD_INTERFACES */
310 * Stub function for those without SIOCGIFCONF
318 #endif /* SIOCGIFCONF && !STUB_LOAD_INTERFACES */
325 char addrbuf[INET6_ADDRSTRLEN], maskbuf[INET6_ADDRSTRLEN];
328 puts("Local IP address and netmask pairs:");
329 for (i = 0; i < num_interfaces; i++) {
330 switch(interfaces[i].family) {
332 printf("\t%s / ", inet_ntoa(interfaces[i].addr.ip4));
333 puts(inet_ntoa(interfaces[i].netmask.ip4));
337 inet_ntop(AF_INET6, &interfaces[i].addr.ip6,
338 addrbuf, sizeof(addrbuf));
339 inet_ntop(AF_INET6, &interfaces[i].netmask.ip6,
340 maskbuf, sizeof(maskbuf));
341 printf("\t%s / %s\n", addrbuf, maskbuf);
343 #endif /* HAVE_IN6_ADDR */