1: /*
2: * Copyright (c) 1996, 1998-2005, 2007-2014
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)
27: struct mbuf;
28: struct rtentry;
29: #endif
30:
31: #include <config.h>
32:
33: #include <sys/types.h>
34: #include <sys/socket.h>
35: #include <sys/time.h>
36: #include <sys/ioctl.h>
37: #if defined(HAVE_SYS_SOCKIO_H) && !defined(SIOCGIFCONF)
38: # include <sys/sockio.h>
39: #endif
40: #include <stdio.h>
41: #ifdef STDC_HEADERS
42: # include <stdlib.h>
43: # include <stddef.h>
44: #else
45: # ifdef HAVE_STDLIB_H
46: # include <stdlib.h>
47: # endif
48: #endif /* STDC_HEADERS */
49: #ifdef HAVE_STRING_H
50: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
51: # include <memory.h>
52: # endif
53: # include <string.h>
54: #endif /* HAVE_STRING_H */
55: #ifdef HAVE_STRINGS_H
56: # include <strings.h>
57: #endif /* HAVE_STRINGS_H */
58: #ifdef HAVE_STDBOOL_H
59: # include <stdbool.h>
60: #else
61: # include "compat/stdbool.h"
62: #endif /* HAVE_STDBOOL_H */
63: #ifdef HAVE_UNISTD_H
64: # include <unistd.h>
65: #endif /* HAVE_UNISTD_H */
66: #include <netdb.h>
67: #include <errno.h>
68: #ifdef _ISC
69: # include <sys/stream.h>
70: # include <sys/sioctl.h>
71: # include <sys/stropts.h>
72: # define STRSET(cmd, param, len) {strioctl.ic_cmd=(cmd);\
73: strioctl.ic_dp=(param);\
74: strioctl.ic_timout=0;\
75: strioctl.ic_len=(len);}
76: #endif /* _ISC */
77: #ifdef _MIPS
78: # include <net/soioctl.h>
79: #endif /* _MIPS */
80: #include <netinet/in.h>
81: #include <arpa/inet.h>
82: #include <net/if.h>
83: #ifdef HAVE_GETIFADDRS
84: # include <ifaddrs.h>
85: #endif
86:
87: #define DEFAULT_TEXT_DOMAIN "sudo"
88: #include "gettext.h" /* must be included before missing.h */
89:
90: #include "missing.h"
91: #include "alloc.h"
92: #include "fatal.h"
93: #include "sudo_conf.h"
94: #include "sudo_debug.h"
95:
96: /* Minix apparently lacks IFF_LOOPBACK */
97: #ifndef IFF_LOOPBACK
98: # define IFF_LOOPBACK 0
99: #endif
100:
101: #ifndef INET6_ADDRSTRLEN
102: # define INET6_ADDRSTRLEN 46
103: #endif
104:
105: #ifdef HAVE_GETIFADDRS
106:
107: /*
108: * Fill in the interfaces string with the machine's ip addresses and netmasks
109: * and return the number of interfaces found.
110: */
111: int
112: get_net_ifs(char **addrinfo)
113: {
114: struct ifaddrs *ifa, *ifaddrs;
115: struct sockaddr_in *sin;
116: #ifdef HAVE_STRUCT_IN6_ADDR
117: struct sockaddr_in6 *sin6;
118: char addrbuf[INET6_ADDRSTRLEN];
119: #endif
120: int ailen, len, num_interfaces = 0;
121: char *cp;
122: debug_decl(get_net_ifs, SUDO_DEBUG_NETIF)
123:
124: if (!sudo_conf_probe_interfaces() || getifaddrs(&ifaddrs) != 0)
125: debug_return_int(0);
126:
127: /* Allocate space for the interfaces info string. */
128: for (ifa = ifaddrs; ifa != NULL; ifa = ifa -> ifa_next) {
129: /* Skip interfaces marked "down" and "loopback". */
130: if (ifa->ifa_addr == NULL || ifa->ifa_netmask == NULL ||
131: !ISSET(ifa->ifa_flags, IFF_UP) || ISSET(ifa->ifa_flags, IFF_LOOPBACK))
132: continue;
133:
134: switch (ifa->ifa_addr->sa_family) {
135: case AF_INET:
136: #ifdef HAVE_STRUCT_IN6_ADDR
137: case AF_INET6:
138: #endif
139: num_interfaces++;
140: break;
141: }
142: }
143: if (num_interfaces == 0)
144: debug_return_int(0);
145: ailen = num_interfaces * 2 * INET6_ADDRSTRLEN;
146: *addrinfo = cp = emalloc(ailen);
147:
148: /* Store the IP addr/netmask pairs. */
149: for (ifa = ifaddrs; ifa != NULL; ifa = ifa -> ifa_next) {
150: /* Skip interfaces marked "down" and "loopback". */
151: if (ifa->ifa_addr == NULL || ifa->ifa_netmask == NULL ||
152: !ISSET(ifa->ifa_flags, IFF_UP) || ISSET(ifa->ifa_flags, IFF_LOOPBACK))
153: continue;
154:
155: switch (ifa->ifa_addr->sa_family) {
156: case AF_INET:
157: sin = (struct sockaddr_in *)ifa->ifa_addr;
158: len = snprintf(cp, ailen - (*addrinfo - cp),
159: "%s%s/", cp == *addrinfo ? "" : " ",
160: inet_ntoa(sin->sin_addr));
161: if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
162: warningx(U_("load_interfaces: overflow detected"));
163: goto done;
164: }
165: cp += len;
166:
167: sin = (struct sockaddr_in *)ifa->ifa_netmask;
168: len = snprintf(cp, ailen - (*addrinfo - cp),
169: "%s", inet_ntoa(sin->sin_addr));
170: if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
171: warningx(U_("load_interfaces: overflow detected"));
172: goto done;
173: }
174: cp += len;
175: break;
176: #ifdef HAVE_STRUCT_IN6_ADDR
177: case AF_INET6:
178: sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
179: inet_ntop(AF_INET6, &sin6->sin6_addr, addrbuf, sizeof(addrbuf));
180: len = snprintf(cp, ailen - (*addrinfo - cp),
181: "%s%s/", cp == *addrinfo ? "" : " ", addrbuf);
182: if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
183: warningx(U_("load_interfaces: overflow detected"));
184: goto done;
185: }
186: cp += len;
187:
188: sin6 = (struct sockaddr_in6 *)ifa->ifa_netmask;
189: inet_ntop(AF_INET6, &sin6->sin6_addr, addrbuf, sizeof(addrbuf));
190: len = snprintf(cp, ailen - (*addrinfo - cp), "%s", addrbuf);
191: if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
192: warningx(U_("load_interfaces: overflow detected"));
193: goto done;
194: }
195: cp += len;
196: break;
197: #endif /* HAVE_STRUCT_IN6_ADDR */
198: }
199: }
200:
201: done:
202: #ifdef HAVE_FREEIFADDRS
203: freeifaddrs(ifaddrs);
204: #else
205: efree(ifaddrs);
206: #endif
207: debug_return_int(num_interfaces);
208: }
209:
210: #elif defined(SIOCGIFCONF) && !defined(STUB_LOAD_INTERFACES)
211:
212: /*
213: * Allocate and fill in the interfaces global variable with the
214: * machine's ip addresses and netmasks.
215: */
216: int
217: get_net_ifs(char **addrinfo)
218: {
219: struct ifconf *ifconf;
220: struct ifreq *ifr, ifr_tmp;
221: struct sockaddr_in *sin;
222: int ailen, i, len, n, sock, num_interfaces = 0;
223: size_t buflen = sizeof(struct ifconf) + BUFSIZ;
224: char *cp, *previfname = "", *ifconf_buf = NULL;
225: #ifdef _ISC
226: struct strioctl strioctl;
227: #endif /* _ISC */
228: debug_decl(get_net_ifs, SUDO_DEBUG_NETIF)
229:
230: if (!sudo_conf_probe_interfaces())
231: debug_return_int(0);
232:
233: sock = socket(AF_INET, SOCK_DGRAM, 0);
234: if (sock < 0)
235: fatal(U_("unable to open socket"));
236:
237: /*
238: * Get interface configuration or return.
239: */
240: for (;;) {
241: ifconf_buf = emalloc(buflen);
242: ifconf = (struct ifconf *) ifconf_buf;
243: ifconf->ifc_len = buflen - sizeof(struct ifconf);
244: ifconf->ifc_buf = (caddr_t) (ifconf_buf + sizeof(struct ifconf));
245:
246: #ifdef _ISC
247: STRSET(SIOCGIFCONF, (caddr_t) ifconf, buflen);
248: if (ioctl(sock, I_STR, (caddr_t) &strioctl) < 0)
249: #else
250: /* Note that some kernels return EINVAL if the buffer is too small */
251: if (ioctl(sock, SIOCGIFCONF, (caddr_t) ifconf) < 0 && errno != EINVAL)
252: #endif /* _ISC */
253: goto done;
254:
255: /* Break out of loop if we have a big enough buffer. */
256: if (ifconf->ifc_len + sizeof(struct ifreq) < buflen)
257: break;
258: buflen += BUFSIZ;
259: efree(ifconf_buf);
260: }
261:
262: /* Allocate space for the maximum number of interfaces that could exist. */
263: if ((n = ifconf->ifc_len / sizeof(struct ifreq)) == 0)
264: debug_return_int(0);
265: ailen = n * 2 * INET6_ADDRSTRLEN;
266: *addrinfo = cp = emalloc(ailen);
267:
268: /* For each interface, store the ip address and netmask. */
269: for (i = 0; i < ifconf->ifc_len; ) {
270: /* Get a pointer to the current interface. */
271: ifr = (struct ifreq *) &ifconf->ifc_buf[i];
272:
273: /* Set i to the subscript of the next interface. */
274: i += sizeof(struct ifreq);
275: #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
276: if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr))
277: i += ifr->ifr_addr.sa_len - sizeof(struct sockaddr);
278: #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
279:
280: /* Skip duplicates and interfaces with NULL addresses. */
281: sin = (struct sockaddr_in *) &ifr->ifr_addr;
282: if (sin->sin_addr.s_addr == 0 ||
283: strncmp(previfname, ifr->ifr_name, sizeof(ifr->ifr_name) - 1) == 0)
284: continue;
285:
286: if (ifr->ifr_addr.sa_family != AF_INET)
287: continue;
288:
289: #ifdef SIOCGIFFLAGS
290: memset(&ifr_tmp, 0, sizeof(ifr_tmp));
291: strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1);
292: if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr_tmp) < 0)
293: #endif
294: ifr_tmp = *ifr;
295:
296: /* Skip interfaces marked "down" and "loopback". */
297: if (!ISSET(ifr_tmp.ifr_flags, IFF_UP) ||
298: ISSET(ifr_tmp.ifr_flags, IFF_LOOPBACK))
299: continue;
300:
301: sin = (struct sockaddr_in *) &ifr->ifr_addr;
302: len = snprintf(cp, ailen - (*addrinfo - cp),
303: "%s%s/", cp == *addrinfo ? "" : " ",
304: inet_ntoa(sin->sin_addr));
305: if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
306: warningx(U_("load_interfaces: overflow detected"));
307: goto done;
308: }
309: cp += len;
310:
311: /* Stash the name of the interface we saved. */
312: previfname = ifr->ifr_name;
313:
314: /* Get the netmask. */
315: memset(&ifr_tmp, 0, sizeof(ifr_tmp));
316: strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1);
317: #ifdef _ISC
318: STRSET(SIOCGIFNETMASK, (caddr_t) &ifr_tmp, sizeof(ifr_tmp));
319: if (ioctl(sock, I_STR, (caddr_t) &strioctl) < 0) {
320: #else
321: if (ioctl(sock, SIOCGIFNETMASK, (caddr_t) &ifr_tmp) < 0) {
322: #endif /* _ISC */
323: sin = (struct sockaddr_in *) &ifr_tmp.ifr_addr;
324: sin->sin_addr.s_addr = htonl(IN_CLASSC_NET);
325: }
326: sin = (struct sockaddr_in *) &ifr_tmp.ifr_addr;
327: len = snprintf(cp, ailen - (*addrinfo - cp),
328: "%s", inet_ntoa(sin->sin_addr));
329: if (len <= 0 || len >= ailen - (*addrinfo - cp)) {
330: warningx(U_("load_interfaces: overflow detected"));
331: goto done;
332: }
333: cp += len;
334: num_interfaces++;
335: }
336:
337: done:
338: efree(ifconf_buf);
339: (void) close(sock);
340:
341: debug_return_int(num_interfaces);
342: }
343:
344: #else /* !SIOCGIFCONF || STUB_LOAD_INTERFACES */
345:
346: /*
347: * Stub function for those without SIOCGIFCONF or getifaddrs()
348: */
349: int
350: get_net_ifs(char **addrinfo)
351: {
352: debug_decl(get_net_ifs, SUDO_DEBUG_NETIF)
353: debug_return_int(0);
354: }
355:
356: #endif /* SIOCGIFCONF && !STUB_LOAD_INTERFACES */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>