/src/libpcap/nametoaddr.c
Line | Count | Source |
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 | | #include <config.h> |
26 | | |
27 | | #ifdef _WIN32 |
28 | | #include <winsock2.h> |
29 | | #include <ws2tcpip.h> |
30 | | #else /* _WIN32 */ |
31 | | #include <sys/param.h> |
32 | | #include <sys/types.h> |
33 | | #include <sys/socket.h> |
34 | | #include <sys/time.h> |
35 | | |
36 | | #include <netinet/in.h> |
37 | | |
38 | | #if defined(__linux__) && defined(HAVE_ETHER_HOSTTON) |
39 | | #include <features.h> |
40 | | #if ! defined(__GLIBC__) && ! defined(__UCLIBC__) |
41 | | /* |
42 | | * In musl libc (which does not identify itself) ether_hostton() is |
43 | | * present and does not work. |
44 | | * |
45 | | * The headers below will include config.h at least one more time, so |
46 | | * instead of undefining HAVE_ETHER_HOSTTON define another macro that is |
47 | | * local to this file, and make it a part of the test condition. |
48 | | */ |
49 | | #define BROKEN_ETHER_HOSTTON |
50 | | #endif |
51 | | #endif // defined(__linux__) && defined(HAVE_ETHER_HOSTTON) |
52 | | |
53 | | #if defined(HAVE_ETHER_HOSTTON) && ! defined(BROKEN_ETHER_HOSTTON) |
54 | | #if defined(NET_ETHERNET_H_DECLARES_ETHER_HOSTTON) |
55 | | /* |
56 | | * OK, just include <net/ethernet.h>. |
57 | | */ |
58 | | #include <net/ethernet.h> |
59 | | #elif defined(NETINET_ETHER_H_DECLARES_ETHER_HOSTTON) |
60 | | /* |
61 | | * OK, just include <netinet/ether.h> |
62 | | */ |
63 | | #include <netinet/ether.h> |
64 | | #elif defined(SYS_ETHERNET_H_DECLARES_ETHER_HOSTTON) |
65 | | /* |
66 | | * OK, just include <sys/ethernet.h> |
67 | | */ |
68 | | #include <sys/ethernet.h> |
69 | | #elif defined(ARPA_INET_H_DECLARES_ETHER_HOSTTON) |
70 | | /* |
71 | | * OK, just include <arpa/inet.h> |
72 | | */ |
73 | | #include <arpa/inet.h> |
74 | | #elif defined(NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON) |
75 | | /* |
76 | | * OK, include <netinet/if_ether.h>, after all the other stuff we |
77 | | * need to include or define for its benefit. |
78 | | */ |
79 | | #define NEED_NETINET_IF_ETHER_H |
80 | | #else |
81 | | /* |
82 | | * We'll have to declare it ourselves. |
83 | | * If <netinet/if_ether.h> defines struct ether_addr, include |
84 | | * it. Otherwise, define it ourselves. |
85 | | */ |
86 | | #ifdef HAVE_STRUCT_ETHER_ADDR |
87 | | #define NEED_NETINET_IF_ETHER_H |
88 | | #else /* HAVE_STRUCT_ETHER_ADDR */ |
89 | | struct ether_addr { |
90 | | unsigned char ether_addr_octet[6]; |
91 | | }; |
92 | | #endif /* HAVE_STRUCT_ETHER_ADDR */ |
93 | | #endif /* what declares ether_hostton() */ |
94 | | |
95 | | #ifdef NEED_NETINET_IF_ETHER_H |
96 | | #include <net/if.h> /* Needed on some platforms */ |
97 | | #include <netinet/in.h> /* Needed on some platforms */ |
98 | | #include <netinet/if_ether.h> |
99 | | #endif /* NEED_NETINET_IF_ETHER_H */ |
100 | | |
101 | | #ifndef HAVE_DECL_ETHER_HOSTTON |
102 | | /* |
103 | | * No header declares it, so declare it ourselves. |
104 | | */ |
105 | | extern int ether_hostton(const char *, struct ether_addr *); |
106 | | #endif /* !defined(HAVE_DECL_ETHER_HOSTTON) */ |
107 | | #endif /* defined(HAVE_ETHER_HOSTTON) && ! defined(BROKEN_ETHER_HOSTTON) */ |
108 | | |
109 | | #include <arpa/inet.h> |
110 | | #include <netdb.h> |
111 | | #endif /* _WIN32 */ |
112 | | |
113 | | #include <errno.h> |
114 | | #include <stdlib.h> |
115 | | #include <string.h> |
116 | | #include <stdio.h> |
117 | | |
118 | | #include "pcap-int.h" |
119 | | |
120 | | #include "diag-control.h" |
121 | | |
122 | | #include "gencode.h" |
123 | | #include <pcap/namedb.h> |
124 | | #include "nametoaddr.h" |
125 | | |
126 | | #include "thread-local.h" |
127 | | |
128 | | #ifdef HAVE_OS_PROTO_H |
129 | | #include "os-proto.h" |
130 | | #endif |
131 | | |
132 | | #ifndef NTOHL |
133 | 0 | #define NTOHL(x) (x) = ntohl(x) |
134 | | #endif |
135 | | |
136 | | /* |
137 | | * Convert a host name to an Internet address. |
138 | | * Return 0 upon failure. |
139 | | * XXX - not thread-safe; don't use it inside libpcap. |
140 | | */ |
141 | | bpf_u_int32 ** |
142 | | pcap_nametoaddr(const char *name) |
143 | 0 | { |
144 | | #ifndef h_addr |
145 | | static bpf_u_int32 *hlist[2]; |
146 | | #endif |
147 | 0 | bpf_u_int32 **p; |
148 | 0 | struct hostent *hp; |
149 | | |
150 | | /* |
151 | | * gethostbyname() is deprecated on Windows, perhaps because |
152 | | * it's not thread-safe, or because it doesn't support IPv6, |
153 | | * or both. |
154 | | * |
155 | | * We deprecate pcap_nametoaddr() on all platforms because |
156 | | * it's not thread-safe; we supply it for backwards compatibility, |
157 | | * so suppress the deprecation warning. We could, I guess, |
158 | | * use getaddrinfo() and construct the array ourselves, but |
159 | | * that's probably not worth the effort, as that wouldn't make |
160 | | * this thread-safe - we can't change the API to require that |
161 | | * our caller free the address array, so we still have to reuse |
162 | | * a local array. |
163 | | */ |
164 | 0 | DIAG_OFF_DEPRECATION |
165 | 0 | if ((hp = gethostbyname(name)) != NULL) { |
166 | 0 | DIAG_ON_DEPRECATION |
167 | | #ifndef h_addr |
168 | | hlist[0] = (bpf_u_int32 *)hp->h_addr; |
169 | | NTOHL(hp->h_addr); |
170 | | return hlist; |
171 | | #else |
172 | 0 | for (p = (bpf_u_int32 **)hp->h_addr_list; *p; ++p) |
173 | 0 | NTOHL(**p); |
174 | 0 | return (bpf_u_int32 **)hp->h_addr_list; |
175 | 0 | #endif |
176 | 0 | } |
177 | 0 | else |
178 | 0 | return 0; |
179 | 0 | } |
180 | | |
181 | | struct addrinfo * |
182 | | pcap_nametoaddrinfo(const char *name) |
183 | 0 | { |
184 | 0 | struct addrinfo hints, *res; |
185 | 0 | int error; |
186 | |
|
187 | 0 | memset(&hints, 0, sizeof(hints)); |
188 | 0 | hints.ai_family = PF_UNSPEC; |
189 | 0 | hints.ai_socktype = SOCK_STREAM; /*not really*/ |
190 | 0 | hints.ai_protocol = IPPROTO_TCP; /*not really*/ |
191 | 0 | error = getaddrinfo(name, NULL, &hints, &res); |
192 | 0 | if (error) |
193 | 0 | return NULL; |
194 | 0 | else |
195 | 0 | return res; |
196 | 0 | } |
197 | | |
198 | | /* |
199 | | * Convert a net name to an Internet address. |
200 | | * Return 0 upon failure. |
201 | | * XXX - not guaranteed to be thread-safe! See below for platforms |
202 | | * on which it is thread-safe and on which it isn't. |
203 | | */ |
204 | | #if defined(_WIN32) || defined(__CYGWIN__) |
205 | | bpf_u_int32 |
206 | | pcap_nametonetaddr(const char *name _U_) |
207 | | { |
208 | | /* |
209 | | * There's no "getnetbyname()" on Windows. |
210 | | * |
211 | | * XXX - I guess we could use the BSD code to read |
212 | | * C:\Windows\System32\drivers\etc/networks, assuming |
213 | | * that's its home on all the versions of Windows |
214 | | * we use, but that file probably just has the loopback |
215 | | * network on 127/24 on 99 44/100% of Windows machines. |
216 | | * |
217 | | * (Heck, these days it probably just has that on 99 44/100% |
218 | | * of *UN*X* machines.) |
219 | | */ |
220 | | return 0; |
221 | | } |
222 | | #else /* _WIN32 */ |
223 | | bpf_u_int32 |
224 | | pcap_nametonetaddr(const char *name) |
225 | 0 | { |
226 | | /* |
227 | | * UN*X. |
228 | | */ |
229 | 0 | struct netent *np; |
230 | 0 | #if defined(HAVE_LINUX_GETNETBYNAME_R) |
231 | | /* |
232 | | * We have Linux's reentrant getnetbyname_r(). |
233 | | */ |
234 | 0 | struct netent result_buf; |
235 | 0 | char buf[1024]; /* arbitrary size */ |
236 | 0 | int h_errnoval; |
237 | 0 | int err; |
238 | | |
239 | | /* |
240 | | * Apparently, the man page at |
241 | | * |
242 | | * http://man7.org/linux/man-pages/man3/getnetbyname_r.3.html |
243 | | * |
244 | | * lies when it says |
245 | | * |
246 | | * If the function call successfully obtains a network record, |
247 | | * then *result is set pointing to result_buf; otherwise, *result |
248 | | * is set to NULL. |
249 | | * |
250 | | * and, in fact, at least in some versions of GNU libc, it does |
251 | | * *not* always get set if getnetbyname_r() succeeds. |
252 | | */ |
253 | 0 | np = NULL; |
254 | 0 | err = getnetbyname_r(name, &result_buf, buf, sizeof buf, &np, |
255 | 0 | &h_errnoval); |
256 | 0 | if (err != 0) { |
257 | | /* |
258 | | * XXX - dynamically allocate the buffer, and make it |
259 | | * bigger if we get ERANGE back? |
260 | | */ |
261 | 0 | return 0; |
262 | 0 | } |
263 | | #elif defined(HAVE_SOLARIS_GETNETBYNAME_R) |
264 | | /* |
265 | | * We have Solaris's reentrant getnetbyname_r(). |
266 | | */ |
267 | | struct netent result_buf; |
268 | | char buf[1024]; /* arbitrary size */ |
269 | | |
270 | | np = getnetbyname_r(name, &result_buf, buf, (int)sizeof buf); |
271 | | #elif defined(HAVE_AIX_GETNETBYNAME_R) |
272 | | /* |
273 | | * We have AIX's reentrant getnetbyname_r(). |
274 | | */ |
275 | | struct netent result_buf; |
276 | | struct netent_data net_data; |
277 | | |
278 | | if (getnetbyname_r(name, &result_buf, &net_data) == -1) |
279 | | np = NULL; |
280 | | else |
281 | | np = &result_buf; |
282 | | #else |
283 | | /* |
284 | | * We don't have any getnetbyname_r(); either we have a |
285 | | * getnetbyname() that uses thread-specific data, in which |
286 | | * case we're thread-safe (sufficiently recent FreeBSD, |
287 | | * sufficiently recent Darwin-based OS, sufficiently recent |
288 | | * HP-UX, or we have the |
289 | | * traditional getnetbyname() (everything else, including |
290 | | * current NetBSD and OpenBSD), in which case we're not |
291 | | * thread-safe. |
292 | | */ |
293 | | np = getnetbyname(name); |
294 | | #endif |
295 | 0 | if (np != NULL) |
296 | 0 | return np->n_net; |
297 | 0 | else |
298 | 0 | return 0; |
299 | 0 | } |
300 | | #endif /* _WIN32 */ |
301 | | |
302 | | /* |
303 | | * Convert a port name to its port and protocol numbers. |
304 | | * We assume only TCP or UDP. |
305 | | * Return 0 upon failure. |
306 | | */ |
307 | | int |
308 | | pcap_nametoport(const char *name, int *port, int *proto) |
309 | 0 | { |
310 | 0 | struct addrinfo hints, *res, *ai; |
311 | 0 | int error; |
312 | 0 | struct sockaddr_in *in4; |
313 | 0 | struct sockaddr_in6 *in6; |
314 | 0 | int tcp_port = -1; |
315 | 0 | int udp_port = -1; |
316 | | |
317 | | /* |
318 | | * We check for both TCP and UDP in case there are |
319 | | * ambiguous entries. |
320 | | */ |
321 | 0 | memset(&hints, 0, sizeof(hints)); |
322 | 0 | hints.ai_family = PF_UNSPEC; |
323 | 0 | hints.ai_socktype = SOCK_STREAM; |
324 | 0 | hints.ai_protocol = IPPROTO_TCP; |
325 | 0 | error = getaddrinfo(NULL, name, &hints, &res); |
326 | 0 | if (error != 0) { |
327 | 0 | if (error != EAI_NONAME && |
328 | 0 | error != EAI_SERVICE) { |
329 | | /* |
330 | | * This is a real error, not just "there's |
331 | | * no such service name". |
332 | | * XXX - this doesn't return an error string. |
333 | | */ |
334 | 0 | return 0; |
335 | 0 | } |
336 | 0 | } else { |
337 | | /* |
338 | | * OK, we found it. Did it find anything? |
339 | | */ |
340 | 0 | for (ai = res; ai != NULL; ai = ai->ai_next) { |
341 | | /* |
342 | | * Does it have an address? |
343 | | */ |
344 | 0 | if (ai->ai_addr != NULL) { |
345 | | /* |
346 | | * Yes. Get a port number; we're done. |
347 | | */ |
348 | 0 | if (ai->ai_addr->sa_family == AF_INET) { |
349 | 0 | in4 = (struct sockaddr_in *)ai->ai_addr; |
350 | 0 | tcp_port = ntohs(in4->sin_port); |
351 | 0 | break; |
352 | 0 | } |
353 | 0 | if (ai->ai_addr->sa_family == AF_INET6) { |
354 | 0 | in6 = (struct sockaddr_in6 *)ai->ai_addr; |
355 | 0 | tcp_port = ntohs(in6->sin6_port); |
356 | 0 | break; |
357 | 0 | } |
358 | 0 | } |
359 | 0 | } |
360 | 0 | freeaddrinfo(res); |
361 | 0 | } |
362 | | |
363 | 0 | memset(&hints, 0, sizeof(hints)); |
364 | 0 | hints.ai_family = PF_UNSPEC; |
365 | 0 | hints.ai_socktype = SOCK_DGRAM; |
366 | 0 | hints.ai_protocol = IPPROTO_UDP; |
367 | 0 | error = getaddrinfo(NULL, name, &hints, &res); |
368 | 0 | if (error != 0) { |
369 | 0 | if (error != EAI_NONAME && |
370 | 0 | error != EAI_SERVICE) { |
371 | | /* |
372 | | * This is a real error, not just "there's |
373 | | * no such service name". |
374 | | * XXX - this doesn't return an error string. |
375 | | */ |
376 | 0 | return 0; |
377 | 0 | } |
378 | 0 | } else { |
379 | | /* |
380 | | * OK, we found it. Did it find anything? |
381 | | */ |
382 | 0 | for (ai = res; ai != NULL; ai = ai->ai_next) { |
383 | | /* |
384 | | * Does it have an address? |
385 | | */ |
386 | 0 | if (ai->ai_addr != NULL) { |
387 | | /* |
388 | | * Yes. Get a port number; we're done. |
389 | | */ |
390 | 0 | if (ai->ai_addr->sa_family == AF_INET) { |
391 | 0 | in4 = (struct sockaddr_in *)ai->ai_addr; |
392 | 0 | udp_port = ntohs(in4->sin_port); |
393 | 0 | break; |
394 | 0 | } |
395 | 0 | if (ai->ai_addr->sa_family == AF_INET6) { |
396 | 0 | in6 = (struct sockaddr_in6 *)ai->ai_addr; |
397 | 0 | udp_port = ntohs(in6->sin6_port); |
398 | 0 | break; |
399 | 0 | } |
400 | 0 | } |
401 | 0 | } |
402 | 0 | freeaddrinfo(res); |
403 | 0 | } |
404 | | |
405 | | /* |
406 | | * We need to check /etc/services for ambiguous entries. |
407 | | * If we find an ambiguous entry, and it has the |
408 | | * same port number, change the proto to PROTO_UNDEF |
409 | | * so both TCP and UDP will be checked. |
410 | | */ |
411 | 0 | if (tcp_port >= 0) { |
412 | 0 | *port = tcp_port; |
413 | 0 | *proto = IPPROTO_TCP; |
414 | 0 | if (udp_port >= 0) { |
415 | 0 | if (udp_port == tcp_port) |
416 | 0 | *proto = PROTO_UNDEF; |
417 | | #ifdef notdef |
418 | | else |
419 | | /* Can't handle ambiguous names that refer |
420 | | to different port numbers. */ |
421 | | warning("ambiguous port %s in /etc/services", |
422 | | name); |
423 | | #endif |
424 | 0 | } |
425 | 0 | return 1; |
426 | 0 | } |
427 | 0 | if (udp_port >= 0) { |
428 | 0 | *port = udp_port; |
429 | 0 | *proto = IPPROTO_UDP; |
430 | 0 | return 1; |
431 | 0 | } |
432 | 0 | return 0; |
433 | 0 | } |
434 | | |
435 | | /* |
436 | | * Convert a string in the form PPP-PPP, where correspond to ports, to |
437 | | * a starting and ending port in a port range. |
438 | | * Return 0 on failure. |
439 | | */ |
440 | | int |
441 | | pcap_nametoportrange(const char *name, int *port1, int *port2, int *proto) |
442 | 0 | { |
443 | 0 | char *off, *cpy; |
444 | 0 | int save_proto; |
445 | |
|
446 | 0 | if ((cpy = strdup(name)) == NULL) |
447 | 0 | return 0; |
448 | | |
449 | 0 | if ((off = strchr(cpy, '-')) == NULL) { |
450 | 0 | free(cpy); |
451 | 0 | return 0; |
452 | 0 | } |
453 | | |
454 | 0 | *off = '\0'; |
455 | |
|
456 | 0 | if (pcap_nametoport(cpy, port1, proto) == 0) { |
457 | 0 | free(cpy); |
458 | 0 | return 0; |
459 | 0 | } |
460 | 0 | save_proto = *proto; |
461 | |
|
462 | 0 | if (pcap_nametoport(off + 1, port2, proto) == 0) { |
463 | 0 | free(cpy); |
464 | 0 | return 0; |
465 | 0 | } |
466 | 0 | free(cpy); |
467 | |
|
468 | 0 | if (*proto != save_proto) |
469 | 0 | *proto = PROTO_UNDEF; |
470 | |
|
471 | 0 | return 1; |
472 | 0 | } |
473 | | |
474 | | /* |
475 | | * XXX - not guaranteed to be thread-safe! See below for platforms |
476 | | * on which it is thread-safe and on which it isn't. |
477 | | */ |
478 | | int |
479 | | pcap_nametoproto(const char *str) |
480 | 0 | { |
481 | 0 | struct protoent *p; |
482 | 0 | #if defined(HAVE_LINUX_GETPROTOBYNAME_R) |
483 | | /* |
484 | | * We have Linux's reentrant getprotobyname_r(). |
485 | | */ |
486 | 0 | struct protoent result_buf; |
487 | 0 | char buf[1024]; // "...1024 bytes should be sufficient for most applications." |
488 | 0 | int err; |
489 | |
|
490 | 0 | err = getprotobyname_r(str, &result_buf, buf, sizeof buf, &p); |
491 | | /* |
492 | | * As far as GNU libc implementation goes, an "error" means the |
493 | | * protocol database could not be searched, which could mean err == |
494 | | * ERANGE if the buffer is too small or ENOENT if the protocols(5) |
495 | | * file does not exist (the man page does not document the latter |
496 | | * eventuality). If the database has been searched normally and the |
497 | | * requested protocol name was not found, it is not an "error" and |
498 | | * err == 0. |
499 | | * |
500 | | * This notwithstanding, p == NULL iff a record was not found for any |
501 | | * reason (whether an "error" or not), which is the same semantics as |
502 | | * in every other HAVE_xxxxx branch of this block. The final check |
503 | | * after the block will catch that if necessary. |
504 | | */ |
505 | 0 | if (err != 0) { |
506 | | /* |
507 | | * XXX - dynamically allocate the buffer, and make it |
508 | | * bigger if we get ERANGE back? |
509 | | */ |
510 | 0 | return PROTO_UNDEF; |
511 | 0 | } |
512 | | #elif defined(HAVE_SOLARIS_GETPROTOBYNAME_R) |
513 | | /* |
514 | | * We have Solaris's reentrant getprotobyname_r(). |
515 | | */ |
516 | | struct protoent result_buf; |
517 | | char buf[1024]; // "...must be at least 1024 bytes." |
518 | | |
519 | | p = getprotobyname_r(str, &result_buf, buf, (int)sizeof buf); |
520 | | #elif defined(HAVE_AIX_GETPROTOBYNAME_R) |
521 | | /* |
522 | | * We have AIX's reentrant getprotobyname_r(). |
523 | | */ |
524 | | struct protoent result_buf; |
525 | | // "The structure must be zero-filled before it is used..." (OpenBSD). |
526 | | struct protoent_data proto_data = {0}; |
527 | | |
528 | | if (getprotobyname_r(str, &result_buf, &proto_data) == -1) |
529 | | p = NULL; |
530 | | else |
531 | | p = &result_buf; |
532 | | #else |
533 | | /* |
534 | | * We don't have any getprotobyname_r(); either we have a |
535 | | * getprotobyname() that uses thread-specific data, in which |
536 | | * case we're thread-safe (sufficiently recent FreeBSD, |
537 | | * sufficiently recent Darwin-based OS, sufficiently recent |
538 | | * HP-UX, Windows), or we have |
539 | | * the traditional getprotobyname() (everything else, including |
540 | | * current NetBSD and OpenBSD), in which case we're not |
541 | | * thread-safe. |
542 | | */ |
543 | | p = getprotobyname(str); |
544 | | #endif |
545 | 0 | if (p != 0) |
546 | 0 | return p->p_proto; |
547 | 0 | else |
548 | 0 | return PROTO_UNDEF; |
549 | 0 | } |
550 | | |
551 | | #include "ethertype.h" |
552 | | |
553 | | struct eproto { |
554 | | const char *s; |
555 | | u_short p; |
556 | | }; |
557 | | |
558 | | /* |
559 | | * Static data base of ether protocol types. |
560 | | * tcpdump used to import this, and it's declared as an export on |
561 | | * Debian, at least, so make it a public symbol, even though we |
562 | | * don't officially export it by declaring it in a header file. |
563 | | * (Programs *should* do this themselves, as tcpdump now does.) |
564 | | * |
565 | | * We declare it here, right before defining it, to squelch any |
566 | | * warnings we might get from compilers about the lack of a |
567 | | * declaration. |
568 | | */ |
569 | | PCAP_API struct eproto eproto_db[]; |
570 | | PCAP_API_DEF struct eproto eproto_db[] = { |
571 | | { "aarp", ETHERTYPE_AARP }, |
572 | | { "arp", ETHERTYPE_ARP }, |
573 | | { "atalk", ETHERTYPE_ATALK }, |
574 | | { "decnet", ETHERTYPE_DN }, |
575 | | { "ip", ETHERTYPE_IP }, |
576 | | { "ip6", ETHERTYPE_IPV6 }, |
577 | | { "lat", ETHERTYPE_LAT }, |
578 | | { "lldp", ETHERTYPE_LLDP }, |
579 | | { "loopback", ETHERTYPE_LOOPBACK }, |
580 | | { "mopdl", ETHERTYPE_MOPDL }, |
581 | | { "moprc", ETHERTYPE_MOPRC }, |
582 | | { "rarp", ETHERTYPE_REVARP }, |
583 | | { "sca", ETHERTYPE_SCA }, |
584 | | { "slow", ETHERTYPE_SLOW }, |
585 | | { NULL, 0 } |
586 | | }; |
587 | | |
588 | | static int |
589 | | proto_or_undef(const struct eproto *p, const char *s) |
590 | 0 | { |
591 | 0 | while (p->s) { |
592 | 0 | if (strcmp(p->s, s) == 0) |
593 | 0 | return p->p; |
594 | 0 | p += 1; |
595 | 0 | } |
596 | 0 | return PROTO_UNDEF; |
597 | 0 | } |
598 | | |
599 | | int |
600 | | pcap_nametoeproto(const char *s) |
601 | 0 | { |
602 | 0 | return proto_or_undef(eproto_db, s); |
603 | 0 | } |
604 | | |
605 | | #include "llc.h" |
606 | | |
607 | | /* Static data base of LLC values. */ |
608 | | static struct eproto llc_db[] = { |
609 | | { "iso", LLCSAP_ISONS }, |
610 | | { "stp", LLCSAP_8021D }, |
611 | | { "ipx", LLCSAP_IPX }, |
612 | | { "netbeui", LLCSAP_NETBEUI }, |
613 | | { NULL, 0 } |
614 | | }; |
615 | | |
616 | | int |
617 | | pcap_nametollc(const char *s) |
618 | 0 | { |
619 | 0 | return proto_or_undef(llc_db, s); |
620 | 0 | } |
621 | | |
622 | | /* Hex digit to 8-bit unsigned integer. */ |
623 | | u_char |
624 | | pcapint_xdtoi(const u_char c) |
625 | 0 | { |
626 | 0 | if (c >= '0' && c <= '9') |
627 | 0 | return (u_char)(c - '0'); |
628 | 0 | else if (c >= 'a' && c <= 'f') |
629 | 0 | return (u_char)(c - 'a' + 10); |
630 | 0 | else |
631 | 0 | return (u_char)(c - 'A' + 10); |
632 | 0 | } |
633 | | |
634 | | int |
635 | | pcapint_atoin(const char *s, bpf_u_int32 *addr) |
636 | 0 | { |
637 | 0 | u_int n; |
638 | 0 | int len; |
639 | |
|
640 | 0 | *addr = 0; |
641 | 0 | len = 0; |
642 | 0 | for (;;) { |
643 | 0 | n = 0; |
644 | 0 | while (*s && *s != '.') { |
645 | 0 | if (n > 25) { |
646 | | /* The result will be > 255 */ |
647 | 0 | return -1; |
648 | 0 | } |
649 | 0 | n = n * 10 + *s++ - '0'; |
650 | 0 | } |
651 | 0 | if (n > 255) |
652 | 0 | return -1; |
653 | 0 | *addr <<= 8; |
654 | 0 | *addr |= n & 0xff; |
655 | 0 | len += 8; |
656 | 0 | if (*s == '\0') |
657 | 0 | return len; |
658 | 0 | ++s; |
659 | 0 | } |
660 | | /* NOTREACHED */ |
661 | 0 | } |
662 | | |
663 | | /* |
664 | | * Iff 's' is a string that is a well-formed DECnet address (aa.nnnn), parse |
665 | | * the address into 'addr' and return 1, otherwise return 0. |
666 | | * |
667 | | * A binary DECnet address consists of a 6-bit area number and a 10-bit node |
668 | | * number; neither area 0 nor node 0 are valid for normal addressing purposes, |
669 | | * but either can potentially appear on the wire. |
670 | | */ |
671 | | int |
672 | | pcapint_atodn(const char *s, uint16_t *addr) |
673 | 0 | { |
674 | 0 | #define AREASHIFT 10 |
675 | 0 | #define AREAMASK 0176000 |
676 | 0 | #define NODEMASK 01777 |
677 | | |
678 | | /* Initialize to squelch a compiler warning only. */ |
679 | 0 | u_int node = 0, area = 0; |
680 | | /* |
681 | | * +--+ +--+ |
682 | | * | | | | |
683 | | * v | v | |
684 | | * --> START --> AREA --> DOT --> NODE --> |
685 | | * | | | | |
686 | | * | v v | |
687 | | * +--------> INVALID <------+ |
688 | | */ |
689 | 0 | enum { |
690 | 0 | START, |
691 | 0 | AREA, |
692 | 0 | DOT, |
693 | 0 | NODE, |
694 | 0 | INVALID |
695 | 0 | } fsm_state = START; |
696 | |
|
697 | 0 | while (*s) { |
698 | 0 | switch (fsm_state) { |
699 | 0 | case START: |
700 | 0 | if (PCAP_ISDIGIT(*s)) { |
701 | 0 | area = *s - '0'; |
702 | 0 | fsm_state = AREA; |
703 | 0 | break; |
704 | 0 | } |
705 | 0 | fsm_state = INVALID; |
706 | 0 | break; |
707 | 0 | case AREA: |
708 | 0 | if (*s == '.') { |
709 | 0 | fsm_state = DOT; |
710 | 0 | break; |
711 | 0 | } |
712 | 0 | if (PCAP_ISDIGIT(*s)) { |
713 | 0 | area = area * 10 + *s - '0'; |
714 | 0 | if (area <= AREAMASK >> AREASHIFT) |
715 | 0 | break; |
716 | 0 | } |
717 | 0 | fsm_state = INVALID; |
718 | 0 | break; |
719 | 0 | case DOT: |
720 | 0 | if (PCAP_ISDIGIT(*s)) { |
721 | 0 | node = *s - '0'; |
722 | 0 | fsm_state = NODE; |
723 | 0 | break; |
724 | 0 | } |
725 | 0 | fsm_state = INVALID; |
726 | 0 | break; |
727 | 0 | case NODE: |
728 | 0 | if (PCAP_ISDIGIT(*s)) { |
729 | 0 | node = node * 10 + *s - '0'; |
730 | 0 | if (node <= NODEMASK) |
731 | 0 | break; |
732 | 0 | } |
733 | 0 | fsm_state = INVALID; |
734 | 0 | break; |
735 | 0 | case INVALID: |
736 | 0 | return 0; |
737 | 0 | } /* switch */ |
738 | 0 | s++; |
739 | 0 | } /* while */ |
740 | | /* |
741 | | * This condition is false if the string comes from the lexer, but |
742 | | * let's not depend on that. |
743 | | */ |
744 | 0 | if (fsm_state != NODE) |
745 | 0 | return 0; |
746 | | |
747 | | // Both 'area' and 'node' have been verified to be in range. |
748 | 0 | *addr = (uint16_t)(area << AREASHIFT | node); |
749 | 0 | return 1; |
750 | 0 | } |
751 | | |
752 | | /* |
753 | | * libpcap ARCnet address format is "^\$[0-9a-fA-F]{1,2}$" in regexp syntax. |
754 | | * Iff the given string is a well-formed ARCnet address, parse the string, |
755 | | * store the 8-bit unsigned value into the provided integer and return 1. |
756 | | * Otherwise return 0. |
757 | | * |
758 | | * --> START -- $ --> DOLLAR -- [0-9a-fA-F] --> HEX1 -- \0 -->-+ |
759 | | * | | | | |
760 | | * [.] [.] [0-9a-fA-F] | |
761 | | * | | | | |
762 | | * v v v v |
763 | | * (invalid) <--------+-<---------------[.]-- HEX2 -- \0 -->-+--> (valid) |
764 | | */ |
765 | | int |
766 | | pcapint_atoan(const char *s, uint8_t *addr) |
767 | 0 | { |
768 | 0 | enum { |
769 | 0 | START, |
770 | 0 | DOLLAR, |
771 | 0 | HEX1, |
772 | 0 | HEX2, |
773 | 0 | } fsm_state = START; |
774 | 0 | uint8_t tmp = 0; |
775 | |
|
776 | 0 | while (*s) { |
777 | 0 | switch (fsm_state) { |
778 | 0 | case START: |
779 | 0 | if (*s != '$') |
780 | 0 | goto invalid; |
781 | 0 | fsm_state = DOLLAR; |
782 | 0 | break; |
783 | 0 | case DOLLAR: |
784 | 0 | if (! PCAP_ISXDIGIT(*s)) |
785 | 0 | goto invalid; |
786 | 0 | tmp = pcapint_xdtoi(*s); |
787 | 0 | fsm_state = HEX1; |
788 | 0 | break; |
789 | 0 | case HEX1: |
790 | 0 | if (! PCAP_ISXDIGIT(*s)) |
791 | 0 | goto invalid; |
792 | 0 | tmp <<= 4; |
793 | 0 | tmp |= pcapint_xdtoi(*s); |
794 | 0 | fsm_state = HEX2; |
795 | 0 | break; |
796 | 0 | case HEX2: |
797 | 0 | goto invalid; |
798 | 0 | } // switch |
799 | 0 | s++; |
800 | 0 | } // while |
801 | 0 | if (fsm_state == HEX1 || fsm_state == HEX2) { |
802 | 0 | *addr = tmp; |
803 | 0 | return 1; |
804 | 0 | } |
805 | | |
806 | 0 | invalid: |
807 | 0 | return 0; |
808 | 0 | } |
809 | | |
810 | | // Man page: "xxxxxxxxxxxx", regexp: "^[0-9a-fA-F]{12}$". |
811 | | static u_char |
812 | | pcapint_atomac48_xxxxxxxxxxxx(const char *s, uint8_t *addr) |
813 | 0 | { |
814 | 0 | if (strlen(s) == 12 && |
815 | 0 | PCAP_ISXDIGIT(s[0]) && |
816 | 0 | PCAP_ISXDIGIT(s[1]) && |
817 | 0 | PCAP_ISXDIGIT(s[2]) && |
818 | 0 | PCAP_ISXDIGIT(s[3]) && |
819 | 0 | PCAP_ISXDIGIT(s[4]) && |
820 | 0 | PCAP_ISXDIGIT(s[5]) && |
821 | 0 | PCAP_ISXDIGIT(s[6]) && |
822 | 0 | PCAP_ISXDIGIT(s[7]) && |
823 | 0 | PCAP_ISXDIGIT(s[8]) && |
824 | 0 | PCAP_ISXDIGIT(s[9]) && |
825 | 0 | PCAP_ISXDIGIT(s[10]) && |
826 | 0 | PCAP_ISXDIGIT(s[11])) { |
827 | 0 | addr[0] = pcapint_xdtoi(s[0]) << 4 | pcapint_xdtoi(s[1]); |
828 | 0 | addr[1] = pcapint_xdtoi(s[2]) << 4 | pcapint_xdtoi(s[3]); |
829 | 0 | addr[2] = pcapint_xdtoi(s[4]) << 4 | pcapint_xdtoi(s[5]); |
830 | 0 | addr[3] = pcapint_xdtoi(s[6]) << 4 | pcapint_xdtoi(s[7]); |
831 | 0 | addr[4] = pcapint_xdtoi(s[8]) << 4 | pcapint_xdtoi(s[9]); |
832 | 0 | addr[5] = pcapint_xdtoi(s[10]) << 4 | pcapint_xdtoi(s[11]); |
833 | 0 | return 1; |
834 | 0 | } |
835 | 0 | return 0; |
836 | 0 | } |
837 | | |
838 | | // Man page: "xxxx.xxxx.xxxx", regexp: "^[0-9a-fA-F]{4}(\.[0-9a-fA-F]{4}){2}$". |
839 | | static u_char |
840 | | pcapint_atomac48_xxxx_3_times(const char *s, uint8_t *addr) |
841 | 0 | { |
842 | 0 | const char sep = '.'; |
843 | 0 | if (strlen(s) == 14 && |
844 | 0 | PCAP_ISXDIGIT(s[0]) && |
845 | 0 | PCAP_ISXDIGIT(s[1]) && |
846 | 0 | PCAP_ISXDIGIT(s[2]) && |
847 | 0 | PCAP_ISXDIGIT(s[3]) && |
848 | 0 | s[4] == sep && |
849 | 0 | PCAP_ISXDIGIT(s[5]) && |
850 | 0 | PCAP_ISXDIGIT(s[6]) && |
851 | 0 | PCAP_ISXDIGIT(s[7]) && |
852 | 0 | PCAP_ISXDIGIT(s[8]) && |
853 | 0 | s[9] == sep && |
854 | 0 | PCAP_ISXDIGIT(s[10]) && |
855 | 0 | PCAP_ISXDIGIT(s[11]) && |
856 | 0 | PCAP_ISXDIGIT(s[12]) && |
857 | 0 | PCAP_ISXDIGIT(s[13])) { |
858 | 0 | addr[0] = pcapint_xdtoi(s[0]) << 4 | pcapint_xdtoi(s[1]); |
859 | 0 | addr[1] = pcapint_xdtoi(s[2]) << 4 | pcapint_xdtoi(s[3]); |
860 | 0 | addr[2] = pcapint_xdtoi(s[5]) << 4 | pcapint_xdtoi(s[6]); |
861 | 0 | addr[3] = pcapint_xdtoi(s[7]) << 4 | pcapint_xdtoi(s[8]); |
862 | 0 | addr[4] = pcapint_xdtoi(s[10]) << 4 | pcapint_xdtoi(s[11]); |
863 | 0 | addr[5] = pcapint_xdtoi(s[12]) << 4 | pcapint_xdtoi(s[13]); |
864 | 0 | return 1; |
865 | 0 | } |
866 | 0 | return 0; |
867 | 0 | } |
868 | | |
869 | | /* |
870 | | * Man page: "xx:xx:xx:xx:xx:xx", regexp: "^[0-9a-fA-F]{1,2}(:[0-9a-fA-F]{1,2}){5}$". |
871 | | * Man page: "xx-xx-xx-xx-xx-xx", regexp: "^[0-9a-fA-F]{1,2}(-[0-9a-fA-F]{1,2}){5}$". |
872 | | * Man page: "xx.xx.xx.xx.xx.xx", regexp: "^[0-9a-fA-F]{1,2}(\.[0-9a-fA-F]{1,2}){5}$". |
873 | | * (Any "xx" above can be "x", which is equivalent to "0x".) |
874 | | * |
875 | | * An equivalent (and parametrisable for EUI-64) FSM could be implemented using |
876 | | * a smaller graph, but that graph would be neither acyclic nor planar nor |
877 | | * trivial to verify. |
878 | | * |
879 | | * | |
880 | | * [.] v |
881 | | * +<---------- START |
882 | | * | | |
883 | | * | | [0-9a-fA-F] |
884 | | * | [.] v |
885 | | * +<--------- BYTE0_X ----------+ |
886 | | * | | | |
887 | | * | | [0-9a-fA-F] | |
888 | | * | [.] v | |
889 | | * +<--------- BYTE0_XX | [:\.-] |
890 | | * | | | |
891 | | * | | [:\.-] | |
892 | | * | [.] v | |
893 | | * +<----- BYTE0_SEP_BYTE1 <-----+ |
894 | | * | | |
895 | | * | | [0-9a-fA-F] |
896 | | * | [.] v |
897 | | * +<--------- BYTE1_X ----------+ |
898 | | * | | | |
899 | | * | | [0-9a-fA-F] | |
900 | | * | [.] v | |
901 | | * +<--------- BYTE1_XX | <sep> |
902 | | * | | | |
903 | | * | | <sep> | |
904 | | * | [.] v | |
905 | | * +<----- BYTE1_SEP_BYTE2 <-----+ |
906 | | * | | |
907 | | * | | [0-9a-fA-F] |
908 | | * | [.] v |
909 | | * +<--------- BYTE2_X ----------+ |
910 | | * | | | |
911 | | * | | [0-9a-fA-F] | |
912 | | * | [.] v | |
913 | | * +<--------- BYTE2_XX | <sep> |
914 | | * | | | |
915 | | * | | <sep> | |
916 | | * | [.] v | |
917 | | * +<----- BYTE2_SEP_BYTE3 <-----+ |
918 | | * | | |
919 | | * | | [0-9a-fA-F] |
920 | | * | [.] v |
921 | | * +<--------- BYTE3_X ----------+ |
922 | | * | | | |
923 | | * | | [0-9a-fA-F] | |
924 | | * | [.] v | |
925 | | * +<--------- BYTE3_XX | <sep> |
926 | | * | | | |
927 | | * | | <sep> | |
928 | | * | [.] v | |
929 | | * +<----- BYTE3_SEP_BYTE4 <-----+ |
930 | | * | | |
931 | | * | | [0-9a-fA-F] |
932 | | * | [.] v |
933 | | * +<--------- BYTE4_X ----------+ |
934 | | * | | | |
935 | | * | | [0-9a-fA-F] | |
936 | | * | [.] v | |
937 | | * +<--------- BYTE4_XX | <sep> |
938 | | * | | | |
939 | | * | | <sep> | |
940 | | * | [.] v | |
941 | | * +<----- BYTE4_SEP_BYTE5 <-----+ |
942 | | * | | |
943 | | * | | [0-9a-fA-F] |
944 | | * | [.] v |
945 | | * +<--------- BYTE5_X ----------+ |
946 | | * | | | |
947 | | * | | [0-9a-fA-F] | |
948 | | * | [.] v | |
949 | | * +<--------- BYTE5_XX | \0 |
950 | | * | | | |
951 | | * | | \0 | |
952 | | * | | v |
953 | | * +--> (reject) +---------> (accept) |
954 | | * |
955 | | */ |
956 | | static u_char |
957 | | pcapint_atomac48_x_xx_6_times(const char *s, uint8_t *addr) |
958 | 0 | { |
959 | 0 | enum { |
960 | 0 | START, |
961 | 0 | BYTE0_X, |
962 | 0 | BYTE0_XX, |
963 | 0 | BYTE0_SEP_BYTE1, |
964 | 0 | BYTE1_X, |
965 | 0 | BYTE1_XX, |
966 | 0 | BYTE1_SEP_BYTE2, |
967 | 0 | BYTE2_X, |
968 | 0 | BYTE2_XX, |
969 | 0 | BYTE2_SEP_BYTE3, |
970 | 0 | BYTE3_X, |
971 | 0 | BYTE3_XX, |
972 | 0 | BYTE3_SEP_BYTE4, |
973 | 0 | BYTE4_X, |
974 | 0 | BYTE4_XX, |
975 | 0 | BYTE4_SEP_BYTE5, |
976 | 0 | BYTE5_X, |
977 | 0 | BYTE5_XX, |
978 | 0 | } fsm_state = START; |
979 | 0 | uint8_t buf[6]; |
980 | 0 | const char *seplist = ":.-"; |
981 | | /* |
982 | | * XXX - the state diagram indicates that we cannot get to states |
983 | | * BYTEn_X or BYTEn_XX, for n > 0, without first going through |
984 | | * states BYTE0_X or BYTE0_XX, but at least some versions of |
985 | | * MSVC complain that sep may be used uninitialized, so we |
986 | | * initialize it here. |
987 | | */ |
988 | 0 | char sep = '\0'; |
989 | |
|
990 | 0 | while (*s) { |
991 | 0 | switch (fsm_state) { |
992 | 0 | case START: |
993 | 0 | if (PCAP_ISXDIGIT(*s)) { |
994 | 0 | buf[0] = pcapint_xdtoi(*s); |
995 | 0 | fsm_state = BYTE0_X; |
996 | 0 | break; |
997 | 0 | } |
998 | 0 | goto reject; |
999 | 0 | case BYTE0_X: |
1000 | 0 | if (strchr(seplist, *s)) { |
1001 | 0 | sep = *s; |
1002 | 0 | fsm_state = BYTE0_SEP_BYTE1; |
1003 | 0 | break; |
1004 | 0 | } |
1005 | 0 | if (PCAP_ISXDIGIT(*s)) { |
1006 | 0 | buf[0] = buf[0] << 4 | pcapint_xdtoi(*s); |
1007 | 0 | fsm_state = BYTE0_XX; |
1008 | 0 | break; |
1009 | 0 | } |
1010 | 0 | goto reject; |
1011 | 0 | case BYTE0_XX: |
1012 | 0 | if (strchr(seplist, *s)) { |
1013 | 0 | sep = *s; |
1014 | 0 | fsm_state = BYTE0_SEP_BYTE1; |
1015 | 0 | break; |
1016 | 0 | } |
1017 | 0 | goto reject; |
1018 | 0 | case BYTE0_SEP_BYTE1: |
1019 | 0 | if (PCAP_ISXDIGIT(*s)) { |
1020 | 0 | buf[1] = pcapint_xdtoi(*s); |
1021 | 0 | fsm_state = BYTE1_X; |
1022 | 0 | break; |
1023 | 0 | } |
1024 | 0 | goto reject; |
1025 | 0 | case BYTE1_X: |
1026 | 0 | if (*s == sep) { |
1027 | 0 | fsm_state = BYTE1_SEP_BYTE2; |
1028 | 0 | break; |
1029 | 0 | } |
1030 | 0 | if (PCAP_ISXDIGIT(*s)) { |
1031 | 0 | buf[1] = buf[1] << 4 | pcapint_xdtoi(*s); |
1032 | 0 | fsm_state = BYTE1_XX; |
1033 | 0 | break; |
1034 | 0 | } |
1035 | 0 | goto reject; |
1036 | 0 | case BYTE1_XX: |
1037 | 0 | if (*s == sep) { |
1038 | 0 | fsm_state = BYTE1_SEP_BYTE2; |
1039 | 0 | break; |
1040 | 0 | } |
1041 | 0 | goto reject; |
1042 | 0 | case BYTE1_SEP_BYTE2: |
1043 | 0 | if (PCAP_ISXDIGIT(*s)) { |
1044 | 0 | buf[2] = pcapint_xdtoi(*s); |
1045 | 0 | fsm_state = BYTE2_X; |
1046 | 0 | break; |
1047 | 0 | } |
1048 | 0 | goto reject; |
1049 | 0 | case BYTE2_X: |
1050 | 0 | if (*s == sep) { |
1051 | 0 | fsm_state = BYTE2_SEP_BYTE3; |
1052 | 0 | break; |
1053 | 0 | } |
1054 | 0 | if (PCAP_ISXDIGIT(*s)) { |
1055 | 0 | buf[2] = buf[2] << 4 | pcapint_xdtoi(*s); |
1056 | 0 | fsm_state = BYTE2_XX; |
1057 | 0 | break; |
1058 | 0 | } |
1059 | 0 | goto reject; |
1060 | 0 | case BYTE2_XX: |
1061 | 0 | if (*s == sep) { |
1062 | 0 | fsm_state = BYTE2_SEP_BYTE3; |
1063 | 0 | break; |
1064 | 0 | } |
1065 | 0 | goto reject; |
1066 | 0 | case BYTE2_SEP_BYTE3: |
1067 | 0 | if (PCAP_ISXDIGIT(*s)) { |
1068 | 0 | buf[3] = pcapint_xdtoi(*s); |
1069 | 0 | fsm_state = BYTE3_X; |
1070 | 0 | break; |
1071 | 0 | } |
1072 | 0 | goto reject; |
1073 | 0 | case BYTE3_X: |
1074 | 0 | if (*s == sep) { |
1075 | 0 | fsm_state = BYTE3_SEP_BYTE4; |
1076 | 0 | break; |
1077 | 0 | } |
1078 | 0 | if (PCAP_ISXDIGIT(*s)) { |
1079 | 0 | buf[3] = buf[3] << 4 | pcapint_xdtoi(*s); |
1080 | 0 | fsm_state = BYTE3_XX; |
1081 | 0 | break; |
1082 | 0 | } |
1083 | 0 | goto reject; |
1084 | 0 | case BYTE3_XX: |
1085 | 0 | if (*s == sep) { |
1086 | 0 | fsm_state = BYTE3_SEP_BYTE4; |
1087 | 0 | break; |
1088 | 0 | } |
1089 | 0 | goto reject; |
1090 | 0 | case BYTE3_SEP_BYTE4: |
1091 | 0 | if (PCAP_ISXDIGIT(*s)) { |
1092 | 0 | buf[4] = pcapint_xdtoi(*s); |
1093 | 0 | fsm_state = BYTE4_X; |
1094 | 0 | break; |
1095 | 0 | } |
1096 | 0 | goto reject; |
1097 | 0 | case BYTE4_X: |
1098 | 0 | if (*s == sep) { |
1099 | 0 | fsm_state = BYTE4_SEP_BYTE5; |
1100 | 0 | break; |
1101 | 0 | } |
1102 | 0 | if (PCAP_ISXDIGIT(*s)) { |
1103 | 0 | buf[4] = buf[4] << 4 | pcapint_xdtoi(*s); |
1104 | 0 | fsm_state = BYTE4_XX; |
1105 | 0 | break; |
1106 | 0 | } |
1107 | 0 | goto reject; |
1108 | 0 | case BYTE4_XX: |
1109 | 0 | if (*s == sep) { |
1110 | 0 | fsm_state = BYTE4_SEP_BYTE5; |
1111 | 0 | break; |
1112 | 0 | } |
1113 | 0 | goto reject; |
1114 | 0 | case BYTE4_SEP_BYTE5: |
1115 | 0 | if (PCAP_ISXDIGIT(*s)) { |
1116 | 0 | buf[5] = pcapint_xdtoi(*s); |
1117 | 0 | fsm_state = BYTE5_X; |
1118 | 0 | break; |
1119 | 0 | } |
1120 | 0 | goto reject; |
1121 | 0 | case BYTE5_X: |
1122 | 0 | if (PCAP_ISXDIGIT(*s)) { |
1123 | 0 | buf[5] = buf[5] << 4 | pcapint_xdtoi(*s); |
1124 | 0 | fsm_state = BYTE5_XX; |
1125 | 0 | break; |
1126 | 0 | } |
1127 | 0 | goto reject; |
1128 | 0 | case BYTE5_XX: |
1129 | 0 | goto reject; |
1130 | 0 | } // switch |
1131 | 0 | s++; |
1132 | 0 | } // while |
1133 | | |
1134 | 0 | if (fsm_state == BYTE5_X || fsm_state == BYTE5_XX) { |
1135 | | // accept |
1136 | 0 | memcpy(addr, buf, sizeof(buf)); |
1137 | 0 | return 1; |
1138 | 0 | } |
1139 | | |
1140 | 0 | reject: |
1141 | 0 | return 0; |
1142 | 0 | } |
1143 | | |
1144 | | // The 'addr' argument must point to an array of at least 6 elements. |
1145 | | int |
1146 | | pcapint_atomac48(const char *s, uint8_t *addr) |
1147 | 0 | { |
1148 | 0 | return s && ( |
1149 | 0 | pcapint_atomac48_xxxxxxxxxxxx(s, addr) || |
1150 | 0 | pcapint_atomac48_xxxx_3_times(s, addr) || |
1151 | 0 | pcapint_atomac48_x_xx_6_times(s, addr) |
1152 | 0 | ); |
1153 | 0 | } |
1154 | | |
1155 | | /* |
1156 | | * If 's' is a MAC-48 address in one of the forms documented in pcap-filter(7) |
1157 | | * for "ether host", return a pointer to an allocated buffer with the binary |
1158 | | * value of the address. Return NULL on any error. |
1159 | | */ |
1160 | | u_char * |
1161 | | pcap_ether_aton(const char *s) |
1162 | 0 | { |
1163 | 0 | uint8_t tmp[6]; |
1164 | 0 | if (! pcapint_atomac48(s, tmp)) |
1165 | 0 | return (NULL); |
1166 | | |
1167 | 0 | u_char *e = malloc(6); |
1168 | 0 | if (e == NULL) |
1169 | 0 | return (NULL); |
1170 | 0 | memcpy(e, tmp, sizeof(tmp)); |
1171 | 0 | return (e); |
1172 | 0 | } |
1173 | | |
1174 | | #if ! defined(HAVE_ETHER_HOSTTON) || defined(BROKEN_ETHER_HOSTTON) |
1175 | | /* |
1176 | | * Roll our own. |
1177 | | * |
1178 | | * This should be thread-safe, as we define the static variables |
1179 | | * we use to be thread-local, and as pcap_next_etherent() does so |
1180 | | * as well. |
1181 | | */ |
1182 | | u_char * |
1183 | | pcap_ether_hostton(const char *name) |
1184 | | { |
1185 | | struct pcap_etherent *ep; |
1186 | | u_char *ap; |
1187 | | static thread_local FILE *fp = NULL; |
1188 | | static thread_local int init = 0; |
1189 | | |
1190 | | if (!init) { |
1191 | | fp = fopen(PCAP_ETHERS_FILE, "r"); |
1192 | | ++init; |
1193 | | if (fp == NULL) |
1194 | | return (NULL); |
1195 | | } else if (fp == NULL) |
1196 | | return (NULL); |
1197 | | else |
1198 | | rewind(fp); |
1199 | | |
1200 | | while ((ep = pcap_next_etherent(fp)) != NULL) { |
1201 | | if (strcmp(ep->name, name) == 0) { |
1202 | | ap = (u_char *)malloc(6); |
1203 | | if (ap != NULL) { |
1204 | | memcpy(ap, ep->addr, 6); |
1205 | | return (ap); |
1206 | | } |
1207 | | break; |
1208 | | } |
1209 | | } |
1210 | | return (NULL); |
1211 | | } |
1212 | | #else |
1213 | | /* |
1214 | | * Use the OS-supplied routine. |
1215 | | * This *should* be thread-safe; the API doesn't have a static buffer. |
1216 | | */ |
1217 | | u_char * |
1218 | | pcap_ether_hostton(const char *name) |
1219 | 0 | { |
1220 | 0 | u_char *ap; |
1221 | 0 | u_char a[6]; |
1222 | 0 | char namebuf[1024]; |
1223 | | |
1224 | | /* |
1225 | | * In AIX 7.1 and 7.2: int ether_hostton(char *, struct ether_addr *); |
1226 | | */ |
1227 | 0 | pcapint_strlcpy(namebuf, name, sizeof(namebuf)); |
1228 | 0 | ap = NULL; |
1229 | 0 | if (ether_hostton(namebuf, (struct ether_addr *)a) == 0) { |
1230 | 0 | ap = (u_char *)malloc(6); |
1231 | 0 | if (ap != NULL) |
1232 | 0 | memcpy((char *)ap, (char *)a, 6); |
1233 | 0 | } |
1234 | 0 | return (ap); |
1235 | 0 | } |
1236 | | #endif |