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