/* * TCPVIEW * * Author: Martin Hunt * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: martinh@cac.washington.edu * * * Copyright 1992 by the University of Washington * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appears in all copies and that both the * above copyright notice and this permission notice appear in supporting * documentation, and that the name of the University of Washington not be * used in advertising or publicity pertaining to distribution of the software * without specific, written prior permission. This software is made * available "as is", and * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ /* * 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 */ #ifndef lint static char rcsid[] = "@(#) $Header: /usr/staff/martinh/tcpview/RCS/tv_addrtoname.c,v 1.2 1993/04/19 23:16:22 martinh Exp $ (UW)"; #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "tcpview.h" #include "addrtoname.h" #include "nametoaddr.h" #include "etherent.h" #define LOOKUP_TCP 0 #define LOOKUP_UDP 1 /* Static data base of ether protocol types. */ #include "etherproto.h" struct eproto eproto_db[] = { { "IP", ETHERTYPE_IP }, { "ARP", ETHERTYPE_ARP }, { "RARP", ETHERTYPE_REVARP }, { "XNS", ETHERTYPE_NS }, { "DECNET", ETHERTYPE_DN }, { "LAT", ETHERTYPE_LAT }, { "ATALK", ETHERTYPE_ATALK }, { "ATALKARP", ETHERTYPE_AARP }, { "PUP", ETHERTYPE_PUP }, { "SPRITE", ETHERTYPE_SPRITE }, { "MOPDL", ETHERTYPE_MOPDL }, { "MOPRC", ETHERTYPE_MOPRC }, { "LANBRIDGE", ETHERTYPE_LANBRIDGE }, { "VEXP", ETHERTYPE_VEXP }, { "VPROD", ETHERTYPE_VPROD }, { "LOOPBACK", ETHERTYPE_LOOPBACK }, { "TRAILER", ETHERTYPE_TRAIL }, { "TRAIL1", ETHERTYPE_TRAIL+1 }, { "TRAIL2", ETHERTYPE_TRAIL+2 }, { (char *)0, 0 } }; struct ipproto { char *s; u_short p; }; #define IPPROTO_HELLO 63 /* "hello" routing protocol */ struct ipproto ipproto_db[] = { { "IP", IPPROTO_IP }, { "ICMP", IPPROTO_ICMP }, { "TCP", IPPROTO_TCP }, { "UDP", IPPROTO_UDP }, { "EGP", IPPROTO_EGP }, { "RAW", IPPROTO_RAW }, { "PUP", IPPROTO_PUP }, { "IDP", IPPROTO_IDP }, { "GGP", IPPROTO_GGP }, { "HELLO", IPPROTO_HELLO}, { (char *)0, 0 } }; #define HASHNAMESIZE 4096 /* size of name hash table */ #define HASHPORTSIZE 256 /* size of TCP and UDP port tables */ #define HASHMNAMESIZE 256 /* size of manufacturer id table */ struct hnamemem { u_long addr; char name[30]; struct hnamemem *next; }; struct enamemem { u_short addr0; u_short addr1; u_short addr2; char e_name[13]; char m_name[13]; char h_name[20]; struct enamemem *next; }; struct mnamemem { u_char addr[3]; char name[9]; struct mnamemem *next; }; struct enamemem *enametable[HASHNAMESIZE]; struct mnamemem *mnametable[HASHMNAMESIZE]; struct hnamemem *hnametable[HASHNAMESIZE]; struct hnamemem *tporttable[HASHPORTSIZE]; struct hnamemem *uporttable[HASHPORTSIZE]; int GetEtherList (list, size) XmString list[]; int size; { register int i, n; struct enamemem *ep; char *foo[512], *tmp; int notdone, last; int strcasecmp(); n=0; for(i=0;ih_name[0] ) { foo[n++] = ep->h_name; } else { foo[n++] = ep->m_name; } if( n == size ) break; ep = ep->next; } } /* real stupid sort because qsort didn't work */ /* replace someday */ notdone=1; last = n-1; while( notdone ) { i=0; notdone=0; do { if( strcasecmp(foo[i],foo[i+1]) > 0 ) { tmp = foo[i+1]; foo[i+1] = foo[i]; foo[i] = tmp; notdone = 1; } } while ( ++i < last ); last--; } /* convert array to XmStrings */ for(i=0;ih_name[0] ) { if(strcmp(str,ep->h_name)==0) goto gotit; } else { if(strcmp(str,ep->m_name)==0) goto gotit; } ep = ep->next; } } *foo = 0; return( foo ); gotit: e = ep->e_name; convert: f = foo; for(i=0;i<6;i++) { *f++ = *e++; *f++ = *e++; if( i<5 ) *f++ = ':'; } *f = '\0'; return( foo ); } static struct mnamemem * lookup_manuf(ep, enter) u_char *ep; int enter; { struct mnamemem *m; m = mnametable[(int)ep[2] & (HASHMNAMESIZE-1)]; if (!m) { if (!enter) return 0; m = mnametable[(int)ep[2] & (HASHMNAMESIZE-1)] = (struct mnamemem *)malloc(sizeof(struct mnamemem)); } else { do { if (!bcmp(ep,m->addr,3)) return m; if (m->next == NULL) { if (!enter) return 0; m->next = (struct mnamemem *)malloc(sizeof(struct mnamemem)); m = m->next; break; } m = m->next; } while(1); } m->next = NULL; bcopy(ep,m->addr,3); strcpy(m->name,"______"); /* put 6 spaces and terminator */ return m; } /* * 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 struct hnamemem *lookup_name(addr) u_long addr; { struct hnamemem *p; p = hnametable[ addr & (HASHNAMESIZE-1)]; if( p==NULL ) { p = hnametable[ addr & (HASHNAMESIZE-1)] = (struct hnamemem *)malloc(sizeof(struct hnamemem)); } else { do { if(p->addr == addr) return( p ); if( p->next == NULL ) { p->next = (struct hnamemem *)malloc(sizeof(struct hnamemem)); p = p->next; break; } p = p->next; } while (1); } /* new entry */ p->addr = addr; p->next = NULL; p->name[0] = '\0'; return( p ); } char * ipaddr_string(ap) u_char *ap; { int f=0; if(nflag) f = ADDR_NUMERICAL; if(!Nflag) f |= ADDR_DOMAIN; return( getname(ap,f)); } 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 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,flag) u_char *ap; int flag; { register struct hnamemem *p; register struct hostent *hp; u_long addr; static char buf1[31], buf2[31]; static int foo=0; char *ptr; #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 /* ugly kludge */ if( flag & ADDR_NUMERICAL ) { if(foo) { foo=0; ptr = buf1; } else { foo++; ptr = buf2; } strcpy(ptr,intoa(addr)); return(ptr); } p = lookup_name(addr); if( p->name[0] != '\0' ) { if(foo) { foo=0; ptr = buf1; } else { foo++; ptr = buf2; } strcpy(ptr,p->name); if ( !(flag&ADDR_DOMAIN) && !isdigit(*ptr) ) { char *dotp; /* Remove domain qualifications */ dotp = strchr(ptr, '.'); if (dotp) *dotp = 0; } return (ptr); } /* didn't find it so look it up and enter it */ /* * 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 ( !(flag & ADDR_NUMERICAL) && (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 *dotp; (void)strncpy(p->name, hp->h_name,30); p->name[29] ='\0'; if(foo) { foo=0; ptr = buf1; } else { foo++; ptr = buf2; } strcpy(ptr,p->name); if (!(flag&ADDR_DOMAIN)) { /* Remove domain qualifications */ dotp = strchr(ptr, '.'); if (dotp) *dotp = 0; } return (ptr); } } } (void)strcpy(p->name, intoa(addr)); return (p->name); } static char hhex[] = "0123456789abcdef"; static void get_manuf(str, addr) char *str; u_char *addr; { struct mnamemem *m; m = lookup_manuf(addr,0); if (m) bcopy(m->name,str,6); } /* Find the hash node that corresponds the ether address 'ep'. */ static struct enamemem * lookup_emem(ep) u_char *ep; { register u_int i, j, k; struct enamemem *tp; char *cp; u_char *p; k = (ep[0] << 8) | ep[1]; j = (ep[2] << 8) | ep[3]; i = (ep[4] << 8) | ep[5]; tp = enametable[(i ^ j) & (HASHNAMESIZE-1)]; if (!tp) { tp= enametable[(i ^ j) & (HASHNAMESIZE-1)] = (struct enamemem *) malloc(sizeof(struct enamemem)); } else { do { if (tp->addr0 == i && tp->addr1 == j && tp->addr2 == k) return tp; if (tp->next == NULL) { tp->next = (struct enamemem *)malloc(sizeof(struct enamemem)); tp = tp->next; break; } tp = tp->next; } while(1); } /* we didn't find an entry so fill in a new one */ tp->addr0 = i; tp->addr1 = j; tp->addr2 = k; tp->next = NULL; /* now fill in ASCII ethernet address */ p = ep; cp = tp->e_name; j = *ep >> 4; *cp++ = hhex[j]; *cp++ = hhex[*ep++ & 0xf]; for (i = 5; (int)--i >= 0;) { j = *ep >> 4; *cp++ = hhex[j]; *cp++ = hhex[*ep++ & 0xf]; } *cp = '\0'; /* fill in default value */ tp->h_name[0]='\0'; /* no host name */ strcpy(tp->m_name,tp->e_name); /* ethernet address with manuf. ID */ get_manuf(tp->m_name,p); return tp; } char *etheraddr_string(ep) register u_char *ep; { int f=0; if( nflag ) f = ADDR_NUMERICAL; return( etheraddr_str(ep,f) ); } char * etheraddr_str(ep, flag) register u_char *ep; int flag; { register struct enamemem *tp; tp = lookup_emem(ep); if( (flag & ADDR_NUMERICAL) || tp->h_name[0]=='\0' ) { if ( Man_Flag ) { return (tp->m_name); } else { return (tp->e_name); } } return (tp->h_name); } /********** char * etherproto_string(port) u_short port; { return etherproto_str(port,nflag?ADDR_NUMERICAL:0); } ***********/ char * etherproto_str(port, flag) u_short port; int flag; { int i; static char buffer[8]; char *cp; ntohs(port); if (!(flag&ADDR_NUMERICAL)) { for(i=0;eproto_db[i].s;i++) { if (eproto_db[i].p == port) return ( eproto_db[i].s ); } } cp = buffer; *cp++ = hhex[port >> 12 & 0xf]; *cp++ = hhex[port >> 8 & 0xf]; *cp++ = hhex[port >> 4 & 0xf]; *cp++ = hhex[port & 0xf]; *cp++ = '\0'; return (buffer); } char * ipproto_string(pro) u_short pro; { int i; /* ntohs(pro); */ for(i=0;ipproto_db[i].s;i++) { if (ipproto_db[i].p == pro) return ( ipproto_db[i].s ); } return("unknown"); } static struct hnamemem * lookup_port(port, mode) u_short port, mode; { register struct hnamemem *tp; register int i; i = port & (HASHNAMESIZE-1); if( mode == LOOKUP_TCP) tp = tporttable[ i & (HASHPORTSIZE-1)]; else tp = uporttable[ i & (HASHPORTSIZE-1)]; if( tp==NULL ) { if( mode == LOOKUP_TCP) tp = tporttable[ i & (HASHPORTSIZE-1)] = (struct hnamemem *)malloc(sizeof(struct hnamemem)); else tp = uporttable[ i & (HASHPORTSIZE-1)] = (struct hnamemem *)malloc(sizeof(struct hnamemem)); } else { do { if( tp->addr == (u_long)port ) { return tp; } if (tp->next == NULL) { tp->next = (struct hnamemem *)malloc(sizeof(struct hnamemem)); tp = tp->next; break; } tp = tp->next; } while(1); } /* we didn't find an entry so fill in a new one */ tp->addr = (u_long)port; tp->next = NULL; tp->name[0] = '\0'; return( tp ); } char * tcpport_string(port) u_short port; { register struct hnamemem *tp; tp = lookup_port(port,LOOKUP_TCP); if( tp->name[0] == '\0' ) (void)sprintf(tp->name, "%d", (u_int)port); return (tp->name); } char * udpport_string(port) u_short port; { register struct hnamemem *tp; tp = lookup_port(port,LOOKUP_UDP); if( tp->name[0] == '\0' ) (void)sprintf(tp->name, "%d", (u_int)port); return (tp->name); } static void init_servarray() { struct servent *sv; register struct hnamemem *table; while (sv = GetServent()) { ntohs(sv->s_port); if (strcmp(sv->s_proto, "tcp") == 0) { table = lookup_port(sv->s_port,LOOKUP_TCP); } else if (strcmp(sv->s_proto, "udp") == 0) { table = lookup_port(sv->s_port,LOOKUP_UDP); } else continue; if( table->name[0]=='\0' ) (void)strcpy(table->name, sv->s_name); } EndServent(); } static void init_etherarray() { FILE *fp; struct etherent *e; struct enamemem *tp; struct manufent *mf; struct mnamemem *mm; fp = fopen(ManufFile, "r"); if (fp) { while (mf = next_manufent(fp)) { mm = lookup_manuf(mf->addr,1); bcopy(mf->name,mm->name,min(strlen(mf->name),6)); } close(fp); } else fprintf(stderr,"Unable to open ethernet manufacturer's file, %s\n",ManufFile); fp = fopen(HostFile, "r"); if (fp) { while (e = next_etherent(fp)) { tp = lookup_emem(e->addr); strncpy(tp->h_name, e->name, 18); } close(fp); } else fprintf(stderr,"Unable to open ethernet hosts file, %s\n",HostFile); } void init_addrtoname() { init_etherarray(); init_servarray(); }