1335640Shselasky/*
2335640Shselasky * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998
3335640Shselasky *	The Regents of the University of California.  All rights reserved.
4335640Shselasky *
5335640Shselasky * Redistribution and use in source and binary forms, with or without
6335640Shselasky * modification, are permitted provided that: (1) source code distributions
7335640Shselasky * retain the above copyright notice and this paragraph in its entirety, (2)
8335640Shselasky * distributions including binary code include the above copyright notice and
9335640Shselasky * this paragraph in its entirety in the documentation or other materials
10335640Shselasky * provided with the distribution, and (3) all advertising materials mentioning
11335640Shselasky * features or use of this software display the following acknowledgement:
12335640Shselasky * ``This product includes software developed by the University of California,
13335640Shselasky * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14335640Shselasky * the University nor the names of its contributors may be used to endorse
15335640Shselasky * or promote products derived from this software without specific prior
16335640Shselasky * written permission.
17335640Shselasky * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18335640Shselasky * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19335640Shselasky * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20335640Shselasky *
21335640Shselasky * Name to id translation routines used by the scanner.
22335640Shselasky * These functions are not time critical.
23335640Shselasky */
24335640Shselasky
25335640Shselasky#ifdef HAVE_CONFIG_H
26335640Shselasky#include <config.h>
27335640Shselasky#endif
28335640Shselasky
29335640Shselasky#ifdef DECNETLIB
30335640Shselasky#include <sys/types.h>
31335640Shselasky#include <netdnet/dnetdb.h>
32335640Shselasky#endif
33335640Shselasky
34335640Shselasky#ifdef _WIN32
35335640Shselasky  #include <winsock2.h>
36335640Shselasky  #include <ws2tcpip.h>
37335640Shselasky
38335640Shselasky  #ifdef INET6
39335640Shselasky    /*
40335640Shselasky     * To quote the MSDN page for getaddrinfo() at
41335640Shselasky     *
42335640Shselasky     *    https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520(v=vs.85).aspx
43335640Shselasky     *
44335640Shselasky     * "Support for getaddrinfo on Windows 2000 and older versions
45335640Shselasky     * The getaddrinfo function was added to the Ws2_32.dll on Windows XP and
46335640Shselasky     * later. To execute an application that uses this function on earlier
47335640Shselasky     * versions of Windows, then you need to include the Ws2tcpip.h and
48335640Shselasky     * Wspiapi.h files. When the Wspiapi.h include file is added, the
49335640Shselasky     * getaddrinfo function is defined to the WspiapiGetAddrInfo inline
50335640Shselasky     * function in the Wspiapi.h file. At runtime, the WspiapiGetAddrInfo
51335640Shselasky     * function is implemented in such a way that if the Ws2_32.dll or the
52335640Shselasky     * Wship6.dll (the file containing getaddrinfo in the IPv6 Technology
53335640Shselasky     * Preview for Windows 2000) does not include getaddrinfo, then a
54335640Shselasky     * version of getaddrinfo is implemented inline based on code in the
55335640Shselasky     * Wspiapi.h header file. This inline code will be used on older Windows
56335640Shselasky     * platforms that do not natively support the getaddrinfo function."
57335640Shselasky     *
58335640Shselasky     * We use getaddrinfo(), so we include Wspiapi.h here.
59335640Shselasky     */
60335640Shselasky    #include <wspiapi.h>
61335640Shselasky  #endif /* INET6 */
62335640Shselasky#else /* _WIN32 */
63335640Shselasky  #include <sys/param.h>
64335640Shselasky  #include <sys/types.h>
65335640Shselasky  #include <sys/socket.h>
66335640Shselasky  #include <sys/time.h>
67335640Shselasky
68335640Shselasky  #include <netinet/in.h>
69335640Shselasky
70335640Shselasky  #ifdef HAVE_ETHER_HOSTTON
71335640Shselasky    #if defined(NET_ETHERNET_H_DECLARES_ETHER_HOSTTON)
72335640Shselasky      /*
73335640Shselasky       * OK, just include <net/ethernet.h>.
74335640Shselasky       */
75335640Shselasky      #include <net/ethernet.h>
76335640Shselasky    #elif defined(NETINET_ETHER_H_DECLARES_ETHER_HOSTTON)
77335640Shselasky      /*
78335640Shselasky       * OK, just include <netinet/ether.h>
79335640Shselasky       */
80335640Shselasky      #include <netinet/ether.h>
81335640Shselasky    #elif defined(SYS_ETHERNET_H_DECLARES_ETHER_HOSTTON)
82335640Shselasky      /*
83335640Shselasky       * OK, just include <sys/ethernet.h>
84335640Shselasky       */
85335640Shselasky      #include <sys/ethernet.h>
86335640Shselasky    #elif defined(ARPA_INET_H_DECLARES_ETHER_HOSTTON)
87335640Shselasky      /*
88335640Shselasky       * OK, just include <arpa/inet.h>
89335640Shselasky       */
90335640Shselasky      #include <arpa/inet.h>
91335640Shselasky    #elif defined(NETINET_IF_ETHER_H_DECLARES_ETHER_HOSTTON)
92335640Shselasky      /*
93335640Shselasky       * OK, include <netinet/if_ether.h>, after all the other stuff we
94335640Shselasky       * need to include or define for its benefit.
95335640Shselasky       */
96335640Shselasky      #define NEED_NETINET_IF_ETHER_H
97335640Shselasky    #else
98335640Shselasky      /*
99335640Shselasky       * We'll have to declare it ourselves.
100335640Shselasky       * If <netinet/if_ether.h> defines struct ether_addr, include
101335640Shselasky       * it.  Otherwise, define it ourselves.
102335640Shselasky       */
103335640Shselasky      #ifdef HAVE_STRUCT_ETHER_ADDR
104335640Shselasky        #define NEED_NETINET_IF_ETHER_H
105335640Shselasky      #else /* HAVE_STRUCT_ETHER_ADDR */
106335640Shselasky	struct ether_addr {
107335640Shselasky		unsigned char ether_addr_octet[6];
108335640Shselasky	};
109335640Shselasky      #endif /* HAVE_STRUCT_ETHER_ADDR */
110335640Shselasky    #endif /* what declares ether_hostton() */
111335640Shselasky
112335640Shselasky    #ifdef NEED_NETINET_IF_ETHER_H
113335640Shselasky      #include <net/if.h>	/* Needed on some platforms */
114335640Shselasky      #include <netinet/in.h>	/* Needed on some platforms */
115335640Shselasky      #include <netinet/if_ether.h>
116335640Shselasky    #endif /* NEED_NETINET_IF_ETHER_H */
117335640Shselasky
118335640Shselasky    #ifndef HAVE_DECL_ETHER_HOSTTON
119335640Shselasky      /*
120335640Shselasky       * No header declares it, so declare it ourselves.
121335640Shselasky       */
122335640Shselasky      extern int ether_hostton(const char *, struct ether_addr *);
123335640Shselasky    #endif /* !defined(HAVE_DECL_ETHER_HOSTTON) */
124335640Shselasky  #endif /* HAVE_ETHER_HOSTTON */
125335640Shselasky
126335640Shselasky  #include <arpa/inet.h>
127335640Shselasky  #include <netdb.h>
128335640Shselasky#endif /* _WIN32 */
129335640Shselasky
130335640Shselasky#include <ctype.h>
131335640Shselasky#include <errno.h>
132335640Shselasky#include <stdlib.h>
133335640Shselasky#include <string.h>
134335640Shselasky#include <stdio.h>
135335640Shselasky
136335640Shselasky#include "pcap-int.h"
137335640Shselasky
138335640Shselasky#include "gencode.h"
139335640Shselasky#include <pcap/namedb.h>
140335640Shselasky#include "nametoaddr.h"
141335640Shselasky
142335640Shselasky#ifdef HAVE_OS_PROTO_H
143335640Shselasky#include "os-proto.h"
144335640Shselasky#endif
145335640Shselasky
146335640Shselasky#ifndef NTOHL
147335640Shselasky#define NTOHL(x) (x) = ntohl(x)
148335640Shselasky#define NTOHS(x) (x) = ntohs(x)
149335640Shselasky#endif
150335640Shselasky
151335640Shselasky/*
152335640Shselasky *  Convert host name to internet address.
153335640Shselasky *  Return 0 upon failure.
154335640Shselasky *  XXX - not thread-safe; don't use it inside libpcap.
155335640Shselasky */
156335640Shselaskybpf_u_int32 **
157335640Shselaskypcap_nametoaddr(const char *name)
158335640Shselasky{
159335640Shselasky#ifndef h_addr
160335640Shselasky	static bpf_u_int32 *hlist[2];
161335640Shselasky#endif
162335640Shselasky	bpf_u_int32 **p;
163335640Shselasky	struct hostent *hp;
164335640Shselasky
165335640Shselasky	if ((hp = gethostbyname(name)) != NULL) {
166335640Shselasky#ifndef h_addr
167335640Shselasky		hlist[0] = (bpf_u_int32 *)hp->h_addr;
168335640Shselasky		NTOHL(hp->h_addr);
169335640Shselasky		return hlist;
170335640Shselasky#else
171335640Shselasky		for (p = (bpf_u_int32 **)hp->h_addr_list; *p; ++p)
172335640Shselasky			NTOHL(**p);
173335640Shselasky		return (bpf_u_int32 **)hp->h_addr_list;
174335640Shselasky#endif
175335640Shselasky	}
176335640Shselasky	else
177335640Shselasky		return 0;
178335640Shselasky}
179335640Shselasky
180335640Shselaskystruct addrinfo *
181335640Shselaskypcap_nametoaddrinfo(const char *name)
182335640Shselasky{
183335640Shselasky	struct addrinfo hints, *res;
184335640Shselasky	int error;
185335640Shselasky
186335640Shselasky	memset(&hints, 0, sizeof(hints));
187335640Shselasky	hints.ai_family = PF_UNSPEC;
188335640Shselasky	hints.ai_socktype = SOCK_STREAM;	/*not really*/
189335640Shselasky	hints.ai_protocol = IPPROTO_TCP;	/*not really*/
190335640Shselasky	error = getaddrinfo(name, NULL, &hints, &res);
191335640Shselasky	if (error)
192335640Shselasky		return NULL;
193335640Shselasky	else
194335640Shselasky		return res;
195335640Shselasky}
196335640Shselasky
197335640Shselasky/*
198335640Shselasky *  Convert net name to internet address.
199335640Shselasky *  Return 0 upon failure.
200335640Shselasky *  XXX - not guaranteed to be thread-safe!  See below for platforms
201335640Shselasky *  on which it is thread-safe and on which it isn't.
202335640Shselasky */
203335640Shselaskybpf_u_int32
204335640Shselaskypcap_nametonetaddr(const char *name)
205335640Shselasky{
206335640Shselasky#ifdef _WIN32
207335640Shselasky	/*
208335640Shselasky	 * There's no "getnetbyname()" on Windows.
209335640Shselasky	 *
210335640Shselasky	 * XXX - I guess we could use the BSD code to read
211335640Shselasky	 * C:\Windows\System32\drivers\etc/networks, assuming
212335640Shselasky	 * that's its home on all the versions of Windows
213335640Shselasky	 * we use, but that file probably just has the loopback
214335640Shselasky	 * network on 127/24 on 99 44/100% of Windows machines.
215335640Shselasky	 *
216335640Shselasky	 * (Heck, these days it probably just has that on 99 44/100%
217335640Shselasky	 * of *UN*X* machines.)
218335640Shselasky	 */
219335640Shselasky	return 0;
220335640Shselasky#else
221335640Shselasky	/*
222335640Shselasky	 * UN*X.
223335640Shselasky	 */
224335640Shselasky	struct netent *np;
225335640Shselasky  #if defined(HAVE_LINUX_GETNETBYNAME_R)
226335640Shselasky	/*
227335640Shselasky	 * We have Linux's reentrant getnetbyname_r().
228335640Shselasky	 */
229335640Shselasky	struct netent result_buf;
230335640Shselasky	char buf[1024];	/* arbitrary size */
231335640Shselasky	int h_errnoval;
232335640Shselasky	int err;
233335640Shselasky
234356341Scy	/*
235356341Scy	 * Apparently, the man page at
236356341Scy	 *
237356341Scy	 *    http://man7.org/linux/man-pages/man3/getnetbyname_r.3.html
238356341Scy	 *
239356341Scy	 * lies when it says
240356341Scy	 *
241356341Scy	 *    If the function call successfully obtains a network record,
242356341Scy	 *    then *result is set pointing to result_buf; otherwise, *result
243356341Scy	 *    is set to NULL.
244356341Scy	 *
245356341Scy	 * and, in fact, at least in some versions of GNU libc, it does
246356341Scy	 * *not* always get set if getnetbyname_r() succeeds.
247356341Scy	 */
248356341Scy	np = NULL;
249356341Scy 	err = getnetbyname_r(name, &result_buf, buf, sizeof buf, &np,
250335640Shselasky	    &h_errnoval);
251335640Shselasky	if (err != 0) {
252335640Shselasky		/*
253335640Shselasky		 * XXX - dynamically allocate the buffer, and make it
254335640Shselasky		 * bigger if we get ERANGE back?
255335640Shselasky		 */
256335640Shselasky		return 0;
257335640Shselasky	}
258335640Shselasky  #elif defined(HAVE_SOLARIS_IRIX_GETNETBYNAME_R)
259335640Shselasky	/*
260335640Shselasky	 * We have Solaris's and IRIX's reentrant getnetbyname_r().
261335640Shselasky	 */
262335640Shselasky	struct netent result_buf;
263335640Shselasky	char buf[1024];	/* arbitrary size */
264335640Shselasky
265335640Shselasky	np = getnetbyname_r(name, &result_buf, buf, (int)sizeof buf);
266335640Shselasky  #elif defined(HAVE_AIX_GETNETBYNAME_R)
267335640Shselasky	/*
268335640Shselasky	 * We have AIX's reentrant getnetbyname_r().
269335640Shselasky	 */
270335640Shselasky	struct netent result_buf;
271335640Shselasky	struct netent_data net_data;
272335640Shselasky
273335640Shselasky	if (getnetbyname_r(name, &result_buf, &net_data) == -1)
274335640Shselasky		np = NULL;
275335640Shselasky	else
276335640Shselasky		np = &result_buf;
277335640Shselasky  #else
278335640Shselasky 	/*
279335640Shselasky 	 * We don't have any getnetbyname_r(); either we have a
280335640Shselasky 	 * getnetbyname() that uses thread-specific data, in which
281335640Shselasky 	 * case we're thread-safe (sufficiently recent FreeBSD,
282335640Shselasky 	 * sufficiently recent Darwin-based OS, sufficiently recent
283335640Shselasky 	 * HP-UX, sufficiently recent Tru64 UNIX), or we have the
284335640Shselasky 	 * traditional getnetbyname() (everything else, including
285335640Shselasky 	 * current NetBSD and OpenBSD), in which case we're not
286335640Shselasky 	 * thread-safe.
287335640Shselasky 	 */
288335640Shselasky	np = getnetbyname(name);
289335640Shselasky  #endif
290335640Shselasky	if (np != NULL)
291335640Shselasky		return np->n_net;
292335640Shselasky	else
293335640Shselasky		return 0;
294335640Shselasky#endif /* _WIN32 */
295335640Shselasky}
296335640Shselasky
297335640Shselasky/*
298335640Shselasky * Convert a port name to its port and protocol numbers.
299335640Shselasky * We assume only TCP or UDP.
300335640Shselasky * Return 0 upon failure.
301335640Shselasky */
302335640Shselaskyint
303335640Shselaskypcap_nametoport(const char *name, int *port, int *proto)
304335640Shselasky{
305335640Shselasky	struct addrinfo hints, *res, *ai;
306335640Shselasky	int error;
307335640Shselasky	struct sockaddr_in *in4;
308335640Shselasky#ifdef INET6
309335640Shselasky	struct sockaddr_in6 *in6;
310335640Shselasky#endif
311335640Shselasky	int tcp_port = -1;
312335640Shselasky	int udp_port = -1;
313335640Shselasky
314335640Shselasky	/*
315335640Shselasky	 * We check for both TCP and UDP in case there are
316335640Shselasky	 * ambiguous entries.
317335640Shselasky	 */
318335640Shselasky	memset(&hints, 0, sizeof(hints));
319335640Shselasky	hints.ai_family = PF_UNSPEC;
320335640Shselasky	hints.ai_socktype = SOCK_STREAM;
321335640Shselasky	hints.ai_protocol = IPPROTO_TCP;
322335640Shselasky	error = getaddrinfo(NULL, name, &hints, &res);
323335640Shselasky	if (error != 0) {
324356341Scy		if (error != EAI_NONAME &&
325356341Scy		    error != EAI_SERVICE) {
326335640Shselasky			/*
327335640Shselasky			 * This is a real error, not just "there's
328335640Shselasky			 * no such service name".
329335640Shselasky			 * XXX - this doesn't return an error string.
330335640Shselasky			 */
331335640Shselasky			return 0;
332335640Shselasky		}
333335640Shselasky	} else {
334335640Shselasky		/*
335335640Shselasky		 * OK, we found it.  Did it find anything?
336335640Shselasky		 */
337335640Shselasky		for (ai = res; ai != NULL; ai = ai->ai_next) {
338335640Shselasky			/*
339335640Shselasky			 * Does it have an address?
340335640Shselasky			 */
341335640Shselasky			if (ai->ai_addr != NULL) {
342335640Shselasky				/*
343335640Shselasky				 * Yes.  Get a port number; we're done.
344335640Shselasky				 */
345335640Shselasky				if (ai->ai_addr->sa_family == AF_INET) {
346335640Shselasky					in4 = (struct sockaddr_in *)ai->ai_addr;
347335640Shselasky					tcp_port = ntohs(in4->sin_port);
348335640Shselasky					break;
349335640Shselasky				}
350335640Shselasky#ifdef INET6
351335640Shselasky				if (ai->ai_addr->sa_family == AF_INET6) {
352335640Shselasky					in6 = (struct sockaddr_in6 *)ai->ai_addr;
353335640Shselasky					tcp_port = ntohs(in6->sin6_port);
354335640Shselasky					break;
355335640Shselasky				}
356335640Shselasky#endif
357335640Shselasky			}
358335640Shselasky		}
359335640Shselasky		freeaddrinfo(res);
360335640Shselasky	}
361335640Shselasky
362335640Shselasky	memset(&hints, 0, sizeof(hints));
363335640Shselasky	hints.ai_family = PF_UNSPEC;
364335640Shselasky	hints.ai_socktype = SOCK_DGRAM;
365335640Shselasky	hints.ai_protocol = IPPROTO_UDP;
366335640Shselasky	error = getaddrinfo(NULL, name, &hints, &res);
367335640Shselasky	if (error != 0) {
368356341Scy		if (error != EAI_NONAME &&
369356341Scy		    error != EAI_SERVICE) {
370335640Shselasky			/*
371335640Shselasky			 * This is a real error, not just "there's
372335640Shselasky			 * no such service name".
373335640Shselasky			 * XXX - this doesn't return an error string.
374335640Shselasky			 */
375335640Shselasky			return 0;
376335640Shselasky		}
377335640Shselasky	} else {
378335640Shselasky		/*
379335640Shselasky		 * OK, we found it.  Did it find anything?
380335640Shselasky		 */
381335640Shselasky		for (ai = res; ai != NULL; ai = ai->ai_next) {
382335640Shselasky			/*
383335640Shselasky			 * Does it have an address?
384335640Shselasky			 */
385335640Shselasky			if (ai->ai_addr != NULL) {
386335640Shselasky				/*
387335640Shselasky				 * Yes.  Get a port number; we're done.
388335640Shselasky				 */
389335640Shselasky				if (ai->ai_addr->sa_family == AF_INET) {
390335640Shselasky					in4 = (struct sockaddr_in *)ai->ai_addr;
391335640Shselasky					udp_port = ntohs(in4->sin_port);
392335640Shselasky					break;
393335640Shselasky				}
394335640Shselasky#ifdef INET6
395335640Shselasky				if (ai->ai_addr->sa_family == AF_INET6) {
396335640Shselasky					in6 = (struct sockaddr_in6 *)ai->ai_addr;
397335640Shselasky					udp_port = ntohs(in6->sin6_port);
398335640Shselasky					break;
399335640Shselasky				}
400335640Shselasky#endif
401335640Shselasky			}
402335640Shselasky		}
403335640Shselasky		freeaddrinfo(res);
404335640Shselasky	}
405335640Shselasky
406335640Shselasky	/*
407335640Shselasky	 * We need to check /etc/services for ambiguous entries.
408335640Shselasky	 * If we find an ambiguous entry, and it has the
409335640Shselasky	 * same port number, change the proto to PROTO_UNDEF
410335640Shselasky	 * so both TCP and UDP will be checked.
411335640Shselasky	 */
412335640Shselasky	if (tcp_port >= 0) {
413335640Shselasky		*port = tcp_port;
414335640Shselasky		*proto = IPPROTO_TCP;
415335640Shselasky		if (udp_port >= 0) {
416335640Shselasky			if (udp_port == tcp_port)
417335640Shselasky				*proto = PROTO_UNDEF;
418335640Shselasky#ifdef notdef
419335640Shselasky			else
420335640Shselasky				/* Can't handle ambiguous names that refer
421335640Shselasky				   to different port numbers. */
422335640Shselasky				warning("ambiguous port %s in /etc/services",
423335640Shselasky					name);
424335640Shselasky#endif
425335640Shselasky		}
426335640Shselasky		return 1;
427335640Shselasky	}
428335640Shselasky	if (udp_port >= 0) {
429335640Shselasky		*port = udp_port;
430335640Shselasky		*proto = IPPROTO_UDP;
431335640Shselasky		return 1;
432335640Shselasky	}
433335640Shselasky#if defined(ultrix) || defined(__osf__)
434335640Shselasky	/* Special hack in case NFS isn't in /etc/services */
435335640Shselasky	if (strcmp(name, "nfs") == 0) {
436335640Shselasky		*port = 2049;
437335640Shselasky		*proto = PROTO_UNDEF;
438335640Shselasky		return 1;
439335640Shselasky	}
440335640Shselasky#endif
441335640Shselasky	return 0;
442335640Shselasky}
443335640Shselasky
444335640Shselasky/*
445335640Shselasky * Convert a string in the form PPP-PPP, where correspond to ports, to
446335640Shselasky * a starting and ending port in a port range.
447335640Shselasky * Return 0 on failure.
448335640Shselasky */
449335640Shselaskyint
450335640Shselaskypcap_nametoportrange(const char *name, int *port1, int *port2, int *proto)
451335640Shselasky{
452335640Shselasky	u_int p1, p2;
453335640Shselasky	char *off, *cpy;
454335640Shselasky	int save_proto;
455335640Shselasky
456335640Shselasky	if (sscanf(name, "%d-%d", &p1, &p2) != 2) {
457335640Shselasky		if ((cpy = strdup(name)) == NULL)
458335640Shselasky			return 0;
459335640Shselasky
460335640Shselasky		if ((off = strchr(cpy, '-')) == NULL) {
461335640Shselasky			free(cpy);
462335640Shselasky			return 0;
463335640Shselasky		}
464335640Shselasky
465335640Shselasky		*off = '\0';
466335640Shselasky
467335640Shselasky		if (pcap_nametoport(cpy, port1, proto) == 0) {
468335640Shselasky			free(cpy);
469335640Shselasky			return 0;
470335640Shselasky		}
471335640Shselasky		save_proto = *proto;
472335640Shselasky
473335640Shselasky		if (pcap_nametoport(off + 1, port2, proto) == 0) {
474335640Shselasky			free(cpy);
475335640Shselasky			return 0;
476335640Shselasky		}
477335640Shselasky		free(cpy);
478335640Shselasky
479335640Shselasky		if (*proto != save_proto)
480335640Shselasky			*proto = PROTO_UNDEF;
481335640Shselasky	} else {
482335640Shselasky		*port1 = p1;
483335640Shselasky		*port2 = p2;
484335640Shselasky		*proto = PROTO_UNDEF;
485335640Shselasky	}
486335640Shselasky
487335640Shselasky	return 1;
488335640Shselasky}
489335640Shselasky
490335640Shselasky/*
491335640Shselasky * XXX - not guaranteed to be thread-safe!  See below for platforms
492335640Shselasky * on which it is thread-safe and on which it isn't.
493335640Shselasky */
494335640Shselaskyint
495335640Shselaskypcap_nametoproto(const char *str)
496335640Shselasky{
497335640Shselasky	struct protoent *p;
498335640Shselasky  #if defined(HAVE_LINUX_GETNETBYNAME_R)
499335640Shselasky	/*
500335640Shselasky	 * We have Linux's reentrant getprotobyname_r().
501335640Shselasky	 */
502335640Shselasky	struct protoent result_buf;
503335640Shselasky	char buf[1024];	/* arbitrary size */
504335640Shselasky	int err;
505335640Shselasky
506335640Shselasky	err = getprotobyname_r(str, &result_buf, buf, sizeof buf, &p);
507335640Shselasky	if (err != 0) {
508335640Shselasky		/*
509335640Shselasky		 * XXX - dynamically allocate the buffer, and make it
510335640Shselasky		 * bigger if we get ERANGE back?
511335640Shselasky		 */
512335640Shselasky		return 0;
513335640Shselasky	}
514335640Shselasky  #elif defined(HAVE_SOLARIS_IRIX_GETNETBYNAME_R)
515335640Shselasky	/*
516335640Shselasky	 * We have Solaris's and IRIX's reentrant getprotobyname_r().
517335640Shselasky	 */
518335640Shselasky	struct protoent result_buf;
519335640Shselasky	char buf[1024];	/* arbitrary size */
520335640Shselasky
521335640Shselasky	p = getprotobyname_r(str, &result_buf, buf, (int)sizeof buf);
522335640Shselasky  #elif defined(HAVE_AIX_GETNETBYNAME_R)
523335640Shselasky	/*
524335640Shselasky	 * We have AIX's reentrant getprotobyname_r().
525335640Shselasky	 */
526335640Shselasky	struct protoent result_buf;
527335640Shselasky	struct protoent_data proto_data;
528335640Shselasky
529335640Shselasky	if (getprotobyname_r(str, &result_buf, &proto_data) == -1)
530335640Shselasky		p = NULL;
531335640Shselasky	else
532335640Shselasky		p = &result_buf;
533335640Shselasky  #else
534335640Shselasky 	/*
535335640Shselasky 	 * We don't have any getprotobyname_r(); either we have a
536335640Shselasky 	 * getprotobyname() that uses thread-specific data, in which
537335640Shselasky 	 * case we're thread-safe (sufficiently recent FreeBSD,
538335640Shselasky 	 * sufficiently recent Darwin-based OS, sufficiently recent
539335640Shselasky 	 * HP-UX, sufficiently recent Tru64 UNIX, Windows), or we have
540335640Shselasky	 * the traditional getprotobyname() (everything else, including
541335640Shselasky 	 * current NetBSD and OpenBSD), in which case we're not
542335640Shselasky 	 * thread-safe.
543335640Shselasky 	 */
544335640Shselasky	p = getprotobyname(str);
545335640Shselasky  #endif
546335640Shselasky	if (p != 0)
547335640Shselasky		return p->p_proto;
548335640Shselasky	else
549335640Shselasky		return PROTO_UNDEF;
550335640Shselasky}
551335640Shselasky
552335640Shselasky#include "ethertype.h"
553335640Shselasky
554335640Shselaskystruct eproto {
555335640Shselasky	const char *s;
556335640Shselasky	u_short p;
557335640Shselasky};
558335640Shselasky
559335640Shselasky/*
560335640Shselasky * Static data base of ether protocol types.
561335640Shselasky * tcpdump used to import this, and it's declared as an export on
562335640Shselasky * Debian, at least, so make it a public symbol, even though we
563335640Shselasky * don't officially export it by declaring it in a header file.
564335640Shselasky * (Programs *should* do this themselves, as tcpdump now does.)
565335640Shselasky *
566335640Shselasky * We declare it here, right before defining it, to squelch any
567335640Shselasky * warnings we might get from compilers about the lack of a
568335640Shselasky * declaration.
569335640Shselasky */
570335640ShselaskyPCAP_API struct eproto eproto_db[];
571335640ShselaskyPCAP_API_DEF struct eproto eproto_db[] = {
572335640Shselasky	{ "pup", ETHERTYPE_PUP },
573335640Shselasky	{ "xns", ETHERTYPE_NS },
574335640Shselasky	{ "ip", ETHERTYPE_IP },
575335640Shselasky#ifdef INET6
576335640Shselasky	{ "ip6", ETHERTYPE_IPV6 },
577335640Shselasky#endif
578335640Shselasky	{ "arp", ETHERTYPE_ARP },
579335640Shselasky	{ "rarp", ETHERTYPE_REVARP },
580335640Shselasky	{ "sprite", ETHERTYPE_SPRITE },
581335640Shselasky	{ "mopdl", ETHERTYPE_MOPDL },
582335640Shselasky	{ "moprc", ETHERTYPE_MOPRC },
583335640Shselasky	{ "decnet", ETHERTYPE_DN },
584335640Shselasky	{ "lat", ETHERTYPE_LAT },
585335640Shselasky	{ "sca", ETHERTYPE_SCA },
586335640Shselasky	{ "lanbridge", ETHERTYPE_LANBRIDGE },
587335640Shselasky	{ "vexp", ETHERTYPE_VEXP },
588335640Shselasky	{ "vprod", ETHERTYPE_VPROD },
589335640Shselasky	{ "atalk", ETHERTYPE_ATALK },
590335640Shselasky	{ "atalkarp", ETHERTYPE_AARP },
591335640Shselasky	{ "loopback", ETHERTYPE_LOOPBACK },
592335640Shselasky	{ "decdts", ETHERTYPE_DECDTS },
593335640Shselasky	{ "decdns", ETHERTYPE_DECDNS },
594335640Shselasky	{ (char *)0, 0 }
595335640Shselasky};
596335640Shselasky
597335640Shselaskyint
598335640Shselaskypcap_nametoeproto(const char *s)
599335640Shselasky{
600335640Shselasky	struct eproto *p = eproto_db;
601335640Shselasky
602335640Shselasky	while (p->s != 0) {
603335640Shselasky		if (strcmp(p->s, s) == 0)
604335640Shselasky			return p->p;
605335640Shselasky		p += 1;
606335640Shselasky	}
607335640Shselasky	return PROTO_UNDEF;
608335640Shselasky}
609335640Shselasky
610335640Shselasky#include "llc.h"
611335640Shselasky
612335640Shselasky/* Static data base of LLC values. */
613335640Shselaskystatic struct eproto llc_db[] = {
614335640Shselasky	{ "iso", LLCSAP_ISONS },
615335640Shselasky	{ "stp", LLCSAP_8021D },
616335640Shselasky	{ "ipx", LLCSAP_IPX },
617335640Shselasky	{ "netbeui", LLCSAP_NETBEUI },
618335640Shselasky	{ (char *)0, 0 }
619335640Shselasky};
620335640Shselasky
621335640Shselaskyint
622335640Shselaskypcap_nametollc(const char *s)
623335640Shselasky{
624335640Shselasky	struct eproto *p = llc_db;
625335640Shselasky
626335640Shselasky	while (p->s != 0) {
627335640Shselasky		if (strcmp(p->s, s) == 0)
628335640Shselasky			return p->p;
629335640Shselasky		p += 1;
630335640Shselasky	}
631335640Shselasky	return PROTO_UNDEF;
632335640Shselasky}
633335640Shselasky
634335640Shselasky/* Hex digit to 8-bit unsigned integer. */
635335640Shselaskystatic inline u_char
636335640Shselaskyxdtoi(u_char c)
637335640Shselasky{
638335640Shselasky	if (isdigit(c))
639335640Shselasky		return (u_char)(c - '0');
640335640Shselasky	else if (islower(c))
641335640Shselasky		return (u_char)(c - 'a' + 10);
642335640Shselasky	else
643335640Shselasky		return (u_char)(c - 'A' + 10);
644335640Shselasky}
645335640Shselasky
646335640Shselaskyint
647335640Shselasky__pcap_atoin(const char *s, bpf_u_int32 *addr)
648335640Shselasky{
649335640Shselasky	u_int n;
650335640Shselasky	int len;
651335640Shselasky
652335640Shselasky	*addr = 0;
653335640Shselasky	len = 0;
654335640Shselasky	for (;;) {
655335640Shselasky		n = 0;
656356341Scy		while (*s && *s != '.') {
657356341Scy			if (n > 25) {
658356341Scy				/* The result will be > 255 */
659356341Scy				return -1;
660356341Scy			}
661335640Shselasky			n = n * 10 + *s++ - '0';
662356341Scy		}
663356341Scy		if (n > 255)
664356341Scy			return -1;
665335640Shselasky		*addr <<= 8;
666335640Shselasky		*addr |= n & 0xff;
667335640Shselasky		len += 8;
668335640Shselasky		if (*s == '\0')
669335640Shselasky			return len;
670335640Shselasky		++s;
671335640Shselasky	}
672335640Shselasky	/* NOTREACHED */
673335640Shselasky}
674335640Shselasky
675335640Shselaskyint
676335640Shselasky__pcap_atodn(const char *s, bpf_u_int32 *addr)
677335640Shselasky{
678335640Shselasky#define AREASHIFT 10
679335640Shselasky#define AREAMASK 0176000
680335640Shselasky#define NODEMASK 01777
681335640Shselasky
682335640Shselasky	u_int node, area;
683335640Shselasky
684335640Shselasky	if (sscanf(s, "%d.%d", &area, &node) != 2)
685335640Shselasky		return(0);
686335640Shselasky
687335640Shselasky	*addr = (area << AREASHIFT) & AREAMASK;
688335640Shselasky	*addr |= (node & NODEMASK);
689335640Shselasky
690335640Shselasky	return(32);
691335640Shselasky}
692335640Shselasky
693335640Shselasky/*
694335640Shselasky * Convert 's', which can have the one of the forms:
695335640Shselasky *
696335640Shselasky *	"xx:xx:xx:xx:xx:xx"
697335640Shselasky *	"xx.xx.xx.xx.xx.xx"
698335640Shselasky *	"xx-xx-xx-xx-xx-xx"
699335640Shselasky *	"xxxx.xxxx.xxxx"
700335640Shselasky *	"xxxxxxxxxxxx"
701335640Shselasky *
702335640Shselasky * (or various mixes of ':', '.', and '-') into a new
703335640Shselasky * ethernet address.  Assumes 's' is well formed.
704335640Shselasky */
705335640Shselaskyu_char *
706335640Shselaskypcap_ether_aton(const char *s)
707335640Shselasky{
708335640Shselasky	register u_char *ep, *e;
709335640Shselasky	register u_char d;
710335640Shselasky
711335640Shselasky	e = ep = (u_char *)malloc(6);
712335640Shselasky	if (e == NULL)
713335640Shselasky		return (NULL);
714335640Shselasky
715335640Shselasky	while (*s) {
716335640Shselasky		if (*s == ':' || *s == '.' || *s == '-')
717335640Shselasky			s += 1;
718335640Shselasky		d = xdtoi(*s++);
719335640Shselasky		if (isxdigit((unsigned char)*s)) {
720335640Shselasky			d <<= 4;
721335640Shselasky			d |= xdtoi(*s++);
722335640Shselasky		}
723335640Shselasky		*ep++ = d;
724335640Shselasky	}
725335640Shselasky
726335640Shselasky	return (e);
727335640Shselasky}
728335640Shselasky
729335640Shselasky#ifndef HAVE_ETHER_HOSTTON
730335640Shselasky/*
731335640Shselasky * Roll our own.
732335640Shselasky * XXX - not thread-safe, because pcap_next_etherent() isn't thread-
733335640Shselasky * safe!  Needs a mutex or a thread-safe pcap_next_etherent().
734335640Shselasky */
735335640Shselaskyu_char *
736335640Shselaskypcap_ether_hostton(const char *name)
737335640Shselasky{
738335640Shselasky	register struct pcap_etherent *ep;
739335640Shselasky	register u_char *ap;
740335640Shselasky	static FILE *fp = NULL;
741335640Shselasky	static int init = 0;
742335640Shselasky
743335640Shselasky	if (!init) {
744335640Shselasky		fp = fopen(PCAP_ETHERS_FILE, "r");
745335640Shselasky		++init;
746335640Shselasky		if (fp == NULL)
747335640Shselasky			return (NULL);
748335640Shselasky	} else if (fp == NULL)
749335640Shselasky		return (NULL);
750335640Shselasky	else
751335640Shselasky		rewind(fp);
752335640Shselasky
753335640Shselasky	while ((ep = pcap_next_etherent(fp)) != NULL) {
754335640Shselasky		if (strcmp(ep->name, name) == 0) {
755335640Shselasky			ap = (u_char *)malloc(6);
756335640Shselasky			if (ap != NULL) {
757335640Shselasky				memcpy(ap, ep->addr, 6);
758335640Shselasky				return (ap);
759335640Shselasky			}
760335640Shselasky			break;
761335640Shselasky		}
762335640Shselasky	}
763335640Shselasky	return (NULL);
764335640Shselasky}
765335640Shselasky#else
766335640Shselasky/*
767335640Shselasky * Use the OS-supplied routine.
768335640Shselasky * This *should* be thread-safe; the API doesn't have a static buffer.
769335640Shselasky */
770335640Shselaskyu_char *
771335640Shselaskypcap_ether_hostton(const char *name)
772335640Shselasky{
773335640Shselasky	register u_char *ap;
774335640Shselasky	u_char a[6];
775335640Shselasky
776335640Shselasky	ap = NULL;
777335640Shselasky	if (ether_hostton(name, (struct ether_addr *)a) == 0) {
778335640Shselasky		ap = (u_char *)malloc(6);
779335640Shselasky		if (ap != NULL)
780335640Shselasky			memcpy((char *)ap, (char *)a, 6);
781335640Shselasky	}
782335640Shselasky	return (ap);
783335640Shselasky}
784335640Shselasky#endif
785335640Shselasky
786335640Shselasky/*
787335640Shselasky * XXX - not guaranteed to be thread-safe!
788335640Shselasky */
789335640Shselaskyint
790335640Shselasky#ifdef	DECNETLIB
791335640Shselasky__pcap_nametodnaddr(const char *name, u_short *res)
792335640Shselasky{
793335640Shselasky	struct nodeent *getnodebyname();
794335640Shselasky	struct nodeent *nep;
795335640Shselasky
796335640Shselasky	nep = getnodebyname(name);
797335640Shselasky	if (nep == ((struct nodeent *)0))
798335640Shselasky		return(0);
799335640Shselasky
800335640Shselasky	memcpy((char *)res, (char *)nep->n_addr, sizeof(unsigned short));
801335640Shselasky	return(1);
802335640Shselasky#else
803335640Shselasky__pcap_nametodnaddr(const char *name _U_, u_short *res _U_)
804335640Shselasky{
805335640Shselasky	return(0);
806335640Shselasky#endif
807335640Shselasky}
808