xref: /csrg-svn/old/htable/htable.c (revision 15785)
1 #ifndef lint
2 static char sccsid[] = "@(#)htable.c	4.8 (Berkeley) 12/30/83";
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, 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, 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 			if (al == connect_addr)
240 				continue;
241 			/* suppress duplicates -- not optimal */
242 			net = inet_netof(al->addr_val);
243 			if (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 	register cc;
334 	struct name *nl;
335 	char type[80];
336 	char dname[80];
337 	char gname[80];
338 	char junk[80];
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 #define	readentry(fp) \
354 	fscanf((fp), "%s %s gateway %s metric %d %s\n", \
355 		type, dname, gname, &metric, junk)
356 	while (readentry(lhf) != EOF) {
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 	u_long v;
431 {
432 	if (v < 128)
433 		fprintf(f, "%d", v);
434 	else if (v < 65536)
435 		fprintf(f, "%d.%d", (v >> 8) & 0xff, v & 0xff);
436 	else
437 		fprintf(f, "%d.%d.%d", (v >> 16) & 0xff,
438 			(v >> 8) & 0xff, v & 0xff);
439 }
440 
441 putaddr(f, v)
442 	FILE *f;
443 	u_long v;
444 {
445 	register char *a = (char *)&v;
446 	char buf[32];
447 
448 	sprintf(buf,"%d.%d.%d.%d", UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]));
449 	fprintf(f, "%-16.16s", buf);
450 }
451 
452 freenames(list)
453 	struct name *list;
454 {
455 	register struct name *nl, *nl2;
456 
457 	nl2 = list;
458 	while (nl = nl2) {
459 		nl2 = nl->name_link;
460 		free(nl->name_val);
461 		free((char *)nl);
462 	}
463 }
464 
465 freeaddrs(list)
466 	struct addr *list;
467 {
468 	register struct addr *al, *al2;
469 
470 	al2 = list;
471 	while (al = al2)
472 		al2 = al->addr_link, free((char *)al);
473 }
474 
475 struct gateway *gateways = 0;
476 struct gateway *lastgateway = 0;
477 
478 struct gateway *
479 gatewayto(net)
480 	register int net;
481 {
482 	register struct gateway *gp;
483 
484 	for (gp = gateways; gp; gp = gp->g_link)
485 		if ((gp->g_net == net) && (gp->g_metric > 0))
486 			return (gp);
487 	return ((struct gateway *) NULL);
488 }
489 
490 struct gateway *
491 savegateway(namelist, net, addr, metric)
492 	struct name *namelist;
493 	u_long addr;
494 	int net, metric;
495 {
496 	register struct gateway *gp;
497 
498 	gp = (struct gateway *)malloc(sizeof (struct gateway));
499 	if (gp == 0) {
500 		fprintf(stderr, "htable: out of memory\n");
501 		exit(1);
502 	}
503 	gp->g_link = (struct gateway *) NULL;
504 	if (lastgateway)
505 		lastgateway->g_link = gp;
506 	else
507 		gateways = gp;
508 	lastgateway = gp;
509 	gp->g_name = namelist;
510 	gp->g_net = net;
511 	gp->g_addr = addr;
512 	gp->g_metric = metric;
513 	if (metric == 1)
514 		gp->g_dst = gp;
515 }
516 
517 connectedto(net)
518 	u_long net;
519 {
520 	register i;
521 
522 	for (i = 0; i < nconnected; i++)
523 		if (connected_nets[i] == net)
524 			return(1);
525 	return(0);
526 }
527 
528 local(net)
529 	u_long net;
530 {
531 	register i;
532 
533 	for (i = 0; i < nlocal; i++)
534 		if (local_nets[i] == net)
535 			return(1);
536 	return(0);
537 }
538 
539 #define	MAXHOPS	10
540 
541 /*
542  * Go through list of gateways, finding connections for gateways
543  * that are not yet connected.
544  */
545 dogateways()
546 {
547 	register struct gateway *gp, *gw, *ggp;
548 	register int hops, changed = 1;
549 	struct name *nl;
550 	char *cp;
551 
552 	for (hops = 0; hops < MAXHOPS && changed; hops++, changed = 0) {
553 	    for (gp = gateways; gp; gp = gp->g_link)
554 		if ((gp->g_metric == 0) && (gw = gatewayto(gp->g_net))) {
555 		    /*
556 		     * Found a new connection.
557 		     * For each other network that this gateway is on,
558 		     * add a new gateway to that network.
559 		     */
560 		    changed = 1;
561 		    gp->g_dst = gw->g_dst;
562 		    gp->g_metric = gw->g_metric + 1;
563 		    for (ggp = gp->g_firstent; ggp->g_name == gp->g_name;
564 			ggp = ggp->g_link) {
565 			    if (ggp == gp)
566 				continue;
567 			    if (gatewayto(ggp->g_net))
568 				continue;
569 			    ggp->g_dst = gp->g_dst;
570 			    ggp->g_metric = gp->g_metric;
571 			    printgateway(ggp->g_net,
572 				    gw->g_dst->g_name->name_val, gp->g_metric);
573 		    }
574 		    /*
575 		     * Put the gateway in the hosts file,
576 		     * using the address for the connected net.
577 		     */
578 		    putaddr(hf, gp->g_addr);
579 		    cp = "%s";
580 		    for (nl = gp->g_name; nl; nl = nl->name_link) {
581 			    fprintf(hf, cp, lower(nl->name_val));
582 			    cp = " %s";
583 		    }
584 		    fprintf(hf, "\t# gateway\n");
585 		}
586 	}
587 }
588