2 * Copyright (c) 1996, 1998-2005, 2007-2010
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)
55 #endif /* HAVE_STRING_H */
58 #endif /* HAVE_STRINGS_H */
61 #endif /* HAVE_UNISTD_H */
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);}
74 # include <net/soioctl.h>
76 #include <netinet/in.h>
77 #include <arpa/inet.h>
79 #ifdef HAVE_GETIFADDRS
84 #include "interfaces.h"
86 /* Minix apparently lacks IFF_LOOPBACK */
88 # define IFF_LOOPBACK 0
91 #ifdef HAVE_GETIFADDRS
94 * Allocate and fill in the interfaces global variable with the
95 * machine's ip addresses and netmasks.
100 struct ifaddrs *ifa, *ifaddrs;
101 struct sockaddr_in *sin;
103 struct sockaddr_in6 *sin6;
107 if (getifaddrs(&ifaddrs))
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))
117 switch(ifa->ifa_addr->sa_family) {
126 if (num_interfaces == 0)
129 (struct interface *) emalloc2(num_interfaces, sizeof(struct interface));
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))
138 switch(ifa->ifa_addr->sa_family) {
140 sin = (struct sockaddr_in *)ifa->ifa_addr;
143 memcpy(&interfaces[i].addr, &sin->sin_addr,
144 sizeof(struct in_addr));
145 sin = (struct sockaddr_in *)ifa->ifa_netmask;
148 memcpy(&interfaces[i].netmask, &sin->sin_addr,
149 sizeof(struct in_addr));
150 interfaces[i].family = AF_INET;
155 sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
158 memcpy(&interfaces[i].addr, &sin6->sin6_addr,
159 sizeof(struct in6_addr));
160 sin6 = (struct sockaddr_in6 *)ifa->ifa_netmask;
163 memcpy(&interfaces[i].netmask, &sin6->sin6_addr,
164 sizeof(struct in6_addr));
165 interfaces[i].family = AF_INET6;
168 #endif /* HAVE_IN6_ADDR */
171 #ifdef HAVE_FREEIFADDRS
172 freeifaddrs(ifaddrs);
178 #elif defined(SIOCGIFCONF) && !defined(STUB_LOAD_INTERFACES)
181 * Allocate and fill in the interfaces global variable with the
182 * machine's ip addresses and netmasks.
187 struct ifconf *ifconf;
188 struct ifreq *ifr, ifr_tmp;
189 struct sockaddr_in *sin;
191 size_t len = sizeof(struct ifconf) + BUFSIZ;
192 char *previfname = "", *ifconf_buf = NULL;
194 struct strioctl strioctl;
197 sock = socket(AF_INET, SOCK_DGRAM, 0);
199 error(1, "cannot open socket");
202 * Get interface configuration or return (leaving num_interfaces == 0)
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));
211 STRSET(SIOCGIFCONF, (caddr_t) ifconf, len);
212 if (ioctl(sock, I_STR, (caddr_t) &strioctl) < 0) {
214 /* Note that some kernels return EINVAL if the buffer is too small */
215 if (ioctl(sock, SIOCGIFCONF, (caddr_t) ifconf) < 0 && errno != EINVAL) {
222 /* Break out of loop if we have a big enough buffer. */
223 if (ifconf->ifc_len + sizeof(struct ifreq) < len)
228 /* Allocate space for the maximum number of interfaces that could exist. */
229 if ((n = ifconf->ifc_len / sizeof(struct ifreq)) == 0)
231 interfaces = (struct interface *) emalloc2(n, sizeof(struct interface));
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];
238 /* Set i to the subscript of the next interface. */
239 i += sizeof(struct ifreq);
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 */
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)
251 if (ifr->ifr_addr.sa_family != AF_INET)
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)
261 /* Skip interfaces marked "down" and "loopback". */
262 if (!ISSET(ifr_tmp.ifr_flags, IFF_UP) ||
263 ISSET(ifr_tmp.ifr_flags, IFF_LOOPBACK))
266 sin = (struct sockaddr_in *) &ifr->ifr_addr;
267 interfaces[num_interfaces].addr.ip4.s_addr = sin->sin_addr.s_addr;
269 /* Stash the name of the interface we saved. */
270 previfname = ifr->ifr_name;
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
277 STRSET(SIOCGIFNETMASK, (caddr_t) &ifr_tmp, sizeof(ifr_tmp));
278 if (ioctl(sock, I_STR, (caddr_t) &strioctl) == 0) {
280 if (ioctl(sock, SIOCGIFNETMASK, (caddr_t) &ifr_tmp) == 0) {
282 sin = (struct sockaddr_in *) &ifr_tmp.ifr_addr;
284 interfaces[num_interfaces].netmask.ip4.s_addr = sin->sin_addr.s_addr;
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);
294 interfaces[num_interfaces].netmask.ip4.s_addr = htonl(IN_CLASSA_NET);
297 /* Only now can we be sure it was a good/interesting interface. */
298 interfaces[num_interfaces].family = AF_INET;
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));
314 #else /* !SIOCGIFCONF || STUB_LOAD_INTERFACES */
317 * Stub function for those without SIOCGIFCONF
325 #endif /* SIOCGIFCONF && !STUB_LOAD_INTERFACES */
332 char addrbuf[INET6_ADDRSTRLEN], maskbuf[INET6_ADDRSTRLEN];
335 puts("Local IP address and netmask pairs:");
336 for (i = 0; i < num_interfaces; i++) {
337 switch(interfaces[i].family) {
339 printf("\t%s / ", inet_ntoa(interfaces[i].addr.ip4));
340 puts(inet_ntoa(interfaces[i].netmask.ip4));
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);
350 #endif /* HAVE_IN6_ADDR */