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