1/*
2 * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 *
21 * Name to id translation routines used by the scanner.
22 * These functions are not time critical.
23 */
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#ifdef DECNETLIB
30#include <sys/types.h>
31#include <netdnet/dnetdb.h>
32#endif
33
34#ifdef _WIN32
35#include <pcap-stdinc.h>
36
37#ifdef INET6
38/*
39 * To quote the MSDN page for getaddrinfo() at
40 *
41 *    https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520(v=vs.85).aspx
42 *
43 * "Support for getaddrinfo on Windows 2000 and older versions
44 * The getaddrinfo function was added to the Ws2_32.dll on Windows XP and
45 * later. To execute an application that uses this function on earlier
46 * versions of Windows, then you need to include the Ws2tcpip.h and
47 * Wspiapi.h files. When the Wspiapi.h include file is added, the
48 * getaddrinfo function is defined to the WspiapiGetAddrInfo inline
49 * function in the Wspiapi.h file. At runtime, the WspiapiGetAddrInfo
50 * function is implemented in such a way that if the Ws2_32.dll or the
51 * Wship6.dll (the file containing getaddrinfo in the IPv6 Technology
52 * Preview for Windows 2000) does not include getaddrinfo, then a
53 * version of getaddrinfo is implemented inline based on code in the
54 * Wspiapi.h header file. This inline code will be used on older Windows
55 * platforms that do not natively support the getaddrinfo function."
56 *
57 * We use getaddrinfo(), so we include Wspiapi.h here.  pcap-stdinc.h
58 * includes Ws2tcpip.h, so we don't need to include it ourselves.
59 */
60#include <Wspiapi.h>
61#endif
62
63#else /* _WIN32 */
64
65#include <sys/param.h>
66#include <sys/types.h>				/* concession to AIX */
67#include <sys/socket.h>
68#include <sys/time.h>
69
70#include <netinet/in.h>
71#endif /* _WIN32 */
72
73#ifndef _WIN32
74#ifdef HAVE_ETHER_HOSTTON
75/*
76 * XXX - do we need any of this if <netinet/if_ether.h> doesn't declare
77 * ether_hostton()?
78 */
79#ifdef HAVE_NETINET_IF_ETHER_H
80struct mbuf;		/* Squelch compiler warnings on some platforms for */
81struct rtentry;		/* declarations in <net/if.h> */
82#include <net/if.h>	/* for "struct ifnet" in "struct arpcom" on Solaris */
83#include <netinet/if_ether.h>
84#endif /* HAVE_NETINET_IF_ETHER_H */
85#ifdef NETINET_ETHER_H_DECLARES_ETHER_HOSTTON
86#include <netinet/ether.h>
87#endif /* NETINET_ETHER_H_DECLARES_ETHER_HOSTTON */
88#endif /* HAVE_ETHER_HOSTTON */
89#include <arpa/inet.h>
90#include <netdb.h>
91#endif /* _WIN32 */
92
93#include <ctype.h>
94#include <errno.h>
95#include <stdlib.h>
96#include <string.h>
97#include <stdio.h>
98
99#include "pcap-int.h"
100
101#include "gencode.h"
102#include <pcap/namedb.h>
103#include "nametoaddr.h"
104
105#ifdef HAVE_OS_PROTO_H
106#include "os-proto.h"
107#endif
108
109#ifndef NTOHL
110#define NTOHL(x) (x) = ntohl(x)
111#define NTOHS(x) (x) = ntohs(x)
112#endif
113
114static inline int xdtoi(int);
115
116/*
117 *  Convert host name to internet address.
118 *  Return 0 upon failure.
119 */
120bpf_u_int32 **
121pcap_nametoaddr(const char *name)
122{
123#ifndef h_addr
124	static bpf_u_int32 *hlist[2];
125#endif
126	bpf_u_int32 **p;
127	struct hostent *hp;
128
129	if ((hp = gethostbyname(name)) != NULL) {
130#ifndef h_addr
131		hlist[0] = (bpf_u_int32 *)hp->h_addr;
132		NTOHL(hp->h_addr);
133		return hlist;
134#else
135		for (p = (bpf_u_int32 **)hp->h_addr_list; *p; ++p)
136			NTOHL(**p);
137		return (bpf_u_int32 **)hp->h_addr_list;
138#endif
139	}
140	else
141		return 0;
142}
143
144#ifdef INET6
145struct addrinfo *
146pcap_nametoaddrinfo(const char *name)
147{
148	struct addrinfo hints, *res;
149	int error;
150
151	memset(&hints, 0, sizeof(hints));
152	hints.ai_family = PF_UNSPEC;
153	hints.ai_socktype = SOCK_STREAM;	/*not really*/
154	hints.ai_protocol = IPPROTO_TCP;	/*not really*/
155	error = getaddrinfo(name, NULL, &hints, &res);
156	if (error)
157		return NULL;
158	else
159		return res;
160}
161#endif /*INET6*/
162
163/*
164 *  Convert net name to internet address.
165 *  Return 0 upon failure.
166 */
167bpf_u_int32
168pcap_nametonetaddr(const char *name)
169{
170#ifndef _WIN32
171	struct netent *np;
172
173	if ((np = getnetbyname(name)) != NULL)
174		return np->n_net;
175	else
176		return 0;
177#else
178	/*
179	 * There's no "getnetbyname()" on Windows.
180	 *
181	 * XXX - I guess we could use the BSD code to read
182	 * C:\Windows\System32\drivers\etc/networks, assuming
183	 * that's its home on all the versions of Windows
184	 * we use, but that file probably just has the loopback
185	 * network on 127/24 on 99 44/100% of Windows machines.
186	 *
187	 * (Heck, these days it probably just has that on 99 44/100%
188	 * of *UN*X* machines.)
189	 */
190	return 0;
191#endif
192}
193
194/*
195 * Convert a port name to its port and protocol numbers.
196 * We assume only TCP or UDP.
197 * Return 0 upon failure.
198 */
199int
200pcap_nametoport(const char *name, int *port, int *proto)
201{
202	struct servent *sp;
203	int tcp_port = -1;
204	int udp_port = -1;
205
206	/*
207	 * We need to check /etc/services for ambiguous entries.
208	 * If we find the ambiguous entry, and it has the
209	 * same port number, change the proto to PROTO_UNDEF
210	 * so both TCP and UDP will be checked.
211	 */
212	sp = getservbyname(name, "tcp");
213	if (sp != NULL) tcp_port = ntohs(sp->s_port);
214	sp = getservbyname(name, "udp");
215	if (sp != NULL) udp_port = ntohs(sp->s_port);
216	if (tcp_port >= 0) {
217		*port = tcp_port;
218		*proto = IPPROTO_TCP;
219		if (udp_port >= 0) {
220			if (udp_port == tcp_port)
221				*proto = PROTO_UNDEF;
222#ifdef notdef
223			else
224				/* Can't handle ambiguous names that refer
225				   to different port numbers. */
226				warning("ambiguous port %s in /etc/services",
227					name);
228#endif
229		}
230		return 1;
231	}
232	if (udp_port >= 0) {
233		*port = udp_port;
234		*proto = IPPROTO_UDP;
235		return 1;
236	}
237#if defined(ultrix) || defined(__osf__)
238	/* Special hack in case NFS isn't in /etc/services */
239	if (strcmp(name, "nfs") == 0) {
240		*port = 2049;
241		*proto = PROTO_UNDEF;
242		return 1;
243	}
244#endif
245	return 0;
246}
247
248/*
249 * Convert a string in the form PPP-PPP, where correspond to ports, to
250 * a starting and ending port in a port range.
251 * Return 0 on failure.
252 */
253int
254pcap_nametoportrange(const char *name, int *port1, int *port2, int *proto)
255{
256	u_int p1, p2;
257	char *off, *cpy;
258	int save_proto;
259
260	if (sscanf(name, "%d-%d", &p1, &p2) != 2) {
261		if ((cpy = strdup(name)) == NULL)
262			return 0;
263
264		if ((off = strchr(cpy, '-')) == NULL) {
265			free(cpy);
266			return 0;
267		}
268
269		*off = '\0';
270
271		if (pcap_nametoport(cpy, port1, proto) == 0) {
272			free(cpy);
273			return 0;
274		}
275		save_proto = *proto;
276
277		if (pcap_nametoport(off + 1, port2, proto) == 0) {
278			free(cpy);
279			return 0;
280		}
281		free(cpy);
282
283		if (*proto != save_proto)
284			*proto = PROTO_UNDEF;
285	} else {
286		*port1 = p1;
287		*port2 = p2;
288		*proto = PROTO_UNDEF;
289	}
290
291	return 1;
292}
293
294int
295pcap_nametoproto(const char *str)
296{
297	struct protoent *p;
298
299	p = getprotobyname(str);
300	if (p != 0)
301		return p->p_proto;
302	else
303		return PROTO_UNDEF;
304}
305
306#include "ethertype.h"
307
308struct eproto {
309	const char *s;
310	u_short p;
311};
312
313/*
314 * Static data base of ether protocol types.
315 * tcpdump used to import this, and it's declared as an export on
316 * Debian, at least, so make it a public symbol, even though we
317 * don't officially export it by declaring it in a header file.
318 * (Programs *should* do this themselves, as tcpdump now does.)
319 */
320PCAP_API_DEF struct eproto eproto_db[] = {
321	{ "pup", ETHERTYPE_PUP },
322	{ "xns", ETHERTYPE_NS },
323	{ "ip", ETHERTYPE_IP },
324#ifdef INET6
325	{ "ip6", ETHERTYPE_IPV6 },
326#endif
327	{ "arp", ETHERTYPE_ARP },
328	{ "rarp", ETHERTYPE_REVARP },
329	{ "sprite", ETHERTYPE_SPRITE },
330	{ "mopdl", ETHERTYPE_MOPDL },
331	{ "moprc", ETHERTYPE_MOPRC },
332	{ "decnet", ETHERTYPE_DN },
333	{ "lat", ETHERTYPE_LAT },
334	{ "sca", ETHERTYPE_SCA },
335	{ "lanbridge", ETHERTYPE_LANBRIDGE },
336	{ "vexp", ETHERTYPE_VEXP },
337	{ "vprod", ETHERTYPE_VPROD },
338	{ "atalk", ETHERTYPE_ATALK },
339	{ "atalkarp", ETHERTYPE_AARP },
340	{ "loopback", ETHERTYPE_LOOPBACK },
341	{ "decdts", ETHERTYPE_DECDTS },
342	{ "decdns", ETHERTYPE_DECDNS },
343	{ (char *)0, 0 }
344};
345
346int
347pcap_nametoeproto(const char *s)
348{
349	struct eproto *p = eproto_db;
350
351	while (p->s != 0) {
352		if (strcmp(p->s, s) == 0)
353			return p->p;
354		p += 1;
355	}
356	return PROTO_UNDEF;
357}
358
359#include "llc.h"
360
361/* Static data base of LLC values. */
362static struct eproto llc_db[] = {
363	{ "iso", LLCSAP_ISONS },
364	{ "stp", LLCSAP_8021D },
365	{ "ipx", LLCSAP_IPX },
366	{ "netbeui", LLCSAP_NETBEUI },
367	{ (char *)0, 0 }
368};
369
370int
371pcap_nametollc(const char *s)
372{
373	struct eproto *p = llc_db;
374
375	while (p->s != 0) {
376		if (strcmp(p->s, s) == 0)
377			return p->p;
378		p += 1;
379	}
380	return PROTO_UNDEF;
381}
382
383/* Hex digit to integer. */
384static inline int
385xdtoi(c)
386	register int c;
387{
388	if (isdigit(c))
389		return c - '0';
390	else if (islower(c))
391		return c - 'a' + 10;
392	else
393		return c - 'A' + 10;
394}
395
396int
397__pcap_atoin(const char *s, bpf_u_int32 *addr)
398{
399	u_int n;
400	int len;
401
402	*addr = 0;
403	len = 0;
404	while (1) {
405		n = 0;
406		while (*s && *s != '.')
407			n = n * 10 + *s++ - '0';
408		*addr <<= 8;
409		*addr |= n & 0xff;
410		len += 8;
411		if (*s == '\0')
412			return len;
413		++s;
414	}
415	/* NOTREACHED */
416}
417
418int
419__pcap_atodn(const char *s, bpf_u_int32 *addr)
420{
421#define AREASHIFT 10
422#define AREAMASK 0176000
423#define NODEMASK 01777
424
425	u_int node, area;
426
427	if (sscanf(s, "%d.%d", &area, &node) != 2)
428		return(0);
429
430	*addr = (area << AREASHIFT) & AREAMASK;
431	*addr |= (node & NODEMASK);
432
433	return(32);
434}
435
436/*
437 * Convert 's', which can have the one of the forms:
438 *
439 *	"xx:xx:xx:xx:xx:xx"
440 *	"xx.xx.xx.xx.xx.xx"
441 *	"xx-xx-xx-xx-xx-xx"
442 *	"xxxx.xxxx.xxxx"
443 *	"xxxxxxxxxxxx"
444 *
445 * (or various mixes of ':', '.', and '-') into a new
446 * ethernet address.  Assumes 's' is well formed.
447 */
448u_char *
449pcap_ether_aton(const char *s)
450{
451	register u_char *ep, *e;
452	register u_int d;
453
454	e = ep = (u_char *)malloc(6);
455	if (e == NULL)
456		return (NULL);
457
458	while (*s) {
459		if (*s == ':' || *s == '.' || *s == '-')
460			s += 1;
461		d = xdtoi(*s++);
462		if (isxdigit((unsigned char)*s)) {
463			d <<= 4;
464			d |= xdtoi(*s++);
465		}
466		*ep++ = d;
467	}
468
469	return (e);
470}
471
472#ifndef HAVE_ETHER_HOSTTON
473/* Roll our own */
474u_char *
475pcap_ether_hostton(const char *name)
476{
477	register struct pcap_etherent *ep;
478	register u_char *ap;
479	static FILE *fp = NULL;
480	static int init = 0;
481
482	if (!init) {
483		fp = fopen(PCAP_ETHERS_FILE, "r");
484		++init;
485		if (fp == NULL)
486			return (NULL);
487	} else if (fp == NULL)
488		return (NULL);
489	else
490		rewind(fp);
491
492	while ((ep = pcap_next_etherent(fp)) != NULL) {
493		if (strcmp(ep->name, name) == 0) {
494			ap = (u_char *)malloc(6);
495			if (ap != NULL) {
496				memcpy(ap, ep->addr, 6);
497				return (ap);
498			}
499			break;
500		}
501	}
502	return (NULL);
503}
504#else
505
506#if !defined(HAVE_DECL_ETHER_HOSTTON) || !HAVE_DECL_ETHER_HOSTTON
507#ifndef HAVE_STRUCT_ETHER_ADDR
508struct ether_addr {
509	unsigned char ether_addr_octet[6];
510};
511#endif
512extern int ether_hostton(const char *, struct ether_addr *);
513#endif
514
515/* Use the os supplied routines */
516u_char *
517pcap_ether_hostton(const char *name)
518{
519	register u_char *ap;
520	u_char a[6];
521
522	ap = NULL;
523	if (ether_hostton(name, (struct ether_addr *)a) == 0) {
524		ap = (u_char *)malloc(6);
525		if (ap != NULL)
526			memcpy((char *)ap, (char *)a, 6);
527	}
528	return (ap);
529}
530#endif
531
532int
533__pcap_nametodnaddr(const char *name, u_short *res)
534{
535#ifdef	DECNETLIB
536	struct nodeent *getnodebyname();
537	struct nodeent *nep;
538
539	nep = getnodebyname(name);
540	if (nep == ((struct nodeent *)0))
541		return(0);
542
543	memcpy((char *)res, (char *)nep->n_addr, sizeof(unsigned short));
544	return(1);
545#else
546	return(0);
547#endif
548}
549