2 * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
3 * The Regents of the University of California. All rights reserved.
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
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.
21 * Internet, ethernet, port, and protocol string to address
22 * and address to string conversion routines
27 static const char rcsid[] =
28 "@(#) $Header: /tcpdump/master/tcpdump/addrtoname.c,v 1.69.2.1 2001/01/17 18:29:58 guy Exp $ (LBL)";
35 #include <sys/types.h>
36 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #ifdef HAVE_NETINET_IF_ETHER_H
45 #include <netinet/if_ether.h>
48 #include <arpa/inet.h>
53 #include <pcap-namedb.h>
60 #include "interface.h"
61 #include "addrtoname.h"
64 #include "setsignal.h"
67 static RETSIGTYPE nohostname(int);
70 * hash tables for whatever-to-name translations
73 #define HASHNAMESIZE 4096
81 struct hnamemem hnametable[HASHNAMESIZE];
82 struct hnamemem tporttable[HASHNAMESIZE];
83 struct hnamemem uporttable[HASHNAMESIZE];
84 struct hnamemem eprototable[HASHNAMESIZE];
85 struct hnamemem dnaddrtable[HASHNAMESIZE];
86 struct hnamemem llcsaptable[HASHNAMESIZE];
92 struct h6namemem *nxt;
95 struct h6namemem h6nametable[HASHNAMESIZE];
103 u_char *e_nsap; /* used only for nsaptable[] */
104 struct enamemem *e_nxt;
107 struct enamemem enametable[HASHNAMESIZE];
108 struct enamemem nsaptable[HASHNAMESIZE];
114 struct protoidmem *p_nxt;
117 struct protoidmem protoidtable[HASHNAMESIZE];
120 * A faster replacement for inet_ntoa().
123 intoa(u_int32_t addr)
128 static char buf[sizeof(".xxx.xxx.xxx.xxx")];
131 cp = &buf[sizeof buf];
137 *--cp = byte % 10 + '0';
140 *--cp = byte % 10 + '0';
152 static u_int32_t f_netmask;
153 static u_int32_t f_localnet;
154 static u_int32_t netmask;
157 * "getname" is written in this atrocious way to make sure we don't
158 * wait forever while trying to get hostnames from yp.
165 nohostname(int signo)
167 longjmp(getname_env, 1);
171 * Return a name for the IP address pointed to by ap. This address
172 * is assumed to be in network byte order.
175 getname(const u_char *ap)
177 register struct hostent *hp;
179 static struct hnamemem *p; /* static for longjmp() */
182 addr = *(const u_int32_t *)ap;
184 memcpy(&addr, ap, sizeof(addr));
186 p = &hnametable[addr & (HASHNAMESIZE-1)];
187 for (; p->nxt; p = p->nxt) {
192 p->nxt = newhnamemem();
195 * Only print names when:
196 * (1) -n was not given.
197 * (2) Address is foreign and -f was given. (If -f was not
198 * give, f_netmask and f_local are 0 and the test
200 * (3) -a was given or the host portion is not all ones
201 * nor all zeros (i.e. not a network or broadcast address)
204 (addr & f_netmask) == f_localnet &&
206 !((addr & ~netmask) == 0 || (addr | netmask) == 0xffffffff))) {
207 if (!setjmp(getname_env)) {
208 (void)setsignal(SIGALRM, nohostname);
210 hp = gethostbyaddr((char *)&addr, 4, AF_INET);
215 p->name = savestr(hp->h_name);
217 /* Remove domain qualifications */
218 dotp = strchr(p->name, '.');
226 p->name = savestr(intoa(addr));
232 * Return a name for the IP6 address pointed to by ap. This address
233 * is assumed to be in network byte order.
236 getname6(const u_char *ap)
238 register struct hostent *hp;
239 struct in6_addr addr;
240 static struct h6namemem *p; /* static for longjmp() */
242 char ntop_buf[INET6_ADDRSTRLEN];
244 memcpy(&addr, ap, sizeof(addr));
245 p = &h6nametable[*(u_int16_t *)&addr.s6_addr[14] & (HASHNAMESIZE-1)];
246 for (; p->nxt; p = p->nxt) {
247 if (memcmp(&p->addr, &addr, sizeof(addr)) == 0)
251 p->nxt = newh6namemem();
254 * Only print names when:
255 * (1) -n was not given.
256 * (2) Address is foreign and -f was given. (If -f was not
257 * give, f_netmask and f_local are 0 and the test
259 * (3) -a was given or the host portion is not all ones
260 * nor all zeros (i.e. not a network or broadcast address)
265 (addr & f_netmask) == f_localnet &&
267 !((addr & ~netmask) == 0 || (addr | netmask) == 0xffffffff))
270 if (!setjmp(getname_env)) {
271 (void)setsignal(SIGALRM, nohostname);
273 hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET6);
278 p->name = savestr(hp->h_name);
280 /* Remove domain qualifications */
281 dotp = strchr(p->name, '.');
289 cp = (char *)inet_ntop(AF_INET6, &addr, ntop_buf, sizeof(ntop_buf));
290 p->name = savestr(cp);
295 static char hex[] = "0123456789abcdef";
298 /* Find the hash node that corresponds the ether address 'ep' */
300 static inline struct enamemem *
301 lookup_emem(const u_char *ep)
303 register u_int i, j, k;
306 k = (ep[0] << 8) | ep[1];
307 j = (ep[2] << 8) | ep[3];
308 i = (ep[4] << 8) | ep[5];
310 tp = &enametable[(i ^ j) & (HASHNAMESIZE-1)];
312 if (tp->e_addr0 == i &&
321 tp->e_nxt = (struct enamemem *)calloc(1, sizeof(*tp));
322 if (tp->e_nxt == NULL)
323 error("lookup_emem: calloc");
328 /* Find the hash node that corresponds the NSAP 'nsap' */
330 static inline struct enamemem *
331 lookup_nsap(register const u_char *nsap)
333 register u_int i, j, k;
336 const u_char *ensap = nsap + nlen - 6;
339 k = (ensap[0] << 8) | ensap[1];
340 j = (ensap[2] << 8) | ensap[3];
341 i = (ensap[4] << 8) | ensap[5];
346 tp = &nsaptable[(i ^ j) & (HASHNAMESIZE-1)];
348 if (tp->e_addr0 == i &&
351 tp->e_nsap[0] == nlen &&
352 memcmp((char *)&(nsap[1]),
353 (char *)&(tp->e_nsap[1]), nlen) == 0)
360 tp->e_nsap = (u_char *)malloc(nlen + 1);
361 if (tp->e_nsap == NULL)
362 error("lookup_nsap: malloc");
363 memcpy((char *)tp->e_nsap, (char *)nsap, nlen + 1);
364 tp->e_nxt = (struct enamemem *)calloc(1, sizeof(*tp));
365 if (tp->e_nxt == NULL)
366 error("lookup_nsap: calloc");
371 /* Find the hash node that corresponds the protoid 'pi'. */
373 static inline struct protoidmem *
374 lookup_protoid(const u_char *pi)
377 struct protoidmem *tp;
379 /* 5 octets won't be aligned */
380 i = (((pi[0] << 8) + pi[1]) << 8) + pi[2];
381 j = (pi[3] << 8) + pi[4];
382 /* XXX should be endian-insensitive, but do big-endian testing XXX */
384 tp = &protoidtable[(i ^ j) & (HASHNAMESIZE-1)];
386 if (tp->p_oui == i && tp->p_proto == j)
392 tp->p_nxt = (struct protoidmem *)calloc(1, sizeof(*tp));
393 if (tp->p_nxt == NULL)
394 error("lookup_protoid: calloc");
400 etheraddr_string(register const u_char *ep)
404 register struct enamemem *tp;
405 char buf[sizeof("00:00:00:00:00:00")];
407 tp = lookup_emem(ep);
410 #ifdef HAVE_ETHER_NTOHOST
413 if (ether_ntohost(buf, (struct ether_addr *)ep) == 0) {
414 tp->e_name = savestr(buf);
420 if ((j = *ep >> 4) != 0)
422 *cp++ = hex[*ep++ & 0xf];
423 for (i = 5; (int)--i >= 0;) {
425 if ((j = *ep >> 4) != 0)
427 *cp++ = hex[*ep++ & 0xf];
430 tp->e_name = savestr(buf);
435 etherproto_string(u_short port)
438 register struct hnamemem *tp;
439 register u_int32_t i = port;
440 char buf[sizeof("0000")];
442 for (tp = &eprototable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
447 tp->nxt = newhnamemem();
451 *cp++ = hex[port >> 12 & 0xf];
452 *cp++ = hex[port >> 8 & 0xf];
453 *cp++ = hex[port >> 4 & 0xf];
454 *cp++ = hex[port & 0xf];
456 tp->name = savestr(buf);
461 protoid_string(register const u_char *pi)
465 register struct protoidmem *tp;
466 char buf[sizeof("00:00:00:00:00")];
468 tp = lookup_protoid(pi);
473 if ((j = *pi >> 4) != 0)
475 *cp++ = hex[*pi++ & 0xf];
476 for (i = 4; (int)--i >= 0;) {
478 if ((j = *pi >> 4) != 0)
480 *cp++ = hex[*pi++ & 0xf];
483 tp->p_name = savestr(buf);
488 llcsap_string(u_char sap)
490 register struct hnamemem *tp;
491 register u_int32_t i = sap;
492 char buf[sizeof("sap 00")];
494 for (tp = &llcsaptable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
499 tp->nxt = newhnamemem();
501 snprintf(buf, sizeof(buf), "sap %02x", sap & 0xff);
502 tp->name = savestr(buf);
507 isonsap_string(const u_char *nsap)
509 register u_int i, nlen = nsap[0];
511 register struct enamemem *tp;
513 tp = lookup_nsap(nsap);
517 tp->e_name = cp = (char *)malloc(nlen * 2 + 2 + (nlen>>1));
519 error("isonsap_string: malloc");
522 for (i = 0; i < nlen; i++) {
523 *cp++ = hex[*nsap >> 4];
524 *cp++ = hex[*nsap++ & 0xf];
525 if (((i & 1) == 0) && (i + 1 < nlen))
533 tcpport_string(u_short port)
535 register struct hnamemem *tp;
536 register u_int32_t i = port;
537 char buf[sizeof("00000")];
539 for (tp = &tporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
544 tp->nxt = newhnamemem();
546 (void)snprintf(buf, sizeof(buf), "%u", i);
547 tp->name = savestr(buf);
552 udpport_string(register u_short port)
554 register struct hnamemem *tp;
555 register u_int32_t i = port;
556 char buf[sizeof("00000")];
558 for (tp = &uporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
563 tp->nxt = newhnamemem();
565 (void)snprintf(buf, sizeof(buf), "%u", i);
566 tp->name = savestr(buf);
574 register struct hnamemem *table;
576 char buf[sizeof("0000000000")];
578 while ((sv = getservent()) != NULL) {
579 int port = ntohs(sv->s_port);
580 i = port & (HASHNAMESIZE-1);
581 if (strcmp(sv->s_proto, "tcp") == 0)
582 table = &tporttable[i];
583 else if (strcmp(sv->s_proto, "udp") == 0)
584 table = &uporttable[i];
591 (void)snprintf(buf, sizeof(buf), "%d", port);
592 table->name = savestr(buf);
594 table->name = savestr(sv->s_name);
596 table->nxt = newhnamemem();
601 /*XXX from libbpfc.a */
602 extern struct eproto {
608 init_eprotoarray(void)
611 register struct hnamemem *table;
613 for (i = 0; eproto_db[i].s; i++) {
614 int j = ntohs(eproto_db[i].p) & (HASHNAMESIZE-1);
615 table = &eprototable[j];
618 table->name = eproto_db[i].s;
619 table->addr = ntohs(eproto_db[i].p);
620 table->nxt = newhnamemem();
625 * SNAP proto IDs with org code 0:0:0 are actually encapsulated Ethernet
629 init_protoidarray(void)
632 register struct protoidmem *tp;
638 for (i = 0; eproto_db[i].s; i++) {
639 u_short etype = htons(eproto_db[i].p);
641 memcpy((char *)&protoid[3], (char *)&etype, 2);
642 tp = lookup_protoid(protoid);
643 tp->p_name = savestr(eproto_db[i].s);
647 static struct etherlist {
651 {{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, "Broadcast" },
652 {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, NULL }
656 * Initialize the ethers hash table. We take two different approaches
657 * depending on whether or not the system provides the ethers name
658 * service. If it does, we just wire in a few names at startup,
659 * and etheraddr_string() fills in the table on demand. If it doesn't,
660 * then we suck in the entire /etc/ethers file at startup. The idea
661 * is that parsing the local file will be fast, but spinning through
662 * all the ethers entries via NIS & next_etherent might be very slow.
664 * XXX pcap_next_etherent doesn't belong in the pcap interface, but
665 * since the pcap module already does name-to-address translation,
666 * it's already does most of the work for the ethernet address-to-name
667 * translation, so we just pcap_next_etherent as a convenience.
670 init_etherarray(void)
672 register struct etherlist *el;
673 register struct enamemem *tp;
674 #ifdef HAVE_ETHER_NTOHOST
677 register struct pcap_etherent *ep;
680 /* Suck in entire ethers file */
681 fp = fopen(PCAP_ETHERS_FILE, "r");
683 while ((ep = pcap_next_etherent(fp)) != NULL) {
684 tp = lookup_emem(ep->addr);
685 tp->e_name = savestr(ep->name);
691 /* Hardwire some ethernet names */
692 for (el = etherlist; el->name != NULL; ++el) {
693 tp = lookup_emem(el->addr);
694 /* Don't override existing name */
695 if (tp->e_name != NULL)
698 #ifdef HAVE_ETHER_NTOHOST
699 /* Use yp/nis version of name if available */
700 if (ether_ntohost(name, (struct ether_addr *)el->addr) == 0) {
701 tp->e_name = savestr(name);
705 tp->e_name = el->name;
709 static struct tok llcsap_db[] = {
710 { LLCSAP_NULL, "null" },
711 { LLCSAP_8021B_I, "802.1b-gsap" },
712 { LLCSAP_8021B_G, "802.1b-isap" },
713 { LLCSAP_IP, "ip-sap" },
714 { LLCSAP_PROWAYNM, "proway-nm" },
715 { LLCSAP_8021D, "802.1d" },
716 { LLCSAP_RS511, "eia-rs511" },
717 { LLCSAP_ISO8208, "x.25/llc2" },
718 { LLCSAP_PROWAY, "proway" },
719 { LLCSAP_ISONS, "iso-clns" },
720 { LLCSAP_GLOBAL, "global" },
725 init_llcsaparray(void)
728 register struct hnamemem *table;
730 for (i = 0; llcsap_db[i].s != NULL; i++) {
731 table = &llcsaptable[llcsap_db[i].v];
734 table->name = llcsap_db[i].s;
735 table->addr = llcsap_db[i].v;
736 table->nxt = newhnamemem();
741 * Initialize the address to name translation machinery. We map all
742 * non-local IP addresses to numeric addresses if fflag is true (i.e.,
743 * to prevent blocking on the nameserver). localnet is the IP address
744 * of the local network. mask is its subnet mask.
747 init_addrtoname(u_int32_t localnet, u_int32_t mask)
751 f_localnet = localnet;
756 * Simplest way to suppress names.
768 dnaddr_string(u_short dnaddr)
770 register struct hnamemem *tp;
772 for (tp = &dnaddrtable[dnaddr & (HASHNAMESIZE-1)]; tp->nxt != 0;
774 if (tp->addr == dnaddr)
778 tp->nxt = newhnamemem();
780 tp->name = dnnum_string(dnaddr);
782 tp->name = dnname_string(dnaddr);
787 /* Return a zero'ed hnamemem struct and cuts down on calloc() overhead */
791 register struct hnamemem *p;
792 static struct hnamemem *ptr = NULL;
793 static u_int num = 0;
797 ptr = (struct hnamemem *)calloc(num, sizeof (*ptr));
799 error("newhnamemem: calloc");
807 /* Return a zero'ed h6namemem struct and cuts down on calloc() overhead */
811 register struct h6namemem *p;
812 static struct h6namemem *ptr = NULL;
813 static u_int num = 0;
817 ptr = (struct h6namemem *)calloc(num, sizeof (*ptr));
819 error("newh6namemem: calloc");