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