1 /* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
2 /*
3  * Copyright (c) 1994, 1995, 1996, 1997, 1998
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by the Computer Systems
17  *	Engineering Group at Lawrence Berkeley Laboratory.
18  * 4. Neither the name of the University nor of the Laboratory may be used
19  *    to endorse or promote products derived from this software without
20  *    specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38 
39 #ifdef _WIN32
40 #include <pcap-stdinc.h>
41 #else /* _WIN32 */
42 
43 #include <sys/param.h>
44 #ifndef MSDOS
45 #include <sys/file.h>
46 #endif
47 #include <sys/ioctl.h>
48 #include <sys/socket.h>
49 #ifdef HAVE_SYS_SOCKIO_H
50 #include <sys/sockio.h>
51 #endif
52 
53 struct mbuf;		/* Squelch compiler warnings on some platforms for */
54 struct rtentry;		/* declarations in <net/if.h> */
55 #include <net/if.h>
56 #include <netinet/in.h>
57 #endif /* _WIN32 */
58 
59 #include <errno.h>
60 #include <memory.h>
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #if !defined(_WIN32) && !defined(__BORLANDC__)
65 #include <unistd.h>
66 #endif /* !_WIN32 && !__BORLANDC__ */
67 
68 #include "pcap-int.h"
69 
70 #ifdef HAVE_OS_PROTO_H
71 #include "os-proto.h"
72 #endif
73 
74 #if !defined(_WIN32) && !defined(MSDOS)
75 
76 /*
77  * Return the name of a network interface attached to the system, or NULL
78  * if none can be found.  The interface must be configured up; the
79  * lowest unit number is preferred; loopback is ignored.
80  */
81 char *
pcap_lookupdev(errbuf)82 pcap_lookupdev(errbuf)
83 	register char *errbuf;
84 {
85 	pcap_if_t *alldevs;
86 /* for old BSD systems, including bsdi3 */
87 #ifndef IF_NAMESIZE
88 #define IF_NAMESIZE IFNAMSIZ
89 #endif
90 	static char device[IF_NAMESIZE + 1];
91 	char *ret;
92 
93 	if (pcap_findalldevs(&alldevs, errbuf) == -1)
94 		return (NULL);
95 
96 	if (alldevs == NULL || (alldevs->flags & PCAP_IF_LOOPBACK)) {
97 		/*
98 		 * There are no devices on the list, or the first device
99 		 * on the list is a loopback device, which means there
100 		 * are no non-loopback devices on the list.  This means
101 		 * we can't return any device.
102 		 *
103 		 * XXX - why not return a loopback device?  If we can't
104 		 * capture on it, it won't be on the list, and if it's
105 		 * on the list, there aren't any non-loopback devices,
106 		 * so why not just supply it as the default device?
107 		 */
108 		(void)strlcpy(errbuf, "no suitable device found",
109 		    PCAP_ERRBUF_SIZE);
110 		ret = NULL;
111 	} else {
112 		/*
113 		 * Return the name of the first device on the list.
114 		 */
115 		(void)strlcpy(device, alldevs->name, sizeof(device));
116 		ret = device;
117 	}
118 
119 	pcap_freealldevs(alldevs);
120 	return (ret);
121 }
122 
123 int
pcap_lookupnet(device,netp,maskp,errbuf)124 pcap_lookupnet(device, netp, maskp, errbuf)
125 	register const char *device;
126 	register bpf_u_int32 *netp, *maskp;
127 	register char *errbuf;
128 {
129 	register int fd;
130 	register struct sockaddr_in *sin4;
131 	struct ifreq ifr;
132 
133 	/*
134 	 * The pseudo-device "any" listens on all interfaces and therefore
135 	 * has the network address and -mask "0.0.0.0" therefore catching
136 	 * all traffic. Using NULL for the interface is the same as "any".
137 	 */
138 	if (!device || strcmp(device, "any") == 0
139 #ifdef HAVE_DAG_API
140 	    || strstr(device, "dag") != NULL
141 #endif
142 #ifdef HAVE_SEPTEL_API
143 	    || strstr(device, "septel") != NULL
144 #endif
145 #ifdef PCAP_SUPPORT_BT
146 	    || strstr(device, "bluetooth") != NULL
147 #endif
148 #ifdef PCAP_SUPPORT_USB
149 	    || strstr(device, "usbmon") != NULL
150 #endif
151 #ifdef HAVE_SNF_API
152 	    || strstr(device, "snf") != NULL
153 #endif
154 	    ) {
155 		*netp = *maskp = 0;
156 		return 0;
157 	}
158 
159 	fd = socket(AF_INET, SOCK_DGRAM, 0);
160 	if (fd < 0) {
161 		(void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "socket: %s",
162 		    pcap_strerror(errno));
163 		return (-1);
164 	}
165 	memset(&ifr, 0, sizeof(ifr));
166 #ifdef linux
167 	/* XXX Work around Linux kernel bug */
168 	ifr.ifr_addr.sa_family = AF_INET;
169 #endif
170 	(void)strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
171 	if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
172 		if (errno == EADDRNOTAVAIL) {
173 			(void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
174 			    "%s: no IPv4 address assigned", device);
175 		} else {
176 			(void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
177 			    "SIOCGIFADDR: %s: %s",
178 			    device, pcap_strerror(errno));
179 		}
180 		(void)close(fd);
181 		return (-1);
182 	}
183 	sin4 = (struct sockaddr_in *)&ifr.ifr_addr;
184 	*netp = sin4->sin_addr.s_addr;
185 	memset(&ifr, 0, sizeof(ifr));
186 #ifdef linux
187 	/* XXX Work around Linux kernel bug */
188 	ifr.ifr_addr.sa_family = AF_INET;
189 #endif
190 	(void)strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
191 	if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) {
192 		(void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
193 		    "SIOCGIFNETMASK: %s: %s", device, pcap_strerror(errno));
194 		(void)close(fd);
195 		return (-1);
196 	}
197 	(void)close(fd);
198 	*maskp = sin4->sin_addr.s_addr;
199 	if (*maskp == 0) {
200 		if (IN_CLASSA(*netp))
201 			*maskp = IN_CLASSA_NET;
202 		else if (IN_CLASSB(*netp))
203 			*maskp = IN_CLASSB_NET;
204 		else if (IN_CLASSC(*netp))
205 			*maskp = IN_CLASSC_NET;
206 		else {
207 			(void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
208 			    "inet class for 0x%x unknown", *netp);
209 			return (-1);
210 		}
211 	}
212 	*netp &= *maskp;
213 	return (0);
214 }
215 
216 #elif defined(_WIN32)
217 
218 /*
219  * Return the name of a network interface attached to the system, or NULL
220  * if none can be found.  The interface must be configured up; the
221  * lowest unit number is preferred; loopback is ignored.
222  *
223  * In the best of all possible worlds, this would be the same as on
224  * UN*X, but there may be software that expects this to return a
225  * full list of devices after the first device.
226  */
227 #define ADAPTERSNAME_LEN	8192
228 char *
pcap_lookupdev(errbuf)229 pcap_lookupdev(errbuf)
230 	register char *errbuf;
231 {
232 	DWORD dwVersion;
233 	DWORD dwWindowsMajorVersion;
234 	char our_errbuf[PCAP_ERRBUF_SIZE+1];
235 
236 #pragma warning (push)
237 #pragma warning (disable: 4996) /* disable MSVC's GetVersion() deprecated warning here */
238 	dwVersion = GetVersion();	/* get the OS version */
239 #pragma warning (pop)
240 	dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
241 
242 	if (dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4) {
243 		/*
244 		 * Windows 95, 98, ME.
245 		 */
246 		ULONG NameLength = ADAPTERSNAME_LEN;
247 		static char AdaptersName[ADAPTERSNAME_LEN];
248 
249 		if (PacketGetAdapterNames(AdaptersName,&NameLength) )
250 			return (AdaptersName);
251 		else
252 			return NULL;
253 	} else {
254 		/*
255 		 * Windows NT (NT 4.0 and later).
256 		 * Convert the names to Unicode for backward compatibility.
257 		 */
258 		ULONG NameLength = ADAPTERSNAME_LEN;
259 		static WCHAR AdaptersName[ADAPTERSNAME_LEN];
260 		size_t BufferSpaceLeft;
261 		char *tAstr;
262 		WCHAR *Unameptr;
263 		char *Adescptr;
264 		size_t namelen, i;
265 		WCHAR *TAdaptersName = (WCHAR*)malloc(ADAPTERSNAME_LEN * sizeof(WCHAR));
266 		int NAdapts = 0;
267 
268 		if(TAdaptersName == NULL)
269 		{
270 			(void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "memory allocation failure");
271 			return NULL;
272 		}
273 
274 		if ( !PacketGetAdapterNames((PTSTR)TAdaptersName,&NameLength) )
275 		{
276 			pcap_win32_err_to_str(GetLastError(), our_errbuf);
277 			(void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
278 				"PacketGetAdapterNames: %s", our_errbuf);
279 			free(TAdaptersName);
280 			return NULL;
281 		}
282 
283 
284 		BufferSpaceLeft = ADAPTERSNAME_LEN * sizeof(WCHAR);
285 		tAstr = (char*)TAdaptersName;
286 		Unameptr = AdaptersName;
287 
288 		/*
289 		 * Convert the device names to Unicode into AdapterName.
290 		 */
291 		do {
292 			/*
293 			 * Length of the name, including the terminating
294 			 * NUL.
295 			 */
296 			namelen = strlen(tAstr) + 1;
297 
298 			/*
299 			 * Do we have room for the name in the Unicode
300 			 * buffer?
301 			 */
302 			if (BufferSpaceLeft < namelen * sizeof(WCHAR)) {
303 				/*
304 				 * No.
305 				 */
306 				goto quit;
307 			}
308 			BufferSpaceLeft -= namelen * sizeof(WCHAR);
309 
310 			/*
311 			 * Copy the name, converting ASCII to Unicode.
312 			 * namelen includes the NUL, so we copy it as
313 			 * well.
314 			 */
315 			for (i = 0; i < namelen; i++)
316 				*Unameptr++ = *tAstr++;
317 
318 			/*
319 			 * Count this adapter.
320 			 */
321 			NAdapts++;
322 		} while (namelen != 1);
323 
324 		/*
325 		 * Copy the descriptions, but don't convert them from
326 		 * ASCII to Unicode.
327 		 */
328 		Adescptr = (char *)Unameptr;
329 		while(NAdapts--)
330 		{
331 			size_t desclen;
332 
333 			desclen = strlen(tAstr) + 1;
334 
335 			/*
336 			 * Do we have room for the name in the Unicode
337 			 * buffer?
338 			 */
339 			if (BufferSpaceLeft < desclen) {
340 				/*
341 				 * No.
342 				 */
343 				goto quit;
344 			}
345 
346 			/*
347 			 * Just copy the ASCII string.
348 			 * namelen includes the NUL, so we copy it as
349 			 * well.
350 			 */
351 			memcpy(Adescptr, tAstr, desclen);
352 			Adescptr += desclen;
353 			tAstr += desclen;
354 			BufferSpaceLeft -= desclen;
355 		}
356 
357 	quit:
358 		free(TAdaptersName);
359 		return (char *)(AdaptersName);
360 	}
361 }
362 
363 
364 int
pcap_lookupnet(device,netp,maskp,errbuf)365 pcap_lookupnet(device, netp, maskp, errbuf)
366 	register const char *device;
367 	register bpf_u_int32 *netp, *maskp;
368 	register char *errbuf;
369 {
370 	/*
371 	 * We need only the first IPv4 address, so we must scan the array returned by PacketGetNetInfo()
372 	 * in order to skip non IPv4 (i.e. IPv6 addresses)
373 	 */
374 	npf_if_addr if_addrs[MAX_NETWORK_ADDRESSES];
375 	LONG if_addr_size = 1;
376 	struct sockaddr_in *t_addr;
377 	unsigned int i;
378 
379 	if (!PacketGetNetInfoEx((void *)device, if_addrs, &if_addr_size)) {
380 		*netp = *maskp = 0;
381 		return (0);
382 	}
383 
384 	for(i=0; i<MAX_NETWORK_ADDRESSES; i++)
385 	{
386 		if(if_addrs[i].IPAddress.ss_family == AF_INET)
387 		{
388 			t_addr = (struct sockaddr_in *) &(if_addrs[i].IPAddress);
389 			*netp = t_addr->sin_addr.S_un.S_addr;
390 			t_addr = (struct sockaddr_in *) &(if_addrs[i].SubnetMask);
391 			*maskp = t_addr->sin_addr.S_un.S_addr;
392 
393 			*netp &= *maskp;
394 			return (0);
395 		}
396 
397 	}
398 
399 	*netp = *maskp = 0;
400 	return (0);
401 }
402 
403 #endif /* !_WIN32 && !MSDOS */
404