xref: /netbsd-src/external/bsd/libpcap/dist/fad-gifc.c (revision 2718af68c3efc72c9769069b5c7f9ed36f6b9def)
1 /*	$NetBSD: fad-gifc.c,v 1.5 2018/09/03 15:26:43 christos Exp $	*/
2 
3 /* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
4 /*
5  * Copyright (c) 1994, 1995, 1996, 1997, 1998
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the Computer Systems
19  *	Engineering Group at Lawrence Berkeley Laboratory.
20  * 4. Neither the name of the University nor of the Laboratory may be used
21  *    to endorse or promote products derived from this software without
22  *    specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #include <sys/cdefs.h>
38 __RCSID("$NetBSD: fad-gifc.c,v 1.5 2018/09/03 15:26:43 christos Exp $");
39 
40 #ifdef HAVE_CONFIG_H
41 #include <config.h>
42 #endif
43 
44 #include <sys/param.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 
52 struct mbuf;		/* Squelch compiler warnings on some platforms for */
53 struct rtentry;		/* declarations in <net/if.h> */
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 
65 #ifdef HAVE_LIMITS_H
66 #include <limits.h>
67 #else
68 #define INT_MAX		2147483647
69 #endif
70 
71 #include "pcap-int.h"
72 
73 #ifdef HAVE_OS_PROTO_H
74 #include "os-proto.h"
75 #endif
76 
77 /*
78  * This is fun.
79  *
80  * In older BSD systems, socket addresses were fixed-length, and
81  * "sizeof (struct sockaddr)" gave the size of the structure.
82  * All addresses fit within a "struct sockaddr".
83  *
84  * In newer BSD systems, the socket address is variable-length, and
85  * there's an "sa_len" field giving the length of the structure;
86  * this allows socket addresses to be longer than 2 bytes of family
87  * and 14 bytes of data.
88  *
89  * Some commercial UNIXes use the old BSD scheme, some use the RFC 2553
90  * variant of the old BSD scheme (with "struct sockaddr_storage" rather
91  * than "struct sockaddr"), and some use the new BSD scheme.
92  *
93  * Some versions of GNU libc use neither scheme, but has an "SA_LEN()"
94  * macro that determines the size based on the address family.  Other
95  * versions don't have "SA_LEN()" (as it was in drafts of RFC 2553
96  * but not in the final version).
97  *
98  * We assume that a UNIX that doesn't have "getifaddrs()" and doesn't have
99  * SIOCGLIFCONF, but has SIOCGIFCONF, uses "struct sockaddr" for the
100  * address in an entry returned by SIOCGIFCONF.
101  */
102 #ifndef SA_LEN
103 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
104 #define SA_LEN(addr)	((addr)->sa_len)
105 #else /* HAVE_STRUCT_SOCKADDR_SA_LEN */
106 #define SA_LEN(addr)	(sizeof (struct sockaddr))
107 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
108 #endif /* SA_LEN */
109 
110 /*
111  * This is also fun.
112  *
113  * There is no ioctl that returns the amount of space required for all
114  * the data that SIOCGIFCONF could return, and if a buffer is supplied
115  * that's not large enough for all the data SIOCGIFCONF could return,
116  * on at least some platforms it just returns the data that'd fit with
117  * no indication that there wasn't enough room for all the data, much
118  * less an indication of how much more room is required.
119  *
120  * The only way to ensure that we got all the data is to pass a buffer
121  * large enough that the amount of space in the buffer *not* filled in
122  * is greater than the largest possible entry.
123  *
124  * We assume that's "sizeof(ifreq.ifr_name)" plus 255, under the assumption
125  * that no address is more than 255 bytes (on systems where the "sa_len"
126  * field in a "struct sockaddr" is 1 byte, e.g. newer BSDs, that's the
127  * case, and addresses are unlikely to be bigger than that in any case).
128  */
129 #define MAX_SA_LEN	255
130 
131 /*
132  * Get a list of all interfaces that are up and that we can open.
133  * Returns -1 on error, 0 otherwise.
134  * The list, as returned through "alldevsp", may be null if no interfaces
135  * were up and could be opened.
136  *
137  * This is the implementation used on platforms that have SIOCGIFCONF but
138  * don't have any other mechanism for getting a list of interfaces.
139  *
140  * XXX - or platforms that have other, better mechanisms but for which
141  * we don't yet have code to use that mechanism; I think there's a better
142  * way on Linux, for example, but if that better way is "getifaddrs()",
143  * we already have that.
144  */
145 int
146 pcap_findalldevs_interfaces(pcap_if_list_t *devlistp, char *errbuf,
147     int (*check_usable)(const char *), get_if_flags_func get_flags_func)
148 {
149 	register int fd;
150 	register struct ifreq *ifrp, *ifend, *ifnext;
151 	size_t n;
152 	struct ifconf ifc;
153 	char *buf = NULL;
154 	unsigned buf_size;
155 #if defined (HAVE_SOLARIS) || defined (HAVE_HPUX10_20_OR_LATER)
156 	char *p, *q;
157 #endif
158 	struct ifreq ifrflags, ifrnetmask, ifrbroadaddr, ifrdstaddr;
159 	struct sockaddr *netmask, *broadaddr, *dstaddr;
160 	size_t netmask_size, broadaddr_size, dstaddr_size;
161 	int ret = 0;
162 
163 	/*
164 	 * Create a socket from which to fetch the list of interfaces.
165 	 */
166 	fd = socket(AF_INET, SOCK_DGRAM, 0);
167 	if (fd < 0) {
168 		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
169 		    errno, "socket");
170 		return (-1);
171 	}
172 
173 	/*
174 	 * Start with an 8K buffer, and keep growing the buffer until
175 	 * we have more than "sizeof(ifrp->ifr_name) + MAX_SA_LEN"
176 	 * bytes left over in the buffer or we fail to get the
177 	 * interface list for some reason other than EINVAL (which is
178 	 * presumed here to mean "buffer is too small").
179 	 */
180 	buf_size = 8192;
181 	for (;;) {
182 		/*
183 		 * Don't let the buffer size get bigger than INT_MAX.
184 		 */
185 		if (buf_size > INT_MAX) {
186 			(void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
187 			    "interface information requires more than %u bytes",
188 			    INT_MAX);
189 			(void)close(fd);
190 			return (-1);
191 		}
192 		buf = malloc(buf_size);
193 		if (buf == NULL) {
194 			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
195 			    errno, "malloc");
196 			(void)close(fd);
197 			return (-1);
198 		}
199 
200 		ifc.ifc_len = buf_size;
201 		ifc.ifc_buf = buf;
202 		memset(buf, 0, buf_size);
203 		if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0
204 		    && errno != EINVAL) {
205 			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
206 			    errno, "SIOCGIFCONF");
207 			(void)close(fd);
208 			free(buf);
209 			return (-1);
210 		}
211 		if (ifc.ifc_len < (int)buf_size &&
212 		    (buf_size - ifc.ifc_len) > sizeof(ifrp->ifr_name) + MAX_SA_LEN)
213 			break;
214 		free(buf);
215 		buf_size *= 2;
216 	}
217 
218 	ifrp = (struct ifreq *)buf;
219 	ifend = (struct ifreq *)(buf + ifc.ifc_len);
220 
221 	for (; ifrp < ifend; ifrp = ifnext) {
222 		/*
223 		 * XXX - what if this isn't an IPv4 address?  Can
224 		 * we still get the netmask, etc. with ioctls on
225 		 * an IPv4 socket?
226 		 *
227 		 * The answer is probably platform-dependent, and
228 		 * if the answer is "no" on more than one platform,
229 		 * the way you work around it is probably platform-
230 		 * dependent as well.
231 		 */
232 		n = SA_LEN(&ifrp->ifr_addr) + sizeof(ifrp->ifr_name);
233 		if (n < sizeof(*ifrp))
234 			ifnext = ifrp + 1;
235 		else
236 			ifnext = (struct ifreq *)((char *)ifrp + n);
237 
238 		/*
239 		 * XXX - The 32-bit compatibility layer for Linux on IA-64
240 		 * is slightly broken. It correctly converts the structures
241 		 * to and from kernel land from 64 bit to 32 bit but
242 		 * doesn't update ifc.ifc_len, leaving it larger than the
243 		 * amount really used. This means we read off the end
244 		 * of the buffer and encounter an interface with an
245 		 * "empty" name. Since this is highly unlikely to ever
246 		 * occur in a valid case we can just finish looking for
247 		 * interfaces if we see an empty name.
248 		 */
249 		if (!(*ifrp->ifr_name))
250 			break;
251 
252 		/*
253 		 * Skip entries that begin with "dummy".
254 		 * XXX - what are these?  Is this Linux-specific?
255 		 * Are there platforms on which we shouldn't do this?
256 		 */
257 		if (strncmp(ifrp->ifr_name, "dummy", 5) == 0)
258 			continue;
259 
260 		/*
261 		 * Can we capture on this device?
262 		 */
263 		if (!(*check_usable)(ifrp->ifr_name)) {
264 			/*
265 			 * No.
266 			 */
267 			continue;
268 		}
269 
270 		/*
271 		 * Get the flags for this interface.
272 		 */
273 		strncpy(ifrflags.ifr_name, ifrp->ifr_name,
274 		    sizeof(ifrflags.ifr_name));
275 		if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifrflags) < 0) {
276 			if (errno == ENXIO)
277 				continue;
278 			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
279 			    errno, "SIOCGIFFLAGS: %.*s",
280 			    (int)sizeof(ifrflags.ifr_name),
281 			    ifrflags.ifr_name);
282 			ret = -1;
283 			break;
284 		}
285 
286 		/*
287 		 * Get the netmask for this address on this interface.
288 		 */
289 		strncpy(ifrnetmask.ifr_name, ifrp->ifr_name,
290 		    sizeof(ifrnetmask.ifr_name));
291 		memcpy(&ifrnetmask.ifr_addr, &ifrp->ifr_addr,
292 		    sizeof(ifrnetmask.ifr_addr));
293 		if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifrnetmask) < 0) {
294 			if (errno == EADDRNOTAVAIL) {
295 				/*
296 				 * Not available.
297 				 */
298 				netmask = NULL;
299 				netmask_size = 0;
300 			} else {
301 				pcap_fmt_errmsg_for_errno(errbuf,
302 				    PCAP_ERRBUF_SIZE, errno,
303 				    "SIOCGIFNETMASK: %.*s",
304 				    (int)sizeof(ifrnetmask.ifr_name),
305 				    ifrnetmask.ifr_name);
306 				ret = -1;
307 				break;
308 			}
309 		} else {
310 			netmask = &ifrnetmask.ifr_addr;
311 			netmask_size = SA_LEN(netmask);
312 		}
313 
314 		/*
315 		 * Get the broadcast address for this address on this
316 		 * interface (if any).
317 		 */
318 		if (ifrflags.ifr_flags & IFF_BROADCAST) {
319 			strncpy(ifrbroadaddr.ifr_name, ifrp->ifr_name,
320 			    sizeof(ifrbroadaddr.ifr_name));
321 			memcpy(&ifrbroadaddr.ifr_addr, &ifrp->ifr_addr,
322 			    sizeof(ifrbroadaddr.ifr_addr));
323 			if (ioctl(fd, SIOCGIFBRDADDR,
324 			    (char *)&ifrbroadaddr) < 0) {
325 				if (errno == EADDRNOTAVAIL) {
326 					/*
327 					 * Not available.
328 					 */
329 					broadaddr = NULL;
330 					broadaddr_size = 0;
331 				} else {
332 					pcap_fmt_errmsg_for_errno(errbuf,
333 					    PCAP_ERRBUF_SIZE, errno,
334 					    "SIOCGIFBRDADDR: %.*s",
335 					    (int)sizeof(ifrbroadaddr.ifr_name),
336 					    ifrbroadaddr.ifr_name);
337 					ret = -1;
338 					break;
339 				}
340 			} else {
341 				broadaddr = &ifrbroadaddr.ifr_broadaddr;
342 				broadaddr_size = SA_LEN(broadaddr);
343 			}
344 		} else {
345 			/*
346 			 * Not a broadcast interface, so no broadcast
347 			 * address.
348 			 */
349 			broadaddr = NULL;
350 			broadaddr_size = 0;
351 		}
352 
353 		/*
354 		 * Get the destination address for this address on this
355 		 * interface (if any).
356 		 */
357 		if (ifrflags.ifr_flags & IFF_POINTOPOINT) {
358 			strncpy(ifrdstaddr.ifr_name, ifrp->ifr_name,
359 			    sizeof(ifrdstaddr.ifr_name));
360 			memcpy(&ifrdstaddr.ifr_addr, &ifrp->ifr_addr,
361 			    sizeof(ifrdstaddr.ifr_addr));
362 			if (ioctl(fd, SIOCGIFDSTADDR,
363 			    (char *)&ifrdstaddr) < 0) {
364 				if (errno == EADDRNOTAVAIL) {
365 					/*
366 					 * Not available.
367 					 */
368 					dstaddr = NULL;
369 					dstaddr_size = 0;
370 				} else {
371 					pcap_fmt_errmsg_for_errno(errbuf,
372 					    PCAP_ERRBUF_SIZE, errno,
373 					    "SIOCGIFDSTADDR: %.*s",
374 					    (int)sizeof(ifrdstaddr.ifr_name),
375 					    ifrdstaddr.ifr_name);
376 					ret = -1;
377 					break;
378 				}
379 			} else {
380 				dstaddr = &ifrdstaddr.ifr_dstaddr;
381 				dstaddr_size = SA_LEN(dstaddr);
382 			}
383 		} else {
384 			/*
385 			 * Not a point-to-point interface, so no destination
386 			 * address.
387 			 */
388 			dstaddr = NULL;
389 			dstaddr_size = 0;
390 		}
391 
392 #if defined (HAVE_SOLARIS) || defined (HAVE_HPUX10_20_OR_LATER)
393 		/*
394 		 * If this entry has a colon followed by a number at
395 		 * the end, it's a logical interface.  Those are just
396 		 * the way you assign multiple IP addresses to a real
397 		 * interface, so an entry for a logical interface should
398 		 * be treated like the entry for the real interface;
399 		 * we do that by stripping off the ":" and the number.
400 		 */
401 		p = strchr(ifrp->ifr_name, ':');
402 		if (p != NULL) {
403 			/*
404 			 * We have a ":"; is it followed by a number?
405 			 */
406 			q = p + 1;
407 			while (isdigit((unsigned char)*q))
408 				q++;
409 			if (*q == '\0') {
410 				/*
411 				 * All digits after the ":" until the end.
412 				 * Strip off the ":" and everything after
413 				 * it.
414 				 */
415 				*p = '\0';
416 			}
417 		}
418 #endif
419 
420 		/*
421 		 * Add information for this address to the list.
422 		 */
423 		if (add_addr_to_if(devlistp, ifrp->ifr_name,
424 		    ifrflags.ifr_flags, get_flags_func,
425 		    &ifrp->ifr_addr, SA_LEN(&ifrp->ifr_addr),
426 		    netmask, netmask_size, broadaddr, broadaddr_size,
427 		    dstaddr, dstaddr_size, errbuf) < 0) {
428 			ret = -1;
429 			break;
430 		}
431 	}
432 	free(buf);
433 	(void)close(fd);
434 
435 	return (ret);
436 }
437