xref: /minix3/external/bsd/libpcap/dist/inet.c (revision d56f51ea7d8b9045e5c8e2028422523d3f9a5840)
1*d56f51eaSDavid van Moolenbroek /*	$NetBSD: inet.c,v 1.3 2015/03/31 21:39:42 christos Exp $	*/
2*d56f51eaSDavid van Moolenbroek 
3*d56f51eaSDavid van Moolenbroek /* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
4*d56f51eaSDavid van Moolenbroek /*
5*d56f51eaSDavid van Moolenbroek  * Copyright (c) 1994, 1995, 1996, 1997, 1998
6*d56f51eaSDavid van Moolenbroek  *	The Regents of the University of California.  All rights reserved.
7*d56f51eaSDavid van Moolenbroek  *
8*d56f51eaSDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
9*d56f51eaSDavid van Moolenbroek  * modification, are permitted provided that the following conditions
10*d56f51eaSDavid van Moolenbroek  * are met:
11*d56f51eaSDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
12*d56f51eaSDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer.
13*d56f51eaSDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce the above copyright
14*d56f51eaSDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer in the
15*d56f51eaSDavid van Moolenbroek  *    documentation and/or other materials provided with the distribution.
16*d56f51eaSDavid van Moolenbroek  * 3. All advertising materials mentioning features or use of this software
17*d56f51eaSDavid van Moolenbroek  *    must display the following acknowledgement:
18*d56f51eaSDavid van Moolenbroek  *	This product includes software developed by the Computer Systems
19*d56f51eaSDavid van Moolenbroek  *	Engineering Group at Lawrence Berkeley Laboratory.
20*d56f51eaSDavid van Moolenbroek  * 4. Neither the name of the University nor of the Laboratory may be used
21*d56f51eaSDavid van Moolenbroek  *    to endorse or promote products derived from this software without
22*d56f51eaSDavid van Moolenbroek  *    specific prior written permission.
23*d56f51eaSDavid van Moolenbroek  *
24*d56f51eaSDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25*d56f51eaSDavid van Moolenbroek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26*d56f51eaSDavid van Moolenbroek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27*d56f51eaSDavid van Moolenbroek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28*d56f51eaSDavid van Moolenbroek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29*d56f51eaSDavid van Moolenbroek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30*d56f51eaSDavid van Moolenbroek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31*d56f51eaSDavid van Moolenbroek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32*d56f51eaSDavid van Moolenbroek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33*d56f51eaSDavid van Moolenbroek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34*d56f51eaSDavid van Moolenbroek  * SUCH DAMAGE.
35*d56f51eaSDavid van Moolenbroek  */
36*d56f51eaSDavid van Moolenbroek 
37*d56f51eaSDavid van Moolenbroek #include <sys/cdefs.h>
38*d56f51eaSDavid van Moolenbroek __RCSID("$NetBSD: inet.c,v 1.3 2015/03/31 21:39:42 christos Exp $");
39*d56f51eaSDavid van Moolenbroek 
40*d56f51eaSDavid van Moolenbroek #ifdef HAVE_CONFIG_H
41*d56f51eaSDavid van Moolenbroek #include "config.h"
42*d56f51eaSDavid van Moolenbroek #endif
43*d56f51eaSDavid van Moolenbroek 
44*d56f51eaSDavid van Moolenbroek #ifdef WIN32
45*d56f51eaSDavid van Moolenbroek #include <pcap-stdinc.h>
46*d56f51eaSDavid van Moolenbroek #else /* WIN32 */
47*d56f51eaSDavid van Moolenbroek 
48*d56f51eaSDavid van Moolenbroek #include <sys/param.h>
49*d56f51eaSDavid van Moolenbroek #ifndef MSDOS
50*d56f51eaSDavid van Moolenbroek #include <sys/file.h>
51*d56f51eaSDavid van Moolenbroek #endif
52*d56f51eaSDavid van Moolenbroek #include <sys/ioctl.h>
53*d56f51eaSDavid van Moolenbroek #include <sys/socket.h>
54*d56f51eaSDavid van Moolenbroek #ifdef HAVE_SYS_SOCKIO_H
55*d56f51eaSDavid van Moolenbroek #include <sys/sockio.h>
56*d56f51eaSDavid van Moolenbroek #endif
57*d56f51eaSDavid van Moolenbroek 
58*d56f51eaSDavid van Moolenbroek struct mbuf;		/* Squelch compiler warnings on some platforms for */
59*d56f51eaSDavid van Moolenbroek struct rtentry;		/* declarations in <net/if.h> */
60*d56f51eaSDavid van Moolenbroek #include <net/if.h>
61*d56f51eaSDavid van Moolenbroek #include <netinet/in.h>
62*d56f51eaSDavid van Moolenbroek #endif /* WIN32 */
63*d56f51eaSDavid van Moolenbroek 
64*d56f51eaSDavid van Moolenbroek #include <ctype.h>
65*d56f51eaSDavid van Moolenbroek #include <errno.h>
66*d56f51eaSDavid van Moolenbroek #include <memory.h>
67*d56f51eaSDavid van Moolenbroek #include <stdio.h>
68*d56f51eaSDavid van Moolenbroek #include <stdlib.h>
69*d56f51eaSDavid van Moolenbroek #include <string.h>
70*d56f51eaSDavid van Moolenbroek #if !defined(WIN32) && !defined(__BORLANDC__)
71*d56f51eaSDavid van Moolenbroek #include <unistd.h>
72*d56f51eaSDavid van Moolenbroek #endif /* !WIN32 && !__BORLANDC__ */
73*d56f51eaSDavid van Moolenbroek #ifdef HAVE_LIMITS_H
74*d56f51eaSDavid van Moolenbroek #include <limits.h>
75*d56f51eaSDavid van Moolenbroek #else
76*d56f51eaSDavid van Moolenbroek #define INT_MAX		2147483647
77*d56f51eaSDavid van Moolenbroek #endif
78*d56f51eaSDavid van Moolenbroek 
79*d56f51eaSDavid van Moolenbroek #include "pcap-int.h"
80*d56f51eaSDavid van Moolenbroek 
81*d56f51eaSDavid van Moolenbroek #ifdef HAVE_OS_PROTO_H
82*d56f51eaSDavid van Moolenbroek #include "os-proto.h"
83*d56f51eaSDavid van Moolenbroek #endif
84*d56f51eaSDavid van Moolenbroek 
85*d56f51eaSDavid van Moolenbroek /* Not all systems have IFF_LOOPBACK */
86*d56f51eaSDavid van Moolenbroek #ifdef IFF_LOOPBACK
87*d56f51eaSDavid van Moolenbroek #define ISLOOPBACK(name, flags) ((flags) & IFF_LOOPBACK)
88*d56f51eaSDavid van Moolenbroek #else
89*d56f51eaSDavid van Moolenbroek #define ISLOOPBACK(name, flags) ((name)[0] == 'l' && (name)[1] == 'o' && \
90*d56f51eaSDavid van Moolenbroek     (isdigit((unsigned char)((name)[2])) || (name)[2] == '\0'))
91*d56f51eaSDavid van Moolenbroek #endif
92*d56f51eaSDavid van Moolenbroek 
93*d56f51eaSDavid van Moolenbroek #ifdef IFF_UP
94*d56f51eaSDavid van Moolenbroek #define ISUP(flags) ((flags) & IFF_UP)
95*d56f51eaSDavid van Moolenbroek #else
96*d56f51eaSDavid van Moolenbroek #define ISUP(flags) 0
97*d56f51eaSDavid van Moolenbroek #endif
98*d56f51eaSDavid van Moolenbroek 
99*d56f51eaSDavid van Moolenbroek #ifdef IFF_RUNNING
100*d56f51eaSDavid van Moolenbroek #define ISRUNNING(flags) ((flags) & IFF_RUNNING)
101*d56f51eaSDavid van Moolenbroek #else
102*d56f51eaSDavid van Moolenbroek #define ISRUNNING(flags) 0
103*d56f51eaSDavid van Moolenbroek #endif
104*d56f51eaSDavid van Moolenbroek 
105*d56f51eaSDavid van Moolenbroek struct sockaddr *
dup_sockaddr(struct sockaddr * sa,size_t sa_length)106*d56f51eaSDavid van Moolenbroek dup_sockaddr(struct sockaddr *sa, size_t sa_length)
107*d56f51eaSDavid van Moolenbroek {
108*d56f51eaSDavid van Moolenbroek 	struct sockaddr *newsa;
109*d56f51eaSDavid van Moolenbroek 
110*d56f51eaSDavid van Moolenbroek 	if ((newsa = malloc(sa_length)) == NULL)
111*d56f51eaSDavid van Moolenbroek 		return (NULL);
112*d56f51eaSDavid van Moolenbroek 	return (memcpy(newsa, sa, sa_length));
113*d56f51eaSDavid van Moolenbroek }
114*d56f51eaSDavid van Moolenbroek 
115*d56f51eaSDavid van Moolenbroek /*
116*d56f51eaSDavid van Moolenbroek  * Construct a "figure of merit" for an interface, for use when sorting
117*d56f51eaSDavid van Moolenbroek  * the list of interfaces, in which interfaces that are up are superior
118*d56f51eaSDavid van Moolenbroek  * to interfaces that aren't up, interfaces that are up and running are
119*d56f51eaSDavid van Moolenbroek  * superior to interfaces that are up but not running, and non-loopback
120*d56f51eaSDavid van Moolenbroek  * interfaces that are up and running are superior to loopback interfaces,
121*d56f51eaSDavid van Moolenbroek  * and interfaces with the same flags have a figure of merit that's higher
122*d56f51eaSDavid van Moolenbroek  * the lower the instance number.
123*d56f51eaSDavid van Moolenbroek  *
124*d56f51eaSDavid van Moolenbroek  * The goal is to try to put the interfaces most likely to be useful for
125*d56f51eaSDavid van Moolenbroek  * capture at the beginning of the list.
126*d56f51eaSDavid van Moolenbroek  *
127*d56f51eaSDavid van Moolenbroek  * The figure of merit, which is lower the "better" the interface is,
128*d56f51eaSDavid van Moolenbroek  * has the uppermost bit set if the interface isn't running, the bit
129*d56f51eaSDavid van Moolenbroek  * below that set if the interface isn't up, the bit below that set
130*d56f51eaSDavid van Moolenbroek  * if the interface is a loopback interface, and the interface index
131*d56f51eaSDavid van Moolenbroek  * in the 29 bits below that.  (Yes, we assume u_int is 32 bits.)
132*d56f51eaSDavid van Moolenbroek  */
133*d56f51eaSDavid van Moolenbroek static u_int
get_figure_of_merit(pcap_if_t * dev)134*d56f51eaSDavid van Moolenbroek get_figure_of_merit(pcap_if_t *dev)
135*d56f51eaSDavid van Moolenbroek {
136*d56f51eaSDavid van Moolenbroek 	const char *cp;
137*d56f51eaSDavid van Moolenbroek 	u_int n;
138*d56f51eaSDavid van Moolenbroek 
139*d56f51eaSDavid van Moolenbroek 	if (strcmp(dev->name, "any") == 0) {
140*d56f51eaSDavid van Moolenbroek 		/*
141*d56f51eaSDavid van Moolenbroek 		 * Give the "any" device an artificially high instance
142*d56f51eaSDavid van Moolenbroek 		 * number, so it shows up after all other non-loopback
143*d56f51eaSDavid van Moolenbroek 		 * interfaces.
144*d56f51eaSDavid van Moolenbroek 		 */
145*d56f51eaSDavid van Moolenbroek 		n = 0x1FFFFFFF;	/* 29 all-1 bits */
146*d56f51eaSDavid van Moolenbroek 	} else {
147*d56f51eaSDavid van Moolenbroek 		/*
148*d56f51eaSDavid van Moolenbroek 		 * A number at the end of the device name string is
149*d56f51eaSDavid van Moolenbroek 		 * assumed to be a unit number.
150*d56f51eaSDavid van Moolenbroek 		 */
151*d56f51eaSDavid van Moolenbroek 		cp = dev->name + strlen(dev->name) - 1;
152*d56f51eaSDavid van Moolenbroek 		while (cp-1 >= dev->name && *(cp-1) >= '0' && *(cp-1) <= '9')
153*d56f51eaSDavid van Moolenbroek 			cp--;
154*d56f51eaSDavid van Moolenbroek 		if (*cp >= '0' && *cp <= '9')
155*d56f51eaSDavid van Moolenbroek 			n = atoi(cp);
156*d56f51eaSDavid van Moolenbroek 		else
157*d56f51eaSDavid van Moolenbroek 			n = 0;
158*d56f51eaSDavid van Moolenbroek 	}
159*d56f51eaSDavid van Moolenbroek 	if (!(dev->flags & PCAP_IF_RUNNING))
160*d56f51eaSDavid van Moolenbroek 		n |= 0x80000000;
161*d56f51eaSDavid van Moolenbroek 	if (!(dev->flags & PCAP_IF_UP))
162*d56f51eaSDavid van Moolenbroek 		n |= 0x40000000;
163*d56f51eaSDavid van Moolenbroek 	if (dev->flags & PCAP_IF_LOOPBACK)
164*d56f51eaSDavid van Moolenbroek 		n |= 0x20000000;
165*d56f51eaSDavid van Moolenbroek 	return (n);
166*d56f51eaSDavid van Moolenbroek }
167*d56f51eaSDavid van Moolenbroek 
168*d56f51eaSDavid van Moolenbroek /*
169*d56f51eaSDavid van Moolenbroek  * Look for a given device in the specified list of devices.
170*d56f51eaSDavid van Moolenbroek  *
171*d56f51eaSDavid van Moolenbroek  * If we find it, return 0 and set *curdev_ret to point to it.
172*d56f51eaSDavid van Moolenbroek  *
173*d56f51eaSDavid van Moolenbroek  * If we don't find it, check whether we can open it:
174*d56f51eaSDavid van Moolenbroek  *
175*d56f51eaSDavid van Moolenbroek  *     If that fails with PCAP_ERROR_NO_SUCH_DEVICE or
176*d56f51eaSDavid van Moolenbroek  *     PCAP_ERROR_IFACE_NOT_UP, don't attempt to add an entry for
177*d56f51eaSDavid van Moolenbroek  *     it, as that probably means it exists but doesn't support
178*d56f51eaSDavid van Moolenbroek  *     packet capture.
179*d56f51eaSDavid van Moolenbroek  *
180*d56f51eaSDavid van Moolenbroek  *     Otherwise, attempt to add an entry for it, with the specified
181*d56f51eaSDavid van Moolenbroek  *     ifnet flags and description, and, if that succeeds, return 0
182*d56f51eaSDavid van Moolenbroek  *     and set *curdev_ret to point to the new entry, otherwise
183*d56f51eaSDavid van Moolenbroek  *     return PCAP_ERROR and set errbuf to an error message.
184*d56f51eaSDavid van Moolenbroek  */
185*d56f51eaSDavid van Moolenbroek int
add_or_find_if(pcap_if_t ** curdev_ret,pcap_if_t ** alldevs,const char * name,u_int flags,const char * description,char * errbuf)186*d56f51eaSDavid van Moolenbroek add_or_find_if(pcap_if_t **curdev_ret, pcap_if_t **alldevs, const char *name,
187*d56f51eaSDavid van Moolenbroek     u_int flags, const char *description, char *errbuf)
188*d56f51eaSDavid van Moolenbroek {
189*d56f51eaSDavid van Moolenbroek 	pcap_t *p;
190*d56f51eaSDavid van Moolenbroek 	pcap_if_t *curdev, *prevdev, *nextdev;
191*d56f51eaSDavid van Moolenbroek 	u_int this_figure_of_merit, nextdev_figure_of_merit;
192*d56f51eaSDavid van Moolenbroek 	char open_errbuf[PCAP_ERRBUF_SIZE];
193*d56f51eaSDavid van Moolenbroek 	int ret;
194*d56f51eaSDavid van Moolenbroek 
195*d56f51eaSDavid van Moolenbroek 	/*
196*d56f51eaSDavid van Moolenbroek 	 * Is there already an entry in the list for this interface?
197*d56f51eaSDavid van Moolenbroek 	 */
198*d56f51eaSDavid van Moolenbroek 	for (curdev = *alldevs; curdev != NULL; curdev = curdev->next) {
199*d56f51eaSDavid van Moolenbroek 		if (strcmp(name, curdev->name) == 0)
200*d56f51eaSDavid van Moolenbroek 			break;	/* yes, we found it */
201*d56f51eaSDavid van Moolenbroek 	}
202*d56f51eaSDavid van Moolenbroek 
203*d56f51eaSDavid van Moolenbroek 	if (curdev == NULL) {
204*d56f51eaSDavid van Moolenbroek 		/*
205*d56f51eaSDavid van Moolenbroek 		 * No, we didn't find it.
206*d56f51eaSDavid van Moolenbroek 		 *
207*d56f51eaSDavid van Moolenbroek 		 * Can we open this interface for live capture?
208*d56f51eaSDavid van Moolenbroek 		 *
209*d56f51eaSDavid van Moolenbroek 		 * We do this check so that interfaces that are
210*d56f51eaSDavid van Moolenbroek 		 * supplied by the interface enumeration mechanism
211*d56f51eaSDavid van Moolenbroek 		 * we're using but that don't support packet capture
212*d56f51eaSDavid van Moolenbroek 		 * aren't included in the list.  Loopback interfaces
213*d56f51eaSDavid van Moolenbroek 		 * on Solaris are an example of this; we don't just
214*d56f51eaSDavid van Moolenbroek 		 * omit loopback interfaces on all platforms because
215*d56f51eaSDavid van Moolenbroek 		 * you *can* capture on loopback interfaces on some
216*d56f51eaSDavid van Moolenbroek 		 * OSes.
217*d56f51eaSDavid van Moolenbroek 		 *
218*d56f51eaSDavid van Moolenbroek 		 * On OS X, we don't do this check if the device
219*d56f51eaSDavid van Moolenbroek 		 * name begins with "wlt"; at least some versions
220*d56f51eaSDavid van Moolenbroek 		 * of OS X offer monitor mode capturing by having
221*d56f51eaSDavid van Moolenbroek 		 * a separate "monitor mode" device for each wireless
222*d56f51eaSDavid van Moolenbroek 		 * adapter, rather than by implementing the ioctls
223*d56f51eaSDavid van Moolenbroek 		 * that {Free,Net,Open,DragonFly}BSD provide.
224*d56f51eaSDavid van Moolenbroek 		 * Opening that device puts the adapter into monitor
225*d56f51eaSDavid van Moolenbroek 		 * mode, which, at least for some adapters, causes
226*d56f51eaSDavid van Moolenbroek 		 * them to deassociate from the network with which
227*d56f51eaSDavid van Moolenbroek 		 * they're associated.
228*d56f51eaSDavid van Moolenbroek 		 *
229*d56f51eaSDavid van Moolenbroek 		 * Instead, we try to open the corresponding "en"
230*d56f51eaSDavid van Moolenbroek 		 * device (so that we don't end up with, for users
231*d56f51eaSDavid van Moolenbroek 		 * without sufficient privilege to open capture
232*d56f51eaSDavid van Moolenbroek 		 * devices, a list of adapters that only includes
233*d56f51eaSDavid van Moolenbroek 		 * the wlt devices).
234*d56f51eaSDavid van Moolenbroek 		 */
235*d56f51eaSDavid van Moolenbroek #ifdef __APPLE__
236*d56f51eaSDavid van Moolenbroek 		if (strncmp(name, "wlt", 3) == 0) {
237*d56f51eaSDavid van Moolenbroek 			char *en_name;
238*d56f51eaSDavid van Moolenbroek 			size_t en_name_len;
239*d56f51eaSDavid van Moolenbroek 
240*d56f51eaSDavid van Moolenbroek 			/*
241*d56f51eaSDavid van Moolenbroek 			 * Try to allocate a buffer for the "en"
242*d56f51eaSDavid van Moolenbroek 			 * device's name.
243*d56f51eaSDavid van Moolenbroek 			 */
244*d56f51eaSDavid van Moolenbroek 			en_name_len = strlen(name) - 1;
245*d56f51eaSDavid van Moolenbroek 			en_name = malloc(en_name_len + 1);
246*d56f51eaSDavid van Moolenbroek 			if (en_name == NULL) {
247*d56f51eaSDavid van Moolenbroek 				(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
248*d56f51eaSDavid van Moolenbroek 				    "malloc: %s", pcap_strerror(errno));
249*d56f51eaSDavid van Moolenbroek 				return (-1);
250*d56f51eaSDavid van Moolenbroek 			}
251*d56f51eaSDavid van Moolenbroek 			strcpy(en_name, "en");
252*d56f51eaSDavid van Moolenbroek 			strcat(en_name, name + 3);
253*d56f51eaSDavid van Moolenbroek 			p = pcap_create(en_name, open_errbuf);
254*d56f51eaSDavid van Moolenbroek 			free(en_name);
255*d56f51eaSDavid van Moolenbroek 		} else
256*d56f51eaSDavid van Moolenbroek #endif /* __APPLE */
257*d56f51eaSDavid van Moolenbroek 		p = pcap_create(name, open_errbuf);
258*d56f51eaSDavid van Moolenbroek 		if (p == NULL) {
259*d56f51eaSDavid van Moolenbroek 			/*
260*d56f51eaSDavid van Moolenbroek 			 * The attempt to create the pcap_t failed;
261*d56f51eaSDavid van Moolenbroek 			 * that's probably an indication that we're
262*d56f51eaSDavid van Moolenbroek 			 * out of memory.
263*d56f51eaSDavid van Moolenbroek 			 *
264*d56f51eaSDavid van Moolenbroek 			 * Don't bother including this interface,
265*d56f51eaSDavid van Moolenbroek 			 * but don't treat it as an error.
266*d56f51eaSDavid van Moolenbroek 			 */
267*d56f51eaSDavid van Moolenbroek 			*curdev_ret = NULL;
268*d56f51eaSDavid van Moolenbroek 			return (0);
269*d56f51eaSDavid van Moolenbroek 		}
270*d56f51eaSDavid van Moolenbroek 		/* Small snaplen, so we don't try to allocate much memory. */
271*d56f51eaSDavid van Moolenbroek 		pcap_set_snaplen(p, 68);
272*d56f51eaSDavid van Moolenbroek 		ret = pcap_activate(p);
273*d56f51eaSDavid van Moolenbroek 		pcap_close(p);
274*d56f51eaSDavid van Moolenbroek 		switch (ret) {
275*d56f51eaSDavid van Moolenbroek 
276*d56f51eaSDavid van Moolenbroek 		case PCAP_ERROR_NO_SUCH_DEVICE:
277*d56f51eaSDavid van Moolenbroek 		case PCAP_ERROR_IFACE_NOT_UP:
278*d56f51eaSDavid van Moolenbroek 			/*
279*d56f51eaSDavid van Moolenbroek 			 * We expect these two errors - they're the
280*d56f51eaSDavid van Moolenbroek 			 * reason we try to open the device.
281*d56f51eaSDavid van Moolenbroek 			 *
282*d56f51eaSDavid van Moolenbroek 			 * PCAP_ERROR_NO_SUCH_DEVICE typically means
283*d56f51eaSDavid van Moolenbroek 			 * "there's no such device *known to the
284*d56f51eaSDavid van Moolenbroek 			 * OS's capture mechanism*", so, even though
285*d56f51eaSDavid van Moolenbroek 			 * it might be a valid network interface, you
286*d56f51eaSDavid van Moolenbroek 			 * can't capture on it (e.g., the loopback
287*d56f51eaSDavid van Moolenbroek 			 * device in Solaris up to Solaris 10, or
288*d56f51eaSDavid van Moolenbroek 			 * the vmnet devices in OS X with VMware
289*d56f51eaSDavid van Moolenbroek 			 * Fusion).  We don't include those devices
290*d56f51eaSDavid van Moolenbroek 			 * in our list of devices, as there's no
291*d56f51eaSDavid van Moolenbroek 			 * point in doing so - they're not available
292*d56f51eaSDavid van Moolenbroek 			 * for capture.
293*d56f51eaSDavid van Moolenbroek 			 *
294*d56f51eaSDavid van Moolenbroek 			 * PCAP_ERROR_IFACE_NOT_UP means that the
295*d56f51eaSDavid van Moolenbroek 			 * OS's capture mechanism doesn't work on
296*d56f51eaSDavid van Moolenbroek 			 * interfaces not marked as up; some capture
297*d56f51eaSDavid van Moolenbroek 			 * mechanisms *do* support that, so we no
298*d56f51eaSDavid van Moolenbroek 			 * longer reject those interfaces out of hand,
299*d56f51eaSDavid van Moolenbroek 			 * but we *do* want to reject them if they
300*d56f51eaSDavid van Moolenbroek 			 * can't be opened for capture.
301*d56f51eaSDavid van Moolenbroek 			 */
302*d56f51eaSDavid van Moolenbroek 			*curdev_ret = NULL;
303*d56f51eaSDavid van Moolenbroek 			return (0);
304*d56f51eaSDavid van Moolenbroek 		}
305*d56f51eaSDavid van Moolenbroek 
306*d56f51eaSDavid van Moolenbroek 		/*
307*d56f51eaSDavid van Moolenbroek 		 * Yes, we can open it, or we can't, for some other
308*d56f51eaSDavid van Moolenbroek 		 * reason.
309*d56f51eaSDavid van Moolenbroek 		 *
310*d56f51eaSDavid van Moolenbroek 		 * If we can open it, we want to offer it for
311*d56f51eaSDavid van Moolenbroek 		 * capture, as you can capture on it.  If we can't,
312*d56f51eaSDavid van Moolenbroek 		 * we want to offer it for capture, so that, if
313*d56f51eaSDavid van Moolenbroek 		 * the user tries to capture on it, they'll get
314*d56f51eaSDavid van Moolenbroek 		 * an error and they'll know why they can't
315*d56f51eaSDavid van Moolenbroek 		 * capture on it (e.g., insufficient permissions)
316*d56f51eaSDavid van Moolenbroek 		 * or they'll report it as a problem (and then
317*d56f51eaSDavid van Moolenbroek 		 * have the error message to provide as information).
318*d56f51eaSDavid van Moolenbroek 		 *
319*d56f51eaSDavid van Moolenbroek 		 * Allocate a new entry.
320*d56f51eaSDavid van Moolenbroek 		 */
321*d56f51eaSDavid van Moolenbroek 		curdev = malloc(sizeof(pcap_if_t));
322*d56f51eaSDavid van Moolenbroek 		if (curdev == NULL) {
323*d56f51eaSDavid van Moolenbroek 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
324*d56f51eaSDavid van Moolenbroek 			    "malloc: %s", pcap_strerror(errno));
325*d56f51eaSDavid van Moolenbroek 			return (-1);
326*d56f51eaSDavid van Moolenbroek 		}
327*d56f51eaSDavid van Moolenbroek 
328*d56f51eaSDavid van Moolenbroek 		/*
329*d56f51eaSDavid van Moolenbroek 		 * Fill in the entry.
330*d56f51eaSDavid van Moolenbroek 		 */
331*d56f51eaSDavid van Moolenbroek 		curdev->next = NULL;
332*d56f51eaSDavid van Moolenbroek 		curdev->name = strdup(name);
333*d56f51eaSDavid van Moolenbroek 		if (curdev->name == NULL) {
334*d56f51eaSDavid van Moolenbroek 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
335*d56f51eaSDavid van Moolenbroek 			    "malloc: %s", pcap_strerror(errno));
336*d56f51eaSDavid van Moolenbroek 			free(curdev);
337*d56f51eaSDavid van Moolenbroek 			return (-1);
338*d56f51eaSDavid van Moolenbroek 		}
339*d56f51eaSDavid van Moolenbroek 		if (description != NULL) {
340*d56f51eaSDavid van Moolenbroek 			/*
341*d56f51eaSDavid van Moolenbroek 			 * We have a description for this interface.
342*d56f51eaSDavid van Moolenbroek 			 */
343*d56f51eaSDavid van Moolenbroek 			curdev->description = strdup(description);
344*d56f51eaSDavid van Moolenbroek 			if (curdev->description == NULL) {
345*d56f51eaSDavid van Moolenbroek 				(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
346*d56f51eaSDavid van Moolenbroek 				    "malloc: %s", pcap_strerror(errno));
347*d56f51eaSDavid van Moolenbroek 				free(curdev->name);
348*d56f51eaSDavid van Moolenbroek 				free(curdev);
349*d56f51eaSDavid van Moolenbroek 				return (-1);
350*d56f51eaSDavid van Moolenbroek 			}
351*d56f51eaSDavid van Moolenbroek 		} else {
352*d56f51eaSDavid van Moolenbroek 			/*
353*d56f51eaSDavid van Moolenbroek 			 * We don't.
354*d56f51eaSDavid van Moolenbroek 			 */
355*d56f51eaSDavid van Moolenbroek 			curdev->description = NULL;
356*d56f51eaSDavid van Moolenbroek 		}
357*d56f51eaSDavid van Moolenbroek 		curdev->addresses = NULL;	/* list starts out as empty */
358*d56f51eaSDavid van Moolenbroek 		curdev->flags = 0;
359*d56f51eaSDavid van Moolenbroek 		if (ISLOOPBACK(name, flags))
360*d56f51eaSDavid van Moolenbroek 			curdev->flags |= PCAP_IF_LOOPBACK;
361*d56f51eaSDavid van Moolenbroek 		if (ISUP(flags))
362*d56f51eaSDavid van Moolenbroek 			curdev->flags |= PCAP_IF_UP;
363*d56f51eaSDavid van Moolenbroek 		if (ISRUNNING(flags))
364*d56f51eaSDavid van Moolenbroek 			curdev->flags |= PCAP_IF_RUNNING;
365*d56f51eaSDavid van Moolenbroek 
366*d56f51eaSDavid van Moolenbroek 		/*
367*d56f51eaSDavid van Moolenbroek 		 * Add it to the list, in the appropriate location.
368*d56f51eaSDavid van Moolenbroek 		 * First, get the "figure of merit" for this
369*d56f51eaSDavid van Moolenbroek 		 * interface.
370*d56f51eaSDavid van Moolenbroek 		 */
371*d56f51eaSDavid van Moolenbroek 		this_figure_of_merit = get_figure_of_merit(curdev);
372*d56f51eaSDavid van Moolenbroek 
373*d56f51eaSDavid van Moolenbroek 		/*
374*d56f51eaSDavid van Moolenbroek 		 * Now look for the last interface with an figure of merit
375*d56f51eaSDavid van Moolenbroek 		 * less than or equal to the new interface's figure of
376*d56f51eaSDavid van Moolenbroek 		 * merit.
377*d56f51eaSDavid van Moolenbroek 		 *
378*d56f51eaSDavid van Moolenbroek 		 * We start with "prevdev" being NULL, meaning we're before
379*d56f51eaSDavid van Moolenbroek 		 * the first element in the list.
380*d56f51eaSDavid van Moolenbroek 		 */
381*d56f51eaSDavid van Moolenbroek 		prevdev = NULL;
382*d56f51eaSDavid van Moolenbroek 		for (;;) {
383*d56f51eaSDavid van Moolenbroek 			/*
384*d56f51eaSDavid van Moolenbroek 			 * Get the interface after this one.
385*d56f51eaSDavid van Moolenbroek 			 */
386*d56f51eaSDavid van Moolenbroek 			if (prevdev == NULL) {
387*d56f51eaSDavid van Moolenbroek 				/*
388*d56f51eaSDavid van Moolenbroek 				 * The next element is the first element.
389*d56f51eaSDavid van Moolenbroek 				 */
390*d56f51eaSDavid van Moolenbroek 				nextdev = *alldevs;
391*d56f51eaSDavid van Moolenbroek 			} else
392*d56f51eaSDavid van Moolenbroek 				nextdev = prevdev->next;
393*d56f51eaSDavid van Moolenbroek 
394*d56f51eaSDavid van Moolenbroek 			/*
395*d56f51eaSDavid van Moolenbroek 			 * Are we at the end of the list?
396*d56f51eaSDavid van Moolenbroek 			 */
397*d56f51eaSDavid van Moolenbroek 			if (nextdev == NULL) {
398*d56f51eaSDavid van Moolenbroek 				/*
399*d56f51eaSDavid van Moolenbroek 				 * Yes - we have to put the new entry
400*d56f51eaSDavid van Moolenbroek 				 * after "prevdev".
401*d56f51eaSDavid van Moolenbroek 				 */
402*d56f51eaSDavid van Moolenbroek 				break;
403*d56f51eaSDavid van Moolenbroek 			}
404*d56f51eaSDavid van Moolenbroek 
405*d56f51eaSDavid van Moolenbroek 			/*
406*d56f51eaSDavid van Moolenbroek 			 * Is the new interface's figure of merit less
407*d56f51eaSDavid van Moolenbroek 			 * than the next interface's figure of merit,
408*d56f51eaSDavid van Moolenbroek 			 * meaning that the new interface is better
409*d56f51eaSDavid van Moolenbroek 			 * than the next interface?
410*d56f51eaSDavid van Moolenbroek 			 */
411*d56f51eaSDavid van Moolenbroek 			nextdev_figure_of_merit = get_figure_of_merit(nextdev);
412*d56f51eaSDavid van Moolenbroek 			if (this_figure_of_merit < nextdev_figure_of_merit) {
413*d56f51eaSDavid van Moolenbroek 				/*
414*d56f51eaSDavid van Moolenbroek 				 * Yes - we should put the new entry
415*d56f51eaSDavid van Moolenbroek 				 * before "nextdev", i.e. after "prevdev".
416*d56f51eaSDavid van Moolenbroek 				 */
417*d56f51eaSDavid van Moolenbroek 				break;
418*d56f51eaSDavid van Moolenbroek 			}
419*d56f51eaSDavid van Moolenbroek 
420*d56f51eaSDavid van Moolenbroek 			prevdev = nextdev;
421*d56f51eaSDavid van Moolenbroek 		}
422*d56f51eaSDavid van Moolenbroek 
423*d56f51eaSDavid van Moolenbroek 		/*
424*d56f51eaSDavid van Moolenbroek 		 * Insert before "nextdev".
425*d56f51eaSDavid van Moolenbroek 		 */
426*d56f51eaSDavid van Moolenbroek 		curdev->next = nextdev;
427*d56f51eaSDavid van Moolenbroek 
428*d56f51eaSDavid van Moolenbroek 		/*
429*d56f51eaSDavid van Moolenbroek 		 * Insert after "prevdev" - unless "prevdev" is null,
430*d56f51eaSDavid van Moolenbroek 		 * in which case this is the first interface.
431*d56f51eaSDavid van Moolenbroek 		 */
432*d56f51eaSDavid van Moolenbroek 		if (prevdev == NULL) {
433*d56f51eaSDavid van Moolenbroek 			/*
434*d56f51eaSDavid van Moolenbroek 			 * This is the first interface.  Pass back a
435*d56f51eaSDavid van Moolenbroek 			 * pointer to it, and put "curdev" before
436*d56f51eaSDavid van Moolenbroek 			 * "nextdev".
437*d56f51eaSDavid van Moolenbroek 			 */
438*d56f51eaSDavid van Moolenbroek 			*alldevs = curdev;
439*d56f51eaSDavid van Moolenbroek 		} else
440*d56f51eaSDavid van Moolenbroek 			prevdev->next = curdev;
441*d56f51eaSDavid van Moolenbroek 	}
442*d56f51eaSDavid van Moolenbroek 
443*d56f51eaSDavid van Moolenbroek 	*curdev_ret = curdev;
444*d56f51eaSDavid van Moolenbroek 	return (0);
445*d56f51eaSDavid van Moolenbroek }
446*d56f51eaSDavid van Moolenbroek 
447*d56f51eaSDavid van Moolenbroek /*
448*d56f51eaSDavid van Moolenbroek  * Try to get a description for a given device.
449*d56f51eaSDavid van Moolenbroek  * Returns a mallocated description if it could and NULL if it couldn't.
450*d56f51eaSDavid van Moolenbroek  *
451*d56f51eaSDavid van Moolenbroek  * XXX - on FreeBSDs that support it, should it get the sysctl named
452*d56f51eaSDavid van Moolenbroek  * "dev.{adapter family name}.{adapter unit}.%desc" to get a description
453*d56f51eaSDavid van Moolenbroek  * of the adapter?  Note that "dev.an.0.%desc" is "Aironet PC4500/PC4800"
454*d56f51eaSDavid van Moolenbroek  * with my Cisco 350 card, so the name isn't entirely descriptive.  The
455*d56f51eaSDavid van Moolenbroek  * "dev.an.0.%pnpinfo" has a better description, although one might argue
456*d56f51eaSDavid van Moolenbroek  * that the problem is really a driver bug - if it can find out that it's
457*d56f51eaSDavid van Moolenbroek  * a Cisco 340 or 350, rather than an old Aironet card, it should use
458*d56f51eaSDavid van Moolenbroek  * that in the description.
459*d56f51eaSDavid van Moolenbroek  *
460*d56f51eaSDavid van Moolenbroek  * Do NetBSD, DragonflyBSD, or OpenBSD support this as well?  FreeBSD
461*d56f51eaSDavid van Moolenbroek  * and OpenBSD let you get a description, but it's not generated by the OS,
462*d56f51eaSDavid van Moolenbroek  * it's set with another ioctl that ifconfig supports; we use that to get
463*d56f51eaSDavid van Moolenbroek  * a description in FreeBSD and OpenBSD, but if there is no such
464*d56f51eaSDavid van Moolenbroek  * description available, it still might be nice to get some description
465*d56f51eaSDavid van Moolenbroek  * string based on the device type or something such as that.
466*d56f51eaSDavid van Moolenbroek  *
467*d56f51eaSDavid van Moolenbroek  * In OS X, the System Configuration framework can apparently return
468*d56f51eaSDavid van Moolenbroek  * names in 10.4 and later.
469*d56f51eaSDavid van Moolenbroek  *
470*d56f51eaSDavid van Moolenbroek  * It also appears that freedesktop.org's HAL offers an "info.product"
471*d56f51eaSDavid van Moolenbroek  * string, but the HAL specification says it "should not be used in any
472*d56f51eaSDavid van Moolenbroek  * UI" and "subsystem/capability specific properties" should be used
473*d56f51eaSDavid van Moolenbroek  * instead and, in any case, I think HAL is being deprecated in
474*d56f51eaSDavid van Moolenbroek  * favor of other stuff such as DeviceKit.  DeviceKit doesn't appear
475*d56f51eaSDavid van Moolenbroek  * to have any obvious product information for devices, but maybe
476*d56f51eaSDavid van Moolenbroek  * I haven't looked hard enough.
477*d56f51eaSDavid van Moolenbroek  *
478*d56f51eaSDavid van Moolenbroek  * Using the System Configuration framework, or HAL, or DeviceKit, or
479*d56f51eaSDavid van Moolenbroek  * whatever, would require that libpcap applications be linked with
480*d56f51eaSDavid van Moolenbroek  * the frameworks/libraries in question.  That shouldn't be a problem
481*d56f51eaSDavid van Moolenbroek  * for programs linking with the shared version of libpcap (unless
482*d56f51eaSDavid van Moolenbroek  * you're running on AIX - which I think is the only UN*X that doesn't
483*d56f51eaSDavid van Moolenbroek  * support linking a shared library with other libraries on which it
484*d56f51eaSDavid van Moolenbroek  * depends, and having an executable linked only with the first shared
485*d56f51eaSDavid van Moolenbroek  * library automatically pick up the other libraries when started -
486*d56f51eaSDavid van Moolenbroek  * and using HAL or whatever).  Programs linked with the static
487*d56f51eaSDavid van Moolenbroek  * version of libpcap would have to use pcap-config with the --static
488*d56f51eaSDavid van Moolenbroek  * flag in order to get the right linker flags in order to pick up
489*d56f51eaSDavid van Moolenbroek  * the additional libraries/frameworks; those programs need that anyway
490*d56f51eaSDavid van Moolenbroek  * for libpcap 1.1 and beyond on Linux, as, by default, it requires
491*d56f51eaSDavid van Moolenbroek  * -lnl.
492*d56f51eaSDavid van Moolenbroek  *
493*d56f51eaSDavid van Moolenbroek  * Do any other UN*Xes, or desktop environments support getting a
494*d56f51eaSDavid van Moolenbroek  * description?
495*d56f51eaSDavid van Moolenbroek  */
496*d56f51eaSDavid van Moolenbroek static char *
get_if_description(const char * name)497*d56f51eaSDavid van Moolenbroek get_if_description(const char *name)
498*d56f51eaSDavid van Moolenbroek {
499*d56f51eaSDavid van Moolenbroek #ifdef SIOCGIFDESCR
500*d56f51eaSDavid van Moolenbroek 	char *description = NULL;
501*d56f51eaSDavid van Moolenbroek 	int s;
502*d56f51eaSDavid van Moolenbroek 	struct ifreq ifrdesc;
503*d56f51eaSDavid van Moolenbroek #ifndef IFDESCRSIZE
504*d56f51eaSDavid van Moolenbroek 	size_t descrlen = 64;
505*d56f51eaSDavid van Moolenbroek #else
506*d56f51eaSDavid van Moolenbroek 	size_t descrlen = IFDESCRSIZE;
507*d56f51eaSDavid van Moolenbroek #endif /* IFDESCRSIZE */
508*d56f51eaSDavid van Moolenbroek 
509*d56f51eaSDavid van Moolenbroek 	/*
510*d56f51eaSDavid van Moolenbroek 	 * Get the description for the interface.
511*d56f51eaSDavid van Moolenbroek 	 */
512*d56f51eaSDavid van Moolenbroek 	memset(&ifrdesc, 0, sizeof ifrdesc);
513*d56f51eaSDavid van Moolenbroek 	strlcpy(ifrdesc.ifr_name, name, sizeof ifrdesc.ifr_name);
514*d56f51eaSDavid van Moolenbroek 	s = socket(AF_INET, SOCK_DGRAM, 0);
515*d56f51eaSDavid van Moolenbroek 	if (s >= 0) {
516*d56f51eaSDavid van Moolenbroek #ifdef __FreeBSD__
517*d56f51eaSDavid van Moolenbroek 		/*
518*d56f51eaSDavid van Moolenbroek 		 * On FreeBSD, if the buffer isn't big enough for the
519*d56f51eaSDavid van Moolenbroek 		 * description, the ioctl succeeds, but the description
520*d56f51eaSDavid van Moolenbroek 		 * isn't copied, ifr_buffer.length is set to the description
521*d56f51eaSDavid van Moolenbroek 		 * length, and ifr_buffer.buffer is set to NULL.
522*d56f51eaSDavid van Moolenbroek 		 */
523*d56f51eaSDavid van Moolenbroek 		for (;;) {
524*d56f51eaSDavid van Moolenbroek 			free(description);
525*d56f51eaSDavid van Moolenbroek 			if ((description = malloc(descrlen)) != NULL) {
526*d56f51eaSDavid van Moolenbroek 				ifrdesc.ifr_buffer.buffer = description;
527*d56f51eaSDavid van Moolenbroek 				ifrdesc.ifr_buffer.length = descrlen;
528*d56f51eaSDavid van Moolenbroek 				if (ioctl(s, SIOCGIFDESCR, &ifrdesc) == 0) {
529*d56f51eaSDavid van Moolenbroek 					if (ifrdesc.ifr_buffer.buffer ==
530*d56f51eaSDavid van Moolenbroek 					    description)
531*d56f51eaSDavid van Moolenbroek 						break;
532*d56f51eaSDavid van Moolenbroek 					else
533*d56f51eaSDavid van Moolenbroek 						descrlen = ifrdesc.ifr_buffer.length;
534*d56f51eaSDavid van Moolenbroek 				} else {
535*d56f51eaSDavid van Moolenbroek 					/*
536*d56f51eaSDavid van Moolenbroek 					 * Failed to get interface description.
537*d56f51eaSDavid van Moolenbroek 					 */
538*d56f51eaSDavid van Moolenbroek 					free(description);
539*d56f51eaSDavid van Moolenbroek 					description = NULL;
540*d56f51eaSDavid van Moolenbroek 					break;
541*d56f51eaSDavid van Moolenbroek 				}
542*d56f51eaSDavid van Moolenbroek 			} else
543*d56f51eaSDavid van Moolenbroek 				break;
544*d56f51eaSDavid van Moolenbroek 		}
545*d56f51eaSDavid van Moolenbroek #else /* __FreeBSD__ */
546*d56f51eaSDavid van Moolenbroek 		/*
547*d56f51eaSDavid van Moolenbroek 		 * The only other OS that currently supports
548*d56f51eaSDavid van Moolenbroek 		 * SIOCGIFDESCR is OpenBSD, and it has no way
549*d56f51eaSDavid van Moolenbroek 		 * to get the description length - it's clamped
550*d56f51eaSDavid van Moolenbroek 		 * to a maximum of IFDESCRSIZE.
551*d56f51eaSDavid van Moolenbroek 		 */
552*d56f51eaSDavid van Moolenbroek 		if ((description = malloc(descrlen)) != NULL) {
553*d56f51eaSDavid van Moolenbroek 			ifrdesc.ifr_data = (caddr_t)description;
554*d56f51eaSDavid van Moolenbroek 			if (ioctl(s, SIOCGIFDESCR, &ifrdesc) != 0) {
555*d56f51eaSDavid van Moolenbroek 				/*
556*d56f51eaSDavid van Moolenbroek 				 * Failed to get interface description.
557*d56f51eaSDavid van Moolenbroek 				 */
558*d56f51eaSDavid van Moolenbroek 				free(description);
559*d56f51eaSDavid van Moolenbroek 				description = NULL;
560*d56f51eaSDavid van Moolenbroek 			}
561*d56f51eaSDavid van Moolenbroek 		}
562*d56f51eaSDavid van Moolenbroek #endif /* __FreeBSD__ */
563*d56f51eaSDavid van Moolenbroek 		close(s);
564*d56f51eaSDavid van Moolenbroek 		if (description != NULL && strlen(description) == 0) {
565*d56f51eaSDavid van Moolenbroek 			free(description);
566*d56f51eaSDavid van Moolenbroek 			description = NULL;
567*d56f51eaSDavid van Moolenbroek 		}
568*d56f51eaSDavid van Moolenbroek 	}
569*d56f51eaSDavid van Moolenbroek 
570*d56f51eaSDavid van Moolenbroek 	return (description);
571*d56f51eaSDavid van Moolenbroek #else /* SIOCGIFDESCR */
572*d56f51eaSDavid van Moolenbroek 	return (NULL);
573*d56f51eaSDavid van Moolenbroek #endif /* SIOCGIFDESCR */
574*d56f51eaSDavid van Moolenbroek }
575*d56f51eaSDavid van Moolenbroek 
576*d56f51eaSDavid van Moolenbroek /*
577*d56f51eaSDavid van Moolenbroek  * Try to get a description for a given device, and then look for that
578*d56f51eaSDavid van Moolenbroek  * device in the specified list of devices.
579*d56f51eaSDavid van Moolenbroek  *
580*d56f51eaSDavid van Moolenbroek  * If we find it, then, if the specified address isn't null, add it to
581*d56f51eaSDavid van Moolenbroek  * the list of addresses for the device and return 0.
582*d56f51eaSDavid van Moolenbroek  *
583*d56f51eaSDavid van Moolenbroek  * If we don't find it, check whether we can open it:
584*d56f51eaSDavid van Moolenbroek  *
585*d56f51eaSDavid van Moolenbroek  *     If that fails with PCAP_ERROR_NO_SUCH_DEVICE or
586*d56f51eaSDavid van Moolenbroek  *     PCAP_ERROR_IFACE_NOT_UP, don't attempt to add an entry for
587*d56f51eaSDavid van Moolenbroek  *     it, as that probably means it exists but doesn't support
588*d56f51eaSDavid van Moolenbroek  *     packet capture.
589*d56f51eaSDavid van Moolenbroek  *
590*d56f51eaSDavid van Moolenbroek  *     Otherwise, attempt to add an entry for it, with the specified
591*d56f51eaSDavid van Moolenbroek  *     ifnet flags and description, and, if that succeeds, add the
592*d56f51eaSDavid van Moolenbroek  *     specified address to its list of addresses if that address is
593*d56f51eaSDavid van Moolenbroek  *     non-null, set *curdev_ret to point to the new entry, and
594*d56f51eaSDavid van Moolenbroek  *     return 0, otherwise return PCAP_ERROR and set errbuf to an
595*d56f51eaSDavid van Moolenbroek  *     error message.
596*d56f51eaSDavid van Moolenbroek  *
597*d56f51eaSDavid van Moolenbroek  * (We can get called with a null address because we might get a list
598*d56f51eaSDavid van Moolenbroek  * of interface name/address combinations from the underlying OS, with
599*d56f51eaSDavid van Moolenbroek  * the address being absent in some cases, rather than a list of
600*d56f51eaSDavid van Moolenbroek  * interfaces with each interface having a list of addresses, so this
601*d56f51eaSDavid van Moolenbroek  * call may be the only call made to add to the list, and we want to
602*d56f51eaSDavid van Moolenbroek  * add interfaces even if they have no addresses.)
603*d56f51eaSDavid van Moolenbroek  */
604*d56f51eaSDavid van Moolenbroek int
add_addr_to_iflist(pcap_if_t ** alldevs,const char * name,u_int flags,struct sockaddr * addr,size_t addr_size,struct sockaddr * netmask,size_t netmask_size,struct sockaddr * broadaddr,size_t broadaddr_size,struct sockaddr * dstaddr,size_t dstaddr_size,char * errbuf)605*d56f51eaSDavid van Moolenbroek add_addr_to_iflist(pcap_if_t **alldevs, const char *name, u_int flags,
606*d56f51eaSDavid van Moolenbroek     struct sockaddr *addr, size_t addr_size,
607*d56f51eaSDavid van Moolenbroek     struct sockaddr *netmask, size_t netmask_size,
608*d56f51eaSDavid van Moolenbroek     struct sockaddr *broadaddr, size_t broadaddr_size,
609*d56f51eaSDavid van Moolenbroek     struct sockaddr *dstaddr, size_t dstaddr_size,
610*d56f51eaSDavid van Moolenbroek     char *errbuf)
611*d56f51eaSDavid van Moolenbroek {
612*d56f51eaSDavid van Moolenbroek 	char *description;
613*d56f51eaSDavid van Moolenbroek 	pcap_if_t *curdev;
614*d56f51eaSDavid van Moolenbroek 
615*d56f51eaSDavid van Moolenbroek 	description = get_if_description(name);
616*d56f51eaSDavid van Moolenbroek 	if (add_or_find_if(&curdev, alldevs, name, flags, description,
617*d56f51eaSDavid van Moolenbroek 	    errbuf) == -1) {
618*d56f51eaSDavid van Moolenbroek 		free(description);
619*d56f51eaSDavid van Moolenbroek 		/*
620*d56f51eaSDavid van Moolenbroek 		 * Error - give up.
621*d56f51eaSDavid van Moolenbroek 		 */
622*d56f51eaSDavid van Moolenbroek 		return (-1);
623*d56f51eaSDavid van Moolenbroek 	}
624*d56f51eaSDavid van Moolenbroek 	free(description);
625*d56f51eaSDavid van Moolenbroek 	if (curdev == NULL) {
626*d56f51eaSDavid van Moolenbroek 		/*
627*d56f51eaSDavid van Moolenbroek 		 * Device wasn't added because it can't be opened.
628*d56f51eaSDavid van Moolenbroek 		 * Not a fatal error.
629*d56f51eaSDavid van Moolenbroek 		 */
630*d56f51eaSDavid van Moolenbroek 		return (0);
631*d56f51eaSDavid van Moolenbroek 	}
632*d56f51eaSDavid van Moolenbroek 
633*d56f51eaSDavid van Moolenbroek 	if (addr == NULL) {
634*d56f51eaSDavid van Moolenbroek 		/*
635*d56f51eaSDavid van Moolenbroek 		 * There's no address to add; this entry just meant
636*d56f51eaSDavid van Moolenbroek 		 * "here's a new interface".
637*d56f51eaSDavid van Moolenbroek 		 */
638*d56f51eaSDavid van Moolenbroek 		return (0);
639*d56f51eaSDavid van Moolenbroek 	}
640*d56f51eaSDavid van Moolenbroek 
641*d56f51eaSDavid van Moolenbroek 	/*
642*d56f51eaSDavid van Moolenbroek 	 * "curdev" is an entry for this interface, and we have an
643*d56f51eaSDavid van Moolenbroek 	 * address for it; add an entry for that address to the
644*d56f51eaSDavid van Moolenbroek 	 * interface's list of addresses.
645*d56f51eaSDavid van Moolenbroek 	 *
646*d56f51eaSDavid van Moolenbroek 	 * Allocate the new entry and fill it in.
647*d56f51eaSDavid van Moolenbroek 	 */
648*d56f51eaSDavid van Moolenbroek 	return (add_addr_to_dev(curdev, addr, addr_size, netmask,
649*d56f51eaSDavid van Moolenbroek 	    netmask_size, broadaddr, broadaddr_size, dstaddr,
650*d56f51eaSDavid van Moolenbroek 	    dstaddr_size, errbuf));
651*d56f51eaSDavid van Moolenbroek }
652*d56f51eaSDavid van Moolenbroek 
653*d56f51eaSDavid van Moolenbroek /*
654*d56f51eaSDavid van Moolenbroek  * Add an entry to the list of addresses for an interface.
655*d56f51eaSDavid van Moolenbroek  * "curdev" is the entry for that interface.
656*d56f51eaSDavid van Moolenbroek  * If this is the first IP address added to the interface, move it
657*d56f51eaSDavid van Moolenbroek  * in the list as appropriate.
658*d56f51eaSDavid van Moolenbroek  */
659*d56f51eaSDavid van Moolenbroek int
add_addr_to_dev(pcap_if_t * curdev,struct sockaddr * addr,size_t addr_size,struct sockaddr * netmask,size_t netmask_size,struct sockaddr * broadaddr,size_t broadaddr_size,struct sockaddr * dstaddr,size_t dstaddr_size,char * errbuf)660*d56f51eaSDavid van Moolenbroek add_addr_to_dev(pcap_if_t *curdev,
661*d56f51eaSDavid van Moolenbroek     struct sockaddr *addr, size_t addr_size,
662*d56f51eaSDavid van Moolenbroek     struct sockaddr *netmask, size_t netmask_size,
663*d56f51eaSDavid van Moolenbroek     struct sockaddr *broadaddr, size_t broadaddr_size,
664*d56f51eaSDavid van Moolenbroek     struct sockaddr *dstaddr, size_t dstaddr_size,
665*d56f51eaSDavid van Moolenbroek     char *errbuf)
666*d56f51eaSDavid van Moolenbroek {
667*d56f51eaSDavid van Moolenbroek 	pcap_addr_t *curaddr, *prevaddr, *nextaddr;
668*d56f51eaSDavid van Moolenbroek 
669*d56f51eaSDavid van Moolenbroek 	curaddr = malloc(sizeof(pcap_addr_t));
670*d56f51eaSDavid van Moolenbroek 	if (curaddr == NULL) {
671*d56f51eaSDavid van Moolenbroek 		(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
672*d56f51eaSDavid van Moolenbroek 		    "malloc: %s", pcap_strerror(errno));
673*d56f51eaSDavid van Moolenbroek 		return (-1);
674*d56f51eaSDavid van Moolenbroek 	}
675*d56f51eaSDavid van Moolenbroek 
676*d56f51eaSDavid van Moolenbroek 	curaddr->next = NULL;
677*d56f51eaSDavid van Moolenbroek 	if (addr != NULL) {
678*d56f51eaSDavid van Moolenbroek 		curaddr->addr = dup_sockaddr(addr, addr_size);
679*d56f51eaSDavid van Moolenbroek 		if (curaddr->addr == NULL) {
680*d56f51eaSDavid van Moolenbroek 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
681*d56f51eaSDavid van Moolenbroek 			    "malloc: %s", pcap_strerror(errno));
682*d56f51eaSDavid van Moolenbroek 			free(curaddr);
683*d56f51eaSDavid van Moolenbroek 			return (-1);
684*d56f51eaSDavid van Moolenbroek 		}
685*d56f51eaSDavid van Moolenbroek 	} else
686*d56f51eaSDavid van Moolenbroek 		curaddr->addr = NULL;
687*d56f51eaSDavid van Moolenbroek 
688*d56f51eaSDavid van Moolenbroek 	if (netmask != NULL) {
689*d56f51eaSDavid van Moolenbroek 		curaddr->netmask = dup_sockaddr(netmask, netmask_size);
690*d56f51eaSDavid van Moolenbroek 		if (curaddr->netmask == NULL) {
691*d56f51eaSDavid van Moolenbroek 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
692*d56f51eaSDavid van Moolenbroek 			    "malloc: %s", pcap_strerror(errno));
693*d56f51eaSDavid van Moolenbroek 			if (curaddr->addr != NULL)
694*d56f51eaSDavid van Moolenbroek 				free(curaddr->addr);
695*d56f51eaSDavid van Moolenbroek 			free(curaddr);
696*d56f51eaSDavid van Moolenbroek 			return (-1);
697*d56f51eaSDavid van Moolenbroek 		}
698*d56f51eaSDavid van Moolenbroek 	} else
699*d56f51eaSDavid van Moolenbroek 		curaddr->netmask = NULL;
700*d56f51eaSDavid van Moolenbroek 
701*d56f51eaSDavid van Moolenbroek 	if (broadaddr != NULL) {
702*d56f51eaSDavid van Moolenbroek 		curaddr->broadaddr = dup_sockaddr(broadaddr, broadaddr_size);
703*d56f51eaSDavid van Moolenbroek 		if (curaddr->broadaddr == NULL) {
704*d56f51eaSDavid van Moolenbroek 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
705*d56f51eaSDavid van Moolenbroek 			    "malloc: %s", pcap_strerror(errno));
706*d56f51eaSDavid van Moolenbroek 			if (curaddr->netmask != NULL)
707*d56f51eaSDavid van Moolenbroek 				free(curaddr->netmask);
708*d56f51eaSDavid van Moolenbroek 			if (curaddr->addr != NULL)
709*d56f51eaSDavid van Moolenbroek 				free(curaddr->addr);
710*d56f51eaSDavid van Moolenbroek 			free(curaddr);
711*d56f51eaSDavid van Moolenbroek 			return (-1);
712*d56f51eaSDavid van Moolenbroek 		}
713*d56f51eaSDavid van Moolenbroek 	} else
714*d56f51eaSDavid van Moolenbroek 		curaddr->broadaddr = NULL;
715*d56f51eaSDavid van Moolenbroek 
716*d56f51eaSDavid van Moolenbroek 	if (dstaddr != NULL) {
717*d56f51eaSDavid van Moolenbroek 		curaddr->dstaddr = dup_sockaddr(dstaddr, dstaddr_size);
718*d56f51eaSDavid van Moolenbroek 		if (curaddr->dstaddr == NULL) {
719*d56f51eaSDavid van Moolenbroek 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
720*d56f51eaSDavid van Moolenbroek 			    "malloc: %s", pcap_strerror(errno));
721*d56f51eaSDavid van Moolenbroek 			if (curaddr->broadaddr != NULL)
722*d56f51eaSDavid van Moolenbroek 				free(curaddr->broadaddr);
723*d56f51eaSDavid van Moolenbroek 			if (curaddr->netmask != NULL)
724*d56f51eaSDavid van Moolenbroek 				free(curaddr->netmask);
725*d56f51eaSDavid van Moolenbroek 			if (curaddr->addr != NULL)
726*d56f51eaSDavid van Moolenbroek 				free(curaddr->addr);
727*d56f51eaSDavid van Moolenbroek 			free(curaddr);
728*d56f51eaSDavid van Moolenbroek 			return (-1);
729*d56f51eaSDavid van Moolenbroek 		}
730*d56f51eaSDavid van Moolenbroek 	} else
731*d56f51eaSDavid van Moolenbroek 		curaddr->dstaddr = NULL;
732*d56f51eaSDavid van Moolenbroek 
733*d56f51eaSDavid van Moolenbroek 	/*
734*d56f51eaSDavid van Moolenbroek 	 * Find the end of the list of addresses.
735*d56f51eaSDavid van Moolenbroek 	 */
736*d56f51eaSDavid van Moolenbroek 	for (prevaddr = curdev->addresses; prevaddr != NULL; prevaddr = nextaddr) {
737*d56f51eaSDavid van Moolenbroek 		nextaddr = prevaddr->next;
738*d56f51eaSDavid van Moolenbroek 		if (nextaddr == NULL) {
739*d56f51eaSDavid van Moolenbroek 			/*
740*d56f51eaSDavid van Moolenbroek 			 * This is the end of the list.
741*d56f51eaSDavid van Moolenbroek 			 */
742*d56f51eaSDavid van Moolenbroek 			break;
743*d56f51eaSDavid van Moolenbroek 		}
744*d56f51eaSDavid van Moolenbroek 	}
745*d56f51eaSDavid van Moolenbroek 
746*d56f51eaSDavid van Moolenbroek 	if (prevaddr == NULL) {
747*d56f51eaSDavid van Moolenbroek 		/*
748*d56f51eaSDavid van Moolenbroek 		 * The list was empty; this is the first member.
749*d56f51eaSDavid van Moolenbroek 		 */
750*d56f51eaSDavid van Moolenbroek 		curdev->addresses = curaddr;
751*d56f51eaSDavid van Moolenbroek 	} else {
752*d56f51eaSDavid van Moolenbroek 		/*
753*d56f51eaSDavid van Moolenbroek 		 * "prevaddr" is the last member of the list; append
754*d56f51eaSDavid van Moolenbroek 		 * this member to it.
755*d56f51eaSDavid van Moolenbroek 		 */
756*d56f51eaSDavid van Moolenbroek 		prevaddr->next = curaddr;
757*d56f51eaSDavid van Moolenbroek 	}
758*d56f51eaSDavid van Moolenbroek 
759*d56f51eaSDavid van Moolenbroek 	return (0);
760*d56f51eaSDavid van Moolenbroek }
761*d56f51eaSDavid van Moolenbroek 
762*d56f51eaSDavid van Moolenbroek /*
763*d56f51eaSDavid van Moolenbroek  * Look for a given device in the specified list of devices.
764*d56f51eaSDavid van Moolenbroek  *
765*d56f51eaSDavid van Moolenbroek  * If we find it, return 0.
766*d56f51eaSDavid van Moolenbroek  *
767*d56f51eaSDavid van Moolenbroek  * If we don't find it, check whether we can open it:
768*d56f51eaSDavid van Moolenbroek  *
769*d56f51eaSDavid van Moolenbroek  *     If that fails with PCAP_ERROR_NO_SUCH_DEVICE or
770*d56f51eaSDavid van Moolenbroek  *     PCAP_ERROR_IFACE_NOT_UP, don't attempt to add an entry for
771*d56f51eaSDavid van Moolenbroek  *     it, as that probably means it exists but doesn't support
772*d56f51eaSDavid van Moolenbroek  *     packet capture.
773*d56f51eaSDavid van Moolenbroek  *
774*d56f51eaSDavid van Moolenbroek  *     Otherwise, attempt to add an entry for it, with the specified
775*d56f51eaSDavid van Moolenbroek  *     ifnet flags and description, and, if that succeeds, return 0
776*d56f51eaSDavid van Moolenbroek  *     and set *curdev_ret to point to the new entry, otherwise
777*d56f51eaSDavid van Moolenbroek  *     return PCAP_ERROR and set errbuf to an error message.
778*d56f51eaSDavid van Moolenbroek  */
779*d56f51eaSDavid van Moolenbroek int
pcap_add_if(pcap_if_t ** devlist,const char * name,u_int flags,const char * description,char * errbuf)780*d56f51eaSDavid van Moolenbroek pcap_add_if(pcap_if_t **devlist, const char *name, u_int flags,
781*d56f51eaSDavid van Moolenbroek     const char *description, char *errbuf)
782*d56f51eaSDavid van Moolenbroek {
783*d56f51eaSDavid van Moolenbroek 	pcap_if_t *curdev;
784*d56f51eaSDavid van Moolenbroek 
785*d56f51eaSDavid van Moolenbroek 	return (add_or_find_if(&curdev, devlist, name, flags, description,
786*d56f51eaSDavid van Moolenbroek 	    errbuf));
787*d56f51eaSDavid van Moolenbroek }
788*d56f51eaSDavid van Moolenbroek 
789*d56f51eaSDavid van Moolenbroek 
790*d56f51eaSDavid van Moolenbroek /*
791*d56f51eaSDavid van Moolenbroek  * Free a list of interfaces.
792*d56f51eaSDavid van Moolenbroek  */
793*d56f51eaSDavid van Moolenbroek void
pcap_freealldevs(pcap_if_t * alldevs)794*d56f51eaSDavid van Moolenbroek pcap_freealldevs(pcap_if_t *alldevs)
795*d56f51eaSDavid van Moolenbroek {
796*d56f51eaSDavid van Moolenbroek 	pcap_if_t *curdev, *nextdev;
797*d56f51eaSDavid van Moolenbroek 	pcap_addr_t *curaddr, *nextaddr;
798*d56f51eaSDavid van Moolenbroek 
799*d56f51eaSDavid van Moolenbroek 	for (curdev = alldevs; curdev != NULL; curdev = nextdev) {
800*d56f51eaSDavid van Moolenbroek 		nextdev = curdev->next;
801*d56f51eaSDavid van Moolenbroek 
802*d56f51eaSDavid van Moolenbroek 		/*
803*d56f51eaSDavid van Moolenbroek 		 * Free all addresses.
804*d56f51eaSDavid van Moolenbroek 		 */
805*d56f51eaSDavid van Moolenbroek 		for (curaddr = curdev->addresses; curaddr != NULL; curaddr = nextaddr) {
806*d56f51eaSDavid van Moolenbroek 			nextaddr = curaddr->next;
807*d56f51eaSDavid van Moolenbroek 			if (curaddr->addr)
808*d56f51eaSDavid van Moolenbroek 				free(curaddr->addr);
809*d56f51eaSDavid van Moolenbroek 			if (curaddr->netmask)
810*d56f51eaSDavid van Moolenbroek 				free(curaddr->netmask);
811*d56f51eaSDavid van Moolenbroek 			if (curaddr->broadaddr)
812*d56f51eaSDavid van Moolenbroek 				free(curaddr->broadaddr);
813*d56f51eaSDavid van Moolenbroek 			if (curaddr->dstaddr)
814*d56f51eaSDavid van Moolenbroek 				free(curaddr->dstaddr);
815*d56f51eaSDavid van Moolenbroek 			free(curaddr);
816*d56f51eaSDavid van Moolenbroek 		}
817*d56f51eaSDavid van Moolenbroek 
818*d56f51eaSDavid van Moolenbroek 		/*
819*d56f51eaSDavid van Moolenbroek 		 * Free the name string.
820*d56f51eaSDavid van Moolenbroek 		 */
821*d56f51eaSDavid van Moolenbroek 		free(curdev->name);
822*d56f51eaSDavid van Moolenbroek 
823*d56f51eaSDavid van Moolenbroek 		/*
824*d56f51eaSDavid van Moolenbroek 		 * Free the description string, if any.
825*d56f51eaSDavid van Moolenbroek 		 */
826*d56f51eaSDavid van Moolenbroek 		if (curdev->description != NULL)
827*d56f51eaSDavid van Moolenbroek 			free(curdev->description);
828*d56f51eaSDavid van Moolenbroek 
829*d56f51eaSDavid van Moolenbroek 		/*
830*d56f51eaSDavid van Moolenbroek 		 * Free the interface.
831*d56f51eaSDavid van Moolenbroek 		 */
832*d56f51eaSDavid van Moolenbroek 		free(curdev);
833*d56f51eaSDavid van Moolenbroek 	}
834*d56f51eaSDavid van Moolenbroek }
835*d56f51eaSDavid van Moolenbroek 
836*d56f51eaSDavid van Moolenbroek #if !defined(WIN32) && !defined(MSDOS)
837*d56f51eaSDavid van Moolenbroek 
838*d56f51eaSDavid van Moolenbroek /*
839*d56f51eaSDavid van Moolenbroek  * Return the name of a network interface attached to the system, or NULL
840*d56f51eaSDavid van Moolenbroek  * if none can be found.  The interface must be configured up; the
841*d56f51eaSDavid van Moolenbroek  * lowest unit number is preferred; loopback is ignored.
842*d56f51eaSDavid van Moolenbroek  */
843*d56f51eaSDavid van Moolenbroek char *
pcap_lookupdev(errbuf)844*d56f51eaSDavid van Moolenbroek pcap_lookupdev(errbuf)
845*d56f51eaSDavid van Moolenbroek 	register char *errbuf;
846*d56f51eaSDavid van Moolenbroek {
847*d56f51eaSDavid van Moolenbroek 	pcap_if_t *alldevs;
848*d56f51eaSDavid van Moolenbroek /* for old BSD systems, including bsdi3 */
849*d56f51eaSDavid van Moolenbroek #ifndef IF_NAMESIZE
850*d56f51eaSDavid van Moolenbroek #define IF_NAMESIZE IFNAMSIZ
851*d56f51eaSDavid van Moolenbroek #endif
852*d56f51eaSDavid van Moolenbroek 	static char device[IF_NAMESIZE + 1];
853*d56f51eaSDavid van Moolenbroek 	char *ret;
854*d56f51eaSDavid van Moolenbroek 
855*d56f51eaSDavid van Moolenbroek 	if (pcap_findalldevs(&alldevs, errbuf) == -1)
856*d56f51eaSDavid van Moolenbroek 		return (NULL);
857*d56f51eaSDavid van Moolenbroek 
858*d56f51eaSDavid van Moolenbroek 	if (alldevs == NULL || (alldevs->flags & PCAP_IF_LOOPBACK)) {
859*d56f51eaSDavid van Moolenbroek 		/*
860*d56f51eaSDavid van Moolenbroek 		 * There are no devices on the list, or the first device
861*d56f51eaSDavid van Moolenbroek 		 * on the list is a loopback device, which means there
862*d56f51eaSDavid van Moolenbroek 		 * are no non-loopback devices on the list.  This means
863*d56f51eaSDavid van Moolenbroek 		 * we can't return any device.
864*d56f51eaSDavid van Moolenbroek 		 *
865*d56f51eaSDavid van Moolenbroek 		 * XXX - why not return a loopback device?  If we can't
866*d56f51eaSDavid van Moolenbroek 		 * capture on it, it won't be on the list, and if it's
867*d56f51eaSDavid van Moolenbroek 		 * on the list, there aren't any non-loopback devices,
868*d56f51eaSDavid van Moolenbroek 		 * so why not just supply it as the default device?
869*d56f51eaSDavid van Moolenbroek 		 */
870*d56f51eaSDavid van Moolenbroek 		(void)strlcpy(errbuf, "no suitable device found",
871*d56f51eaSDavid van Moolenbroek 		    PCAP_ERRBUF_SIZE);
872*d56f51eaSDavid van Moolenbroek 		ret = NULL;
873*d56f51eaSDavid van Moolenbroek 	} else {
874*d56f51eaSDavid van Moolenbroek 		/*
875*d56f51eaSDavid van Moolenbroek 		 * Return the name of the first device on the list.
876*d56f51eaSDavid van Moolenbroek 		 */
877*d56f51eaSDavid van Moolenbroek 		(void)strlcpy(device, alldevs->name, sizeof(device));
878*d56f51eaSDavid van Moolenbroek 		ret = device;
879*d56f51eaSDavid van Moolenbroek 	}
880*d56f51eaSDavid van Moolenbroek 
881*d56f51eaSDavid van Moolenbroek 	pcap_freealldevs(alldevs);
882*d56f51eaSDavid van Moolenbroek 	return (ret);
883*d56f51eaSDavid van Moolenbroek }
884*d56f51eaSDavid van Moolenbroek 
885*d56f51eaSDavid van Moolenbroek int
pcap_lookupnet(device,netp,maskp,errbuf)886*d56f51eaSDavid van Moolenbroek pcap_lookupnet(device, netp, maskp, errbuf)
887*d56f51eaSDavid van Moolenbroek 	register const char *device;
888*d56f51eaSDavid van Moolenbroek 	register bpf_u_int32 *netp, *maskp;
889*d56f51eaSDavid van Moolenbroek 	register char *errbuf;
890*d56f51eaSDavid van Moolenbroek {
891*d56f51eaSDavid van Moolenbroek 	register int fd;
892*d56f51eaSDavid van Moolenbroek 	register struct sockaddr_in *sin4;
893*d56f51eaSDavid van Moolenbroek 	struct ifreq ifr;
894*d56f51eaSDavid van Moolenbroek 
895*d56f51eaSDavid van Moolenbroek 	/*
896*d56f51eaSDavid van Moolenbroek 	 * The pseudo-device "any" listens on all interfaces and therefore
897*d56f51eaSDavid van Moolenbroek 	 * has the network address and -mask "0.0.0.0" therefore catching
898*d56f51eaSDavid van Moolenbroek 	 * all traffic. Using NULL for the interface is the same as "any".
899*d56f51eaSDavid van Moolenbroek 	 */
900*d56f51eaSDavid van Moolenbroek 	if (!device || strcmp(device, "any") == 0
901*d56f51eaSDavid van Moolenbroek #ifdef HAVE_DAG_API
902*d56f51eaSDavid van Moolenbroek 	    || strstr(device, "dag") != NULL
903*d56f51eaSDavid van Moolenbroek #endif
904*d56f51eaSDavid van Moolenbroek #ifdef HAVE_SEPTEL_API
905*d56f51eaSDavid van Moolenbroek 	    || strstr(device, "septel") != NULL
906*d56f51eaSDavid van Moolenbroek #endif
907*d56f51eaSDavid van Moolenbroek #ifdef PCAP_SUPPORT_BT
908*d56f51eaSDavid van Moolenbroek 	    || strstr(device, "bluetooth") != NULL
909*d56f51eaSDavid van Moolenbroek #endif
910*d56f51eaSDavid van Moolenbroek #ifdef PCAP_SUPPORT_USB
911*d56f51eaSDavid van Moolenbroek 	    || strstr(device, "usbmon") != NULL
912*d56f51eaSDavid van Moolenbroek #endif
913*d56f51eaSDavid van Moolenbroek #ifdef HAVE_SNF_API
914*d56f51eaSDavid van Moolenbroek 	    || strstr(device, "snf") != NULL
915*d56f51eaSDavid van Moolenbroek #endif
916*d56f51eaSDavid van Moolenbroek 	    ) {
917*d56f51eaSDavid van Moolenbroek 		*netp = *maskp = 0;
918*d56f51eaSDavid van Moolenbroek 		return 0;
919*d56f51eaSDavid van Moolenbroek 	}
920*d56f51eaSDavid van Moolenbroek 
921*d56f51eaSDavid van Moolenbroek 	fd = socket(AF_INET, SOCK_DGRAM, 0);
922*d56f51eaSDavid van Moolenbroek 	if (fd < 0) {
923*d56f51eaSDavid van Moolenbroek 		(void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "socket: %s",
924*d56f51eaSDavid van Moolenbroek 		    pcap_strerror(errno));
925*d56f51eaSDavid van Moolenbroek 		return (-1);
926*d56f51eaSDavid van Moolenbroek 	}
927*d56f51eaSDavid van Moolenbroek 	memset(&ifr, 0, sizeof(ifr));
928*d56f51eaSDavid van Moolenbroek #ifdef linux
929*d56f51eaSDavid van Moolenbroek 	/* XXX Work around Linux kernel bug */
930*d56f51eaSDavid van Moolenbroek 	ifr.ifr_addr.sa_family = AF_INET;
931*d56f51eaSDavid van Moolenbroek #endif
932*d56f51eaSDavid van Moolenbroek 	(void)strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
933*d56f51eaSDavid van Moolenbroek 	if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
934*d56f51eaSDavid van Moolenbroek 		if (errno == EADDRNOTAVAIL) {
935*d56f51eaSDavid van Moolenbroek 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
936*d56f51eaSDavid van Moolenbroek 			    "%s: no IPv4 address assigned", device);
937*d56f51eaSDavid van Moolenbroek 		} else {
938*d56f51eaSDavid van Moolenbroek 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
939*d56f51eaSDavid van Moolenbroek 			    "SIOCGIFADDR: %s: %s",
940*d56f51eaSDavid van Moolenbroek 			    device, pcap_strerror(errno));
941*d56f51eaSDavid van Moolenbroek 		}
942*d56f51eaSDavid van Moolenbroek 		(void)close(fd);
943*d56f51eaSDavid van Moolenbroek 		return (-1);
944*d56f51eaSDavid van Moolenbroek 	}
945*d56f51eaSDavid van Moolenbroek 	sin4 = (struct sockaddr_in *)&ifr.ifr_addr;
946*d56f51eaSDavid van Moolenbroek 	*netp = sin4->sin_addr.s_addr;
947*d56f51eaSDavid van Moolenbroek 	memset(&ifr, 0, sizeof(ifr));
948*d56f51eaSDavid van Moolenbroek #ifdef linux
949*d56f51eaSDavid van Moolenbroek 	/* XXX Work around Linux kernel bug */
950*d56f51eaSDavid van Moolenbroek 	ifr.ifr_addr.sa_family = AF_INET;
951*d56f51eaSDavid van Moolenbroek #endif
952*d56f51eaSDavid van Moolenbroek 	(void)strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
953*d56f51eaSDavid van Moolenbroek 	if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) {
954*d56f51eaSDavid van Moolenbroek 		(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
955*d56f51eaSDavid van Moolenbroek 		    "SIOCGIFNETMASK: %s: %s", device, pcap_strerror(errno));
956*d56f51eaSDavid van Moolenbroek 		(void)close(fd);
957*d56f51eaSDavid van Moolenbroek 		return (-1);
958*d56f51eaSDavid van Moolenbroek 	}
959*d56f51eaSDavid van Moolenbroek 	(void)close(fd);
960*d56f51eaSDavid van Moolenbroek 	*maskp = sin4->sin_addr.s_addr;
961*d56f51eaSDavid van Moolenbroek 	if (*maskp == 0) {
962*d56f51eaSDavid van Moolenbroek 		if (IN_CLASSA(*netp))
963*d56f51eaSDavid van Moolenbroek 			*maskp = IN_CLASSA_NET;
964*d56f51eaSDavid van Moolenbroek 		else if (IN_CLASSB(*netp))
965*d56f51eaSDavid van Moolenbroek 			*maskp = IN_CLASSB_NET;
966*d56f51eaSDavid van Moolenbroek 		else if (IN_CLASSC(*netp))
967*d56f51eaSDavid van Moolenbroek 			*maskp = IN_CLASSC_NET;
968*d56f51eaSDavid van Moolenbroek 		else {
969*d56f51eaSDavid van Moolenbroek 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
970*d56f51eaSDavid van Moolenbroek 			    "inet class for 0x%x unknown", *netp);
971*d56f51eaSDavid van Moolenbroek 			return (-1);
972*d56f51eaSDavid van Moolenbroek 		}
973*d56f51eaSDavid van Moolenbroek 	}
974*d56f51eaSDavid van Moolenbroek 	*netp &= *maskp;
975*d56f51eaSDavid van Moolenbroek 	return (0);
976*d56f51eaSDavid van Moolenbroek }
977*d56f51eaSDavid van Moolenbroek 
978*d56f51eaSDavid van Moolenbroek #elif defined(WIN32)
979*d56f51eaSDavid van Moolenbroek 
980*d56f51eaSDavid van Moolenbroek /*
981*d56f51eaSDavid van Moolenbroek  * Return the name of a network interface attached to the system, or NULL
982*d56f51eaSDavid van Moolenbroek  * if none can be found.  The interface must be configured up; the
983*d56f51eaSDavid van Moolenbroek  * lowest unit number is preferred; loopback is ignored.
984*d56f51eaSDavid van Moolenbroek  */
985*d56f51eaSDavid van Moolenbroek char *
pcap_lookupdev(errbuf)986*d56f51eaSDavid van Moolenbroek pcap_lookupdev(errbuf)
987*d56f51eaSDavid van Moolenbroek 	register char *errbuf;
988*d56f51eaSDavid van Moolenbroek {
989*d56f51eaSDavid van Moolenbroek 	DWORD dwVersion;
990*d56f51eaSDavid van Moolenbroek 	DWORD dwWindowsMajorVersion;
991*d56f51eaSDavid van Moolenbroek 	dwVersion = GetVersion();	/* get the OS version */
992*d56f51eaSDavid van Moolenbroek 	dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
993*d56f51eaSDavid van Moolenbroek 
994*d56f51eaSDavid van Moolenbroek 	if (dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4) {
995*d56f51eaSDavid van Moolenbroek 		/*
996*d56f51eaSDavid van Moolenbroek 		 * Windows 95, 98, ME.
997*d56f51eaSDavid van Moolenbroek 		 */
998*d56f51eaSDavid van Moolenbroek 		ULONG NameLength = 8192;
999*d56f51eaSDavid van Moolenbroek 		static char AdaptersName[8192];
1000*d56f51eaSDavid van Moolenbroek 
1001*d56f51eaSDavid van Moolenbroek 		if (PacketGetAdapterNames(AdaptersName,&NameLength) )
1002*d56f51eaSDavid van Moolenbroek 			return (AdaptersName);
1003*d56f51eaSDavid van Moolenbroek 		else
1004*d56f51eaSDavid van Moolenbroek 			return NULL;
1005*d56f51eaSDavid van Moolenbroek 	} else {
1006*d56f51eaSDavid van Moolenbroek 		/*
1007*d56f51eaSDavid van Moolenbroek 		 * Windows NT (NT 4.0, W2K, WXP). Convert the names to UNICODE for backward compatibility
1008*d56f51eaSDavid van Moolenbroek 		 */
1009*d56f51eaSDavid van Moolenbroek 		ULONG NameLength = 8192;
1010*d56f51eaSDavid van Moolenbroek 		static WCHAR AdaptersName[8192];
1011*d56f51eaSDavid van Moolenbroek 		char *tAstr;
1012*d56f51eaSDavid van Moolenbroek 		WCHAR *tUstr;
1013*d56f51eaSDavid van Moolenbroek 		WCHAR *TAdaptersName = (WCHAR*)malloc(8192 * sizeof(WCHAR));
1014*d56f51eaSDavid van Moolenbroek 		int NAdapts = 0;
1015*d56f51eaSDavid van Moolenbroek 
1016*d56f51eaSDavid van Moolenbroek 		if(TAdaptersName == NULL)
1017*d56f51eaSDavid van Moolenbroek 		{
1018*d56f51eaSDavid van Moolenbroek 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "memory allocation failure");
1019*d56f51eaSDavid van Moolenbroek 			return NULL;
1020*d56f51eaSDavid van Moolenbroek 		}
1021*d56f51eaSDavid van Moolenbroek 
1022*d56f51eaSDavid van Moolenbroek 		if ( !PacketGetAdapterNames((PTSTR)TAdaptersName,&NameLength) )
1023*d56f51eaSDavid van Moolenbroek 		{
1024*d56f51eaSDavid van Moolenbroek 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
1025*d56f51eaSDavid van Moolenbroek 				"PacketGetAdapterNames: %s",
1026*d56f51eaSDavid van Moolenbroek 				pcap_win32strerror());
1027*d56f51eaSDavid van Moolenbroek 			free(TAdaptersName);
1028*d56f51eaSDavid van Moolenbroek 			return NULL;
1029*d56f51eaSDavid van Moolenbroek 		}
1030*d56f51eaSDavid van Moolenbroek 
1031*d56f51eaSDavid van Moolenbroek 
1032*d56f51eaSDavid van Moolenbroek 		tAstr = (char*)TAdaptersName;
1033*d56f51eaSDavid van Moolenbroek 		tUstr = (WCHAR*)AdaptersName;
1034*d56f51eaSDavid van Moolenbroek 
1035*d56f51eaSDavid van Moolenbroek 		/*
1036*d56f51eaSDavid van Moolenbroek 		 * Convert and copy the device names
1037*d56f51eaSDavid van Moolenbroek 		 */
1038*d56f51eaSDavid van Moolenbroek 		while(sscanf(tAstr, "%S", tUstr) > 0)
1039*d56f51eaSDavid van Moolenbroek 		{
1040*d56f51eaSDavid van Moolenbroek 			tAstr += strlen(tAstr) + 1;
1041*d56f51eaSDavid van Moolenbroek 			tUstr += wcslen(tUstr) + 1;
1042*d56f51eaSDavid van Moolenbroek 			NAdapts ++;
1043*d56f51eaSDavid van Moolenbroek 		}
1044*d56f51eaSDavid van Moolenbroek 
1045*d56f51eaSDavid van Moolenbroek 		tAstr++;
1046*d56f51eaSDavid van Moolenbroek 		*tUstr = 0;
1047*d56f51eaSDavid van Moolenbroek 		tUstr++;
1048*d56f51eaSDavid van Moolenbroek 
1049*d56f51eaSDavid van Moolenbroek 		/*
1050*d56f51eaSDavid van Moolenbroek 		 * Copy the descriptions
1051*d56f51eaSDavid van Moolenbroek 		 */
1052*d56f51eaSDavid van Moolenbroek 		while(NAdapts--)
1053*d56f51eaSDavid van Moolenbroek 		{
1054*d56f51eaSDavid van Moolenbroek 			char* tmp = (char*)tUstr;
1055*d56f51eaSDavid van Moolenbroek 			strcpy(tmp, tAstr);
1056*d56f51eaSDavid van Moolenbroek 			tmp += strlen(tAstr) + 1;
1057*d56f51eaSDavid van Moolenbroek 			tUstr = (WCHAR*)tmp;
1058*d56f51eaSDavid van Moolenbroek 			tAstr += strlen(tAstr) + 1;
1059*d56f51eaSDavid van Moolenbroek 		}
1060*d56f51eaSDavid van Moolenbroek 
1061*d56f51eaSDavid van Moolenbroek 		free(TAdaptersName);
1062*d56f51eaSDavid van Moolenbroek 		return (char *)(AdaptersName);
1063*d56f51eaSDavid van Moolenbroek 	}
1064*d56f51eaSDavid van Moolenbroek }
1065*d56f51eaSDavid van Moolenbroek 
1066*d56f51eaSDavid van Moolenbroek 
1067*d56f51eaSDavid van Moolenbroek int
pcap_lookupnet(device,netp,maskp,errbuf)1068*d56f51eaSDavid van Moolenbroek pcap_lookupnet(device, netp, maskp, errbuf)
1069*d56f51eaSDavid van Moolenbroek 	register const char *device;
1070*d56f51eaSDavid van Moolenbroek 	register bpf_u_int32 *netp, *maskp;
1071*d56f51eaSDavid van Moolenbroek 	register char *errbuf;
1072*d56f51eaSDavid van Moolenbroek {
1073*d56f51eaSDavid van Moolenbroek 	/*
1074*d56f51eaSDavid van Moolenbroek 	 * We need only the first IPv4 address, so we must scan the array returned by PacketGetNetInfo()
1075*d56f51eaSDavid van Moolenbroek 	 * in order to skip non IPv4 (i.e. IPv6 addresses)
1076*d56f51eaSDavid van Moolenbroek 	 */
1077*d56f51eaSDavid van Moolenbroek 	npf_if_addr if_addrs[MAX_NETWORK_ADDRESSES];
1078*d56f51eaSDavid van Moolenbroek 	LONG if_addr_size = 1;
1079*d56f51eaSDavid van Moolenbroek 	struct sockaddr_in *t_addr;
1080*d56f51eaSDavid van Moolenbroek 	unsigned int i;
1081*d56f51eaSDavid van Moolenbroek 
1082*d56f51eaSDavid van Moolenbroek 	if (!PacketGetNetInfoEx((void *)device, if_addrs, &if_addr_size)) {
1083*d56f51eaSDavid van Moolenbroek 		*netp = *maskp = 0;
1084*d56f51eaSDavid van Moolenbroek 		return (0);
1085*d56f51eaSDavid van Moolenbroek 	}
1086*d56f51eaSDavid van Moolenbroek 
1087*d56f51eaSDavid van Moolenbroek 	for(i=0; i<MAX_NETWORK_ADDRESSES; i++)
1088*d56f51eaSDavid van Moolenbroek 	{
1089*d56f51eaSDavid van Moolenbroek 		if(if_addrs[i].IPAddress.ss_family == AF_INET)
1090*d56f51eaSDavid van Moolenbroek 		{
1091*d56f51eaSDavid van Moolenbroek 			t_addr = (struct sockaddr_in *) &(if_addrs[i].IPAddress);
1092*d56f51eaSDavid van Moolenbroek 			*netp = t_addr->sin_addr.S_un.S_addr;
1093*d56f51eaSDavid van Moolenbroek 			t_addr = (struct sockaddr_in *) &(if_addrs[i].SubnetMask);
1094*d56f51eaSDavid van Moolenbroek 			*maskp = t_addr->sin_addr.S_un.S_addr;
1095*d56f51eaSDavid van Moolenbroek 
1096*d56f51eaSDavid van Moolenbroek 			*netp &= *maskp;
1097*d56f51eaSDavid van Moolenbroek 			return (0);
1098*d56f51eaSDavid van Moolenbroek 		}
1099*d56f51eaSDavid van Moolenbroek 
1100*d56f51eaSDavid van Moolenbroek 	}
1101*d56f51eaSDavid van Moolenbroek 
1102*d56f51eaSDavid van Moolenbroek 	*netp = *maskp = 0;
1103*d56f51eaSDavid van Moolenbroek 	return (0);
1104*d56f51eaSDavid van Moolenbroek }
1105*d56f51eaSDavid van Moolenbroek 
1106*d56f51eaSDavid van Moolenbroek #endif /* !WIN32 && !MSDOS */
1107