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