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/types.h>
40335640Shselasky#include <sys/socket.h>
41335640Shselasky#include <netinet/in.h>
42335640Shselasky
43335640Shselasky#include <net/if.h>
44335640Shselasky
45335640Shselasky#include <ctype.h>
46335640Shselasky#include <errno.h>
47335640Shselasky#include <stdio.h>
48335640Shselasky#include <stdlib.h>
49335640Shselasky#include <string.h>
50335640Shselasky#include <ifaddrs.h>
51335640Shselasky
52335640Shselasky#include "pcap-int.h"
53335640Shselasky
54335640Shselasky#ifdef HAVE_OS_PROTO_H
55335640Shselasky#include "os-proto.h"
56335640Shselasky#endif
57335640Shselasky
58335640Shselasky/*
59335640Shselasky * We don't do this on Solaris 11 and later, as it appears there aren't
60335640Shselasky * any AF_PACKET addresses on interfaces, so we don't need this, and
61335640Shselasky * we end up including both the OS's <net/bpf.h> and our <pcap/bpf.h>,
62335640Shselasky * and their definitions of some data structures collide.
63335640Shselasky */
64335640Shselasky#if (defined(linux) || defined(__Lynx__)) && defined(AF_PACKET)
65335640Shselasky# ifdef HAVE_NETPACKET_PACKET_H
66335640Shselasky/* Linux distributions with newer glibc */
67335640Shselasky#  include <netpacket/packet.h>
68335640Shselasky# else /* HAVE_NETPACKET_PACKET_H */
69335640Shselasky/* LynxOS, Linux distributions with older glibc */
70335640Shselasky# ifdef __Lynx__
71335640Shselasky/* LynxOS */
72335640Shselasky#  include <netpacket/if_packet.h>
73335640Shselasky# else /* __Lynx__ */
74335640Shselasky/* Linux */
75335640Shselasky#  include <linux/types.h>
76335640Shselasky#  include <linux/if_packet.h>
77335640Shselasky# endif /* __Lynx__ */
78335640Shselasky# endif /* HAVE_NETPACKET_PACKET_H */
79335640Shselasky#endif /* (defined(linux) || defined(__Lynx__)) && defined(AF_PACKET) */
80335640Shselasky
81335640Shselasky/*
82335640Shselasky * This is fun.
83335640Shselasky *
84335640Shselasky * In older BSD systems, socket addresses were fixed-length, and
85335640Shselasky * "sizeof (struct sockaddr)" gave the size of the structure.
86335640Shselasky * All addresses fit within a "struct sockaddr".
87335640Shselasky *
88335640Shselasky * In newer BSD systems, the socket address is variable-length, and
89335640Shselasky * there's an "sa_len" field giving the length of the structure;
90335640Shselasky * this allows socket addresses to be longer than 2 bytes of family
91335640Shselasky * and 14 bytes of data.
92335640Shselasky *
93335640Shselasky * Some commercial UNIXes use the old BSD scheme, some use the RFC 2553
94335640Shselasky * variant of the old BSD scheme (with "struct sockaddr_storage" rather
95335640Shselasky * than "struct sockaddr"), and some use the new BSD scheme.
96335640Shselasky *
97335640Shselasky * Some versions of GNU libc use neither scheme, but has an "SA_LEN()"
98335640Shselasky * macro that determines the size based on the address family.  Other
99335640Shselasky * versions don't have "SA_LEN()" (as it was in drafts of RFC 2553
100335640Shselasky * but not in the final version).  On the latter systems, we explicitly
101335640Shselasky * check the AF_ type to determine the length; we assume that on
102335640Shselasky * all those systems we have "struct sockaddr_storage".
103335640Shselasky */
104335640Shselasky#ifndef SA_LEN
105335640Shselasky#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
106335640Shselasky#define SA_LEN(addr)	((addr)->sa_len)
107335640Shselasky#else /* HAVE_STRUCT_SOCKADDR_SA_LEN */
108335640Shselasky#ifdef HAVE_STRUCT_SOCKADDR_STORAGE
109335640Shselaskystatic size_t
110335640Shselaskyget_sa_len(struct sockaddr *addr)
111335640Shselasky{
112335640Shselasky	switch (addr->sa_family) {
113335640Shselasky
114335640Shselasky#ifdef AF_INET
115335640Shselasky	case AF_INET:
116335640Shselasky		return (sizeof (struct sockaddr_in));
117335640Shselasky#endif
118335640Shselasky
119335640Shselasky#ifdef AF_INET6
120335640Shselasky	case AF_INET6:
121335640Shselasky		return (sizeof (struct sockaddr_in6));
122335640Shselasky#endif
123335640Shselasky
124335640Shselasky#if (defined(linux) || defined(__Lynx__)) && defined(AF_PACKET)
125335640Shselasky	case AF_PACKET:
126335640Shselasky		return (sizeof (struct sockaddr_ll));
127335640Shselasky#endif
128335640Shselasky
129335640Shselasky	default:
130335640Shselasky		return (sizeof (struct sockaddr));
131335640Shselasky	}
132335640Shselasky}
133335640Shselasky#define SA_LEN(addr)	(get_sa_len(addr))
134335640Shselasky#else /* HAVE_STRUCT_SOCKADDR_STORAGE */
135335640Shselasky#define SA_LEN(addr)	(sizeof (struct sockaddr))
136335640Shselasky#endif /* HAVE_STRUCT_SOCKADDR_STORAGE */
137335640Shselasky#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
138335640Shselasky#endif /* SA_LEN */
139335640Shselasky
140335640Shselasky/*
141335640Shselasky * Get a list of all interfaces that are up and that we can open.
142335640Shselasky * Returns -1 on error, 0 otherwise.
143335640Shselasky * The list, as returned through "alldevsp", may be null if no interfaces
144335640Shselasky * could be opened.
145335640Shselasky */
146335640Shselaskyint
147335640Shselaskypcap_findalldevs_interfaces(pcap_if_list_t *devlistp, char *errbuf,
148335640Shselasky    int (*check_usable)(const char *), get_if_flags_func get_flags_func)
149335640Shselasky{
150335640Shselasky	struct ifaddrs *ifap, *ifa;
151335640Shselasky	struct sockaddr *addr, *netmask, *broadaddr, *dstaddr;
152335640Shselasky	size_t addr_size, broadaddr_size, dstaddr_size;
153335640Shselasky	int ret = 0;
154335640Shselasky	char *p, *q;
155335640Shselasky
156335640Shselasky	/*
157335640Shselasky	 * Get the list of interface addresses.
158335640Shselasky	 *
159335640Shselasky	 * Note: this won't return information about interfaces
160335640Shselasky	 * with no addresses, so, if a platform has interfaces
161335640Shselasky	 * with no interfaces on which traffic can be captured,
162335640Shselasky	 * we must check for those interfaces as well (see, for
163335640Shselasky	 * example, what's done on Linux).
164335640Shselasky	 *
165335640Shselasky	 * LAN interfaces will probably have link-layer
166335640Shselasky	 * addresses; I don't know whether all implementations
167335640Shselasky	 * of "getifaddrs()" now, or in the future, will return
168335640Shselasky	 * those.
169335640Shselasky	 */
170335640Shselasky	if (getifaddrs(&ifap) != 0) {
171335640Shselasky		pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
172335640Shselasky		    errno, "getifaddrs");
173335640Shselasky		return (-1);
174335640Shselasky	}
175335640Shselasky	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
176335640Shselasky		/*
177335640Shselasky		 * If this entry has a colon followed by a number at
178335640Shselasky		 * the end, we assume it's a logical interface.  Those
179335640Shselasky		 * are just the way you assign multiple IP addresses to
180335640Shselasky		 * a real interface on Linux, so an entry for a logical
181335640Shselasky		 * interface should be treated like the entry for the
182335640Shselasky		 * real interface; we do that by stripping off the ":"
183335640Shselasky		 * and the number.
184335640Shselasky		 *
185335640Shselasky		 * XXX - should we do this only on Linux?
186335640Shselasky		 */
187335640Shselasky		p = strchr(ifa->ifa_name, ':');
188335640Shselasky		if (p != NULL) {
189335640Shselasky			/*
190335640Shselasky			 * We have a ":"; is it followed by a number?
191335640Shselasky			 */
192335640Shselasky			q = p + 1;
193335640Shselasky			while (isdigit((unsigned char)*q))
194335640Shselasky				q++;
195335640Shselasky			if (*q == '\0') {
196335640Shselasky				/*
197335640Shselasky				 * All digits after the ":" until the end.
198335640Shselasky				 * Strip off the ":" and everything after
199335640Shselasky				 * it.
200335640Shselasky				 */
201335640Shselasky			       *p = '\0';
202335640Shselasky			}
203335640Shselasky		}
204335640Shselasky
205335640Shselasky		/*
206335640Shselasky		 * Can we capture on this device?
207335640Shselasky		 */
208335640Shselasky		if (!(*check_usable)(ifa->ifa_name)) {
209335640Shselasky			/*
210335640Shselasky			 * No.
211335640Shselasky			 */
212335640Shselasky			continue;
213335640Shselasky		}
214335640Shselasky
215335640Shselasky		/*
216335640Shselasky		 * "ifa_addr" was apparently null on at least one
217335640Shselasky		 * interface on some system.  Therefore, we supply
218335640Shselasky		 * the address and netmask only if "ifa_addr" is
219335640Shselasky		 * non-null (if there's no address, there's obviously
220335640Shselasky		 * no netmask).
221335640Shselasky		 */
222335640Shselasky		if (ifa->ifa_addr != NULL) {
223335640Shselasky			addr = ifa->ifa_addr;
224335640Shselasky			addr_size = SA_LEN(addr);
225335640Shselasky			netmask = ifa->ifa_netmask;
226335640Shselasky		} else {
227335640Shselasky			addr = NULL;
228335640Shselasky			addr_size = 0;
229335640Shselasky			netmask = NULL;
230335640Shselasky		}
231335640Shselasky
232335640Shselasky		/*
233335640Shselasky		 * Note that, on some platforms, ifa_broadaddr and
234335640Shselasky		 * ifa_dstaddr could be the same field (true on at
235335640Shselasky		 * least some versions of *BSD and macOS), so we
236335640Shselasky		 * can't just check whether the broadcast address
237335640Shselasky		 * is null and add it if so and check whether the
238335640Shselasky		 * destination address is null and add it if so.
239335640Shselasky		 *
240335640Shselasky		 * Therefore, we must also check the IFF_BROADCAST
241335640Shselasky		 * flag, and only add a broadcast address if it's
242335640Shselasky		 * set, and check the IFF_POINTTOPOINT flag, and
243335640Shselasky		 * only add a destination address if it's set (as
244335640Shselasky		 * per man page recommendations on some of those
245335640Shselasky		 * platforms).
246335640Shselasky		 */
247335640Shselasky		if (ifa->ifa_flags & IFF_BROADCAST &&
248335640Shselasky		    ifa->ifa_broadaddr != NULL) {
249335640Shselasky			broadaddr = ifa->ifa_broadaddr;
250335640Shselasky			broadaddr_size = SA_LEN(broadaddr);
251335640Shselasky		} else {
252335640Shselasky			broadaddr = NULL;
253335640Shselasky			broadaddr_size = 0;
254335640Shselasky		}
255335640Shselasky		if (ifa->ifa_flags & IFF_POINTOPOINT &&
256335640Shselasky		    ifa->ifa_dstaddr != NULL) {
257335640Shselasky			dstaddr = ifa->ifa_dstaddr;
258335640Shselasky			dstaddr_size = SA_LEN(ifa->ifa_dstaddr);
259335640Shselasky		} else {
260335640Shselasky			dstaddr = NULL;
261335640Shselasky			dstaddr_size = 0;
262335640Shselasky		}
263335640Shselasky
264335640Shselasky		/*
265335640Shselasky		 * Add information for this address to the list.
266335640Shselasky		 */
267335640Shselasky		if (add_addr_to_if(devlistp, ifa->ifa_name, ifa->ifa_flags,
268335640Shselasky		    get_flags_func,
269335640Shselasky		    addr, addr_size, netmask, addr_size,
270335640Shselasky		    broadaddr, broadaddr_size, dstaddr, dstaddr_size,
271335640Shselasky		    errbuf) < 0) {
272335640Shselasky			ret = -1;
273335640Shselasky			break;
274335640Shselasky		}
275335640Shselasky	}
276335640Shselasky
277335640Shselasky	freeifaddrs(ifap);
278335640Shselasky
279335640Shselasky	return (ret);
280335640Shselasky}
281