/* * Copyright (c) 1993-1997 JSC Rinet, Novosibirsk, Russia * * Redistribution and use in source forms, with and without modification, * are permitted provided that this entire comment appears intact. * Redistribution in binary form may occur without any restrictions. * * THIS SOFTWARE IS PROVIDED ``AS IS'' WITHOUT ANY WARRANTIES OF ANY KIND. */ /* addrtoname.c -- address to name translation routines */ /* Portions of this software may fall under the following copyrights: */ /* * Copyright (c) 1988, 1990 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code distributions * retain the above copyright notice and this paragraph in its entirety, (2) * distributions including binary code include the above copyright notice and * this paragraph in its entirety in the documentation or other materials * provided with the distribution, and (3) all advertising materials mentioning * features or use of this software display the following acknowledgement: * ``This product includes software developed by the University of California, * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of * the University nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior * written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Internet, ethernet, port, and protocol string to address * and address to string conversion routines */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #ifdef TIME_WITH_SYS_TIME #include #endif #include "trafshow.h" typedef void (*sigfunc) (); /* Hash tables for whatever-to-name translations */ #define HASHNAMESIZE 4096 /* IP level */ struct hnamemem { u_int32_t addr; char *name; struct hnamemem *nxt; }; struct hnamemem hnametable[HASHNAMESIZE]; struct hnamemem tporttable[HASHNAMESIZE]; struct hnamemem uporttable[HASHNAMESIZE]; /* Ethernet level */ struct enamemem { u_short addr0; u_short addr1; u_short addr2; char *name; struct enamemem *nxt; }; struct enamemem enametable[HASHNAMESIZE]; struct hnamemem eprototable[HASHNAMESIZE]; static u_int32_t f_netmask; static u_int32_t f_localnet; static u_int32_t netmask; /* * A faster replacement for inet_ntoa(). */ char * intoa(addr) u_int32_t addr; { register char *cp; register u_int byte; register int n; static char buf[sizeof(".xxx.xxx.xxx.xxx")]; addr = ntohl(addr); cp = &buf[sizeof buf]; *--cp = '\0'; n = 4; do { byte = addr & 0xff; *--cp = byte % 10 + '0'; byte /= 10; if (byte > 0) { *--cp = byte % 10 + '0'; byte /= 10; if (byte > 0) *--cp = byte + '0'; } *--cp = '.'; addr >>= 8; } while (--n > 0); return cp + 1; } /* Return a zero'ed hnamemem struct and cuts down on calloc() overhead */ struct hnamemem * newhnamemem() { register struct hnamemem *p; static struct hnamemem *ptr = NULL; static u_int num = 0; if (num <= 0) { num = 64; ptr = (struct hnamemem *)calloc(num, sizeof (*ptr)); if (ptr == NULL) error(1, "newhnamemem: calloc"); } --num; p = ptr++; return (p); } /* A replacement for strdup() that cuts down on malloc() overhead */ char * savestr(str) register const char *str; { register u_int size; register char *p; static char *strptr = NULL; static u_int strsize = 0; size = strlen(str) + 1; if (size > strsize) { strsize = 1024; if (strsize < size) strsize = size; strptr = (char *)malloc(strsize); if (strptr == NULL) error(1, "savestr: malloc"); } (void)strcpy(strptr, str); p = strptr; strptr += size; strsize -= size; return (p); } /* * "getname" is written in this atrocious way to make sure we don't * wait forever while trying to get hostnames from yp. */ #ifdef HAVE_SIGINTERRUPT /* BSD signal semantics */ #include jmp_buf getname_env; static void nohostname() { longjmp(getname_env, 1); } #else /* SYSV */ static void nohostname() { /* empty */ } #endif /* * Return a name for the IP address pointed to by ap. This address * is assumed to be in network byte order. */ char * getname(ap) u_char *ap; { register char *cp; u_int32_t addr; /* static for longjmp */ static struct hostent *hp; static struct hnamemem *p; static int oldtimer; static sigfunc oldalarm; #ifndef LBL_ALIGN addr = *(const u_int32_t *)ap; #else /* * Extract 32 bits in network order, dealing with alignment. */ switch ((long)ap & 3) { case 0: addr = *(u_int32_t *)ap; break; case 2: #ifdef WORDS_BIGENDIAN addr = ((u_int32_t)*(u_short *)ap << 16) | (u_int32_t)*(u_short *)(ap + 2); #else addr = ((u_int32_t)*(u_short *)(ap + 2) << 16) | (u_int32_t)*(u_short *)ap; #endif break; default: #ifdef WORDS_BIGENDIAN addr = ((u_int32_t)ap[0] << 24) | ((u_int32_t)ap[1] << 16) | ((u_int32_t)ap[2] << 8) | (u_int32_t)ap[3]; #else addr = ((u_int32_t)ap[3] << 24) | ((u_int32_t)ap[2] << 16) | ((u_int32_t)ap[1] << 8) | (u_int32_t)ap[0]; #endif break; } #endif for (p = &hnametable[addr & (HASHNAMESIZE-1)]; p->nxt; p = p->nxt) if (p->addr == addr) return (p->name); p->addr = addr; p->nxt = newhnamemem(); hp = NULL; /* * Only print names when: * (1) -n was not given. * (2) Address is foreign and -f was given. If -f was not * present, f_netmask and f_local are 0 and the second * test will succeed. * (3) The host portion is not 0 (i.e., a network address). * (4) The host portion is not broadcast. */ if (!nflag && (addr & f_netmask) == f_localnet && (addr &~ netmask) != 0 && (addr | netmask) != 0xffffffff) { oldtimer = alarm(dns_timeout); oldalarm = signal(SIGALRM, nohostname); #ifdef HAVE_SIGINTERRUPT if (!setjmp(getname_env)) #endif hp = gethostbyaddr((char *)&addr, 4, AF_INET); (void)signal(SIGALRM, oldalarm); if (oldtimer < 1) oldtimer = 1; (void)alarm(oldtimer); } if (hp) { if (Nflag && (cp = strchr(hp->h_name, '.')) != NULL) *cp = '\0'; cp = hp->h_name; } else cp = intoa(addr); p->name = savestr(cp); return p->name; } char * tcpport_string(port) u_short port; { register struct hnamemem *tp; register u_int32_t i = port; char buf[sizeof("00000")]; for (tp = &tporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt) if (tp->addr == i) return (tp->name); tp->addr = i; tp->nxt = newhnamemem(); (void)sprintf(buf, "%u", i); tp->name = savestr(buf); return (tp->name); } char * udpport_string(port) u_short port; { register struct hnamemem *tp; register u_int32_t i = port; char buf[sizeof("00000")]; for (tp = &uporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt) if (tp->addr == i) return (tp->name); tp->addr = i; tp->nxt = newhnamemem(); (void)sprintf(buf, "%u", i); tp->name = savestr(buf); return (tp->name); } static void init_servarray() { struct servent *sv; register struct hnamemem *table; register int i; char buf[sizeof("0000000000")]; while ((sv = getservent()) != NULL) { int port = ntohs(sv->s_port); i = port & (HASHNAMESIZE-1); if (strcmp(sv->s_proto, "tcp") == 0) table = &tporttable[i]; else if (strcmp(sv->s_proto, "udp") == 0) table = &uporttable[i]; else continue; while (table->name) table = table->nxt; if (nflag) { (void)sprintf(buf, "%d", port); table->name = savestr(buf); } else table->name = savestr(sv->s_name); table->addr = port; table->nxt = newhnamemem(); } endservent(); } static char hex[] = "0123456789abcdef"; char * entoa(ep) register u_char *ep; { register u_int i, j; register char *cp; static char buf[sizeof("00:00:00:00:00:00")]; cp = buf; if ((j = *ep >> 4) != 0) *cp++ = hex[j]; *cp++ = hex[*ep++ & 0xf]; for (i = 5; (int)--i >= 0;) { *cp++ = ':'; if ((j = *ep >> 4) != 0) *cp++ = hex[j]; *cp++ = hex[*ep++ & 0xf]; } *cp = '\0'; return buf; } char * etheraddr_string(ep) register u_char *ep; { register u_int i, j, k; register struct enamemem *tp; u_char *ap; k = (ep[0] << 8) | ep[1]; j = (ep[2] << 8) | ep[3]; i = (ep[4] << 8) | ep[5]; for (tp = &enametable[(i ^ j) & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt) if (tp->addr0 == i && tp->addr1 == j && tp->addr2 == k) return (tp->name); tp->addr0 = i; tp->addr1 = j; tp->addr2 = k; tp->nxt = (struct enamemem *)calloc(1, sizeof(*tp)); if (tp->nxt == NULL) error(1, "etheraddr_string: calloc"); if ((ap = getarptab(ep)) != NULL) ap = getname(ap); else ap = entoa(ep); tp->name = savestr(ap); return (tp->name); } char * etherproto_string(proto) u_short proto; { register char *cp; register struct hnamemem *tp; register u_int32_t i = proto; char buf[sizeof("0000")]; for (tp = &eprototable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt) if (tp->addr == i) return (tp->name); tp->addr = i; tp->nxt = newhnamemem(); cp = buf; proto = ntohs(proto); *cp++ = hex[proto >> 12 & 0xf]; *cp++ = hex[proto >> 8 & 0xf]; *cp++ = hex[proto >> 4 & 0xf]; *cp++ = hex[proto & 0xf]; *cp++ = '\0'; tp->name = savestr(buf); return (tp->name); } /* XXX from pcap library */ extern struct eproto { char *s; u_short p; } eproto_db[]; static void init_eprotoarray() { register int i; register struct hnamemem *tp; for (i = 0; eproto_db[i].s; i++) { for (tp = &eprototable[ntohs(eproto_db[i].p) & (HASHNAMESIZE-1)]; tp->name; tp = tp->nxt) ; tp->name = eproto_db[i].s; tp->addr = ntohs(eproto_db[i].p); tp->nxt = newhnamemem(); } } /* * Initialize the address to name translation machinery. We map all * non-local IP addresses to numeric addresses if fflag is true (i.e., * to prevent blocking on the nameserver). localnet is the IP address * of the local network. mask is its subnet mask. */ void init_addrtoname(localnet, mask) u_int32_t localnet; u_int32_t mask; { netmask = mask; if (fflag) { f_localnet = localnet; f_netmask = mask; } if (nflag) /* * Simplest way to suppress names. */ return; init_servarray(); init_eprotoarray(); }