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