xref: /freebsd/contrib/libpcap/fad-gifc.c (revision 4ed925457ab06e83238a5db33e89ccc94b99a713)
1 /* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
2 /*
3  * Copyright (c) 1994, 1995, 1996, 1997, 1998
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by the Computer Systems
17  *	Engineering Group at Lawrence Berkeley Laboratory.
18  * 4. Neither the name of the University nor of the Laboratory may be used
19  *    to endorse or promote products derived from this software without
20  *    specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #ifndef lint
36 static const char rcsid[] _U_ =
37     "@(#) $Header: /tcpdump/master/libpcap/fad-gifc.c,v 1.11.2.1 2008-08-06 07:35:01 guy Exp $ (LBL)";
38 #endif
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 #include "pcap-int.h"
66 
67 #ifdef HAVE_OS_PROTO_H
68 #include "os-proto.h"
69 #endif
70 
71 /*
72  * This is fun.
73  *
74  * In older BSD systems, socket addresses were fixed-length, and
75  * "sizeof (struct sockaddr)" gave the size of the structure.
76  * All addresses fit within a "struct sockaddr".
77  *
78  * In newer BSD systems, the socket address is variable-length, and
79  * there's an "sa_len" field giving the length of the structure;
80  * this allows socket addresses to be longer than 2 bytes of family
81  * and 14 bytes of data.
82  *
83  * Some commercial UNIXes use the old BSD scheme, some use the RFC 2553
84  * variant of the old BSD scheme (with "struct sockaddr_storage" rather
85  * than "struct sockaddr"), and some use the new BSD scheme.
86  *
87  * Some versions of GNU libc use neither scheme, but has an "SA_LEN()"
88  * macro that determines the size based on the address family.  Other
89  * versions don't have "SA_LEN()" (as it was in drafts of RFC 2553
90  * but not in the final version).
91  *
92  * We assume that a UNIX that doesn't have "getifaddrs()" and doesn't have
93  * SIOCGLIFCONF, but has SIOCGIFCONF, uses "struct sockaddr" for the
94  * address in an entry returned by SIOCGIFCONF.
95  */
96 #ifndef SA_LEN
97 #ifdef HAVE_SOCKADDR_SA_LEN
98 #define SA_LEN(addr)	((addr)->sa_len)
99 #else /* HAVE_SOCKADDR_SA_LEN */
100 #define SA_LEN(addr)	(sizeof (struct sockaddr))
101 #endif /* HAVE_SOCKADDR_SA_LEN */
102 #endif /* SA_LEN */
103 
104 /*
105  * This is also fun.
106  *
107  * There is no ioctl that returns the amount of space required for all
108  * the data that SIOCGIFCONF could return, and if a buffer is supplied
109  * that's not large enough for all the data SIOCGIFCONF could return,
110  * on at least some platforms it just returns the data that'd fit with
111  * no indication that there wasn't enough room for all the data, much
112  * less an indication of how much more room is required.
113  *
114  * The only way to ensure that we got all the data is to pass a buffer
115  * large enough that the amount of space in the buffer *not* filled in
116  * is greater than the largest possible entry.
117  *
118  * We assume that's "sizeof(ifreq.ifr_name)" plus 255, under the assumption
119  * that no address is more than 255 bytes (on systems where the "sa_len"
120  * field in a "struct sockaddr" is 1 byte, e.g. newer BSDs, that's the
121  * case, and addresses are unlikely to be bigger than that in any case).
122  */
123 #define MAX_SA_LEN	255
124 
125 #ifdef HAVE_PROC_NET_DEV
126 /*
127  * Get from "/proc/net/dev" all interfaces listed there; if they're
128  * already in the list of interfaces we have, that won't add another
129  * instance, but if they're not, that'll add them.
130  *
131  * We don't bother getting any addresses for them; it appears you can't
132  * use SIOCGIFADDR on Linux to get IPv6 addresses for interfaces, and,
133  * although some other types of addresses can be fetched with SIOCGIFADDR,
134  * we don't bother with them for now.
135  *
136  * We also don't fail if we couldn't open "/proc/net/dev"; we just leave
137  * the list of interfaces as is.
138  */
139 static int
140 scan_proc_net_dev(pcap_if_t **devlistp, int fd, char *errbuf)
141 {
142 	FILE *proc_net_f;
143 	char linebuf[512];
144 	int linenum;
145 	unsigned char *p;
146 	char name[512];	/* XXX - pick a size */
147 	char *q, *saveq;
148 	struct ifreq ifrflags;
149 	int ret = 0;
150 
151 	proc_net_f = fopen("/proc/net/dev", "r");
152 	if (proc_net_f == NULL)
153 		return (0);
154 
155 	for (linenum = 1;
156 	    fgets(linebuf, sizeof linebuf, proc_net_f) != NULL; linenum++) {
157 		/*
158 		 * Skip the first two lines - they're headers.
159 		 */
160 		if (linenum <= 2)
161 			continue;
162 
163 		p = &linebuf[0];
164 
165 		/*
166 		 * Skip leading white space.
167 		 */
168 		while (*p != '\0' && isspace(*p))
169 			p++;
170 		if (*p == '\0' || *p == '\n')
171 			continue;	/* blank line */
172 
173 		/*
174 		 * Get the interface name.
175 		 */
176 		q = &name[0];
177 		while (*p != '\0' && !isspace(*p)) {
178 			if (*p == ':') {
179 				/*
180 				 * This could be the separator between a
181 				 * name and an alias number, or it could be
182 				 * the separator between a name with no
183 				 * alias number and the next field.
184 				 *
185 				 * If there's a colon after digits, it
186 				 * separates the name and the alias number,
187 				 * otherwise it separates the name and the
188 				 * next field.
189 				 */
190 				saveq = q;
191 				while (isdigit(*p))
192 					*q++ = *p++;
193 				if (*p != ':') {
194 					/*
195 					 * That was the next field,
196 					 * not the alias number.
197 					 */
198 					q = saveq;
199 				}
200 				break;
201 			} else
202 				*q++ = *p++;
203 		}
204 		*q = '\0';
205 
206 		/*
207 		 * Get the flags for this interface, and skip it if
208 		 * it's not up.
209 		 */
210 		strncpy(ifrflags.ifr_name, name, sizeof(ifrflags.ifr_name));
211 		if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifrflags) < 0) {
212 			if (errno == ENXIO)
213 				continue;
214 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
215 			    "SIOCGIFFLAGS: %.*s: %s",
216 			    (int)sizeof(ifrflags.ifr_name),
217 			    ifrflags.ifr_name,
218 			    pcap_strerror(errno));
219 			ret = -1;
220 			break;
221 		}
222 		if (!(ifrflags.ifr_flags & IFF_UP))
223 			continue;
224 
225 		/*
226 		 * Add an entry for this interface, with no addresses.
227 		 */
228 		if (pcap_add_if(devlistp, name, ifrflags.ifr_flags, NULL,
229 		    errbuf) == -1) {
230 			/*
231 			 * Failure.
232 			 */
233 			ret = -1;
234 			break;
235 		}
236 	}
237 	if (ret != -1) {
238 		/*
239 		 * Well, we didn't fail for any other reason; did we
240 		 * fail due to an error reading the file?
241 		 */
242 		if (ferror(proc_net_f)) {
243 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
244 			    "Error reading /proc/net/dev: %s",
245 			    pcap_strerror(errno));
246 			ret = -1;
247 		}
248 	}
249 
250 	(void)fclose(proc_net_f);
251 	return (ret);
252 }
253 #endif /* HAVE_PROC_NET_DEV */
254 
255 /*
256  * Get a list of all interfaces that are up and that we can open.
257  * Returns -1 on error, 0 otherwise.
258  * The list, as returned through "alldevsp", may be null if no interfaces
259  * were up and could be opened.
260  *
261  * This is the implementation used on platforms that have SIOCGIFCONF but
262  * don't have any other mechanism for getting a list of interfaces.
263  *
264  * XXX - or platforms that have other, better mechanisms but for which
265  * we don't yet have code to use that mechanism; I think there's a better
266  * way on Linux, for example.
267  */
268 int
269 pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf)
270 {
271 	pcap_if_t *devlist = NULL;
272 	register int fd;
273 	register struct ifreq *ifrp, *ifend, *ifnext;
274 	int n;
275 	struct ifconf ifc;
276 	char *buf = NULL;
277 	unsigned buf_size;
278 #if defined (HAVE_SOLARIS) || defined (HAVE_HPUX10_20_OR_LATER)
279 	char *p, *q;
280 #endif
281 	struct ifreq ifrflags, ifrnetmask, ifrbroadaddr, ifrdstaddr;
282 	struct sockaddr *netmask, *broadaddr, *dstaddr;
283 	size_t netmask_size, broadaddr_size, dstaddr_size;
284 	int ret = 0;
285 
286 	/*
287 	 * Create a socket from which to fetch the list of interfaces.
288 	 */
289 	fd = socket(AF_INET, SOCK_DGRAM, 0);
290 	if (fd < 0) {
291 		(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
292 		    "socket: %s", pcap_strerror(errno));
293 		return (-1);
294 	}
295 
296 	/*
297 	 * Start with an 8K buffer, and keep growing the buffer until
298 	 * we have more than "sizeof(ifrp->ifr_name) + MAX_SA_LEN"
299 	 * bytes left over in the buffer or we fail to get the
300 	 * interface list for some reason other than EINVAL (which is
301 	 * presumed here to mean "buffer is too small").
302 	 */
303 	buf_size = 8192;
304 	for (;;) {
305 		buf = malloc(buf_size);
306 		if (buf == NULL) {
307 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
308 			    "malloc: %s", pcap_strerror(errno));
309 			(void)close(fd);
310 			return (-1);
311 		}
312 
313 		ifc.ifc_len = buf_size;
314 		ifc.ifc_buf = buf;
315 		memset(buf, 0, buf_size);
316 		if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0
317 		    && errno != EINVAL) {
318 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
319 			    "SIOCGIFCONF: %s", pcap_strerror(errno));
320 			(void)close(fd);
321 			free(buf);
322 			return (-1);
323 		}
324 		if (ifc.ifc_len < buf_size &&
325 		    (buf_size - ifc.ifc_len) > sizeof(ifrp->ifr_name) + MAX_SA_LEN)
326 			break;
327 		free(buf);
328 		buf_size *= 2;
329 	}
330 
331 	ifrp = (struct ifreq *)buf;
332 	ifend = (struct ifreq *)(buf + ifc.ifc_len);
333 
334 	for (; ifrp < ifend; ifrp = ifnext) {
335 		/*
336 		 * XXX - what if this isn't an IPv4 address?  Can
337 		 * we still get the netmask, etc. with ioctls on
338 		 * an IPv4 socket?
339 		 *
340 		 * The answer is probably platform-dependent, and
341 		 * if the answer is "no" on more than one platform,
342 		 * the way you work around it is probably platform-
343 		 * dependent as well.
344 		 */
345 		n = SA_LEN(&ifrp->ifr_addr) + sizeof(ifrp->ifr_name);
346 		if (n < sizeof(*ifrp))
347 			ifnext = ifrp + 1;
348 		else
349 			ifnext = (struct ifreq *)((char *)ifrp + n);
350 
351 		/*
352 		 * XXX - The 32-bit compatibility layer for Linux on IA-64
353 		 * is slightly broken. It correctly converts the structures
354 		 * to and from kernel land from 64 bit to 32 bit but
355 		 * doesn't update ifc.ifc_len, leaving it larger than the
356 		 * amount really used. This means we read off the end
357 		 * of the buffer and encounter an interface with an
358 		 * "empty" name. Since this is highly unlikely to ever
359 		 * occur in a valid case we can just finish looking for
360 		 * interfaces if we see an empty name.
361 		 */
362 		if (!(*ifrp->ifr_name))
363 			break;
364 
365 		/*
366 		 * Skip entries that begin with "dummy".
367 		 * XXX - what are these?  Is this Linux-specific?
368 		 * Are there platforms on which we shouldn't do this?
369 		 */
370 		if (strncmp(ifrp->ifr_name, "dummy", 5) == 0)
371 			continue;
372 
373 		/*
374 		 * Get the flags for this interface, and skip it if it's
375 		 * not up.
376 		 */
377 		strncpy(ifrflags.ifr_name, ifrp->ifr_name,
378 		    sizeof(ifrflags.ifr_name));
379 		if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifrflags) < 0) {
380 			if (errno == ENXIO)
381 				continue;
382 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
383 			    "SIOCGIFFLAGS: %.*s: %s",
384 			    (int)sizeof(ifrflags.ifr_name),
385 			    ifrflags.ifr_name,
386 			    pcap_strerror(errno));
387 			ret = -1;
388 			break;
389 		}
390 		if (!(ifrflags.ifr_flags & IFF_UP))
391 			continue;
392 
393 		/*
394 		 * Get the netmask for this address on this interface.
395 		 */
396 		strncpy(ifrnetmask.ifr_name, ifrp->ifr_name,
397 		    sizeof(ifrnetmask.ifr_name));
398 		memcpy(&ifrnetmask.ifr_addr, &ifrp->ifr_addr,
399 		    sizeof(ifrnetmask.ifr_addr));
400 		if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifrnetmask) < 0) {
401 			if (errno == EADDRNOTAVAIL) {
402 				/*
403 				 * Not available.
404 				 */
405 				netmask = NULL;
406 				netmask_size = 0;
407 			} else {
408 				(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
409 				    "SIOCGIFNETMASK: %.*s: %s",
410 				    (int)sizeof(ifrnetmask.ifr_name),
411 				    ifrnetmask.ifr_name,
412 				    pcap_strerror(errno));
413 				ret = -1;
414 				break;
415 			}
416 		} else {
417 			netmask = &ifrnetmask.ifr_addr;
418 			netmask_size = SA_LEN(netmask);
419 		}
420 
421 		/*
422 		 * Get the broadcast address for this address on this
423 		 * interface (if any).
424 		 */
425 		if (ifrflags.ifr_flags & IFF_BROADCAST) {
426 			strncpy(ifrbroadaddr.ifr_name, ifrp->ifr_name,
427 			    sizeof(ifrbroadaddr.ifr_name));
428 			memcpy(&ifrbroadaddr.ifr_addr, &ifrp->ifr_addr,
429 			    sizeof(ifrbroadaddr.ifr_addr));
430 			if (ioctl(fd, SIOCGIFBRDADDR,
431 			    (char *)&ifrbroadaddr) < 0) {
432 				if (errno == EADDRNOTAVAIL) {
433 					/*
434 					 * Not available.
435 					 */
436 					broadaddr = NULL;
437 					broadaddr_size = 0;
438 				} else {
439 					(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
440 					    "SIOCGIFBRDADDR: %.*s: %s",
441 					    (int)sizeof(ifrbroadaddr.ifr_name),
442 					    ifrbroadaddr.ifr_name,
443 					    pcap_strerror(errno));
444 					ret = -1;
445 					break;
446 				}
447 			} else {
448 				broadaddr = &ifrbroadaddr.ifr_broadaddr;
449 				broadaddr_size = SA_LEN(broadaddr);
450 			}
451 		} else {
452 			/*
453 			 * Not a broadcast interface, so no broadcast
454 			 * address.
455 			 */
456 			broadaddr = NULL;
457 			broadaddr_size = 0;
458 		}
459 
460 		/*
461 		 * Get the destination address for this address on this
462 		 * interface (if any).
463 		 */
464 		if (ifrflags.ifr_flags & IFF_POINTOPOINT) {
465 			strncpy(ifrdstaddr.ifr_name, ifrp->ifr_name,
466 			    sizeof(ifrdstaddr.ifr_name));
467 			memcpy(&ifrdstaddr.ifr_addr, &ifrp->ifr_addr,
468 			    sizeof(ifrdstaddr.ifr_addr));
469 			if (ioctl(fd, SIOCGIFDSTADDR,
470 			    (char *)&ifrdstaddr) < 0) {
471 				if (errno == EADDRNOTAVAIL) {
472 					/*
473 					 * Not available.
474 					 */
475 					dstaddr = NULL;
476 					dstaddr_size = 0;
477 				} else {
478 					(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
479 					    "SIOCGIFDSTADDR: %.*s: %s",
480 					    (int)sizeof(ifrdstaddr.ifr_name),
481 					    ifrdstaddr.ifr_name,
482 					    pcap_strerror(errno));
483 					ret = -1;
484 					break;
485 				}
486 			} else {
487 				dstaddr = &ifrdstaddr.ifr_dstaddr;
488 				dstaddr_size = SA_LEN(dstaddr);
489 			}
490 		} else {
491 			/*
492 			 * Not a point-to-point interface, so no destination
493 			 * address.
494 			 */
495 			dstaddr = NULL;
496 			dstaddr_size = 0;
497 		}
498 
499 #if defined (HAVE_SOLARIS) || defined (HAVE_HPUX10_20_OR_LATER)
500 		/*
501 		 * If this entry has a colon followed by a number at
502 		 * the end, it's a logical interface.  Those are just
503 		 * the way you assign multiple IP addresses to a real
504 		 * interface, so an entry for a logical interface should
505 		 * be treated like the entry for the real interface;
506 		 * we do that by stripping off the ":" and the number.
507 		 */
508 		p = strchr(ifrp->ifr_name, ':');
509 		if (p != NULL) {
510 			/*
511 			 * We have a ":"; is it followed by a number?
512 			 */
513 			q = p + 1;
514 			while (isdigit((unsigned char)*q))
515 				q++;
516 			if (*q == '\0') {
517 				/*
518 				 * All digits after the ":" until the end.
519 				 * Strip off the ":" and everything after
520 				 * it.
521 				 */
522 				*p = '\0';
523 			}
524 		}
525 #endif
526 
527 		/*
528 		 * Add information for this address to the list.
529 		 */
530 		if (add_addr_to_iflist(&devlist, ifrp->ifr_name,
531 		    ifrflags.ifr_flags, &ifrp->ifr_addr,
532 		    SA_LEN(&ifrp->ifr_addr), netmask, netmask_size,
533 		    broadaddr, broadaddr_size, dstaddr, dstaddr_size,
534 		    errbuf) < 0) {
535 			ret = -1;
536 			break;
537 		}
538 	}
539 	free(buf);
540 
541 #ifdef HAVE_PROC_NET_DEV
542 	if (ret != -1) {
543 		/*
544 		 * We haven't had any errors yet; now read "/proc/net/dev",
545 		 * and add to the list of interfaces all interfaces listed
546 		 * there that we don't already have, because, on Linux,
547 		 * SIOCGIFCONF reports only interfaces with IPv4 addresses,
548 		 * so you need to read "/proc/net/dev" to get the names of
549 		 * the rest of the interfaces.
550 		 */
551 		ret = scan_proc_net_dev(&devlist, fd, errbuf);
552 	}
553 #endif
554 	(void)close(fd);
555 
556 	if (ret != -1) {
557 		/*
558 		 * We haven't had any errors yet; do any platform-specific
559 		 * operations to add devices.
560 		 */
561 		if (pcap_platform_finddevs(&devlist, errbuf) < 0)
562 			ret = -1;
563 	}
564 
565 	if (ret == -1) {
566 		/*
567 		 * We had an error; free the list we've been constructing.
568 		 */
569 		if (devlist != NULL) {
570 			pcap_freealldevs(devlist);
571 			devlist = NULL;
572 		}
573 	}
574 
575 	*alldevsp = devlist;
576 	return (ret);
577 }
578