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