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 int 320 mkreq(DN *dp, int type, uchar *buf, int flags, ushort reqno) 321 { 322 DNSmsg m; 323 int len; 324 OUdphdr *uh = (OUdphdr*)buf; 325 326 /* stuff port number into output buffer */ 327 memset(uh, 0, sizeof(*uh)); 328 hnputs(uh->rport, 53); 329 330 /* make request and convert it to output format */ 331 memset(&m, 0, sizeof(m)); 332 m.flags = flags; 333 m.id = reqno; 334 m.qd = rralloc(type); 335 m.qd->owner = dp; 336 m.qd->type = type; 337 len = convDNS2M(&m, &buf[OUdphdrsize], Maxudp); 338 if(len < 0) 339 abort(); /* "can't convert" */ 340 rrfree(m.qd); 341 return len; 342 } 343 344 /* for alarms in readreply */ 345 static void 346 ding(void *x, char *msg) 347 { 348 USED(x); 349 if(strcmp(msg, "alarm") == 0) 350 noted(NCONT); 351 else 352 noted(NDFLT); 353 } 354 355 static void 356 freeanswers(DNSmsg *mp) 357 { 358 rrfreelist(mp->qd); 359 rrfreelist(mp->an); 360 rrfreelist(mp->ns); 361 rrfreelist(mp->ar); 362 mp->qd = mp->an = mp->ns = mp->ar = nil; 363 } 364 365 /* 366 * read replies to a request. ignore any of the wrong type. 367 * wait at most until endtime. 368 */ 369 static int 370 readreply(int fd, DN *dp, int type, ushort req, uchar *ibuf, DNSmsg *mp, 371 ulong endtime, Request *reqp) 372 { 373 char *err; 374 int len; 375 ulong now; 376 RR *rp; 377 378 notify(ding); 379 380 for(; ; freeanswers(mp)){ 381 now = time(nil); 382 if(now >= endtime) 383 return -1; /* timed out */ 384 385 /* timed read */ 386 alarm((endtime - now) * 1000); 387 len = read(fd, ibuf, OUdphdrsize+Maxudpin); 388 alarm(0); 389 len -= OUdphdrsize; 390 if(len < 0) 391 return -1; /* timed out */ 392 393 /* convert into internal format */ 394 memset(mp, 0, sizeof(*mp)); 395 err = convM2DNS(&ibuf[OUdphdrsize], len, mp, nil); 396 if(err){ 397 dnslog("input err: %s: %I", err, ibuf); 398 continue; 399 } 400 if(debug) 401 logreply(reqp->id, ibuf, mp); 402 403 /* answering the right question? */ 404 if(mp->id != req){ 405 dnslog("%d: id %d instead of %d: %I", reqp->id, 406 mp->id, req, ibuf); 407 continue; 408 } 409 if(mp->qd == 0){ 410 dnslog("%d: no question RR: %I", reqp->id, ibuf); 411 continue; 412 } 413 if(mp->qd->owner != dp){ 414 dnslog("%d: owner %s instead of %s: %I", 415 reqp->id, mp->qd->owner->name, dp->name, ibuf); 416 continue; 417 } 418 if(mp->qd->type != type){ 419 dnslog("%d: type %d instead of %d: %I", 420 reqp->id, mp->qd->type, type, ibuf); 421 continue; 422 } 423 424 /* remember what request this is in answer to */ 425 for(rp = mp->an; rp; rp = rp->next) 426 rp->query = type; 427 428 return 0; 429 } 430 } 431 432 /* 433 * return non-0 if first list includes second list 434 */ 435 int 436 contains(RR *rp1, RR *rp2) 437 { 438 RR *trp1, *trp2; 439 440 for(trp2 = rp2; trp2; trp2 = trp2->next){ 441 for(trp1 = rp1; trp1; trp1 = trp1->next){ 442 if(trp1->type == trp2->type) 443 if(trp1->host == trp2->host) 444 if(trp1->owner == trp2->owner) 445 break; 446 } 447 if(trp1 == nil) 448 return 0; 449 } 450 return 1; 451 } 452 453 454 typedef struct Dest Dest; 455 struct Dest 456 { 457 uchar a[IPaddrlen]; /* ip address */ 458 DN *s; /* name server */ 459 int nx; /* number of transmissions */ 460 int code; /* response code; used to clear dp->respcode */ 461 }; 462 463 464 /* 465 * return multicast version if any 466 */ 467 int 468 ipisbm(uchar *ip) 469 { 470 if(isv4(ip)){ 471 if (ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0 || 472 ipcmp(ip, IPv4bcast) == 0) 473 return 4; 474 } else 475 if(ip[0] == 0xff) 476 return 6; 477 return 0; 478 } 479 480 /* 481 * Get next server address 482 */ 483 static int 484 serveraddrs(DN *dp, RR *nsrp, Dest *dest, int nd, int depth, Request *reqp) 485 { 486 RR *rp, *arp, *trp; 487 Dest *cur; 488 489 if(nd >= Maxdest) 490 return 0; 491 492 /* 493 * look for a server whose address we already know. 494 * if we find one, mark it so we ignore this on 495 * subsequent passes. 496 */ 497 arp = 0; 498 for(rp = nsrp; rp; rp = rp->next){ 499 assert(rp->magic == RRmagic); 500 if(rp->marker) 501 continue; 502 arp = rrlookup(rp->host, Ta, NOneg); 503 if(arp){ 504 rp->marker = 1; 505 break; 506 } 507 arp = dblookup(rp->host->name, Cin, Ta, 0, 0); 508 if(arp){ 509 rp->marker = 1; 510 break; 511 } 512 } 513 514 /* 515 * if the cache and database lookup didn't find any new 516 * server addresses, try resolving one via the network. 517 * Mark any we try to resolve so we don't try a second time. 518 */ 519 if(arp == 0) 520 for(rp = nsrp; rp; rp = rp->next){ 521 if(rp->marker) 522 continue; 523 rp->marker = 1; 524 525 /* 526 * avoid loops looking up a server under itself 527 */ 528 if(subsume(rp->owner->name, rp->host->name)) 529 continue; 530 531 arp = dnresolve(rp->host->name, Cin, Ta, reqp, 0, 532 depth+1, Recurse, 1, 0); 533 rrfreelist(rrremneg(&arp)); 534 if(arp) 535 break; 536 } 537 538 /* use any addresses that we found */ 539 for(trp = arp; trp; trp = trp->next){ 540 if(nd >= Maxdest) 541 break; 542 cur = &dest[nd]; 543 parseip(cur->a, trp->ip->name); 544 /* 545 * straddling servers can reject all nameservers if they are all 546 * inside, so be sure to list at least one outside ns at 547 * the end of the ns list in /lib/ndb for `dom='. 548 */ 549 if (ipisbm(cur->a) || 550 cfg.straddle && !insideaddr(dp->name) && insidens(cur->a)) 551 continue; 552 cur->nx = 0; 553 cur->s = trp->owner; 554 cur->code = Rtimeout; 555 nd++; 556 } 557 rrfreelist(arp); 558 return nd; 559 } 560 561 /* 562 * cache negative responses 563 */ 564 static void 565 cacheneg(DN *dp, int type, int rcode, RR *soarr) 566 { 567 RR *rp; 568 DN *soaowner; 569 ulong ttl; 570 571 /* no cache time specified, don't make anything up */ 572 if(soarr != nil){ 573 if(soarr->next != nil){ 574 rrfreelist(soarr->next); 575 soarr->next = nil; 576 } 577 soaowner = soarr->owner; 578 } else 579 soaowner = nil; 580 581 /* the attach can cause soarr to be freed so mine it now */ 582 if(soarr != nil && soarr->soa != nil) 583 ttl = soarr->soa->minttl+now; 584 else 585 ttl = 5*Min; 586 587 /* add soa and negative RR to the database */ 588 rrattach(soarr, 1); 589 590 rp = rralloc(type); 591 rp->owner = dp; 592 rp->negative = 1; 593 rp->negsoaowner = soaowner; 594 rp->negrcode = rcode; 595 rp->ttl = ttl; 596 rrattach(rp, 1); 597 } 598 599 static int 600 setdestoutns(Dest *p, int n) 601 { 602 uchar *outns = outsidens(n); 603 604 memset(p, 0, sizeof *p); 605 if (outns == nil) { 606 if (n == 0) 607 dnslog("[%d] no outside-ns in ndb", getpid()); 608 return -1; 609 } 610 memmove(p->a, outns, sizeof p->a); 611 p->s = dnlookup("outside-ns-ips", Cin, 1); 612 return 0; 613 } 614 615 /* 616 * query name servers. If the name server returns a pointer to another 617 * name server, recurse. 618 */ 619 static int 620 netquery1(int fd, DN *dp, int type, RR *nsrp, Request *reqp, int depth, 621 uchar *ibuf, uchar *obuf, int waitsecs, int inns) 622 { 623 int ndest, j, len, replywaits, rv, n; 624 ushort req; 625 ulong endtime; 626 char buf[12]; 627 DN *ndp; 628 DNSmsg m; 629 Dest *p, *l, *np; 630 Dest dest[Maxdest]; 631 RR *tp, *soarr; 632 // char fdbuf[1024]; 633 634 // fd2path(fd, fdbuf, sizeof fdbuf); 635 // dnslog("netquery: on %s for %s %s ns", fdbuf, dp->name, 636 // (inns? "inside": "outside")); 637 638 /* pack request into a message */ 639 req = rand(); 640 len = mkreq(dp, type, obuf, Frecurse|Oquery, req); 641 642 /* no server addresses yet */ 643 l = dest; 644 645 /* 646 * transmit requests and wait for answers. 647 * at most Maxtrans attempts to each address. 648 * each cycle send one more message than the previous. 649 */ 650 for(ndest = 1; ndest < Maxdest; ndest++){ 651 // dnslog("netquery1 xmit loop: now %ld aborttime %ld", time(nil), 652 // reqp->aborttime); 653 if(time(nil) >= reqp->aborttime) 654 break; 655 656 /* get a server address if we need one */ 657 p = dest; 658 if(ndest > l - p){ 659 j = serveraddrs(dp, nsrp, dest, l - p, depth, reqp); 660 l = &dest[j]; 661 } 662 663 /* no servers, punt */ 664 if(l == dest) 665 if (cfg.straddle && cfg.inside) { 666 p = l = dest; 667 for(n = 0; n < Maxdest; n++, l++) 668 if (setdestoutns(l, n) < 0) 669 break; 670 } else { 671 // dnslog("netquery1: %s: no servers", dp->name); 672 break; 673 } 674 675 /* send to first 'ndest' destinations */ 676 j = 0; 677 for(; p < &dest[ndest] && p < l; p++){ 678 /* skip destinations we've finished with */ 679 if(p->nx >= Maxtrans) 680 continue; 681 682 j++; 683 684 /* exponential backoff of requests */ 685 if((1<<p->nx) > ndest) 686 continue; 687 688 memmove(obuf, p->a, sizeof p->a); 689 procsetname("req slave: %sside query to %I/%s %s %s", 690 (inns? "in": "out"), obuf, p->s->name, dp->name, 691 rrname(type, buf, sizeof buf)); 692 if(debug) 693 logsend(reqp->id, depth, obuf, p->s->name, 694 dp->name, type); 695 696 /* actually send the UDP packet */ 697 if(write(fd, obuf, len + OUdphdrsize) < 0) 698 warning("sending udp msg %r"); 699 p->nx++; 700 } 701 if(j == 0) 702 break; /* no destinations left */ 703 704 endtime = time(nil) + waitsecs; 705 if(endtime > reqp->aborttime) 706 endtime = reqp->aborttime; 707 708 // dnslog( 709 // "netquery1 reply wait: now %ld aborttime %ld endtime %ld", 710 // time(nil), reqp->aborttime, endtime); 711 for(replywaits = 0; replywaits < ndest; replywaits++){ 712 procsetname( 713 "req slave: reading %sside reply from %I for %s %s", 714 (inns? "in": "out"), obuf, dp->name, 715 rrname(type, buf, sizeof buf)); 716 memset(&m, 0, sizeof m); 717 if(readreply(fd, dp, type, req, ibuf, &m, endtime, reqp) 718 < 0) 719 break; /* timed out */ 720 721 // dnslog("netquery1 got reply from %I", ibuf); 722 /* find responder */ 723 for(p = dest; p < l; p++) 724 if(memcmp(p->a, ibuf, sizeof p->a) == 0) 725 break; 726 727 /* remove all addrs of responding server from list */ 728 for(np = dest; np < l; np++) 729 if(np->s == p->s) 730 p->nx = Maxtrans; 731 732 /* ignore any error replies */ 733 if((m.flags & Rmask) == Rserver){ 734 // dnslog( 735 // "netquery1 got Rserver for dest %s of name %s", 736 // p->s->name, dp->name); 737 rrfreelist(m.qd); 738 rrfreelist(m.an); 739 rrfreelist(m.ar); 740 rrfreelist(m.ns); 741 if(p != l) { 742 // dnslog( 743 // "netquery1 setting Rserver for dest %s of name %s due to Rserver reply", 744 // p->s->name, dp->name); 745 p->code = Rserver; 746 } 747 continue; 748 } 749 750 /* ignore any bad delegations */ 751 if(m.ns && baddelegation(m.ns, nsrp, ibuf)){ 752 // dnslog("netquery1 got a bad delegation from %s", 753 // p->s->name); 754 rrfreelist(m.ns); 755 m.ns = nil; 756 if(m.an == nil){ 757 rrfreelist(m.qd); 758 rrfreelist(m.ar); 759 if(p != l) { 760 // dnslog( 761 //"netquery1 setting Rserver for dest %s of name %s due to bad delegation", 762 // p->s->name, dp->name); 763 p->code = Rserver; 764 } 765 continue; 766 } 767 } 768 769 /* remove any soa's from the authority section */ 770 soarr = rrremtype(&m.ns, Tsoa); 771 772 /* incorporate answers */ 773 if(m.an) 774 rrattach(m.an, (m.flags & Fauth) != 0); 775 if(m.ar) 776 rrattach(m.ar, 0); 777 if(m.ns){ 778 ndp = m.ns->owner; 779 rrattach(m.ns, 0); 780 } else 781 ndp = nil; 782 783 /* free the question */ 784 if(m.qd) 785 rrfreelist(m.qd); 786 787 /* 788 * Any reply from an authoritative server, 789 * or a positive reply terminates the search 790 */ 791 if(m.an != nil || (m.flags & Fauth)){ 792 if(m.an == nil && (m.flags & Rmask) == Rname) 793 dp->respcode = Rname; 794 else 795 dp->respcode = 0; 796 797 /* 798 * cache any negative responses, free soarr 799 */ 800 if((m.flags & Fauth) && m.an == nil) 801 cacheneg(dp, type, (m.flags & Rmask), 802 soarr); 803 else 804 rrfreelist(soarr); 805 return 1; 806 } 807 rrfreelist(soarr); 808 809 /* 810 * if we've been given better name servers, 811 * recurse. we're called from udpquery, called from 812 * netquery, which current holds dp->querylck, 813 * so release it now and acquire it upon return. 814 */ 815 if(m.ns){ 816 tp = rrlookup(ndp, Tns, NOneg); 817 if(!contains(nsrp, tp)){ 818 procsetname( 819 "req slave: recursive query for %s %s", 820 dp->name, 821 rrname(type, buf, sizeof buf)); 822 qunlock(&dp->querylck); 823 824 rv = netquery(dp, type, tp, reqp, 825 depth+1); 826 827 qlock(&dp->querylck); 828 rrfreelist(tp); 829 return rv; 830 } else 831 rrfreelist(tp); 832 } 833 } 834 } 835 836 /* if all servers returned failure, propagate it */ 837 dp->respcode = Rserver; 838 for(p = dest; p < l; p++) 839 if(p->code != Rserver) 840 dp->respcode = 0; 841 842 // if (dp->respcode) 843 // dnslog("netquery1 setting Rserver for %s", dp->name); 844 845 return 0; 846 } 847 848 /* 849 * run a command with a supplied fd as standard input 850 */ 851 char * 852 system(int fd, char *cmd) 853 { 854 int pid, p, i; 855 static Waitmsg msg; 856 857 if((pid = fork()) == -1) 858 sysfatal("fork failed: %r"); 859 else if(pid == 0){ 860 dup(fd, 0); 861 close(fd); 862 for (i = 3; i < 200; i++) 863 close(i); /* don't leak fds */ 864 execl("/bin/rc", "rc", "-c", cmd, nil); 865 sysfatal("exec rc: %r"); 866 } 867 for(p = waitpid(); p >= 0; p = waitpid()) 868 if(p == pid) 869 return msg.msg; 870 return "lost child"; 871 } 872 873 enum { Hurry, Patient, }; 874 enum { Outns, Inns, }; 875 enum { Remntretry = 15, }; /* min. sec.s between remount attempts */ 876 877 static int 878 udpquery(char *mntpt, DN *dp, int type, RR *nsrp, Request *reqp, int depth, 879 int patient, int inns) 880 { 881 int fd, rv = 0; 882 long now; 883 char *msg; 884 uchar *obuf, *ibuf; 885 static QLock mntlck; 886 static ulong lastmount; 887 888 /* use alloced buffers rather than ones from the stack */ 889 ibuf = emalloc(Maxudpin+OUdphdrsize); 890 obuf = emalloc(Maxudp+OUdphdrsize); 891 892 fd = udpport(mntpt); 893 while (fd < 0 && cfg.straddle && strcmp(mntpt, "/net.alt") == 0) { 894 /* HACK: remount /net.alt */ 895 now = time(nil); 896 if (now < lastmount + Remntretry) 897 sleep((lastmount + Remntretry - now)*1000); 898 qlock(&mntlck); 899 fd = udpport(mntpt); /* try again under lock */ 900 if (fd < 0) { 901 dnslog("[%d] remounting /net.alt", getpid()); 902 unmount(nil, "/net.alt"); 903 904 msg = system(open("/dev/null", ORDWR), "outside"); 905 906 lastmount = time(nil); 907 if (msg && *msg) { 908 dnslog("[%d] can't remount /net.alt: %s", 909 getpid(), msg); 910 sleep(10*1000); /* don't spin wildly */ 911 } else 912 fd = udpport(mntpt); 913 } 914 qunlock(&mntlck); 915 } 916 if(fd >= 0) { 917 reqp->aborttime = time(nil) + (patient? Maxreqtm: Maxreqtm/2); 918 // dnslog("udpquery: %s/udp for %s with %s ns", mntpt, dp->name, 919 // (inns? "inside": "outside")); 920 rv = netquery1(fd, dp, type, nsrp, reqp, depth, 921 ibuf, obuf, (patient? 15: 10), inns); 922 close(fd); 923 } else 924 dnslog("can't get udpport for %s query of name %s: %r", 925 mntpt, dp->name); 926 927 free(obuf); 928 free(ibuf); 929 return rv; 930 } 931 932 static int 933 dnssetup(int domount, char *dns, char *srv, char *mtpt) 934 { 935 int fd; 936 937 fd = open(dns, ORDWR); 938 if(fd < 0){ 939 if(domount == 0){ 940 werrstr("can't open %s: %r", mtpt); 941 return -1; 942 } 943 fd = open(srv, ORDWR); 944 if(fd < 0){ 945 werrstr("can't open %s: %r", srv); 946 return -1; 947 } 948 if(mount(fd, -1, mtpt, MBEFORE, "") < 0){ 949 werrstr("can't mount(%s, %s): %r", srv, mtpt); 950 return -1; 951 } 952 fd = open(mtpt, ORDWR); 953 if(fd < 0) 954 werrstr("can't open %s: %r", mtpt); 955 } 956 return fd; 957 } 958 959 static RR * 960 rrparse(char *lines) 961 { 962 int nl, nf, ln, type; 963 char *line[100]; 964 char *field[32]; 965 RR *rp, *rplist; 966 // Server *s; 967 SOA *soa; 968 Srv *srv; 969 // Txt *t; 970 971 rplist = nil; 972 nl = tokenize(lines, line, nelem(line)); 973 for (ln = 0; ln < nl; ln++) { 974 if (*line[ln] == '!' || *line[ln] == '?') 975 continue; /* error */ 976 nf = tokenize(line[ln], field, nelem(field)); 977 if (nf < 2) 978 continue; /* mal-formed */ 979 type = rrtype(field[1]); 980 rp = rralloc(type); 981 rp->owner = dnlookup(field[0], Cin, 1); 982 rp->next = rplist; 983 rplist = rp; 984 switch (type) { /* TODO: copy fields to *rp */ 985 case Thinfo: 986 // "\t%s %s", dnname(rp->cpu), dnname(rp->os)); 987 break; 988 case Tcname: 989 case Tmb: 990 case Tmd: 991 case Tmf: 992 case Tns: 993 // "\t%s", dnname(rp->host)); 994 break; 995 case Tmg: 996 case Tmr: 997 // "\t%s", dnname(rp->mb)); 998 break; 999 case Tminfo: 1000 // "\t%s %s", dnname(rp->mb), dnname(rp->rmb)); 1001 break; 1002 case Tmx: 1003 // "\t%lud %s", rp->pref, dnname(rp->host)); 1004 break; 1005 case Ta: 1006 case Taaaa: 1007 // "\t%s", dnname(rp->ip)); // TODO parseip 1008 break; 1009 case Tptr: 1010 // "\t%s", dnname(rp->ptr)); 1011 break; 1012 case Tsoa: 1013 soa = rp->soa; 1014 USED(soa); 1015 // "\t%s %s %lud %lud %lud %lud %lud", 1016 // dnname(rp->host), dnname(rp->rmb), 1017 // (soa? soa->serial: 0), 1018 // (soa? soa->refresh: 0), (soa? soa->retry: 0), 1019 // (soa? soa->expire: 0), (soa? soa->minttl: 0)); 1020 break; 1021 case Tsrv: 1022 srv = rp->srv; 1023 USED(srv); 1024 break; 1025 case Tnull: 1026 // "\t%.*H", rp->null->dlen, rp->null->data); 1027 break; 1028 case Ttxt: 1029 // for(t = rp->txt; t != nil; t = t->next) 1030 // "%s", t->p); 1031 break; 1032 case Trp: 1033 // "\t%s %s", dnname(rp->rmb), dnname(rp->rp)); 1034 break; 1035 case Tkey: 1036 // "\t%d %d %d", rp->key->flags, rp->key->proto, rp->key->alg); 1037 break; 1038 case Tsig: 1039 // "\t%d %d %d %lud %lud %lud %d %s", 1040 // rp->sig->type, rp->sig->alg, rp->sig->labels, 1041 // rp->sig->ttl, rp->sig->exp, rp->sig->incep, 1042 // rp->sig->tag, dnname(rp->sig->signer)); 1043 break; 1044 case Tcert: 1045 // "\t%d %d %d", rp->cert->type, rp->cert->tag, rp->cert->alg); 1046 break; 1047 } 1048 } 1049 return nil; 1050 } 1051 1052 static int 1053 querydns(int fd, char *line, int n) 1054 { 1055 int rv = 0; 1056 char buf[1024]; 1057 1058 seek(fd, 0, 0); 1059 if(write(fd, line, n) != n) 1060 return rv; 1061 1062 seek(fd, 0, 0); 1063 buf[0] = '\0'; 1064 while((n = read(fd, buf, sizeof buf - 1)) > 0) { 1065 buf[n] = 0; 1066 rrattach(rrparse(buf), 1); /* incorporate answers */ 1067 rv = 1; 1068 buf[0] = '\0'; 1069 } 1070 return rv; 1071 } 1072 1073 static void 1074 askoutdns(DN *dp, int type) /* ask /net.alt/dns directly */ 1075 { 1076 int len; 1077 char buf[32]; 1078 char *query; 1079 char *mtpt = "/net.alt"; 1080 char *dns = "/net.alt/dns"; 1081 char *srv = "/srv/dns_net.alt"; 1082 static int fd = -1; 1083 1084 if (fd < 0) 1085 fd = dnssetup(1, dns, srv, mtpt); 1086 1087 query = smprint("%s %s\n", dp->name, rrname(type, buf, sizeof buf)); 1088 len = strlen(query); 1089 if (!querydns(fd, query, len)) { 1090 close(fd); 1091 /* could run outside here */ 1092 fd = dnssetup(1, dns, srv, mtpt); 1093 querydns(fd, query, len); 1094 } 1095 free(query); 1096 } 1097 1098 /* look up (dp->name,type) via *nsrp with results in *reqp */ 1099 static int 1100 netquery(DN *dp, int type, RR *nsrp, Request *reqp, int depth) 1101 { 1102 int lock, rv, triedin, inname; 1103 RR *rp; 1104 1105 if(depth > 12) /* in a recursive loop? */ 1106 return 0; 1107 1108 slave(reqp); 1109 /* 1110 * slave might have forked. if so, the parent process longjmped to 1111 * req->mret; we're usually the child slave, but if there are too 1112 * many children already, we're still the same process. 1113 */ 1114 1115 /* don't lock before call to slave so only children can block */ 1116 lock = reqp->isslave != 0; 1117 if(lock) { 1118 procsetname("waiting for query lock on %s", dp->name); 1119 /* don't make concurrent queries for this name */ 1120 qlock(&dp->querylck); 1121 procsetname("netquery: %s", dp->name); 1122 } 1123 1124 /* prepare server RR's for incremental lookup */ 1125 for(rp = nsrp; rp; rp = rp->next) 1126 rp->marker = 0; 1127 1128 rv = 0; /* pessimism */ 1129 triedin = 0; 1130 /* 1131 * normal resolvers and servers will just use mntpt for all addresses, 1132 * even on the outside. straddling servers will use mntpt (/net) 1133 * for inside addresses and /net.alt for outside addresses, 1134 * thus bypassing other inside nameservers. 1135 */ 1136 inname = insideaddr(dp->name); 1137 if (!cfg.straddle || inname) { 1138 rv = udpquery(mntpt, dp, type, nsrp, reqp, depth, Hurry, 1139 (cfg.inside? Inns: Outns)); 1140 triedin = 1; 1141 } 1142 1143 /* 1144 * if we're still looking, are inside, and have an outside domain, 1145 * try it on our outside interface, if any. 1146 */ 1147 if (rv == 0 && cfg.inside && !inname) { 1148 if (triedin) 1149 dnslog( 1150 "[%d] netquery: internal nameservers failed for %s; trying external", 1151 getpid(), dp->name); 1152 1153 /* prepare server RR's for incremental lookup */ 1154 for(rp = nsrp; rp; rp = rp->next) 1155 rp->marker = 0; 1156 1157 rv = udpquery("/net.alt", dp, type, nsrp, reqp, depth, Patient, 1158 Outns); 1159 } 1160 if (0 && rv == 0) /* TODO: ask /net.alt/dns directly */ 1161 askoutdns(dp, type); 1162 1163 if(lock) 1164 qunlock(&dp->querylck); 1165 1166 return rv; 1167 } 1168 1169 int 1170 seerootns(void) 1171 { 1172 char root[] = ""; 1173 Request req; 1174 1175 memset(&req, 0, sizeof req); 1176 req.isslave = 1; 1177 req.aborttime = now + Maxreqtm*2; /* be patient */ 1178 return netquery(dnlookup(root, Cin, 1), Tns, 1179 dblookup(root, Cin, Tns, 0, 0), &req, 0); 1180 } 1181