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
main(argc,argv)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
usage()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 */
addlocal(arg,nets)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 *
newname(str)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 *
lower(str)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
do_entry(keyword,addrlist,namelist,cputype,opsys,protos)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
printgateway(net,name,metric)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
copylocal(f,filename)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
copygateways(filename)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
getnetaddr(name,addr)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
gethostaddr(name,addr)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
copycomments(in,out,ccount)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 */
putnet(f,v)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
putaddr(f,v)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 *
gatewayto(net)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 *
savegateway(namelist,net,addr,metric)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
connectedto(net)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
local(net)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 */
dogateways()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