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 char *LOG = "dns"; 18 19 /* 20 * reading /proc/pid/args yields either "name" or "name [display args]", 21 * so return only display args, if any. 22 */ 23 static char * 24 procgetname(void) 25 { 26 int fd, n; 27 char *lp, *rp; 28 char buf[256]; 29 30 snprint(buf, sizeof buf, "#p/%d/args", getpid()); 31 if((fd = open(buf, OREAD)) < 0) 32 return strdup(""); 33 *buf = '\0'; 34 n = read(fd, buf, sizeof buf-1); 35 close(fd); 36 if (n >= 0) 37 buf[n] = '\0'; 38 if ((lp = strchr(buf, '[')) == nil || 39 (rp = strrchr(buf, ']')) == nil) 40 return strdup(""); 41 *rp = '\0'; 42 return strdup(lp+1); 43 } 44 45 /* 46 * lookup 'type' info for domain name 'name'. If it doesn't exist, try 47 * looking it up as a canonical name. 48 */ 49 RR* 50 dnresolve(char *name, int class, int type, Request *req, RR **cn, int depth, 51 int recurse, int rooted, int *status) 52 { 53 RR *rp, *nrp, *drp; 54 DN *dp; 55 int loops; 56 char *procname; 57 char nname[Domlen]; 58 59 if(status) 60 *status = 0; 61 62 procname = procgetname(); 63 /* 64 * hack for systems that don't have resolve search 65 * lists. Just look up the simple name in the database. 66 */ 67 if(!rooted && strchr(name, '.') == 0){ 68 rp = nil; 69 drp = domainlist(class); 70 for(nrp = drp; nrp != nil; nrp = nrp->next){ 71 snprint(nname, sizeof nname, "%s.%s", name, 72 nrp->ptr->name); 73 rp = dnresolve(nname, class, type, req, cn, depth, 74 recurse, rooted, status); 75 rrfreelist(rrremneg(&rp)); 76 if(rp != nil) 77 break; 78 } 79 if(drp != nil) 80 rrfree(drp); 81 procsetname(procname); 82 free(procname); 83 return rp; 84 } 85 86 /* 87 * try the name directly 88 */ 89 rp = dnresolve1(name, class, type, req, depth, recurse); 90 if(rp) { 91 procsetname(procname); 92 free(procname); 93 return randomize(rp); 94 } 95 96 /* try it as a canonical name if we weren't told the name didn't exist */ 97 dp = dnlookup(name, class, 0); 98 if(type != Tptr && dp->nonexistent != Rname) 99 for(loops=0; rp == nil && loops < 32; loops++){ 100 rp = dnresolve1(name, class, Tcname, req, depth, recurse); 101 if(rp == nil) 102 break; 103 104 if(rp->negative){ 105 rrfreelist(rp); 106 rp = nil; 107 break; 108 } 109 110 name = rp->host->name; 111 if(cn) 112 rrcat(cn, rp); 113 else 114 rrfreelist(rp); 115 116 rp = dnresolve1(name, class, type, req, depth, recurse); 117 } 118 119 /* distinction between not found and not good */ 120 if(rp == nil && status != nil && dp->nonexistent != 0) 121 *status = dp->nonexistent; 122 123 procsetname(procname); 124 free(procname); 125 return randomize(rp); 126 } 127 128 static RR* 129 dnresolve1(char *name, int class, int type, Request *req, int depth, 130 int recurse) 131 { 132 DN *dp, *nsdp; 133 RR *rp, *nsrp, *dbnsrp; 134 char *cp; 135 136 if(debug) 137 syslog(0, LOG, "[%d] dnresolve1 %s %d %d", 138 getpid(), name, type, class); 139 140 /* only class Cin implemented so far */ 141 if(class != Cin) 142 return nil; 143 144 dp = dnlookup(name, class, 1); 145 146 /* 147 * Try the cache first 148 */ 149 rp = rrlookup(dp, type, OKneg); 150 if(rp) 151 if(rp->db){ 152 /* unauthenticated db entries are hints */ 153 if(rp->auth) 154 return rp; 155 } else 156 /* cached entry must still be valid */ 157 if(rp->ttl > now) 158 /* but Tall entries are special */ 159 if(type != Tall || rp->query == Tall) 160 return rp; 161 162 rrfreelist(rp); 163 164 /* 165 * try the cache for a canonical name. if found punt 166 * since we'll find it during the canonical name search 167 * in dnresolve(). 168 */ 169 if(type != Tcname){ 170 rp = rrlookup(dp, Tcname, NOneg); 171 rrfreelist(rp); 172 if(rp) 173 return nil; 174 } 175 176 /* 177 * if we're running as just a resolver, go to our 178 * designated name servers 179 */ 180 if(resolver){ 181 nsrp = randomize(getdnsservers(class)); 182 if(nsrp != nil) { 183 if(netquery(dp, type, nsrp, req, depth+1)){ 184 rrfreelist(nsrp); 185 return rrlookup(dp, type, OKneg); 186 } 187 rrfreelist(nsrp); 188 } 189 } 190 191 /* 192 * walk up the domain name looking for 193 * a name server for the domain. 194 */ 195 for(cp = name; cp; cp = walkup(cp)){ 196 /* 197 * if this is a local (served by us) domain, 198 * return answer 199 */ 200 dbnsrp = randomize(dblookup(cp, class, Tns, 0, 0)); 201 if(dbnsrp && dbnsrp->local){ 202 rp = dblookup(name, class, type, 1, dbnsrp->ttl); 203 rrfreelist(dbnsrp); 204 return rp; 205 } 206 207 /* 208 * if recursion isn't set, just accept local 209 * entries 210 */ 211 if(recurse == Dontrecurse){ 212 if(dbnsrp) 213 rrfreelist(dbnsrp); 214 continue; 215 } 216 217 /* look for ns in cache */ 218 nsdp = dnlookup(cp, class, 0); 219 nsrp = nil; 220 if(nsdp) 221 nsrp = randomize(rrlookup(nsdp, Tns, NOneg)); 222 223 /* if the entry timed out, ignore it */ 224 if(nsrp && nsrp->ttl < now){ 225 rrfreelist(nsrp); 226 nsrp = nil; 227 } 228 229 if(nsrp){ 230 rrfreelist(dbnsrp); 231 232 /* try the name servers found in cache */ 233 if(netquery(dp, type, nsrp, req, depth+1)){ 234 rrfreelist(nsrp); 235 return rrlookup(dp, type, OKneg); 236 } 237 rrfreelist(nsrp); 238 continue; 239 } 240 241 /* use ns from db */ 242 if(dbnsrp){ 243 /* try the name servers found in db */ 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 5 seconds. 368 */ 369 static int 370 readreply(int fd, DN *dp, int type, ushort req, 371 uchar *ibuf, DNSmsg *mp, 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(0); 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 syslog(0, LOG, "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 syslog(0, LOG, "%d: id %d instead of %d: %I", reqp->id, 406 mp->id, req, ibuf); 407 continue; 408 } 409 if(mp->qd == 0){ 410 syslog(0, LOG, "%d: no question RR: %I", reqp->id, ibuf); 411 continue; 412 } 413 if(mp->qd->owner != dp){ 414 syslog(0, LOG, "%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 syslog(0, LOG, "%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; 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 static Ndbtuple *indoms, *innmsrvs, *outnmsrvs; 481 static QLock readlock; 482 483 /* 484 * is this domain (or DOMAIN or Domain or dOMAIN) 485 * internal to our organisation (behind our firewall)? 486 */ 487 static int 488 insideaddr(char *dom) 489 { 490 int domlen, vallen; 491 Ndb *db; 492 Ndbs s; 493 Ndbtuple *t; 494 495 if (0 && indoms == nil) { /* not ready for prime time */ 496 db = ndbopen("/lib/ndb/local"); 497 if (db != nil) { 498 qlock(&readlock); 499 if (indoms == nil) { /* retest under lock */ 500 free(ndbgetvalue(db, &s, "sys", "inside-dom", 501 "dom", &indoms)); 502 free(ndbgetvalue(db, &s, "sys", "inside-ns", 503 "ip", &innmsrvs)); 504 free(ndbgetvalue(db, &s, "sys", "outside-ns", 505 "ip", &outnmsrvs)); 506 } 507 qunlock(&readlock); 508 ndbclose(db); /* destroys *indoms, *innmsrvs? */ 509 } 510 } 511 if (indoms == nil) 512 return 1; /* no "inside" sys, try inside nameservers */ 513 514 domlen = strlen(dom); 515 for (t = indoms; t != nil; t = t->entry) { 516 if (strcmp(t->attr, "dom") != 0) 517 continue; 518 vallen = strlen(t->val); 519 if (cistrcmp(dom, t->val) == 0 || 520 domlen > vallen && 521 cistrcmp(dom + domlen - vallen, t->val) == 0 && 522 dom[domlen - vallen - 1] == '.') 523 return 1; 524 } 525 return 0; 526 } 527 528 static int 529 insidens(uchar *ip) 530 { 531 uchar ipa[IPaddrlen]; 532 Ndbtuple *t; 533 534 for (t = innmsrvs; t != nil; t = t->entry) 535 if (strcmp(t->attr, "ip") == 0) { 536 parseip(ipa, t->val); 537 if (memcmp(ipa, ip, sizeof ipa) == 0) 538 return 1; 539 } 540 return 0; 541 } 542 543 static uchar * 544 outsidens(void) 545 { 546 Ndbtuple *t; 547 static uchar ipa[IPaddrlen]; 548 549 for (t = outnmsrvs; t != nil; t = t->entry) 550 if (strcmp(t->attr, "ip") == 0) { 551 parseip(ipa, t->val); 552 return ipa; 553 } 554 return nil; 555 } 556 557 /* 558 * Get next server address 559 */ 560 static int 561 serveraddrs(DN *dp, RR *nsrp, Dest *dest, int nd, int depth, Request *reqp) 562 { 563 RR *rp, *arp, *trp; 564 Dest *cur; 565 566 if(nd >= Maxdest) 567 return 0; 568 569 /* 570 * look for a server whose address we already know. 571 * if we find one, mark it so we ignore this on 572 * subsequent passes. 573 */ 574 arp = 0; 575 for(rp = nsrp; rp; rp = rp->next){ 576 assert(rp->magic == RRmagic); 577 if(rp->marker) 578 continue; 579 arp = rrlookup(rp->host, Ta, NOneg); 580 if(arp){ 581 rp->marker = 1; 582 break; 583 } 584 arp = dblookup(rp->host->name, Cin, Ta, 0, 0); 585 if(arp){ 586 rp->marker = 1; 587 break; 588 } 589 } 590 591 /* 592 * if the cache and database lookup didn't find any new 593 * server addresses, try resolving one via the network. 594 * Mark any we try to resolve so we don't try a second time. 595 */ 596 if(arp == 0) 597 for(rp = nsrp; rp; rp = rp->next){ 598 if(rp->marker) 599 continue; 600 rp->marker = 1; 601 602 /* 603 * avoid loops looking up a server under itself 604 */ 605 if(subsume(rp->owner->name, rp->host->name)) 606 continue; 607 608 arp = dnresolve(rp->host->name, Cin, Ta, reqp, 0, 609 depth+1, Recurse, 1, 0); 610 rrfreelist(rrremneg(&arp)); 611 if(arp) 612 break; 613 } 614 615 /* use any addresses that we found */ 616 for(trp = arp; trp; trp = trp->next){ 617 if(nd >= Maxdest) 618 break; 619 cur = &dest[nd]; 620 parseip(cur->a, trp->ip->name); 621 if (ipisbm(cur->a) || 622 !insideaddr(dp->name) && insidens(cur->a)) 623 continue; 624 cur->nx = 0; 625 cur->s = trp->owner; 626 cur->code = Rtimeout; 627 nd++; 628 } 629 rrfreelist(arp); 630 return nd; 631 } 632 633 /* 634 * cache negative responses 635 */ 636 static void 637 cacheneg(DN *dp, int type, int rcode, RR *soarr) 638 { 639 RR *rp; 640 DN *soaowner; 641 ulong ttl; 642 643 /* no cache time specified, don't make anything up */ 644 if(soarr != nil){ 645 if(soarr->next != nil){ 646 rrfreelist(soarr->next); 647 soarr->next = nil; 648 } 649 soaowner = soarr->owner; 650 } else 651 soaowner = nil; 652 653 /* the attach can cause soarr to be freed so mine it now */ 654 if(soarr != nil && soarr->soa != nil) 655 ttl = soarr->soa->minttl+now; 656 else 657 ttl = 5*Min; 658 659 /* add soa and negative RR to the database */ 660 rrattach(soarr, 1); 661 662 rp = rralloc(type); 663 rp->owner = dp; 664 rp->negative = 1; 665 rp->negsoaowner = soaowner; 666 rp->negrcode = rcode; 667 rp->ttl = ttl; 668 rrattach(rp, 1); 669 } 670 671 /* 672 * query name servers. If the name server returns a pointer to another 673 * name server, recurse. 674 */ 675 static int 676 netquery1(int fd, DN *dp, int type, RR *nsrp, Request *reqp, int depth, 677 uchar *ibuf, uchar *obuf, int waitsecs, int inns) 678 { 679 int ndest, j, len, replywaits, rv; 680 ulong endtime; 681 ushort req; 682 char buf[12]; 683 DN *ndp; 684 DNSmsg m; 685 Dest *p, *l, *np; 686 Dest dest[Maxdest]; 687 RR *tp, *soarr; 688 689 /* pack request into a message */ 690 req = rand(); 691 len = mkreq(dp, type, obuf, Frecurse|Oquery, req); 692 693 /* no server addresses yet */ 694 l = dest; 695 696 /* 697 * transmit requests and wait for answers. 698 * at most Maxtrans attempts to each address. 699 * each cycle send one more message than the previous. 700 */ 701 for(ndest = 1; ndest < Maxdest; ndest++){ 702 p = dest; 703 704 endtime = time(0); 705 if(endtime >= reqp->aborttime) 706 break; 707 708 /* get a server address if we need one */ 709 if(ndest > l - p){ 710 j = serveraddrs(dp, nsrp, dest, l - p, depth, reqp); 711 l = &dest[j]; 712 } 713 714 /* no servers, punt */ 715 if(l == dest) 716 if (0 && inside) { /* not ready for prime time */ 717 /* HACK: use sys=outside ips */ 718 if (0 && outsidens() == nil) 719 sysfatal("no outside-ns in ndb"); 720 p = dest; 721 memmove(p->a, outsidens(), sizeof p->a); 722 p->s = dnlookup("outside", Cin, 1); 723 p->nx = p->code = 0; 724 l = p + 1; 725 } else { 726 syslog(0, LOG, "netquery1: no servers for %s", dp->name); // DEBUG 727 break; 728 } 729 730 /* send to first 'ndest' destinations */ 731 j = 0; 732 for(; p < &dest[ndest] && p < l; p++){ 733 /* skip destinations we've finished with */ 734 if(p->nx >= Maxtrans) 735 continue; 736 737 j++; 738 739 /* exponential backoff of requests */ 740 if((1<<p->nx) > ndest) 741 continue; 742 743 memmove(obuf, p->a, sizeof p->a); 744 procsetname("req slave: %sside query to %I/%s %s %s", 745 (inns? "in": "out"), obuf, p->s->name, dp->name, 746 rrname(type, buf, sizeof buf)); 747 if(debug) 748 logsend(reqp->id, depth, obuf, p->s->name, 749 dp->name, type); 750 751 /* actually send the UDP packet */ 752 if(write(fd, obuf, len + OUdphdrsize) < 0) 753 warning("sending udp msg %r"); 754 p->nx++; 755 } 756 if(j == 0) 757 break; /* no destinations left */ 758 759 endtime = time(0) + waitsecs; 760 if(endtime > reqp->aborttime) 761 endtime = reqp->aborttime; 762 763 for(replywaits = 0; replywaits < ndest; replywaits++){ 764 procsetname( 765 "req slave: reading %sside reply from %I for %s %s", 766 (inns? "in": "out"), obuf, dp->name, 767 rrname(type, buf, sizeof buf)); 768 memset(&m, 0, sizeof m); 769 if(readreply(fd, dp, type, req, ibuf, &m, endtime, reqp) < 0) 770 break; /* timed out */ 771 772 /* find responder */ 773 for(p = dest; p < l; p++) 774 if(memcmp(p->a, ibuf, sizeof(p->a)) == 0) 775 break; 776 777 /* remove all addrs of responding server from list */ 778 for(np = dest; np < l; np++) 779 if(np->s == p->s) 780 p->nx = Maxtrans; 781 782 /* ignore any error replies */ 783 if((m.flags & Rmask) == Rserver){ 784 rrfreelist(m.qd); 785 rrfreelist(m.an); 786 rrfreelist(m.ar); 787 rrfreelist(m.ns); 788 if(p != l) 789 p->code = Rserver; 790 continue; 791 } 792 793 /* ignore any bad delegations */ 794 if(m.ns && baddelegation(m.ns, nsrp, ibuf)){ 795 rrfreelist(m.ns); 796 m.ns = nil; 797 if(m.an == nil){ 798 rrfreelist(m.qd); 799 rrfreelist(m.ar); 800 if(p != l) 801 p->code = Rserver; 802 continue; 803 } 804 } 805 806 807 /* remove any soa's from the authority section */ 808 soarr = rrremtype(&m.ns, Tsoa); 809 810 /* incorporate answers */ 811 if(m.an) 812 rrattach(m.an, (m.flags & Fauth) != 0); 813 if(m.ar) 814 rrattach(m.ar, 0); 815 if(m.ns){ 816 ndp = m.ns->owner; 817 rrattach(m.ns, 0); 818 } else 819 ndp = nil; 820 821 /* free the question */ 822 if(m.qd) 823 rrfreelist(m.qd); 824 825 /* 826 * Any reply from an authoritative server, 827 * or a positive reply terminates the search 828 */ 829 if(m.an != nil || (m.flags & Fauth)){ 830 if(m.an == nil && (m.flags & Rmask) == Rname) 831 dp->nonexistent = Rname; 832 else 833 dp->nonexistent = 0; 834 835 /* 836 * cache any negative responses, free soarr 837 */ 838 if((m.flags & Fauth) && m.an == nil) 839 cacheneg(dp, type, (m.flags & Rmask), 840 soarr); 841 else 842 rrfreelist(soarr); 843 return 1; 844 } 845 rrfreelist(soarr); 846 847 /* 848 * if we've been given better name servers, 849 * recurse. we're called from udpquery, called from 850 * netquery, which current holds dp->querylck, 851 * so release it now and acquire it upon return. 852 */ 853 if(m.ns){ 854 tp = rrlookup(ndp, Tns, NOneg); 855 if(!contains(nsrp, tp)){ 856 procsetname( 857 "req slave: recursive query for %s %s", 858 dp->name, 859 rrname(type, buf, sizeof buf)); 860 qunlock(&dp->querylck); 861 rv = netquery(dp, type, tp, reqp, 862 depth + 1); 863 qlock(&dp->querylck); 864 rrfreelist(tp); 865 return rv; 866 } else 867 rrfreelist(tp); 868 } 869 } 870 } 871 872 /* if all servers returned failure, propagate it */ 873 dp->nonexistent = Rserver; 874 for(p = dest; p < l; p++) 875 if(p->code != Rserver) 876 dp->nonexistent = 0; 877 878 return 0; 879 } 880 881 enum { Hurry, Patient, }; 882 enum { Outns, Inns, }; 883 884 static int 885 udpquery(char *mntpt, DN *dp, int type, RR *nsrp, Request *reqp, int depth, 886 int patient, int inns) 887 { 888 int fd, rv = 0; 889 uchar *obuf, *ibuf; 890 891 /* use alloced buffers rather than ones from the stack */ 892 ibuf = emalloc(Maxudpin+OUdphdrsize); 893 obuf = emalloc(Maxudp+OUdphdrsize); 894 895 fd = udpport(mntpt); 896 if(fd >= 0) { 897 reqp->aborttime = time(0) + (patient? Maxreqtm: Maxreqtm/2); 898 rv = netquery1(fd, dp, type, nsrp, reqp, depth, 899 ibuf, obuf, (patient? 15: 10), inns); 900 close(fd); 901 } 902 903 free(obuf); 904 free(ibuf); 905 return rv; 906 } 907 908 /* look up (dp->name,type) via *nsrp with results in *reqp */ 909 static int 910 netquery(DN *dp, int type, RR *nsrp, Request *reqp, int depth) 911 { 912 int lock, rv, triedin; 913 RR *rp; 914 915 if(depth > 12) /* in a recursive loop? */ 916 return 0; 917 918 slave(reqp); /* might fork */ 919 /* if so, parent process longjmped to req->mret; we're child slave */ 920 if (!reqp->isslave) 921 syslog(0, LOG, 922 "[%d] netquery: slave returned with reqp->isslave==0", 923 getpid()); 924 925 /* don't lock before call to slave so only children can block */ 926 lock = reqp->isslave != 0; 927 if(lock) { 928 procsetname("waiting for query lock on %s", dp->name); 929 /* don't make concurrent queries for this name */ 930 qlock(&dp->querylck); 931 procsetname("netquery: %s", dp->name); 932 } 933 934 /* prepare server RR's for incremental lookup */ 935 for(rp = nsrp; rp; rp = rp->next) 936 rp->marker = 0; 937 938 rv = 0; /* pessimism */ 939 triedin = 0; 940 /* 941 * don't bother to query the broken inside nameservers for outside 942 * addresses. 943 */ 944 if (!inside || insideaddr(dp->name)) { 945 rv = udpquery(mntpt, dp, type, nsrp, reqp, depth, Hurry, 946 (inside? Inns: Outns)); 947 triedin = 1; 948 } 949 950 /* 951 * if we're still looking and have an outside address, 952 * try it on our outside interface, if any. 953 */ 954 if (rv == 0 && inside && !insideaddr(dp->name)) { 955 if (triedin) 956 syslog(0, LOG, 957 "[%d] netquery: internal nameservers failed for %s; trying external", 958 getpid(), dp->name); 959 960 /* prepare server RR's for incremental lookup */ 961 for(rp = nsrp; rp; rp = rp->next) 962 rp->marker = 0; 963 964 rv = udpquery("/net.alt", dp, type, nsrp, reqp, depth, Patient, 965 Outns); 966 if (rv == 0) 967 syslog(0, LOG, "[%d] netquery: no luck for %s", 968 getpid(), dp->name); 969 } 970 971 if(lock) 972 qunlock(&dp->querylck); 973 974 return rv; 975 } 976