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