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