addrtoname.c revision 26183
1/*
2 * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 *
21 *  Internet, ethernet, port, and protocol string to address
22 *  and address to string conversion routines
23 */
24#ifndef lint
25static const char rcsid[] =
26    "@(#) $Header: addrtoname.c,v 1.54 96/12/05 22:10:19 leres Exp $ (LBL)";
27#endif
28
29#include <sys/types.h>
30#include <sys/socket.h>
31#include <sys/time.h>
32
33#if __STDC__
34struct mbuf;
35struct rtentry;
36#endif
37#include <net/if.h>
38
39#include <netinet/in.h>
40#include <net/ethernet.h>
41
42#include <arpa/inet.h>
43
44#include <ctype.h>
45#include <netdb.h>
46#include <pcap.h>
47#include <pcap-namedb.h>
48#include <signal.h>
49#include <stdio.h>
50#include <string.h>
51#include <stdlib.h>
52#include <unistd.h>
53
54#include "interface.h"
55#include "addrtoname.h"
56#include "llc.h"
57
58/* Forwards */
59static RETSIGTYPE nohostname(int);
60
61/*
62 * hash tables for whatever-to-name translations
63 */
64
65#define HASHNAMESIZE 4096
66
67struct hnamemem {
68	u_int32_t addr;
69	char *name;
70	struct hnamemem *nxt;
71};
72
73struct hnamemem hnametable[HASHNAMESIZE];
74struct hnamemem tporttable[HASHNAMESIZE];
75struct hnamemem uporttable[HASHNAMESIZE];
76struct hnamemem eprototable[HASHNAMESIZE];
77struct hnamemem dnaddrtable[HASHNAMESIZE];
78struct hnamemem llcsaptable[HASHNAMESIZE];
79
80struct enamemem {
81	u_short e_addr0;
82	u_short e_addr1;
83	u_short e_addr2;
84	char *e_name;
85	u_char *e_nsap;			/* used only for nsaptable[] */
86	struct enamemem *e_nxt;
87};
88
89struct enamemem enametable[HASHNAMESIZE];
90struct enamemem nsaptable[HASHNAMESIZE];
91
92struct protoidmem {
93	u_int32_t p_oui;
94	u_short p_proto;
95	char *p_name;
96	struct protoidmem *p_nxt;
97};
98
99struct protoidmem protoidtable[HASHNAMESIZE];
100
101/*
102 * A faster replacement for inet_ntoa().
103 */
104char *
105intoa(u_int32_t addr)
106{
107	register char *cp;
108	register u_int byte;
109	register int n;
110	static char buf[sizeof(".xxx.xxx.xxx.xxx")];
111
112	NTOHL(addr);
113	cp = &buf[sizeof buf];
114	*--cp = '\0';
115
116	n = 4;
117	do {
118		byte = addr & 0xff;
119		*--cp = byte % 10 + '0';
120		byte /= 10;
121		if (byte > 0) {
122			*--cp = byte % 10 + '0';
123			byte /= 10;
124			if (byte > 0)
125				*--cp = byte + '0';
126		}
127		*--cp = '.';
128		addr >>= 8;
129	} while (--n > 0);
130
131	return cp + 1;
132}
133
134static u_int32_t f_netmask;
135static u_int32_t f_localnet;
136static u_int32_t netmask;
137
138/*
139 * "getname" is written in this atrocious way to make sure we don't
140 * wait forever while trying to get hostnames from yp.
141 */
142#include <setjmp.h>
143
144jmp_buf getname_env;
145
146static RETSIGTYPE
147nohostname(int signo)
148{
149	longjmp(getname_env, 1);
150}
151
152/*
153 * Return a name for the IP address pointed to by ap.  This address
154 * is assumed to be in network byte order.
155 */
156char *
157getname(const u_char *ap)
158{
159	register struct hostent *hp;
160	u_int32_t addr;
161	static struct hnamemem *p;		/* static for longjmp() */
162
163#ifndef LBL_ALIGN
164	addr = *(const u_int32_t *)ap;
165#else
166	/*
167	 * Extract 32 bits in network order, dealing with alignment.
168	 */
169	switch ((long)ap & 3) {
170
171	case 0:
172		addr = *(u_int32_t *)ap;
173		break;
174
175	case 2:
176#ifdef WORDS_BIGENDIAN
177		addr = ((u_int32_t)*(u_short *)ap << 16) |
178			(u_int32_t)*(u_short *)(ap + 2);
179#else
180		addr = ((u_int32_t)*(u_short *)(ap + 2) << 16) |
181			(u_int32_t)*(u_short *)ap;
182#endif
183		break;
184
185	default:
186#ifdef WORDS_BIGENDIAN
187		addr = ((u_int32_t)ap[0] << 24) |
188			((u_int32_t)ap[1] << 16) |
189			((u_int32_t)ap[2] << 8) |
190			(u_int32_t)ap[3];
191#else
192		addr = ((u_int32_t)ap[3] << 24) |
193			((u_int32_t)ap[2] << 16) |
194			((u_int32_t)ap[1] << 8) |
195			(u_int32_t)ap[0];
196#endif
197		break;
198	}
199#endif
200	p = &hnametable[addr & (HASHNAMESIZE-1)];
201	for (; p->nxt; p = p->nxt) {
202		if (p->addr == addr)
203			return (p->name);
204	}
205	p->addr = addr;
206	p->nxt = newhnamemem();
207
208	/*
209	 * Only print names when:
210	 *	(1) -n was not given.
211	 *	(2) Address is foreign and -f was given.  If -f was not
212	 *	    present, f_netmask and f_local are 0 and the second
213	 *	    test will succeed.
214	 *	(3) The host portion is not 0 (i.e., a network address).
215	 *	(4) The host portion is not broadcast.
216	 */
217	if (!nflag && (addr & f_netmask) == f_localnet
218	    && (addr &~ netmask) != 0 && (addr | netmask) != 0xffffffff) {
219		if (!setjmp(getname_env)) {
220			(void)signal(SIGALRM, nohostname);
221			(void)alarm(20);
222			hp = gethostbyaddr((char *)&addr, 4, AF_INET);
223			(void)alarm(0);
224			if (hp) {
225				char *dotp;
226
227				p->name = savestr(hp->h_name);
228				if (Nflag) {
229					/* Remove domain qualifications */
230					dotp = strchr(p->name, '.');
231					if (dotp)
232						*dotp = '\0';
233				}
234				return (p->name);
235			}
236		}
237	}
238	p->name = savestr(intoa(addr));
239	return (p->name);
240}
241
242static char hex[] = "0123456789abcdef";
243
244
245/* Find the hash node that corresponds the ether address 'ep' */
246
247static inline struct enamemem *
248lookup_emem(const u_char *ep)
249{
250	register u_int i, j, k;
251	struct enamemem *tp;
252
253	k = (ep[0] << 8) | ep[1];
254	j = (ep[2] << 8) | ep[3];
255	i = (ep[4] << 8) | ep[5];
256
257	tp = &enametable[(i ^ j) & (HASHNAMESIZE-1)];
258	while (tp->e_nxt)
259		if (tp->e_addr0 == i &&
260		    tp->e_addr1 == j &&
261		    tp->e_addr2 == k)
262			return tp;
263		else
264			tp = tp->e_nxt;
265	tp->e_addr0 = i;
266	tp->e_addr1 = j;
267	tp->e_addr2 = k;
268	tp->e_nxt = (struct enamemem *)calloc(1, sizeof(*tp));
269	if (tp->e_nxt == NULL)
270		error("lookup_emem: calloc");
271
272	return tp;
273}
274
275/* Find the hash node that corresponds the NSAP 'nsap' */
276
277static inline struct enamemem *
278lookup_nsap(register const u_char *nsap)
279{
280	register u_int i, j, k;
281	int nlen = *nsap;
282	struct enamemem *tp;
283	const u_char *ensap = nsap + nlen - 6;
284
285	if (nlen > 6) {
286		k = (ensap[0] << 8) | ensap[1];
287		j = (ensap[2] << 8) | ensap[3];
288		i = (ensap[4] << 8) | ensap[5];
289	}
290	else
291		i = j = k = 0;
292
293	tp = &nsaptable[(i ^ j) & (HASHNAMESIZE-1)];
294	while (tp->e_nxt)
295		if (tp->e_addr0 == i &&
296		    tp->e_addr1 == j &&
297		    tp->e_addr2 == k &&
298		    tp->e_nsap[0] == nlen &&
299		    memcmp((char *)&(nsap[1]),
300			(char *)&(tp->e_nsap[1]), nlen) == 0)
301			return tp;
302		else
303			tp = tp->e_nxt;
304	tp->e_addr0 = i;
305	tp->e_addr1 = j;
306	tp->e_addr2 = k;
307	tp->e_nsap = (u_char *)malloc(nlen + 1);
308	if (tp->e_nsap == NULL)
309		error("lookup_nsap: malloc");
310	memcpy(tp->e_nsap, nsap, nlen + 1);
311	tp->e_nxt = (struct enamemem *)calloc(1, sizeof(*tp));
312	if (tp->e_nxt == NULL)
313		error("lookup_nsap: calloc");
314
315	return tp;
316}
317
318/* Find the hash node that corresponds the protoid 'pi'. */
319
320static inline struct protoidmem *
321lookup_protoid(const u_char *pi)
322{
323	register u_int i, j;
324	struct protoidmem *tp;
325
326	/* 5 octets won't be aligned */
327	i = (((pi[0] << 8) + pi[1]) << 8) + pi[2];
328	j =   (pi[3] << 8) + pi[4];
329	/* XXX should be endian-insensitive, but do big-endian testing  XXX */
330
331	tp = &protoidtable[(i ^ j) & (HASHNAMESIZE-1)];
332	while (tp->p_nxt)
333		if (tp->p_oui == i && tp->p_proto == j)
334			return tp;
335		else
336			tp = tp->p_nxt;
337	tp->p_oui = i;
338	tp->p_proto = j;
339	tp->p_nxt = (struct protoidmem *)calloc(1, sizeof(*tp));
340	if (tp->p_nxt == NULL)
341		error("lookup_protoid: calloc");
342
343	return tp;
344}
345
346char *
347etheraddr_string(register const u_char *ep)
348{
349	register u_int i, j;
350	register char *cp;
351	register struct enamemem *tp;
352	char buf[sizeof("00:00:00:00:00:00")];
353
354	tp = lookup_emem(ep);
355	if (tp->e_name)
356		return (tp->e_name);
357#ifdef HAVE_ETHER_NTOHOST
358	if (!nflag) {
359		char buf[128];
360		if (ether_ntohost(buf, (struct ether_addr *)ep) == 0) {
361			tp->e_name = savestr(buf);
362			return (tp->e_name);
363		}
364	}
365#endif
366	cp = buf;
367	if ((j = *ep >> 4) != 0)
368		*cp++ = hex[j];
369	*cp++ = hex[*ep++ & 0xf];
370	for (i = 5; (int)--i >= 0;) {
371		*cp++ = ':';
372		if ((j = *ep >> 4) != 0)
373			*cp++ = hex[j];
374		*cp++ = hex[*ep++ & 0xf];
375	}
376	*cp = '\0';
377	tp->e_name = savestr(buf);
378	return (tp->e_name);
379}
380
381char *
382etherproto_string(u_short port)
383{
384	register char *cp;
385	register struct hnamemem *tp;
386	register u_int32_t i = port;
387	char buf[sizeof("0000")];
388
389	for (tp = &eprototable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
390		if (tp->addr == i)
391			return (tp->name);
392
393	tp->addr = i;
394	tp->nxt = newhnamemem();
395
396	cp = buf;
397	NTOHS(port);
398	*cp++ = hex[port >> 12 & 0xf];
399	*cp++ = hex[port >> 8 & 0xf];
400	*cp++ = hex[port >> 4 & 0xf];
401	*cp++ = hex[port & 0xf];
402	*cp++ = '\0';
403	tp->name = savestr(buf);
404	return (tp->name);
405}
406
407char *
408protoid_string(register const u_char *pi)
409{
410	register u_int i, j;
411	register char *cp;
412	register struct protoidmem *tp;
413	char buf[sizeof("00:00:00:00:00")];
414
415	tp = lookup_protoid(pi);
416	if (tp->p_name)
417		return tp->p_name;
418
419	cp = buf;
420	if ((j = *pi >> 4) != 0)
421		*cp++ = hex[j];
422	*cp++ = hex[*pi++ & 0xf];
423	for (i = 4; (int)--i >= 0;) {
424		*cp++ = ':';
425		if ((j = *pi >> 4) != 0)
426			*cp++ = hex[j];
427		*cp++ = hex[*pi++ & 0xf];
428	}
429	*cp = '\0';
430	tp->p_name = savestr(buf);
431	return (tp->p_name);
432}
433
434char *
435llcsap_string(u_char sap)
436{
437	register char *cp;
438	register struct hnamemem *tp;
439	register u_int32_t i = sap;
440	char buf[sizeof("sap 00")];
441
442	for (tp = &llcsaptable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
443		if (tp->addr == i)
444			return (tp->name);
445
446	tp->addr = i;
447	tp->nxt = newhnamemem();
448
449	cp = buf;
450	(void)strcpy(cp, "sap ");
451	cp += strlen(cp);
452	*cp++ = hex[sap >> 4 & 0xf];
453	*cp++ = hex[sap & 0xf];
454	*cp++ = '\0';
455	tp->name = savestr(buf);
456	return (tp->name);
457}
458
459char *
460isonsap_string(const u_char *nsap)
461{
462	register u_int i, nlen = nsap[0];
463	register char *cp;
464	register struct enamemem *tp;
465
466	tp = lookup_nsap(nsap);
467	if (tp->e_name)
468		return tp->e_name;
469
470	tp->e_name = cp = (char *)malloc(nlen * 2 + 2 + (nlen>>1));
471	if (cp == NULL)
472		error("isonsap_string: malloc");
473
474	nsap++;
475	for (i = 0; i < nlen; i++) {
476		*cp++ = hex[*nsap >> 4];
477		*cp++ = hex[*nsap++ & 0xf];
478		if (((i & 1) == 0) && (i + 1 < nlen))
479			*cp++ = '.';
480	}
481	*cp = '\0';
482	return (tp->e_name);
483}
484
485char *
486tcpport_string(u_short port)
487{
488	register struct hnamemem *tp;
489	register u_int32_t i = port;
490	char buf[sizeof("00000")];
491
492	for (tp = &tporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
493		if (tp->addr == i)
494			return (tp->name);
495
496	tp->addr = i;
497	tp->nxt = newhnamemem();
498
499	(void)sprintf(buf, "%u", i);
500	tp->name = savestr(buf);
501	return (tp->name);
502}
503
504char *
505udpport_string(register u_short port)
506{
507	register struct hnamemem *tp;
508	register u_int32_t i = port;
509	char buf[sizeof("00000")];
510
511	for (tp = &uporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
512		if (tp->addr == i)
513			return (tp->name);
514
515	tp->addr = i;
516	tp->nxt = newhnamemem();
517
518	(void)sprintf(buf, "%u", i);
519	tp->name = savestr(buf);
520	return (tp->name);
521}
522
523static void
524init_servarray(void)
525{
526	struct servent *sv;
527	register struct hnamemem *table;
528	register int i;
529	char buf[sizeof("0000000000")];
530
531	while ((sv = getservent()) != NULL) {
532		int port = ntohs(sv->s_port);
533		i = port & (HASHNAMESIZE-1);
534		if (strcmp(sv->s_proto, "tcp") == 0)
535			table = &tporttable[i];
536		else if (strcmp(sv->s_proto, "udp") == 0)
537			table = &uporttable[i];
538		else
539			continue;
540
541		while (table->name)
542			table = table->nxt;
543		if (nflag) {
544			(void)sprintf(buf, "%d", port);
545			table->name = savestr(buf);
546		} else
547			table->name = savestr(sv->s_name);
548		table->addr = port;
549		table->nxt = newhnamemem();
550	}
551	endservent();
552}
553
554/*XXX from libbpfc.a */
555extern struct eproto {
556	char *s;
557	u_short p;
558} eproto_db[];
559
560static void
561init_eprotoarray(void)
562{
563	register int i;
564	register struct hnamemem *table;
565
566	for (i = 0; eproto_db[i].s; i++) {
567		int j = ntohs(eproto_db[i].p) & (HASHNAMESIZE-1);
568		table = &eprototable[j];
569		while (table->name)
570			table = table->nxt;
571		table->name = eproto_db[i].s;
572		table->addr = ntohs(eproto_db[i].p);
573		table->nxt = newhnamemem();
574	}
575}
576
577/*
578 * SNAP proto IDs with org code 0:0:0 are actually encapsulated Ethernet
579 * types.
580 */
581static void
582init_protoidarray(void)
583{
584	register int i;
585	register struct protoidmem *tp;
586	u_char protoid[5];
587
588	protoid[0] = 0;
589	protoid[1] = 0;
590	protoid[2] = 0;
591	for (i = 0; eproto_db[i].s; i++) {
592		u_short etype = htons(eproto_db[i].p);
593
594		memcpy((char *)&protoid[3], (char *)&etype, 2);
595		tp = lookup_protoid(protoid);
596		tp->p_name = savestr(eproto_db[i].s);
597	}
598}
599
600static struct etherlist {
601	u_char addr[6];
602	char *name;
603} etherlist[] = {
604	{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, "Broadcast" },
605	{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, NULL }
606};
607
608/*
609 * Initialize the ethers hash table.  We take two different approaches
610 * depending on whether or not the system provides the ethers name
611 * service.  If it does, we just wire in a few names at startup,
612 * and etheraddr_string() fills in the table on demand.  If it doesn't,
613 * then we suck in the entire /etc/ethers file at startup.  The idea
614 * is that parsing the local file will be fast, but spinning through
615 * all the ethers entries via NIS & next_etherent might be very slow.
616 *
617 * XXX pcap_next_etherent doesn't belong in the pcap interface, but
618 * since the pcap module already does name-to-address translation,
619 * it's already does most of the work for the ethernet address-to-name
620 * translation, so we just pcap_next_etherent as a convenience.
621 */
622static void
623init_etherarray(void)
624{
625	register struct etherlist *el;
626	register struct enamemem *tp;
627#ifdef HAVE_ETHER_NTOHOST
628	char name[256];
629#else
630	register struct pcap_etherent *ep;
631	register FILE *fp;
632
633	/* Suck in entire ethers file */
634	fp = fopen(PCAP_ETHERS_FILE, "r");
635	if (fp != NULL) {
636		while ((ep = pcap_next_etherent(fp)) != NULL) {
637			tp = lookup_emem(ep->addr);
638			tp->e_name = savestr(ep->name);
639		}
640		(void)fclose(fp);
641	}
642#endif
643
644	/* Hardwire some ethernet names */
645	for (el = etherlist; el->name != NULL; ++el) {
646		tp = lookup_emem(el->addr);
647		/* Don't override existing name */
648		if (tp->e_name != NULL)
649			continue;
650
651#ifdef HAVE_ETHER_NTOHOST
652                /* Use yp/nis version of name if available */
653                if (ether_ntohost(name, (struct ether_addr *)el->addr) == 0) {
654                        tp->e_name = savestr(name);
655			continue;
656		}
657#endif
658		tp->e_name = el->name;
659	}
660}
661
662static struct tok llcsap_db[] = {
663	{ LLCSAP_NULL,		"null" },
664	{ LLCSAP_8021B_I,	"802.1b-gsap" },
665	{ LLCSAP_8021B_G,	"802.1b-isap" },
666	{ LLCSAP_IP,		"ip-sap" },
667	{ LLCSAP_PROWAYNM,	"proway-nm" },
668	{ LLCSAP_8021D,		"802.1d" },
669	{ LLCSAP_RS511,		"eia-rs511" },
670	{ LLCSAP_ISO8208,	"x.25/llc2" },
671	{ LLCSAP_PROWAY,	"proway" },
672	{ LLCSAP_ISONS,		"iso-clns" },
673	{ LLCSAP_GLOBAL,	"global" },
674	{ 0,			NULL }
675};
676
677static void
678init_llcsaparray(void)
679{
680	register int i;
681	register struct hnamemem *table;
682
683	for (i = 0; llcsap_db[i].s != NULL; i++) {
684		table = &llcsaptable[llcsap_db[i].v];
685		while (table->name)
686			table = table->nxt;
687		table->name = llcsap_db[i].s;
688		table->addr = llcsap_db[i].v;
689		table->nxt = newhnamemem();
690	}
691}
692
693/*
694 * Initialize the address to name translation machinery.  We map all
695 * non-local IP addresses to numeric addresses if fflag is true (i.e.,
696 * to prevent blocking on the nameserver).  localnet is the IP address
697 * of the local network.  mask is its subnet mask.
698 */
699void
700init_addrtoname(int fflag, u_int32_t localnet, u_int32_t mask)
701{
702	netmask = mask;
703	if (fflag) {
704		f_localnet = localnet;
705		f_netmask = mask;
706	}
707	if (nflag)
708		/*
709		 * Simplest way to suppress names.
710		 */
711		return;
712
713	init_etherarray();
714	init_servarray();
715	init_eprotoarray();
716	init_llcsaparray();
717	init_protoidarray();
718}
719
720char *
721dnaddr_string(u_short dnaddr)
722{
723	register struct hnamemem *tp;
724
725	for (tp = &dnaddrtable[dnaddr & (HASHNAMESIZE-1)]; tp->nxt != 0;
726	     tp = tp->nxt)
727		if (tp->addr == dnaddr)
728			return (tp->name);
729
730	tp->addr = dnaddr;
731	tp->nxt = newhnamemem();
732	if (nflag)
733		tp->name = dnnum_string(dnaddr);
734	else
735		tp->name = dnname_string(dnaddr);
736
737	return(tp->name);
738}
739
740/* Return a zero'ed hnamemem struct and cuts down on calloc() overhead */
741struct hnamemem *
742newhnamemem(void)
743{
744	register struct hnamemem *p;
745	static struct hnamemem *ptr = NULL;
746	static u_int num = 0;
747
748	if (num  <= 0) {
749		num = 64;
750		ptr = (struct hnamemem *)calloc(num, sizeof (*ptr));
751		if (ptr == NULL)
752			error("newhnamemem: calloc");
753	}
754	--num;
755	p = ptr++;
756	return (p);
757}
758