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