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