/*
* 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 <config.h>
#endif
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <netdb.h>
#ifdef TIME_WITH_SYS_TIME
#include <time.h>
#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 <setjmp.h>
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();
}
syntax highlighted by Code2HTML, v. 0.9.1