xref: /openbsd-src/lib/libpcap/nametoaddr.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*	$OpenBSD: nametoaddr.c,v 1.9 2002/02/19 19:39:37 millert Exp $	*/
2 
3 /*
4  * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996
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 #ifndef lint
28 static const char rcsid[] =
29     "@(#) $Header: /home/cvs/src/lib/libpcap/nametoaddr.c,v 1.9 2002/02/19 19:39:37 millert Exp $ (LBL)";
30 #endif
31 
32 #include <sys/param.h>
33 #include <sys/types.h>				/* concession to AIX */
34 #include <sys/socket.h>
35 #include <sys/time.h>
36 
37 struct mbuf;
38 struct rtentry;
39 
40 #include <net/if.h>
41 #include <netinet/in.h>
42 #include <netinet/if_ether.h>
43 #include <arpa/inet.h>
44 #ifdef INET6
45 #include <netdb.h>
46 #include <sys/socket.h>
47 #endif /*INET6*/
48 
49 #include <ctype.h>
50 #include <errno.h>
51 #include <stdlib.h>
52 #include <memory.h>
53 #include <netdb.h>
54 #include <stdio.h>
55 
56 #include "pcap-int.h"
57 
58 #include "gencode.h"
59 #include <pcap-namedb.h>
60 
61 #ifdef HAVE_OS_PROTO_H
62 #include "os-proto.h"
63 #endif
64 
65 #ifndef NTOHL
66 #define NTOHL(x) (x) = ntohl(x)
67 #define NTOHS(x) (x) = ntohs(x)
68 #endif
69 
70 static __inline int xdtoi(int);
71 
72 /*
73  *  Convert host name to internet address.
74  *  Return 0 upon failure.
75  */
76 bpf_u_int32 **
77 pcap_nametoaddr(const char *name)
78 {
79 #ifndef h_addr
80 	static bpf_u_int32 *hlist[2];
81 #endif
82 	bpf_u_int32 **p;
83 	struct hostent *hp;
84 
85 	if ((hp = gethostbyname(name)) != NULL) {
86 #ifndef h_addr
87 		hlist[0] = (bpf_u_int32 *)hp->h_addr;
88 		NTOHL(hp->h_addr);
89 		return hlist;
90 #else
91 		for (p = (bpf_u_int32 **)hp->h_addr_list; *p; ++p)
92 			NTOHL(**p);
93 		return (bpf_u_int32 **)hp->h_addr_list;
94 #endif
95 	}
96 	else
97 		return 0;
98 }
99 
100 #ifdef INET6
101 struct addrinfo *
102 pcap_nametoaddrinfo(const char *name)
103 {
104 	struct addrinfo hints, *res;
105 	int error;
106 
107 	memset(&hints, 0, sizeof(hints));
108 	hints.ai_family = PF_UNSPEC;
109 	hints.ai_socktype = SOCK_STREAM;	/*not really*/
110 	error = getaddrinfo(name, NULL, &hints, &res);
111 	if (error)
112 		return NULL;
113 	else
114 		return res;
115 }
116 #endif /*INET6*/
117 
118 /*
119  *  Convert net name to internet address.
120  *  Return 0 upon failure.
121  */
122 bpf_u_int32
123 pcap_nametonetaddr(const char *name)
124 {
125 	struct netent *np;
126 
127 	if ((np = getnetbyname(name)) != NULL)
128 		return np->n_net;
129 	else
130 		return 0;
131 }
132 
133 /*
134  * Convert a port name to its port and protocol numbers.
135  * We assume only TCP or UDP.
136  * Return 0 upon failure.
137  */
138 int
139 pcap_nametoport(const char *name, int *port, int *proto)
140 {
141 	struct servent *sp;
142 	char *other;
143 
144 	sp = getservbyname(name, (char *)0);
145 	if (sp != NULL) {
146 		NTOHS(sp->s_port);
147 		*port = sp->s_port;
148 		*proto = pcap_nametoproto(sp->s_proto);
149 		/*
150 		 * We need to check /etc/services for ambiguous entries.
151 		 * If we find the ambiguous entry, and it has the
152 		 * same port number, change the proto to PROTO_UNDEF
153 		 * so both TCP and UDP will be checked.
154 		 */
155 		if (*proto == IPPROTO_TCP)
156 			other = "udp";
157 		else
158 			other = "tcp";
159 
160 		sp = getservbyname(name, other);
161 		if (sp != 0) {
162 			NTOHS(sp->s_port);
163 #ifdef notdef
164 			if (*port != sp->s_port)
165 				/* Can't handle ambiguous names that refer
166 				   to different port numbers. */
167 				warning("ambiguous port %s in /etc/services",
168 					name);
169 #endif
170 			*proto = PROTO_UNDEF;
171 		}
172 		return 1;
173 	}
174 #if defined(ultrix) || defined(__osf__)
175 	/* Special hack in case NFS isn't in /etc/services */
176 	if (strcmp(name, "nfs") == 0) {
177 		*port = 2049;
178 		*proto = PROTO_UNDEF;
179 		return 1;
180 	}
181 #endif
182 	return 0;
183 }
184 
185 int
186 pcap_nametoproto(const char *str)
187 {
188 	struct protoent *p;
189 
190 	p = getprotobyname(str);
191 	if (p != 0)
192 		return p->p_proto;
193 	else
194 		return PROTO_UNDEF;
195 }
196 
197 #include "ethertype.h"
198 
199 struct eproto {
200 	char *s;
201 	u_short p;
202 };
203 
204 /* Static data base of ether protocol types. */
205 struct eproto eproto_db[] = {
206 	{ "pup", ETHERTYPE_PUP },
207 	{ "xns", ETHERTYPE_NS },
208 	{ "ip", ETHERTYPE_IP },
209 #ifdef INET6
210 	{ "ip6", ETHERTYPE_IPV6 },
211 #endif
212 	{ "arp", ETHERTYPE_ARP },
213 	{ "rarp", ETHERTYPE_REVARP },
214 	{ "sprite", ETHERTYPE_SPRITE },
215 	{ "mopdl", ETHERTYPE_MOPDL },
216 	{ "moprc", ETHERTYPE_MOPRC },
217 	{ "decnet", ETHERTYPE_DN },
218 	{ "lat", ETHERTYPE_LAT },
219 	{ "sca", ETHERTYPE_SCA },
220 	{ "lanbridge", ETHERTYPE_LANBRIDGE },
221 	{ "vexp", ETHERTYPE_VEXP },
222 	{ "vprod", ETHERTYPE_VPROD },
223 	{ "atalk", ETHERTYPE_ATALK },
224 	{ "atalkarp", ETHERTYPE_AARP },
225 	{ "loopback", ETHERTYPE_LOOPBACK },
226 	{ "decdts", ETHERTYPE_DECDTS },
227 	{ "decdns", ETHERTYPE_DECDNS },
228 	{ (char *)0, 0 }
229 };
230 
231 int
232 pcap_nametoeproto(const char *s)
233 {
234 	struct eproto *p = eproto_db;
235 
236 	while (p->s != 0) {
237 		if (strcmp(p->s, s) == 0)
238 			return p->p;
239 		p += 1;
240 	}
241 	return PROTO_UNDEF;
242 }
243 
244 /* Hex digit to integer. */
245 static __inline int
246 xdtoi(c)
247 	register int c;
248 {
249 	if (isdigit(c))
250 		return c - '0';
251 	else if (islower(c))
252 		return c - 'a' + 10;
253 	else
254 		return c - 'A' + 10;
255 }
256 
257 int
258 __pcap_atoin(const char *s, bpf_u_int32 *addr)
259 {
260 	u_int n;
261 	int len;
262 
263 	*addr = 0;
264 	len = 0;
265 	while (1) {
266 		n = 0;
267 		while (*s && *s != '.')
268 			n = n * 10 + *s++ - '0';
269 		*addr <<= 8;
270 		*addr |= n & 0xff;
271 		len += 8;
272 		if (*s == '\0')
273 			return len;
274 		++s;
275 	}
276 	/* NOTREACHED */
277 }
278 
279 int
280 __pcap_atodn(const char *s, bpf_u_int32 *addr)
281 {
282 #define AREASHIFT 10
283 #define AREAMASK 0176000
284 #define NODEMASK 01777
285 
286 	u_int node, area;
287 
288 	if (sscanf((char *)s, "%d.%d", &area, &node) != 2)
289 		bpf_error("malformed decnet address '%s'", s);
290 
291 	*addr = (area << AREASHIFT) & AREAMASK;
292 	*addr |= (node & NODEMASK);
293 
294 	return(32);
295 }
296 
297 /*
298  * Convert 's' which has the form "xx:xx:xx:xx:xx:xx" into a new
299  * ethernet address.  Assumes 's' is well formed.
300  */
301 u_char *
302 pcap_ether_aton(const char *s)
303 {
304 	register u_char *ep, *e;
305 	register u_int d;
306 
307 	e = ep = (u_char *)malloc(6);
308 
309 	while (*s) {
310 		if (*s == ':')
311 			s += 1;
312 		d = xdtoi(*s++);
313 		if (isxdigit(*s)) {
314 			d <<= 4;
315 			d |= xdtoi(*s++);
316 		}
317 		*ep++ = d;
318 	}
319 
320 	return (e);
321 }
322 
323 #ifndef HAVE_ETHER_HOSTTON
324 /* Roll our own */
325 u_char *
326 pcap_ether_hostton(const char *name)
327 {
328 	register struct pcap_etherent *ep;
329 	register u_char *ap;
330 	static FILE *fp = NULL;
331 	static init = 0;
332 
333 	if (!init) {
334 		fp = fopen(PCAP_ETHERS_FILE, "r");
335 		++init;
336 		if (fp == NULL)
337 			return (NULL);
338 	} else if (fp == NULL)
339 		return (NULL);
340 	else
341 		rewind(fp);
342 
343 	while ((ep = pcap_next_etherent(fp)) != NULL) {
344 		if (strcmp(ep->name, name) == 0) {
345 			ap = (u_char *)malloc(6);
346 			if (ap != NULL) {
347 				memcpy(ap, ep->addr, 6);
348 				return (ap);
349 			}
350 			break;
351 		}
352 	}
353 	return (NULL);
354 }
355 #else
356 
357 #if !defined(sgi) && !defined(__NetBSD__)
358 extern int ether_hostton(char *, struct ether_addr *);
359 #endif
360 
361 /* Use the os supplied routines */
362 u_char *
363 pcap_ether_hostton(const char *name)
364 {
365 	register u_char *ap;
366 	u_char a[6];
367 
368 	ap = NULL;
369 	if (ether_hostton((char *)name, (struct ether_addr *)a) == 0) {
370 		ap = (u_char *)malloc(6);
371 		if (ap != NULL)
372 			memcpy((char *)ap, (char *)a, 6);
373 	}
374 	return (ap);
375 }
376 #endif
377 
378 u_short
379 __pcap_nametodnaddr(const char *name)
380 {
381 #ifdef	DECNETLIB
382 	struct nodeent *getnodebyname();
383 	struct nodeent *nep;
384 	unsigned short res;
385 
386 	nep = getnodebyname(name);
387 	if (nep == ((struct nodeent *)0))
388 		bpf_error("unknown decnet host name '%s'\n", name);
389 
390 	memcpy((char *)&res, (char *)nep->n_addr, sizeof(unsigned short));
391 	return(res);
392 #else
393 	bpf_error("decnet name support not included, '%s' cannot be translated\n",
394 		name);
395 	/* NOTREACHED */
396 #ifdef lint
397 	/*
398 	 * Arguably, lint should assume that functions which don't return
399 	 * (i.e. that contain no return statements and whose ends are
400 	 * unreachable) actually return a value, so callers won't get
401 	 * warnings for using that value (since they won't actually
402 	 * be doing so).  However, most lints don't seem to do that...
403 	 */
404 	return (0);
405 #endif
406 #endif
407 }
408