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