1127664Sbms/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
2127664Sbms/*
3127664Sbms * Copyright (c) 1994, 1995, 1996, 1997, 1998
4127664Sbms *	The Regents of the University of California.  All rights reserved.
5127664Sbms *
6127664Sbms * Redistribution and use in source and binary forms, with or without
7127664Sbms * modification, are permitted provided that the following conditions
8127664Sbms * are met:
9127664Sbms * 1. Redistributions of source code must retain the above copyright
10127664Sbms *    notice, this list of conditions and the following disclaimer.
11127664Sbms * 2. Redistributions in binary form must reproduce the above copyright
12127664Sbms *    notice, this list of conditions and the following disclaimer in the
13127664Sbms *    documentation and/or other materials provided with the distribution.
14127664Sbms * 3. All advertising materials mentioning features or use of this software
15127664Sbms *    must display the following acknowledgement:
16127664Sbms *	This product includes software developed by the Computer Systems
17127664Sbms *	Engineering Group at Lawrence Berkeley Laboratory.
18127664Sbms * 4. Neither the name of the University nor of the Laboratory may be used
19127664Sbms *    to endorse or promote products derived from this software without
20127664Sbms *    specific prior written permission.
21127664Sbms *
22127664Sbms * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23127664Sbms * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24127664Sbms * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25127664Sbms * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26127664Sbms * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27127664Sbms * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28127664Sbms * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29127664Sbms * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30127664Sbms * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31127664Sbms * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32127664Sbms * SUCH DAMAGE.
33127664Sbms */
34127664Sbms
35127664Sbms#ifndef lint
36127664Sbmsstatic const char rcsid[] _U_ =
37214518Srpaulo    "@(#) $Header: /tcpdump/master/libpcap/fad-gifc.c,v 1.12 2008-08-06 07:34:09 guy Exp $ (LBL)";
38127664Sbms#endif
39127664Sbms
40127664Sbms#ifdef HAVE_CONFIG_H
41127664Sbms#include "config.h"
42127664Sbms#endif
43127664Sbms
44127664Sbms#include <sys/param.h>
45127664Sbms#include <sys/ioctl.h>
46127664Sbms#include <sys/socket.h>
47127664Sbms#ifdef HAVE_SYS_SOCKIO_H
48127664Sbms#include <sys/sockio.h>
49127664Sbms#endif
50127664Sbms#include <sys/time.h>				/* concession to AIX */
51127664Sbms
52127664Sbmsstruct mbuf;		/* Squelch compiler warnings on some platforms for */
53127664Sbmsstruct rtentry;		/* declarations in <net/if.h> */
54127664Sbms#include <net/if.h>
55127664Sbms#include <netinet/in.h>
56127664Sbms
57127664Sbms#include <ctype.h>
58127664Sbms#include <errno.h>
59127664Sbms#include <memory.h>
60127664Sbms#include <stdio.h>
61127664Sbms#include <stdlib.h>
62127664Sbms#include <string.h>
63127664Sbms#include <unistd.h>
64127664Sbms
65127664Sbms#include "pcap-int.h"
66127664Sbms
67127664Sbms#ifdef HAVE_OS_PROTO_H
68127664Sbms#include "os-proto.h"
69127664Sbms#endif
70127664Sbms
71127664Sbms/*
72127664Sbms * This is fun.
73127664Sbms *
74127664Sbms * In older BSD systems, socket addresses were fixed-length, and
75127664Sbms * "sizeof (struct sockaddr)" gave the size of the structure.
76127664Sbms * All addresses fit within a "struct sockaddr".
77127664Sbms *
78127664Sbms * In newer BSD systems, the socket address is variable-length, and
79127664Sbms * there's an "sa_len" field giving the length of the structure;
80127664Sbms * this allows socket addresses to be longer than 2 bytes of family
81127664Sbms * and 14 bytes of data.
82127664Sbms *
83127664Sbms * Some commercial UNIXes use the old BSD scheme, some use the RFC 2553
84127664Sbms * variant of the old BSD scheme (with "struct sockaddr_storage" rather
85127664Sbms * than "struct sockaddr"), and some use the new BSD scheme.
86127664Sbms *
87127664Sbms * Some versions of GNU libc use neither scheme, but has an "SA_LEN()"
88127664Sbms * macro that determines the size based on the address family.  Other
89127664Sbms * versions don't have "SA_LEN()" (as it was in drafts of RFC 2553
90127664Sbms * but not in the final version).
91127664Sbms *
92127664Sbms * We assume that a UNIX that doesn't have "getifaddrs()" and doesn't have
93127664Sbms * SIOCGLIFCONF, but has SIOCGIFCONF, uses "struct sockaddr" for the
94127664Sbms * address in an entry returned by SIOCGIFCONF.
95127664Sbms */
96127664Sbms#ifndef SA_LEN
97127664Sbms#ifdef HAVE_SOCKADDR_SA_LEN
98127664Sbms#define SA_LEN(addr)	((addr)->sa_len)
99127664Sbms#else /* HAVE_SOCKADDR_SA_LEN */
100127664Sbms#define SA_LEN(addr)	(sizeof (struct sockaddr))
101127664Sbms#endif /* HAVE_SOCKADDR_SA_LEN */
102127664Sbms#endif /* SA_LEN */
103127664Sbms
104147894Ssam/*
105147894Ssam * This is also fun.
106147894Ssam *
107147894Ssam * There is no ioctl that returns the amount of space required for all
108147894Ssam * the data that SIOCGIFCONF could return, and if a buffer is supplied
109147894Ssam * that's not large enough for all the data SIOCGIFCONF could return,
110147894Ssam * on at least some platforms it just returns the data that'd fit with
111147894Ssam * no indication that there wasn't enough room for all the data, much
112147894Ssam * less an indication of how much more room is required.
113147894Ssam *
114147894Ssam * The only way to ensure that we got all the data is to pass a buffer
115147894Ssam * large enough that the amount of space in the buffer *not* filled in
116147894Ssam * is greater than the largest possible entry.
117147894Ssam *
118147894Ssam * We assume that's "sizeof(ifreq.ifr_name)" plus 255, under the assumption
119147894Ssam * that no address is more than 255 bytes (on systems where the "sa_len"
120147894Ssam * field in a "struct sockaddr" is 1 byte, e.g. newer BSDs, that's the
121147894Ssam * case, and addresses are unlikely to be bigger than that in any case).
122147894Ssam */
123147894Ssam#define MAX_SA_LEN	255
124147894Ssam
125127664Sbms/*
126127664Sbms * Get a list of all interfaces that are up and that we can open.
127127664Sbms * Returns -1 on error, 0 otherwise.
128127664Sbms * The list, as returned through "alldevsp", may be null if no interfaces
129127664Sbms * were up and could be opened.
130127664Sbms *
131127664Sbms * This is the implementation used on platforms that have SIOCGIFCONF but
132127664Sbms * don't have any other mechanism for getting a list of interfaces.
133127664Sbms *
134127664Sbms * XXX - or platforms that have other, better mechanisms but for which
135127664Sbms * we don't yet have code to use that mechanism; I think there's a better
136251129Sdelphij * way on Linux, for example, but if that better way is "getifaddrs()",
137251129Sdelphij * we already have that.
138127664Sbms */
139127664Sbmsint
140251129Sdelphijpcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf)
141127664Sbms{
142127664Sbms	pcap_if_t *devlist = NULL;
143127664Sbms	register int fd;
144127664Sbms	register struct ifreq *ifrp, *ifend, *ifnext;
145127664Sbms	int n;
146127664Sbms	struct ifconf ifc;
147127664Sbms	char *buf = NULL;
148127664Sbms	unsigned buf_size;
149147894Ssam#if defined (HAVE_SOLARIS) || defined (HAVE_HPUX10_20_OR_LATER)
150146768Ssam	char *p, *q;
151146768Ssam#endif
152127664Sbms	struct ifreq ifrflags, ifrnetmask, ifrbroadaddr, ifrdstaddr;
153127664Sbms	struct sockaddr *netmask, *broadaddr, *dstaddr;
154127664Sbms	size_t netmask_size, broadaddr_size, dstaddr_size;
155127664Sbms	int ret = 0;
156127664Sbms
157127664Sbms	/*
158127664Sbms	 * Create a socket from which to fetch the list of interfaces.
159127664Sbms	 */
160127664Sbms	fd = socket(AF_INET, SOCK_DGRAM, 0);
161127664Sbms	if (fd < 0) {
162127664Sbms		(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
163127664Sbms		    "socket: %s", pcap_strerror(errno));
164127664Sbms		return (-1);
165127664Sbms	}
166127664Sbms
167127664Sbms	/*
168127664Sbms	 * Start with an 8K buffer, and keep growing the buffer until
169147894Ssam	 * we have more than "sizeof(ifrp->ifr_name) + MAX_SA_LEN"
170147894Ssam	 * bytes left over in the buffer or we fail to get the
171147894Ssam	 * interface list for some reason other than EINVAL (which is
172147894Ssam	 * presumed here to mean "buffer is too small").
173127664Sbms	 */
174127664Sbms	buf_size = 8192;
175127664Sbms	for (;;) {
176127664Sbms		buf = malloc(buf_size);
177127664Sbms		if (buf == NULL) {
178127664Sbms			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
179127664Sbms			    "malloc: %s", pcap_strerror(errno));
180127664Sbms			(void)close(fd);
181127664Sbms			return (-1);
182127664Sbms		}
183127664Sbms
184127664Sbms		ifc.ifc_len = buf_size;
185127664Sbms		ifc.ifc_buf = buf;
186127664Sbms		memset(buf, 0, buf_size);
187127664Sbms		if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0
188127664Sbms		    && errno != EINVAL) {
189127664Sbms			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
190127664Sbms			    "SIOCGIFCONF: %s", pcap_strerror(errno));
191127664Sbms			(void)close(fd);
192127664Sbms			free(buf);
193127664Sbms			return (-1);
194127664Sbms		}
195147894Ssam		if (ifc.ifc_len < buf_size &&
196147894Ssam		    (buf_size - ifc.ifc_len) > sizeof(ifrp->ifr_name) + MAX_SA_LEN)
197127664Sbms			break;
198127664Sbms		free(buf);
199127664Sbms		buf_size *= 2;
200127664Sbms	}
201127664Sbms
202127664Sbms	ifrp = (struct ifreq *)buf;
203127664Sbms	ifend = (struct ifreq *)(buf + ifc.ifc_len);
204127664Sbms
205127664Sbms	for (; ifrp < ifend; ifrp = ifnext) {
206127664Sbms		/*
207127664Sbms		 * XXX - what if this isn't an IPv4 address?  Can
208127664Sbms		 * we still get the netmask, etc. with ioctls on
209127664Sbms		 * an IPv4 socket?
210127664Sbms		 *
211127664Sbms		 * The answer is probably platform-dependent, and
212127664Sbms		 * if the answer is "no" on more than one platform,
213127664Sbms		 * the way you work around it is probably platform-
214127664Sbms		 * dependent as well.
215127664Sbms		 */
216127664Sbms		n = SA_LEN(&ifrp->ifr_addr) + sizeof(ifrp->ifr_name);
217127664Sbms		if (n < sizeof(*ifrp))
218127664Sbms			ifnext = ifrp + 1;
219127664Sbms		else
220127664Sbms			ifnext = (struct ifreq *)((char *)ifrp + n);
221127664Sbms
222127664Sbms		/*
223146768Ssam		 * XXX - The 32-bit compatibility layer for Linux on IA-64
224146768Ssam		 * is slightly broken. It correctly converts the structures
225146768Ssam		 * to and from kernel land from 64 bit to 32 bit but
226146768Ssam		 * doesn't update ifc.ifc_len, leaving it larger than the
227146768Ssam		 * amount really used. This means we read off the end
228146768Ssam		 * of the buffer and encounter an interface with an
229146768Ssam		 * "empty" name. Since this is highly unlikely to ever
230146768Ssam		 * occur in a valid case we can just finish looking for
231146768Ssam		 * interfaces if we see an empty name.
232146768Ssam		 */
233146768Ssam		if (!(*ifrp->ifr_name))
234146768Ssam			break;
235146768Ssam
236146768Ssam		/*
237146768Ssam		 * Skip entries that begin with "dummy".
238146768Ssam		 * XXX - what are these?  Is this Linux-specific?
239146768Ssam		 * Are there platforms on which we shouldn't do this?
240146768Ssam		 */
241146768Ssam		if (strncmp(ifrp->ifr_name, "dummy", 5) == 0)
242146768Ssam			continue;
243146768Ssam
244146768Ssam		/*
245127664Sbms		 * Get the flags for this interface, and skip it if it's
246127664Sbms		 * not up.
247127664Sbms		 */
248127664Sbms		strncpy(ifrflags.ifr_name, ifrp->ifr_name,
249127664Sbms		    sizeof(ifrflags.ifr_name));
250127664Sbms		if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifrflags) < 0) {
251127664Sbms			if (errno == ENXIO)
252127664Sbms				continue;
253127664Sbms			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
254127664Sbms			    "SIOCGIFFLAGS: %.*s: %s",
255127664Sbms			    (int)sizeof(ifrflags.ifr_name),
256127664Sbms			    ifrflags.ifr_name,
257127664Sbms			    pcap_strerror(errno));
258127664Sbms			ret = -1;
259127664Sbms			break;
260127664Sbms		}
261127664Sbms		if (!(ifrflags.ifr_flags & IFF_UP))
262127664Sbms			continue;
263127664Sbms
264127664Sbms		/*
265127664Sbms		 * Get the netmask for this address on this interface.
266127664Sbms		 */
267127664Sbms		strncpy(ifrnetmask.ifr_name, ifrp->ifr_name,
268127664Sbms		    sizeof(ifrnetmask.ifr_name));
269127664Sbms		memcpy(&ifrnetmask.ifr_addr, &ifrp->ifr_addr,
270127664Sbms		    sizeof(ifrnetmask.ifr_addr));
271127664Sbms		if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifrnetmask) < 0) {
272127664Sbms			if (errno == EADDRNOTAVAIL) {
273127664Sbms				/*
274127664Sbms				 * Not available.
275127664Sbms				 */
276127664Sbms				netmask = NULL;
277127664Sbms				netmask_size = 0;
278127664Sbms			} else {
279127664Sbms				(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
280127664Sbms				    "SIOCGIFNETMASK: %.*s: %s",
281127664Sbms				    (int)sizeof(ifrnetmask.ifr_name),
282127664Sbms				    ifrnetmask.ifr_name,
283127664Sbms				    pcap_strerror(errno));
284127664Sbms				ret = -1;
285127664Sbms				break;
286127664Sbms			}
287127664Sbms		} else {
288127664Sbms			netmask = &ifrnetmask.ifr_addr;
289127664Sbms			netmask_size = SA_LEN(netmask);
290127664Sbms		}
291127664Sbms
292127664Sbms		/*
293127664Sbms		 * Get the broadcast address for this address on this
294127664Sbms		 * interface (if any).
295127664Sbms		 */
296127664Sbms		if (ifrflags.ifr_flags & IFF_BROADCAST) {
297127664Sbms			strncpy(ifrbroadaddr.ifr_name, ifrp->ifr_name,
298127664Sbms			    sizeof(ifrbroadaddr.ifr_name));
299127664Sbms			memcpy(&ifrbroadaddr.ifr_addr, &ifrp->ifr_addr,
300127664Sbms			    sizeof(ifrbroadaddr.ifr_addr));
301127664Sbms			if (ioctl(fd, SIOCGIFBRDADDR,
302127664Sbms			    (char *)&ifrbroadaddr) < 0) {
303127664Sbms				if (errno == EADDRNOTAVAIL) {
304127664Sbms					/*
305127664Sbms					 * Not available.
306127664Sbms					 */
307127664Sbms					broadaddr = NULL;
308127664Sbms					broadaddr_size = 0;
309127664Sbms				} else {
310127664Sbms					(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
311127664Sbms					    "SIOCGIFBRDADDR: %.*s: %s",
312127664Sbms					    (int)sizeof(ifrbroadaddr.ifr_name),
313127664Sbms					    ifrbroadaddr.ifr_name,
314127664Sbms					    pcap_strerror(errno));
315127664Sbms					ret = -1;
316127664Sbms					break;
317127664Sbms				}
318127664Sbms			} else {
319127664Sbms				broadaddr = &ifrbroadaddr.ifr_broadaddr;
320127664Sbms				broadaddr_size = SA_LEN(broadaddr);
321127664Sbms			}
322127664Sbms		} else {
323127664Sbms			/*
324127664Sbms			 * Not a broadcast interface, so no broadcast
325127664Sbms			 * address.
326127664Sbms			 */
327127664Sbms			broadaddr = NULL;
328127664Sbms			broadaddr_size = 0;
329127664Sbms		}
330127664Sbms
331127664Sbms		/*
332127664Sbms		 * Get the destination address for this address on this
333127664Sbms		 * interface (if any).
334127664Sbms		 */
335127664Sbms		if (ifrflags.ifr_flags & IFF_POINTOPOINT) {
336127664Sbms			strncpy(ifrdstaddr.ifr_name, ifrp->ifr_name,
337127664Sbms			    sizeof(ifrdstaddr.ifr_name));
338127664Sbms			memcpy(&ifrdstaddr.ifr_addr, &ifrp->ifr_addr,
339127664Sbms			    sizeof(ifrdstaddr.ifr_addr));
340127664Sbms			if (ioctl(fd, SIOCGIFDSTADDR,
341127664Sbms			    (char *)&ifrdstaddr) < 0) {
342127664Sbms				if (errno == EADDRNOTAVAIL) {
343127664Sbms					/*
344127664Sbms					 * Not available.
345127664Sbms					 */
346127664Sbms					dstaddr = NULL;
347127664Sbms					dstaddr_size = 0;
348127664Sbms				} else {
349127664Sbms					(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
350127664Sbms					    "SIOCGIFDSTADDR: %.*s: %s",
351127664Sbms					    (int)sizeof(ifrdstaddr.ifr_name),
352127664Sbms					    ifrdstaddr.ifr_name,
353127664Sbms					    pcap_strerror(errno));
354127664Sbms					ret = -1;
355127664Sbms					break;
356127664Sbms				}
357127664Sbms			} else {
358127664Sbms				dstaddr = &ifrdstaddr.ifr_dstaddr;
359127664Sbms				dstaddr_size = SA_LEN(dstaddr);
360127664Sbms			}
361127664Sbms		} else {
362127664Sbms			/*
363127664Sbms			 * Not a point-to-point interface, so no destination
364127664Sbms			 * address.
365127664Sbms			 */
366127664Sbms			dstaddr = NULL;
367127664Sbms			dstaddr_size = 0;
368127664Sbms		}
369127664Sbms
370147894Ssam#if defined (HAVE_SOLARIS) || defined (HAVE_HPUX10_20_OR_LATER)
371127664Sbms		/*
372146768Ssam		 * If this entry has a colon followed by a number at
373146768Ssam		 * the end, it's a logical interface.  Those are just
374146768Ssam		 * the way you assign multiple IP addresses to a real
375146768Ssam		 * interface, so an entry for a logical interface should
376146768Ssam		 * be treated like the entry for the real interface;
377146768Ssam		 * we do that by stripping off the ":" and the number.
378146768Ssam		 */
379146768Ssam		p = strchr(ifrp->ifr_name, ':');
380146768Ssam		if (p != NULL) {
381146768Ssam			/*
382146768Ssam			 * We have a ":"; is it followed by a number?
383146768Ssam			 */
384146768Ssam			q = p + 1;
385146768Ssam			while (isdigit((unsigned char)*q))
386146768Ssam				q++;
387146768Ssam			if (*q == '\0') {
388146768Ssam				/*
389146768Ssam				 * All digits after the ":" until the end.
390146768Ssam				 * Strip off the ":" and everything after
391146768Ssam				 * it.
392146768Ssam				 */
393146768Ssam				*p = '\0';
394146768Ssam			}
395146768Ssam		}
396146768Ssam#endif
397146768Ssam
398146768Ssam		/*
399127664Sbms		 * Add information for this address to the list.
400127664Sbms		 */
401127664Sbms		if (add_addr_to_iflist(&devlist, ifrp->ifr_name,
402127664Sbms		    ifrflags.ifr_flags, &ifrp->ifr_addr,
403127664Sbms		    SA_LEN(&ifrp->ifr_addr), netmask, netmask_size,
404127664Sbms		    broadaddr, broadaddr_size, dstaddr, dstaddr_size,
405127664Sbms		    errbuf) < 0) {
406127664Sbms			ret = -1;
407127664Sbms			break;
408127664Sbms		}
409127664Sbms	}
410127664Sbms	free(buf);
411127664Sbms	(void)close(fd);
412127664Sbms
413127664Sbms	if (ret == -1) {
414127664Sbms		/*
415127664Sbms		 * We had an error; free the list we've been constructing.
416127664Sbms		 */
417127664Sbms		if (devlist != NULL) {
418127664Sbms			pcap_freealldevs(devlist);
419127664Sbms			devlist = NULL;
420127664Sbms		}
421127664Sbms	}
422127664Sbms
423127664Sbms	*alldevsp = devlist;
424127664Sbms	return (ret);
425127664Sbms}
426