xref: /csrg-svn/old/htable/htable.c (revision 16024)
1 #ifndef lint
2 static char sccsid[] = "@(#)htable.c	4.10 (Berkeley) 02/09/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 		cp++;
164 	}
165 	return (str);
166 }
167 
168 do_entry(keyword, addrlist, namelist, cputype, opsys, protos)
169 	int keyword;
170 	struct addr *addrlist;
171 	struct name *namelist, *cputype, *opsys, *protos;
172 {
173 	register struct addr *al, *al2;
174 	register struct name *nl;
175 	struct addr *connect_addr;
176 	char *cp;
177 
178 	switch (keyword) {
179 
180 	case KW_NET:
181 		nl = namelist;
182 		if (nl == NONAME) {
183 			fprintf(stderr, "htable: net");
184 			putnet(stderr, inet_netof(addrlist->addr_val));
185 			fprintf(stderr, " missing names.\n");
186 			break;
187 		}
188 		fprintf(nf, "%-16.16s", lower(nl->name_val));
189 		al2 = addrlist;
190 		while (al = al2) {
191 			char *cp;
192 
193 			putnet(nf, inet_netof(al->addr_val));
194 			cp = "\t%s";
195 			while (nl = nl->name_link) {
196 				fprintf(nf, cp, lower(nl->name_val));
197 				cp = " %s";
198 			}
199 			putc('\n', nf);
200 			al2 = al->addr_link;
201 			free((char *)al);
202 		}
203 		break;
204 
205 	case KW_GATEWAY:
206 		/* locate locally connected address, if one */
207 		for (al = addrlist; al; al = al->addr_link)
208 			if (connectedto(inet_netof(al->addr_val)))
209 				break;
210 		if (al == NULL) {
211 			/*
212 			 * Not connected to known networks.  Save for later.
213 			 */
214 			struct gateway *gw, *firstgw = (struct gateway *) NULL;
215 
216 			for (al = addrlist; al; al = al->addr_link) {
217 				register int net;
218 
219 				net = inet_netof(al->addr_val);
220 				gw = savegateway(namelist, net,
221 				    al->addr_val, 0);
222 				if (firstgw == (struct gateway *) NULL)
223 					firstgw = gw;
224 				gw->g_firstent = firstgw;
225 			}
226 			freeaddrs(addrlist);
227 			goto dontfree;
228 		}
229 		/*
230 		 * Connected to a known network.
231 		 * Mark this as the gateway to all other networks
232 		 * that are on the addrlist (unless we already have
233 		 * gateways to them).
234 		 */
235 		connect_addr = al;
236 		for (al = addrlist; al; al = al->addr_link) {
237 			register int net;
238 
239 			/* suppress duplicates -- not optimal */
240 			net = inet_netof(al->addr_val);
241 			if (connectedto(net) || gatewayto(net))
242 				continue;
243 			printgateway(net, namelist->name_val, 1);
244 			(void) savegateway(namelist, net, al->addr_val, 1);
245 		}
246 		/*
247 		 * Put the gateway in the hosts file.
248 		 */
249 		putaddr(hf, connect_addr->addr_val);
250 		cp = "%s";
251 		for (nl = namelist; nl; nl = nl->name_link) {
252 			fprintf(hf, cp, lower(nl->name_val));
253 			cp = " %s";
254 		}
255 		fprintf(hf, "\t# gateway\n");
256 		freeaddrs(addrlist);
257 		goto dontfree;
258 
259 	case KW_HOST:
260 		al2 = addrlist;
261 		while (al = al2) {
262 			if (!local(inet_netof(al->addr_val))) {
263 				char *cp;
264 
265 				putaddr(hf, al->addr_val);
266 				cp = "%s";
267 				for (nl = namelist; nl; nl = nl->name_link) {
268 					fprintf(hf, cp, lower(nl->name_val));
269 					cp = " %s";
270 				}
271 				putc('\n', hf);
272 			}
273 			al2 = al->addr_link;
274 			free((char *)al);
275 		}
276 		break;
277 
278 	default:
279 		fprintf(stderr, "Unknown keyword: %d.\n", keyword);
280 	}
281 	freenames(namelist);
282 dontfree:
283 	freenames(protos);
284 }
285 
286 printgateway(net, name, metric)
287 	int net;
288 	char *name;
289 	int metric;
290 {
291 	struct netent *np;
292 
293 	fprintf(gf, "net ");
294 	np = getnetbyaddr(net, AF_INET);
295 	if (np)
296 		fprintf(gf, "%s", np->n_name);
297 	else
298 		putnet(gf, net);
299 	fprintf(gf, " gateway %s metric %d passive\n",
300 		lower(name), metric);
301 }
302 
303 copylocal(f, filename)
304 	FILE *f;
305 	char *filename;
306 {
307 	register FILE *lhf;
308 	register cc;
309 	char buf[BUFSIZ];
310 	extern int errno;
311 
312 	lhf = fopen(filename, "r");
313 	if (lhf == NULL) {
314 		if (errno != ENOENT) {
315 			perror(filename);
316 			exit(1);
317 		}
318 		fprintf(stderr, "Warning, no %s file.\n", filename);
319 		return;
320 	}
321 	while (cc = fread(buf, 1, sizeof(buf), lhf))
322 		fwrite(buf, 1, cc, f);
323 	fclose(lhf);
324 }
325 
326 copygateways(f, filename)
327 	FILE *f;
328 	char *filename;
329 {
330 	register FILE *lhf;
331 	struct name *nl;
332 	char type[80];
333 	char dname[80];
334 	char gname[80];
335 	char junk[80];
336 	u_long addr;
337 	int net, metric;
338 	extern int errno;
339 
340 	lhf = fopen(filename, "r");
341 	if (lhf == NULL) {
342 		if (errno != ENOENT) {
343 			perror(filename);
344 			exit(1);
345 		}
346 		fprintf(stderr, "Warning, no %s file.\n", filename);
347 		return;
348 	}
349 	/* format: {net | host} XX gateway XX metric DD [passive]\n */
350 #define	readentry(fp) \
351 	fscanf((fp), "%s %s gateway %s metric %d %s\n", \
352 		type, dname, gname, &metric, junk)
353 	for (;;) {
354 		junk[0] = 0;
355 		if (readentry(lhf) == EOF)
356 			break;
357 		if (strcmp(type, "net"))
358 			goto dumpit;
359 		if (!getnetaddr(dname, &net))
360 			goto dumpit;
361 		if (!gethostaddr(gname, &addr))
362 			goto dumpit;
363 		nl = newname(gname);
364 		(void) savegateway(nl, net, addr, metric);
365 dumpit:
366 		fprintf(gf, "%s %s gateway %s metric %d %s\n",
367 			type, dname, gname, metric, junk);
368 	}
369 	fclose(lhf);
370 }
371 
372 getnetaddr(name, addr)
373 	char *name;
374 	int *addr;
375 {
376 	struct netent *np = getnetbyname(name);
377 	int n;
378 
379 	if (np == 0) {
380 		*addr = inet_network(name);
381 		return (*addr != -1);
382 	} else {
383 		if (np->n_addrtype != AF_INET)
384 			return (0);
385 		*addr = np->n_net;
386 		return (1);
387 	}
388 }
389 
390 gethostaddr(name, addr)
391 	char *name;
392 	u_long *addr;
393 {
394 	struct hostent *hp;
395 
396 	hp = gethostbyname(name);
397 	if (hp) {
398 		*addr = *(u_long *)(hp->h_addr);
399 		return (1);
400 	}
401 	*addr = inet_addr(name);
402 	return (*addr != -1);
403 }
404 
405 copycomments(in, out, ccount)
406 	FILE *in, *out;
407 	int ccount;
408 {
409 	char buf[BUFSIZ];
410 	int length;
411 	int count;
412 	char *fgets();
413 
414 	for (count=0; count < ccount; count++) {
415 		if ((fgets(buf, sizeof(buf), in) == NULL) || (buf[0] != ';'))
416 			return;
417 		buf[0] = '#';
418 		fputs(buf, out);
419 	}
420 	return;
421 }
422 #define	UC(b)	(((int)(b))&0xff)
423 
424 /*
425  * Print network number in internet-standard dot notation;
426  * v is in host byte order.
427  */
428 putnet(f, v)
429 	FILE *f;
430 	register int v;
431 {
432 	if (v < 128)
433 		fprintf(f, "%d", v);
434 	else if (v < 65536)
435 		fprintf(f, "%d.%d", UC(v >> 8), UC(v));
436 	else
437 		fprintf(f, "%d.%d.%d", UC(v >> 16), UC(v >> 8), UC(v));
438 }
439 
440 putaddr(f, v)
441 	FILE *f;
442 	u_long v;
443 {
444 	register char *a = (char *)&v;
445 	char buf[32];
446 
447 	sprintf(buf,"%d.%d.%d.%d", UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]));
448 	fprintf(f, "%-16.16s", buf);
449 }
450 
451 freenames(list)
452 	struct name *list;
453 {
454 	register struct name *nl, *nl2;
455 
456 	nl2 = list;
457 	while (nl = nl2) {
458 		nl2 = nl->name_link;
459 		free(nl->name_val);
460 		free((char *)nl);
461 	}
462 }
463 
464 freeaddrs(list)
465 	struct addr *list;
466 {
467 	register struct addr *al, *al2;
468 
469 	al2 = list;
470 	while (al = al2)
471 		al2 = al->addr_link, free((char *)al);
472 }
473 
474 struct gateway *gateways = 0;
475 struct gateway *lastgateway = 0;
476 
477 struct gateway *
478 gatewayto(net)
479 	register int net;
480 {
481 	register struct gateway *gp;
482 
483 	for (gp = gateways; gp; gp = gp->g_link)
484 		if ((gp->g_net == net) && (gp->g_metric > 0))
485 			return (gp);
486 	return ((struct gateway *) NULL);
487 }
488 
489 struct gateway *
490 savegateway(namelist, net, addr, metric)
491 	struct name *namelist;
492 	u_long addr;
493 	int net, metric;
494 {
495 	register struct gateway *gp;
496 
497 	gp = (struct gateway *)malloc(sizeof (struct gateway));
498 	if (gp == 0) {
499 		fprintf(stderr, "htable: out of memory\n");
500 		exit(1);
501 	}
502 	gp->g_link = (struct gateway *) NULL;
503 	if (lastgateway)
504 		lastgateway->g_link = gp;
505 	else
506 		gateways = gp;
507 	lastgateway = gp;
508 	gp->g_name = namelist;
509 	gp->g_net = net;
510 	gp->g_addr = addr;
511 	gp->g_metric = metric;
512 	if (metric == 1)
513 		gp->g_dst = gp;
514 }
515 
516 connectedto(net)
517 	u_long net;
518 {
519 	register i;
520 
521 	for (i = 0; i < nconnected; i++)
522 		if (connected_nets[i] == net)
523 			return(1);
524 	return(0);
525 }
526 
527 local(net)
528 	u_long net;
529 {
530 	register i;
531 
532 	for (i = 0; i < nlocal; i++)
533 		if (local_nets[i] == net)
534 			return(1);
535 	return(0);
536 }
537 
538 #define	MAXHOPS	10
539 
540 /*
541  * Go through list of gateways, finding connections for gateways
542  * that are not yet connected.
543  */
544 dogateways()
545 {
546 	register struct gateway *gp, *gw, *ggp;
547 	register int hops, changed = 1;
548 	struct name *nl;
549 	char *cp;
550 
551 	for (hops = 0; hops < MAXHOPS && changed; hops++, changed = 0) {
552 	    for (gp = gateways; gp; gp = gp->g_link)
553 		if ((gp->g_metric == 0) && (gw = gatewayto(gp->g_net))) {
554 		    /*
555 		     * Found a new connection.
556 		     * For each other network that this gateway is on,
557 		     * add a new gateway to that network.
558 		     */
559 		    changed = 1;
560 		    gp->g_dst = gw->g_dst;
561 		    gp->g_metric = gw->g_metric + 1;
562 		    for (ggp = gp->g_firstent; ggp->g_name == gp->g_name;
563 			ggp = ggp->g_link) {
564 			    if (ggp == gp)
565 				continue;
566 			    if (gatewayto(ggp->g_net))
567 				continue;
568 			    ggp->g_dst = gp->g_dst;
569 			    ggp->g_metric = gp->g_metric;
570 			    printgateway(ggp->g_net,
571 				    gw->g_dst->g_name->name_val, gp->g_metric);
572 		    }
573 		    /*
574 		     * Put the gateway in the hosts file,
575 		     * using the address for the connected net.
576 		     */
577 		    putaddr(hf, gp->g_addr);
578 		    cp = "%s";
579 		    for (nl = gp->g_name; nl; nl = nl->name_link) {
580 			    fprintf(hf, cp, lower(nl->name_val));
581 			    cp = " %s";
582 		    }
583 		    fprintf(hf, "\t# gateway\n");
584 		}
585 	}
586 }
587