481 lines
10 KiB
C
481 lines
10 KiB
C
/*
|
|
* 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
|
|
*
|
|
* $Id: addrtoname.c,v 1.1 1993/11/14 21:19:55 deraadt Exp $
|
|
*/
|
|
#ifndef lint
|
|
static char rcsid[] =
|
|
"@(#) Header: addrtoname.c,v 1.14 92/05/25 14:29:07 mccanne Exp (LBL)";
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <strings.h>
|
|
#include <ctype.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <net/if.h>
|
|
#include <netdb.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/if_ether.h>
|
|
#include <arpa/inet.h>
|
|
#include <signal.h>
|
|
|
|
#include "interface.h"
|
|
#include "addrtoname.h"
|
|
#include "nametoaddr.h"
|
|
#include "etherent.h"
|
|
|
|
/*
|
|
* hash tables for whatever-to-name translations
|
|
*/
|
|
|
|
#define HASHNAMESIZE 4096
|
|
|
|
struct hnamemem {
|
|
u_long addr;
|
|
char *name;
|
|
struct hnamemem *nxt;
|
|
};
|
|
|
|
struct hnamemem hnametable[HASHNAMESIZE];
|
|
struct hnamemem tporttable[HASHNAMESIZE];
|
|
struct hnamemem uporttable[HASHNAMESIZE];
|
|
struct hnamemem eprototable[HASHNAMESIZE];
|
|
|
|
struct enamemem {
|
|
u_short e_addr0;
|
|
u_short e_addr1;
|
|
u_short e_addr2;
|
|
char *e_name;
|
|
struct enamemem *e_nxt;
|
|
};
|
|
|
|
struct enamemem enametable[HASHNAMESIZE];
|
|
|
|
|
|
/*
|
|
* A faster replacement for inet_ntoa().
|
|
*/
|
|
char *
|
|
intoa(addr)
|
|
u_long addr;
|
|
{
|
|
register char *cp;
|
|
register u_int byte;
|
|
register int n;
|
|
static char buf[sizeof(".xxx.xxx.xxx.xxx")];
|
|
|
|
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;
|
|
}
|
|
|
|
static u_long f_netmask;
|
|
static u_long f_localnet;
|
|
static u_long netmask;
|
|
|
|
/*
|
|
* "getname" is written in this atrocious way to make sure we don't
|
|
* wait forever while trying to get hostnames from yp.
|
|
*/
|
|
#include <setjmp.h>
|
|
|
|
jmp_buf getname_env;
|
|
|
|
static void
|
|
nohostname()
|
|
{
|
|
longjmp(getname_env, 1);
|
|
}
|
|
|
|
/*
|
|
* 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 struct hnamemem *p;
|
|
register struct hostent *hp;
|
|
register char *cp;
|
|
u_long addr;
|
|
|
|
#ifndef TCPDUMP_ALIGN
|
|
addr = *(u_long *)ap;
|
|
#else
|
|
/*
|
|
* Deal with alignment.
|
|
*/
|
|
switch ((int)ap & 3) {
|
|
|
|
case 0:
|
|
addr = *(u_long *)ap;
|
|
break;
|
|
|
|
case 2:
|
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
|
addr = ((u_long)*(u_short *)(ap + 2) << 16) |
|
|
(u_long)*(u_short *)ap;
|
|
#else
|
|
addr = ((u_long)*(u_short *)ap << 16) |
|
|
(u_long)*(u_short *)(ap + 2);
|
|
#endif
|
|
break;
|
|
|
|
default:
|
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
|
addr = ((u_long)ap[0] << 24) |
|
|
((u_long)ap[1] << 16) |
|
|
((u_long)ap[2] << 8) |
|
|
(u_long)ap[3];
|
|
#else
|
|
addr = ((u_long)ap[3] << 24) |
|
|
((u_long)ap[2] << 16) |
|
|
((u_long)ap[1] << 8) |
|
|
(u_long)ap[0];
|
|
#endif
|
|
break;
|
|
}
|
|
#endif
|
|
p = &hnametable[addr & (HASHNAMESIZE-1)];
|
|
for (; p->nxt; p = p->nxt) {
|
|
if (p->addr == addr)
|
|
return (p->name);
|
|
}
|
|
p->addr = addr;
|
|
p->nxt = (struct hnamemem *)calloc(1, sizeof (*p));
|
|
|
|
/*
|
|
* 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) {
|
|
if (!setjmp(getname_env)) {
|
|
(void)signal(SIGALRM, nohostname);
|
|
(void)alarm(20);
|
|
hp = gethostbyaddr((char *)&addr, 4, AF_INET);
|
|
(void)alarm(0);
|
|
if (hp) {
|
|
char *index();
|
|
char *dotp;
|
|
u_int len = strlen(hp->h_name) + 1;
|
|
p->name = (char *)malloc(len);
|
|
(void)strcpy(p->name, hp->h_name);
|
|
if (Nflag) {
|
|
/* Remove domain qualifications */
|
|
dotp = index(p->name, '.');
|
|
if (dotp)
|
|
*dotp = 0;
|
|
}
|
|
return (p->name);
|
|
}
|
|
}
|
|
}
|
|
cp = intoa(addr);
|
|
p->name = (char *)malloc((unsigned)(strlen(cp) + 1));
|
|
(void)strcpy(p->name, cp);
|
|
return (p->name);
|
|
}
|
|
|
|
static char hex[] = "0123456789abcdef";
|
|
|
|
|
|
/* Find the hash node that corresponds the ether address 'ep'. */
|
|
|
|
static inline struct enamemem *
|
|
lookup_emem(ep)
|
|
u_char *ep;
|
|
{
|
|
register u_int i, j, k;
|
|
struct enamemem *tp;
|
|
|
|
k = (ep[0] << 8) | ep[1];
|
|
j = (ep[2] << 8) | ep[3];
|
|
i = (ep[4] << 8) | ep[5];
|
|
|
|
tp = &enametable[(i ^ j) & (HASHNAMESIZE-1)];
|
|
while (tp->e_nxt)
|
|
if (tp->e_addr0 == i &&
|
|
tp->e_addr1 == j &&
|
|
tp->e_addr2 == k)
|
|
return tp;
|
|
else
|
|
tp = tp->e_nxt;
|
|
tp->e_addr0 = i;
|
|
tp->e_addr1 = j;
|
|
tp->e_addr2 = k;
|
|
tp->e_nxt = (struct enamemem *)calloc(1, sizeof(*tp));
|
|
|
|
return tp;
|
|
}
|
|
|
|
char *
|
|
etheraddr_string(ep)
|
|
register u_char *ep;
|
|
{
|
|
register u_int i, j;
|
|
register char *cp;
|
|
register struct enamemem *tp;
|
|
|
|
tp = lookup_emem(ep);
|
|
if (tp->e_name)
|
|
return tp->e_name;
|
|
|
|
#ifdef ETHER_SERVICE
|
|
if (!nflag) {
|
|
cp = ETHER_ntohost(ep);
|
|
if (cp) {
|
|
tp->e_name = cp;
|
|
return cp;
|
|
}
|
|
}
|
|
#endif
|
|
tp->e_name = cp = (char *)malloc(sizeof("00:00:00:00:00:00"));
|
|
|
|
if (j = *ep >> 4)
|
|
*cp++ = hex[j];
|
|
*cp++ = hex[*ep++ & 0xf];
|
|
for (i = 5; (int)--i >= 0;) {
|
|
*cp++ = ':';
|
|
if (j = *ep >> 4)
|
|
*cp++ = hex[j];
|
|
*cp++ = hex[*ep++ & 0xf];
|
|
}
|
|
*cp = '\0';
|
|
return (tp->e_name);
|
|
}
|
|
|
|
char *
|
|
etherproto_string(port)
|
|
u_short port;
|
|
{
|
|
register char *cp;
|
|
register struct hnamemem *tp;
|
|
register u_long i = port;
|
|
|
|
for (tp = &eprototable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
|
|
if (tp->addr == i)
|
|
return (tp->name);
|
|
|
|
tp->name = cp = (char *)malloc(sizeof("0000"));
|
|
tp->addr = i;
|
|
tp->nxt = (struct hnamemem *)calloc(1, sizeof (*tp));
|
|
|
|
NTOHS(port);
|
|
*cp++ = hex[port >> 12 & 0xf];
|
|
*cp++ = hex[port >> 8 & 0xf];
|
|
*cp++ = hex[port >> 4 & 0xf];
|
|
*cp++ = hex[port & 0xf];
|
|
*cp++ = '\0';
|
|
return (tp->name);
|
|
}
|
|
|
|
char *
|
|
tcpport_string(port)
|
|
u_short port;
|
|
{
|
|
register struct hnamemem *tp;
|
|
register int i = port;
|
|
|
|
for (tp = &tporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
|
|
if (tp->addr == i)
|
|
return (tp->name);
|
|
|
|
tp->name = (char *)malloc(sizeof("00000"));
|
|
tp->addr = i;
|
|
tp->nxt = (struct hnamemem *)calloc(1, sizeof (*tp));
|
|
|
|
(void)sprintf(tp->name, "%d", i);
|
|
return (tp->name);
|
|
}
|
|
|
|
char *
|
|
udpport_string(port)
|
|
register u_short port;
|
|
{
|
|
register struct hnamemem *tp;
|
|
register int i = port;
|
|
|
|
for (tp = &uporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
|
|
if (tp->addr == i)
|
|
return (tp->name);
|
|
|
|
tp->name = (char *)malloc(sizeof("00000"));
|
|
tp->addr = i;
|
|
tp->nxt = (struct hnamemem *)calloc(1, sizeof(*tp));
|
|
|
|
(void)sprintf(tp->name, "%d", i);
|
|
|
|
return (tp->name);
|
|
}
|
|
|
|
static void
|
|
init_servarray()
|
|
{
|
|
struct servent *sv;
|
|
register struct hnamemem *table;
|
|
register int i;
|
|
|
|
while (sv = getservent()) {
|
|
NTOHS(sv->s_port);
|
|
i = sv->s_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) {
|
|
char buf[32];
|
|
|
|
(void)sprintf(buf, "%d", sv->s_port);
|
|
table->name = (char *)malloc((unsigned)strlen(buf)+1);
|
|
(void)strcpy(table->name, buf);
|
|
} else {
|
|
table->name =
|
|
(char *)malloc((unsigned)strlen(sv->s_name)+1);
|
|
(void)strcpy(table->name, sv->s_name);
|
|
}
|
|
table->addr = sv->s_port;
|
|
table->nxt = (struct hnamemem *)calloc(1, sizeof(*table));
|
|
}
|
|
endservent();
|
|
}
|
|
|
|
#include "etherproto.h"
|
|
|
|
/* Static data base of ether protocol types. */
|
|
struct eproto eproto_db[] = {
|
|
{ "pup", ETHERTYPE_PUP },
|
|
{ "xns", ETHERTYPE_NS },
|
|
{ "ip", ETHERTYPE_IP },
|
|
{ "arp", ETHERTYPE_ARP },
|
|
{ "rarp", ETHERTYPE_REVARP },
|
|
{ "sprite", ETHERTYPE_SPRITE },
|
|
{ "mopdl", ETHERTYPE_MOPDL },
|
|
{ "moprc", ETHERTYPE_MOPRC },
|
|
{ "decnet", ETHERTYPE_DN },
|
|
{ "lat", ETHERTYPE_LAT },
|
|
{ "lanbridge", ETHERTYPE_LANBRIDGE },
|
|
{ "vexp", ETHERTYPE_VEXP },
|
|
{ "vprod", ETHERTYPE_VPROD },
|
|
{ "atalk", ETHERTYPE_ATALK },
|
|
{ "atalkarp", ETHERTYPE_AARP },
|
|
{ "loopback", ETHERTYPE_LOOPBACK },
|
|
{ (char *)0, 0 }
|
|
};
|
|
|
|
static void
|
|
init_eprotoarray()
|
|
{
|
|
register int i;
|
|
register struct hnamemem *table;
|
|
|
|
for (i = 0; eproto_db[i].s; i++) {
|
|
int j = ntohs(eproto_db[i].p) & (HASHNAMESIZE-1);
|
|
table = &eprototable[j];
|
|
while (table->name)
|
|
table = table->nxt;
|
|
table->name = eproto_db[i].s;
|
|
table->addr = ntohs(eproto_db[i].p);
|
|
table->nxt = (struct hnamemem *)calloc(1, sizeof(*table));
|
|
}
|
|
}
|
|
|
|
static void
|
|
init_etherarray()
|
|
{
|
|
#ifndef ETHER_SERVICE
|
|
FILE *fp;
|
|
struct etherent *ep;
|
|
struct enamemem *tp;
|
|
|
|
fp = fopen(ETHERS_FILE, "r");
|
|
if (fp == 0)
|
|
/* No data base; will have to settle for
|
|
numeric addresses. */
|
|
return;
|
|
|
|
while (ep = next_etherent(fp)) {
|
|
tp = lookup_emem(ep->addr);
|
|
tp->e_name = (char *)malloc((unsigned)strlen(ep->name)+1);
|
|
strcpy(tp->e_name, ep->name);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* 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(fflag, localnet, mask)
|
|
int fflag;
|
|
u_long localnet;
|
|
u_long mask;
|
|
{
|
|
netmask = mask;
|
|
if (fflag) {
|
|
f_localnet = localnet;
|
|
f_netmask = mask;
|
|
}
|
|
if (nflag)
|
|
/*
|
|
* Simplest way to suppress names.
|
|
*/
|
|
return;
|
|
|
|
init_etherarray();
|
|
init_servarray();
|
|
init_eprotoarray();
|
|
}
|