1 #include <u.h> 2 #include <libc.h> 3 #include <ip.h> 4 #include <bio.h> 5 #include <ndb.h> 6 #include "dns.h" 7 8 enum 9 { 10 Maxdest= 24, /* maximum destinations for a request message */ 11 Maxtrans= 3, /* maximum transmissions to a server */ 12 }; 13 14 static int netquery(DN*, int, RR*, Request*, int); 15 static RR* dnresolve1(char*, int, int, Request*, int, int); 16 17 /* 18 * reading /proc/pid/args yields either "name" or "name [display args]", 19 * so return only display args, if any. 20 */ 21 static char * 22 procgetname(void) 23 { 24 int fd, n; 25 char *lp, *rp; 26 char buf[256]; 27 28 snprint(buf, sizeof buf, "#p/%d/args", getpid()); 29 if((fd = open(buf, OREAD)) < 0) 30 return strdup(""); 31 *buf = '\0'; 32 n = read(fd, buf, sizeof buf-1); 33 close(fd); 34 if (n >= 0) 35 buf[n] = '\0'; 36 if ((lp = strchr(buf, '[')) == nil || 37 (rp = strrchr(buf, ']')) == nil) 38 return strdup(""); 39 *rp = '\0'; 40 return strdup(lp+1); 41 } 42 43 /* 44 * lookup 'type' info for domain name 'name'. If it doesn't exist, try 45 * looking it up as a canonical name. 46 */ 47 RR* 48 dnresolve(char *name, int class, int type, Request *req, RR **cn, int depth, 49 int recurse, int rooted, int *status) 50 { 51 RR *rp, *nrp, *drp; 52 DN *dp; 53 int loops; 54 char *procname; 55 char nname[Domlen]; 56 57 if(status) 58 *status = 0; 59 60 procname = procgetname(); 61 /* 62 * hack for systems that don't have resolve search 63 * lists. Just look up the simple name in the database. 64 */ 65 if(!rooted && strchr(name, '.') == 0){ 66 rp = nil; 67 drp = domainlist(class); 68 for(nrp = drp; nrp != nil; nrp = nrp->next){ 69 snprint(nname, sizeof nname, "%s.%s", name, 70 nrp->ptr->name); 71 rp = dnresolve(nname, class, type, req, cn, depth, 72 recurse, rooted, status); 73 rrfreelist(rrremneg(&rp)); 74 if(rp != nil) 75 break; 76 } 77 if(drp != nil) 78 rrfree(drp); 79 procsetname(procname); 80 free(procname); 81 return rp; 82 } 83 84 /* 85 * try the name directly 86 */ 87 rp = dnresolve1(name, class, type, req, depth, recurse); 88 if(rp) { 89 procsetname(procname); 90 free(procname); 91 return randomize(rp); 92 } 93 94 /* try it as a canonical name if we weren't told the name didn't exist */ 95 dp = dnlookup(name, class, 0); 96 if(type != Tptr && dp->respcode != Rname) 97 for(loops = 0; rp == nil && loops < 32; loops++){ 98 rp = dnresolve1(name, class, Tcname, req, depth, recurse); 99 if(rp == nil) 100 break; 101 102 if(rp->negative){ 103 rrfreelist(rp); 104 rp = nil; 105 break; 106 } 107 108 name = rp->host->name; 109 if(cn) 110 rrcat(cn, rp); 111 else 112 rrfreelist(rp); 113 114 rp = dnresolve1(name, class, type, req, depth, recurse); 115 } 116 117 /* distinction between not found and not good */ 118 if(rp == nil && status != nil && dp->respcode != 0) 119 *status = dp->respcode; 120 121 procsetname(procname); 122 free(procname); 123 return randomize(rp); 124 } 125 126 static RR* 127 dnresolve1(char *name, int class, int type, Request *req, int depth, 128 int recurse) 129 { 130 DN *dp, *nsdp; 131 RR *rp, *nsrp, *dbnsrp; 132 char *cp; 133 134 if(debug) 135 dnslog("[%d] dnresolve1 %s %d %d", getpid(), name, type, class); 136 137 /* only class Cin implemented so far */ 138 if(class != Cin) 139 return nil; 140 141 dp = dnlookup(name, class, 1); 142 143 /* 144 * Try the cache first 145 */ 146 rp = rrlookup(dp, type, OKneg); 147 if(rp) 148 if(rp->db){ 149 /* unauthoritative db entries are hints */ 150 if(rp->auth) 151 return rp; 152 } else 153 /* cached entry must still be valid */ 154 if(rp->ttl > now) 155 /* but Tall entries are special */ 156 if(type != Tall || rp->query == Tall) 157 return rp; 158 159 rrfreelist(rp); 160 161 /* 162 * try the cache for a canonical name. if found punt 163 * since we'll find it during the canonical name search 164 * in dnresolve(). 165 */ 166 if(type != Tcname){ 167 rp = rrlookup(dp, Tcname, NOneg); 168 rrfreelist(rp); 169 if(rp) 170 return nil; 171 } 172 173 /* 174 * if we're running as just a resolver, query our 175 * designated name servers 176 */ 177 if(cfg.resolver){ 178 nsrp = randomize(getdnsservers(class)); 179 if(nsrp != nil) { 180 if(netquery(dp, type, nsrp, req, depth+1)){ 181 rrfreelist(nsrp); 182 return rrlookup(dp, type, OKneg); 183 } 184 rrfreelist(nsrp); 185 } 186 } 187 188 /* 189 * walk up the domain name looking for 190 * a name server for the domain. 191 */ 192 for(cp = name; cp; cp = walkup(cp)){ 193 /* 194 * if this is a local (served by us) domain, 195 * return answer 196 */ 197 dbnsrp = randomize(dblookup(cp, class, Tns, 0, 0)); 198 if(dbnsrp && dbnsrp->local){ 199 rp = dblookup(name, class, type, 1, dbnsrp->ttl); 200 // dnslog("dnresolve1: local domain %s -> %#p", name, rp); 201 rrfreelist(dbnsrp); 202 return rp; 203 } 204 205 /* 206 * if recursion isn't set, just accept local 207 * entries 208 */ 209 if(recurse == Dontrecurse){ 210 if(dbnsrp) 211 rrfreelist(dbnsrp); 212 continue; 213 } 214 215 /* look for ns in cache */ 216 nsdp = dnlookup(cp, class, 0); 217 nsrp = nil; 218 if(nsdp) 219 nsrp = randomize(rrlookup(nsdp, Tns, NOneg)); 220 221 /* if the entry timed out, ignore it */ 222 if(nsrp && nsrp->ttl < now){ 223 rrfreelist(nsrp); 224 nsrp = nil; 225 } 226 227 if(nsrp){ 228 rrfreelist(dbnsrp); 229 230 /* query the name servers found in cache */ 231 // dnslog("dnresolve1: %s: trying ns in cache", dp->name); 232 if(netquery(dp, type, nsrp, req, depth+1)){ 233 rrfreelist(nsrp); 234 return rrlookup(dp, type, OKneg); 235 } 236 rrfreelist(nsrp); 237 continue; 238 } 239 240 /* use ns from db */ 241 if(dbnsrp){ 242 /* try the name servers found in db */ 243 // dnslog("dnresolve1: %s: trying ns in db", dp->name); 244 if(netquery(dp, type, dbnsrp, req, depth+1)){ 245 /* we got an answer */ 246 rrfreelist(dbnsrp); 247 return rrlookup(dp, type, NOneg); 248 } 249 rrfreelist(dbnsrp); 250 } 251 } 252 253 /* settle for a non-authoritative answer */ 254 rp = rrlookup(dp, type, OKneg); 255 if(rp) 256 return rp; 257 258 /* noone answered. try the database, we might have a chance. */ 259 return dblookup(name, class, type, 0, 0); 260 } 261 262 /* 263 * walk a domain name one element to the right. 264 * return a pointer to that element. 265 * in other words, return a pointer to the parent domain name. 266 */ 267 char* 268 walkup(char *name) 269 { 270 char *cp; 271 272 cp = strchr(name, '.'); 273 if(cp) 274 return cp+1; 275 else if(*name) 276 return ""; 277 else 278 return 0; 279 } 280 281 /* 282 * Get a udpport for requests and replies. Put the port 283 * into "headers" mode. 284 */ 285 static char *hmsg = "headers"; 286 static char *ohmsg = "oldheaders"; 287 288 int 289 udpport(char *mtpt) 290 { 291 int fd, ctl; 292 char ds[64], adir[64]; 293 294 /* get a udp port */ 295 snprint(ds, sizeof ds, "%s/udp!*!0", (mtpt? mtpt: "/net")); 296 ctl = announce(ds, adir); 297 if(ctl < 0){ 298 /* warning("can't get udp port"); */ 299 return -1; 300 } 301 302 /* turn on header style interface */ 303 if(write(ctl, hmsg, strlen(hmsg)) , 0){ 304 close(ctl); 305 warning(hmsg); 306 return -1; 307 } 308 write(ctl, ohmsg, strlen(ohmsg)); 309 310 /* grab the data file */ 311 snprint(ds, sizeof ds, "%s/data", adir); 312 fd = open(ds, ORDWR); 313 close(ctl); 314 if(fd < 0) 315 warning("can't open udp port %s: %r", ds); 316 return fd; 317 } 318 319 /* generate a DNS UDP query packet */ 320 int 321 mkreq(DN *dp, int type, uchar *buf, int flags, ushort reqno) 322 { 323 DNSmsg m; 324 int len; 325 OUdphdr *uh = (OUdphdr*)buf; 326 327 /* stuff port number into output buffer */ 328 memset(uh, 0, sizeof(*uh)); 329 hnputs(uh->rport, 53); 330 331 /* make request and convert it to output format */ 332 memset(&m, 0, sizeof(m)); 333 m.flags = flags; 334 m.id = reqno; 335 m.qd = rralloc(type); 336 m.qd->owner = dp; 337 m.qd->type = type; 338 len = convDNS2M(&m, &buf[OUdphdrsize], Maxudp); 339 rrfree(m.qd); 340 return len; 341 } 342 343 /* for alarms in readreply */ 344 static void 345 ding(void *x, char *msg) 346 { 347 USED(x); 348 if(strcmp(msg, "alarm") == 0) 349 noted(NCONT); 350 else 351 noted(NDFLT); 352 } 353 354 static void 355 freeanswers(DNSmsg *mp) 356 { 357 rrfreelist(mp->qd); 358 rrfreelist(mp->an); 359 rrfreelist(mp->ns); 360 rrfreelist(mp->ar); 361 mp->qd = mp->an = mp->ns = mp->ar = nil; 362 } 363 364 /* 365 * read replies to a request. ignore any of the wrong type. 366 * wait at most until endtime. 367 */ 368 static int 369 readreply(int fd, DN *dp, int type, ushort req, uchar *ibuf, DNSmsg *mp, 370 ulong endtime, Request *reqp) 371 { 372 char *err; 373 int len; 374 ulong now; 375 RR *rp; 376 377 notify(ding); 378 379 for(; ; freeanswers(mp)){ 380 now = time(nil); 381 if(now >= endtime) 382 return -1; /* timed out */ 383 384 /* timed read of UDP reply */ 385 alarm((endtime - now) * 1000); 386 len = read(fd, ibuf, OUdphdrsize+Maxudpin); 387 alarm(0); 388 len -= OUdphdrsize; 389 if(len < 0) 390 return -1; /* timed out */ 391 392 /* convert into internal format */ 393 memset(mp, 0, sizeof(*mp)); 394 err = convM2DNS(&ibuf[OUdphdrsize], len, mp, nil); 395 if (mp->flags & Ftrunc) { 396 dnslog("truncated reply, len %d from %I", len, ibuf); 397 /* TODO: reissue query via tcp, process answer */ 398 /* for now, salvage what we can */ 399 } 400 if(err){ 401 dnslog("input err, len %d: %s: %I", len, err, ibuf); 402 continue; 403 } 404 if(debug) 405 logreply(reqp->id, ibuf, mp); 406 407 /* answering the right question? */ 408 if(mp->id != req){ 409 dnslog("%d: id %d instead of %d: %I", reqp->id, 410 mp->id, req, ibuf); 411 continue; 412 } 413 if(mp->qd == 0){ 414 dnslog("%d: no question RR: %I", reqp->id, ibuf); 415 continue; 416 } 417 if(mp->qd->owner != dp){ 418 dnslog("%d: owner %s instead of %s: %I", 419 reqp->id, mp->qd->owner->name, dp->name, ibuf); 420 continue; 421 } 422 if(mp->qd->type != type){ 423 dnslog("%d: type %d instead of %d: %I", 424 reqp->id, mp->qd->type, type, ibuf); 425 continue; 426 } 427 428 /* remember what request this is in answer to */ 429 for(rp = mp->an; rp; rp = rp->next) 430 rp->query = type; 431 432 return 0; 433 } 434 } 435 436 /* 437 * return non-0 if first list includes second list 438 */ 439 int 440 contains(RR *rp1, RR *rp2) 441 { 442 RR *trp1, *trp2; 443 444 for(trp2 = rp2; trp2; trp2 = trp2->next){ 445 for(trp1 = rp1; trp1; trp1 = trp1->next){ 446 if(trp1->type == trp2->type) 447 if(trp1->host == trp2->host) 448 if(trp1->owner == trp2->owner) 449 break; 450 } 451 if(trp1 == nil) 452 return 0; 453 } 454 return 1; 455 } 456 457 458 typedef struct Dest Dest; 459 struct Dest 460 { 461 uchar a[IPaddrlen]; /* ip address */ 462 DN *s; /* name server */ 463 int nx; /* number of transmissions */ 464 int code; /* response code; used to clear dp->respcode */ 465 }; 466 467 468 /* 469 * return multicast version if any 470 */ 471 int 472 ipisbm(uchar *ip) 473 { 474 if(isv4(ip)){ 475 if (ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0 || 476 ipcmp(ip, IPv4bcast) == 0) 477 return 4; 478 } else 479 if(ip[0] == 0xff) 480 return 6; 481 return 0; 482 } 483 484 /* 485 * Get next server address 486 */ 487 static int 488 serveraddrs(DN *dp, RR *nsrp, Dest *dest, int nd, int depth, Request *reqp) 489 { 490 RR *rp, *arp, *trp; 491 Dest *cur; 492 493 if(nd >= Maxdest) 494 return 0; 495 496 /* 497 * look for a server whose address we already know. 498 * if we find one, mark it so we ignore this on 499 * subsequent passes. 500 */ 501 arp = 0; 502 for(rp = nsrp; rp; rp = rp->next){ 503 assert(rp->magic == RRmagic); 504 if(rp->marker) 505 continue; 506 arp = rrlookup(rp->host, Ta, NOneg); 507 if(arp){ 508 rp->marker = 1; 509 break; 510 } 511 arp = dblookup(rp->host->name, Cin, Ta, 0, 0); 512 if(arp){ 513 rp->marker = 1; 514 break; 515 } 516 } 517 518 /* 519 * if the cache and database lookup didn't find any new 520 * server addresses, try resolving one via the network. 521 * Mark any we try to resolve so we don't try a second time. 522 */ 523 if(arp == 0) 524 for(rp = nsrp; rp; rp = rp->next){ 525 if(rp->marker) 526 continue; 527 rp->marker = 1; 528 529 /* 530 * avoid loops looking up a server under itself 531 */ 532 if(subsume(rp->owner->name, rp->host->name)) 533 continue; 534 535 arp = dnresolve(rp->host->name, Cin, Ta, reqp, 0, 536 depth+1, Recurse, 1, 0); 537 rrfreelist(rrremneg(&arp)); 538 if(arp) 539 break; 540 } 541 542 /* use any addresses that we found */ 543 for(trp = arp; trp; trp = trp->next){ 544 if(nd >= Maxdest) 545 break; 546 cur = &dest[nd]; 547 parseip(cur->a, trp->ip->name); 548 /* 549 * straddling servers can reject all nameservers if they are all 550 * inside, so be sure to list at least one outside ns at 551 * the end of the ns list in /lib/ndb for `dom='. 552 */ 553 if (ipisbm(cur->a) || 554 cfg.straddle && !insideaddr(dp->name) && insidens(cur->a)) 555 continue; 556 cur->nx = 0; 557 cur->s = trp->owner; 558 cur->code = Rtimeout; 559 nd++; 560 } 561 rrfreelist(arp); 562 return nd; 563 } 564 565 /* 566 * cache negative responses 567 */ 568 static void 569 cacheneg(DN *dp, int type, int rcode, RR *soarr) 570 { 571 RR *rp; 572 DN *soaowner; 573 ulong ttl; 574 575 /* no cache time specified, don't make anything up */ 576 if(soarr != nil){ 577 if(soarr->next != nil){ 578 rrfreelist(soarr->next); 579 soarr->next = nil; 580 } 581 soaowner = soarr->owner; 582 } else 583 soaowner = nil; 584 585 /* the attach can cause soarr to be freed so mine it now */ 586 if(soarr != nil && soarr->soa != nil) 587 ttl = soarr->soa->minttl+now; 588 else 589 ttl = 5*Min; 590 591 /* add soa and negative RR to the database */ 592 rrattach(soarr, 1); 593 594 rp = rralloc(type); 595 rp->owner = dp; 596 rp->negative = 1; 597 rp->negsoaowner = soaowner; 598 rp->negrcode = rcode; 599 rp->ttl = ttl; 600 rrattach(rp, 1); 601 } 602 603 static int 604 setdestoutns(Dest *p, int n) 605 { 606 uchar *outns = outsidens(n); 607 608 memset(p, 0, sizeof *p); 609 if (outns == nil) { 610 if (n == 0) 611 dnslog("[%d] no outside-ns in ndb", getpid()); 612 return -1; 613 } 614 memmove(p->a, outns, sizeof p->a); 615 p->s = dnlookup("outside-ns-ips", Cin, 1); 616 return 0; 617 } 618 619 /* 620 * query name servers. If the name server returns a pointer to another 621 * name server, recurse. 622 * BUG: UDP only currently. 623 */ 624 static int 625 netquery1(int fd, DN *dp, int type, RR *nsrp, Request *reqp, int depth, 626 uchar *ibuf, uchar *obuf, int waitsecs, int inns) 627 { 628 int ndest, j, len, replywaits, rv, n; 629 ushort req; 630 ulong endtime; 631 char buf[12]; 632 DN *ndp; 633 DNSmsg m; 634 Dest *p, *l, *np; 635 Dest dest[Maxdest]; 636 RR *tp, *soarr; 637 // char fdbuf[1024]; 638 639 // fd2path(fd, fdbuf, sizeof fdbuf); 640 // dnslog("netquery: on %s for %s %s ns", fdbuf, dp->name, 641 // (inns? "inside": "outside")); 642 643 /* pack request into a message */ 644 req = rand(); 645 /* 1. generate UDP DNS query packet */ 646 len = mkreq(dp, type, obuf, Frecurse|Oquery, req); 647 /* TODO: convert back and see if m.flags&Ftrunc is set */ 648 649 /* no server addresses yet */ 650 l = dest; 651 652 /* 653 * transmit requests and wait for answers. 654 * at most Maxtrans attempts to each address. 655 * each cycle send one more message than the previous. 656 */ 657 for(ndest = 1; ndest < Maxdest; ndest++){ 658 // dnslog("netquery1 xmit loop: now %ld aborttime %ld", time(nil), 659 // reqp->aborttime); 660 if(time(nil) >= reqp->aborttime) 661 break; 662 663 /* get a server address if we need one */ 664 p = dest; 665 if(ndest > l - p){ 666 j = serveraddrs(dp, nsrp, dest, l - p, depth, reqp); 667 l = &dest[j]; 668 } 669 670 /* no servers, punt */ 671 if(l == dest) 672 if (cfg.straddle && cfg.inside) { 673 p = l = dest; 674 for(n = 0; n < Maxdest; n++, l++) 675 if (setdestoutns(l, n) < 0) 676 break; 677 } else { 678 // dnslog("netquery1: %s: no servers", dp->name); 679 break; 680 } 681 682 /* send to first 'ndest' destinations */ 683 j = 0; 684 for(; p < &dest[ndest] && p < l; p++){ 685 /* skip destinations we've finished with */ 686 if(p->nx >= Maxtrans) 687 continue; 688 689 j++; 690 691 /* exponential backoff of requests */ 692 if((1<<p->nx) > ndest) 693 continue; 694 695 memmove(obuf, p->a, sizeof p->a); 696 procsetname("req slave: %sside query to %I/%s %s %s", 697 (inns? "in": "out"), obuf, p->s->name, dp->name, 698 rrname(type, buf, sizeof buf)); 699 if(debug) 700 logsend(reqp->id, depth, obuf, p->s->name, 701 dp->name, type); 702 703 /* 2. actually send the UDP packet */ 704 // TODO or send via TCP & keep fd around for reply */ 705 if(write(fd, obuf, len + OUdphdrsize) < 0) 706 warning("sending udp msg %r"); 707 p->nx++; 708 } 709 if(j == 0) 710 break; /* no destinations left */ 711 712 endtime = time(nil) + waitsecs; 713 if(endtime > reqp->aborttime) 714 endtime = reqp->aborttime; 715 716 // dnslog( 717 // "netquery1 reply wait: now %ld aborttime %ld endtime %ld", 718 // time(nil), reqp->aborttime, endtime); 719 for(replywaits = 0; replywaits < ndest; replywaits++){ 720 procsetname( 721 "req slave: reading %sside reply from %I for %s %s", 722 (inns? "in": "out"), obuf, dp->name, 723 rrname(type, buf, sizeof buf)); 724 memset(&m, 0, sizeof m); 725 /* 3. get UDP reply packet */ 726 if(readreply(fd, dp, type, req, ibuf, &m, endtime, reqp) 727 < 0) 728 break; /* timed out */ 729 730 // dnslog("netquery1 got reply from %I", ibuf); 731 /* find responder */ 732 for(p = dest; p < l; p++) 733 if(memcmp(p->a, ibuf, sizeof p->a) == 0) 734 break; 735 736 /* remove all addrs of responding server from list */ 737 for(np = dest; np < l; np++) 738 if(np->s == p->s) 739 p->nx = Maxtrans; 740 741 /* ignore any error replies */ 742 if((m.flags & Rmask) == Rserver){ 743 // dnslog( 744 // "netquery1 got Rserver for dest %s of name %s", 745 // p->s->name, dp->name); 746 rrfreelist(m.qd); 747 rrfreelist(m.an); 748 rrfreelist(m.ar); 749 rrfreelist(m.ns); 750 if(p != l) { 751 // dnslog( 752 // "netquery1 setting Rserver for dest %s of name %s due to Rserver reply", 753 // p->s->name, dp->name); 754 p->code = Rserver; 755 } 756 continue; 757 } 758 759 /* ignore any bad delegations */ 760 if(m.ns && baddelegation(m.ns, nsrp, ibuf)){ 761 // dnslog("netquery1 got a bad delegation from %s", 762 // p->s->name); 763 rrfreelist(m.ns); 764 m.ns = nil; 765 if(m.an == nil){ 766 rrfreelist(m.qd); 767 rrfreelist(m.ar); 768 if(p != l) { 769 // dnslog( 770 //"netquery1 setting Rserver for dest %s of name %s due to bad delegation", 771 // p->s->name, dp->name); 772 p->code = Rserver; 773 } 774 continue; 775 } 776 } 777 778 /* remove any soa's from the authority section */ 779 soarr = rrremtype(&m.ns, Tsoa); 780 781 /* incorporate answers */ 782 if(m.an) 783 rrattach(m.an, (m.flags & Fauth) != 0); 784 if(m.ar) 785 rrattach(m.ar, 0); 786 if(m.ns){ 787 ndp = m.ns->owner; 788 rrattach(m.ns, 0); 789 } else 790 ndp = nil; 791 792 /* free the question */ 793 if(m.qd) 794 rrfreelist(m.qd); 795 796 /* 797 * Any reply from an authoritative server, 798 * or a positive reply terminates the search 799 */ 800 if(m.an != nil || (m.flags & Fauth)){ 801 if(m.an == nil && (m.flags & Rmask) == Rname) 802 dp->respcode = Rname; 803 else 804 dp->respcode = 0; 805 806 /* 807 * cache any negative responses, free soarr 808 */ 809 if((m.flags & Fauth) && m.an == nil) 810 cacheneg(dp, type, (m.flags & Rmask), 811 soarr); 812 else 813 rrfreelist(soarr); 814 return 1; 815 } 816 rrfreelist(soarr); 817 818 /* 819 * if we've been given better name servers, 820 * recurse. we're called from udpquery, called from 821 * netquery, which current holds dp->querylck, 822 * so release it now and acquire it upon return. 823 */ 824 if(m.ns){ 825 tp = rrlookup(ndp, Tns, NOneg); 826 if(!contains(nsrp, tp)){ 827 procsetname( 828 "req slave: recursive query for %s %s", 829 dp->name, 830 rrname(type, buf, sizeof buf)); 831 qunlock(&dp->querylck); 832 833 rv = netquery(dp, type, tp, reqp, 834 depth+1); 835 836 qlock(&dp->querylck); 837 rrfreelist(tp); 838 return rv; 839 } else 840 rrfreelist(tp); 841 } 842 } 843 } 844 845 /* if all servers returned failure, propagate it */ 846 dp->respcode = Rserver; 847 for(p = dest; p < l; p++) 848 if(p->code != Rserver) 849 dp->respcode = 0; 850 851 // if (dp->respcode) 852 // dnslog("netquery1 setting Rserver for %s", dp->name); 853 854 return 0; 855 } 856 857 /* 858 * run a command with a supplied fd as standard input 859 */ 860 char * 861 system(int fd, char *cmd) 862 { 863 int pid, p, i; 864 static Waitmsg msg; 865 866 if((pid = fork()) == -1) 867 sysfatal("fork failed: %r"); 868 else if(pid == 0){ 869 dup(fd, 0); 870 close(fd); 871 for (i = 3; i < 200; i++) 872 close(i); /* don't leak fds */ 873 execl("/bin/rc", "rc", "-c", cmd, nil); 874 sysfatal("exec rc: %r"); 875 } 876 for(p = waitpid(); p >= 0; p = waitpid()) 877 if(p == pid) 878 return msg.msg; 879 return "lost child"; 880 } 881 882 enum { Hurry, Patient, }; 883 enum { Outns, Inns, }; 884 enum { Remntretry = 15, }; /* min. sec.s between remount attempts */ 885 886 static int 887 udpquery(char *mntpt, DN *dp, int type, RR *nsrp, Request *reqp, int depth, 888 int patient, int inns) 889 { 890 int fd, rv = 0; 891 long now; 892 char *msg; 893 uchar *obuf, *ibuf; 894 static QLock mntlck; 895 static ulong lastmount; 896 897 /* use alloced buffers rather than ones from the stack */ 898 ibuf = emalloc(Maxudpin+OUdphdrsize); 899 obuf = emalloc(Maxudp+OUdphdrsize); 900 901 fd = udpport(mntpt); 902 while (fd < 0 && cfg.straddle && strcmp(mntpt, "/net.alt") == 0) { 903 /* HACK: remount /net.alt */ 904 now = time(nil); 905 if (now < lastmount + Remntretry) 906 sleep((lastmount + Remntretry - now)*1000); 907 qlock(&mntlck); 908 fd = udpport(mntpt); /* try again under lock */ 909 if (fd < 0) { 910 dnslog("[%d] remounting /net.alt", getpid()); 911 unmount(nil, "/net.alt"); 912 913 msg = system(open("/dev/null", ORDWR), "outside"); 914 915 lastmount = time(nil); 916 if (msg && *msg) { 917 dnslog("[%d] can't remount /net.alt: %s", 918 getpid(), msg); 919 sleep(10*1000); /* don't spin wildly */ 920 } else 921 fd = udpport(mntpt); 922 } 923 qunlock(&mntlck); 924 } 925 if(fd >= 0) { 926 reqp->aborttime = time(nil) + (patient? Maxreqtm: Maxreqtm/2); 927 // dnslog("udpquery: %s/udp for %s with %s ns", mntpt, dp->name, 928 // (inns? "inside": "outside")); 929 /* tune; was (patient? 15: 10) */ 930 rv = netquery1(fd, dp, type, nsrp, reqp, depth, 931 ibuf, obuf, (patient? 10: 5), inns); 932 close(fd); 933 } else 934 dnslog("can't get udpport for %s query of name %s: %r", 935 mntpt, dp->name); 936 937 free(obuf); 938 free(ibuf); 939 return rv; 940 } 941 942 static int 943 dnssetup(int domount, char *dns, char *srv, char *mtpt) 944 { 945 int fd; 946 947 fd = open(dns, ORDWR); 948 if(fd < 0){ 949 if(domount == 0){ 950 werrstr("can't open %s: %r", mtpt); 951 return -1; 952 } 953 fd = open(srv, ORDWR); 954 if(fd < 0){ 955 werrstr("can't open %s: %r", srv); 956 return -1; 957 } 958 if(mount(fd, -1, mtpt, MBEFORE, "") < 0){ 959 werrstr("can't mount(%s, %s): %r", srv, mtpt); 960 return -1; 961 } 962 fd = open(mtpt, ORDWR); 963 if(fd < 0) 964 werrstr("can't open %s: %r", mtpt); 965 } 966 return fd; 967 } 968 969 /* this is unfinished */ 970 static RR * 971 rrparse(char *lines) 972 { 973 int nl, nf, ln, type; 974 char *line[100]; 975 char *field[32]; 976 RR *rp, *rplist; 977 // Server *s; 978 SOA *soa; 979 Srv *srv; 980 // Txt *t; 981 982 rplist = nil; 983 nl = tokenize(lines, line, nelem(line)); 984 for (ln = 0; ln < nl; ln++) { 985 if (*line[ln] == '!' || *line[ln] == '?') 986 continue; /* error */ 987 nf = tokenize(line[ln], field, nelem(field)); 988 if (nf < 2) 989 continue; /* mal-formed */ 990 type = rrtype(field[1]); 991 rp = rralloc(type); 992 rp->owner = dnlookup(field[0], Cin, 1); 993 rp->next = rplist; 994 rplist = rp; 995 switch (type) { /* TODO: copy fields to *rp */ 996 case Thinfo: 997 // "\t%s %s", dnname(rp->cpu), dnname(rp->os)); 998 break; 999 case Tcname: 1000 case Tmb: 1001 case Tmd: 1002 case Tmf: 1003 case Tns: 1004 // "\t%s", dnname(rp->host)); 1005 break; 1006 case Tmg: 1007 case Tmr: 1008 // "\t%s", dnname(rp->mb)); 1009 break; 1010 case Tminfo: 1011 // "\t%s %s", dnname(rp->mb), dnname(rp->rmb)); 1012 break; 1013 case Tmx: 1014 // "\t%lud %s", rp->pref, dnname(rp->host)); 1015 break; 1016 case Ta: 1017 case Taaaa: 1018 // "\t%s", dnname(rp->ip)); // TODO: parseip 1019 break; 1020 case Tptr: 1021 // "\t%s", dnname(rp->ptr)); 1022 break; 1023 case Tsoa: 1024 soa = rp->soa; 1025 USED(soa); 1026 // "\t%s %s %lud %lud %lud %lud %lud", 1027 // dnname(rp->host), dnname(rp->rmb), 1028 // (soa? soa->serial: 0), 1029 // (soa? soa->refresh: 0), (soa? soa->retry: 0), 1030 // (soa? soa->expire: 0), (soa? soa->minttl: 0)); 1031 break; 1032 case Tsrv: 1033 srv = rp->srv; 1034 USED(srv); 1035 break; 1036 case Tnull: 1037 // "\t%.*H", rp->null->dlen, rp->null->data); 1038 break; 1039 case Ttxt: 1040 // for(t = rp->txt; t != nil; t = t->next) 1041 // "%s", t->p); 1042 break; 1043 case Trp: 1044 // "\t%s %s", dnname(rp->rmb), dnname(rp->rp)); 1045 break; 1046 case Tkey: 1047 // "\t%d %d %d", rp->key->flags, rp->key->proto, rp->key->alg); 1048 break; 1049 case Tsig: 1050 // "\t%d %d %d %lud %lud %lud %d %s", 1051 // rp->sig->type, rp->sig->alg, rp->sig->labels, 1052 // rp->sig->ttl, rp->sig->exp, rp->sig->incep, 1053 // rp->sig->tag, dnname(rp->sig->signer)); 1054 break; 1055 case Tcert: 1056 // "\t%d %d %d", rp->cert->type, rp->cert->tag, rp->cert->alg); 1057 break; 1058 } 1059 } 1060 return nil; 1061 } 1062 1063 static int 1064 querydns(int fd, char *line, int n) 1065 { 1066 int rv = 0; 1067 char buf[1024]; 1068 1069 seek(fd, 0, 0); 1070 if(write(fd, line, n) != n) 1071 return rv; 1072 1073 seek(fd, 0, 0); 1074 buf[0] = '\0'; 1075 while((n = read(fd, buf, sizeof buf - 1)) > 0) { 1076 buf[n] = 0; 1077 rrattach(rrparse(buf), 1); /* incorporate answers */ 1078 rv = 1; 1079 buf[0] = '\0'; 1080 } 1081 return rv; 1082 } 1083 1084 static void 1085 askoutdns(DN *dp, int type) /* ask /net.alt/dns directly */ 1086 { 1087 int len; 1088 char buf[32]; 1089 char *query; 1090 char *mtpt = "/net.alt"; 1091 char *dns = "/net.alt/dns"; 1092 char *srv = "/srv/dns_net.alt"; 1093 static int fd = -1; 1094 1095 if (fd < 0) 1096 fd = dnssetup(1, dns, srv, mtpt); 1097 1098 query = smprint("%s %s\n", dp->name, rrname(type, buf, sizeof buf)); 1099 len = strlen(query); 1100 if (!querydns(fd, query, len)) { 1101 close(fd); 1102 /* could run outside here */ 1103 fd = dnssetup(1, dns, srv, mtpt); 1104 querydns(fd, query, len); 1105 } 1106 free(query); 1107 } 1108 1109 /* look up (dp->name,type) via *nsrp with results in *reqp */ 1110 static int 1111 netquery(DN *dp, int type, RR *nsrp, Request *reqp, int depth) 1112 { 1113 int lock, rv, triedin, inname; 1114 RR *rp; 1115 1116 if(depth > 12) /* in a recursive loop? */ 1117 return 0; 1118 1119 slave(reqp); 1120 /* 1121 * slave might have forked. if so, the parent process longjmped to 1122 * req->mret; we're usually the child slave, but if there are too 1123 * many children already, we're still the same process. 1124 */ 1125 1126 /* don't lock before call to slave so only children can block */ 1127 lock = reqp->isslave != 0; 1128 if(lock) { 1129 procsetname("waiting for query lock on %s", dp->name); 1130 /* don't make concurrent queries for this name */ 1131 qlock(&dp->querylck); 1132 procsetname("netquery: %s", dp->name); 1133 } 1134 1135 /* prepare server RR's for incremental lookup */ 1136 for(rp = nsrp; rp; rp = rp->next) 1137 rp->marker = 0; 1138 1139 rv = 0; /* pessimism */ 1140 triedin = 0; 1141 /* 1142 * normal resolvers and servers will just use mntpt for all addresses, 1143 * even on the outside. straddling servers will use mntpt (/net) 1144 * for inside addresses and /net.alt for outside addresses, 1145 * thus bypassing other inside nameservers. 1146 */ 1147 inname = insideaddr(dp->name); 1148 if (!cfg.straddle || inname) { 1149 rv = udpquery(mntpt, dp, type, nsrp, reqp, depth, Hurry, 1150 (cfg.inside? Inns: Outns)); 1151 triedin = 1; 1152 } 1153 1154 /* 1155 * if we're still looking, are inside, and have an outside domain, 1156 * try it on our outside interface, if any. 1157 */ 1158 if (rv == 0 && cfg.inside && !inname) { 1159 if (triedin) 1160 dnslog( 1161 "[%d] netquery: internal nameservers failed for %s; trying external", 1162 getpid(), dp->name); 1163 1164 /* prepare server RR's for incremental lookup */ 1165 for(rp = nsrp; rp; rp = rp->next) 1166 rp->marker = 0; 1167 1168 rv = udpquery("/net.alt", dp, type, nsrp, reqp, depth, Patient, 1169 Outns); 1170 } 1171 if (0 && rv == 0) /* could ask /net.alt/dns directly */ 1172 askoutdns(dp, type); 1173 1174 if(lock) 1175 qunlock(&dp->querylck); 1176 1177 return rv; 1178 } 1179 1180 int 1181 seerootns(void) 1182 { 1183 char root[] = ""; 1184 Request req; 1185 1186 memset(&req, 0, sizeof req); 1187 req.isslave = 1; 1188 req.aborttime = now + Maxreqtm*2; /* be patient */ 1189 return netquery(dnlookup(root, Cin, 1), Tns, 1190 dblookup(root, Cin, Tns, 0, 0), &req, 0); 1191 } 1192