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