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