]> The Tcpdump Group git mirrors - libpcap/blob - inet.c
bfad07a1fe9456ba03e785ca2e67bbdca148a8cc
[libpcap] / inet.c
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 #ifndef _WIN32
40 #include <sys/param.h>
41 #ifndef MSDOS
42 #include <sys/file.h>
43 #endif
44 #include <sys/ioctl.h>
45 #include <sys/socket.h>
46 #ifdef HAVE_SYS_SOCKIO_H
47 #include <sys/sockio.h>
48 #endif
49
50 struct mbuf; /* Squelch compiler warnings on some platforms for */
51 struct rtentry; /* declarations in <net/if.h> */
52 #include <net/if.h>
53 #include <netinet/in.h>
54 #endif /* _WIN32 */
55
56 #include <errno.h>
57 #include <memory.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #if !defined(_WIN32) && !defined(__BORLANDC__)
62 #include <unistd.h>
63 #endif /* !_WIN32 && !__BORLANDC__ */
64
65 #include "pcap-int.h"
66
67 #ifdef HAVE_OS_PROTO_H
68 #include "os-proto.h"
69 #endif
70
71 #if !defined(_WIN32) && !defined(MSDOS)
72
73 /*
74 * Return the name of a network interface attached to the system, or NULL
75 * if none can be found. The interface must be configured up; the
76 * lowest unit number is preferred; loopback is ignored.
77 */
78 char *
79 pcap_lookupdev(errbuf)
80 register char *errbuf;
81 {
82 pcap_if_t *alldevs;
83 /* for old BSD systems, including bsdi3 */
84 #ifndef IF_NAMESIZE
85 #define IF_NAMESIZE IFNAMSIZ
86 #endif
87 static char device[IF_NAMESIZE + 1];
88 char *ret;
89
90 if (pcap_findalldevs(&alldevs, errbuf) == -1)
91 return (NULL);
92
93 if (alldevs == NULL || (alldevs->flags & PCAP_IF_LOOPBACK)) {
94 /*
95 * There are no devices on the list, or the first device
96 * on the list is a loopback device, which means there
97 * are no non-loopback devices on the list. This means
98 * we can't return any device.
99 *
100 * XXX - why not return a loopback device? If we can't
101 * capture on it, it won't be on the list, and if it's
102 * on the list, there aren't any non-loopback devices,
103 * so why not just supply it as the default device?
104 */
105 (void)strlcpy(errbuf, "no suitable device found",
106 PCAP_ERRBUF_SIZE);
107 ret = NULL;
108 } else {
109 /*
110 * Return the name of the first device on the list.
111 */
112 (void)strlcpy(device, alldevs->name, sizeof(device));
113 ret = device;
114 }
115
116 pcap_freealldevs(alldevs);
117 return (ret);
118 }
119
120 int
121 pcap_lookupnet(device, netp, maskp, errbuf)
122 register const char *device;
123 register bpf_u_int32 *netp, *maskp;
124 register char *errbuf;
125 {
126 register int fd;
127 register struct sockaddr_in *sin4;
128 struct ifreq ifr;
129
130 /*
131 * The pseudo-device "any" listens on all interfaces and therefore
132 * has the network address and -mask "0.0.0.0" therefore catching
133 * all traffic. Using NULL for the interface is the same as "any".
134 */
135 if (!device || strcmp(device, "any") == 0
136 #ifdef HAVE_DAG_API
137 || strstr(device, "dag") != NULL
138 #endif
139 #ifdef HAVE_SEPTEL_API
140 || strstr(device, "septel") != NULL
141 #endif
142 #ifdef PCAP_SUPPORT_BT
143 || strstr(device, "bluetooth") != NULL
144 #endif
145 #ifdef PCAP_SUPPORT_USB
146 || strstr(device, "usbmon") != NULL
147 #endif
148 #ifdef HAVE_SNF_API
149 || strstr(device, "snf") != NULL
150 #endif
151 #ifdef PCAP_SUPPORT_NETMAP
152 || strncmp(device, "netmap:", 7) == 0
153 || strncmp(device, "vale", 4) == 0
154 #endif
155 ) {
156 *netp = *maskp = 0;
157 return 0;
158 }
159
160 fd = socket(AF_INET, SOCK_DGRAM, 0);
161 if (fd < 0) {
162 (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "socket: %s",
163 pcap_strerror(errno));
164 return (-1);
165 }
166 memset(&ifr, 0, sizeof(ifr));
167 #ifdef linux
168 /* XXX Work around Linux kernel bug */
169 ifr.ifr_addr.sa_family = AF_INET;
170 #endif
171 (void)strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
172 if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
173 if (errno == EADDRNOTAVAIL) {
174 (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
175 "%s: no IPv4 address assigned", device);
176 } else {
177 (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
178 "SIOCGIFADDR: %s: %s",
179 device, pcap_strerror(errno));
180 }
181 (void)close(fd);
182 return (-1);
183 }
184 sin4 = (struct sockaddr_in *)&ifr.ifr_addr;
185 *netp = sin4->sin_addr.s_addr;
186 memset(&ifr, 0, sizeof(ifr));
187 #ifdef linux
188 /* XXX Work around Linux kernel bug */
189 ifr.ifr_addr.sa_family = AF_INET;
190 #endif
191 (void)strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
192 if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) {
193 (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
194 "SIOCGIFNETMASK: %s: %s", device, pcap_strerror(errno));
195 (void)close(fd);
196 return (-1);
197 }
198 (void)close(fd);
199 *maskp = sin4->sin_addr.s_addr;
200 if (*maskp == 0) {
201 if (IN_CLASSA(*netp))
202 *maskp = IN_CLASSA_NET;
203 else if (IN_CLASSB(*netp))
204 *maskp = IN_CLASSB_NET;
205 else if (IN_CLASSC(*netp))
206 *maskp = IN_CLASSC_NET;
207 else {
208 (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
209 "inet class for 0x%x unknown", *netp);
210 return (-1);
211 }
212 }
213 *netp &= *maskp;
214 return (0);
215 }
216
217 #elif defined(_WIN32)
218
219 /*
220 * Return the name of a network interface attached to the system, or NULL
221 * if none can be found. The interface must be configured up; the
222 * lowest unit number is preferred; loopback is ignored.
223 *
224 * In the best of all possible worlds, this would be the same as on
225 * UN*X, but there may be software that expects this to return a
226 * full list of devices after the first device.
227 */
228 #define ADAPTERSNAME_LEN 8192
229 char *
230 pcap_lookupdev(errbuf)
231 register char *errbuf;
232 {
233 DWORD dwVersion;
234 DWORD dwWindowsMajorVersion;
235 char our_errbuf[PCAP_ERRBUF_SIZE+1];
236
237 #pragma warning (push)
238 #pragma warning (disable: 4996) /* disable MSVC's GetVersion() deprecated warning here */
239 dwVersion = GetVersion(); /* get the OS version */
240 #pragma warning (pop)
241 dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
242
243 if (dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4) {
244 /*
245 * Windows 95, 98, ME.
246 */
247 ULONG NameLength = ADAPTERSNAME_LEN;
248 static char AdaptersName[ADAPTERSNAME_LEN];
249
250 if (PacketGetAdapterNames(AdaptersName,&NameLength) )
251 return (AdaptersName);
252 else
253 return NULL;
254 } else {
255 /*
256 * Windows NT (NT 4.0 and later).
257 * Convert the names to Unicode for backward compatibility.
258 */
259 ULONG NameLength = ADAPTERSNAME_LEN;
260 static WCHAR AdaptersName[ADAPTERSNAME_LEN];
261 size_t BufferSpaceLeft;
262 char *tAstr;
263 WCHAR *Unameptr;
264 char *Adescptr;
265 size_t namelen, i;
266 WCHAR *TAdaptersName = (WCHAR*)malloc(ADAPTERSNAME_LEN * sizeof(WCHAR));
267 int NAdapts = 0;
268
269 if(TAdaptersName == NULL)
270 {
271 (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "memory allocation failure");
272 return NULL;
273 }
274
275 if ( !PacketGetAdapterNames((PTSTR)TAdaptersName,&NameLength) )
276 {
277 pcap_win32_err_to_str(GetLastError(), our_errbuf);
278 (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
279 "PacketGetAdapterNames: %s", our_errbuf);
280 free(TAdaptersName);
281 return NULL;
282 }
283
284
285 BufferSpaceLeft = ADAPTERSNAME_LEN * sizeof(WCHAR);
286 tAstr = (char*)TAdaptersName;
287 Unameptr = AdaptersName;
288
289 /*
290 * Convert the device names to Unicode into AdapterName.
291 */
292 do {
293 /*
294 * Length of the name, including the terminating
295 * NUL.
296 */
297 namelen = strlen(tAstr) + 1;
298
299 /*
300 * Do we have room for the name in the Unicode
301 * buffer?
302 */
303 if (BufferSpaceLeft < namelen * sizeof(WCHAR)) {
304 /*
305 * No.
306 */
307 goto quit;
308 }
309 BufferSpaceLeft -= namelen * sizeof(WCHAR);
310
311 /*
312 * Copy the name, converting ASCII to Unicode.
313 * namelen includes the NUL, so we copy it as
314 * well.
315 */
316 for (i = 0; i < namelen; i++)
317 *Unameptr++ = *tAstr++;
318
319 /*
320 * Count this adapter.
321 */
322 NAdapts++;
323 } while (namelen != 1);
324
325 /*
326 * Copy the descriptions, but don't convert them from
327 * ASCII to Unicode.
328 */
329 Adescptr = (char *)Unameptr;
330 while(NAdapts--)
331 {
332 size_t desclen;
333
334 desclen = strlen(tAstr) + 1;
335
336 /*
337 * Do we have room for the name in the Unicode
338 * buffer?
339 */
340 if (BufferSpaceLeft < desclen) {
341 /*
342 * No.
343 */
344 goto quit;
345 }
346
347 /*
348 * Just copy the ASCII string.
349 * namelen includes the NUL, so we copy it as
350 * well.
351 */
352 memcpy(Adescptr, tAstr, desclen);
353 Adescptr += desclen;
354 tAstr += desclen;
355 BufferSpaceLeft -= desclen;
356 }
357
358 quit:
359 free(TAdaptersName);
360 return (char *)(AdaptersName);
361 }
362 }
363
364
365 int
366 pcap_lookupnet(device, netp, maskp, errbuf)
367 register const char *device;
368 register bpf_u_int32 *netp, *maskp;
369 register char *errbuf;
370 {
371 /*
372 * We need only the first IPv4 address, so we must scan the array returned by PacketGetNetInfo()
373 * in order to skip non IPv4 (i.e. IPv6 addresses)
374 */
375 npf_if_addr if_addrs[MAX_NETWORK_ADDRESSES];
376 LONG if_addr_size = MAX_NETWORK_ADDRESSES;
377 struct sockaddr_in *t_addr;
378 unsigned int i;
379
380 if (!PacketGetNetInfoEx((void *)device, if_addrs, &if_addr_size)) {
381 *netp = *maskp = 0;
382 return (0);
383 }
384
385 for(i = 0; i < if_addr_size; i++)
386 {
387 if(if_addrs[i].IPAddress.ss_family == AF_INET)
388 {
389 t_addr = (struct sockaddr_in *) &(if_addrs[i].IPAddress);
390 *netp = t_addr->sin_addr.S_un.S_addr;
391 t_addr = (struct sockaddr_in *) &(if_addrs[i].SubnetMask);
392 *maskp = t_addr->sin_addr.S_un.S_addr;
393
394 *netp &= *maskp;
395 return (0);
396 }
397
398 }
399
400 *netp = *maskp = 0;
401 return (0);
402 }
403
404 #endif /* !_WIN32 && !MSDOS */