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