xref: /csrg-svn/old/htable/htable.c (revision 33539)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that this notice is preserved and that due credit is given
7  * to the University of California at Berkeley. The name of the University
8  * may not be used to endorse or promote products derived from this
9  * software without specific prior written permission. This software
10  * is provided ``as is'' without express or implied warranty.
11  */
12 
13 #ifndef lint
14 char copyright[] =
15 "@(#) Copyright (c) 1983 Regents of the University of California.\n\
16  All rights reserved.\n";
17 #endif /* not lint */
18 
19 #ifndef lint
20 static char sccsid[] = "@(#)htable.c	5.7 (Berkeley) 02/23/88";
21 #endif /* not lint */
22 
23 /*
24  * htable - convert NIC host table into a UNIX format.
25  * NIC format is described in RFC 810, 1 March 1982.
26  */
27 #include <stdio.h>
28 #include <ctype.h>
29 #include <errno.h>
30 #include <netdb.h>
31 
32 #include "htable.h"		/* includes <sys/types.h> */
33 
34 #include <sys/socket.h>
35 #include <arpa/inet.h>
36 
37 #define	DATELINES	3	/* these lines usually contain the date */
38 #define	MAXNETS		30	/* array size for local, connected nets */
39 
40 FILE	*hf;			/* hosts file */
41 FILE	*gf;			/* gateways file */
42 FILE	*nf;			/* networks file */
43 struct gateway *savegateway(), *gatewayto();
44 
45 int connected_nets[MAXNETS];
46 int nconnected;
47 int local_nets[MAXNETS];
48 int nlocal;
49 char *myname;
50 
51 main(argc, argv)
52 	int argc;
53 	char *argv[];
54 {
55 	int errs;
56 
57 	infile = "(stdin)";
58 	myname = argv[0];
59 	argc--;
60 	argv++;
61 	while (argc--) {
62 		if (*argv[0] == '-') {
63 			switch (argv[0][1]) {
64 			case 'c':
65 				nconnected = addlocal(argv[1], connected_nets);
66 				argv++;
67 				argc--;
68 				break;
69 			case 'l':
70 				nlocal = addlocal(argv[1], local_nets);
71 				argv++;
72 				argc--;
73 				break;
74 			default:
75 				usage();
76 				/*NOTREACHED*/
77 			}
78 		} else {
79 			infile = argv[0];
80 			if (freopen(infile, "r", stdin) == NULL) {
81 				perror(infile);
82 				exit(1);
83 			}
84 		}
85 		argv++;
86 	}
87 	hf = fopen("hosts", "w");
88 	if (hf == NULL) {
89 		perror("hosts");
90 		exit(1);
91 	}
92 	copylocal(hf, "localhosts");
93 	gf = fopen("gateways", "w");
94 	if (gf == NULL) {
95 		perror("gateways");
96 		exit(1);
97 	}
98 	copygateways("localgateways");
99 	nf = fopen("networks", "w");
100 	if (nf == NULL) {
101 		perror("networks");
102 		exit(1);
103 	}
104 	copylocal(nf, "localnetworks");
105 	copycomments(stdin, hf, DATELINES);
106 	errs = yyparse();
107 	dogateways();
108 	exit(errs);
109 }
110 
111 usage()
112 {
113 	fprintf(stderr,
114 	"usage: %s [ -c connected-nets ] [-l local-nets ] [ input-file ]\n",
115 		myname);
116 	exit(1);
117 }
118 
119 /*
120  *  Turn a comma-separated list of network names or numbers in dot notation
121  *  (e.g.  "arpanet, 128.32") into an array of net numbers.
122  */
123 addlocal(arg, nets)
124 	char *arg;
125 	int *nets;
126 {
127 	register char *p, c;
128 	register int nfound = 0;
129 
130 	do {
131 		p = arg;
132 		while (*p && *p != ',' && !isspace(*p))
133 			p++;
134 		c = *p;
135 		*p = 0;
136 		while (*arg && isspace(*arg))
137 			arg++;
138 		if (*arg == 0)
139 			continue;
140 		if (nfound == MAXNETS) {
141 			fprintf(stderr, "%s: Too many networks in list\n",
142 				myname);
143 			return (nfound);
144 		}
145 		if (getnetaddr(arg, &nets[nfound]))
146 			nfound++;
147 		else {
148 			fprintf(stderr, "%s: %s: unknown network\n",
149 				myname, arg);
150 			exit(1);
151 		}
152 		arg = p + 1;
153 	} while (c);
154 	return (nfound);
155 }
156 
157 struct name *
158 newname(str)
159 	char *str;
160 {
161 	char *p;
162 	struct name *nm;
163 
164 	p = malloc(strlen(str) + 1);
165 	strcpy(p, str);
166 	nm = (struct name *)malloc(sizeof (struct name));
167 	nm->name_val = p;
168 	nm->name_link = NONAME;
169 	return (nm);
170 }
171 
172 char *
173 lower(str)
174 	char *str;
175 {
176 	register char *cp = str;
177 
178 	while (*cp) {
179 		if (isupper(*cp))
180 			*cp = tolower(*cp);
181 		cp++;
182 	}
183 	return (str);
184 }
185 
186 do_entry(keyword, addrlist, namelist, cputype, opsys, protos)
187 	int keyword;
188 	struct addr *addrlist;
189 	struct name *namelist, *cputype, *opsys, *protos;
190 {
191 	register struct addr *al, *al2;
192 	register struct name *nl;
193 	struct addr *connect_addr;
194 	char *cp;
195 
196 	switch (keyword) {
197 
198 	case KW_NET:
199 		nl = namelist;
200 		if (nl == NONAME) {
201 			fprintf(stderr, "htable: net");
202 			putnet(stderr, inet_netof(addrlist->addr_val));
203 			fprintf(stderr, " missing names.\n");
204 			break;
205 		}
206 		fprintf(nf, "%-16.16s", lower(nl->name_val));
207 		al2 = addrlist;
208 		while (al = al2) {
209 			char *cp;
210 
211 			putnet(nf, inet_netof(al->addr_val));
212 			cp = "\t%s";
213 			while (nl = nl->name_link) {
214 				fprintf(nf, cp, lower(nl->name_val));
215 				cp = " %s";
216 			}
217 			putc('\n', nf);
218 			al2 = al->addr_link;
219 			free((char *)al);
220 		}
221 		break;
222 
223 	case KW_GATEWAY:
224 		/* locate locally connected address, if one */
225 		for (al = addrlist; al; al = al->addr_link)
226 			if (connectedto(inet_netof(al->addr_val)))
227 				break;
228 		if (al == NULL) {
229 			/*
230 			 * Not connected to known networks.  Save for later.
231 			 */
232 			struct gateway *gw, *firstgw = (struct gateway *) NULL;
233 
234 			for (al = addrlist; al; al = al->addr_link) {
235 				register int net;
236 
237 				net = inet_netof(al->addr_val);
238 				gw = savegateway(namelist, net,
239 				    al->addr_val, 0);
240 				if (firstgw == (struct gateway *) NULL)
241 					firstgw = gw;
242 				gw->g_firstent = firstgw;
243 			}
244 			freeaddrs(addrlist);
245 			goto dontfree;
246 		}
247 		/*
248 		 * Connected to a known network.
249 		 * Mark this as the gateway to all other networks
250 		 * that are on the addrlist (unless we already have
251 		 * gateways to them).
252 		 */
253 		connect_addr = al;
254 		for (al = addrlist; al; al = al->addr_link) {
255 			register int net;
256 
257 			/* suppress duplicates -- not optimal */
258 			net = inet_netof(al->addr_val);
259 			if (connectedto(net) || gatewayto(net))
260 				continue;
261 			printgateway(net, namelist->name_val, 1);
262 			(void) savegateway(namelist, net, al->addr_val, 1);
263 		}
264 		/*
265 		 * Put the gateway in the hosts file.
266 		 */
267 		putaddr(hf, connect_addr->addr_val);
268 		cp = "%s";
269 		for (nl = namelist; nl; nl = nl->name_link) {
270 			fprintf(hf, cp, lower(nl->name_val));
271 			cp = " %s";
272 		}
273 		fprintf(hf, "\t# gateway\n");
274 		freeaddrs(addrlist);
275 		goto dontfree;
276 
277 	case KW_HOST:
278 		al2 = addrlist;
279 		while (al = al2) {
280 			if (!local(inet_netof(al->addr_val))) {
281 				char *cp;
282 
283 				putaddr(hf, al->addr_val);
284 				cp = "%s";
285 				for (nl = namelist; nl; nl = nl->name_link) {
286 					fprintf(hf, cp, lower(nl->name_val));
287 					cp = " %s";
288 				}
289 				putc('\n', hf);
290 			}
291 			al2 = al->addr_link;
292 			free((char *)al);
293 		}
294 		break;
295 
296 	default:
297 		fprintf(stderr, "Unknown keyword: %d.\n", keyword);
298 	}
299 	freenames(namelist);
300 dontfree:
301 	freenames(protos);
302 }
303 
304 printgateway(net, name, metric)
305 	int net;
306 	char *name;
307 	int metric;
308 {
309 	struct netent *np;
310 
311 	fprintf(gf, "net ");
312 	np = getnetbyaddr(net, AF_INET);
313 	if (np)
314 		fprintf(gf, "%s", np->n_name);
315 	else
316 		putnet(gf, net);
317 	fprintf(gf, " gateway %s metric %d passive\n",
318 		lower(name), metric);
319 }
320 
321 copylocal(f, filename)
322 	FILE *f;
323 	char *filename;
324 {
325 	register FILE *lhf;
326 	register cc;
327 	char buf[BUFSIZ];
328 	extern int errno;
329 
330 	lhf = fopen(filename, "r");
331 	if (lhf == NULL) {
332 		if (errno != ENOENT) {
333 			perror(filename);
334 			exit(1);
335 		}
336 		fprintf(stderr, "Warning, no %s file.\n", filename);
337 		return;
338 	}
339 	while (cc = fread(buf, 1, sizeof(buf), lhf))
340 		fwrite(buf, 1, cc, f);
341 	fclose(lhf);
342 }
343 
344 copygateways(filename)
345 	char *filename;
346 {
347 	register FILE *lhf;
348 	struct name *nl;
349 	char type[80];
350 	char dname[80];
351 	char gname[80];
352 	char junk[80];
353 	char buf[500];
354 	struct in_addr addr;
355 	int net, metric;
356 	extern int errno;
357 
358 	lhf = fopen(filename, "r");
359 	if (lhf == NULL) {
360 		if (errno != ENOENT) {
361 			perror(filename);
362 			exit(1);
363 		}
364 		fprintf(stderr, "Warning, no %s file.\n", filename);
365 		return;
366 	}
367 	/* format: {net | host} XX gateway XX metric DD [passive]\n */
368 	for (;;) {
369 		junk[0] = 0;
370 		if (fgets(buf, sizeof(buf), lhf) == (char *)NULL)
371 			break;
372 		fputs(buf, gf);
373 		if (buf[0] == '#' ||
374 		    sscanf(buf, "%s %s gateway %s metric %d %s",
375 		    type, dname, gname, &metric, junk) < 5)
376 			continue;
377 		if (strcmp(type, "net"))
378 			continue;
379 		if (!getnetaddr(dname, &net))
380 			continue;
381 		if (!gethostaddr(gname, &addr.s_addr))
382 			continue;
383 		nl = newname(gname);
384 		(void) savegateway(nl, net, addr, metric);
385 	}
386 	fclose(lhf);
387 }
388 
389 getnetaddr(name, addr)
390 	char *name;
391 	int *addr;
392 {
393 	struct netent *np = getnetbyname(name);
394 
395 	if (np == 0) {
396 		*addr = inet_network(name);
397 		return (*addr != -1);
398 	} else {
399 		if (np->n_addrtype != AF_INET)
400 			return (0);
401 		*addr = np->n_net;
402 		return (1);
403 	}
404 }
405 
406 gethostaddr(name, addr)
407 	char *name;
408 	u_long *addr;
409 {
410 	struct hostent *hp;
411 
412 	hp = gethostbyname(name);
413 	if (hp) {
414 		*addr = *(u_long *)(hp->h_addr);
415 		return (1);
416 	}
417 	*addr = inet_addr(name);
418 	return (*addr != -1);
419 }
420 
421 copycomments(in, out, ccount)
422 	FILE *in, *out;
423 	int ccount;
424 {
425 	int count;
426 	char buf[BUFSIZ], *fgets();
427 
428 	for (count=0; count < ccount; count++) {
429 		if ((fgets(buf, sizeof(buf), in) == NULL) || (buf[0] != ';'))
430 			return;
431 		buf[0] = '#';
432 		fputs(buf, out);
433 	}
434 	return;
435 }
436 #define	UC(b)	(((int)(b))&0xff)
437 
438 /*
439  * Print network number in internet-standard dot notation;
440  * v is in host byte order.
441  */
442 putnet(f, v)
443 	FILE *f;
444 	register int v;
445 {
446 	if (v < 128)
447 		fprintf(f, "%d", v);
448 	else if (v < 65536)
449 		fprintf(f, "%d.%d", UC(v >> 8), UC(v));
450 	else
451 		fprintf(f, "%d.%d.%d", UC(v >> 16), UC(v >> 8), UC(v));
452 }
453 
454 putaddr(f, v)
455 	FILE *f;
456 	struct in_addr v;
457 {
458 	fprintf(f, "%-16.16s", inet_ntoa(v));
459 }
460 
461 freenames(list)
462 	struct name *list;
463 {
464 	register struct name *nl, *nl2;
465 
466 	nl2 = list;
467 	while (nl = nl2) {
468 		nl2 = nl->name_link;
469 		free(nl->name_val);
470 		free((char *)nl);
471 	}
472 }
473 
474 freeaddrs(list)
475 	struct addr *list;
476 {
477 	register struct addr *al, *al2;
478 
479 	al2 = list;
480 	while (al = al2)
481 		al2 = al->addr_link, free((char *)al);
482 }
483 
484 struct gateway *gateways = 0;
485 struct gateway *lastgateway = 0;
486 
487 struct gateway *
488 gatewayto(net)
489 	register int net;
490 {
491 	register struct gateway *gp;
492 
493 	for (gp = gateways; gp; gp = gp->g_link)
494 		if ((gp->g_net == net) && (gp->g_metric > 0))
495 			return (gp);
496 	return ((struct gateway *) NULL);
497 }
498 
499 struct gateway *
500 savegateway(namelist, net, addr, metric)
501 	struct name *namelist;
502 	struct in_addr addr;
503 	int net, metric;
504 {
505 	register struct gateway *gp;
506 
507 	gp = (struct gateway *)malloc(sizeof (struct gateway));
508 	if (gp == 0) {
509 		fprintf(stderr, "htable: out of memory\n");
510 		exit(1);
511 	}
512 	gp->g_link = (struct gateway *) NULL;
513 	if (lastgateway)
514 		lastgateway->g_link = gp;
515 	else
516 		gateways = gp;
517 	lastgateway = gp;
518 	gp->g_name = namelist;
519 	gp->g_net = net;
520 	gp->g_addr = addr;
521 	gp->g_metric = metric;
522 	if (metric == 1)
523 		gp->g_dst = gp;
524 	return (gp);
525 }
526 
527 connectedto(net)
528 	u_long net;
529 {
530 	register i;
531 
532 	for (i = 0; i < nconnected; i++)
533 		if (connected_nets[i] == net)
534 			return(1);
535 	return(0);
536 }
537 
538 local(net)
539 	u_long net;
540 {
541 	register i;
542 
543 	for (i = 0; i < nlocal; i++)
544 		if (local_nets[i] == net)
545 			return(1);
546 	return(0);
547 }
548 
549 #define	MAXHOPS	10
550 
551 /*
552  * Go through list of gateways, finding connections for gateways
553  * that are not yet connected.
554  */
555 dogateways()
556 {
557 	register struct gateway *gp, *gw, *ggp;
558 	register int hops, changed = 1;
559 	struct name *nl;
560 	char *cp;
561 
562 	for (hops = 0; hops < MAXHOPS && changed; hops++, changed = 0) {
563 	    for (gp = gateways; gp; gp = gp->g_link)
564 		if ((gp->g_metric == 0) && (gw = gatewayto(gp->g_net))) {
565 		    /*
566 		     * Found a new connection.
567 		     * For each other network that this gateway is on,
568 		     * add a new gateway to that network.
569 		     */
570 		    changed = 1;
571 		    gp->g_dst = gw->g_dst;
572 		    gp->g_metric = gw->g_metric + 1;
573 		    for (ggp = gp->g_firstent; ggp->g_name == gp->g_name;
574 			ggp = ggp->g_link) {
575 			    if (ggp == gp)
576 				continue;
577 			    if (gatewayto(ggp->g_net))
578 				continue;
579 			    ggp->g_dst = gp->g_dst;
580 			    ggp->g_metric = gp->g_metric;
581 			    printgateway(ggp->g_net,
582 				    gw->g_dst->g_name->name_val, gp->g_metric);
583 		    }
584 		    /*
585 		     * Put the gateway in the hosts file,
586 		     * using the address for the connected net.
587 		     */
588 		    putaddr(hf, gp->g_addr);
589 		    cp = "%s";
590 		    for (nl = gp->g_name; nl; nl = nl->name_link) {
591 			    fprintf(hf, cp, lower(nl->name_val));
592 			    cp = " %s";
593 		    }
594 		    fprintf(hf, "\t# gateway\n");
595 		}
596 	}
597 }
598