1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 #include <ndb.h> 5 #include <ip.h> 6 #include "dns.h" 7 8 enum { 9 Nibwidth = 4, 10 Nibmask = (1<<Nibwidth) - 1, 11 V6maxrevdomdepth = 128 / Nibwidth, /* bits / bits-per-nibble */ 12 13 /* 14 * ttl for generated ptr records. it was zero, which might seem 15 * like a good idea, but some dns implementations seem to be 16 * confused by a zero ttl, and instead of using the data and then 17 * discarding the RR, they conclude that they don't have valid data. 18 */ 19 Ptrttl = 300, 20 }; 21 22 static Ndb *db; 23 static Lock dblock; 24 25 static RR* addrrr(Ndbtuple*, Ndbtuple*); 26 static RR* cnamerr(Ndbtuple*, Ndbtuple*); 27 static void createptrs(void); 28 static RR* dblookup1(char*, int, int, int); 29 static RR* doaxfr(Ndb*, char*); 30 static Ndbtuple*look(Ndbtuple*, Ndbtuple*, char*); 31 static RR* mxrr(Ndbtuple*, Ndbtuple*); 32 static RR* nsrr(Ndbtuple*, Ndbtuple*); 33 static RR* nullrr(Ndbtuple*, Ndbtuple*); 34 static RR* ptrrr(Ndbtuple*, Ndbtuple*); 35 static RR* soarr(Ndbtuple*, Ndbtuple*); 36 static RR* srvrr(Ndbtuple*, Ndbtuple*); 37 static RR* txtrr(Ndbtuple*, Ndbtuple*); 38 39 static int implemented[Tall] = 40 { 41 [Ta] 1, 42 [Taaaa] 1, 43 [Tcname] 1, 44 [Tmx] 1, 45 [Tns] 1, 46 [Tnull] 1, 47 [Tptr] 1, 48 [Tsoa] 1, 49 [Tsrv] 1, 50 [Ttxt] 1, 51 }; 52 53 /* straddle server configuration */ 54 static Ndbtuple *indoms, *innmsrvs, *outnmsrvs; 55 56 static void 57 nstrcpy(char *to, char *from, int len) 58 { 59 strncpy(to, from, len); 60 to[len-1] = 0; 61 } 62 63 int 64 opendatabase(void) 65 { 66 char netdbnm[256]; 67 Ndb *xdb, *netdb; 68 69 if (db) 70 return 0; 71 72 xdb = ndbopen(dbfile); /* /lib/ndb */ 73 if(xdb) 74 xdb->nohash = 1; /* seems odd */ 75 76 snprint(netdbnm, sizeof netdbnm, "%s/ndb", mntpt); 77 netdb = ndbopen(netdbnm); /* /net/ndb */ 78 // if(netdb) 79 // netdb->nohash = 1; /* cs does this; seems right */ 80 81 db = ndbcat(netdb, xdb); /* both */ 82 return db? 0: -1; 83 } 84 85 /* 86 * lookup an RR in the network database, look for matches 87 * against both the domain name and the wildcarded domain name. 88 * 89 * the lock makes sure only one process can be accessing the data 90 * base at a time. This is important since there's a lot of 91 * shared state there. 92 * 93 * e.g. for x.research.bell-labs.com, first look for a match against 94 * the x.research.bell-labs.com. If nothing matches, 95 * try *.research.bell-labs.com. 96 */ 97 RR* 98 dblookup(char *name, int class, int type, int auth, int ttl) 99 { 100 int err; 101 char *wild, *cp; 102 char buf[256]; 103 RR *rp, *tp; 104 DN *dp, *ndp; 105 static int parallel; 106 static int parfd[2]; 107 static char token[1]; 108 109 /* so far only internet lookups are implemented */ 110 if(class != Cin) 111 return 0; 112 113 err = Rname; 114 115 if(type == Tall){ 116 rp = nil; 117 for (type = Ta; type < Tall; type++) 118 /* HACK: exclude Taaaa (ipv6) for speed for now */ 119 if(implemented[type] && (1 || type != Taaaa)) 120 rrcat(&rp, dblookup(name, class, type, auth, ttl)); 121 return rp; 122 } 123 124 rp = nil; 125 126 lock(&dblock); 127 dp = dnlookup(name, class, 1); 128 129 if(opendatabase() < 0) 130 goto out; 131 if(dp->rr) 132 err = 0; 133 134 /* first try the given name */ 135 if(cfg.cachedb) 136 rp = rrlookup(dp, type, NOneg); 137 else 138 rp = dblookup1(name, type, auth, ttl); 139 if(rp) 140 goto out; 141 142 /* try lower case version */ 143 for(cp = name; *cp; cp++) 144 *cp = tolower(*cp); 145 if(cfg.cachedb) 146 rp = rrlookup(dp, type, NOneg); 147 else 148 rp = dblookup1(name, type, auth, ttl); 149 if(rp) 150 goto out; 151 152 /* walk the domain name trying the wildcard '*' at each position */ 153 for(wild = strchr(name, '.'); wild; wild = strchr(wild+1, '.')){ 154 snprint(buf, sizeof buf, "*%s", wild); 155 ndp = dnlookup(buf, class, 1); 156 if(ndp->rr) 157 err = 0; 158 if(cfg.cachedb) 159 rp = rrlookup(ndp, type, NOneg); 160 else 161 rp = dblookup1(buf, type, auth, ttl); 162 if(rp) 163 break; 164 } 165 out: 166 /* add owner to uncached records */ 167 if(rp) 168 for(tp = rp; tp; tp = tp->next) 169 tp->owner = dp; 170 else { 171 /* 172 * don't call it non-existent if it's not ours 173 * (unless we're a resolver). 174 */ 175 if(err == Rname && (!inmyarea(name) || cfg.resolver)) 176 err = Rserver; 177 dp->respcode = err; 178 } 179 180 unlock(&dblock); 181 return rp; 182 } 183 184 static ulong 185 intval(Ndbtuple *entry, Ndbtuple *pair, char *attr, ulong def) 186 { 187 Ndbtuple *t = look(entry, pair, attr); 188 189 return (t? strtoul(t->val, 0, 10): def); 190 } 191 192 /* 193 * lookup an RR in the network database 194 */ 195 static RR* 196 dblookup1(char *name, int type, int auth, int ttl) 197 { 198 Ndbtuple *t, *nt; 199 RR *rp, *list, **l; 200 Ndbs s; 201 char dname[Domlen]; 202 char *attr; 203 DN *dp; 204 RR *(*f)(Ndbtuple*, Ndbtuple*); 205 int found, x; 206 207 dp = nil; 208 switch(type){ 209 case Tptr: 210 attr = "ptr"; 211 f = ptrrr; 212 break; 213 case Ta: 214 attr = "ip"; 215 f = addrrr; 216 break; 217 case Tnull: 218 attr = "nullrr"; 219 f = nullrr; 220 break; 221 case Tns: 222 attr = "ns"; 223 f = nsrr; 224 break; 225 case Tsoa: 226 attr = "soa"; 227 f = soarr; 228 break; 229 case Tsrv: 230 attr = "srv"; 231 f = srvrr; 232 break; 233 case Tmx: 234 attr = "mx"; 235 f = mxrr; 236 break; 237 case Tcname: 238 attr = "cname"; 239 f = cnamerr; 240 break; 241 case Taxfr: 242 case Tixfr: 243 return doaxfr(db, name); 244 default: 245 // dnslog("dnlookup1(%s) bad type", name); 246 return nil; 247 } 248 249 /* 250 * find a matching entry in the database 251 */ 252 t = nil; 253 free(ndbgetvalue(db, &s, "dom", name, attr, &t)); 254 255 /* 256 * hack for local names 257 */ 258 if(t == nil && strchr(name, '.') == nil) 259 free(ndbgetvalue(db, &s, "sys", name, attr, &t)); 260 if(t == nil) { 261 // dnslog("dnlookup1(%s) name not found", name); 262 return nil; 263 } 264 265 /* search whole entry for default domain name */ 266 strncpy(dname, name, sizeof dname); 267 for(nt = t; nt; nt = nt->entry) 268 if(strcmp(nt->attr, "dom") == 0){ 269 nstrcpy(dname, nt->val, sizeof dname); 270 break; 271 } 272 273 /* ttl is maximum of soa minttl and entry's ttl ala rfc883 */ 274 x = intval(t, s.t, "ttl", 0); 275 if(x > ttl) 276 ttl = x; 277 278 /* default ttl is one day */ 279 if(ttl < 0) 280 ttl = DEFTTL; 281 282 /* 283 * The database has 2 levels of precedence; line and entry. 284 * Pairs on the same line bind tighter than pairs in the 285 * same entry, so we search the line first. 286 */ 287 found = 0; 288 list = 0; 289 l = &list; 290 for(nt = s.t;; ){ 291 if(found == 0 && strcmp(nt->attr, "dom") == 0){ 292 nstrcpy(dname, nt->val, sizeof dname); 293 found = 1; 294 } 295 if(cistrcmp(attr, nt->attr) == 0){ 296 rp = (*f)(t, nt); 297 rp->auth = auth; 298 rp->db = 1; 299 if(ttl) 300 rp->ttl = ttl; 301 if(dp == nil) 302 dp = dnlookup(dname, Cin, 1); 303 rp->owner = dp; 304 *l = rp; 305 l = &rp->next; 306 nt->ptr = 1; 307 } 308 nt = nt->line; 309 if(nt == s.t) 310 break; 311 } 312 313 /* search whole entry */ 314 for(nt = t; nt; nt = nt->entry) 315 if(nt->ptr == 0 && cistrcmp(attr, nt->attr) == 0){ 316 rp = (*f)(t, nt); 317 rp->db = 1; 318 if(ttl) 319 rp->ttl = ttl; 320 rp->auth = auth; 321 if(dp == nil) 322 dp = dnlookup(dname, Cin, 1); 323 rp->owner = dp; 324 *l = rp; 325 l = &rp->next; 326 } 327 ndbfree(t); 328 329 // dnslog("dnlookup1(%s) -> %#p", name, list); 330 return list; 331 } 332 333 /* 334 * make various types of resource records from a database entry 335 */ 336 static RR* 337 addrrr(Ndbtuple *entry, Ndbtuple *pair) 338 { 339 RR *rp; 340 uchar addr[IPaddrlen]; 341 342 USED(entry); 343 parseip(addr, pair->val); 344 if(isv4(addr)) 345 rp = rralloc(Ta); 346 else 347 rp = rralloc(Taaaa); 348 rp->ip = dnlookup(pair->val, Cin, 1); 349 return rp; 350 } 351 static RR* 352 nullrr(Ndbtuple *entry, Ndbtuple *pair) 353 { 354 RR *rp; 355 356 USED(entry); 357 rp = rralloc(Tnull); 358 rp->null->data = (uchar*)estrdup(pair->val); 359 rp->null->dlen = strlen((char*)rp->null->data); 360 return rp; 361 } 362 /* 363 * txt rr strings are at most 255 bytes long. one 364 * can represent longer strings by multiple concatenated 365 * <= 255 byte ones. 366 */ 367 static RR* 368 txtrr(Ndbtuple *entry, Ndbtuple *pair) 369 { 370 RR *rp; 371 Txt *t, **l; 372 int i, len, sofar; 373 374 USED(entry); 375 rp = rralloc(Ttxt); 376 l = &rp->txt; 377 rp->txt = nil; 378 len = strlen(pair->val); 379 sofar = 0; 380 while(len > sofar){ 381 t = emalloc(sizeof(*t)); 382 t->next = nil; 383 384 i = len-sofar; 385 if(i > 255) 386 i = 255; 387 388 t->p = emalloc(i+1); 389 memmove(t->p, pair->val+sofar, i); 390 t->p[i] = 0; 391 sofar += i; 392 393 *l = t; 394 l = &t->next; 395 } 396 return rp; 397 } 398 static RR* 399 cnamerr(Ndbtuple *entry, Ndbtuple *pair) 400 { 401 RR *rp; 402 403 USED(entry); 404 rp = rralloc(Tcname); 405 rp->host = dnlookup(pair->val, Cin, 1); 406 return rp; 407 } 408 static RR* 409 mxrr(Ndbtuple *entry, Ndbtuple *pair) 410 { 411 RR *rp; 412 413 rp = rralloc(Tmx); 414 rp->host = dnlookup(pair->val, Cin, 1); 415 rp->pref = intval(entry, pair, "pref", 1); 416 return rp; 417 } 418 static RR* 419 nsrr(Ndbtuple *entry, Ndbtuple *pair) 420 { 421 RR *rp; 422 Ndbtuple *t; 423 424 rp = rralloc(Tns); 425 rp->host = dnlookup(pair->val, Cin, 1); 426 t = look(entry, pair, "soa"); 427 if(t && t->val[0] == 0) 428 rp->local = 1; 429 return rp; 430 } 431 static RR* 432 ptrrr(Ndbtuple *entry, Ndbtuple *pair) 433 { 434 RR *rp; 435 436 USED(entry); 437 rp = rralloc(Tns); 438 rp->ptr = dnlookup(pair->val, Cin, 1); 439 return rp; 440 } 441 static RR* 442 soarr(Ndbtuple *entry, Ndbtuple *pair) 443 { 444 RR *rp; 445 Ndbtuple *ns, *mb, *t; 446 char mailbox[Domlen]; 447 Ndb *ndb; 448 char *p; 449 450 rp = rralloc(Tsoa); 451 rp->soa->serial = 1; 452 for(ndb = db; ndb; ndb = ndb->next) 453 if(ndb->mtime > rp->soa->serial) 454 rp->soa->serial = ndb->mtime; 455 456 rp->soa->retry = intval(entry, pair, "retry", Hour); 457 rp->soa->expire = intval(entry, pair, "expire", Day); 458 rp->soa->minttl = intval(entry, pair, "ttl", Day); 459 rp->soa->refresh = intval(entry, pair, "refresh", Day); 460 rp->soa->serial = intval(entry, pair, "serial", rp->soa->serial); 461 462 ns = look(entry, pair, "ns"); 463 if(ns == nil) 464 ns = look(entry, pair, "dom"); 465 rp->host = dnlookup(ns->val, Cin, 1); 466 467 /* accept all of: 468 * mbox=person 469 * mbox=person@machine.dom 470 * mbox=person.machine.dom 471 */ 472 mb = look(entry, pair, "mbox"); 473 if(mb == nil) 474 mb = look(entry, pair, "mb"); 475 if(mb) 476 if(strchr(mb->val, '.')) { 477 p = strchr(mb->val, '@'); 478 if(p != nil) 479 *p = '.'; 480 rp->rmb = dnlookup(mb->val, Cin, 1); 481 } else { 482 snprint(mailbox, sizeof mailbox, "%s.%s", 483 mb->val, ns->val); 484 rp->rmb = dnlookup(mailbox, Cin, 1); 485 } 486 else { 487 snprint(mailbox, sizeof mailbox, "postmaster.%s", ns->val); 488 rp->rmb = dnlookup(mailbox, Cin, 1); 489 } 490 491 /* 492 * hang dns slaves off of the soa. this is 493 * for managing the area. 494 */ 495 for(t = entry; t != nil; t = t->entry) 496 if(strcmp(t->attr, "dnsslave") == 0) 497 addserver(&rp->soa->slaves, t->val); 498 499 return rp; 500 } 501 502 static RR* 503 srvrr(Ndbtuple *entry, Ndbtuple *pair) 504 { 505 RR *rp; 506 507 rp = rralloc(Tsrv); 508 rp->srv->target = dnlookup(pair->val, Cin, 1); 509 rp->srv->pri = intval(entry, pair, "pri", 0); 510 rp->srv->weight = intval(entry, pair, "weight", 0); 511 /* TODO: translate service name to port # */ 512 rp->srv->port = intval(entry, pair, "port", 0); 513 return rp; 514 } 515 516 /* 517 * Look for a pair with the given attribute. look first on the same line, 518 * then in the whole entry. 519 */ 520 static Ndbtuple* 521 look(Ndbtuple *entry, Ndbtuple *line, char *attr) 522 { 523 Ndbtuple *nt; 524 525 /* first look on same line (closer binding) */ 526 for(nt = line;;){ 527 if(cistrcmp(attr, nt->attr) == 0) 528 return nt; 529 nt = nt->line; 530 if(nt == line) 531 break; 532 } 533 /* search whole tuple */ 534 for(nt = entry; nt; nt = nt->entry) 535 if(cistrcmp(attr, nt->attr) == 0) 536 return nt; 537 return 0; 538 } 539 540 static RR** 541 linkrr(RR *rp, DN *dp, RR **l) 542 { 543 rp->owner = dp; 544 rp->auth = 1; 545 rp->db = 1; 546 *l = rp; 547 return &rp->next; 548 } 549 550 /* these are answered specially by the tcp version */ 551 static RR* 552 doaxfr(Ndb *db, char *name) 553 { 554 USED(db, name); 555 return 0; 556 } 557 558 559 /* 560 * read the all the soa's from the database to determine area's. 561 * this is only used when we're not caching the database. 562 */ 563 static void 564 dbfile2area(Ndb *db) 565 { 566 Ndbtuple *t; 567 568 if(debug) 569 dnslog("rereading %s", db->file); 570 Bseek(&db->b, 0, 0); 571 while(t = ndbparse(db)) 572 ndbfree(t); 573 } 574 575 /* 576 * read the database into the cache 577 */ 578 static void 579 dbpair2cache(DN *dp, Ndbtuple *entry, Ndbtuple *pair) 580 { 581 RR *rp; 582 static ulong ord; 583 584 rp = 0; 585 if(cistrcmp(pair->attr, "ip") == 0){ 586 dp->ordinal = ord++; 587 rp = addrrr(entry, pair); 588 } else if(cistrcmp(pair->attr, "ns") == 0) 589 rp = nsrr(entry, pair); 590 else if(cistrcmp(pair->attr, "soa") == 0) { 591 rp = soarr(entry, pair); 592 addarea(dp, rp, pair); 593 } else if(cistrcmp(pair->attr, "mx") == 0) 594 rp = mxrr(entry, pair); 595 else if(cistrcmp(pair->attr, "srv") == 0) 596 rp = srvrr(entry, pair); 597 else if(cistrcmp(pair->attr, "cname") == 0) 598 rp = cnamerr(entry, pair); 599 else if(cistrcmp(pair->attr, "nullrr") == 0) 600 rp = nullrr(entry, pair); 601 else if(cistrcmp(pair->attr, "txtrr") == 0) 602 rp = txtrr(entry, pair); 603 if(rp == nil) 604 return; 605 606 rp->owner = dp; 607 rp->db = 1; 608 rp->ttl = intval(entry, pair, "ttl", rp->ttl); 609 rrattach(rp, Notauthoritative); 610 } 611 static void 612 dbtuple2cache(Ndbtuple *t) 613 { 614 Ndbtuple *et, *nt; 615 DN *dp; 616 617 for(et = t; et; et = et->entry) 618 if(strcmp(et->attr, "dom") == 0){ 619 dp = dnlookup(et->val, Cin, 1); 620 621 /* first same line */ 622 for(nt = et->line; nt != et; nt = nt->line){ 623 dbpair2cache(dp, t, nt); 624 nt->ptr = 1; 625 } 626 627 /* then rest of entry */ 628 for(nt = t; nt; nt = nt->entry){ 629 if(nt->ptr == 0) 630 dbpair2cache(dp, t, nt); 631 nt->ptr = 0; 632 } 633 } 634 } 635 static void 636 dbfile2cache(Ndb *db) 637 { 638 Ndbtuple *t; 639 640 if(debug) 641 dnslog("rereading %s", db->file); 642 Bseek(&db->b, 0, 0); 643 while(t = ndbparse(db)){ 644 dbtuple2cache(t); 645 ndbfree(t); 646 } 647 } 648 649 /* called with dblock held */ 650 static void 651 loaddomsrvs(void) 652 { 653 Ndbs s; 654 655 if (!cfg.inside || !cfg.straddle || !cfg.serve) 656 return; 657 if (indoms) { 658 ndbfree(indoms); 659 ndbfree(innmsrvs); 660 ndbfree(outnmsrvs); 661 indoms = innmsrvs = outnmsrvs = nil; 662 } 663 if (db == nil) 664 opendatabase(); 665 free(ndbgetvalue(db, &s, "sys", "inside-dom", "dom", &indoms)); 666 free(ndbgetvalue(db, &s, "sys", "inside-ns", "ip", &innmsrvs)); 667 free(ndbgetvalue(db, &s, "sys", "outside-ns", "ip", &outnmsrvs)); 668 dnslog("[%d] ndb changed: reloaded inside-dom, inside-ns, outside-ns", 669 getpid()); 670 } 671 672 void 673 db2cache(int doit) 674 { 675 ulong youngest, temp; 676 Ndb *ndb; 677 Dir *d; 678 static ulong lastcheck, lastyoungest; 679 680 /* no faster than once every 2 minutes */ 681 if(now < lastcheck + 2*Min && !doit) 682 return; 683 684 refresh_areas(owned); 685 686 lock(&dblock); 687 688 if(opendatabase() < 0){ 689 unlock(&dblock); 690 return; 691 } 692 693 /* 694 * file may be changing as we are reading it, so loop till 695 * mod times are consistent. 696 * 697 * we don't use the times in the ndb records because they may 698 * change outside of refreshing our cached knowledge. 699 */ 700 for(;;){ 701 lastcheck = now; 702 youngest = 0; 703 for(ndb = db; ndb; ndb = ndb->next) 704 /* dirfstat avoids walking the mount table each time */ 705 if((d = dirfstat(Bfildes(&ndb->b))) != nil || 706 (d = dirstat(ndb->file)) != nil){ 707 temp = d->mtime; /* ulong vs int crap */ 708 if(temp > youngest) 709 youngest = temp; 710 free(d); 711 } 712 if(!doit && youngest == lastyoungest) 713 break; 714 715 /* forget our area definition */ 716 freearea(&owned); 717 freearea(&delegated); 718 719 /* reopen all the files (to get oldest for time stamp) */ 720 for(ndb = db; ndb; ndb = ndb->next) 721 ndbreopen(ndb); 722 723 /* reload straddle-server configuration */ 724 loaddomsrvs(); 725 726 if(cfg.cachedb){ 727 /* mark all db records as timed out */ 728 dnagedb(); 729 730 /* read in new entries */ 731 for(ndb = db; ndb; ndb = ndb->next) 732 dbfile2cache(ndb); 733 734 /* mark as authoritative anything in our domain */ 735 dnauthdb(); 736 737 /* remove old entries */ 738 dnageall(1); 739 } else 740 /* read all the soa's to get database defaults */ 741 for(ndb = db; ndb; ndb = ndb->next) 742 dbfile2area(ndb); 743 744 doit = 0; 745 lastyoungest = youngest; 746 createptrs(); 747 } 748 749 unlock(&dblock); 750 } 751 752 void 753 dnforceage(void) 754 { 755 lock(&dblock); 756 dnageall(1); 757 unlock(&dblock); 758 } 759 760 extern uchar ipaddr[IPaddrlen]; /* my ip address */ 761 762 /* 763 * get all my xxx 764 * caller ndbfrees the result 765 */ 766 Ndbtuple* 767 lookupinfo(char *attr) 768 { 769 char buf[64]; 770 char *a[2]; 771 Ndbtuple *t; 772 773 snprint(buf, sizeof buf, "%I", ipaddr); 774 a[0] = attr; 775 776 lock(&dblock); 777 if(opendatabase() < 0){ 778 unlock(&dblock); 779 return nil; 780 } 781 t = ndbipinfo(db, "ip", buf, a, 1); 782 unlock(&dblock); 783 return t; 784 } 785 786 char *localservers = "local#dns#servers"; 787 char *localserverprefix = "local#dns#server"; 788 789 /* 790 * return non-zero is this is a bad delegation 791 */ 792 int 793 baddelegation(RR *rp, RR *nsrp, uchar *addr) 794 { 795 Ndbtuple *nt; 796 static Ndbtuple *t; 797 798 if(t == nil) 799 t = lookupinfo("dom"); 800 if(t == nil) 801 return 0; 802 803 for(; rp; rp = rp->next){ 804 if(rp->type != Tns) 805 continue; 806 807 /* see if delegation is looping */ 808 if(nsrp) 809 if(rp->owner != nsrp->owner) 810 if(subsume(rp->owner->name, nsrp->owner->name) && 811 strcmp(nsrp->owner->name, localservers) != 0){ 812 dnslog("delegation loop %R -> %R from %I", 813 nsrp, rp, addr); 814 return 1; 815 } 816 817 /* see if delegating to us what we don't own */ 818 for(nt = t; nt != nil; nt = nt->entry) 819 if(rp->host && cistrcmp(rp->host->name, nt->val) == 0) 820 break; 821 if(nt != nil && !inmyarea(rp->owner->name)){ 822 dnslog("bad delegation %R from %I", rp, addr); 823 return 1; 824 } 825 } 826 827 return 0; 828 } 829 830 int 831 myaddr(char *addr) 832 { 833 char *name, *line, *sp; 834 char buf[64]; 835 Biobuf *bp; 836 837 snprint(buf, sizeof buf, "%I", ipaddr); 838 if (strcmp(addr, buf) == 0) { 839 dnslog("rejecting my ip %s as local dns server", addr); 840 return 1; 841 } 842 843 name = smprint("%s/ipselftab", mntpt); 844 bp = Bopen(name, OREAD); 845 free(name); 846 if (bp != nil) { 847 while ((line = Brdline(bp, '\n')) != nil) { 848 line[Blinelen(bp) - 1] = '\0'; 849 sp = strchr(line, ' '); 850 if (sp) { 851 *sp = '\0'; 852 if (strcmp(addr, line) == 0) { 853 dnslog("rejecting my ip %s as local dns server", 854 addr); 855 return 1; 856 } 857 } 858 } 859 Bterm(bp); 860 } 861 return 0; 862 } 863 864 static char *locdns[20]; 865 866 static void 867 addlocaldnsserver(DN *dp, int class, char *ipaddr, int i) 868 { 869 int n; 870 DN *nsdp; 871 RR *rp; 872 char buf[32]; 873 static QLock locdnslck; 874 875 /* reject our own ip addresses so we don't query ourselves via udp */ 876 if (myaddr(ipaddr)) 877 return; 878 879 qlock(&locdnslck); 880 for (n = 0; n < i && n < nelem(locdns) && locdns[n]; n++) 881 if (strcmp(locdns[n], ipaddr) == 0) { 882 dnslog("rejecting duplicate local dns server ip %s", 883 ipaddr); 884 qunlock(&locdnslck); 885 return; 886 } 887 if (n < nelem(locdns)) 888 if (locdns[n] == nil || ++n < nelem(locdns)) 889 locdns[n] = strdup(ipaddr); /* remember first few local ns */ 890 qunlock(&locdnslck); 891 892 /* ns record for name server, make up an impossible name */ 893 rp = rralloc(Tns); 894 snprint(buf, sizeof buf, "%s%d", localserverprefix, i); 895 nsdp = dnlookup(buf, class, 1); 896 rp->host = nsdp; 897 rp->owner = dp; /* e.g., local#dns#servers */ 898 rp->local = 1; 899 rp->db = 1; 900 // rp->ttl = 10*Min; /* seems too short */ 901 rp->ttl = (1UL<<31)-1; 902 rrattach(rp, Authoritative); /* will not attach rrs in my area */ 903 904 /* A record */ 905 rp = rralloc(Ta); 906 rp->ip = dnlookup(ipaddr, class, 1); 907 rp->owner = nsdp; 908 rp->local = 1; 909 rp->db = 1; 910 // rp->ttl = 10*Min; /* seems too short */ 911 rp->ttl = (1UL<<31)-1; 912 rrattach(rp, Authoritative); /* will not attach rrs in my area */ 913 914 dnslog("added local dns server %s at %s", buf, ipaddr); 915 } 916 917 /* 918 * return list of dns server addresses to use when 919 * acting just as a resolver. 920 */ 921 RR* 922 dnsservers(int class) 923 { 924 int i, n; 925 char *p, *buf; 926 char *args[5]; 927 Ndbtuple *t, *nt; 928 RR *nsrp; 929 DN *dp; 930 931 dp = dnlookup(localservers, class, 1); 932 nsrp = rrlookup(dp, Tns, NOneg); 933 if(nsrp != nil) 934 return nsrp; 935 936 p = getenv("DNSSERVER"); /* list of ip addresses */ 937 if(p != nil){ 938 buf = estrdup(p); 939 n = tokenize(buf, args, nelem(args)); 940 for(i = 0; i < n; i++) 941 addlocaldnsserver(dp, class, args[i], i); 942 free(buf); 943 } else { 944 t = lookupinfo("@dns"); /* @dns=ip1 @dns=ip2 ... */ 945 if(t == nil) 946 return nil; 947 i = 0; 948 for(nt = t; nt != nil; nt = nt->entry){ 949 addlocaldnsserver(dp, class, nt->val, i); 950 i++; 951 } 952 ndbfree(t); 953 } 954 955 return rrlookup(dp, Tns, NOneg); 956 } 957 958 static void 959 addlocaldnsdomain(DN *dp, int class, char *domain) 960 { 961 RR *rp; 962 963 /* A record */ 964 rp = rralloc(Tptr); 965 rp->ptr = dnlookup(domain, class, 1); 966 rp->owner = dp; 967 rp->db = 1; 968 rp->ttl = 10*Min; 969 rrattach(rp, Authoritative); 970 } 971 972 /* 973 * return list of domains to use when resolving names without '.'s 974 */ 975 RR* 976 domainlist(int class) 977 { 978 Ndbtuple *t, *nt; 979 RR *rp; 980 DN *dp; 981 982 dp = dnlookup("local#dns#domains", class, 1); 983 rp = rrlookup(dp, Tptr, NOneg); 984 if(rp != nil) 985 return rp; 986 987 t = lookupinfo("dnsdomain"); 988 if(t == nil) 989 return nil; 990 for(nt = t; nt != nil; nt = nt->entry) 991 addlocaldnsdomain(dp, class, nt->val); 992 ndbfree(t); 993 994 return rrlookup(dp, Tptr, NOneg); 995 } 996 997 char *v4ptrdom = ".in-addr.arpa"; 998 char *v6ptrdom = ".ip6.arpa"; /* ip6.int deprecated, rfc 3152 */ 999 1000 char *attribs[] = { 1001 "ipmask", 1002 0 1003 }; 1004 1005 /* 1006 * create ptrs that are in our v4 areas 1007 */ 1008 static void 1009 createv4ptrs(void) 1010 { 1011 int len, dlen, n; 1012 char *dom; 1013 char buf[Domlen+1], ipa[48]; 1014 char *f[40]; 1015 uchar net[IPaddrlen], mask[IPaddrlen]; 1016 Area *s; 1017 Ndbtuple *t, *nt; 1018 1019 dlen = strlen(v4ptrdom); 1020 for(s = owned; s; s = s->next){ 1021 dom = s->soarr->owner->name; 1022 len = strlen(dom); 1023 if((len <= dlen || cistrcmp(dom+len-dlen, v4ptrdom) != 0) && 1024 cistrcmp(dom, v4ptrdom+1) != 0) 1025 continue; 1026 1027 /* get mask and net value */ 1028 strncpy(buf, dom, sizeof buf); 1029 buf[sizeof buf-1] = 0; 1030 /* buf contains something like 178.204.in-addr.arpa (n==4) */ 1031 n = getfields(buf, f, nelem(f), 0, "."); 1032 memset(mask, 0xff, IPaddrlen); 1033 ipmove(net, v4prefix); 1034 switch(n){ 1035 case 3: /* /8 */ 1036 net[IPv4off] = atoi(f[0]); 1037 mask[IPv4off+1] = 0; 1038 mask[IPv4off+2] = 0; 1039 mask[IPv4off+3] = 0; 1040 break; 1041 case 4: /* /16 */ 1042 net[IPv4off] = atoi(f[1]); 1043 net[IPv4off+1] = atoi(f[0]); 1044 mask[IPv4off+2] = 0; 1045 mask[IPv4off+3] = 0; 1046 break; 1047 case 5: /* /24 */ 1048 net[IPv4off] = atoi(f[2]); 1049 net[IPv4off+1] = atoi(f[1]); 1050 net[IPv4off+2] = atoi(f[0]); 1051 mask[IPv4off+3] = 0; 1052 break; 1053 case 6: /* rfc2317 */ 1054 net[IPv4off] = atoi(f[3]); 1055 net[IPv4off+1] = atoi(f[2]); 1056 net[IPv4off+2] = atoi(f[1]); 1057 net[IPv4off+3] = atoi(f[0]); 1058 sprint(ipa, "%I", net); 1059 t = ndbipinfo(db, "ip", ipa, attribs, 1); 1060 if(t == nil) /* could be a reverse with no forward */ 1061 continue; 1062 nt = look(t, t, "ipmask"); 1063 if(nt == nil){ /* we're confused */ 1064 ndbfree(t); 1065 continue; 1066 } 1067 parseipmask(mask, nt->val); 1068 ndbfree(t); 1069 n = 5; 1070 break; 1071 default: 1072 continue; 1073 } 1074 1075 /* 1076 * go through all domain entries looking for RR's 1077 * in this network and create ptrs. 1078 * +2 for ".in-addr.arpa". 1079 */ 1080 dnptr(net, mask, dom, Ta, 4+2-n, Ptrttl); 1081 } 1082 } 1083 1084 /* convert bytes to nibbles, big-endian */ 1085 void 1086 bytes2nibbles(uchar *nibbles, uchar *bytes, int nbytes) 1087 { 1088 while (nbytes-- > 0) { 1089 *nibbles++ = *bytes >> Nibwidth; 1090 *nibbles++ = *bytes++ & Nibmask; 1091 } 1092 } 1093 1094 void 1095 nibbles2bytes(uchar *bytes, uchar *nibbles, int nnibs) 1096 { 1097 for (; nnibs >= 2; nnibs -= 2) { 1098 *bytes++ = nibbles[0] << Nibwidth | (nibbles[1]&Nibmask); 1099 nibbles += 2; 1100 } 1101 if (nnibs > 0) 1102 *bytes = nibbles[0] << Nibwidth; 1103 } 1104 1105 /* 1106 * create ptrs that are in our v6 areas. see rfc3596 1107 */ 1108 static void 1109 createv6ptrs(void) 1110 { 1111 int len, dlen, i, n, pfxnibs; 1112 char *dom; 1113 char buf[Domlen+1]; 1114 char *f[40]; 1115 uchar net[IPaddrlen], mask[IPaddrlen]; 1116 uchar nibnet[IPaddrlen*2], nibmask[IPaddrlen*2]; 1117 Area *s; 1118 1119 dlen = strlen(v6ptrdom); 1120 for(s = owned; s; s = s->next){ 1121 dom = s->soarr->owner->name; 1122 len = strlen(dom); 1123 if((len <= dlen || cistrcmp(dom+len-dlen, v6ptrdom) != 0) && 1124 cistrcmp(dom, v6ptrdom+1) != 0) 1125 continue; 1126 1127 /* get mask and net value */ 1128 strncpy(buf, dom, sizeof buf); 1129 buf[sizeof buf-1] = 0; 1130 /* buf contains something like 2.0.0.2.ip6.arpa (n==6) */ 1131 n = getfields(buf, f, nelem(f), 0, "."); 1132 pfxnibs = n - 2; 1133 if (pfxnibs < 0 || pfxnibs > V6maxrevdomdepth) 1134 continue; 1135 1136 memset(net, 0, IPaddrlen); 1137 memset(mask, 0xff, IPaddrlen); 1138 bytes2nibbles(nibnet, net, IPaddrlen); 1139 bytes2nibbles(nibmask, mask, IPaddrlen); 1140 1141 /* copy prefix of f, in reverse order, to start of net. */ 1142 for (i = 0; i < pfxnibs; i++) 1143 nibnet[i] = strtol(f[pfxnibs - 1 - i], nil, 16); 1144 /* zero nibbles of mask after prefix in net */ 1145 memset(nibmask + pfxnibs, 0, V6maxrevdomdepth - pfxnibs); 1146 1147 nibbles2bytes(net, nibnet, 2*IPaddrlen); 1148 nibbles2bytes(mask, nibmask, 2*IPaddrlen); 1149 1150 /* 1151 * go through all domain entries looking for RR's 1152 * in this network and create ptrs. 1153 * +2 for .ip6.arpa. 1154 */ 1155 dnptr(net, mask, dom, Taaaa, V6maxrevdomdepth - pfxnibs, Ptrttl); 1156 } 1157 } 1158 1159 /* 1160 * create ptrs that are in our areas 1161 */ 1162 static void 1163 createptrs(void) 1164 { 1165 createv4ptrs(); 1166 createv6ptrs(); 1167 } 1168 1169 /* 1170 * is this domain (or DOMAIN or Domain or dOMAIN) 1171 * internal to our organisation (behind our firewall)? 1172 * only inside straddling servers care, everybody else gets told `yes', 1173 * so they'll use mntpt for their queries. 1174 */ 1175 int 1176 insideaddr(char *dom) 1177 { 1178 int domlen, vallen, rv; 1179 Ndbtuple *t; 1180 1181 if (!cfg.inside || !cfg.straddle || !cfg.serve) 1182 return 1; 1183 1184 lock(&dblock); 1185 if (indoms == nil) 1186 loaddomsrvs(); 1187 if (indoms == nil) { 1188 unlock(&dblock); 1189 return 1; /* no "inside" sys, try inside nameservers */ 1190 } 1191 1192 rv = 0; 1193 domlen = strlen(dom); 1194 for (t = indoms; t != nil; t = t->entry) { 1195 if (strcmp(t->attr, "dom") != 0) 1196 continue; 1197 vallen = strlen(t->val); 1198 if (cistrcmp(dom, t->val) == 0 || 1199 domlen > vallen && 1200 cistrcmp(dom + domlen - vallen, t->val) == 0 && 1201 dom[domlen - vallen - 1] == '.') { 1202 rv = 1; 1203 break; 1204 } 1205 } 1206 unlock(&dblock); 1207 return rv; 1208 } 1209 1210 int 1211 insidens(uchar *ip) 1212 { 1213 uchar ipa[IPaddrlen]; 1214 Ndbtuple *t; 1215 1216 for (t = innmsrvs; t != nil; t = t->entry) 1217 if (strcmp(t->attr, "ip") == 0) { 1218 parseip(ipa, t->val); 1219 if (memcmp(ipa, ip, sizeof ipa) == 0) 1220 return 1; 1221 } 1222 return 0; 1223 } 1224 1225 uchar * 1226 outsidens(int n) 1227 { 1228 int i; 1229 Ndbtuple *t; 1230 static uchar ipa[IPaddrlen]; 1231 1232 i = 0; 1233 for (t = outnmsrvs; t != nil; t = t->entry) 1234 if (strcmp(t->attr, "ip") == 0 && i++ == n) { 1235 parseip(ipa, t->val); 1236 return ipa; 1237 } 1238 return nil; 1239 } 1240