1335640Shselasky/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
2335640Shselasky/*
3335640Shselasky * Copyright (c) 1994, 1995, 1996, 1997, 1998
4335640Shselasky *	The Regents of the University of California.  All rights reserved.
5335640Shselasky *
6335640Shselasky * Redistribution and use in source and binary forms, with or without
7335640Shselasky * modification, are permitted provided that the following conditions
8335640Shselasky * are met:
9335640Shselasky * 1. Redistributions of source code must retain the above copyright
10335640Shselasky *    notice, this list of conditions and the following disclaimer.
11335640Shselasky * 2. Redistributions in binary form must reproduce the above copyright
12335640Shselasky *    notice, this list of conditions and the following disclaimer in the
13335640Shselasky *    documentation and/or other materials provided with the distribution.
14335640Shselasky * 3. All advertising materials mentioning features or use of this software
15335640Shselasky *    must display the following acknowledgement:
16335640Shselasky *	This product includes software developed by the Computer Systems
17335640Shselasky *	Engineering Group at Lawrence Berkeley Laboratory.
18335640Shselasky * 4. Neither the name of the University nor of the Laboratory may be used
19335640Shselasky *    to endorse or promote products derived from this software without
20335640Shselasky *    specific prior written permission.
21335640Shselasky *
22335640Shselasky * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23335640Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24335640Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25335640Shselasky * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26335640Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27335640Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28335640Shselasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29335640Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30335640Shselasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31335640Shselasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32335640Shselasky * SUCH DAMAGE.
33335640Shselasky */
34335640Shselasky
35335640Shselasky#ifdef HAVE_CONFIG_H
36335640Shselasky#include <config.h>
37335640Shselasky#endif
38335640Shselasky
39335640Shselasky#include <sys/param.h>
40335640Shselasky#include <sys/file.h>
41335640Shselasky#include <sys/ioctl.h>
42335640Shselasky#include <sys/socket.h>
43335640Shselasky#ifdef HAVE_SYS_SOCKIO_H
44335640Shselasky#include <sys/sockio.h>
45335640Shselasky#endif
46335640Shselasky#include <sys/time.h>				/* concession to AIX */
47335640Shselasky
48335640Shselaskystruct mbuf;		/* Squelch compiler warnings on some platforms for */
49335640Shselaskystruct rtentry;		/* declarations in <net/if.h> */
50335640Shselasky#include <net/if.h>
51335640Shselasky#include <netinet/in.h>
52335640Shselasky
53335640Shselasky#include <ctype.h>
54335640Shselasky#include <errno.h>
55335640Shselasky#include <memory.h>
56335640Shselasky#include <stdio.h>
57335640Shselasky#include <stdlib.h>
58335640Shselasky#include <string.h>
59335640Shselasky#include <unistd.h>
60335640Shselasky
61335640Shselasky#include "pcap-int.h"
62335640Shselasky
63335640Shselasky#ifdef HAVE_OS_PROTO_H
64335640Shselasky#include "os-proto.h"
65335640Shselasky#endif
66335640Shselasky
67335640Shselasky/*
68335640Shselasky * Get a list of all interfaces that are up and that we can open.
69335640Shselasky * Returns -1 on error, 0 otherwise.
70335640Shselasky * The list, as returned through "alldevsp", may be null if no interfaces
71335640Shselasky * were up and could be opened.
72335640Shselasky *
73335640Shselasky * This is the implementation used on platforms that have SIOCGLIFCONF
74335640Shselasky * but don't have "getifaddrs()".  (Solaris 8 and later; we use
75335640Shselasky * SIOCGLIFCONF rather than SIOCGIFCONF in order to get IPv6 addresses.)
76335640Shselasky */
77335640Shselaskyint
78335640Shselaskypcap_findalldevs_interfaces(pcap_if_list_t *devlistp, char *errbuf,
79335640Shselasky    int (*check_usable)(const char *), get_if_flags_func get_flags_func)
80335640Shselasky{
81335640Shselasky	register int fd4, fd6, fd;
82335640Shselasky	register struct lifreq *ifrp, *ifend;
83335640Shselasky	struct lifnum ifn;
84335640Shselasky	struct lifconf ifc;
85335640Shselasky	char *buf = NULL;
86335640Shselasky	unsigned buf_size;
87335640Shselasky#ifdef HAVE_SOLARIS
88335640Shselasky	char *p, *q;
89335640Shselasky#endif
90335640Shselasky	struct lifreq ifrflags, ifrnetmask, ifrbroadaddr, ifrdstaddr;
91335640Shselasky	struct sockaddr *netmask, *broadaddr, *dstaddr;
92335640Shselasky	int ret = 0;
93335640Shselasky
94335640Shselasky	/*
95335640Shselasky	 * Create a socket from which to fetch the list of interfaces,
96335640Shselasky	 * and from which to fetch IPv4 information.
97335640Shselasky	 */
98335640Shselasky	fd4 = socket(AF_INET, SOCK_DGRAM, 0);
99335640Shselasky	if (fd4 < 0) {
100335640Shselasky		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
101335640Shselasky		    errno, "socket: AF_INET");
102335640Shselasky		return (-1);
103335640Shselasky	}
104335640Shselasky
105335640Shselasky	/*
106335640Shselasky	 * Create a socket from which to fetch IPv6 information.
107335640Shselasky	 */
108335640Shselasky	fd6 = socket(AF_INET6, SOCK_DGRAM, 0);
109335640Shselasky	if (fd6 < 0) {
110335640Shselasky		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
111335640Shselasky		    errno, "socket: AF_INET6");
112335640Shselasky		(void)close(fd4);
113335640Shselasky		return (-1);
114335640Shselasky	}
115335640Shselasky
116335640Shselasky	/*
117335640Shselasky	 * How many entries will SIOCGLIFCONF return?
118335640Shselasky	 */
119335640Shselasky	ifn.lifn_family = AF_UNSPEC;
120335640Shselasky	ifn.lifn_flags = 0;
121335640Shselasky	ifn.lifn_count = 0;
122335640Shselasky	if (ioctl(fd4, SIOCGLIFNUM, (char *)&ifn) < 0) {
123335640Shselasky		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
124335640Shselasky		    errno, "SIOCGLIFNUM");
125335640Shselasky		(void)close(fd6);
126335640Shselasky		(void)close(fd4);
127335640Shselasky		return (-1);
128335640Shselasky	}
129335640Shselasky
130335640Shselasky	/*
131335640Shselasky	 * Allocate a buffer for those entries.
132335640Shselasky	 */
133335640Shselasky	buf_size = ifn.lifn_count * sizeof (struct lifreq);
134335640Shselasky	buf = malloc(buf_size);
135335640Shselasky	if (buf == NULL) {
136335640Shselasky		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
137335640Shselasky		    errno, "malloc");
138335640Shselasky		(void)close(fd6);
139335640Shselasky		(void)close(fd4);
140335640Shselasky		return (-1);
141335640Shselasky	}
142335640Shselasky
143335640Shselasky	/*
144335640Shselasky	 * Get the entries.
145335640Shselasky	 */
146335640Shselasky	ifc.lifc_len = buf_size;
147335640Shselasky	ifc.lifc_buf = buf;
148335640Shselasky	ifc.lifc_family = AF_UNSPEC;
149335640Shselasky	ifc.lifc_flags = 0;
150335640Shselasky	memset(buf, 0, buf_size);
151335640Shselasky	if (ioctl(fd4, SIOCGLIFCONF, (char *)&ifc) < 0) {
152335640Shselasky		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
153335640Shselasky		    errno, "SIOCGLIFCONF");
154335640Shselasky		(void)close(fd6);
155335640Shselasky		(void)close(fd4);
156335640Shselasky		free(buf);
157335640Shselasky		return (-1);
158335640Shselasky	}
159335640Shselasky
160335640Shselasky	/*
161335640Shselasky	 * Loop over the entries.
162335640Shselasky	 */
163335640Shselasky	ifrp = (struct lifreq *)buf;
164335640Shselasky	ifend = (struct lifreq *)(buf + ifc.lifc_len);
165335640Shselasky
166335640Shselasky	for (; ifrp < ifend; ifrp++) {
167335640Shselasky		/*
168335640Shselasky		 * Skip entries that begin with "dummy".
169335640Shselasky		 * XXX - what are these?  Is this Linux-specific?
170335640Shselasky		 * Are there platforms on which we shouldn't do this?
171335640Shselasky		 */
172335640Shselasky		if (strncmp(ifrp->lifr_name, "dummy", 5) == 0)
173335640Shselasky			continue;
174335640Shselasky
175335640Shselasky		/*
176335640Shselasky		 * Can we capture on this device?
177335640Shselasky		 */
178335640Shselasky		if (!(*check_usable)(ifrp->lifr_name)) {
179335640Shselasky			/*
180335640Shselasky			 * No.
181335640Shselasky			 */
182335640Shselasky			continue;
183335640Shselasky		}
184335640Shselasky
185335640Shselasky		/*
186335640Shselasky		 * IPv6 or not?
187335640Shselasky		 */
188335640Shselasky		if (((struct sockaddr *)&ifrp->lifr_addr)->sa_family == AF_INET6)
189335640Shselasky			fd = fd6;
190335640Shselasky		else
191335640Shselasky			fd = fd4;
192335640Shselasky
193335640Shselasky		/*
194335640Shselasky		 * Get the flags for this interface.
195335640Shselasky		 */
196335640Shselasky		strncpy(ifrflags.lifr_name, ifrp->lifr_name,
197335640Shselasky		    sizeof(ifrflags.lifr_name));
198335640Shselasky		if (ioctl(fd, SIOCGLIFFLAGS, (char *)&ifrflags) < 0) {
199335640Shselasky			if (errno == ENXIO)
200335640Shselasky				continue;
201335640Shselasky			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
202335640Shselasky			    errno, "SIOCGLIFFLAGS: %.*s",
203335640Shselasky			    (int)sizeof(ifrflags.lifr_name),
204335640Shselasky			    ifrflags.lifr_name);
205335640Shselasky			ret = -1;
206335640Shselasky			break;
207335640Shselasky		}
208335640Shselasky
209335640Shselasky		/*
210335640Shselasky		 * Get the netmask for this address on this interface.
211335640Shselasky		 */
212335640Shselasky		strncpy(ifrnetmask.lifr_name, ifrp->lifr_name,
213335640Shselasky		    sizeof(ifrnetmask.lifr_name));
214335640Shselasky		memcpy(&ifrnetmask.lifr_addr, &ifrp->lifr_addr,
215335640Shselasky		    sizeof(ifrnetmask.lifr_addr));
216335640Shselasky		if (ioctl(fd, SIOCGLIFNETMASK, (char *)&ifrnetmask) < 0) {
217335640Shselasky			if (errno == EADDRNOTAVAIL) {
218335640Shselasky				/*
219335640Shselasky				 * Not available.
220335640Shselasky				 */
221335640Shselasky				netmask = NULL;
222335640Shselasky			} else {
223335640Shselasky				pcap_fmt_errmsg_for_errno(errbuf,
224335640Shselasky				    PCAP_ERRBUF_SIZE, errno,
225335640Shselasky				    "SIOCGLIFNETMASK: %.*s",
226335640Shselasky				    (int)sizeof(ifrnetmask.lifr_name),
227335640Shselasky				    ifrnetmask.lifr_name);
228335640Shselasky				ret = -1;
229335640Shselasky				break;
230335640Shselasky			}
231335640Shselasky		} else
232335640Shselasky			netmask = (struct sockaddr *)&ifrnetmask.lifr_addr;
233335640Shselasky
234335640Shselasky		/*
235335640Shselasky		 * Get the broadcast address for this address on this
236335640Shselasky		 * interface (if any).
237335640Shselasky		 */
238335640Shselasky		if (ifrflags.lifr_flags & IFF_BROADCAST) {
239335640Shselasky			strncpy(ifrbroadaddr.lifr_name, ifrp->lifr_name,
240335640Shselasky			    sizeof(ifrbroadaddr.lifr_name));
241335640Shselasky			memcpy(&ifrbroadaddr.lifr_addr, &ifrp->lifr_addr,
242335640Shselasky			    sizeof(ifrbroadaddr.lifr_addr));
243335640Shselasky			if (ioctl(fd, SIOCGLIFBRDADDR,
244335640Shselasky			    (char *)&ifrbroadaddr) < 0) {
245335640Shselasky				if (errno == EADDRNOTAVAIL) {
246335640Shselasky					/*
247335640Shselasky					 * Not available.
248335640Shselasky					 */
249335640Shselasky					broadaddr = NULL;
250335640Shselasky				} else {
251335640Shselasky					pcap_fmt_errmsg_for_errno(errbuf,
252335640Shselasky					    PCAP_ERRBUF_SIZE, errno,
253335640Shselasky					    "SIOCGLIFBRDADDR: %.*s",
254335640Shselasky					    (int)sizeof(ifrbroadaddr.lifr_name),
255335640Shselasky					    ifrbroadaddr.lifr_name);
256335640Shselasky					ret = -1;
257335640Shselasky					break;
258335640Shselasky				}
259335640Shselasky			} else
260335640Shselasky				broadaddr = (struct sockaddr *)&ifrbroadaddr.lifr_broadaddr;
261335640Shselasky		} else {
262335640Shselasky			/*
263335640Shselasky			 * Not a broadcast interface, so no broadcast
264335640Shselasky			 * address.
265335640Shselasky			 */
266335640Shselasky			broadaddr = NULL;
267335640Shselasky		}
268335640Shselasky
269335640Shselasky		/*
270335640Shselasky		 * Get the destination address for this address on this
271335640Shselasky		 * interface (if any).
272335640Shselasky		 */
273335640Shselasky		if (ifrflags.lifr_flags & IFF_POINTOPOINT) {
274335640Shselasky			strncpy(ifrdstaddr.lifr_name, ifrp->lifr_name,
275335640Shselasky			    sizeof(ifrdstaddr.lifr_name));
276335640Shselasky			memcpy(&ifrdstaddr.lifr_addr, &ifrp->lifr_addr,
277335640Shselasky			    sizeof(ifrdstaddr.lifr_addr));
278335640Shselasky			if (ioctl(fd, SIOCGLIFDSTADDR,
279335640Shselasky			    (char *)&ifrdstaddr) < 0) {
280335640Shselasky				if (errno == EADDRNOTAVAIL) {
281335640Shselasky					/*
282335640Shselasky					 * Not available.
283335640Shselasky					 */
284335640Shselasky					dstaddr = NULL;
285335640Shselasky				} else {
286335640Shselasky					pcap_fmt_errmsg_for_errno(errbuf,
287335640Shselasky					    PCAP_ERRBUF_SIZE, errno,
288335640Shselasky					    "SIOCGLIFDSTADDR: %.*s",
289335640Shselasky					    (int)sizeof(ifrdstaddr.lifr_name),
290335640Shselasky					    ifrdstaddr.lifr_name);
291335640Shselasky					ret = -1;
292335640Shselasky					break;
293335640Shselasky				}
294335640Shselasky			} else
295335640Shselasky				dstaddr = (struct sockaddr *)&ifrdstaddr.lifr_dstaddr;
296335640Shselasky		} else
297335640Shselasky			dstaddr = NULL;
298335640Shselasky
299335640Shselasky#ifdef HAVE_SOLARIS
300335640Shselasky		/*
301335640Shselasky		 * If this entry has a colon followed by a number at
302335640Shselasky		 * the end, it's a logical interface.  Those are just
303335640Shselasky		 * the way you assign multiple IP addresses to a real
304335640Shselasky		 * interface, so an entry for a logical interface should
305335640Shselasky		 * be treated like the entry for the real interface;
306335640Shselasky		 * we do that by stripping off the ":" and the number.
307335640Shselasky		 */
308335640Shselasky		p = strchr(ifrp->lifr_name, ':');
309335640Shselasky		if (p != NULL) {
310335640Shselasky			/*
311335640Shselasky			 * We have a ":"; is it followed by a number?
312335640Shselasky			 */
313335640Shselasky			q = p + 1;
314335640Shselasky			while (isdigit((unsigned char)*q))
315335640Shselasky				q++;
316335640Shselasky			if (*q == '\0') {
317335640Shselasky				/*
318335640Shselasky				 * All digits after the ":" until the end.
319335640Shselasky				 * Strip off the ":" and everything after
320335640Shselasky				 * it.
321335640Shselasky				 */
322335640Shselasky				*p = '\0';
323335640Shselasky			}
324335640Shselasky		}
325335640Shselasky#endif
326335640Shselasky
327335640Shselasky		/*
328335640Shselasky		 * Add information for this address to the list.
329335640Shselasky		 */
330335640Shselasky		if (add_addr_to_if(devlistp, ifrp->lifr_name,
331335640Shselasky		    ifrflags.lifr_flags, get_flags_func,
332335640Shselasky		    (struct sockaddr *)&ifrp->lifr_addr,
333335640Shselasky		    sizeof (struct sockaddr_storage),
334335640Shselasky		    netmask, sizeof (struct sockaddr_storage),
335335640Shselasky		    broadaddr, sizeof (struct sockaddr_storage),
336335640Shselasky		    dstaddr, sizeof (struct sockaddr_storage), errbuf) < 0) {
337335640Shselasky			ret = -1;
338335640Shselasky			break;
339335640Shselasky		}
340335640Shselasky	}
341335640Shselasky	free(buf);
342335640Shselasky	(void)close(fd6);
343335640Shselasky	(void)close(fd4);
344335640Shselasky
345335640Shselasky	return (ret);
346335640Shselasky}
347