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