1 /* 2 * domain name resolvers, see rfcs 1035 and 1123 3 */ 4 #include <u.h> 5 #include <libc.h> 6 #include <ip.h> 7 #include <bio.h> 8 #include <ndb.h> 9 #include "dns.h" 10 11 #define NS2MS(ns) ((ns) / 1000000L) 12 #define S2MS(s) ((s) * 1000) 13 #define MS2S(ms) ((ms) / 1000) 14 15 typedef struct Dest Dest; 16 typedef struct Ipaddr Ipaddr; 17 typedef struct Query Query; 18 19 enum 20 { 21 Udp, Tcp, 22 Maxdest= 24, /* maximum destinations for a request message */ 23 Maxtrans= 3, /* maximum transmissions to a server */ 24 Destmagic= 0xcafebabe, 25 Querymagic= 0xdeadbeef, 26 }; 27 enum { Hurry, Patient, }; 28 enum { Outns, Inns, }; 29 enum { Remntretry = 15, }; /* min. sec.s between remount attempts */ 30 31 struct Ipaddr { 32 Ipaddr *next; 33 uchar ip[IPaddrlen]; 34 }; 35 36 struct Dest 37 { 38 uchar a[IPaddrlen]; /* ip address */ 39 DN *s; /* name server */ 40 int nx; /* number of transmissions */ 41 int code; /* response code; used to clear dp->respcode */ 42 43 ulong magic; 44 }; 45 46 /* 47 * Query has a QLock in it, thus it can't be an automatic 48 * variable, since each process would see a separate copy 49 * of the lock on its stack. 50 */ 51 struct Query { 52 DN *dp; /* domain */ 53 ushort type; /* and type to look up */ 54 Request *req; 55 RR *nsrp; /* name servers to consult */ 56 57 /* dest must not be on the stack due to forking in slave() */ 58 Dest *dest; /* array of destinations */ 59 Dest *curdest; /* pointer to one of them */ 60 int ndest; 61 62 int udpfd; 63 64 QLock tcplock; /* only one tcp call at a time per query */ 65 int tcpset; 66 int tcpfd; /* if Tcp, read replies from here */ 67 int tcpctlfd; 68 uchar tcpip[IPaddrlen]; 69 70 ulong magic; 71 }; 72 73 /* estimated % probability of such a record existing at all */ 74 int likely[] = { 75 [Ta] 95, 76 [Taaaa] 10, 77 [Tcname] 15, 78 [Tmx] 60, 79 [Tns] 90, 80 [Tnull] 5, 81 [Tptr] 35, 82 [Tsoa] 90, 83 [Tsrv] 60, 84 [Ttxt] 15, 85 [Tall] 95, 86 }; 87 88 static RR* dnresolve1(char*, int, int, Request*, int, int); 89 static int netquery(Query *, int); 90 91 /* 92 * reading /proc/pid/args yields either "name" or "name [display args]", 93 * so return only display args, if any. 94 */ 95 static char * 96 procgetname(void) 97 { 98 int fd, n; 99 char *lp, *rp; 100 char buf[256]; 101 102 snprint(buf, sizeof buf, "#p/%d/args", getpid()); 103 if((fd = open(buf, OREAD)) < 0) 104 return strdup(""); 105 *buf = '\0'; 106 n = read(fd, buf, sizeof buf-1); 107 close(fd); 108 if (n >= 0) 109 buf[n] = '\0'; 110 if ((lp = strchr(buf, '[')) == nil || 111 (rp = strrchr(buf, ']')) == nil) 112 return strdup(""); 113 *rp = '\0'; 114 return strdup(lp+1); 115 } 116 117 /* 118 * lookup 'type' info for domain name 'name'. If it doesn't exist, try 119 * looking it up as a canonical name. 120 */ 121 RR* 122 dnresolve(char *name, int class, int type, Request *req, RR **cn, int depth, 123 int recurse, int rooted, int *status) 124 { 125 RR *rp, *nrp, *drp; 126 DN *dp; 127 int loops; 128 char *procname; 129 char nname[Domlen]; 130 131 if(status) 132 *status = 0; 133 134 if(depth > 12) /* in a recursive loop? */ 135 return nil; 136 137 procname = procgetname(); 138 /* 139 * hack for systems that don't have resolve search 140 * lists. Just look up the simple name in the database. 141 */ 142 if(!rooted && strchr(name, '.') == nil){ 143 rp = nil; 144 drp = domainlist(class); 145 for(nrp = drp; rp == nil && nrp != nil; nrp = nrp->next){ 146 snprint(nname, sizeof nname, "%s.%s", name, 147 nrp->ptr->name); 148 rp = dnresolve(nname, class, type, req, cn, depth+1, 149 recurse, rooted, status); 150 rrfreelist(rrremneg(&rp)); 151 } 152 if(drp != nil) 153 rrfreelist(drp); 154 procsetname(procname); 155 free(procname); 156 return rp; 157 } 158 159 /* 160 * try the name directly 161 */ 162 rp = dnresolve1(name, class, type, req, depth, recurse); 163 if(rp == nil) { 164 /* 165 * try it as a canonical name if we weren't told 166 * that the name didn't exist 167 */ 168 dp = dnlookup(name, class, 0); 169 if(type != Tptr && dp->respcode != Rname) 170 for(loops = 0; rp == nil && loops < 32; loops++){ 171 rp = dnresolve1(name, class, Tcname, req, 172 depth, recurse); 173 if(rp == nil) 174 break; 175 176 /* rp->host == nil shouldn't happen, but does */ 177 if(rp->negative || rp->host == nil){ 178 rrfreelist(rp); 179 rp = nil; 180 break; 181 } 182 183 name = rp->host->name; 184 if(cn) 185 rrcat(cn, rp); 186 else 187 rrfreelist(rp); 188 189 rp = dnresolve1(name, class, type, req, 190 depth, recurse); 191 } 192 193 /* distinction between not found and not good */ 194 if(rp == nil && status != nil && dp->respcode != 0) 195 *status = dp->respcode; 196 } 197 procsetname(procname); 198 free(procname); 199 return randomize(rp); 200 } 201 202 static void 203 queryinit(Query *qp, DN *dp, int type, Request *req) 204 { 205 memset(qp, 0, sizeof *qp); 206 qp->udpfd = qp->tcpfd = qp->tcpctlfd = -1; 207 qp->dp = dp; 208 qp->type = type; 209 if (qp->type != type) 210 dnslog("queryinit: bogus type %d", type); 211 qp->req = req; 212 qp->nsrp = nil; 213 qp->dest = qp->curdest = nil; 214 qp->magic = Querymagic; 215 } 216 217 static void 218 queryck(Query *qp) 219 { 220 assert(qp); 221 assert(qp->magic == Querymagic); 222 } 223 224 static void 225 querydestroy(Query *qp) 226 { 227 queryck(qp); 228 /* leave udpfd alone */ 229 if (qp->tcpfd > 0) 230 close(qp->tcpfd); 231 if (qp->tcpctlfd > 0) { 232 hangup(qp->tcpctlfd); 233 close(qp->tcpctlfd); 234 } 235 free(qp->dest); 236 memset(qp, 0, sizeof *qp); /* prevent accidents */ 237 qp->udpfd = qp->tcpfd = qp->tcpctlfd = -1; 238 } 239 240 static void 241 destinit(Dest *p) 242 { 243 memset(p, 0, sizeof *p); 244 p->magic = Destmagic; 245 } 246 247 static void 248 destck(Dest *p) 249 { 250 assert(p); 251 assert(p->magic == Destmagic); 252 } 253 254 static void 255 destdestroy(Dest *p) 256 { 257 USED(p); 258 } 259 260 /* 261 * if the response to a query hasn't arrived within 100 ms., 262 * it's unlikely to arrive at all. after 1 s., it's really unlikely. 263 * queries for missing RRs are likely to produce time-outs rather than 264 * negative responses, so cname and aaaa queries are likely to time out, 265 * thus we don't wait very long for them. 266 */ 267 static void 268 notestats(vlong start, int tmout, int type) 269 { 270 qlock(&stats); 271 if (tmout) { 272 stats.tmout++; 273 if (type == Taaaa) 274 stats.tmoutv6++; 275 else if (type == Tcname) 276 stats.tmoutcname++; 277 } else { 278 long wait10ths = NS2MS(nsec() - start) / 100; 279 280 if (wait10ths <= 0) 281 stats.under10ths[0]++; 282 else if (wait10ths >= nelem(stats.under10ths)) 283 stats.under10ths[nelem(stats.under10ths) - 1]++; 284 else 285 stats.under10ths[wait10ths]++; 286 } 287 qunlock(&stats); 288 } 289 290 static void 291 noteinmem(void) 292 { 293 qlock(&stats); 294 stats.answinmem++; 295 qunlock(&stats); 296 } 297 298 static RR* 299 issuequery(Query *qp, char *name, int class, int depth, int recurse) 300 { 301 char *cp; 302 DN *nsdp; 303 RR *rp, *nsrp, *dbnsrp; 304 305 /* 306 * if we're running as just a resolver, query our 307 * designated name servers 308 */ 309 if(cfg.resolver){ 310 nsrp = randomize(getdnsservers(class)); 311 if(nsrp != nil) { 312 qp->nsrp = nsrp; 313 if(netquery(qp, depth+1)){ 314 rrfreelist(nsrp); 315 return rrlookup(qp->dp, qp->type, OKneg); 316 } 317 rrfreelist(nsrp); 318 } 319 } 320 321 /* 322 * walk up the domain name looking for 323 * a name server for the domain. 324 */ 325 for(cp = name; cp; cp = walkup(cp)){ 326 /* 327 * if this is a local (served by us) domain, 328 * return answer 329 */ 330 dbnsrp = randomize(dblookup(cp, class, Tns, 0, 0)); 331 if(dbnsrp && dbnsrp->local){ 332 rp = dblookup(name, class, qp->type, 1, dbnsrp->ttl); 333 rrfreelist(dbnsrp); 334 return rp; 335 } 336 337 /* 338 * if recursion isn't set, just accept local 339 * entries 340 */ 341 if(recurse == Dontrecurse){ 342 if(dbnsrp) 343 rrfreelist(dbnsrp); 344 continue; 345 } 346 347 /* look for ns in cache */ 348 nsdp = dnlookup(cp, class, 0); 349 nsrp = nil; 350 if(nsdp) 351 nsrp = randomize(rrlookup(nsdp, Tns, NOneg)); 352 353 /* if the entry timed out, ignore it */ 354 if(nsrp && nsrp->ttl < now){ 355 rrfreelist(nsrp); 356 nsrp = nil; 357 } 358 359 if(nsrp){ 360 rrfreelist(dbnsrp); 361 362 /* query the name servers found in cache */ 363 qp->nsrp = nsrp; 364 if(netquery(qp, depth+1)){ 365 rrfreelist(nsrp); 366 return rrlookup(qp->dp, qp->type, OKneg); 367 } 368 rrfreelist(nsrp); 369 continue; 370 } 371 372 /* use ns from db */ 373 if(dbnsrp){ 374 /* try the name servers found in db */ 375 qp->nsrp = dbnsrp; 376 if(netquery(qp, depth+1)){ 377 /* we got an answer */ 378 rrfreelist(dbnsrp); 379 return rrlookup(qp->dp, qp->type, NOneg); 380 } 381 rrfreelist(dbnsrp); 382 } 383 } 384 return nil; 385 } 386 387 static RR* 388 dnresolve1(char *name, int class, int type, Request *req, int depth, 389 int recurse) 390 { 391 Area *area; 392 DN *dp; 393 RR *rp; 394 Query *qp; 395 396 if(debug) 397 dnslog("[%d] dnresolve1 %s %d %d", getpid(), name, type, class); 398 399 /* only class Cin implemented so far */ 400 if(class != Cin) 401 return nil; 402 403 dp = dnlookup(name, class, 1); 404 405 /* 406 * Try the cache first 407 */ 408 rp = rrlookup(dp, type, OKneg); 409 if(rp) 410 if(rp->db){ 411 /* unauthoritative db entries are hints */ 412 if(rp->auth) { 413 noteinmem(); 414 return rp; 415 } 416 } else 417 /* cached entry must still be valid */ 418 if(rp->ttl > now) 419 /* but Tall entries are special */ 420 if(type != Tall || rp->query == Tall) { 421 noteinmem(); 422 return rp; 423 } 424 rrfreelist(rp); 425 rp = nil; /* accident prevention */ 426 USED(rp); 427 428 /* 429 * try the cache for a canonical name. if found punt 430 * since we'll find it during the canonical name search 431 * in dnresolve(). 432 */ 433 if(type != Tcname){ 434 rp = rrlookup(dp, Tcname, NOneg); 435 rrfreelist(rp); 436 if(rp) 437 return nil; 438 } 439 440 /* 441 * if the domain name is within an area of ours, 442 * we should have found its data in memory by now. 443 */ 444 area = inmyarea(dp->name); 445 if (area || strncmp(dp->name, "local#", 6) == 0) { 446 // char buf[32]; 447 448 // dnslog("%s %s: no data in area %s", dp->name, 449 // rrname(type, buf, sizeof buf), area->soarr->owner->name); 450 return nil; 451 } 452 453 qp = emalloc(sizeof *qp); 454 queryinit(qp, dp, type, req); 455 rp = issuequery(qp, name, class, depth, recurse); 456 querydestroy(qp); 457 free(qp); 458 if(rp) 459 return rp; 460 461 /* settle for a non-authoritative answer */ 462 rp = rrlookup(dp, type, OKneg); 463 if(rp) 464 return rp; 465 466 /* noone answered. try the database, we might have a chance. */ 467 return dblookup(name, class, type, 0, 0); 468 } 469 470 /* 471 * walk a domain name one element to the right. 472 * return a pointer to that element. 473 * in other words, return a pointer to the parent domain name. 474 */ 475 char* 476 walkup(char *name) 477 { 478 char *cp; 479 480 cp = strchr(name, '.'); 481 if(cp) 482 return cp+1; 483 else if(*name) 484 return ""; 485 else 486 return 0; 487 } 488 489 /* 490 * Get a udp port for sending requests and reading replies. Put the port 491 * into "headers" mode. 492 */ 493 static char *hmsg = "headers"; 494 495 int 496 udpport(char *mtpt) 497 { 498 int fd, ctl; 499 char ds[64], adir[64]; 500 501 /* get a udp port */ 502 snprint(ds, sizeof ds, "%s/udp!*!0", (mtpt? mtpt: "/net")); 503 ctl = announce(ds, adir); 504 if(ctl < 0){ 505 /* warning("can't get udp port"); */ 506 return -1; 507 } 508 509 /* turn on header style interface */ 510 if(write(ctl, hmsg, strlen(hmsg)) , 0){ 511 close(ctl); 512 warning(hmsg); 513 return -1; 514 } 515 516 /* grab the data file */ 517 snprint(ds, sizeof ds, "%s/data", adir); 518 fd = open(ds, ORDWR); 519 close(ctl); 520 if(fd < 0) 521 warning("can't open udp port %s: %r", ds); 522 return fd; 523 } 524 525 /* generate a DNS UDP query packet */ 526 int 527 mkreq(DN *dp, int type, uchar *buf, int flags, ushort reqno) 528 { 529 DNSmsg m; 530 int len; 531 Udphdr *uh = (Udphdr*)buf; 532 533 /* stuff port number into output buffer */ 534 memset(uh, 0, sizeof *uh); 535 hnputs(uh->rport, 53); 536 537 /* make request and convert it to output format */ 538 memset(&m, 0, sizeof m); 539 m.flags = flags; 540 m.id = reqno; 541 m.qd = rralloc(type); 542 m.qd->owner = dp; 543 m.qd->type = type; 544 if (m.qd->type != type) 545 dnslog("mkreq: bogus type %d", type); 546 len = convDNS2M(&m, &buf[Udphdrsize], Maxudp); 547 rrfree(m.qd); 548 memset(&m, 0, sizeof m); /* cause trouble */ 549 return len; 550 } 551 552 void 553 freeanswers(DNSmsg *mp) 554 { 555 rrfreelist(mp->qd); 556 rrfreelist(mp->an); 557 rrfreelist(mp->ns); 558 rrfreelist(mp->ar); 559 mp->qd = mp->an = mp->ns = mp->ar = nil; 560 } 561 562 /* sets srcip */ 563 static int 564 readnet(Query *qp, int medium, uchar *ibuf, ulong endtime, uchar **replyp, 565 uchar *srcip) 566 { 567 int len, fd; 568 long ms; 569 vlong startns = nsec(); 570 uchar *reply; 571 uchar lenbuf[2]; 572 573 /* timed read of reply */ 574 ms = S2MS(endtime) - NS2MS(startns); 575 if (ms < 2000) 576 ms = 2000; /* give the remote ns a fighting chance */ 577 reply = ibuf; 578 len = -1; /* pessimism */ 579 memset(srcip, 0, IPaddrlen); 580 if (medium == Udp) 581 if (qp->udpfd <= 0) 582 dnslog("readnet: qp->udpfd closed"); 583 else { 584 alarm(ms); 585 len = read(qp->udpfd, ibuf, Udphdrsize+Maxudpin); 586 alarm(0); 587 notestats(startns, len < 0, qp->type); 588 if (len >= IPaddrlen) 589 memmove(srcip, ibuf, IPaddrlen); 590 if (len >= Udphdrsize) { 591 len -= Udphdrsize; 592 reply += Udphdrsize; 593 } 594 } 595 else { 596 if (!qp->tcpset) 597 dnslog("readnet: tcp params not set"); 598 alarm(ms); 599 fd = qp->tcpfd; 600 if (fd <= 0) 601 dnslog("readnet: %s: tcp fd unset for dest %I", 602 qp->dp->name, qp->tcpip); 603 else if (readn(fd, lenbuf, 2) != 2) { 604 dnslog("readnet: short read of tcp size from %I", 605 qp->tcpip); 606 /* probably a time-out */ 607 notestats(startns, 1, qp->type); 608 } else { 609 len = lenbuf[0]<<8 | lenbuf[1]; 610 if (readn(fd, ibuf, len) != len) { 611 dnslog("readnet: short read of tcp data from %I", 612 qp->tcpip); 613 /* probably a time-out */ 614 notestats(startns, 1, qp->type); 615 len = -1; 616 } 617 } 618 alarm(0); 619 memmove(srcip, qp->tcpip, IPaddrlen); 620 } 621 *replyp = reply; 622 return len; 623 } 624 625 /* 626 * read replies to a request and remember the rrs in the answer(s). 627 * ignore any of the wrong type. 628 * wait at most until endtime. 629 */ 630 static int 631 readreply(Query *qp, int medium, ushort req, uchar *ibuf, DNSmsg *mp, 632 ulong endtime) 633 { 634 int len, rv; 635 char *err; 636 char tbuf[32]; 637 uchar *reply; 638 uchar srcip[IPaddrlen]; 639 RR *rp; 640 641 queryck(qp); 642 rv = 0; 643 memset(mp, 0, sizeof *mp); 644 if (time(nil) >= endtime) 645 return -1; /* timed out before we started */ 646 647 memset(srcip, 0, sizeof srcip); 648 if (0) 649 len = -1; 650 for (; time(nil) < endtime && 651 (len = readnet(qp, medium, ibuf, endtime, &reply, srcip)) >= 0; 652 freeanswers(mp)){ 653 /* convert into internal format */ 654 memset(mp, 0, sizeof *mp); 655 err = convM2DNS(reply, len, mp, nil); 656 if (mp->flags & Ftrunc) { 657 free(err); 658 freeanswers(mp); 659 /* notify our caller to retry the query via tcp. */ 660 return -1; 661 } else if(err){ 662 dnslog("readreply: %s: input err, len %d: %s: %I", 663 qp->dp->name, len, err, srcip); 664 free(err); 665 continue; 666 } 667 if(debug) 668 logreply(qp->req->id, srcip, mp); 669 670 /* answering the right question? */ 671 if(mp->id != req) 672 dnslog("%d: id %d instead of %d: %I", qp->req->id, 673 mp->id, req, srcip); 674 else if(mp->qd == 0) 675 dnslog("%d: no question RR: %I", qp->req->id, srcip); 676 else if(mp->qd->owner != qp->dp) 677 dnslog("%d: owner %s instead of %s: %I", qp->req->id, 678 mp->qd->owner->name, qp->dp->name, srcip); 679 else if(mp->qd->type != qp->type) 680 dnslog("%d: qp->type %d instead of %d: %I", 681 qp->req->id, mp->qd->type, qp->type, srcip); 682 else { 683 /* remember what request this is in answer to */ 684 for(rp = mp->an; rp; rp = rp->next) 685 rp->query = qp->type; 686 return rv; 687 } 688 } 689 if (time(nil) >= endtime) { 690 ; /* query expired */ 691 } else if (0) { 692 /* this happens routinely when a read times out */ 693 dnslog("readreply: %s type %s: ns %I read error or eof " 694 "(returned %d): %r", qp->dp->name, rrname(qp->type, 695 tbuf, sizeof tbuf), srcip, len); 696 if (medium == Udp) 697 for (rp = qp->nsrp; rp != nil; rp = rp->next) 698 if (rp->type == Tns) 699 dnslog("readreply: %s: query sent to " 700 "ns %s", qp->dp->name, 701 rp->host->name); 702 } 703 return -1; 704 } 705 706 /* 707 * return non-0 if first list includes second list 708 */ 709 int 710 contains(RR *rp1, RR *rp2) 711 { 712 RR *trp1, *trp2; 713 714 for(trp2 = rp2; trp2; trp2 = trp2->next){ 715 for(trp1 = rp1; trp1; trp1 = trp1->next) 716 if(trp1->type == trp2->type) 717 if(trp1->host == trp2->host) 718 if(trp1->owner == trp2->owner) 719 break; 720 if(trp1 == nil) 721 return 0; 722 } 723 return 1; 724 } 725 726 727 /* 728 * return multicast version if any 729 */ 730 int 731 ipisbm(uchar *ip) 732 { 733 if(isv4(ip)){ 734 if (ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0 || 735 ipcmp(ip, IPv4bcast) == 0) 736 return 4; 737 } else 738 if(ip[0] == 0xff) 739 return 6; 740 return 0; 741 } 742 743 /* 744 * Get next server address 745 */ 746 static int 747 serveraddrs(Query *qp, int nd, int depth) 748 { 749 RR *rp, *arp, *trp; 750 Dest *cur; 751 752 if(nd >= Maxdest) 753 return 0; 754 755 /* 756 * look for a server whose address we already know. 757 * if we find one, mark it so we ignore this on 758 * subsequent passes. 759 */ 760 arp = 0; 761 for(rp = qp->nsrp; rp; rp = rp->next){ 762 assert(rp->magic == RRmagic); 763 if(rp->marker) 764 continue; 765 arp = rrlookup(rp->host, Ta, NOneg); 766 if(arp){ 767 rp->marker = 1; 768 break; 769 } 770 arp = dblookup(rp->host->name, Cin, Ta, 0, 0); 771 if(arp){ 772 rp->marker = 1; 773 break; 774 } 775 } 776 777 /* 778 * if the cache and database lookup didn't find any new 779 * server addresses, try resolving one via the network. 780 * Mark any we try to resolve so we don't try a second time. 781 */ 782 if(arp == 0) 783 for(rp = qp->nsrp; rp; rp = rp->next){ 784 if(rp->marker) 785 continue; 786 rp->marker = 1; 787 788 /* 789 * avoid loops looking up a server under itself 790 */ 791 if(subsume(rp->owner->name, rp->host->name)) 792 continue; 793 794 arp = dnresolve(rp->host->name, Cin, Ta, qp->req, 0, 795 depth+1, Recurse, 1, 0); 796 rrfreelist(rrremneg(&arp)); 797 if(arp) 798 break; 799 } 800 801 /* use any addresses that we found */ 802 for(trp = arp; trp && nd < Maxdest; trp = trp->next){ 803 cur = &qp->dest[nd]; 804 parseip(cur->a, trp->ip->name); 805 /* 806 * straddling servers can reject all nameservers if they are all 807 * inside, so be sure to list at least one outside ns at 808 * the end of the ns list in /lib/ndb for `dom='. 809 */ 810 if (ipisbm(cur->a) || 811 cfg.straddle && !insideaddr(qp->dp->name) && insidens(cur->a)) 812 continue; 813 cur->nx = 0; 814 cur->s = trp->owner; 815 cur->code = Rtimeout; 816 nd++; 817 } 818 rrfreelist(arp); 819 return nd; 820 } 821 822 /* 823 * cache negative responses 824 */ 825 static void 826 cacheneg(DN *dp, int type, int rcode, RR *soarr) 827 { 828 RR *rp; 829 DN *soaowner; 830 ulong ttl; 831 832 stats.negcached++; 833 834 /* no cache time specified, don't make anything up */ 835 if(soarr != nil){ 836 if(soarr->next != nil){ 837 rrfreelist(soarr->next); 838 soarr->next = nil; 839 } 840 soaowner = soarr->owner; 841 } else 842 soaowner = nil; 843 844 /* the attach can cause soarr to be freed so mine it now */ 845 if(soarr != nil && soarr->soa != nil) 846 ttl = soarr->soa->minttl+now; 847 else 848 ttl = 5*Min; 849 850 /* add soa and negative RR to the database */ 851 rrattach(soarr, Authoritative); 852 853 rp = rralloc(type); 854 rp->owner = dp; 855 rp->negative = 1; 856 rp->negsoaowner = soaowner; 857 rp->negrcode = rcode; 858 rp->ttl = ttl; 859 rrattach(rp, Authoritative); 860 } 861 862 static int 863 setdestoutns(Dest *p, int n) 864 { 865 uchar *outns = outsidens(n); 866 867 destck(p); 868 destinit(p); 869 if (outns == nil) { 870 if (n == 0) 871 dnslog("[%d] no outside-ns in ndb", getpid()); 872 return -1; 873 } 874 memmove(p->a, outns, sizeof p->a); 875 p->s = dnlookup("outside-ns-ips", Cin, 1); 876 return 0; 877 } 878 879 /* 880 * issue query via UDP or TCP as appropriate. 881 * for TCP, returns with qp->tcpip set from udppkt header. 882 */ 883 static int 884 mydnsquery(Query *qp, int medium, uchar *udppkt, int len) 885 { 886 int rv = -1, nfd; 887 char *domain; 888 char conndir[40]; 889 uchar belen[2]; 890 NetConnInfo *nci; 891 892 queryck(qp); 893 domain = smprint("%I", udppkt); 894 if (myaddr(domain)) { 895 dnslog("mydnsquery: trying to send to myself (%s); bzzzt", 896 domain); 897 free(domain); 898 return rv; 899 } 900 901 switch (medium) { 902 case Udp: 903 free(domain); 904 nfd = dup(qp->udpfd, -1); 905 if (nfd < 0) { 906 warning("mydnsquery: qp->udpfd %d: %r", qp->udpfd); 907 close(qp->udpfd); /* ensure it's closed */ 908 qp->udpfd = -1; /* poison it */ 909 return rv; 910 } 911 close(nfd); 912 913 if (qp->udpfd <= 0) 914 dnslog("mydnsquery: qp->udpfd %d closed", qp->udpfd); 915 else { 916 if (write(qp->udpfd, udppkt, len+Udphdrsize) != 917 len+Udphdrsize) 918 warning("sending udp msg: %r"); 919 else { 920 stats.qsent++; 921 rv = 0; 922 } 923 } 924 break; 925 case Tcp: 926 /* send via TCP & keep fd around for reply */ 927 alarm(10*1000); 928 qp->tcpfd = rv = dial(netmkaddr(domain, "tcp", "dns"), nil, 929 conndir, &qp->tcpctlfd); 930 alarm(0); 931 if (qp->tcpfd < 0) { 932 dnslog("can't dial tcp!%s!dns: %r", domain); 933 free(domain); 934 break; 935 } 936 free(domain); 937 nci = getnetconninfo(conndir, qp->tcpfd); 938 if (nci) { 939 parseip(qp->tcpip, nci->rsys); 940 freenetconninfo(nci); 941 } else 942 dnslog("mydnsquery: getnetconninfo failed"); 943 qp->tcpset = 1; 944 945 belen[0] = len >> 8; 946 belen[1] = len; 947 if (write(qp->tcpfd, belen, 2) != 2 || 948 write(qp->tcpfd, udppkt + Udphdrsize, len) != len) 949 warning("sending tcp msg: %r"); 950 break; 951 default: 952 sysfatal("mydnsquery: bad medium"); 953 } 954 return rv; 955 } 956 957 /* 958 * send query to all UDP destinations or one TCP destination, 959 * taken from obuf (udp packet) header 960 */ 961 static int 962 xmitquery(Query *qp, int medium, int depth, uchar *obuf, int inns, int len) 963 { 964 int j, n; 965 char buf[32]; 966 Dest *p; 967 968 queryck(qp); 969 if(time(nil) >= qp->req->aborttime) 970 return -1; 971 972 /* 973 * get a nameserver address if we need one. 974 * serveraddrs populates qp->dest. 975 */ 976 p = qp->dest; 977 destck(p); 978 if (qp->ndest < 0 || qp->ndest > Maxdest) 979 dnslog("qp->ndest %d out of range", qp->ndest); 980 if (qp->ndest > qp->curdest - p) 981 qp->curdest = &qp->dest[serveraddrs(qp, qp->curdest - p, depth)]; 982 destck(qp->curdest); 983 984 /* no servers, punt */ 985 if (qp->curdest == qp->dest) 986 if (cfg.straddle && cfg.inside) { 987 /* get ips of "outside-ns-ips" */ 988 p = qp->curdest = qp->dest; 989 for(n = 0; n < Maxdest; n++, qp->curdest++) 990 if (setdestoutns(qp->curdest, n) < 0) 991 break; 992 } else { 993 /* it's probably just a bogus domain, don't log it */ 994 // dnslog("xmitquery: %s: no nameservers", qp->dp->name); 995 return -1; 996 } 997 998 /* send to first 'qp->ndest' destinations */ 999 j = 0; 1000 if (medium == Tcp) { 1001 j++; 1002 queryck(qp); 1003 assert(qp->dp); 1004 procsetname("tcp %sside query for %s %s", (inns? "in": "out"), 1005 qp->dp->name, rrname(qp->type, buf, sizeof buf)); 1006 mydnsquery(qp, medium, obuf, len); /* sets qp->tcpip from obuf */ 1007 if(debug) 1008 logsend(qp->req->id, depth, qp->tcpip, "", qp->dp->name, 1009 qp->type); 1010 } else 1011 for(; p < &qp->dest[qp->ndest] && p < qp->curdest; p++){ 1012 /* skip destinations we've finished with */ 1013 if(p->nx >= Maxtrans) 1014 continue; 1015 1016 j++; 1017 1018 /* exponential backoff of requests */ 1019 if((1<<p->nx) > qp->ndest) 1020 continue; 1021 1022 procsetname("udp %sside query to %I/%s %s %s", 1023 (inns? "in": "out"), p->a, p->s->name, 1024 qp->dp->name, rrname(qp->type, buf, sizeof buf)); 1025 if(debug) 1026 logsend(qp->req->id, depth, p->a, p->s->name, 1027 qp->dp->name, qp->type); 1028 1029 /* fill in UDP destination addr & send it */ 1030 memmove(obuf, p->a, sizeof p->a); 1031 mydnsquery(qp, medium, obuf, len); 1032 p->nx++; 1033 } 1034 if(j == 0) { 1035 // dnslog("xmitquery: %s: no destinations left", qp->dp->name); 1036 return -1; 1037 } 1038 return 0; 1039 } 1040 1041 static int lckindex[Maxlcks] = { 1042 0, /* all others map here */ 1043 Ta, 1044 Tns, 1045 Tcname, 1046 Tsoa, 1047 Tptr, 1048 Tmx, 1049 Ttxt, 1050 Taaaa, 1051 }; 1052 1053 static int 1054 qtype2lck(int qtype) /* map query type to querylck index */ 1055 { 1056 int i; 1057 1058 for (i = 1; i < nelem(lckindex); i++) 1059 if (lckindex[i] == qtype) 1060 return i; 1061 return 0; 1062 } 1063 1064 /* is mp a cachable negative response (with Rname set)? */ 1065 static int 1066 isnegrname(DNSmsg *mp) 1067 { 1068 /* TODO: could add || cfg.justforw to RHS of && */ 1069 return mp->an == nil && (mp->flags & Rmask) == Rname; 1070 } 1071 1072 static int 1073 procansw(Query *qp, DNSmsg *mp, uchar *srcip, int depth, Dest *p) 1074 { 1075 int rv; 1076 // int lcktype; 1077 char buf[32]; 1078 DN *ndp; 1079 Query *nqp; 1080 RR *tp, *soarr; 1081 1082 if (mp->an == nil) 1083 stats.negans++; 1084 1085 /* ignore any error replies */ 1086 if((mp->flags & Rmask) == Rserver){ 1087 stats.negserver++; 1088 freeanswers(mp); 1089 if(p != qp->curdest) 1090 p->code = Rserver; 1091 return -1; 1092 } 1093 1094 /* ignore any bad delegations */ 1095 if(mp->ns && baddelegation(mp->ns, qp->nsrp, srcip)){ 1096 stats.negbaddeleg++; 1097 if(mp->an == nil){ 1098 stats.negbdnoans++; 1099 freeanswers(mp); 1100 if(p != qp->curdest) 1101 p->code = Rserver; 1102 return -1; 1103 } 1104 rrfreelist(mp->ns); 1105 mp->ns = nil; 1106 } 1107 1108 /* remove any soa's from the authority section */ 1109 soarr = rrremtype(&mp->ns, Tsoa); 1110 1111 /* incorporate answers */ 1112 unique(mp->an); 1113 unique(mp->ns); 1114 unique(mp->ar); 1115 if(mp->an) 1116 rrattach(mp->an, (mp->flags & Fauth) != 0); 1117 if(mp->ar) 1118 rrattach(mp->ar, Notauthoritative); 1119 if(mp->ns && !cfg.justforw){ 1120 ndp = mp->ns->owner; 1121 rrattach(mp->ns, Notauthoritative); 1122 } else { 1123 ndp = nil; 1124 rrfreelist(mp->ns); 1125 mp->ns = nil; 1126 } 1127 1128 /* free the question */ 1129 if(mp->qd) { 1130 rrfreelist(mp->qd); 1131 mp->qd = nil; 1132 } 1133 1134 /* 1135 * Any reply from an authoritative server, 1136 * or a positive reply terminates the search. 1137 * A negative response now also terminates the search. 1138 */ 1139 if(mp->an != nil || (mp->flags & Fauth)){ 1140 if(isnegrname(mp)) 1141 qp->dp->respcode = Rname; 1142 else 1143 qp->dp->respcode = 0; 1144 1145 /* 1146 * cache any negative responses, free soarr. 1147 * negative responses need not be authoritative: 1148 * they can legitimately come from a cache. 1149 */ 1150 if( /* (mp->flags & Fauth) && */ mp->an == nil) 1151 cacheneg(qp->dp, qp->type, (mp->flags & Rmask), soarr); 1152 else 1153 rrfreelist(soarr); 1154 return 1; 1155 } else if (isnegrname(mp)) { 1156 qp->dp->respcode = Rname; 1157 /* 1158 * cache negative response. 1159 * negative responses need not be authoritative: 1160 * they can legitimately come from a cache. 1161 */ 1162 cacheneg(qp->dp, qp->type, (mp->flags & Rmask), soarr); 1163 return 1; 1164 } 1165 stats.negnorname++; 1166 rrfreelist(soarr); 1167 1168 /* 1169 * if we've been given better name servers, recurse. 1170 * if we're a pure resolver, don't recurse, we have 1171 * to forward to a fixed set of named servers. 1172 */ 1173 if(!mp->ns || cfg.resolver && cfg.justforw) 1174 return 0; 1175 tp = rrlookup(ndp, Tns, NOneg); 1176 if(contains(qp->nsrp, tp)){ 1177 rrfreelist(tp); 1178 return 0; 1179 } 1180 procsetname("recursive query for %s %s", qp->dp->name, 1181 rrname(qp->type, buf, sizeof buf)); 1182 /* 1183 * we're called from udpquery, called from 1184 * netquery, which current holds qp->dp->querylck, 1185 * so release it now and acquire it upon return. 1186 */ 1187 // lcktype = qtype2lck(qp->type); 1188 // qunlock(&qp->dp->querylck[lcktype]); 1189 1190 nqp = emalloc(sizeof *nqp); 1191 queryinit(nqp, qp->dp, qp->type, qp->req); 1192 nqp->nsrp = tp; 1193 rv = netquery(nqp, depth+1); 1194 1195 // qlock(&qp->dp->querylck[lcktype]); 1196 rrfreelist(nqp->nsrp); 1197 querydestroy(nqp); 1198 free(nqp); 1199 return rv; 1200 } 1201 1202 /* 1203 * send a query via tcp to a single address (from ibuf's udp header) 1204 * and read the answer(s) into mp->an. 1205 */ 1206 static int 1207 tcpquery(Query *qp, DNSmsg *mp, int depth, uchar *ibuf, uchar *obuf, int len, 1208 int waitsecs, int inns, ushort req) 1209 { 1210 int rv = 0; 1211 ulong endtime; 1212 1213 endtime = time(nil) + waitsecs; 1214 if(endtime > qp->req->aborttime) 1215 endtime = qp->req->aborttime; 1216 1217 if (0) 1218 dnslog("%s: udp reply truncated; retrying query via tcp to %I", 1219 qp->dp->name, qp->tcpip); 1220 1221 qlock(&qp->tcplock); 1222 memmove(obuf, ibuf, IPaddrlen); /* send back to respondent */ 1223 /* sets qp->tcpip from obuf's udp header */ 1224 if (xmitquery(qp, Tcp, depth, obuf, inns, len) < 0 || 1225 readreply(qp, Tcp, req, ibuf, mp, endtime) < 0) 1226 rv = -1; 1227 if (qp->tcpfd > 0) { 1228 hangup(qp->tcpctlfd); 1229 close(qp->tcpctlfd); 1230 close(qp->tcpfd); 1231 } 1232 qp->tcpfd = qp->tcpctlfd = -1; 1233 qunlock(&qp->tcplock); 1234 return rv; 1235 } 1236 1237 /* 1238 * query name servers. If the name server returns a pointer to another 1239 * name server, recurse. 1240 */ 1241 static int 1242 queryns(Query *qp, int depth, uchar *ibuf, uchar *obuf, int waitsecs, int inns) 1243 { 1244 int ndest, len, replywaits, rv; 1245 ushort req; 1246 ulong endtime; 1247 char buf[12]; 1248 uchar srcip[IPaddrlen]; 1249 Dest *p, *np, *dest; 1250 // Dest dest[Maxdest]; 1251 1252 /* pack request into a udp message */ 1253 req = rand(); 1254 len = mkreq(qp->dp, qp->type, obuf, Frecurse|Oquery, req); 1255 1256 /* no server addresses yet */ 1257 queryck(qp); 1258 dest = emalloc(Maxdest * sizeof *dest); /* dest can't be on stack */ 1259 for (p = dest; p < dest + Maxdest; p++) 1260 destinit(p); 1261 /* this dest array is local to this call of queryns() */ 1262 free(qp->dest); 1263 qp->curdest = qp->dest = dest; 1264 1265 /* 1266 * transmit udp requests and wait for answers. 1267 * at most Maxtrans attempts to each address. 1268 * each cycle send one more message than the previous. 1269 * retry a query via tcp if its response is truncated. 1270 */ 1271 for(ndest = 1; ndest < Maxdest; ndest++){ 1272 qp->ndest = ndest; 1273 qp->tcpset = 0; 1274 if (xmitquery(qp, Udp, depth, obuf, inns, len) < 0) 1275 break; 1276 1277 endtime = time(nil) + waitsecs; 1278 if(endtime > qp->req->aborttime) 1279 endtime = qp->req->aborttime; 1280 1281 for(replywaits = 0; replywaits < ndest; replywaits++){ 1282 DNSmsg m; 1283 1284 procsetname("reading %sside reply from %I: %s %s from %s", 1285 (inns? "in": "out"), obuf, qp->dp->name, 1286 rrname(qp->type, buf, sizeof buf), qp->req->from); 1287 1288 /* read udp answer into m */ 1289 if (readreply(qp, Udp, req, ibuf, &m, endtime) >= 0) 1290 memmove(srcip, ibuf, IPaddrlen); 1291 else if (!(m.flags & Ftrunc)) { 1292 freeanswers(&m); 1293 break; /* timed out on this dest */ 1294 } else { 1295 /* whoops, it was truncated! ask again via tcp */ 1296 freeanswers(&m); 1297 rv = tcpquery(qp, &m, depth, ibuf, obuf, len, 1298 waitsecs, inns, req); /* answer in m */ 1299 if (rv < 0) { 1300 freeanswers(&m); 1301 break; /* failed via tcp too */ 1302 } 1303 memmove(srcip, qp->tcpip, IPaddrlen); 1304 } 1305 1306 /* find responder */ 1307 // dnslog("queryns got reply from %I", srcip); 1308 for(p = qp->dest; p < qp->curdest; p++) 1309 if(memcmp(p->a, srcip, sizeof p->a) == 0) 1310 break; 1311 1312 /* remove all addrs of responding server from list */ 1313 for(np = qp->dest; np < qp->curdest; np++) 1314 if(np->s == p->s) 1315 p->nx = Maxtrans; 1316 1317 /* free or incorporate RRs in m */ 1318 rv = procansw(qp, &m, srcip, depth, p); 1319 if (rv > 0) { 1320 free(qp->dest); 1321 qp->dest = qp->curdest = nil; /* prevent accidents */ 1322 return rv; 1323 } 1324 } 1325 } 1326 1327 /* if all servers returned failure, propagate it */ 1328 qp->dp->respcode = Rserver; 1329 for(p = dest; p < qp->curdest; p++) { 1330 destck(p); 1331 if(p->code != Rserver) 1332 qp->dp->respcode = 0; 1333 p->magic = 0; /* prevent accidents */ 1334 } 1335 1336 // if (qp->dp->respcode) 1337 // dnslog("queryns setting Rserver for %s", qp->dp->name); 1338 1339 free(qp->dest); 1340 qp->dest = qp->curdest = nil; /* prevent accidents */ 1341 return 0; 1342 } 1343 1344 /* 1345 * run a command with a supplied fd as standard input 1346 */ 1347 char * 1348 system(int fd, char *cmd) 1349 { 1350 int pid, p, i; 1351 static Waitmsg msg; 1352 1353 if((pid = fork()) == -1) 1354 sysfatal("fork failed: %r"); 1355 else if(pid == 0){ 1356 dup(fd, 0); 1357 close(fd); 1358 for (i = 3; i < 200; i++) 1359 close(i); /* don't leak fds */ 1360 execl("/bin/rc", "rc", "-c", cmd, nil); 1361 sysfatal("exec rc: %r"); 1362 } 1363 for(p = waitpid(); p >= 0; p = waitpid()) 1364 if(p == pid) 1365 return msg.msg; 1366 return "lost child"; 1367 } 1368 1369 /* compute wait, weighted by probability of success, with minimum */ 1370 static ulong 1371 weight(ulong ms, unsigned pcntprob) 1372 { 1373 ulong wait; 1374 1375 wait = (ms * pcntprob) / 100; 1376 if (wait < 1500) 1377 wait = 1500; 1378 return wait; 1379 } 1380 1381 /* 1382 * in principle we could use a single descriptor for a udp port 1383 * to send all queries and receive all the answers to them, 1384 * but we'd have to sort out the answers by dns-query id. 1385 */ 1386 static int 1387 udpquery(Query *qp, char *mntpt, int depth, int patient, int inns) 1388 { 1389 int fd, rv; 1390 long now; 1391 ulong pcntprob, wait, reqtm; 1392 char *msg; 1393 uchar *obuf, *ibuf; 1394 static QLock mntlck; 1395 static ulong lastmount; 1396 1397 /* use alloced buffers rather than ones from the stack */ 1398 // ibuf = emalloc(Maxudpin+Udphdrsize); 1399 ibuf = emalloc(64*1024); /* max. tcp reply size */ 1400 obuf = emalloc(Maxudp+Udphdrsize); 1401 1402 fd = udpport(mntpt); 1403 while (fd < 0 && cfg.straddle && strcmp(mntpt, "/net.alt") == 0) { 1404 /* HACK: remount /net.alt */ 1405 now = time(nil); 1406 if (now < lastmount + Remntretry) 1407 sleep((lastmount + Remntretry - now)*1000); 1408 qlock(&mntlck); 1409 fd = udpport(mntpt); /* try again under lock */ 1410 if (fd < 0) { 1411 dnslog("[%d] remounting /net.alt", getpid()); 1412 unmount(nil, "/net.alt"); 1413 1414 msg = system(open("/dev/null", ORDWR), "outside"); 1415 1416 lastmount = time(nil); 1417 if (msg && *msg) { 1418 dnslog("[%d] can't remount /net.alt: %s", 1419 getpid(), msg); 1420 sleep(10*1000); /* don't spin wildly */ 1421 } else 1422 fd = udpport(mntpt); 1423 } 1424 qunlock(&mntlck); 1425 } 1426 if (fd < 0) { 1427 dnslog("can't get udpport for %s query of name %s: %r", 1428 mntpt, qp->dp->name); 1429 sysfatal("out of udp conversations"); /* we're buggered */ 1430 } 1431 1432 /* 1433 * Our QIP servers are busted, don't answer AAAA and 1434 * take forever to answer CNAME if there isn't one. 1435 * They rarely set Rname. 1436 * make time-to-wait proportional to estimated probability of an 1437 * RR of that type existing. 1438 */ 1439 if (qp->type >= nelem(likely)) 1440 pcntprob = 35; /* unpopular query type */ 1441 else 1442 pcntprob = likely[qp->type]; 1443 reqtm = (patient? 2*Maxreqtm: Maxreqtm); 1444 /* time for a single outgoing udp query */ 1445 wait = weight(S2MS(reqtm)/3, pcntprob); 1446 qp->req->aborttime = time(nil) + MS2S(3*wait); /* for all udp queries */ 1447 1448 qp->udpfd = fd; 1449 rv = queryns(qp, depth, ibuf, obuf, MS2S(wait), inns); 1450 close(fd); 1451 qp->udpfd = -1; 1452 1453 free(obuf); 1454 free(ibuf); 1455 return rv; 1456 } 1457 1458 /* look up (qp->dp->name,qp->type) rr in dns, via *nsrp with results in *reqp */ 1459 static int 1460 netquery(Query *qp, int depth) 1461 { 1462 int lock, rv, triedin, inname, cnt; 1463 // char buf[32]; 1464 RR *rp; 1465 DN *dp; 1466 Querylck *qlp; 1467 static int whined; 1468 1469 rv = 0; /* pessimism */ 1470 if(depth > 12) /* in a recursive loop? */ 1471 return 0; 1472 1473 slave(qp->req); 1474 /* 1475 * slave might have forked. if so, the parent process longjmped to 1476 * req->mret; we're usually the child slave, but if there are too 1477 * many children already, we're still the same process. 1478 */ 1479 1480 /* 1481 * don't lock before call to slave so only children can block. 1482 * just lock at top-level invocation. 1483 */ 1484 lock = depth <= 1 && qp->req->isslave; 1485 dp = qp->dp; /* ensure that it doesn't change underfoot */ 1486 qlp = nil; 1487 if(lock) { 1488 // procsetname("query lock wait: %s %s from %s", dp->name, 1489 // rrname(qp->type, buf, sizeof buf), qp->req->from); 1490 /* 1491 * don't make concurrent queries for this name. 1492 * dozens of processes blocking here probably indicates 1493 * an error in our dns data that causes us to not 1494 * recognise a zone (area) as one of our own, thus 1495 * causing us to query other nameservers. 1496 */ 1497 qlp = &dp->querylck[qtype2lck(qp->type)]; 1498 incref(qlp); 1499 qlock(qlp); 1500 cnt = qlp->Ref.ref; 1501 qunlock(qlp); 1502 if (cnt > 10) { 1503 decref(qlp); 1504 if (!whined) { 1505 whined = 1; 1506 dnslog("too many outstanding queries for %s; " 1507 "dropping this one; " 1508 "no further logging of drops", 1509 dp->name); 1510 } 1511 return 0; 1512 } 1513 } 1514 procsetname("netquery: %s", dp->name); 1515 1516 /* prepare server RR's for incremental lookup */ 1517 for(rp = qp->nsrp; rp; rp = rp->next) 1518 rp->marker = 0; 1519 1520 triedin = 0; 1521 1522 /* 1523 * normal resolvers and servers will just use mntpt for all addresses, 1524 * even on the outside. straddling servers will use mntpt (/net) 1525 * for inside addresses and /net.alt for outside addresses, 1526 * thus bypassing other inside nameservers. 1527 */ 1528 inname = insideaddr(dp->name); 1529 if (!cfg.straddle || inname) { 1530 rv = udpquery(qp, mntpt, depth, Hurry, (cfg.inside? Inns: Outns)); 1531 triedin = 1; 1532 } 1533 1534 /* 1535 * if we're still looking, are inside, and have an outside domain, 1536 * try it on our outside interface, if any. 1537 */ 1538 if (rv == 0 && cfg.inside && !inname) { 1539 if (triedin) 1540 dnslog( 1541 "[%d] netquery: internal nameservers failed for %s; trying external", 1542 getpid(), dp->name); 1543 1544 /* prepare server RR's for incremental lookup */ 1545 for(rp = qp->nsrp; rp; rp = rp->next) 1546 rp->marker = 0; 1547 1548 rv = udpquery(qp, "/net.alt", depth, Patient, Outns); 1549 } 1550 // if (rv == 0) /* could ask /net.alt/dns directly */ 1551 // askoutdns(dp, qp->type); 1552 1553 if(lock && qlp) 1554 decref(qlp); 1555 return rv; 1556 } 1557 1558 int 1559 seerootns(void) 1560 { 1561 int rv; 1562 char root[] = ""; 1563 Request req; 1564 Query *qp; 1565 1566 memset(&req, 0, sizeof req); 1567 req.isslave = 1; 1568 req.aborttime = now + Maxreqtm; 1569 req.from = "internal"; 1570 qp = emalloc(sizeof *qp); 1571 queryinit(qp, dnlookup(root, Cin, 1), Tns, &req); 1572 1573 qp->nsrp = dblookup(root, Cin, Tns, 0, 0); 1574 rv = netquery(qp, 0); 1575 1576 rrfreelist(qp->nsrp); 1577 querydestroy(qp); 1578 free(qp); 1579 return rv; 1580 } 1581