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