/* $Id: net_names.c,v 0.10 2004/08/14 12:32:13 kjc Exp kjc $ */
/*
* Copyright (c) 1996-2000
* Sony Computer Science Laboratories, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms of parts of or the
* whole original or derived work are permitted provided that the above
* copyright notice is retained and the original work is properly
* attributed to the author. The name of the author may not 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.
*/
/* net_names.c -- a module to translate ids to name strings. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/if_ether.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <arpa/inet.h>
#include <netdb.h>
#if STDC_HEADERS
#include <string.h>
#else
#include <strings.h>
#endif
#include "ttt.h"
#include "ttt_account.h"
#ifdef IPV6
#include "ttt_ipv6.h"
#endif
#ifdef HAVE_GETHOSTENT
/* some systems (e.g. bsd) don't have gethostent(3) any more, assuming
dns be a way to lookup host names. but some systems (e.g. sunos)
still have it. if it does, it may be a good idea to initialize the
name table at the startup.
*/
#define INIT_HOSTNAME_TAB /* create host name table beforehand */
#endif
static u_long f_localnet, f_netmask;
static char *tcpport_string(u_short port);
static char *udpport_string(register u_short port);
static void init_servarray(void);
#ifdef INIT_HOSTNAME_TAB
static void init_hostarray(void);
#endif
static char *getname(const u_long addr);
static char *intoa(u_long addr);
void netname_init(u_long netaddr, u_long netmask)
{
/* save localnet address and netmask */
f_localnet = netaddr;
f_netmask = netmask;
/* initialize tcp/udp service table */
init_servarray();
#ifdef INIT_HOSTNAME_TAB
/* initialize host name table */
if (!ttt_nohostname)
init_hostarray();
#endif
}
#ifndef ETHERTYPE_LOOPBACK
#define ETHERTYPE_LOOPBACK 0x9000
#endif
#ifndef ETHERTYPE_ATALK
#define ETHERTYPE_ATALK 0x809b
#endif
struct pname_tab {
char *pn_name;
int pn_value;
};
static struct pname_tab eth_tab[] =
{
{ "ip", ETHERTYPE_IP }, /* IP protocol */
{ "arp", ETHERTYPE_ARP }, /* Addr. resolution protocol */
#ifdef IPV6
{ "ipv6", ETHERTYPE_IPV6 }, /* IPv6 protocol */
#endif
{ "pup", ETHERTYPE_PUP }, /* PUP protocol */
{ "revarp", ETHERTYPE_REVARP }, /* Reverse ARP */
{ "loop", ETHERTYPE_LOOPBACK }, /* Loopback */
{ "atalk", ETHERTYPE_ATALK }, /* AppleTalk */
{ NULL, 0 }
};
/* stick to RFC1700. some systems has wrong numbers. */
#undef IPPROTO_IP
#define IPPROTO_IP 4 /* IP in IP (encasulation) */
#undef IPPROTO_IPIP
#define IPPROTO_IPIP 94 /* IP-within-IP Encapsulation Protocol */
#undef IPPROTO_ENCAP
#define IPPROTO_ENCAP 98 /* Encapsulation Header */
/* other protocols we are interested in */
#ifndef IPPROTO_RSVP
#define IPPROTO_RSVP 46 /* RSVP Reservation Protocol */
#endif
#ifndef IPPROTO_GRE
#define IPPROTO_GRE 47 /* General Routing Encapsulation */
#endif
#ifndef IPPROTO_ESP
#define IPPROTO_ESP 50 /* encapsulating security payload */
#endif
#ifndef IPPROTO_OSPFIGP
#define IPPROTO_OSPFIGP 89 /* OSPFIGP */
#endif
static struct pname_tab ip_tab[] =
{
{ "tcp", IPPROTO_TCP }, /* tcp */
{ "udp", IPPROTO_UDP }, /* user datagram protocol */
{ "icmp", IPPROTO_ICMP }, /* control message protocol */
{ "igmp", IPPROTO_IGMP }, /* group control protocol */
#ifdef IPPROTO_GGP
{ "ggp", IPPROTO_GGP }, /* gateway^2 (deprecated) */
#endif
{ "egp", IPPROTO_EGP }, /* exterior gateway protocol */
{ "pup", IPPROTO_PUP }, /* pup */
{ "ospf", IPPROTO_OSPFIGP }, /* OSPFIGP */
{ "rsvp", IPPROTO_RSVP }, /* RSVP */
{ "gre", IPPROTO_GRE }, /* GRE */
{ "esp", IPPROTO_ESP }, /* encapsulating security payload */
{ "ip", IPPROTO_IP }, /* IP in IP */
{ "ipip", IPPROTO_IPIP }, /* IP-within-IP */
{ "encap", IPPROTO_ENCAP }, /* Encapsulation Header */
#ifdef IPV6
{ "icmp6", IPPROTO_ICMPV6 }, /* ICMP version 6 */
#endif
{ NULL, 0 }
};
static char *pname_lookup(struct pname_tab *tab, long id)
{
struct pname_tab *tp = tab;
while (tp->pn_name != NULL) {
if (tp->pn_value == id)
return (tp->pn_name);
tp++;
}
return NULL;
}
static char *inet6_ntoa(uint32_t *addr); /* should be replaced by addr2ascii */
char *net_getname(long type, long *id)
{
char *buf, *name;
u_short portno;
switch(type) {
case TTTTYPE_ETHER:
if ((buf = malloc(sizeof("revarp/ether "))) == NULL)
fatal_error("get_protoname: no memory\n");
name = pname_lookup(eth_tab, id[0]);
if (name != NULL)
sprintf(buf, "%s/ether", name);
else
sprintf(buf, "0x%lx/ether", id[0]);
break;
case TTTTYPE_IP:
if ((buf = malloc(sizeof("encap/ip "))) == NULL)
fatal_error("get_protoname: no memory\n");
name = pname_lookup(ip_tab, id[0]);
if (name != NULL)
sprintf(buf, "%s/ip", name);
else
sprintf(buf, "%lu/ip", id[0]);
break;
case TTTTYPE_UDP:
if ((buf = malloc(sizeof("some-long-service-name/udp"))) == NULL)
fatal_error("get_protoname: no memory\n");
portno = id[0];
if ((name = udpport_string(portno)) != NULL)
sprintf(buf, "%s/udp", name);
else
sprintf(buf, "%lu/udp", id[0]);
break;
case TTTTYPE_TCP:
if ((buf = malloc(sizeof("some-long-service-name/tcp"))) == NULL)
fatal_error("get_protoname: no memory\n");
portno = id[0];
if ((name = tcpport_string(portno)) != NULL)
sprintf(buf, "%s/tcp", name);
else
sprintf(buf, "%lu/tcp", id[0]);
break;
case TTTTYPE_IPHOST:
{
u_long addr;
if ((buf = malloc(sizeof("xxx.xxx.xxx.xxx"))) == NULL)
fatal_error("get_protoname: no memory\n");
addr = htonl(id[0]);
#ifdef DONT_LOOKUP_HOSTNAME
if (!ttt_nohostname && (name = getname(addr)) != NULL) {
#else
/* lookup the hostname only when
(1) the address is local. (otherwise, it might take a long time
to lookup dns)
(2) the host portion is not 0 (i.e., a network address).
(3) the host portion is not broadcast.
*/
if (!ttt_nohostname && (addr & f_netmask) == f_localnet
&& (addr &~ f_localnet) != 0
&& (addr | f_netmask) != 0xffffffff
&& ((name = getname(addr)) != NULL)) {
#endif /* !DONT_LOOKUP_HOSTNAME */
strcpy(buf, name);
}
else
sprintf(buf, "%s", intoa(addr));
}
break;
#ifdef IPV6
case TTTTYPE_IPV6:
if ((buf = malloc(sizeof("icmp6/ip6 "))) == NULL)
fatal_error("get_protoname: no memory\n");
name = pname_lookup(ip_tab, id[0]);
if (name != NULL)
sprintf(buf, "%s/ip6", name);
else
sprintf(buf, "%lu/ip6", id[0]);
break;
case TTTTYPE_UDPV6:
if ((buf = malloc(sizeof("some-long-service-name/udp6"))) == NULL)
fatal_error("get_protoname: no memory\n");
portno = id[0];
if ((name = udpport_string(portno)) != NULL)
sprintf(buf, "%s/udp6", name);
else
sprintf(buf, "%lu/udp6", id[0]);
break;
case TTTTYPE_TCPV6:
if ((buf = malloc(sizeof("some-long-service-name/tcp6"))) == NULL)
fatal_error("get_protoname: no memory\n");
portno = id[0];
if ((name = tcpport_string(portno)) != NULL)
sprintf(buf, "%s/tcp6", name);
else
sprintf(buf, "%lu/tcp6", id[0]);
break;
case TTTTYPE_IPV6HOST:
{
u_int32_t tmp[4];
if ((buf = malloc(sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx")))
== NULL)
fatal_error("get_protoname: no memory\n");
tmp[0] = htonl(id[0]);
tmp[1] = htonl(id[1]);
tmp[2] = htonl(id[2]);
tmp[3] = htonl(id[3]);
sprintf(buf, "%s", inet6_ntoa(tmp));
}
break;
#endif /* IPV6 */
default:
if ((buf = malloc(sizeof("unknown"))) == NULL)
sprintf(buf, "unknown");
break;
}
return buf;
}
/*
cache tables for udp/tcp services and host names derived from tcpdump.
we don't manage memory space since
- tcp/udp services has limited entries.
- only local host names are looked up.
*/
/*
* Copyright (c) 1990, 1991, 1992, 1993, 1994
* 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
*/
typedef unsigned long u_int32;
/*
* hash tables for whatever-to-name translations
*/
#define HASHNAMESIZE 4096
struct hnamemem {
u_int32 addr;
char *name;
struct hnamemem *nxt;
};
static struct hnamemem hnametable[HASHNAMESIZE];
static struct hnamemem tporttable[HASHNAMESIZE];
static struct hnamemem uporttable[HASHNAMESIZE];
static char *tcpport_string(u_short port)
{
struct hnamemem *tp;
u_long i = port;
for (tp = &tporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
if (tp->addr == i)
return (tp->name);
return NULL;
}
static char *udpport_string(register u_short port)
{
struct hnamemem *tp;
u_long i = port;
for (tp = &uporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
if (tp->addr == i)
return (tp->name);
return NULL;
}
static void init_servarray(void)
{
struct servent *sv;
struct hnamemem *table;
int i, n = 0;
setservent(1);
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) {
if (table->addr == port) {
/* dup entry! */
break;
}
table = table->nxt;
}
if (table->name == NULL) {
table->name = strdup(sv->s_name);
table->addr = port;
table->nxt = (struct hnamemem *)calloc(1, sizeof(*table));
n++;
}
}
endservent();
#ifdef REMOTE_DEBUG
printf("[debug] initialized serv table %d entries\n", n);
#endif
}
#ifdef INIT_HOSTNAME_TAB
static void init_hostarray(void)
{
struct hostent *hp;
struct hnamemem *p;
int n = 0;
sethostent(1);
while ((hp = gethostent()) != NULL) {
u_int32 addr;
if (hp->h_length != 4)
continue;
memcpy(&addr, hp->h_addr, hp->h_length);
addr = ntohl(addr);
p = &hnametable[addr & (HASHNAMESIZE-1)];
while (p->name) {
if (p->addr == addr) {
/* dup entry! */
break;
}
p = p->nxt;
}
if (p->name == NULL) {
char *dotp;
p->name = strdup(hp->h_name);
p->addr = addr;
p->nxt = (struct hnamemem *)calloc(1, sizeof(*p));
/* Remove domain qualifications */
dotp = strchr(p->name, '.');
if (dotp)
*dotp = 0;
n++;
}
}
endhostent();
#ifdef REMOTE_DEBUG
printf("[debug] initialized host name table %d entries\n", n);
#endif
}
#endif /* INIT_HOSTNAME_TAB */
/*
* Return a name for the IP address. This address
* is assumed to be in network byte order.
*/
static char *getname(const u_int32 addr)
{
struct hnamemem *p;
p = &hnametable[addr & (HASHNAMESIZE-1)];
for (; p->nxt; p = p->nxt) {
if (p->addr == addr)
return (p->name);
}
#ifndef DONT_LOOKUP_HOSTNAME
{
struct hostent *hp;
p->addr = addr;
p->nxt = (struct hnamemem *)calloc(1, sizeof (*p));
hp = gethostbyaddr((char *)&addr, 4, AF_INET);
if (hp) {
char *dotp;
p->name = strdup(hp->h_name);
/* Remove domain qualifications */
dotp = strchr(p->name, '.');
if (dotp)
*dotp = 0;
return (p->name);
}
}
#endif /* DONT_LOOKUP_HOSTNAME */
return NULL;
}
/*
* A faster replacement for inet_ntoa().
*/
static char *intoa(u_int32 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;
}
#ifdef IPV6
/* derived from ascii_addr.c */
#if !defined(BSD4_4) && !(defined(__linux__) && defined(__USE_BSD))
typedef u_long u_int32_t;
typedef u_short u_int16_t;
#endif
/*
* Copyright (c) 1994 Bell Communications Research Inc. (Bellcore).
*
* Permission to use, copy, modify and distribute this material for any
* purpose and without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies,
* and the name of Bellcore not be used in advertising or publicity
* pertaining to this material without the specific, prior written
* permission of an authorized representative of Bellcore. BELLCORE
* MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS MATERIAL
* FOR ANY PURPOSE. IT IS PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES.
*/
static char digits[] = "0123456789abcdef";
static char buf[128];
static char *
inet6_ntoa(u_int32_t *addr)
{
register int i;
register char *cp = buf;
register u_int16_t *a = (u_int16_t *)addr;
register u_char *d;
int zeros, h, dcolon = 0;
for (i = 0; i < 8; i++) {
if (dcolon == 1) {
if (*a == 0) {
/* trailing zeros */
if (i == 7)
*cp++ = ':';
a++;
continue;
} else
dcolon = 2;
}
if (*a == 0) {
if (dcolon == 0 && *(a + 1) == 0) {
/* leading zeros */
if (i == 0)
*cp++ = ':';
*cp++ = ':';
dcolon = 1;
} else {
*cp++ = '0';
*cp++ = ':';
}
a++;
continue;
}
d = (u_char *)a;
zeros = 0;
if ((h = (*d >> 4)) == 0)
zeros = 1;
else
*cp++ = digits[h];
if (((h = (*d++ & 0xf)) == 0) && (zeros == 1))
zeros = 2;
else
*cp++ = digits[h];
if (((h = (*d >> 4)) == 0) && (zeros == 2))
zeros = 3;
else
*cp++ = digits[h];
*cp++ = digits[*d & 0xf];
*cp++ = ':';
a++;
}
*--cp = 0;
return (buf);
}
#endif /* IPV6 */
syntax highlighted by Code2HTML, v. 0.9.1