fad-glifc.c revision 127664
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
12146768Ssam *    notice, this list of conditions and the following disclaimer in the
13162012Ssam *    documentation and/or other materials provided with the distribution.
14162012Ssam * 3. All advertising materials mentioning features or use of this software
15162012Ssam *    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
20214518Srpaulo *    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_ =
37127664Sbms    "@(#) $Header: /tcpdump/master/libpcap/fad-glifc.c,v 1.2.2.1 2003/11/15 23:26:39 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>
46146768Ssam#include <sys/ioctl.h>
47146768Ssam#include <sys/socket.h>
48127664Sbms#ifdef HAVE_SYS_SOCKIO_H
49190225Srpaulo#include <sys/sockio.h>
50190225Srpaulo#endif
51251129Sdelphij#include <sys/time.h>				/* concession to AIX */
52251129Sdelphij
53251129Sdelphijstruct mbuf;		/* Squelch compiler warnings on some platforms for */
54251129Sdelphijstruct rtentry;		/* declarations in <net/if.h> */
55251129Sdelphij#include <net/if.h>
56251129Sdelphij#include <netinet/in.h>
57146768Ssam
58146768Ssam#include <ctype.h>
59127664Sbms#include <errno.h>
60172677Smlaier#include <memory.h>
61172677Smlaier#include <stdio.h>
62172677Smlaier#include <stdlib.h>
63172677Smlaier#include <string.h>
64172677Smlaier#include <unistd.h>
65172677Smlaier
66172677Smlaier#include "pcap-int.h"
67172677Smlaier
68172677Smlaier#ifdef HAVE_OS_PROTO_H
69172677Smlaier#include "os-proto.h"
70172677Smlaier#endif
71172677Smlaier
72146768Ssam/*
73146768Ssam * Get a list of all interfaces that are up and that we can open.
74146768Ssam * Returns -1 on error, 0 otherwise.
75146768Ssam * The list, as returned through "alldevsp", may be null if no interfaces
76146768Ssam * were up and could be opened.
77146768Ssam *
78146768Ssam * This is the implementation used on platforms that have SIOCLGIFCONF
79127664Sbms * but don't have "getifaddrs()".  (Solaris 8 and later; we use
80146768Ssam * SIOCLGIFCONF rather than SIOCGIFCONF in order to get IPv6 addresses.)
81146768Ssam */
82146768Ssamint
83127664Sbmspcap_findalldevs(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;
91172677Smlaier	unsigned buf_size;
92172677Smlaier	struct lifreq ifrflags, ifrnetmask, ifrbroadaddr, ifrdstaddr;
93172677Smlaier	struct sockaddr *netmask, *broadaddr, *dstaddr;
94172677Smlaier	int ret = 0;
95127664Sbms
96127664Sbms	/*
97127664Sbms	 * Create a socket from which to fetch the list of interfaces,
98127664Sbms	 * and from which to fetch IPv4 information.
99127664Sbms	 */
100127664Sbms	fd4 = socket(AF_INET, SOCK_DGRAM, 0);
101146768Ssam	if (fd4 < 0) {
102146768Ssam		(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
103146768Ssam		    "socket: %s", pcap_strerror(errno));
104146768Ssam		return (-1);
105127664Sbms	}
106146768Ssam
107146768Ssam	/*
108146768Ssam	 * Create a socket from which to fetch IPv6 information.
109127664Sbms	 */
110146768Ssam	fd6 = socket(AF_INET6, SOCK_DGRAM, 0);
111146768Ssam	if (fd6 < 0) {
112146768Ssam		(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
113146768Ssam		    "socket: %s", pcap_strerror(errno));
114146768Ssam		(void)close(fd4);
115146768Ssam		return (-1);
116146768Ssam	}
117127664Sbms
118127664Sbms	/*
119127664Sbms	 * How many entries will SIOCGLIFCONF return?
120127664Sbms	 */
121127664Sbms	ifn.lifn_family = AF_UNSPEC;
122127664Sbms	ifn.lifn_flags = 0;
123127664Sbms	ifn.lifn_count = 0;
124146768Ssam	if (ioctl(fd4, SIOCGLIFNUM, (char *)&ifn) < 0) {
125190225Srpaulo		(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
126146768Ssam		    "SIOCGLIFNUM: %s", pcap_strerror(errno));
127162012Ssam		(void)close(fd6);
128162012Ssam		(void)close(fd4);
129162012Ssam		return (-1);
130162012Ssam	}
131162012Ssam
132146768Ssam	/*
133162012Ssam	 * Allocate a buffer for those entries.
134162012Ssam	 */
135127664Sbms	buf_size = ifn.lifn_count * sizeof (struct lifreq);
136146768Ssam	buf = malloc(buf_size);
137146768Ssam	if (buf == NULL) {
138162012Ssam		(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
139190225Srpaulo		    "malloc: %s", pcap_strerror(errno));
140190225Srpaulo		(void)close(fd6);
141190225Srpaulo		(void)close(fd4);
142190225Srpaulo		return (-1);
143190225Srpaulo	}
144190225Srpaulo
145190225Srpaulo	/*
146146768Ssam	 * Get the entries.
147146768Ssam	 */
148127664Sbms	ifc.lifc_len = buf_size;
149127664Sbms	ifc.lifc_buf = buf;
150146768Ssam	ifc.lifc_family = AF_UNSPEC;
151146768Ssam	ifc.lifc_flags = 0;
152146768Ssam	memset(buf, 0, buf_size);
153146768Ssam	if (ioctl(fd4, SIOCGLIFCONF, (char *)&ifc) < 0) {
154146768Ssam		(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
155190225Srpaulo		    "SIOCGLIFCONF: %s", pcap_strerror(errno));
156146768Ssam		(void)close(fd6);
157146768Ssam		(void)close(fd4);
158146768Ssam		free(buf);
159146768Ssam		return (-1);
160127664Sbms	}
161127664Sbms
162146768Ssam	/*
163146768Ssam	 * Loop over the entries.
164146768Ssam	 */
165146768Ssam	ifrp = (struct lifreq *)buf;
166127664Sbms	ifend = (struct lifreq *)(buf + ifc.lifc_len);
167146768Ssam
168146768Ssam	for (; ifrp < ifend; ifrp++) {
169146768Ssam		/*
170127664Sbms		 * IPv6 or not?
171146768Ssam		 */
172146768Ssam		if (((struct sockaddr *)&ifrp->lifr_addr)->sa_family == AF_INET6)
173146768Ssam			fd = fd6;
174146768Ssam		else
175127664Sbms			fd = fd4;
176146768Ssam
177146768Ssam		/*
178146768Ssam		 * Get the flags for this interface, and skip it if it's
179127664Sbms		 * not up.
180146768Ssam		 */
181127664Sbms		strncpy(ifrflags.lifr_name, ifrp->lifr_name,
182146768Ssam		    sizeof(ifrflags.lifr_name));
183127664Sbms		if (ioctl(fd, SIOCGLIFFLAGS, (char *)&ifrflags) < 0) {
184127664Sbms			if (errno == ENXIO)
185190225Srpaulo				continue;
186190225Srpaulo			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
187190225Srpaulo			    "SIOCGLIFFLAGS: %.*s: %s",
188190225Srpaulo			    (int)sizeof(ifrflags.lifr_name),
189190225Srpaulo			    ifrflags.lifr_name,
190190225Srpaulo			    pcap_strerror(errno));
191190225Srpaulo			ret = -1;
192190225Srpaulo			break;
193190225Srpaulo		}
194190225Srpaulo		if (!(ifrflags.lifr_flags & IFF_UP))
195190225Srpaulo			continue;
196190225Srpaulo
197190225Srpaulo		/*
198190225Srpaulo		 * Get the netmask for this address on this interface.
199190225Srpaulo		 */
200190225Srpaulo		strncpy(ifrnetmask.lifr_name, ifrp->lifr_name,
201190225Srpaulo		    sizeof(ifrnetmask.lifr_name));
202190225Srpaulo		memcpy(&ifrnetmask.lifr_addr, &ifrp->lifr_addr,
203190225Srpaulo		    sizeof(ifrnetmask.lifr_addr));
204190225Srpaulo		if (ioctl(fd, SIOCGLIFNETMASK, (char *)&ifrnetmask) < 0) {
205190225Srpaulo			if (errno == EADDRNOTAVAIL) {
206190225Srpaulo				/*
207190225Srpaulo				 * Not available.
208190225Srpaulo				 */
209190225Srpaulo				netmask = NULL;
210190225Srpaulo			} else {
211190225Srpaulo				(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
212190225Srpaulo				    "SIOCGLIFNETMASK: %.*s: %s",
213190225Srpaulo				    (int)sizeof(ifrnetmask.lifr_name),
214190225Srpaulo				    ifrnetmask.lifr_name,
215190225Srpaulo				    pcap_strerror(errno));
216190225Srpaulo				ret = -1;
217127664Sbms				break;
218127664Sbms			}
219127664Sbms		} else
220127664Sbms			netmask = (struct sockaddr *)&ifrnetmask.lifr_addr;
221127664Sbms
222146768Ssam		/*
223146768Ssam		 * Get the broadcast address for this address on this
224146768Ssam		 * interface (if any).
225127664Sbms		 */
226127664Sbms		if (ifrflags.lifr_flags & IFF_BROADCAST) {
227127664Sbms			strncpy(ifrbroadaddr.lifr_name, ifrp->lifr_name,
228190225Srpaulo			    sizeof(ifrbroadaddr.lifr_name));
229127664Sbms			memcpy(&ifrbroadaddr.lifr_addr, &ifrp->lifr_addr,
230162012Ssam			    sizeof(ifrbroadaddr.lifr_addr));
231162012Ssam			if (ioctl(fd, SIOCGLIFBRDADDR,
232127664Sbms			    (char *)&ifrbroadaddr) < 0) {
233162012Ssam				if (errno == EADDRNOTAVAIL) {
234162012Ssam					/*
235162012Ssam					 * Not available.
236162012Ssam					 */
237127664Sbms					broadaddr = NULL;
238162012Ssam				} else {
239162012Ssam					(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
240162012Ssam					    "SIOCGLIFBRDADDR: %.*s: %s",
241127664Sbms					    (int)sizeof(ifrbroadaddr.lifr_name),
242162012Ssam					    ifrbroadaddr.lifr_name,
243162012Ssam					    pcap_strerror(errno));
244162012Ssam					ret = -1;
245127664Sbms					break;
246162012Ssam				}
247162012Ssam			} else
248162012Ssam				broadaddr = (struct sockaddr *)&ifrbroadaddr.lifr_broadaddr;
249162012Ssam		} else {
250162012Ssam			/*
251162012Ssam			 * Not a broadcast interface, so no broadcast
252162012Ssam			 * address.
253162012Ssam			 */
254162012Ssam			broadaddr = NULL;
255162012Ssam		}
256162012Ssam
257162012Ssam		/*
258190225Srpaulo		 * Get the destination address for this address on this
259190225Srpaulo		 * interface (if any).
260190225Srpaulo		 */
261162012Ssam		if (ifrflags.lifr_flags & IFF_POINTOPOINT) {
262162012Ssam			strncpy(ifrdstaddr.lifr_name, ifrp->lifr_name,
263162012Ssam			    sizeof(ifrdstaddr.lifr_name));
264162012Ssam			memcpy(&ifrdstaddr.lifr_addr, &ifrp->lifr_addr,
265162012Ssam			    sizeof(ifrdstaddr.lifr_addr));
266162012Ssam			if (ioctl(fd, SIOCGLIFDSTADDR,
267162012Ssam			    (char *)&ifrdstaddr) < 0) {
268162012Ssam				if (errno == EADDRNOTAVAIL) {
269162012Ssam					/*
270127664Sbms					 * Not available.
271162012Ssam					 */
272162012Ssam					dstaddr = NULL;
273162012Ssam				} else {
274162012Ssam					(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
275162012Ssam					    "SIOCGLIFDSTADDR: %.*s: %s",
276162012Ssam					    (int)sizeof(ifrdstaddr.lifr_name),
277162012Ssam					    ifrdstaddr.lifr_name,
278162012Ssam					    pcap_strerror(errno));
279162012Ssam					ret = -1;
280162012Ssam					break;
281146768Ssam				}
282162012Ssam			} else
283162012Ssam				dstaddr = (struct sockaddr *)&ifrdstaddr.lifr_dstaddr;
284190225Srpaulo		} else
285162012Ssam			dstaddr = NULL;
286162012Ssam
287162012Ssam		/*
288190225Srpaulo		 * Add information for this address to the list.
289162012Ssam		 */
290162012Ssam		if (add_addr_to_iflist(&devlist, ifrp->lifr_name,
291162012Ssam		    ifrflags.lifr_flags, (struct sockaddr *)&ifrp->lifr_addr,
292162012Ssam		    sizeof (struct sockaddr_storage),
293162012Ssam		    netmask, sizeof (struct sockaddr_storage),
294162012Ssam		    broadaddr, sizeof (struct sockaddr_storage),
295190225Srpaulo		    dstaddr, sizeof (struct sockaddr_storage), errbuf) < 0) {
296162012Ssam			ret = -1;
297127664Sbms			break;
298162012Ssam		}
299162012Ssam	}
300162012Ssam	free(buf);
301162012Ssam	(void)close(fd6);
302127664Sbms	(void)close(fd4);
303162012Ssam
304162012Ssam	if (ret != -1) {
305162012Ssam		/*
306127664Sbms		 * We haven't had any errors yet; do any platform-specific
307162012Ssam		 * operations to add devices.
308162012Ssam		 */
309162012Ssam		if (pcap_platform_finddevs(&devlist, errbuf) < 0)
310127664Sbms			ret = -1;
311162012Ssam	}
312162012Ssam
313162012Ssam	if (ret == -1) {
314162012Ssam		/*
315162012Ssam		 * We had an error; free the list we've been constructing.
316162012Ssam		 */
317162012Ssam		if (devlist != NULL) {
318162012Ssam			pcap_freealldevs(devlist);
319162012Ssam			devlist = NULL;
320190225Srpaulo		}
321190225Srpaulo	}
322162012Ssam
323162012Ssam	*alldevsp = devlist;
324172677Smlaier	return (ret);
325172677Smlaier}
326172677Smlaier