/src/libpcap/nametoaddr.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998 |
3 | | * The Regents of the University of California. All rights reserved. |
4 | | * |
5 | | * Redistribution and use in source and binary forms, with or without |
6 | | * modification, are permitted provided that: (1) source code distributions |
7 | | * retain the above copyright notice and this paragraph in its entirety, (2) |
8 | | * distributions including binary code include the above copyright notice and |
9 | | * this paragraph in its entirety in the documentation or other materials |
10 | | * provided with the distribution, and (3) all advertising materials mentioning |
11 | | * features or use of this software display the following acknowledgement: |
12 | | * ``This product includes software developed by the University of California, |
13 | | * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of |
14 | | * the University nor the names of its contributors may be used to endorse |
15 | | * or promote products derived from this software without specific prior |
16 | | * written permission. |
17 | | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
18 | | * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF |
19 | | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
20 | | * |
21 | | * Name to id translation routines used by the scanner. |
22 | | * These functions are not time critical. |
23 | | */ |
24 | | |
25 | | #ifdef HAVE_CONFIG_H |
26 | | #include <config.h> |
27 | | #endif |
28 | | |
29 | | #ifdef DECNETLIB |
30 | | #include <sys/types.h> |
31 | | #include <netdnet/dnetdb.h> |
32 | | #endif |
33 | | |
34 | | #ifdef _WIN32 |
35 | | #include <winsock2.h> |
36 | | #include <ws2tcpip.h> |
37 | | |
38 | | #ifdef INET6 |
39 | | /* |
40 | | * To quote the MSDN page for getaddrinfo() at |
41 | | * |
42 | | * https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520(v=vs.85).aspx |
43 | | * |
44 | | * "Support for getaddrinfo on Windows 2000 and older versions |
45 | | * The getaddrinfo function was added to the Ws2_32.dll on Windows XP and |
46 | | * later. To execute an application that uses this function on earlier |
47 | | * versions of Windows, then you need to include the Ws2tcpip.h and |
48 | | * Wspiapi.h files. When the Wspiapi.h include file is added, the |
49 | | * getaddrinfo function is defined to the WspiapiGetAddrInfo inline |
50 | | * function in the Wspiapi.h file. At runtime, the WspiapiGetAddrInfo |
51 | | * function is implemented in such a way that if the Ws2_32.dll or the |
52 | | * Wship6.dll (the file containing getaddrinfo in the IPv6 Technology |
53 | | * Preview for Windows 2000) does not include getaddrinfo, then a |
54 | | * version of getaddrinfo is implemented inline based on code in the |
55 | | * Wspiapi.h header file. This inline code will be used on older Windows |
56 | | * platforms that do not natively support the getaddrinfo function." |
57 | | * |
58 | | * We use getaddrinfo(), so we include Wspiapi.h here. |
59 | | */ |
60 | | #include <wspiapi.h> |
61 | | #endif /* INET6 */ |
62 | | #else /* _WIN32 */ |
63 | | #include <sys/param.h> |
64 | | #include <sys/types.h> |
65 | | #include <sys/socket.h> |
66 | | #include <sys/time.h> |
67 | | |
68 | | #include <netinet/in.h> |
69 | | |
70 | | #ifdef HAVE_ETHER_HOSTTON |
71 | | #if defined(NET_ETHERNET_H_DECLARES_ETHER_HOSTTON) |
72 | | /* |
73 | | * OK, just include <net/ethernet.h>. |
74 | | */ |
75 | | #include <net/ethernet.h> |
76 | | #elif defined(NETINET_ETHER_H_DECLARES_ETHER_HOSTTON) |
77 | | /* |
78 | | * OK, just include <netinet/ether.h> |
79 | | */ |
80 | | #include <netinet/ether.h> |
81 | | #elif defined(SYS_ETHERNET_H_DECLARES_ETHER_HOSTTON) |
82 | | /* |
83 | | * OK, just include <sys/ethernet.h> |
84 | | */ |
85 | | #include <sys/ethernet.h> |
86 | | #elif defined(ARPA_INET_H_DECLARES_ETHER_HOSTTON) |
87 | | /* |
88 | | * OK, just include <arpa/inet.h> |
89 | | */ |
90 | | #include <arpa/inet.h> |
91 | | #elif defined(NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON) |
92 | | /* |
93 | | * OK, include <netinet/if_ether.h>, after all the other stuff we |
94 | | * need to include or define for its benefit. |
95 | | */ |
96 | | #define NEED_NETINET_IF_ETHER_H |
97 | | #else |
98 | | /* |
99 | | * We'll have to declare it ourselves. |
100 | | * If <netinet/if_ether.h> defines struct ether_addr, include |
101 | | * it. Otherwise, define it ourselves. |
102 | | */ |
103 | | #ifdef HAVE_STRUCT_ETHER_ADDR |
104 | | #define NEED_NETINET_IF_ETHER_H |
105 | | #else /* HAVE_STRUCT_ETHER_ADDR */ |
106 | | struct ether_addr { |
107 | | unsigned char ether_addr_octet[6]; |
108 | | }; |
109 | | #endif /* HAVE_STRUCT_ETHER_ADDR */ |
110 | | #endif /* what declares ether_hostton() */ |
111 | | |
112 | | #ifdef NEED_NETINET_IF_ETHER_H |
113 | | #include <net/if.h> /* Needed on some platforms */ |
114 | | #include <netinet/in.h> /* Needed on some platforms */ |
115 | | #include <netinet/if_ether.h> |
116 | | #endif /* NEED_NETINET_IF_ETHER_H */ |
117 | | |
118 | | #ifndef HAVE_DECL_ETHER_HOSTTON |
119 | | /* |
120 | | * No header declares it, so declare it ourselves. |
121 | | */ |
122 | | extern int ether_hostton(const char *, struct ether_addr *); |
123 | | #endif /* !defined(HAVE_DECL_ETHER_HOSTTON) */ |
124 | | #endif /* HAVE_ETHER_HOSTTON */ |
125 | | |
126 | | #include <arpa/inet.h> |
127 | | #include <netdb.h> |
128 | | #endif /* _WIN32 */ |
129 | | |
130 | | #include <errno.h> |
131 | | #include <stdlib.h> |
132 | | #include <string.h> |
133 | | #include <stdio.h> |
134 | | |
135 | | #include "pcap-int.h" |
136 | | |
137 | | #include "diag-control.h" |
138 | | |
139 | | #include "gencode.h" |
140 | | #include <pcap/namedb.h> |
141 | | #include "nametoaddr.h" |
142 | | |
143 | | #ifdef HAVE_OS_PROTO_H |
144 | | #include "os-proto.h" |
145 | | #endif |
146 | | |
147 | | #ifndef NTOHL |
148 | 0 | #define NTOHL(x) (x) = ntohl(x) |
149 | | #define NTOHS(x) (x) = ntohs(x) |
150 | | #endif |
151 | | |
152 | | /* |
153 | | * Convert host name to internet address. |
154 | | * Return 0 upon failure. |
155 | | * XXX - not thread-safe; don't use it inside libpcap. |
156 | | */ |
157 | | bpf_u_int32 ** |
158 | | pcap_nametoaddr(const char *name) |
159 | 0 | { |
160 | | #ifndef h_addr |
161 | | static bpf_u_int32 *hlist[2]; |
162 | | #endif |
163 | 0 | bpf_u_int32 **p; |
164 | 0 | struct hostent *hp; |
165 | | |
166 | | /* |
167 | | * gethostbyname() is deprecated on Windows, perhaps because |
168 | | * it's not thread-safe, or because it doesn't support IPv6, |
169 | | * or both. |
170 | | * |
171 | | * We deprecate pcap_nametoaddr() on all platforms because |
172 | | * it's not thread-safe; we supply it for backwards compatibility, |
173 | | * so suppress the deprecation warning. We could, I guess, |
174 | | * use getaddrinfo() and construct the array ourselves, but |
175 | | * that's probably not worth the effort, as that wouldn't make |
176 | | * this thread-safe - we can't change the API to require that |
177 | | * our caller free the address array, so we still have to reuse |
178 | | * a local array. |
179 | | */ |
180 | 0 | DIAG_OFF_DEPRECATION |
181 | 0 | if ((hp = gethostbyname(name)) != NULL) { |
182 | 0 | DIAG_ON_DEPRECATION |
183 | | #ifndef h_addr |
184 | | hlist[0] = (bpf_u_int32 *)hp->h_addr; |
185 | | NTOHL(hp->h_addr); |
186 | | return hlist; |
187 | | #else |
188 | 0 | for (p = (bpf_u_int32 **)hp->h_addr_list; *p; ++p) |
189 | 0 | NTOHL(**p); |
190 | 0 | return (bpf_u_int32 **)hp->h_addr_list; |
191 | 0 | #endif |
192 | 0 | } |
193 | 0 | else |
194 | 0 | return 0; |
195 | 0 | } |
196 | | |
197 | | struct addrinfo * |
198 | | pcap_nametoaddrinfo(const char *name) |
199 | 35 | { |
200 | 35 | struct addrinfo hints, *res; |
201 | 35 | int error; |
202 | | |
203 | 35 | memset(&hints, 0, sizeof(hints)); |
204 | 35 | hints.ai_family = PF_UNSPEC; |
205 | 35 | hints.ai_socktype = SOCK_STREAM; /*not really*/ |
206 | 35 | hints.ai_protocol = IPPROTO_TCP; /*not really*/ |
207 | 35 | error = getaddrinfo(name, NULL, &hints, &res); |
208 | 35 | if (error) |
209 | 0 | return NULL; |
210 | 35 | else |
211 | 35 | return res; |
212 | 35 | } |
213 | | |
214 | | /* |
215 | | * Convert net name to internet address. |
216 | | * Return 0 upon failure. |
217 | | * XXX - not guaranteed to be thread-safe! See below for platforms |
218 | | * on which it is thread-safe and on which it isn't. |
219 | | */ |
220 | | #if defined(_WIN32) || defined(__CYGWIN__) |
221 | | bpf_u_int32 |
222 | | pcap_nametonetaddr(const char *name _U_) |
223 | | { |
224 | | /* |
225 | | * There's no "getnetbyname()" on Windows. |
226 | | * |
227 | | * XXX - I guess we could use the BSD code to read |
228 | | * C:\Windows\System32\drivers\etc/networks, assuming |
229 | | * that's its home on all the versions of Windows |
230 | | * we use, but that file probably just has the loopback |
231 | | * network on 127/24 on 99 44/100% of Windows machines. |
232 | | * |
233 | | * (Heck, these days it probably just has that on 99 44/100% |
234 | | * of *UN*X* machines.) |
235 | | */ |
236 | | return 0; |
237 | | } |
238 | | #else /* _WIN32 */ |
239 | | bpf_u_int32 |
240 | | pcap_nametonetaddr(const char *name) |
241 | 0 | { |
242 | | /* |
243 | | * UN*X. |
244 | | */ |
245 | 0 | struct netent *np; |
246 | 0 | #if defined(HAVE_LINUX_GETNETBYNAME_R) |
247 | | /* |
248 | | * We have Linux's reentrant getnetbyname_r(). |
249 | | */ |
250 | 0 | struct netent result_buf; |
251 | 0 | char buf[1024]; /* arbitrary size */ |
252 | 0 | int h_errnoval; |
253 | 0 | int err; |
254 | | |
255 | | /* |
256 | | * Apparently, the man page at |
257 | | * |
258 | | * http://man7.org/linux/man-pages/man3/getnetbyname_r.3.html |
259 | | * |
260 | | * lies when it says |
261 | | * |
262 | | * If the function call successfully obtains a network record, |
263 | | * then *result is set pointing to result_buf; otherwise, *result |
264 | | * is set to NULL. |
265 | | * |
266 | | * and, in fact, at least in some versions of GNU libc, it does |
267 | | * *not* always get set if getnetbyname_r() succeeds. |
268 | | */ |
269 | 0 | np = NULL; |
270 | 0 | err = getnetbyname_r(name, &result_buf, buf, sizeof buf, &np, |
271 | 0 | &h_errnoval); |
272 | 0 | if (err != 0) { |
273 | | /* |
274 | | * XXX - dynamically allocate the buffer, and make it |
275 | | * bigger if we get ERANGE back? |
276 | | */ |
277 | 0 | return 0; |
278 | 0 | } |
279 | | #elif defined(HAVE_SOLARIS_IRIX_GETNETBYNAME_R) |
280 | | /* |
281 | | * We have Solaris's and IRIX's reentrant getnetbyname_r(). |
282 | | */ |
283 | | struct netent result_buf; |
284 | | char buf[1024]; /* arbitrary size */ |
285 | | |
286 | | np = getnetbyname_r(name, &result_buf, buf, (int)sizeof buf); |
287 | | #elif defined(HAVE_AIX_GETNETBYNAME_R) |
288 | | /* |
289 | | * We have AIX's reentrant getnetbyname_r(). |
290 | | */ |
291 | | struct netent result_buf; |
292 | | struct netent_data net_data; |
293 | | |
294 | | if (getnetbyname_r(name, &result_buf, &net_data) == -1) |
295 | | np = NULL; |
296 | | else |
297 | | np = &result_buf; |
298 | | #else |
299 | | /* |
300 | | * We don't have any getnetbyname_r(); either we have a |
301 | | * getnetbyname() that uses thread-specific data, in which |
302 | | * case we're thread-safe (sufficiently recent FreeBSD, |
303 | | * sufficiently recent Darwin-based OS, sufficiently recent |
304 | | * HP-UX, sufficiently recent Tru64 UNIX), or we have the |
305 | | * traditional getnetbyname() (everything else, including |
306 | | * current NetBSD and OpenBSD), in which case we're not |
307 | | * thread-safe. |
308 | | */ |
309 | | np = getnetbyname(name); |
310 | | #endif |
311 | 0 | if (np != NULL) |
312 | 0 | return np->n_net; |
313 | 0 | else |
314 | 0 | return 0; |
315 | 0 | } |
316 | | #endif /* _WIN32 */ |
317 | | |
318 | | /* |
319 | | * Convert a port name to its port and protocol numbers. |
320 | | * We assume only TCP or UDP. |
321 | | * Return 0 upon failure. |
322 | | */ |
323 | | int |
324 | | pcap_nametoport(const char *name, int *port, int *proto) |
325 | 0 | { |
326 | 0 | struct addrinfo hints, *res, *ai; |
327 | 0 | int error; |
328 | 0 | struct sockaddr_in *in4; |
329 | 0 | #ifdef INET6 |
330 | 0 | struct sockaddr_in6 *in6; |
331 | 0 | #endif |
332 | 0 | int tcp_port = -1; |
333 | 0 | int udp_port = -1; |
334 | | |
335 | | /* |
336 | | * We check for both TCP and UDP in case there are |
337 | | * ambiguous entries. |
338 | | */ |
339 | 0 | memset(&hints, 0, sizeof(hints)); |
340 | 0 | hints.ai_family = PF_UNSPEC; |
341 | 0 | hints.ai_socktype = SOCK_STREAM; |
342 | 0 | hints.ai_protocol = IPPROTO_TCP; |
343 | 0 | error = getaddrinfo(NULL, name, &hints, &res); |
344 | 0 | if (error != 0) { |
345 | 0 | if (error != EAI_NONAME && |
346 | 0 | error != EAI_SERVICE) { |
347 | | /* |
348 | | * This is a real error, not just "there's |
349 | | * no such service name". |
350 | | * XXX - this doesn't return an error string. |
351 | | */ |
352 | 0 | return 0; |
353 | 0 | } |
354 | 0 | } else { |
355 | | /* |
356 | | * OK, we found it. Did it find anything? |
357 | | */ |
358 | 0 | for (ai = res; ai != NULL; ai = ai->ai_next) { |
359 | | /* |
360 | | * Does it have an address? |
361 | | */ |
362 | 0 | if (ai->ai_addr != NULL) { |
363 | | /* |
364 | | * Yes. Get a port number; we're done. |
365 | | */ |
366 | 0 | if (ai->ai_addr->sa_family == AF_INET) { |
367 | 0 | in4 = (struct sockaddr_in *)ai->ai_addr; |
368 | 0 | tcp_port = ntohs(in4->sin_port); |
369 | 0 | break; |
370 | 0 | } |
371 | 0 | #ifdef INET6 |
372 | 0 | if (ai->ai_addr->sa_family == AF_INET6) { |
373 | 0 | in6 = (struct sockaddr_in6 *)ai->ai_addr; |
374 | 0 | tcp_port = ntohs(in6->sin6_port); |
375 | 0 | break; |
376 | 0 | } |
377 | 0 | #endif |
378 | 0 | } |
379 | 0 | } |
380 | 0 | freeaddrinfo(res); |
381 | 0 | } |
382 | | |
383 | 0 | memset(&hints, 0, sizeof(hints)); |
384 | 0 | hints.ai_family = PF_UNSPEC; |
385 | 0 | hints.ai_socktype = SOCK_DGRAM; |
386 | 0 | hints.ai_protocol = IPPROTO_UDP; |
387 | 0 | error = getaddrinfo(NULL, name, &hints, &res); |
388 | 0 | if (error != 0) { |
389 | 0 | if (error != EAI_NONAME && |
390 | 0 | error != EAI_SERVICE) { |
391 | | /* |
392 | | * This is a real error, not just "there's |
393 | | * no such service name". |
394 | | * XXX - this doesn't return an error string. |
395 | | */ |
396 | 0 | return 0; |
397 | 0 | } |
398 | 0 | } else { |
399 | | /* |
400 | | * OK, we found it. Did it find anything? |
401 | | */ |
402 | 0 | for (ai = res; ai != NULL; ai = ai->ai_next) { |
403 | | /* |
404 | | * Does it have an address? |
405 | | */ |
406 | 0 | if (ai->ai_addr != NULL) { |
407 | | /* |
408 | | * Yes. Get a port number; we're done. |
409 | | */ |
410 | 0 | if (ai->ai_addr->sa_family == AF_INET) { |
411 | 0 | in4 = (struct sockaddr_in *)ai->ai_addr; |
412 | 0 | udp_port = ntohs(in4->sin_port); |
413 | 0 | break; |
414 | 0 | } |
415 | 0 | #ifdef INET6 |
416 | 0 | if (ai->ai_addr->sa_family == AF_INET6) { |
417 | 0 | in6 = (struct sockaddr_in6 *)ai->ai_addr; |
418 | 0 | udp_port = ntohs(in6->sin6_port); |
419 | 0 | break; |
420 | 0 | } |
421 | 0 | #endif |
422 | 0 | } |
423 | 0 | } |
424 | 0 | freeaddrinfo(res); |
425 | 0 | } |
426 | | |
427 | | /* |
428 | | * We need to check /etc/services for ambiguous entries. |
429 | | * If we find an ambiguous entry, and it has the |
430 | | * same port number, change the proto to PROTO_UNDEF |
431 | | * so both TCP and UDP will be checked. |
432 | | */ |
433 | 0 | if (tcp_port >= 0) { |
434 | 0 | *port = tcp_port; |
435 | 0 | *proto = IPPROTO_TCP; |
436 | 0 | if (udp_port >= 0) { |
437 | 0 | if (udp_port == tcp_port) |
438 | 0 | *proto = PROTO_UNDEF; |
439 | | #ifdef notdef |
440 | | else |
441 | | /* Can't handle ambiguous names that refer |
442 | | to different port numbers. */ |
443 | | warning("ambiguous port %s in /etc/services", |
444 | | name); |
445 | | #endif |
446 | 0 | } |
447 | 0 | return 1; |
448 | 0 | } |
449 | 0 | if (udp_port >= 0) { |
450 | 0 | *port = udp_port; |
451 | 0 | *proto = IPPROTO_UDP; |
452 | 0 | return 1; |
453 | 0 | } |
454 | | #if defined(ultrix) || defined(__osf__) |
455 | | /* Special hack in case NFS isn't in /etc/services */ |
456 | | if (strcmp(name, "nfs") == 0) { |
457 | | *port = 2049; |
458 | | *proto = PROTO_UNDEF; |
459 | | return 1; |
460 | | } |
461 | | #endif |
462 | 0 | return 0; |
463 | 0 | } |
464 | | |
465 | | /* |
466 | | * Convert a string in the form PPP-PPP, where correspond to ports, to |
467 | | * a starting and ending port in a port range. |
468 | | * Return 0 on failure. |
469 | | */ |
470 | | int |
471 | | pcap_nametoportrange(const char *name, int *port1, int *port2, int *proto) |
472 | 0 | { |
473 | 0 | u_int p1, p2; |
474 | 0 | char *off, *cpy; |
475 | 0 | int save_proto; |
476 | |
|
477 | 0 | if (sscanf(name, "%d-%d", &p1, &p2) != 2) { |
478 | 0 | if ((cpy = strdup(name)) == NULL) |
479 | 0 | return 0; |
480 | | |
481 | 0 | if ((off = strchr(cpy, '-')) == NULL) { |
482 | 0 | free(cpy); |
483 | 0 | return 0; |
484 | 0 | } |
485 | | |
486 | 0 | *off = '\0'; |
487 | |
|
488 | 0 | if (pcap_nametoport(cpy, port1, proto) == 0) { |
489 | 0 | free(cpy); |
490 | 0 | return 0; |
491 | 0 | } |
492 | 0 | save_proto = *proto; |
493 | |
|
494 | 0 | if (pcap_nametoport(off + 1, port2, proto) == 0) { |
495 | 0 | free(cpy); |
496 | 0 | return 0; |
497 | 0 | } |
498 | 0 | free(cpy); |
499 | |
|
500 | 0 | if (*proto != save_proto) |
501 | 0 | *proto = PROTO_UNDEF; |
502 | 0 | } else { |
503 | 0 | *port1 = p1; |
504 | 0 | *port2 = p2; |
505 | 0 | *proto = PROTO_UNDEF; |
506 | 0 | } |
507 | | |
508 | 0 | return 1; |
509 | 0 | } |
510 | | |
511 | | /* |
512 | | * XXX - not guaranteed to be thread-safe! See below for platforms |
513 | | * on which it is thread-safe and on which it isn't. |
514 | | */ |
515 | | int |
516 | | pcap_nametoproto(const char *str) |
517 | 0 | { |
518 | 0 | struct protoent *p; |
519 | 0 | #if defined(HAVE_LINUX_GETNETBYNAME_R) |
520 | | /* |
521 | | * We have Linux's reentrant getprotobyname_r(). |
522 | | */ |
523 | 0 | struct protoent result_buf; |
524 | 0 | char buf[1024]; /* arbitrary size */ |
525 | 0 | int err; |
526 | |
|
527 | 0 | err = getprotobyname_r(str, &result_buf, buf, sizeof buf, &p); |
528 | 0 | if (err != 0) { |
529 | | /* |
530 | | * XXX - dynamically allocate the buffer, and make it |
531 | | * bigger if we get ERANGE back? |
532 | | */ |
533 | 0 | return 0; |
534 | 0 | } |
535 | | #elif defined(HAVE_SOLARIS_IRIX_GETNETBYNAME_R) |
536 | | /* |
537 | | * We have Solaris's and IRIX's reentrant getprotobyname_r(). |
538 | | */ |
539 | | struct protoent result_buf; |
540 | | char buf[1024]; /* arbitrary size */ |
541 | | |
542 | | p = getprotobyname_r(str, &result_buf, buf, (int)sizeof buf); |
543 | | #elif defined(HAVE_AIX_GETNETBYNAME_R) |
544 | | /* |
545 | | * We have AIX's reentrant getprotobyname_r(). |
546 | | */ |
547 | | struct protoent result_buf; |
548 | | struct protoent_data proto_data; |
549 | | |
550 | | if (getprotobyname_r(str, &result_buf, &proto_data) == -1) |
551 | | p = NULL; |
552 | | else |
553 | | p = &result_buf; |
554 | | #else |
555 | | /* |
556 | | * We don't have any getprotobyname_r(); either we have a |
557 | | * getprotobyname() that uses thread-specific data, in which |
558 | | * case we're thread-safe (sufficiently recent FreeBSD, |
559 | | * sufficiently recent Darwin-based OS, sufficiently recent |
560 | | * HP-UX, sufficiently recent Tru64 UNIX, Windows), or we have |
561 | | * the traditional getprotobyname() (everything else, including |
562 | | * current NetBSD and OpenBSD), in which case we're not |
563 | | * thread-safe. |
564 | | */ |
565 | | p = getprotobyname(str); |
566 | | #endif |
567 | 0 | if (p != 0) |
568 | 0 | return p->p_proto; |
569 | 0 | else |
570 | 0 | return PROTO_UNDEF; |
571 | 0 | } |
572 | | |
573 | | #include "ethertype.h" |
574 | | |
575 | | struct eproto { |
576 | | const char *s; |
577 | | u_short p; |
578 | | }; |
579 | | |
580 | | /* |
581 | | * Static data base of ether protocol types. |
582 | | * tcpdump used to import this, and it's declared as an export on |
583 | | * Debian, at least, so make it a public symbol, even though we |
584 | | * don't officially export it by declaring it in a header file. |
585 | | * (Programs *should* do this themselves, as tcpdump now does.) |
586 | | * |
587 | | * We declare it here, right before defining it, to squelch any |
588 | | * warnings we might get from compilers about the lack of a |
589 | | * declaration. |
590 | | */ |
591 | | PCAP_API struct eproto eproto_db[]; |
592 | | PCAP_API_DEF struct eproto eproto_db[] = { |
593 | | { "aarp", ETHERTYPE_AARP }, |
594 | | { "arp", ETHERTYPE_ARP }, |
595 | | { "atalk", ETHERTYPE_ATALK }, |
596 | | { "decnet", ETHERTYPE_DN }, |
597 | | { "ip", ETHERTYPE_IP }, |
598 | | #ifdef INET6 |
599 | | { "ip6", ETHERTYPE_IPV6 }, |
600 | | #endif |
601 | | { "lat", ETHERTYPE_LAT }, |
602 | | { "loopback", ETHERTYPE_LOOPBACK }, |
603 | | { "mopdl", ETHERTYPE_MOPDL }, |
604 | | { "moprc", ETHERTYPE_MOPRC }, |
605 | | { "rarp", ETHERTYPE_REVARP }, |
606 | | { "sca", ETHERTYPE_SCA }, |
607 | | { (char *)0, 0 } |
608 | | }; |
609 | | |
610 | | int |
611 | | pcap_nametoeproto(const char *s) |
612 | 0 | { |
613 | 0 | struct eproto *p = eproto_db; |
614 | |
|
615 | 0 | while (p->s != 0) { |
616 | 0 | if (strcmp(p->s, s) == 0) |
617 | 0 | return p->p; |
618 | 0 | p += 1; |
619 | 0 | } |
620 | 0 | return PROTO_UNDEF; |
621 | 0 | } |
622 | | |
623 | | #include "llc.h" |
624 | | |
625 | | /* Static data base of LLC values. */ |
626 | | static struct eproto llc_db[] = { |
627 | | { "iso", LLCSAP_ISONS }, |
628 | | { "stp", LLCSAP_8021D }, |
629 | | { "ipx", LLCSAP_IPX }, |
630 | | { "netbeui", LLCSAP_NETBEUI }, |
631 | | { (char *)0, 0 } |
632 | | }; |
633 | | |
634 | | int |
635 | | pcap_nametollc(const char *s) |
636 | 0 | { |
637 | 0 | struct eproto *p = llc_db; |
638 | |
|
639 | 0 | while (p->s != 0) { |
640 | 0 | if (strcmp(p->s, s) == 0) |
641 | 0 | return p->p; |
642 | 0 | p += 1; |
643 | 0 | } |
644 | 0 | return PROTO_UNDEF; |
645 | 0 | } |
646 | | |
647 | | /* Hex digit to 8-bit unsigned integer. */ |
648 | | static inline u_char |
649 | | xdtoi(u_char c) |
650 | 0 | { |
651 | 0 | if (c >= '0' && c <= '9') |
652 | 0 | return (u_char)(c - '0'); |
653 | 0 | else if (c >= 'a' && c <= 'f') |
654 | 0 | return (u_char)(c - 'a' + 10); |
655 | 0 | else |
656 | 0 | return (u_char)(c - 'A' + 10); |
657 | 0 | } |
658 | | |
659 | | int |
660 | | __pcap_atoin(const char *s, bpf_u_int32 *addr) |
661 | 230 | { |
662 | 230 | u_int n; |
663 | 230 | int len; |
664 | | |
665 | 230 | *addr = 0; |
666 | 230 | len = 0; |
667 | 479 | for (;;) { |
668 | 479 | n = 0; |
669 | 2.00k | while (*s && *s != '.') { |
670 | 1.59k | if (n > 25) { |
671 | | /* The result will be > 255 */ |
672 | 68 | return -1; |
673 | 68 | } |
674 | 1.52k | n = n * 10 + *s++ - '0'; |
675 | 1.52k | } |
676 | 411 | if (n > 255) |
677 | 6 | return -1; |
678 | 405 | *addr <<= 8; |
679 | 405 | *addr |= n & 0xff; |
680 | 405 | len += 8; |
681 | 405 | if (*s == '\0') |
682 | 156 | return len; |
683 | 249 | ++s; |
684 | 249 | } |
685 | | /* NOTREACHED */ |
686 | 230 | } |
687 | | |
688 | | int |
689 | | __pcap_atodn(const char *s, bpf_u_int32 *addr) |
690 | 0 | { |
691 | 0 | #define AREASHIFT 10 |
692 | 0 | #define AREAMASK 0176000 |
693 | 0 | #define NODEMASK 01777 |
694 | |
|
695 | 0 | u_int node, area; |
696 | |
|
697 | 0 | if (sscanf(s, "%d.%d", &area, &node) != 2) |
698 | 0 | return(0); |
699 | | |
700 | 0 | *addr = (area << AREASHIFT) & AREAMASK; |
701 | 0 | *addr |= (node & NODEMASK); |
702 | |
|
703 | 0 | return(32); |
704 | 0 | } |
705 | | |
706 | | /* |
707 | | * Convert 's', which can have the one of the forms: |
708 | | * |
709 | | * "xx:xx:xx:xx:xx:xx" |
710 | | * "xx.xx.xx.xx.xx.xx" |
711 | | * "xx-xx-xx-xx-xx-xx" |
712 | | * "xxxx.xxxx.xxxx" |
713 | | * "xxxxxxxxxxxx" |
714 | | * |
715 | | * (or various mixes of ':', '.', and '-') into a new |
716 | | * ethernet address. Assumes 's' is well formed. |
717 | | */ |
718 | | u_char * |
719 | | pcap_ether_aton(const char *s) |
720 | 0 | { |
721 | 0 | register u_char *ep, *e; |
722 | 0 | register u_char d; |
723 | |
|
724 | 0 | e = ep = (u_char *)malloc(6); |
725 | 0 | if (e == NULL) |
726 | 0 | return (NULL); |
727 | | |
728 | 0 | while (*s) { |
729 | 0 | if (*s == ':' || *s == '.' || *s == '-') |
730 | 0 | s += 1; |
731 | 0 | d = xdtoi(*s++); |
732 | 0 | if (PCAP_ISXDIGIT(*s)) { |
733 | 0 | d <<= 4; |
734 | 0 | d |= xdtoi(*s++); |
735 | 0 | } |
736 | 0 | *ep++ = d; |
737 | 0 | } |
738 | |
|
739 | 0 | return (e); |
740 | 0 | } |
741 | | |
742 | | #ifndef HAVE_ETHER_HOSTTON |
743 | | /* |
744 | | * Roll our own. |
745 | | * XXX - not thread-safe, because pcap_next_etherent() isn't thread- |
746 | | * safe! Needs a mutex or a thread-safe pcap_next_etherent(). |
747 | | */ |
748 | | u_char * |
749 | | pcap_ether_hostton(const char *name) |
750 | | { |
751 | | register struct pcap_etherent *ep; |
752 | | register u_char *ap; |
753 | | static FILE *fp = NULL; |
754 | | static int init = 0; |
755 | | |
756 | | if (!init) { |
757 | | fp = fopen(PCAP_ETHERS_FILE, "r"); |
758 | | ++init; |
759 | | if (fp == NULL) |
760 | | return (NULL); |
761 | | } else if (fp == NULL) |
762 | | return (NULL); |
763 | | else |
764 | | rewind(fp); |
765 | | |
766 | | while ((ep = pcap_next_etherent(fp)) != NULL) { |
767 | | if (strcmp(ep->name, name) == 0) { |
768 | | ap = (u_char *)malloc(6); |
769 | | if (ap != NULL) { |
770 | | memcpy(ap, ep->addr, 6); |
771 | | return (ap); |
772 | | } |
773 | | break; |
774 | | } |
775 | | } |
776 | | return (NULL); |
777 | | } |
778 | | #else |
779 | | /* |
780 | | * Use the OS-supplied routine. |
781 | | * This *should* be thread-safe; the API doesn't have a static buffer. |
782 | | */ |
783 | | u_char * |
784 | | pcap_ether_hostton(const char *name) |
785 | 0 | { |
786 | 0 | register u_char *ap; |
787 | 0 | u_char a[6]; |
788 | 0 | char namebuf[1024]; |
789 | | |
790 | | /* |
791 | | * In AIX 7.1 and 7.2: int ether_hostton(char *, struct ether_addr *); |
792 | | */ |
793 | 0 | pcap_strlcpy(namebuf, name, sizeof(namebuf)); |
794 | 0 | ap = NULL; |
795 | 0 | if (ether_hostton(namebuf, (struct ether_addr *)a) == 0) { |
796 | 0 | ap = (u_char *)malloc(6); |
797 | 0 | if (ap != NULL) |
798 | 0 | memcpy((char *)ap, (char *)a, 6); |
799 | 0 | } |
800 | 0 | return (ap); |
801 | 0 | } |
802 | | #endif |
803 | | |
804 | | /* |
805 | | * XXX - not guaranteed to be thread-safe! |
806 | | */ |
807 | | int |
808 | | #ifdef DECNETLIB |
809 | | __pcap_nametodnaddr(const char *name, u_short *res) |
810 | | { |
811 | | struct nodeent *getnodebyname(); |
812 | | struct nodeent *nep; |
813 | | |
814 | | nep = getnodebyname(name); |
815 | | if (nep == ((struct nodeent *)0)) |
816 | | return(0); |
817 | | |
818 | | memcpy((char *)res, (char *)nep->n_addr, sizeof(unsigned short)); |
819 | | return(1); |
820 | | #else |
821 | | __pcap_nametodnaddr(const char *name _U_, u_short *res _U_) |
822 | 0 | { |
823 | 0 | return(0); |
824 | 0 | #endif |
825 | 0 | } |