xref: /386bsd/usr/src/usr.sbin/tcpdump/addrtoname.c (revision a2142627)
1 /*
2  * Copyright (c) 1988, 1990 The Regents of the University of California.
3  * 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
25 static char rcsid[] =
26     "@(#) $Header: addrtoname.c,v 1.9 91/05/06 02:11:44 mccanne Exp $ (LBL)";
27 #endif
28 
29 #include <stdio.h>
30 #include <strings.h>
31 #include <ctype.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <net/if.h>
35 #include <netdb.h>
36 #include <netinet/in.h>
37 #include <netinet/if_ether.h>
38 #include <arpa/inet.h>
39 #include <signal.h>
40 
41 #include "interface.h"
42 #include "addrtoname.h"
43 #include "nametoaddr.h"
44 #include "etherent.h"
45 
46 /*
47  * hash tables for whatever-to-name translations
48  */
49 
50 #define HASHNAMESIZE 4096
51 
52 struct hnamemem {
53 	u_long addr;
54 	char *name;
55 	struct hnamemem *nxt;
56 };
57 
58 struct hnamemem hnametable[HASHNAMESIZE];
59 struct hnamemem tporttable[HASHNAMESIZE];
60 struct hnamemem uporttable[HASHNAMESIZE];
61 struct hnamemem eprototable[HASHNAMESIZE];
62 
63 struct enamemem {
64 	u_short e_addr0;
65 	u_short e_addr1;
66 	u_short e_addr2;
67 	char *e_name;
68 	struct enamemem *e_nxt;
69 };
70 
71 struct enamemem enametable[HASHNAMESIZE];
72 
73 
74 /*
75  * A faster replacement for inet_ntoa().
76  */
77 char *
intoa(addr)78 intoa(addr)
79 	u_long addr;
80 {
81 	register char *cp;
82 	register u_int byte;
83 	register int n;
84 	static char buf[sizeof(".xxx.xxx.xxx.xxx")];
85 
86 	NTOHL(addr);
87 	cp = &buf[sizeof buf];
88 	*--cp = '\0';
89 
90 	n = 4;
91 	do {
92 		byte = addr & 0xff;
93 		*--cp = byte % 10 + '0';
94 		byte /= 10;
95 		if (byte > 0) {
96 			*--cp = byte % 10 + '0';
97 			byte /= 10;
98 			if (byte > 0)
99 				*--cp = byte + '0';
100 		}
101 		*--cp = '.';
102 		addr >>= 8;
103 	} while (--n > 0);
104 
105 	return cp + 1;
106 }
107 
108 static u_long f_netmask;
109 static u_long f_localnet;
110 static u_long netmask;
111 
112 /*
113  * "getname" is written in this atrocious way to make sure we don't
114  * wait forever while trying to get hostnames from yp.
115  */
116 #include <setjmp.h>
117 
118 jmp_buf getname_env;
119 
120 static void
nohostname()121 nohostname()
122 {
123 	longjmp(getname_env, 1);
124 }
125 
126 char *
getname(addr)127 getname(addr)
128 	u_long addr;
129 {
130 	register struct hnamemem *p;
131 	register struct hostent *hp;
132 	register u_long raddr = addr;
133 	register char *cp;
134 
135 	p = &hnametable[ntohl(raddr) & (HASHNAMESIZE-1)];
136 	for (; p->nxt; p = p->nxt) {
137 		if (p->addr == raddr)
138 			return (p->name);
139 	}
140 	p->addr = raddr;
141 	p->nxt = (struct hnamemem *)calloc(1, sizeof (*p));
142 
143 	/*
144 	 * Only print names when:
145 	 * 	(1) -n was not given.
146 	 *	(2) Address is foreign and -f was given.  If -f was not
147 	 *	    present, f_netmask and f_local are 0 and the second
148 	 *	    test will succeed.
149 	 *	(3) The host portion is not 0 (i.e., a network address).
150 	 *	(4) The host portion is not broadcast.
151 	 */
152 	if (!nflag && (raddr & f_netmask) == f_localnet
153 	    && (raddr &~ netmask) != 0 && (raddr | netmask) != 0xffffffff) {
154 		if (!setjmp(getname_env)) {
155 			(void)signal(SIGALRM, nohostname);
156 			(void)alarm(20);
157 			hp = gethostbyaddr((char *)&addr, sizeof(addr),
158 					   AF_INET);
159 			(void)alarm(0);
160 			if (hp) {
161 				char *index();
162 				char *dotp;
163 				u_int len = strlen(hp->h_name) + 1;
164 				p->name = (char *)malloc(len);
165 				(void)strcpy(p->name, hp->h_name);
166 				if (Nflag) {
167 					/* Remove domain qualifications */
168 					dotp = index(p->name, '.');
169 					if (dotp)
170 						*dotp = 0;
171 				}
172 				return (p->name);
173 			}
174 		}
175 	}
176 	cp = intoa(raddr);
177 	p->name = (char *)malloc((unsigned)(strlen(cp) + 1));
178 	(void)strcpy(p->name, cp);
179 	return (p->name);
180 }
181 
182 static char hex[] = "0123456789abcdef";
183 
184 
185 /* Find the hash node that corresponds the ether address 'ep'. */
186 
187 static inline struct enamemem *
lookup_emem(ep)188 lookup_emem(ep)
189 	u_char *ep;
190 {
191 	register u_int i, j;
192 	struct enamemem *tp;
193 
194 	i = *(u_short *)(ep + 4);
195 	j = *(u_short *)(ep + 2);
196 
197 	tp = &enametable[(i ^ j) & (HASHNAMESIZE-1)];
198 	while (tp->e_nxt)
199 		if (tp->e_addr0 == i &&
200 		    tp->e_addr1 == j &&
201 		    tp->e_addr2 == *(u_short *)ep)
202 			return tp;
203 		else
204 			tp = tp->e_nxt;
205 	tp->e_addr0 = i;
206 	tp->e_addr1 = j;
207 	tp->e_addr2 = *(u_short *)ep;
208 	tp->e_nxt = (struct enamemem *)calloc(1, sizeof(*tp));
209 
210 	return tp;
211 }
212 
213 char *
etheraddr_string(ep)214 etheraddr_string(ep)
215 	register u_char *ep;
216 {
217 	register u_int i, j;
218 	register char *cp;
219 	register struct enamemem *tp;
220 
221 	tp = lookup_emem(ep);
222 	if (tp->e_name)
223 		return tp->e_name;
224 
225 #ifdef ETHER_SERVICE
226 	if (!nflag) {
227 		cp = ETHER_ntohost(ep);
228 		if (cp) {
229 			tp->e_name = cp;
230 			return cp;
231 		}
232 	}
233 #endif
234 	tp->e_name = cp = (char *)malloc(sizeof("00:00:00:00:00:00"));
235 
236 	if (j = *ep >> 4)
237 		*cp++ = hex[j];
238 	*cp++ = hex[*ep++ & 0xf];
239 	for (i = 5; (int)--i >= 0;) {
240 		*cp++ = ':';
241 		if (j = *ep >> 4)
242 			*cp++ = hex[j];
243 		*cp++ = hex[*ep++ & 0xf];
244 	}
245 	*cp = '\0';
246 	return (tp->e_name);
247 }
248 
249 char *
etherproto_string(port)250 etherproto_string(port)
251 	u_short port;
252 {
253 	register char *cp;
254 	register struct hnamemem *tp;
255 	register u_long i = port;
256 
257 	for (tp = &eprototable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
258 		if (tp->addr == i)
259 			return (tp->name);
260 
261 	tp->name = cp = (char *)malloc(sizeof("0000"));
262 	tp->addr = i;
263 	tp->nxt = (struct hnamemem *)calloc(1, sizeof (*tp));
264 
265 	NTOHS(port);
266 	*cp++ = hex[port >> 12 & 0xf];
267 	*cp++ = hex[port >> 8 & 0xf];
268 	*cp++ = hex[port >> 4 & 0xf];
269 	*cp++ = hex[port & 0xf];
270 	*cp++ = '\0';
271 	return (tp->name);
272 }
273 
274 char *
tcpport_string(port)275 tcpport_string(port)
276 	u_short port;
277 {
278 	register struct hnamemem *tp;
279 	register int i = port;
280 
281 	for (tp = &tporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
282 		if (tp->addr == i)
283 			return (tp->name);
284 
285 	tp->name = (char *)malloc(sizeof("00000"));
286 	tp->addr = i;
287 	tp->nxt = (struct hnamemem *)calloc(1, sizeof (*tp));
288 
289 	(void)sprintf(tp->name, "%d", i);
290 	return (tp->name);
291 }
292 
293 char *
udpport_string(port)294 udpport_string(port)
295 	register u_short port;
296 {
297 	register struct hnamemem *tp;
298 	register int i = port;
299 
300 	for (tp = &uporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
301 		if (tp->addr == i)
302 			return (tp->name);
303 
304 	tp->name = (char *)malloc(sizeof("00000"));
305 	tp->addr = i;
306 	tp->nxt = (struct hnamemem *)calloc(1, sizeof(*tp));
307 
308 	(void)sprintf(tp->name, "%d", i);
309 
310 	return (tp->name);
311 }
312 
313 static void
init_servarray()314 init_servarray()
315 {
316 	struct servent *sv;
317 	register struct hnamemem *table;
318 	register int i;
319 
320 	while (sv = getservent()) {
321 		NTOHS(sv->s_port);
322 		i = sv->s_port & (HASHNAMESIZE-1);
323 		if (strcmp(sv->s_proto, "tcp") == 0)
324 			table = &tporttable[i];
325 		else if (strcmp(sv->s_proto, "udp") == 0)
326 			table = &uporttable[i];
327 		else
328 			continue;
329 
330 		while (table->name)
331 			table = table->nxt;
332 		if (nflag) {
333 			char buf[32];
334 
335 			(void)sprintf(buf, "%d", sv->s_port);
336 			table->name = (char *)malloc((unsigned)strlen(buf)+1);
337 			(void)strcpy(table->name, buf);
338 		} else {
339 			table->name =
340 				(char *)malloc((unsigned)strlen(sv->s_name)+1);
341 			(void)strcpy(table->name, sv->s_name);
342 		}
343 		table->addr = sv->s_port;
344 		table->nxt = (struct hnamemem *)calloc(1, sizeof(*table));
345 	}
346 	endservent();
347 }
348 
349 #include "etherproto.h"
350 
351 /* Static data base of ether protocol types. */
352 struct eproto eproto_db[] = {
353 	{ "pup", ETHERTYPE_PUP },
354 	{ "xns", ETHERTYPE_NS },
355 	{ "ip", ETHERTYPE_IP },
356 	{ "arp", ETHERTYPE_ARP },
357 	{ "rarp", ETHERTYPE_REVARP },
358 	{ "sprite", ETHERTYPE_SPRITE },
359 	{ "mopdl", ETHERTYPE_MOPDL },
360 	{ "moprc", ETHERTYPE_MOPRC },
361 	{ "decnet", ETHERTYPE_DN },
362 	{ "lat", ETHERTYPE_LAT },
363 	{ "lanbridge", ETHERTYPE_LANBRIDGE },
364 	{ "vexp", ETHERTYPE_VEXP },
365 	{ "vprod", ETHERTYPE_VPROD },
366 	{ "atalk", ETHERTYPE_ATALK },
367 	{ "atalkarp", ETHERTYPE_AARP },
368 	{ "loopback", ETHERTYPE_LOOPBACK },
369 	{ (char *)0, 0 }
370 };
371 
372 static void
init_eprotoarray()373 init_eprotoarray()
374 {
375 	register int i;
376 	register struct hnamemem *table;
377 
378 	for (i = 0; eproto_db[i].s; i++) {
379 		int j = ntohs(eproto_db[i].p) & (HASHNAMESIZE-1);
380 		table = &eprototable[j];
381 		while (table->name)
382 			table = table->nxt;
383 		table->name = eproto_db[i].s;
384 		table->addr = ntohs(eproto_db[i].p);
385 		table->nxt = (struct hnamemem *)calloc(1, sizeof(*table));
386 	}
387 }
388 
389 static void
init_etherarray()390 init_etherarray()
391 {
392 #ifndef ETHER_SERVICE
393 	FILE *fp;
394 	struct etherent *ep;
395 	struct enamemem *tp;
396 
397 	fp = fopen(ETHERS_FILE, "r");
398 	if (fp == 0)
399 		/* No data base; will have to settle for
400 		   numeric addresses. */
401 		return;
402 
403 	while (ep = next_etherent(fp)) {
404 		tp = lookup_emem(ep->addr);
405 		tp->e_name = (char *)malloc((unsigned)strlen(ep->name)+1);
406 		strcpy(tp->e_name, ep->name);
407 	}
408 #endif
409 }
410 
411 void
init_addrtoname(device,fflag)412 init_addrtoname(device, fflag)
413 	char *device;
414 	int fflag;
415 {
416 	u_long localnet;
417 
418 	if (device != 0)
419 		lookup_net(device, &localnet, &netmask);
420 	if (fflag) {
421 		f_localnet = localnet;
422 		f_netmask = netmask;
423 	}
424 	if (nflag)
425 		/*
426 		 * Simplest way to suppress names.
427 		 */
428 		return;
429 
430 	init_etherarray();
431 	init_servarray();
432 	init_eprotoarray();
433 }
434