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