328 lines
6.7 KiB
C
328 lines
6.7 KiB
C
/*
|
|
* IP Utility module for the "Etherfind" program
|
|
*
|
|
* @(#)ip.c 1.1 94/10/31
|
|
*
|
|
* Copyright (c) 1988 by Sun Microsystems, Inc.
|
|
*/
|
|
|
|
#include <netdb.h>
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/time.h>
|
|
#include <sys/socket.h>
|
|
#include <net/if.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/if_ether.h>
|
|
#include <netinet/in_systm.h>
|
|
#include <netinet/ip.h>
|
|
#include <netinet/udp.h>
|
|
#include <netinet/ip_var.h>
|
|
#include <netinet/udp_var.h>
|
|
#include <netinet/ip_icmp.h>
|
|
|
|
extern unsigned long inet_network();
|
|
extern unsigned long inet_addr();
|
|
extern char *malloc(), *index();
|
|
|
|
#define ICMPTABLESIZE 256
|
|
char *icmptable[ICMPTABLESIZE];
|
|
|
|
extern int nflag;
|
|
|
|
#define HASHNAMESIZE 256
|
|
|
|
/*
|
|
* XXX: Need to revise to take multiple addresses per interface
|
|
* into account. This change should be part of a revision
|
|
* that teaches etherfind about protocol families other than
|
|
* AF_INET.
|
|
*/
|
|
struct hnamemem {
|
|
struct in_addr h_addr0; /* first address in list (XXX) */
|
|
char *h_name;
|
|
struct hnamemem *h_nxt;
|
|
};
|
|
|
|
struct hnamemem *htable[HASHNAMESIZE];
|
|
|
|
#define TCP 0
|
|
#define UDP 1
|
|
#define NPROTOCOLS 2
|
|
#define MAXPORT 1024
|
|
char *names[NPROTOCOLS][MAXPORT];
|
|
|
|
#define PROTOTABLESIZE 256
|
|
|
|
char *prototable[PROTOTABLESIZE];
|
|
|
|
|
|
/*
|
|
* return the name of the given IP address, using the internal hash
|
|
* table if necessary. The "nflag" bypasses all name lookup and just
|
|
* prints it out as a number. The address is passed as a structure in
|
|
* network order.
|
|
*/
|
|
char *
|
|
getname(addr)
|
|
struct in_addr addr;
|
|
{
|
|
int x;
|
|
struct hnamemem *p;
|
|
char *buf, *inet_ntoa();
|
|
struct netent *np;
|
|
struct hostent *hp;
|
|
|
|
x = ntohl(addr.s_addr) & 0xff;
|
|
for (p = htable[x]; p != NULL; p = p->h_nxt) {
|
|
if (p->h_addr0.s_addr == addr.s_addr)
|
|
return (p->h_name);
|
|
}
|
|
p = (struct hnamemem *)malloc(sizeof(struct hnamemem));
|
|
p->h_addr0 = addr;
|
|
p->h_nxt = htable[x];
|
|
htable[x] = p;
|
|
|
|
# ifndef INADDR_BROADCAST
|
|
# define INADDR_BROADCAST (0xffffffff)
|
|
# endif
|
|
|
|
if (nflag) {
|
|
hp = NULL;
|
|
}
|
|
else {
|
|
if (addr.s_addr == htonl(INADDR_BROADCAST)) {
|
|
p->h_name = "broadcast";
|
|
return (p->h_name);
|
|
}
|
|
if (addr.s_addr == htonl(INADDR_ANY)) {
|
|
p->h_name = "old-broadcast";
|
|
return (p->h_name);
|
|
}
|
|
hp = gethostbyaddr((char *)&addr, sizeof(int), AF_INET);
|
|
if (hp == NULL && inet_lnaof(addr) == 0) {
|
|
np = getnetbyaddr(inet_netof(addr), AF_INET);
|
|
if (np) {
|
|
p->h_name = malloc((unsigned)strlen(np->n_name) + 1);
|
|
(void) strcpy(p->h_name, np->n_name);
|
|
return (p->h_name);
|
|
}
|
|
}
|
|
}
|
|
if (hp) {
|
|
p->h_name = malloc((unsigned)strlen(hp->h_name) + 1);
|
|
(void) strcpy(p->h_name, hp->h_name);
|
|
}
|
|
else {
|
|
buf = inet_ntoa(addr);
|
|
p->h_name = malloc((unsigned)(strlen(buf)) + 1);
|
|
(void) strcpy(p->h_name, buf);
|
|
}
|
|
return (p->h_name);
|
|
}
|
|
|
|
/*
|
|
* convert string (which may be host address or host name) to address
|
|
*/
|
|
stringtoaddr(name)
|
|
char *name;
|
|
{
|
|
struct hostent *hp;
|
|
char *p;
|
|
unsigned short a, b;
|
|
|
|
if (isdigit(name[0])) {
|
|
p = index(name, '.');
|
|
if (p && index(p+1, '.') == 0) { /* decnet address area.host */
|
|
a = atoi(name);
|
|
b = atoi(p+1);
|
|
if ((a < 1) || (a > 63)) {
|
|
fprintf(stderr, "%d invalid decnet area\n", a);
|
|
exit(1);
|
|
}
|
|
if ((b < 1) || (b > 1023)) {
|
|
fprintf(stderr, "%d invalid decnet host\n", b);
|
|
exit(1);
|
|
}
|
|
a = (a << 10) + b;
|
|
swab((char *)&a, (char *)&b, 2);
|
|
return(b);
|
|
} else
|
|
return(inet_addr(name));
|
|
}
|
|
|
|
hp = gethostbyname(name);
|
|
if (hp == NULL) {
|
|
fprintf(stderr, "%s unknown host name\n", name);
|
|
exit(1);
|
|
}
|
|
else
|
|
return(*(int *)hp->h_addr);
|
|
}
|
|
|
|
|
|
stringtonetaddr(name)
|
|
char *name;
|
|
{
|
|
struct netent *np;
|
|
|
|
if (isdigit(name[0]))
|
|
return(inet_network(name));
|
|
|
|
np = getnetbyname(name);
|
|
if (np == NULL) {
|
|
fprintf(stderr, "%s unknown net name\n", name);
|
|
exit(1);
|
|
}
|
|
else
|
|
return (np->n_net);
|
|
}
|
|
|
|
|
|
/*
|
|
* returns the port number in Network byte order
|
|
*/
|
|
unsigned short
|
|
stringtoport(str)
|
|
char *str;
|
|
{
|
|
struct servent *sp;
|
|
|
|
if (isdigit(str[0]))
|
|
return(htons((u_short) atoi(str)));
|
|
else {
|
|
sp = getservbyname(str, (char *)NULL);
|
|
if (sp == NULL) {
|
|
fprintf(stderr,
|
|
"etherfind: %s is not a valid port name or number\n",
|
|
str);
|
|
exit(1);
|
|
}
|
|
return(sp->s_port);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Return the printable version of an IP port number
|
|
*/
|
|
char *
|
|
getportname(port, proto)
|
|
u_short port;
|
|
{
|
|
static char buf[10];
|
|
int protonum;
|
|
|
|
port = ntohs(port);
|
|
|
|
if (proto == IPPROTO_TCP)
|
|
protonum = TCP;
|
|
else if (proto == IPPROTO_UDP)
|
|
protonum = UDP;
|
|
else {
|
|
sprintf(buf, "%d", port);
|
|
return (buf);
|
|
}
|
|
if (port < MAXPORT && names[protonum][port])
|
|
return (names[protonum][port]);
|
|
else {
|
|
sprintf(buf, "%d", port);
|
|
return (buf);
|
|
}
|
|
}
|
|
|
|
char *icmptype(icp)
|
|
struct icmp *icp; /* points to icmp packet */
|
|
{
|
|
return(icmptable[icp->icmp_type]);
|
|
}
|
|
|
|
initIP()
|
|
/*
|
|
* Initialize the Internet Protocol specific module
|
|
*/
|
|
{
|
|
struct servent *sv;
|
|
int proto;
|
|
char *p;
|
|
|
|
icmptable[ICMP_ECHOREPLY] = "echo reply";
|
|
icmptable[ICMP_UNREACH] = "dst unreachable";
|
|
icmptable[ICMP_SOURCEQUENCH] = "src quench";
|
|
icmptable[ICMP_REDIRECT] = "redirect";
|
|
icmptable[ICMP_ECHO] = "echo";
|
|
icmptable[ICMP_TIMXCEED] = "time exceeded";
|
|
icmptable[ICMP_PARAMPROB] = "param problem";
|
|
icmptable[ICMP_TSTAMP] = "timestamp";
|
|
icmptable[ICMP_TSTAMPREPLY] = "timestamp reply";
|
|
icmptable[ICMP_IREQ] = "info request";
|
|
icmptable[ICMP_IREQREPLY] = "info reply";
|
|
icmptable[ICMP_MASKREQ] = "mask request";
|
|
icmptable[ICMP_MASKREPLY] = "mask reply";
|
|
|
|
for (proto = 0; proto < ICMPTABLESIZE; proto++) {
|
|
if (icmptable[proto] == NULL) {
|
|
p = malloc(5);
|
|
sprintf(p, "%d", proto);
|
|
icmptable[proto] = p;
|
|
}
|
|
}
|
|
|
|
prototable[IPPROTO_ICMP] = "icmp";
|
|
prototable[IPPROTO_IGMP] = "igmp";
|
|
prototable[IPPROTO_GGP] = "ggp";
|
|
prototable[5] = "st";
|
|
prototable[IPPROTO_TCP] = "tcp";
|
|
prototable[IPPROTO_EGP] = "egp";
|
|
prototable[IPPROTO_UDP] = "udp";
|
|
prototable[27] = "rdp";
|
|
prototable[30] = "netblt";
|
|
prototable[IPPROTO_HELLO] = "hello";
|
|
prototable[IPPROTO_ND] = "nd";
|
|
|
|
while (sv = getservent()) {
|
|
if (strcmp(sv->s_proto, "tcp") == 0)
|
|
proto = TCP;
|
|
else if (strcmp(sv->s_proto, "udp") == 0)
|
|
proto = UDP;
|
|
else
|
|
continue;
|
|
sv->s_port = ntohs(sv->s_port);
|
|
if (sv->s_port < 0 || sv->s_port >= MAXPORT)
|
|
continue;
|
|
names[proto][sv->s_port] =
|
|
malloc((unsigned)strlen(sv->s_name) + 1);
|
|
(void) strcpy(names[proto][sv->s_port], sv->s_name);
|
|
}
|
|
endservent();
|
|
}
|
|
|
|
getproto(arg)
|
|
char *arg;
|
|
{
|
|
char **p;
|
|
int protonum;
|
|
|
|
if (isalpha(arg[0])) {
|
|
protonum = -1;
|
|
for (p = prototable; p < prototable + PROTOTABLESIZE; p++) {
|
|
if (*p && strcmp(arg, *p) == 0) {
|
|
protonum = p - prototable;
|
|
break;
|
|
}
|
|
}
|
|
if (protonum == -1) {
|
|
fprintf(stderr, "%s unknown protocol\n", arg);
|
|
exit(1);
|
|
/*NOTREACHED*/
|
|
}
|
|
else
|
|
return (protonum);
|
|
}
|
|
else
|
|
return (atoi(arg));
|
|
}
|
|
|