xref: /freebsd/contrib/libpcap/nametoaddr.c (revision fed1ca4b719c56c930f2259d80663cd34be812bb)
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  * $FreeBSD$
25  */
26 
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30 
31 #ifdef DECNETLIB
32 #include <sys/types.h>
33 #include <netdnet/dnetdb.h>
34 #endif
35 
36 #ifdef WIN32
37 #include <pcap-stdinc.h>
38 
39 #else /* WIN32 */
40 
41 #include <sys/param.h>
42 #include <sys/types.h>				/* concession to AIX */
43 #include <sys/socket.h>
44 #include <sys/time.h>
45 
46 #include <netinet/in.h>
47 #endif /* WIN32 */
48 
49 #ifndef WIN32
50 #ifdef HAVE_ETHER_HOSTTON
51 /*
52  * XXX - do we need any of this if <netinet/if_ether.h> doesn't declare
53  * ether_hostton()?
54  */
55 #ifdef HAVE_NETINET_IF_ETHER_H
56 struct mbuf;		/* Squelch compiler warnings on some platforms for */
57 struct rtentry;		/* declarations in <net/if.h> */
58 #include <net/if.h>	/* for "struct ifnet" in "struct arpcom" on Solaris */
59 #include <netinet/if_ether.h>
60 #endif /* HAVE_NETINET_IF_ETHER_H */
61 #ifdef NETINET_ETHER_H_DECLARES_ETHER_HOSTTON
62 #include <netinet/ether.h>
63 #endif /* NETINET_ETHER_H_DECLARES_ETHER_HOSTTON */
64 #endif /* HAVE_ETHER_HOSTTON */
65 #include <arpa/inet.h>
66 #include <netdb.h>
67 #endif /* WIN32 */
68 
69 #include <ctype.h>
70 #include <errno.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <stdio.h>
74 
75 #include "pcap-int.h"
76 
77 #include "gencode.h"
78 #include <pcap/namedb.h>
79 
80 #ifdef HAVE_OS_PROTO_H
81 #include "os-proto.h"
82 #endif
83 
84 #ifndef NTOHL
85 #define NTOHL(x) (x) = ntohl(x)
86 #define NTOHS(x) (x) = ntohs(x)
87 #endif
88 
89 static inline int xdtoi(int);
90 
91 /*
92  *  Convert host name to internet address.
93  *  Return 0 upon failure.
94  */
95 bpf_u_int32 **
96 pcap_nametoaddr(const char *name)
97 {
98 #ifndef h_addr
99 	static bpf_u_int32 *hlist[2];
100 #endif
101 	bpf_u_int32 **p;
102 	struct hostent *hp;
103 
104 	if ((hp = gethostbyname(name)) != NULL) {
105 #ifndef h_addr
106 		hlist[0] = (bpf_u_int32 *)hp->h_addr;
107 		NTOHL(hp->h_addr);
108 		return hlist;
109 #else
110 		for (p = (bpf_u_int32 **)hp->h_addr_list; *p; ++p)
111 			NTOHL(**p);
112 		return (bpf_u_int32 **)hp->h_addr_list;
113 #endif
114 	}
115 	else
116 		return 0;
117 }
118 
119 #ifdef INET6
120 struct addrinfo *
121 pcap_nametoaddrinfo(const char *name)
122 {
123 	struct addrinfo hints, *res;
124 	int error;
125 
126 	memset(&hints, 0, sizeof(hints));
127 	hints.ai_family = PF_UNSPEC;
128 	hints.ai_socktype = SOCK_STREAM;	/*not really*/
129 	hints.ai_protocol = IPPROTO_TCP;	/*not really*/
130 	error = getaddrinfo(name, NULL, &hints, &res);
131 	if (error)
132 		return NULL;
133 	else
134 		return res;
135 }
136 #endif /*INET6*/
137 
138 /*
139  *  Convert net name to internet address.
140  *  Return 0 upon failure.
141  */
142 bpf_u_int32
143 pcap_nametonetaddr(const char *name)
144 {
145 #ifndef WIN32
146 	struct netent *np;
147 
148 	if ((np = getnetbyname(name)) != NULL)
149 		return np->n_net;
150 	else
151 		return 0;
152 #else
153 	/*
154 	 * There's no "getnetbyname()" on Windows.
155 	 */
156 	return 0;
157 #endif
158 }
159 
160 /*
161  * Convert a port name to its port and protocol numbers.
162  * We assume only TCP or UDP.
163  * Return 0 upon failure.
164  */
165 int
166 pcap_nametoport(const char *name, int *port, int *proto)
167 {
168 	struct servent *sp;
169 	int tcp_port = -1;
170 	int udp_port = -1;
171 
172 	/*
173 	 * We need to check /etc/services for ambiguous entries.
174 	 * If we find the ambiguous entry, and it has the
175 	 * same port number, change the proto to PROTO_UNDEF
176 	 * so both TCP and UDP will be checked.
177 	 */
178 	sp = getservbyname(name, "tcp");
179 	if (sp != NULL) tcp_port = ntohs(sp->s_port);
180 	sp = getservbyname(name, "udp");
181 	if (sp != NULL) udp_port = ntohs(sp->s_port);
182 	if (tcp_port >= 0) {
183 		*port = tcp_port;
184 		*proto = IPPROTO_TCP;
185 		if (udp_port >= 0) {
186 			if (udp_port == tcp_port)
187 				*proto = PROTO_UNDEF;
188 #ifdef notdef
189 			else
190 				/* Can't handle ambiguous names that refer
191 				   to different port numbers. */
192 				warning("ambiguous port %s in /etc/services",
193 					name);
194 #endif
195 		}
196 		return 1;
197 	}
198 	if (udp_port >= 0) {
199 		*port = udp_port;
200 		*proto = IPPROTO_UDP;
201 		return 1;
202 	}
203 #if defined(ultrix) || defined(__osf__)
204 	/* Special hack in case NFS isn't in /etc/services */
205 	if (strcmp(name, "nfs") == 0) {
206 		*port = 2049;
207 		*proto = PROTO_UNDEF;
208 		return 1;
209 	}
210 #endif
211 	return 0;
212 }
213 
214 /*
215  * Convert a string in the form PPP-PPP, where correspond to ports, to
216  * a starting and ending port in a port range.
217  * Return 0 on failure.
218  */
219 int
220 pcap_nametoportrange(const char *name, int *port1, int *port2, int *proto)
221 {
222 	u_int p1, p2;
223 	char *off, *cpy;
224 	int save_proto;
225 
226 	if (sscanf(name, "%d-%d", &p1, &p2) != 2) {
227 		if ((cpy = strdup(name)) == NULL)
228 			return 0;
229 
230 		if ((off = strchr(cpy, '-')) == NULL) {
231 			free(cpy);
232 			return 0;
233 		}
234 
235 		*off = '\0';
236 
237 		if (pcap_nametoport(cpy, port1, proto) == 0) {
238 			free(cpy);
239 			return 0;
240 		}
241 		save_proto = *proto;
242 
243 		if (pcap_nametoport(off + 1, port2, proto) == 0) {
244 			free(cpy);
245 			return 0;
246 		}
247 		free(cpy);
248 
249 		if (*proto != save_proto)
250 			*proto = PROTO_UNDEF;
251 	} else {
252 		*port1 = p1;
253 		*port2 = p2;
254 		*proto = PROTO_UNDEF;
255 	}
256 
257 	return 1;
258 }
259 
260 int
261 pcap_nametoproto(const char *str)
262 {
263 	struct protoent *p;
264 
265 	p = getprotobyname(str);
266 	if (p != 0)
267 		return p->p_proto;
268 	else
269 		return PROTO_UNDEF;
270 }
271 
272 #include "ethertype.h"
273 
274 struct eproto {
275 	const char *s;
276 	u_short p;
277 };
278 
279 /* Static data base of ether protocol types. */
280 struct eproto eproto_db[] = {
281 #if 0
282 	/* The FreeBSD elf linker generates a request to copy this array
283 	 * (including its size) when you link with -lpcap.  In order to
284 	 * not bump the major version number of this libpcap.so, we need
285 	 * to ensure that the array stays the same size.  Since PUP is
286 	 * likely never seen in real life any more, it's the first to
287 	 * be sacrificed (in favor of ip6).
288 	 */
289 	{ "pup", ETHERTYPE_PUP },
290 #endif
291 	{ "xns", ETHERTYPE_NS },
292 	{ "ip", ETHERTYPE_IP },
293 #ifdef INET6
294 	{ "ip6", ETHERTYPE_IPV6 },
295 #endif
296 	{ "arp", ETHERTYPE_ARP },
297 	{ "rarp", ETHERTYPE_REVARP },
298 	{ "sprite", ETHERTYPE_SPRITE },
299 	{ "mopdl", ETHERTYPE_MOPDL },
300 	{ "moprc", ETHERTYPE_MOPRC },
301 	{ "decnet", ETHERTYPE_DN },
302 	{ "lat", ETHERTYPE_LAT },
303 	{ "sca", ETHERTYPE_SCA },
304 	{ "lanbridge", ETHERTYPE_LANBRIDGE },
305 	{ "vexp", ETHERTYPE_VEXP },
306 	{ "vprod", ETHERTYPE_VPROD },
307 	{ "atalk", ETHERTYPE_ATALK },
308 	{ "atalkarp", ETHERTYPE_AARP },
309 	{ "loopback", ETHERTYPE_LOOPBACK },
310 	{ "decdts", ETHERTYPE_DECDTS },
311 	{ "decdns", ETHERTYPE_DECDNS },
312 	{ (char *)0, 0 }
313 };
314 
315 int
316 pcap_nametoeproto(const char *s)
317 {
318 	struct eproto *p = eproto_db;
319 
320 	while (p->s != 0) {
321 		if (strcmp(p->s, s) == 0)
322 			return p->p;
323 		p += 1;
324 	}
325 	return PROTO_UNDEF;
326 }
327 
328 #include "llc.h"
329 
330 /* Static data base of LLC values. */
331 static struct eproto llc_db[] = {
332 	{ "iso", LLCSAP_ISONS },
333 	{ "stp", LLCSAP_8021D },
334 	{ "ipx", LLCSAP_IPX },
335 	{ "netbeui", LLCSAP_NETBEUI },
336 	{ (char *)0, 0 }
337 };
338 
339 int
340 pcap_nametollc(const char *s)
341 {
342 	struct eproto *p = llc_db;
343 
344 	while (p->s != 0) {
345 		if (strcmp(p->s, s) == 0)
346 			return p->p;
347 		p += 1;
348 	}
349 	return PROTO_UNDEF;
350 }
351 
352 /* Hex digit to integer. */
353 static inline int
354 xdtoi(c)
355 	register int c;
356 {
357 	if (isdigit(c))
358 		return c - '0';
359 	else if (islower(c))
360 		return c - 'a' + 10;
361 	else
362 		return c - 'A' + 10;
363 }
364 
365 int
366 __pcap_atoin(const char *s, bpf_u_int32 *addr)
367 {
368 	u_int n;
369 	int len;
370 
371 	*addr = 0;
372 	len = 0;
373 	while (1) {
374 		n = 0;
375 		while (*s && *s != '.')
376 			n = n * 10 + *s++ - '0';
377 		*addr <<= 8;
378 		*addr |= n & 0xff;
379 		len += 8;
380 		if (*s == '\0')
381 			return len;
382 		++s;
383 	}
384 	/* NOTREACHED */
385 }
386 
387 int
388 __pcap_atodn(const char *s, bpf_u_int32 *addr)
389 {
390 #define AREASHIFT 10
391 #define AREAMASK 0176000
392 #define NODEMASK 01777
393 
394 	u_int node, area;
395 
396 	if (sscanf(s, "%d.%d", &area, &node) != 2)
397 		bpf_error("malformed decnet address '%s'", s);
398 
399 	*addr = (area << AREASHIFT) & AREAMASK;
400 	*addr |= (node & NODEMASK);
401 
402 	return(32);
403 }
404 
405 /*
406  * Convert 's', which can have the one of the forms:
407  *
408  *	"xx:xx:xx:xx:xx:xx"
409  *	"xx.xx.xx.xx.xx.xx"
410  *	"xx-xx-xx-xx-xx-xx"
411  *	"xxxx.xxxx.xxxx"
412  *	"xxxxxxxxxxxx"
413  *
414  * (or various mixes of ':', '.', and '-') into a new
415  * ethernet address.  Assumes 's' is well formed.
416  */
417 u_char *
418 pcap_ether_aton(const char *s)
419 {
420 	register u_char *ep, *e;
421 	register u_int d;
422 
423 	e = ep = (u_char *)malloc(6);
424 	if (e == NULL)
425 		return (NULL);
426 
427 	while (*s) {
428 		if (*s == ':' || *s == '.' || *s == '-')
429 			s += 1;
430 		d = xdtoi(*s++);
431 		if (isxdigit((unsigned char)*s)) {
432 			d <<= 4;
433 			d |= xdtoi(*s++);
434 		}
435 		*ep++ = d;
436 	}
437 
438 	return (e);
439 }
440 
441 #ifndef HAVE_ETHER_HOSTTON
442 /* Roll our own */
443 u_char *
444 pcap_ether_hostton(const char *name)
445 {
446 	register struct pcap_etherent *ep;
447 	register u_char *ap;
448 	static FILE *fp = NULL;
449 	static int init = 0;
450 
451 	if (!init) {
452 		fp = fopen(PCAP_ETHERS_FILE, "r");
453 		++init;
454 		if (fp == NULL)
455 			return (NULL);
456 	} else if (fp == NULL)
457 		return (NULL);
458 	else
459 		rewind(fp);
460 
461 	while ((ep = pcap_next_etherent(fp)) != NULL) {
462 		if (strcmp(ep->name, name) == 0) {
463 			ap = (u_char *)malloc(6);
464 			if (ap != NULL) {
465 				memcpy(ap, ep->addr, 6);
466 				return (ap);
467 			}
468 			break;
469 		}
470 	}
471 	return (NULL);
472 }
473 #else
474 
475 #if !defined(HAVE_DECL_ETHER_HOSTTON) || !HAVE_DECL_ETHER_HOSTTON
476 #ifndef HAVE_STRUCT_ETHER_ADDR
477 struct ether_addr {
478 	unsigned char ether_addr_octet[6];
479 };
480 #endif
481 extern int ether_hostton(const char *, struct ether_addr *);
482 #endif
483 
484 /* Use the os supplied routines */
485 u_char *
486 pcap_ether_hostton(const char *name)
487 {
488 	register u_char *ap;
489 	u_char a[6];
490 
491 	ap = NULL;
492 	if (ether_hostton(name, (struct ether_addr *)a) == 0) {
493 		ap = (u_char *)malloc(6);
494 		if (ap != NULL)
495 			memcpy((char *)ap, (char *)a, 6);
496 	}
497 	return (ap);
498 }
499 #endif
500 
501 u_short
502 __pcap_nametodnaddr(const char *name)
503 {
504 #ifdef	DECNETLIB
505 	struct nodeent *getnodebyname();
506 	struct nodeent *nep;
507 	unsigned short res;
508 
509 	nep = getnodebyname(name);
510 	if (nep == ((struct nodeent *)0))
511 		bpf_error("unknown decnet host name '%s'\n", name);
512 
513 	memcpy((char *)&res, (char *)nep->n_addr, sizeof(unsigned short));
514 	return(res);
515 #else
516 	bpf_error("decnet name support not included, '%s' cannot be translated\n",
517 		name);
518 	return(0);
519 #endif
520 }
521