1*d5dfe396Schristos /* $NetBSD: nametoaddr.c,v 1.5 2019/10/01 16:02:11 christos Exp $ */
2e3899b6dSchristos
354a6ec8aSchristos /*
454a6ec8aSchristos * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998
554a6ec8aSchristos * The Regents of the University of California. All rights reserved.
654a6ec8aSchristos *
754a6ec8aSchristos * Redistribution and use in source and binary forms, with or without
854a6ec8aSchristos * modification, are permitted provided that: (1) source code distributions
954a6ec8aSchristos * retain the above copyright notice and this paragraph in its entirety, (2)
1054a6ec8aSchristos * distributions including binary code include the above copyright notice and
1154a6ec8aSchristos * this paragraph in its entirety in the documentation or other materials
1254a6ec8aSchristos * provided with the distribution, and (3) all advertising materials mentioning
1354a6ec8aSchristos * features or use of this software display the following acknowledgement:
1454a6ec8aSchristos * ``This product includes software developed by the University of California,
1554a6ec8aSchristos * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1654a6ec8aSchristos * the University nor the names of its contributors may be used to endorse
1754a6ec8aSchristos * or promote products derived from this software without specific prior
1854a6ec8aSchristos * written permission.
1954a6ec8aSchristos * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
2054a6ec8aSchristos * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
2154a6ec8aSchristos * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2254a6ec8aSchristos *
2354a6ec8aSchristos * Name to id translation routines used by the scanner.
2454a6ec8aSchristos * These functions are not time critical.
2554a6ec8aSchristos */
2654a6ec8aSchristos
27e3899b6dSchristos #include <sys/cdefs.h>
28*d5dfe396Schristos __RCSID("$NetBSD: nametoaddr.c,v 1.5 2019/10/01 16:02:11 christos Exp $");
29e3899b6dSchristos
3054a6ec8aSchristos #ifdef HAVE_CONFIG_H
31e1375535Schristos #include <config.h>
3254a6ec8aSchristos #endif
3354a6ec8aSchristos
3454a6ec8aSchristos #ifdef DECNETLIB
3554a6ec8aSchristos #include <sys/types.h>
3654a6ec8aSchristos #include <netdnet/dnetdb.h>
3754a6ec8aSchristos #endif
3854a6ec8aSchristos
3903e25b48Schristos #ifdef _WIN32
40e1375535Schristos #include <winsock2.h>
41e1375535Schristos #include <ws2tcpip.h>
4254a6ec8aSchristos
4303e25b48Schristos #ifdef INET6
4403e25b48Schristos /*
4503e25b48Schristos * To quote the MSDN page for getaddrinfo() at
4603e25b48Schristos *
4703e25b48Schristos * https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520(v=vs.85).aspx
4803e25b48Schristos *
4903e25b48Schristos * "Support for getaddrinfo on Windows 2000 and older versions
5003e25b48Schristos * The getaddrinfo function was added to the Ws2_32.dll on Windows XP and
5103e25b48Schristos * later. To execute an application that uses this function on earlier
5203e25b48Schristos * versions of Windows, then you need to include the Ws2tcpip.h and
5303e25b48Schristos * Wspiapi.h files. When the Wspiapi.h include file is added, the
5403e25b48Schristos * getaddrinfo function is defined to the WspiapiGetAddrInfo inline
5503e25b48Schristos * function in the Wspiapi.h file. At runtime, the WspiapiGetAddrInfo
5603e25b48Schristos * function is implemented in such a way that if the Ws2_32.dll or the
5703e25b48Schristos * Wship6.dll (the file containing getaddrinfo in the IPv6 Technology
5803e25b48Schristos * Preview for Windows 2000) does not include getaddrinfo, then a
5903e25b48Schristos * version of getaddrinfo is implemented inline based on code in the
6003e25b48Schristos * Wspiapi.h header file. This inline code will be used on older Windows
6103e25b48Schristos * platforms that do not natively support the getaddrinfo function."
6203e25b48Schristos *
63e1375535Schristos * We use getaddrinfo(), so we include Wspiapi.h here.
6403e25b48Schristos */
65e1375535Schristos #include <wspiapi.h>
66e1375535Schristos #endif /* INET6 */
6703e25b48Schristos #else /* _WIN32 */
6854a6ec8aSchristos #include <sys/param.h>
69e1375535Schristos #include <sys/types.h>
7054a6ec8aSchristos #include <sys/socket.h>
7154a6ec8aSchristos #include <sys/time.h>
7254a6ec8aSchristos
7354a6ec8aSchristos #include <netinet/in.h>
7454a6ec8aSchristos
7554a6ec8aSchristos #ifdef HAVE_ETHER_HOSTTON
76e1375535Schristos #if defined(NET_ETHERNET_H_DECLARES_ETHER_HOSTTON)
7754a6ec8aSchristos /*
78e1375535Schristos * OK, just include <net/ethernet.h>.
7954a6ec8aSchristos */
80e1375535Schristos #include <net/ethernet.h>
81e1375535Schristos #elif defined(NETINET_ETHER_H_DECLARES_ETHER_HOSTTON)
82e1375535Schristos /*
83e1375535Schristos * OK, just include <netinet/ether.h>
84e1375535Schristos */
8554a6ec8aSchristos #include <netinet/ether.h>
86e1375535Schristos #elif defined(SYS_ETHERNET_H_DECLARES_ETHER_HOSTTON)
87e1375535Schristos /*
88e1375535Schristos * OK, just include <sys/ethernet.h>
89e1375535Schristos */
90e1375535Schristos #include <sys/ethernet.h>
91e1375535Schristos #elif defined(ARPA_INET_H_DECLARES_ETHER_HOSTTON)
92e1375535Schristos /*
93e1375535Schristos * OK, just include <arpa/inet.h>
94e1375535Schristos */
95e1375535Schristos #include <arpa/inet.h>
96e1375535Schristos #elif defined(NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON)
97e1375535Schristos /*
98e1375535Schristos * OK, include <netinet/if_ether.h>, after all the other stuff we
99e1375535Schristos * need to include or define for its benefit.
100e1375535Schristos */
101e1375535Schristos #define NEED_NETINET_IF_ETHER_H
102e1375535Schristos #else
103e1375535Schristos /*
104e1375535Schristos * We'll have to declare it ourselves.
105e1375535Schristos * If <netinet/if_ether.h> defines struct ether_addr, include
106e1375535Schristos * it. Otherwise, define it ourselves.
107e1375535Schristos */
108e1375535Schristos #ifdef HAVE_STRUCT_ETHER_ADDR
109e1375535Schristos #define NEED_NETINET_IF_ETHER_H
110e1375535Schristos #else /* HAVE_STRUCT_ETHER_ADDR */
111e1375535Schristos struct ether_addr {
112e1375535Schristos unsigned char ether_addr_octet[6];
113e1375535Schristos };
114e1375535Schristos #endif /* HAVE_STRUCT_ETHER_ADDR */
115e1375535Schristos #endif /* what declares ether_hostton() */
116e1375535Schristos
117e1375535Schristos #ifdef NEED_NETINET_IF_ETHER_H
118e1375535Schristos #include <net/if.h> /* Needed on some platforms */
119e1375535Schristos #include <netinet/in.h> /* Needed on some platforms */
120e1375535Schristos #include <netinet/if_ether.h>
121e1375535Schristos #endif /* NEED_NETINET_IF_ETHER_H */
122e1375535Schristos
123e1375535Schristos #ifndef HAVE_DECL_ETHER_HOSTTON
124e1375535Schristos /*
125e1375535Schristos * No header declares it, so declare it ourselves.
126e1375535Schristos */
127e1375535Schristos extern int ether_hostton(const char *, struct ether_addr *);
128e1375535Schristos #endif /* !defined(HAVE_DECL_ETHER_HOSTTON) */
12954a6ec8aSchristos #endif /* HAVE_ETHER_HOSTTON */
130e1375535Schristos
13154a6ec8aSchristos #include <arpa/inet.h>
13254a6ec8aSchristos #include <netdb.h>
13303e25b48Schristos #endif /* _WIN32 */
13454a6ec8aSchristos
13554a6ec8aSchristos #include <ctype.h>
13654a6ec8aSchristos #include <errno.h>
13754a6ec8aSchristos #include <stdlib.h>
13854a6ec8aSchristos #include <string.h>
13954a6ec8aSchristos #include <stdio.h>
14054a6ec8aSchristos
14154a6ec8aSchristos #include "pcap-int.h"
14254a6ec8aSchristos
14354a6ec8aSchristos #include "gencode.h"
14454a6ec8aSchristos #include <pcap/namedb.h>
14503e25b48Schristos #include "nametoaddr.h"
14654a6ec8aSchristos
14754a6ec8aSchristos #ifdef HAVE_OS_PROTO_H
14854a6ec8aSchristos #include "os-proto.h"
14954a6ec8aSchristos #endif
15054a6ec8aSchristos
15154a6ec8aSchristos #ifndef NTOHL
15254a6ec8aSchristos #define NTOHL(x) (x) = ntohl(x)
15354a6ec8aSchristos #define NTOHS(x) (x) = ntohs(x)
15454a6ec8aSchristos #endif
15554a6ec8aSchristos
15654a6ec8aSchristos /*
15754a6ec8aSchristos * Convert host name to internet address.
15854a6ec8aSchristos * Return 0 upon failure.
159e1375535Schristos * XXX - not thread-safe; don't use it inside libpcap.
16054a6ec8aSchristos */
16154a6ec8aSchristos bpf_u_int32 **
pcap_nametoaddr(const char * name)16254a6ec8aSchristos pcap_nametoaddr(const char *name)
16354a6ec8aSchristos {
16454a6ec8aSchristos #ifndef h_addr
16554a6ec8aSchristos static bpf_u_int32 *hlist[2];
16654a6ec8aSchristos #endif
16754a6ec8aSchristos bpf_u_int32 **p;
16854a6ec8aSchristos struct hostent *hp;
16954a6ec8aSchristos
17054a6ec8aSchristos if ((hp = gethostbyname(name)) != NULL) {
17154a6ec8aSchristos #ifndef h_addr
17254a6ec8aSchristos hlist[0] = (bpf_u_int32 *)hp->h_addr;
17354a6ec8aSchristos NTOHL(hp->h_addr);
17454a6ec8aSchristos return hlist;
17554a6ec8aSchristos #else
17654a6ec8aSchristos for (p = (bpf_u_int32 **)hp->h_addr_list; *p; ++p)
17754a6ec8aSchristos NTOHL(**p);
17854a6ec8aSchristos return (bpf_u_int32 **)hp->h_addr_list;
17954a6ec8aSchristos #endif
18054a6ec8aSchristos }
18154a6ec8aSchristos else
18254a6ec8aSchristos return 0;
18354a6ec8aSchristos }
18454a6ec8aSchristos
18554a6ec8aSchristos struct addrinfo *
pcap_nametoaddrinfo(const char * name)18654a6ec8aSchristos pcap_nametoaddrinfo(const char *name)
18754a6ec8aSchristos {
18854a6ec8aSchristos struct addrinfo hints, *res;
18954a6ec8aSchristos int error;
19054a6ec8aSchristos
19154a6ec8aSchristos memset(&hints, 0, sizeof(hints));
19254a6ec8aSchristos hints.ai_family = PF_UNSPEC;
19354a6ec8aSchristos hints.ai_socktype = SOCK_STREAM; /*not really*/
19454a6ec8aSchristos hints.ai_protocol = IPPROTO_TCP; /*not really*/
19554a6ec8aSchristos error = getaddrinfo(name, NULL, &hints, &res);
19654a6ec8aSchristos if (error)
19754a6ec8aSchristos return NULL;
19854a6ec8aSchristos else
19954a6ec8aSchristos return res;
20054a6ec8aSchristos }
20154a6ec8aSchristos
20254a6ec8aSchristos /*
20354a6ec8aSchristos * Convert net name to internet address.
20454a6ec8aSchristos * Return 0 upon failure.
205e1375535Schristos * XXX - not guaranteed to be thread-safe! See below for platforms
206e1375535Schristos * on which it is thread-safe and on which it isn't.
20754a6ec8aSchristos */
20854a6ec8aSchristos bpf_u_int32
pcap_nametonetaddr(const char * name)20954a6ec8aSchristos pcap_nametonetaddr(const char *name)
21054a6ec8aSchristos {
211e1375535Schristos #ifdef _WIN32
21254a6ec8aSchristos /*
21354a6ec8aSchristos * There's no "getnetbyname()" on Windows.
21403e25b48Schristos *
21503e25b48Schristos * XXX - I guess we could use the BSD code to read
21603e25b48Schristos * C:\Windows\System32\drivers\etc/networks, assuming
21703e25b48Schristos * that's its home on all the versions of Windows
21803e25b48Schristos * we use, but that file probably just has the loopback
21903e25b48Schristos * network on 127/24 on 99 44/100% of Windows machines.
22003e25b48Schristos *
22103e25b48Schristos * (Heck, these days it probably just has that on 99 44/100%
22203e25b48Schristos * of *UN*X* machines.)
22354a6ec8aSchristos */
22454a6ec8aSchristos return 0;
225e1375535Schristos #else
226e1375535Schristos /*
227e1375535Schristos * UN*X.
228e1375535Schristos */
229e1375535Schristos struct netent *np;
230e1375535Schristos #if defined(HAVE_LINUX_GETNETBYNAME_R)
231e1375535Schristos /*
232e1375535Schristos * We have Linux's reentrant getnetbyname_r().
233e1375535Schristos */
234e1375535Schristos struct netent result_buf;
235e1375535Schristos char buf[1024]; /* arbitrary size */
236e1375535Schristos int h_errnoval;
237e1375535Schristos int err;
238e1375535Schristos
239*d5dfe396Schristos /*
240*d5dfe396Schristos * Apparently, the man page at
241*d5dfe396Schristos *
242*d5dfe396Schristos * http://man7.org/linux/man-pages/man3/getnetbyname_r.3.html
243*d5dfe396Schristos *
244*d5dfe396Schristos * lies when it says
245*d5dfe396Schristos *
246*d5dfe396Schristos * If the function call successfully obtains a network record,
247*d5dfe396Schristos * then *result is set pointing to result_buf; otherwise, *result
248*d5dfe396Schristos * is set to NULL.
249*d5dfe396Schristos *
250*d5dfe396Schristos * and, in fact, at least in some versions of GNU libc, it does
251*d5dfe396Schristos * *not* always get set if getnetbyname_r() succeeds.
252*d5dfe396Schristos */
253*d5dfe396Schristos np = NULL;
254e1375535Schristos err = getnetbyname_r(name, &result_buf, buf, sizeof buf, &np,
255e1375535Schristos &h_errnoval);
256e1375535Schristos if (err != 0) {
257e1375535Schristos /*
258e1375535Schristos * XXX - dynamically allocate the buffer, and make it
259e1375535Schristos * bigger if we get ERANGE back?
260e1375535Schristos */
261e1375535Schristos return 0;
262e1375535Schristos }
263e1375535Schristos #elif defined(HAVE_SOLARIS_IRIX_GETNETBYNAME_R)
264e1375535Schristos /*
265e1375535Schristos * We have Solaris's and IRIX's reentrant getnetbyname_r().
266e1375535Schristos */
267e1375535Schristos struct netent result_buf;
268e1375535Schristos char buf[1024]; /* arbitrary size */
269e1375535Schristos
270e1375535Schristos np = getnetbyname_r(name, &result_buf, buf, (int)sizeof buf);
271e1375535Schristos #elif defined(HAVE_AIX_GETNETBYNAME_R)
272e1375535Schristos /*
273e1375535Schristos * We have AIX's reentrant getnetbyname_r().
274e1375535Schristos */
275e1375535Schristos struct netent result_buf;
276e1375535Schristos struct netent_data net_data;
277e1375535Schristos
278e1375535Schristos if (getnetbyname_r(name, &result_buf, &net_data) == -1)
279e1375535Schristos np = NULL;
280e1375535Schristos else
281e1375535Schristos np = &result_buf;
282e1375535Schristos #else
283e1375535Schristos /*
284e1375535Schristos * We don't have any getnetbyname_r(); either we have a
285e1375535Schristos * getnetbyname() that uses thread-specific data, in which
286e1375535Schristos * case we're thread-safe (sufficiently recent FreeBSD,
287e1375535Schristos * sufficiently recent Darwin-based OS, sufficiently recent
288e1375535Schristos * HP-UX, sufficiently recent Tru64 UNIX), or we have the
289e1375535Schristos * traditional getnetbyname() (everything else, including
290e1375535Schristos * current NetBSD and OpenBSD), in which case we're not
291e1375535Schristos * thread-safe.
292e1375535Schristos */
293e1375535Schristos np = getnetbyname(name);
29454a6ec8aSchristos #endif
295e1375535Schristos if (np != NULL)
296e1375535Schristos return np->n_net;
297e1375535Schristos else
298e1375535Schristos return 0;
299e1375535Schristos #endif /* _WIN32 */
30054a6ec8aSchristos }
30154a6ec8aSchristos
30254a6ec8aSchristos /*
30354a6ec8aSchristos * Convert a port name to its port and protocol numbers.
30454a6ec8aSchristos * We assume only TCP or UDP.
30554a6ec8aSchristos * Return 0 upon failure.
30654a6ec8aSchristos */
30754a6ec8aSchristos int
pcap_nametoport(const char * name,int * port,int * proto)30854a6ec8aSchristos pcap_nametoport(const char *name, int *port, int *proto)
30954a6ec8aSchristos {
310e1375535Schristos struct addrinfo hints, *res, *ai;
311e1375535Schristos int error;
312e1375535Schristos struct sockaddr_in *in4;
313e1375535Schristos #ifdef INET6
314e1375535Schristos struct sockaddr_in6 *in6;
315e1375535Schristos #endif
31654a6ec8aSchristos int tcp_port = -1;
31754a6ec8aSchristos int udp_port = -1;
31854a6ec8aSchristos
31954a6ec8aSchristos /*
320e1375535Schristos * We check for both TCP and UDP in case there are
321e1375535Schristos * ambiguous entries.
322e1375535Schristos */
323e1375535Schristos memset(&hints, 0, sizeof(hints));
324e1375535Schristos hints.ai_family = PF_UNSPEC;
325e1375535Schristos hints.ai_socktype = SOCK_STREAM;
326e1375535Schristos hints.ai_protocol = IPPROTO_TCP;
327e1375535Schristos error = getaddrinfo(NULL, name, &hints, &res);
328e1375535Schristos if (error != 0) {
329e1375535Schristos if (error != EAI_NONAME &&
330e1375535Schristos error != EAI_SERVICE) {
331e1375535Schristos /*
332e1375535Schristos * This is a real error, not just "there's
333e1375535Schristos * no such service name".
334e1375535Schristos * XXX - this doesn't return an error string.
335e1375535Schristos */
336e1375535Schristos return 0;
337e1375535Schristos }
338e1375535Schristos } else {
339e1375535Schristos /*
340e1375535Schristos * OK, we found it. Did it find anything?
341e1375535Schristos */
342e1375535Schristos for (ai = res; ai != NULL; ai = ai->ai_next) {
343e1375535Schristos /*
344e1375535Schristos * Does it have an address?
345e1375535Schristos */
346e1375535Schristos if (ai->ai_addr != NULL) {
347e1375535Schristos /*
348e1375535Schristos * Yes. Get a port number; we're done.
349e1375535Schristos */
350e1375535Schristos if (ai->ai_addr->sa_family == AF_INET) {
351e1375535Schristos in4 = (struct sockaddr_in *)ai->ai_addr;
352e1375535Schristos tcp_port = ntohs(in4->sin_port);
353e1375535Schristos break;
354e1375535Schristos }
355e1375535Schristos #ifdef INET6
356e1375535Schristos if (ai->ai_addr->sa_family == AF_INET6) {
357e1375535Schristos in6 = (struct sockaddr_in6 *)ai->ai_addr;
358e1375535Schristos tcp_port = ntohs(in6->sin6_port);
359e1375535Schristos break;
360e1375535Schristos }
361e1375535Schristos #endif
362e1375535Schristos }
363e1375535Schristos }
364e1375535Schristos freeaddrinfo(res);
365e1375535Schristos }
366e1375535Schristos
367e1375535Schristos memset(&hints, 0, sizeof(hints));
368e1375535Schristos hints.ai_family = PF_UNSPEC;
369e1375535Schristos hints.ai_socktype = SOCK_DGRAM;
370e1375535Schristos hints.ai_protocol = IPPROTO_UDP;
371e1375535Schristos error = getaddrinfo(NULL, name, &hints, &res);
372e1375535Schristos if (error != 0) {
373e1375535Schristos if (error != EAI_NONAME &&
374e1375535Schristos error != EAI_SERVICE) {
375e1375535Schristos /*
376e1375535Schristos * This is a real error, not just "there's
377e1375535Schristos * no such service name".
378e1375535Schristos * XXX - this doesn't return an error string.
379e1375535Schristos */
380e1375535Schristos return 0;
381e1375535Schristos }
382e1375535Schristos } else {
383e1375535Schristos /*
384e1375535Schristos * OK, we found it. Did it find anything?
385e1375535Schristos */
386e1375535Schristos for (ai = res; ai != NULL; ai = ai->ai_next) {
387e1375535Schristos /*
388e1375535Schristos * Does it have an address?
389e1375535Schristos */
390e1375535Schristos if (ai->ai_addr != NULL) {
391e1375535Schristos /*
392e1375535Schristos * Yes. Get a port number; we're done.
393e1375535Schristos */
394e1375535Schristos if (ai->ai_addr->sa_family == AF_INET) {
395e1375535Schristos in4 = (struct sockaddr_in *)ai->ai_addr;
396e1375535Schristos udp_port = ntohs(in4->sin_port);
397e1375535Schristos break;
398e1375535Schristos }
399e1375535Schristos #ifdef INET6
400e1375535Schristos if (ai->ai_addr->sa_family == AF_INET6) {
401e1375535Schristos in6 = (struct sockaddr_in6 *)ai->ai_addr;
402e1375535Schristos udp_port = ntohs(in6->sin6_port);
403e1375535Schristos break;
404e1375535Schristos }
405e1375535Schristos #endif
406e1375535Schristos }
407e1375535Schristos }
408e1375535Schristos freeaddrinfo(res);
409e1375535Schristos }
410e1375535Schristos
411e1375535Schristos /*
41254a6ec8aSchristos * We need to check /etc/services for ambiguous entries.
413e1375535Schristos * If we find an ambiguous entry, and it has the
41454a6ec8aSchristos * same port number, change the proto to PROTO_UNDEF
41554a6ec8aSchristos * so both TCP and UDP will be checked.
41654a6ec8aSchristos */
41754a6ec8aSchristos if (tcp_port >= 0) {
41854a6ec8aSchristos *port = tcp_port;
41954a6ec8aSchristos *proto = IPPROTO_TCP;
42054a6ec8aSchristos if (udp_port >= 0) {
42154a6ec8aSchristos if (udp_port == tcp_port)
42254a6ec8aSchristos *proto = PROTO_UNDEF;
42354a6ec8aSchristos #ifdef notdef
42454a6ec8aSchristos else
42554a6ec8aSchristos /* Can't handle ambiguous names that refer
42654a6ec8aSchristos to different port numbers. */
42754a6ec8aSchristos warning("ambiguous port %s in /etc/services",
42854a6ec8aSchristos name);
42954a6ec8aSchristos #endif
43054a6ec8aSchristos }
43154a6ec8aSchristos return 1;
43254a6ec8aSchristos }
43354a6ec8aSchristos if (udp_port >= 0) {
43454a6ec8aSchristos *port = udp_port;
43554a6ec8aSchristos *proto = IPPROTO_UDP;
43654a6ec8aSchristos return 1;
43754a6ec8aSchristos }
43854a6ec8aSchristos #if defined(ultrix) || defined(__osf__)
43954a6ec8aSchristos /* Special hack in case NFS isn't in /etc/services */
44054a6ec8aSchristos if (strcmp(name, "nfs") == 0) {
44154a6ec8aSchristos *port = 2049;
44254a6ec8aSchristos *proto = PROTO_UNDEF;
44354a6ec8aSchristos return 1;
44454a6ec8aSchristos }
44554a6ec8aSchristos #endif
44654a6ec8aSchristos return 0;
44754a6ec8aSchristos }
44854a6ec8aSchristos
44954a6ec8aSchristos /*
45054a6ec8aSchristos * Convert a string in the form PPP-PPP, where correspond to ports, to
45154a6ec8aSchristos * a starting and ending port in a port range.
45254a6ec8aSchristos * Return 0 on failure.
45354a6ec8aSchristos */
45454a6ec8aSchristos int
pcap_nametoportrange(const char * name,int * port1,int * port2,int * proto)45554a6ec8aSchristos pcap_nametoportrange(const char *name, int *port1, int *port2, int *proto)
45654a6ec8aSchristos {
45754a6ec8aSchristos u_int p1, p2;
45854a6ec8aSchristos char *off, *cpy;
45954a6ec8aSchristos int save_proto;
46054a6ec8aSchristos
46154a6ec8aSchristos if (sscanf(name, "%d-%d", &p1, &p2) != 2) {
46254a6ec8aSchristos if ((cpy = strdup(name)) == NULL)
46354a6ec8aSchristos return 0;
46454a6ec8aSchristos
46554a6ec8aSchristos if ((off = strchr(cpy, '-')) == NULL) {
46654a6ec8aSchristos free(cpy);
46754a6ec8aSchristos return 0;
46854a6ec8aSchristos }
46954a6ec8aSchristos
47054a6ec8aSchristos *off = '\0';
47154a6ec8aSchristos
47254a6ec8aSchristos if (pcap_nametoport(cpy, port1, proto) == 0) {
47354a6ec8aSchristos free(cpy);
47454a6ec8aSchristos return 0;
47554a6ec8aSchristos }
47654a6ec8aSchristos save_proto = *proto;
47754a6ec8aSchristos
47854a6ec8aSchristos if (pcap_nametoport(off + 1, port2, proto) == 0) {
47954a6ec8aSchristos free(cpy);
48054a6ec8aSchristos return 0;
48154a6ec8aSchristos }
482c15d5effSchristos free(cpy);
48354a6ec8aSchristos
48454a6ec8aSchristos if (*proto != save_proto)
48554a6ec8aSchristos *proto = PROTO_UNDEF;
48654a6ec8aSchristos } else {
48754a6ec8aSchristos *port1 = p1;
48854a6ec8aSchristos *port2 = p2;
48954a6ec8aSchristos *proto = PROTO_UNDEF;
49054a6ec8aSchristos }
49154a6ec8aSchristos
49254a6ec8aSchristos return 1;
49354a6ec8aSchristos }
49454a6ec8aSchristos
495e1375535Schristos /*
496e1375535Schristos * XXX - not guaranteed to be thread-safe! See below for platforms
497e1375535Schristos * on which it is thread-safe and on which it isn't.
498e1375535Schristos */
49954a6ec8aSchristos int
pcap_nametoproto(const char * str)50054a6ec8aSchristos pcap_nametoproto(const char *str)
50154a6ec8aSchristos {
50254a6ec8aSchristos struct protoent *p;
503e1375535Schristos #if defined(HAVE_LINUX_GETNETBYNAME_R)
504e1375535Schristos /*
505e1375535Schristos * We have Linux's reentrant getprotobyname_r().
506e1375535Schristos */
507e1375535Schristos struct protoent result_buf;
508e1375535Schristos char buf[1024]; /* arbitrary size */
509e1375535Schristos int err;
51054a6ec8aSchristos
511e1375535Schristos err = getprotobyname_r(str, &result_buf, buf, sizeof buf, &p);
512e1375535Schristos if (err != 0) {
513e1375535Schristos /*
514e1375535Schristos * XXX - dynamically allocate the buffer, and make it
515e1375535Schristos * bigger if we get ERANGE back?
516e1375535Schristos */
517e1375535Schristos return 0;
518e1375535Schristos }
519e1375535Schristos #elif defined(HAVE_SOLARIS_IRIX_GETNETBYNAME_R)
520e1375535Schristos /*
521e1375535Schristos * We have Solaris's and IRIX's reentrant getprotobyname_r().
522e1375535Schristos */
523e1375535Schristos struct protoent result_buf;
524e1375535Schristos char buf[1024]; /* arbitrary size */
525e1375535Schristos
526e1375535Schristos p = getprotobyname_r(str, &result_buf, buf, (int)sizeof buf);
527e1375535Schristos #elif defined(HAVE_AIX_GETNETBYNAME_R)
528e1375535Schristos /*
529e1375535Schristos * We have AIX's reentrant getprotobyname_r().
530e1375535Schristos */
531e1375535Schristos struct protoent result_buf;
532e1375535Schristos struct protoent_data proto_data;
533e1375535Schristos
534e1375535Schristos if (getprotobyname_r(str, &result_buf, &proto_data) == -1)
535e1375535Schristos p = NULL;
536e1375535Schristos else
537e1375535Schristos p = &result_buf;
538e1375535Schristos #else
539e1375535Schristos /*
540e1375535Schristos * We don't have any getprotobyname_r(); either we have a
541e1375535Schristos * getprotobyname() that uses thread-specific data, in which
542e1375535Schristos * case we're thread-safe (sufficiently recent FreeBSD,
543e1375535Schristos * sufficiently recent Darwin-based OS, sufficiently recent
544e1375535Schristos * HP-UX, sufficiently recent Tru64 UNIX, Windows), or we have
545e1375535Schristos * the traditional getprotobyname() (everything else, including
546e1375535Schristos * current NetBSD and OpenBSD), in which case we're not
547e1375535Schristos * thread-safe.
548e1375535Schristos */
54954a6ec8aSchristos p = getprotobyname(str);
550e1375535Schristos #endif
55154a6ec8aSchristos if (p != 0)
55254a6ec8aSchristos return p->p_proto;
55354a6ec8aSchristos else
55454a6ec8aSchristos return PROTO_UNDEF;
55554a6ec8aSchristos }
55654a6ec8aSchristos
55754a6ec8aSchristos #include "ethertype.h"
55854a6ec8aSchristos
55954a6ec8aSchristos struct eproto {
56054a6ec8aSchristos const char *s;
56154a6ec8aSchristos u_short p;
56254a6ec8aSchristos };
56354a6ec8aSchristos
56403e25b48Schristos /*
56503e25b48Schristos * Static data base of ether protocol types.
56603e25b48Schristos * tcpdump used to import this, and it's declared as an export on
56703e25b48Schristos * Debian, at least, so make it a public symbol, even though we
56803e25b48Schristos * don't officially export it by declaring it in a header file.
56903e25b48Schristos * (Programs *should* do this themselves, as tcpdump now does.)
570e1375535Schristos *
571e1375535Schristos * We declare it here, right before defining it, to squelch any
572e1375535Schristos * warnings we might get from compilers about the lack of a
573e1375535Schristos * declaration.
57403e25b48Schristos */
575e1375535Schristos PCAP_API struct eproto eproto_db[];
57603e25b48Schristos PCAP_API_DEF struct eproto eproto_db[] = {
57754a6ec8aSchristos { "pup", ETHERTYPE_PUP },
57854a6ec8aSchristos { "xns", ETHERTYPE_NS },
57954a6ec8aSchristos { "ip", ETHERTYPE_IP },
58054a6ec8aSchristos #ifdef INET6
58154a6ec8aSchristos { "ip6", ETHERTYPE_IPV6 },
58254a6ec8aSchristos #endif
58354a6ec8aSchristos { "arp", ETHERTYPE_ARP },
58454a6ec8aSchristos { "rarp", ETHERTYPE_REVARP },
58554a6ec8aSchristos { "sprite", ETHERTYPE_SPRITE },
58654a6ec8aSchristos { "mopdl", ETHERTYPE_MOPDL },
58754a6ec8aSchristos { "moprc", ETHERTYPE_MOPRC },
58854a6ec8aSchristos { "decnet", ETHERTYPE_DN },
58954a6ec8aSchristos { "lat", ETHERTYPE_LAT },
59054a6ec8aSchristos { "sca", ETHERTYPE_SCA },
59154a6ec8aSchristos { "lanbridge", ETHERTYPE_LANBRIDGE },
59254a6ec8aSchristos { "vexp", ETHERTYPE_VEXP },
59354a6ec8aSchristos { "vprod", ETHERTYPE_VPROD },
59454a6ec8aSchristos { "atalk", ETHERTYPE_ATALK },
59554a6ec8aSchristos { "atalkarp", ETHERTYPE_AARP },
59654a6ec8aSchristos { "loopback", ETHERTYPE_LOOPBACK },
59754a6ec8aSchristos { "decdts", ETHERTYPE_DECDTS },
59854a6ec8aSchristos { "decdns", ETHERTYPE_DECDNS },
59954a6ec8aSchristos { (char *)0, 0 }
60054a6ec8aSchristos };
60154a6ec8aSchristos
60254a6ec8aSchristos int
pcap_nametoeproto(const char * s)60354a6ec8aSchristos pcap_nametoeproto(const char *s)
60454a6ec8aSchristos {
60554a6ec8aSchristos struct eproto *p = eproto_db;
60654a6ec8aSchristos
60754a6ec8aSchristos while (p->s != 0) {
60854a6ec8aSchristos if (strcmp(p->s, s) == 0)
60954a6ec8aSchristos return p->p;
61054a6ec8aSchristos p += 1;
61154a6ec8aSchristos }
61254a6ec8aSchristos return PROTO_UNDEF;
61354a6ec8aSchristos }
61454a6ec8aSchristos
61554a6ec8aSchristos #include "llc.h"
61654a6ec8aSchristos
61754a6ec8aSchristos /* Static data base of LLC values. */
61854a6ec8aSchristos static struct eproto llc_db[] = {
61954a6ec8aSchristos { "iso", LLCSAP_ISONS },
62054a6ec8aSchristos { "stp", LLCSAP_8021D },
62154a6ec8aSchristos { "ipx", LLCSAP_IPX },
62254a6ec8aSchristos { "netbeui", LLCSAP_NETBEUI },
62354a6ec8aSchristos { (char *)0, 0 }
62454a6ec8aSchristos };
62554a6ec8aSchristos
62654a6ec8aSchristos int
pcap_nametollc(const char * s)62754a6ec8aSchristos pcap_nametollc(const char *s)
62854a6ec8aSchristos {
62954a6ec8aSchristos struct eproto *p = llc_db;
63054a6ec8aSchristos
63154a6ec8aSchristos while (p->s != 0) {
63254a6ec8aSchristos if (strcmp(p->s, s) == 0)
63354a6ec8aSchristos return p->p;
63454a6ec8aSchristos p += 1;
63554a6ec8aSchristos }
63654a6ec8aSchristos return PROTO_UNDEF;
63754a6ec8aSchristos }
63854a6ec8aSchristos
639e1375535Schristos /* Hex digit to 8-bit unsigned integer. */
640e1375535Schristos static inline u_char
xdtoi(u_char c)641e1375535Schristos xdtoi(u_char c)
64254a6ec8aSchristos {
64354a6ec8aSchristos if (isdigit(c))
644e1375535Schristos return (u_char)(c - '0');
64554a6ec8aSchristos else if (islower(c))
646e1375535Schristos return (u_char)(c - 'a' + 10);
64754a6ec8aSchristos else
648e1375535Schristos return (u_char)(c - 'A' + 10);
64954a6ec8aSchristos }
65054a6ec8aSchristos
65154a6ec8aSchristos int
__pcap_atoin(const char * s,bpf_u_int32 * addr)65254a6ec8aSchristos __pcap_atoin(const char *s, bpf_u_int32 *addr)
65354a6ec8aSchristos {
65454a6ec8aSchristos u_int n;
65554a6ec8aSchristos int len;
65654a6ec8aSchristos
65754a6ec8aSchristos *addr = 0;
65854a6ec8aSchristos len = 0;
659e1375535Schristos for (;;) {
66054a6ec8aSchristos n = 0;
66154a6ec8aSchristos while (*s && *s != '.')
66254a6ec8aSchristos n = n * 10 + *s++ - '0';
66354a6ec8aSchristos *addr <<= 8;
66454a6ec8aSchristos *addr |= n & 0xff;
66554a6ec8aSchristos len += 8;
66654a6ec8aSchristos if (*s == '\0')
66754a6ec8aSchristos return len;
66854a6ec8aSchristos ++s;
66954a6ec8aSchristos }
67054a6ec8aSchristos /* NOTREACHED */
67154a6ec8aSchristos }
67254a6ec8aSchristos
67354a6ec8aSchristos int
__pcap_atodn(const char * s,bpf_u_int32 * addr)67454a6ec8aSchristos __pcap_atodn(const char *s, bpf_u_int32 *addr)
67554a6ec8aSchristos {
67654a6ec8aSchristos #define AREASHIFT 10
67754a6ec8aSchristos #define AREAMASK 0176000
67854a6ec8aSchristos #define NODEMASK 01777
67954a6ec8aSchristos
68054a6ec8aSchristos u_int node, area;
68154a6ec8aSchristos
68254a6ec8aSchristos if (sscanf(s, "%d.%d", &area, &node) != 2)
68303e25b48Schristos return(0);
68454a6ec8aSchristos
68554a6ec8aSchristos *addr = (area << AREASHIFT) & AREAMASK;
68654a6ec8aSchristos *addr |= (node & NODEMASK);
68754a6ec8aSchristos
68854a6ec8aSchristos return(32);
68954a6ec8aSchristos }
69054a6ec8aSchristos
69154a6ec8aSchristos /*
69254a6ec8aSchristos * Convert 's', which can have the one of the forms:
69354a6ec8aSchristos *
69454a6ec8aSchristos * "xx:xx:xx:xx:xx:xx"
69554a6ec8aSchristos * "xx.xx.xx.xx.xx.xx"
69654a6ec8aSchristos * "xx-xx-xx-xx-xx-xx"
69754a6ec8aSchristos * "xxxx.xxxx.xxxx"
69854a6ec8aSchristos * "xxxxxxxxxxxx"
69954a6ec8aSchristos *
70054a6ec8aSchristos * (or various mixes of ':', '.', and '-') into a new
70154a6ec8aSchristos * ethernet address. Assumes 's' is well formed.
70254a6ec8aSchristos */
70354a6ec8aSchristos u_char *
pcap_ether_aton(const char * s)70454a6ec8aSchristos pcap_ether_aton(const char *s)
70554a6ec8aSchristos {
70654a6ec8aSchristos register u_char *ep, *e;
707e1375535Schristos register u_char d;
70854a6ec8aSchristos
70954a6ec8aSchristos e = ep = (u_char *)malloc(6);
710c15d5effSchristos if (e == NULL)
711c15d5effSchristos return (NULL);
71254a6ec8aSchristos
71354a6ec8aSchristos while (*s) {
71454a6ec8aSchristos if (*s == ':' || *s == '.' || *s == '-')
71554a6ec8aSchristos s += 1;
71654a6ec8aSchristos d = xdtoi(*s++);
71754a6ec8aSchristos if (isxdigit((unsigned char)*s)) {
71854a6ec8aSchristos d <<= 4;
71954a6ec8aSchristos d |= xdtoi(*s++);
72054a6ec8aSchristos }
72154a6ec8aSchristos *ep++ = d;
72254a6ec8aSchristos }
72354a6ec8aSchristos
72454a6ec8aSchristos return (e);
72554a6ec8aSchristos }
72654a6ec8aSchristos
72754a6ec8aSchristos #ifndef HAVE_ETHER_HOSTTON
728e1375535Schristos /*
729e1375535Schristos * Roll our own.
730e1375535Schristos * XXX - not thread-safe, because pcap_next_etherent() isn't thread-
731e1375535Schristos * safe! Needs a mutex or a thread-safe pcap_next_etherent().
732e1375535Schristos */
73354a6ec8aSchristos u_char *
pcap_ether_hostton(const char * name)73454a6ec8aSchristos pcap_ether_hostton(const char *name)
73554a6ec8aSchristos {
73654a6ec8aSchristos register struct pcap_etherent *ep;
73754a6ec8aSchristos register u_char *ap;
73854a6ec8aSchristos static FILE *fp = NULL;
73954a6ec8aSchristos static int init = 0;
74054a6ec8aSchristos
74154a6ec8aSchristos if (!init) {
74254a6ec8aSchristos fp = fopen(PCAP_ETHERS_FILE, "r");
74354a6ec8aSchristos ++init;
74454a6ec8aSchristos if (fp == NULL)
74554a6ec8aSchristos return (NULL);
74654a6ec8aSchristos } else if (fp == NULL)
74754a6ec8aSchristos return (NULL);
74854a6ec8aSchristos else
74954a6ec8aSchristos rewind(fp);
75054a6ec8aSchristos
75154a6ec8aSchristos while ((ep = pcap_next_etherent(fp)) != NULL) {
75254a6ec8aSchristos if (strcmp(ep->name, name) == 0) {
75354a6ec8aSchristos ap = (u_char *)malloc(6);
75454a6ec8aSchristos if (ap != NULL) {
75554a6ec8aSchristos memcpy(ap, ep->addr, 6);
75654a6ec8aSchristos return (ap);
75754a6ec8aSchristos }
75854a6ec8aSchristos break;
75954a6ec8aSchristos }
76054a6ec8aSchristos }
76154a6ec8aSchristos return (NULL);
76254a6ec8aSchristos }
76354a6ec8aSchristos #else
764e1375535Schristos /*
765e1375535Schristos * Use the OS-supplied routine.
766e1375535Schristos * This *should* be thread-safe; the API doesn't have a static buffer.
767e1375535Schristos */
76854a6ec8aSchristos u_char *
pcap_ether_hostton(const char * name)76954a6ec8aSchristos pcap_ether_hostton(const char *name)
77054a6ec8aSchristos {
77154a6ec8aSchristos register u_char *ap;
77254a6ec8aSchristos u_char a[6];
77354a6ec8aSchristos
77454a6ec8aSchristos ap = NULL;
77554a6ec8aSchristos if (ether_hostton(name, (struct ether_addr *)a) == 0) {
77654a6ec8aSchristos ap = (u_char *)malloc(6);
77754a6ec8aSchristos if (ap != NULL)
77854a6ec8aSchristos memcpy((char *)ap, (char *)a, 6);
77954a6ec8aSchristos }
78054a6ec8aSchristos return (ap);
78154a6ec8aSchristos }
78254a6ec8aSchristos #endif
78354a6ec8aSchristos
784e1375535Schristos /*
785e1375535Schristos * XXX - not guaranteed to be thread-safe!
786e1375535Schristos */
78703e25b48Schristos int
788e1375535Schristos #ifdef DECNETLIB
__pcap_nametodnaddr(const char * name,u_short * res)78903e25b48Schristos __pcap_nametodnaddr(const char *name, u_short *res)
79054a6ec8aSchristos {
79154a6ec8aSchristos struct nodeent *getnodebyname();
79254a6ec8aSchristos struct nodeent *nep;
79354a6ec8aSchristos
79454a6ec8aSchristos nep = getnodebyname(name);
79554a6ec8aSchristos if (nep == ((struct nodeent *)0))
79603e25b48Schristos return(0);
79754a6ec8aSchristos
79803e25b48Schristos memcpy((char *)res, (char *)nep->n_addr, sizeof(unsigned short));
79903e25b48Schristos return(1);
80054a6ec8aSchristos #else
801e1375535Schristos __pcap_nametodnaddr(const char *name _U_, u_short *res _U_)
802e1375535Schristos {
80354a6ec8aSchristos return(0);
80454a6ec8aSchristos #endif
80554a6ec8aSchristos }
806