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-glifc.c,v 1.7 2008-01-30 09:35:48 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/file.h>
46127664Sbms#include <sys/ioctl.h>
47127664Sbms#include <sys/socket.h>
48127664Sbms#ifdef HAVE_SYS_SOCKIO_H
49127664Sbms#include <sys/sockio.h>
50127664Sbms#endif
51127664Sbms#include <sys/time.h>				/* concession to AIX */
52127664Sbms
53127664Sbmsstruct mbuf;		/* Squelch compiler warnings on some platforms for */
54127664Sbmsstruct rtentry;		/* declarations in <net/if.h> */
55127664Sbms#include <net/if.h>
56127664Sbms#include <netinet/in.h>
57127664Sbms
58127664Sbms#include <ctype.h>
59127664Sbms#include <errno.h>
60127664Sbms#include <memory.h>
61127664Sbms#include <stdio.h>
62127664Sbms#include <stdlib.h>
63127664Sbms#include <string.h>
64127664Sbms#include <unistd.h>
65127664Sbms
66127664Sbms#include "pcap-int.h"
67127664Sbms
68127664Sbms#ifdef HAVE_OS_PROTO_H
69127664Sbms#include "os-proto.h"
70127664Sbms#endif
71127664Sbms
72127664Sbms/*
73127664Sbms * Get a list of all interfaces that are up and that we can open.
74127664Sbms * Returns -1 on error, 0 otherwise.
75127664Sbms * The list, as returned through "alldevsp", may be null if no interfaces
76127664Sbms * were up and could be opened.
77127664Sbms *
78190225Srpaulo * This is the implementation used on platforms that have SIOCGLIFCONF
79127664Sbms * but don't have "getifaddrs()".  (Solaris 8 and later; we use
80190225Srpaulo * SIOCGLIFCONF rather than SIOCGIFCONF in order to get IPv6 addresses.)
81127664Sbms */
82127664Sbmsint
83251129Sdelphijpcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf)
84127664Sbms{
85127664Sbms	pcap_if_t *devlist = NULL;
86127664Sbms	register int fd4, fd6, fd;
87127664Sbms	register struct lifreq *ifrp, *ifend;
88127664Sbms	struct lifnum ifn;
89127664Sbms	struct lifconf ifc;
90127664Sbms	char *buf = NULL;
91127664Sbms	unsigned buf_size;
92146768Ssam#ifdef HAVE_SOLARIS
93146768Ssam	char *p, *q;
94146768Ssam#endif
95127664Sbms	struct lifreq ifrflags, ifrnetmask, ifrbroadaddr, ifrdstaddr;
96127664Sbms	struct sockaddr *netmask, *broadaddr, *dstaddr;
97127664Sbms	int ret = 0;
98127664Sbms
99127664Sbms	/*
100127664Sbms	 * Create a socket from which to fetch the list of interfaces,
101127664Sbms	 * and from which to fetch IPv4 information.
102127664Sbms	 */
103127664Sbms	fd4 = socket(AF_INET, SOCK_DGRAM, 0);
104127664Sbms	if (fd4 < 0) {
105127664Sbms		(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
106127664Sbms		    "socket: %s", pcap_strerror(errno));
107127664Sbms		return (-1);
108127664Sbms	}
109127664Sbms
110127664Sbms	/*
111127664Sbms	 * Create a socket from which to fetch IPv6 information.
112127664Sbms	 */
113127664Sbms	fd6 = socket(AF_INET6, SOCK_DGRAM, 0);
114127664Sbms	if (fd6 < 0) {
115127664Sbms		(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
116127664Sbms		    "socket: %s", pcap_strerror(errno));
117127664Sbms		(void)close(fd4);
118127664Sbms		return (-1);
119127664Sbms	}
120127664Sbms
121127664Sbms	/*
122127664Sbms	 * How many entries will SIOCGLIFCONF return?
123127664Sbms	 */
124127664Sbms	ifn.lifn_family = AF_UNSPEC;
125127664Sbms	ifn.lifn_flags = 0;
126127664Sbms	ifn.lifn_count = 0;
127127664Sbms	if (ioctl(fd4, SIOCGLIFNUM, (char *)&ifn) < 0) {
128127664Sbms		(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
129127664Sbms		    "SIOCGLIFNUM: %s", pcap_strerror(errno));
130127664Sbms		(void)close(fd6);
131127664Sbms		(void)close(fd4);
132127664Sbms		return (-1);
133127664Sbms	}
134127664Sbms
135127664Sbms	/*
136127664Sbms	 * Allocate a buffer for those entries.
137127664Sbms	 */
138127664Sbms	buf_size = ifn.lifn_count * sizeof (struct lifreq);
139127664Sbms	buf = malloc(buf_size);
140127664Sbms	if (buf == NULL) {
141127664Sbms		(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
142127664Sbms		    "malloc: %s", pcap_strerror(errno));
143127664Sbms		(void)close(fd6);
144127664Sbms		(void)close(fd4);
145127664Sbms		return (-1);
146127664Sbms	}
147127664Sbms
148127664Sbms	/*
149127664Sbms	 * Get the entries.
150127664Sbms	 */
151127664Sbms	ifc.lifc_len = buf_size;
152127664Sbms	ifc.lifc_buf = buf;
153127664Sbms	ifc.lifc_family = AF_UNSPEC;
154127664Sbms	ifc.lifc_flags = 0;
155127664Sbms	memset(buf, 0, buf_size);
156127664Sbms	if (ioctl(fd4, SIOCGLIFCONF, (char *)&ifc) < 0) {
157127664Sbms		(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
158127664Sbms		    "SIOCGLIFCONF: %s", pcap_strerror(errno));
159127664Sbms		(void)close(fd6);
160127664Sbms		(void)close(fd4);
161127664Sbms		free(buf);
162127664Sbms		return (-1);
163127664Sbms	}
164127664Sbms
165127664Sbms	/*
166127664Sbms	 * Loop over the entries.
167127664Sbms	 */
168127664Sbms	ifrp = (struct lifreq *)buf;
169127664Sbms	ifend = (struct lifreq *)(buf + ifc.lifc_len);
170127664Sbms
171127664Sbms	for (; ifrp < ifend; ifrp++) {
172127664Sbms		/*
173127664Sbms		 * IPv6 or not?
174127664Sbms		 */
175127664Sbms		if (((struct sockaddr *)&ifrp->lifr_addr)->sa_family == AF_INET6)
176127664Sbms			fd = fd6;
177127664Sbms		else
178127664Sbms			fd = fd4;
179127664Sbms
180127664Sbms		/*
181146768Ssam		 * Skip entries that begin with "dummy".
182146768Ssam		 * XXX - what are these?  Is this Linux-specific?
183146768Ssam		 * Are there platforms on which we shouldn't do this?
184146768Ssam		 */
185146768Ssam		if (strncmp(ifrp->lifr_name, "dummy", 5) == 0)
186146768Ssam			continue;
187146768Ssam
188146768Ssam#ifdef HAVE_SOLARIS
189146768Ssam		/*
190146768Ssam		 * Skip entries that have a ":" followed by a number
191146768Ssam		 * at the end - those are Solaris virtual interfaces
192146768Ssam		 * on which you can't capture.
193146768Ssam		 */
194146768Ssam		p = strchr(ifrp->lifr_name, ':');
195146768Ssam		if (p != NULL) {
196146768Ssam			/*
197146768Ssam			 * We have a ":"; is it followed by a number?
198146768Ssam			 */
199146768Ssam			while (isdigit((unsigned char)*p))
200146768Ssam				p++;
201146768Ssam			if (*p == '\0') {
202146768Ssam				/*
203146768Ssam				 * All digits after the ":" until the end.
204146768Ssam				 */
205146768Ssam				continue;
206146768Ssam			}
207146768Ssam		}
208146768Ssam#endif
209146768Ssam
210146768Ssam		/*
211127664Sbms		 * Get the flags for this interface, and skip it if it's
212127664Sbms		 * not up.
213127664Sbms		 */
214127664Sbms		strncpy(ifrflags.lifr_name, ifrp->lifr_name,
215127664Sbms		    sizeof(ifrflags.lifr_name));
216127664Sbms		if (ioctl(fd, SIOCGLIFFLAGS, (char *)&ifrflags) < 0) {
217127664Sbms			if (errno == ENXIO)
218127664Sbms				continue;
219127664Sbms			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
220127664Sbms			    "SIOCGLIFFLAGS: %.*s: %s",
221127664Sbms			    (int)sizeof(ifrflags.lifr_name),
222127664Sbms			    ifrflags.lifr_name,
223127664Sbms			    pcap_strerror(errno));
224127664Sbms			ret = -1;
225127664Sbms			break;
226127664Sbms		}
227127664Sbms		if (!(ifrflags.lifr_flags & IFF_UP))
228127664Sbms			continue;
229127664Sbms
230127664Sbms		/*
231127664Sbms		 * Get the netmask for this address on this interface.
232127664Sbms		 */
233127664Sbms		strncpy(ifrnetmask.lifr_name, ifrp->lifr_name,
234127664Sbms		    sizeof(ifrnetmask.lifr_name));
235127664Sbms		memcpy(&ifrnetmask.lifr_addr, &ifrp->lifr_addr,
236127664Sbms		    sizeof(ifrnetmask.lifr_addr));
237127664Sbms		if (ioctl(fd, SIOCGLIFNETMASK, (char *)&ifrnetmask) < 0) {
238127664Sbms			if (errno == EADDRNOTAVAIL) {
239127664Sbms				/*
240127664Sbms				 * Not available.
241127664Sbms				 */
242127664Sbms				netmask = NULL;
243127664Sbms			} else {
244127664Sbms				(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
245127664Sbms				    "SIOCGLIFNETMASK: %.*s: %s",
246127664Sbms				    (int)sizeof(ifrnetmask.lifr_name),
247127664Sbms				    ifrnetmask.lifr_name,
248127664Sbms				    pcap_strerror(errno));
249127664Sbms				ret = -1;
250127664Sbms				break;
251127664Sbms			}
252127664Sbms		} else
253127664Sbms			netmask = (struct sockaddr *)&ifrnetmask.lifr_addr;
254127664Sbms
255127664Sbms		/*
256127664Sbms		 * Get the broadcast address for this address on this
257127664Sbms		 * interface (if any).
258127664Sbms		 */
259127664Sbms		if (ifrflags.lifr_flags & IFF_BROADCAST) {
260127664Sbms			strncpy(ifrbroadaddr.lifr_name, ifrp->lifr_name,
261127664Sbms			    sizeof(ifrbroadaddr.lifr_name));
262127664Sbms			memcpy(&ifrbroadaddr.lifr_addr, &ifrp->lifr_addr,
263127664Sbms			    sizeof(ifrbroadaddr.lifr_addr));
264127664Sbms			if (ioctl(fd, SIOCGLIFBRDADDR,
265127664Sbms			    (char *)&ifrbroadaddr) < 0) {
266127664Sbms				if (errno == EADDRNOTAVAIL) {
267127664Sbms					/*
268127664Sbms					 * Not available.
269127664Sbms					 */
270127664Sbms					broadaddr = NULL;
271127664Sbms				} else {
272127664Sbms					(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
273127664Sbms					    "SIOCGLIFBRDADDR: %.*s: %s",
274127664Sbms					    (int)sizeof(ifrbroadaddr.lifr_name),
275127664Sbms					    ifrbroadaddr.lifr_name,
276127664Sbms					    pcap_strerror(errno));
277127664Sbms					ret = -1;
278127664Sbms					break;
279127664Sbms				}
280127664Sbms			} else
281127664Sbms				broadaddr = (struct sockaddr *)&ifrbroadaddr.lifr_broadaddr;
282127664Sbms		} else {
283127664Sbms			/*
284127664Sbms			 * Not a broadcast interface, so no broadcast
285127664Sbms			 * address.
286127664Sbms			 */
287127664Sbms			broadaddr = NULL;
288127664Sbms		}
289127664Sbms
290127664Sbms		/*
291127664Sbms		 * Get the destination address for this address on this
292127664Sbms		 * interface (if any).
293127664Sbms		 */
294127664Sbms		if (ifrflags.lifr_flags & IFF_POINTOPOINT) {
295127664Sbms			strncpy(ifrdstaddr.lifr_name, ifrp->lifr_name,
296127664Sbms			    sizeof(ifrdstaddr.lifr_name));
297127664Sbms			memcpy(&ifrdstaddr.lifr_addr, &ifrp->lifr_addr,
298127664Sbms			    sizeof(ifrdstaddr.lifr_addr));
299127664Sbms			if (ioctl(fd, SIOCGLIFDSTADDR,
300127664Sbms			    (char *)&ifrdstaddr) < 0) {
301127664Sbms				if (errno == EADDRNOTAVAIL) {
302127664Sbms					/*
303127664Sbms					 * Not available.
304127664Sbms					 */
305127664Sbms					dstaddr = NULL;
306127664Sbms				} else {
307127664Sbms					(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
308127664Sbms					    "SIOCGLIFDSTADDR: %.*s: %s",
309127664Sbms					    (int)sizeof(ifrdstaddr.lifr_name),
310127664Sbms					    ifrdstaddr.lifr_name,
311127664Sbms					    pcap_strerror(errno));
312127664Sbms					ret = -1;
313127664Sbms					break;
314127664Sbms				}
315127664Sbms			} else
316127664Sbms				dstaddr = (struct sockaddr *)&ifrdstaddr.lifr_dstaddr;
317127664Sbms		} else
318127664Sbms			dstaddr = NULL;
319127664Sbms
320146768Ssam#ifdef HAVE_SOLARIS
321127664Sbms		/*
322146768Ssam		 * If this entry has a colon followed by a number at
323146768Ssam		 * the end, it's a logical interface.  Those are just
324146768Ssam		 * the way you assign multiple IP addresses to a real
325146768Ssam		 * interface, so an entry for a logical interface should
326146768Ssam		 * be treated like the entry for the real interface;
327146768Ssam		 * we do that by stripping off the ":" and the number.
328146768Ssam		 */
329147894Ssam		p = strchr(ifrp->lifr_name, ':');
330146768Ssam		if (p != NULL) {
331146768Ssam			/*
332146768Ssam			 * We have a ":"; is it followed by a number?
333146768Ssam			 */
334146768Ssam			q = p + 1;
335146768Ssam			while (isdigit((unsigned char)*q))
336146768Ssam				q++;
337146768Ssam			if (*q == '\0') {
338146768Ssam				/*
339146768Ssam				 * All digits after the ":" until the end.
340146768Ssam				 * Strip off the ":" and everything after
341146768Ssam				 * it.
342146768Ssam				 */
343146768Ssam				*p = '\0';
344146768Ssam			}
345146768Ssam		}
346146768Ssam#endif
347146768Ssam
348146768Ssam		/*
349127664Sbms		 * Add information for this address to the list.
350127664Sbms		 */
351127664Sbms		if (add_addr_to_iflist(&devlist, ifrp->lifr_name,
352127664Sbms		    ifrflags.lifr_flags, (struct sockaddr *)&ifrp->lifr_addr,
353127664Sbms		    sizeof (struct sockaddr_storage),
354127664Sbms		    netmask, sizeof (struct sockaddr_storage),
355127664Sbms		    broadaddr, sizeof (struct sockaddr_storage),
356127664Sbms		    dstaddr, sizeof (struct sockaddr_storage), errbuf) < 0) {
357127664Sbms			ret = -1;
358127664Sbms			break;
359127664Sbms		}
360127664Sbms	}
361127664Sbms	free(buf);
362127664Sbms	(void)close(fd6);
363127664Sbms	(void)close(fd4);
364127664Sbms
365127664Sbms	if (ret == -1) {
366127664Sbms		/*
367127664Sbms		 * We had an error; free the list we've been constructing.
368127664Sbms		 */
369127664Sbms		if (devlist != NULL) {
370127664Sbms			pcap_freealldevs(devlist);
371127664Sbms			devlist = NULL;
372127664Sbms		}
373127664Sbms	}
374127664Sbms
375127664Sbms	*alldevsp = devlist;
376127664Sbms	return (ret);
377127664Sbms}
378