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