/* * 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: addrtoname.c,v 1.14 92/05/25 14:29:07 mccanne Exp $ (LBL)"; #endif #include #include #include #include #include #include #include #include #include #include #include #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 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(); }