]> The Tcpdump Group git mirrors - libpcap/blob - inet.c
pcap_create_interface() needs the interface name on Linux.
[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 #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 *
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
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 char *
228 pcap_lookupdev(errbuf)
229 register char *errbuf;
230 {
231 DWORD dwVersion;
232 DWORD dwWindowsMajorVersion;
233 char our_errbuf[PCAP_ERRBUF_SIZE+1];
234
235 dwVersion = GetVersion(); /* get the OS version */
236 dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
237
238 if (dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4) {
239 /*
240 * Windows 95, 98, ME.
241 */
242 ULONG NameLength = 8192;
243 static char AdaptersName[8192];
244
245 if (PacketGetAdapterNames(AdaptersName,&NameLength) )
246 return (AdaptersName);
247 else
248 return NULL;
249 } else {
250 /*
251 * Windows NT (NT 4.0, W2K, WXP). Convert the names to UNICODE for backward compatibility
252 */
253 ULONG NameLength = 8192;
254 static WCHAR AdaptersName[8192];
255 char *tAstr;
256 WCHAR *tUstr;
257 WCHAR *TAdaptersName = (WCHAR*)malloc(8192 * sizeof(WCHAR));
258 int NAdapts = 0;
259
260 if(TAdaptersName == NULL)
261 {
262 (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "memory allocation failure");
263 return NULL;
264 }
265
266 if ( !PacketGetAdapterNames((PTSTR)TAdaptersName,&NameLength) )
267 {
268 pcap_win32_err_to_str(GetLastError(), our_errbuf);
269 (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
270 "PacketGetAdapterNames: %s", our_errbuf);
271 free(TAdaptersName);
272 return NULL;
273 }
274
275
276 tAstr = (char*)TAdaptersName;
277 tUstr = (WCHAR*)AdaptersName;
278
279 /*
280 * Convert and copy the device names
281 */
282 while(sscanf(tAstr, "%S", tUstr) > 0)
283 {
284 tAstr += strlen(tAstr) + 1;
285 tUstr += wcslen(tUstr) + 1;
286 NAdapts ++;
287 }
288
289 tAstr++;
290 *tUstr = 0;
291 tUstr++;
292
293 /*
294 * Copy the descriptions
295 */
296 while(NAdapts--)
297 {
298 char* tmp = (char*)tUstr;
299 strcpy(tmp, tAstr);
300 tmp += strlen(tAstr) + 1;
301 tUstr = (WCHAR*)tmp;
302 tAstr += strlen(tAstr) + 1;
303 }
304
305 free(TAdaptersName);
306 return (char *)(AdaptersName);
307 }
308 }
309
310
311 int
312 pcap_lookupnet(device, netp, maskp, errbuf)
313 register const char *device;
314 register bpf_u_int32 *netp, *maskp;
315 register char *errbuf;
316 {
317 /*
318 * We need only the first IPv4 address, so we must scan the array returned by PacketGetNetInfo()
319 * in order to skip non IPv4 (i.e. IPv6 addresses)
320 */
321 npf_if_addr if_addrs[MAX_NETWORK_ADDRESSES];
322 LONG if_addr_size = 1;
323 struct sockaddr_in *t_addr;
324 unsigned int i;
325
326 if (!PacketGetNetInfoEx((void *)device, if_addrs, &if_addr_size)) {
327 *netp = *maskp = 0;
328 return (0);
329 }
330
331 for(i=0; i<MAX_NETWORK_ADDRESSES; i++)
332 {
333 if(if_addrs[i].IPAddress.ss_family == AF_INET)
334 {
335 t_addr = (struct sockaddr_in *) &(if_addrs[i].IPAddress);
336 *netp = t_addr->sin_addr.S_un.S_addr;
337 t_addr = (struct sockaddr_in *) &(if_addrs[i].SubnetMask);
338 *maskp = t_addr->sin_addr.S_un.S_addr;
339
340 *netp &= *maskp;
341 return (0);
342 }
343
344 }
345
346 *netp = *maskp = 0;
347 return (0);
348 }
349
350 #endif /* !_WIN32 && !MSDOS */