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); /* was rrfree */ 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, RR *rp, char *name, int class, int depth, int recurse) 300 { 301 char *cp; 302 DN *nsdp; 303 RR *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 rp; 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; 426 427 /* 428 * try the cache for a canonical name. if found punt 429 * since we'll find it during the canonical name search 430 * in dnresolve(). 431 */ 432 if(type != Tcname){ 433 rp = rrlookup(dp, Tcname, NOneg); 434 rrfreelist(rp); 435 if(rp) 436 return nil; 437 } 438 439 /* 440 * if the domain name is within an area of ours, 441 * we should have found its data in memory by now. 442 */ 443 area = inmyarea(dp->name); 444 if (area || strncmp(dp->name, "local#", 6) == 0) { 445 // char buf[32]; 446 447 // dnslog("%s %s: no data in area %s", dp->name, 448 // rrname(type, buf, sizeof buf), area->soarr->owner->name); 449 return nil; 450 } 451 452 qp = emalloc(sizeof *qp); 453 queryinit(qp, dp, type, req); 454 rp = issuequery(qp, rp, name, class, depth, recurse); 455 querydestroy(qp); 456 free(qp); 457 if(rp) 458 return rp; 459 460 /* settle for a non-authoritative answer */ 461 rp = rrlookup(dp, type, OKneg); 462 if(rp) 463 return rp; 464 465 /* noone answered. try the database, we might have a chance. */ 466 return dblookup(name, class, type, 0, 0); 467 } 468 469 /* 470 * walk a domain name one element to the right. 471 * return a pointer to that element. 472 * in other words, return a pointer to the parent domain name. 473 */ 474 char* 475 walkup(char *name) 476 { 477 char *cp; 478 479 cp = strchr(name, '.'); 480 if(cp) 481 return cp+1; 482 else if(*name) 483 return ""; 484 else 485 return 0; 486 } 487 488 /* 489 * Get a udp port for sending requests and reading replies. Put the port 490 * into "headers" mode. 491 */ 492 static char *hmsg = "headers"; 493 494 int 495 udpport(char *mtpt) 496 { 497 int fd, ctl; 498 char ds[64], adir[64]; 499 500 /* get a udp port */ 501 snprint(ds, sizeof ds, "%s/udp!*!0", (mtpt? mtpt: "/net")); 502 ctl = announce(ds, adir); 503 if(ctl < 0){ 504 /* warning("can't get udp port"); */ 505 return -1; 506 } 507 508 /* turn on header style interface */ 509 if(write(ctl, hmsg, strlen(hmsg)) , 0){ 510 close(ctl); 511 warning(hmsg); 512 return -1; 513 } 514 515 /* grab the data file */ 516 snprint(ds, sizeof ds, "%s/data", adir); 517 fd = open(ds, ORDWR); 518 close(ctl); 519 if(fd < 0) 520 warning("can't open udp port %s: %r", ds); 521 return fd; 522 } 523 524 /* generate a DNS UDP query packet */ 525 int 526 mkreq(DN *dp, int type, uchar *buf, int flags, ushort reqno) 527 { 528 DNSmsg m; 529 int len; 530 Udphdr *uh = (Udphdr*)buf; 531 532 /* stuff port number into output buffer */ 533 memset(uh, 0, sizeof *uh); 534 hnputs(uh->rport, 53); 535 536 /* make request and convert it to output format */ 537 memset(&m, 0, sizeof m); 538 m.flags = flags; 539 m.id = reqno; 540 m.qd = rralloc(type); 541 m.qd->owner = dp; 542 m.qd->type = type; 543 if (m.qd->type != type) 544 dnslog("mkreq: bogus type %d", type); 545 len = convDNS2M(&m, &buf[Udphdrsize], Maxudp); 546 rrfree(m.qd); 547 return len; 548 } 549 550 /* for alarms in readreply */ 551 static void 552 ding(void*, char *msg) 553 { 554 if(strstr(msg, "alarm") != nil) 555 noted(NCONT); /* resume with system call error */ 556 else 557 noted(NDFLT); /* die */ 558 } 559 560 void 561 freeanswers(DNSmsg *mp) 562 { 563 rrfreelist(mp->qd); 564 rrfreelist(mp->an); 565 rrfreelist(mp->ns); 566 rrfreelist(mp->ar); 567 mp->qd = mp->an = mp->ns = mp->ar = nil; 568 } 569 570 /* sets srcip */ 571 static int 572 readnet(Query *qp, int medium, uchar *ibuf, ulong endtime, uchar **replyp, 573 uchar *srcip) 574 { 575 int len, fd; 576 long ms; 577 vlong startns = nsec(); 578 uchar *reply; 579 uchar lenbuf[2]; 580 581 /* timed read of reply */ 582 ms = S2MS(endtime) - NS2MS(startns); 583 if (ms < 2000) 584 ms = 2000; /* give the remote ns a fighting chance */ 585 reply = ibuf; 586 len = -1; /* pessimism */ 587 memset(srcip, 0, IPaddrlen); 588 if (medium == Udp) 589 if (qp->udpfd <= 0) 590 dnslog("readnet: qp->udpfd closed"); 591 else { 592 alarm(ms); 593 len = read(qp->udpfd, ibuf, Udphdrsize+Maxudpin); 594 alarm(0); 595 notestats(startns, len < 0, qp->type); 596 if (len >= IPaddrlen) 597 memmove(srcip, ibuf, IPaddrlen); 598 if (len >= Udphdrsize) { 599 len -= Udphdrsize; 600 reply += Udphdrsize; 601 } 602 } 603 else { 604 if (!qp->tcpset) 605 dnslog("readnet: tcp params not set"); 606 alarm(ms); 607 fd = qp->tcpfd; 608 if (fd <= 0) 609 dnslog("readnet: %s: tcp fd unset for dest %I", 610 qp->dp->name, qp->tcpip); 611 else if (readn(fd, lenbuf, 2) != 2) { 612 dnslog("readnet: short read of tcp size from %I", 613 qp->tcpip); 614 /* probably a time-out */ 615 notestats(startns, 1, qp->type); 616 } else { 617 len = lenbuf[0]<<8 | lenbuf[1]; 618 if (readn(fd, ibuf, len) != len) { 619 dnslog("readnet: short read of tcp data from %I", 620 qp->tcpip); 621 /* probably a time-out */ 622 notestats(startns, 1, qp->type); 623 len = -1; 624 } 625 } 626 alarm(0); 627 memmove(srcip, qp->tcpip, IPaddrlen); 628 } 629 *replyp = reply; 630 return len; 631 } 632 633 /* 634 * read replies to a request and remember the rrs in the answer(s). 635 * ignore any of the wrong type. 636 * wait at most until endtime. 637 */ 638 static int 639 readreply(Query *qp, int medium, ushort req, uchar *ibuf, DNSmsg *mp, 640 ulong endtime) 641 { 642 int len, rv; 643 char *err; 644 char tbuf[32]; 645 uchar *reply; 646 uchar srcip[IPaddrlen]; 647 RR *rp; 648 649 notify(ding); 650 651 queryck(qp); 652 rv = 0; 653 memset(mp, 0, sizeof *mp); 654 if (time(nil) >= endtime) 655 return -1; /* timed out before we started */ 656 657 memset(srcip, 0, sizeof srcip); 658 if (0) 659 len = -1; 660 for (; time(nil) < endtime && 661 (len = readnet(qp, medium, ibuf, endtime, &reply, srcip)) >= 0; 662 freeanswers(mp)){ 663 /* convert into internal format */ 664 memset(mp, 0, sizeof *mp); 665 err = convM2DNS(reply, len, mp, nil); 666 if (mp->flags & Ftrunc) { 667 free(err); 668 freeanswers(mp); 669 /* notify our caller to retry the query via tcp. */ 670 return -1; 671 } else if(err){ 672 dnslog("readreply: %s: input err, len %d: %s: %I", 673 qp->dp->name, len, err, srcip); 674 free(err); 675 continue; 676 } 677 if(debug) 678 logreply(qp->req->id, srcip, mp); 679 680 /* answering the right question? */ 681 if(mp->id != req) 682 dnslog("%d: id %d instead of %d: %I", qp->req->id, 683 mp->id, req, srcip); 684 else if(mp->qd == 0) 685 dnslog("%d: no question RR: %I", qp->req->id, srcip); 686 else if(mp->qd->owner != qp->dp) 687 dnslog("%d: owner %s instead of %s: %I", qp->req->id, 688 mp->qd->owner->name, qp->dp->name, srcip); 689 else if(mp->qd->type != qp->type) 690 dnslog("%d: qp->type %d instead of %d: %I", 691 qp->req->id, mp->qd->type, qp->type, srcip); 692 else { 693 /* remember what request this is in answer to */ 694 for(rp = mp->an; rp; rp = rp->next) 695 rp->query = qp->type; 696 return rv; 697 } 698 } 699 if (time(nil) >= endtime) { 700 ; /* query expired */ 701 } else if (0) { 702 /* this happens routinely when a read times out */ 703 dnslog("readreply: %s type %s: ns %I read error or eof " 704 "(returned %d): %r", qp->dp->name, rrname(qp->type, 705 tbuf, sizeof tbuf), srcip, len); 706 if (medium == Udp) 707 for (rp = qp->nsrp; rp != nil; rp = rp->next) 708 if (rp->type == Tns) 709 dnslog("readreply: %s: query sent to " 710 "ns %s", qp->dp->name, 711 rp->host->name); 712 } 713 return -1; 714 } 715 716 /* 717 * return non-0 if first list includes second list 718 */ 719 int 720 contains(RR *rp1, RR *rp2) 721 { 722 RR *trp1, *trp2; 723 724 for(trp2 = rp2; trp2; trp2 = trp2->next){ 725 for(trp1 = rp1; trp1; trp1 = trp1->next) 726 if(trp1->type == trp2->type) 727 if(trp1->host == trp2->host) 728 if(trp1->owner == trp2->owner) 729 break; 730 if(trp1 == nil) 731 return 0; 732 } 733 return 1; 734 } 735 736 737 /* 738 * return multicast version if any 739 */ 740 int 741 ipisbm(uchar *ip) 742 { 743 if(isv4(ip)){ 744 if (ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0 || 745 ipcmp(ip, IPv4bcast) == 0) 746 return 4; 747 } else 748 if(ip[0] == 0xff) 749 return 6; 750 return 0; 751 } 752 753 /* 754 * Get next server address 755 */ 756 static int 757 serveraddrs(Query *qp, int nd, int depth) 758 { 759 RR *rp, *arp, *trp; 760 Dest *cur; 761 762 if(nd >= Maxdest) 763 return 0; 764 765 /* 766 * look for a server whose address we already know. 767 * if we find one, mark it so we ignore this on 768 * subsequent passes. 769 */ 770 arp = 0; 771 for(rp = qp->nsrp; rp; rp = rp->next){ 772 assert(rp->magic == RRmagic); 773 if(rp->marker) 774 continue; 775 arp = rrlookup(rp->host, Ta, NOneg); 776 if(arp){ 777 rp->marker = 1; 778 break; 779 } 780 arp = dblookup(rp->host->name, Cin, Ta, 0, 0); 781 if(arp){ 782 rp->marker = 1; 783 break; 784 } 785 } 786 787 /* 788 * if the cache and database lookup didn't find any new 789 * server addresses, try resolving one via the network. 790 * Mark any we try to resolve so we don't try a second time. 791 */ 792 if(arp == 0) 793 for(rp = qp->nsrp; rp; rp = rp->next){ 794 if(rp->marker) 795 continue; 796 rp->marker = 1; 797 798 /* 799 * avoid loops looking up a server under itself 800 */ 801 if(subsume(rp->owner->name, rp->host->name)) 802 continue; 803 804 arp = dnresolve(rp->host->name, Cin, Ta, qp->req, 0, 805 depth+1, Recurse, 1, 0); 806 rrfreelist(rrremneg(&arp)); 807 if(arp) 808 break; 809 } 810 811 /* use any addresses that we found */ 812 for(trp = arp; trp && nd < Maxdest; trp = trp->next){ 813 cur = &qp->dest[nd]; 814 parseip(cur->a, trp->ip->name); 815 /* 816 * straddling servers can reject all nameservers if they are all 817 * inside, so be sure to list at least one outside ns at 818 * the end of the ns list in /lib/ndb for `dom='. 819 */ 820 if (ipisbm(cur->a) || 821 cfg.straddle && !insideaddr(qp->dp->name) && insidens(cur->a)) 822 continue; 823 cur->nx = 0; 824 cur->s = trp->owner; 825 cur->code = Rtimeout; 826 nd++; 827 } 828 rrfreelist(arp); 829 return nd; 830 } 831 832 /* 833 * cache negative responses 834 */ 835 static void 836 cacheneg(DN *dp, int type, int rcode, RR *soarr) 837 { 838 RR *rp; 839 DN *soaowner; 840 ulong ttl; 841 842 stats.negcached++; 843 844 /* no cache time specified, don't make anything up */ 845 if(soarr != nil){ 846 if(soarr->next != nil){ 847 rrfreelist(soarr->next); 848 soarr->next = nil; 849 } 850 soaowner = soarr->owner; 851 } else 852 soaowner = nil; 853 854 /* the attach can cause soarr to be freed so mine it now */ 855 if(soarr != nil && soarr->soa != nil) 856 ttl = soarr->soa->minttl+now; 857 else 858 ttl = 5*Min; 859 860 /* add soa and negative RR to the database */ 861 rrattach(soarr, Authoritative); 862 863 rp = rralloc(type); 864 rp->owner = dp; 865 rp->negative = 1; 866 rp->negsoaowner = soaowner; 867 rp->negrcode = rcode; 868 rp->ttl = ttl; 869 rrattach(rp, Authoritative); 870 } 871 872 static int 873 setdestoutns(Dest *p, int n) 874 { 875 uchar *outns = outsidens(n); 876 877 destck(p); 878 destinit(p); 879 if (outns == nil) { 880 if (n == 0) 881 dnslog("[%d] no outside-ns in ndb", getpid()); 882 return -1; 883 } 884 memmove(p->a, outns, sizeof p->a); 885 p->s = dnlookup("outside-ns-ips", Cin, 1); 886 return 0; 887 } 888 889 /* 890 * issue query via UDP or TCP as appropriate. 891 * for TCP, returns with qp->tcpip set from udppkt header. 892 */ 893 static int 894 mydnsquery(Query *qp, int medium, uchar *udppkt, int len) 895 { 896 int rv = -1, nfd; 897 char *domain; 898 char conndir[40]; 899 uchar belen[2]; 900 NetConnInfo *nci; 901 902 queryck(qp); 903 domain = smprint("%I", udppkt); 904 if (myaddr(domain)) { 905 dnslog("mydnsquery: trying to send to myself (%s); bzzzt", 906 domain); 907 free(domain); 908 return rv; 909 } 910 911 switch (medium) { 912 case Udp: 913 free(domain); 914 nfd = dup(qp->udpfd, -1); 915 if (nfd < 0) { 916 warning("mydnsquery: qp->udpfd %d: %r", qp->udpfd); 917 close(qp->udpfd); /* ensure it's closed */ 918 qp->udpfd = -1; /* poison it */ 919 return rv; 920 } 921 close(nfd); 922 923 if (qp->udpfd <= 0) 924 dnslog("mydnsquery: qp->udpfd %d closed", qp->udpfd); 925 else { 926 if (write(qp->udpfd, udppkt, len+Udphdrsize) != 927 len+Udphdrsize) 928 warning("sending udp msg: %r"); 929 else { 930 stats.qsent++; 931 rv = 0; 932 } 933 } 934 break; 935 case Tcp: 936 /* send via TCP & keep fd around for reply */ 937 alarm(10*1000); 938 qp->tcpfd = rv = dial(netmkaddr(domain, "tcp", "dns"), nil, 939 conndir, &qp->tcpctlfd); 940 alarm(0); 941 if (qp->tcpfd < 0) { 942 dnslog("can't dial tcp!%s!dns: %r", domain); 943 free(domain); 944 break; 945 } 946 free(domain); 947 nci = getnetconninfo(conndir, qp->tcpfd); 948 if (nci) { 949 parseip(qp->tcpip, nci->rsys); 950 freenetconninfo(nci); 951 } else 952 dnslog("mydnsquery: getnetconninfo failed"); 953 qp->tcpset = 1; 954 955 belen[0] = len >> 8; 956 belen[1] = len; 957 if (write(qp->tcpfd, belen, 2) != 2 || 958 write(qp->tcpfd, udppkt + Udphdrsize, len) != len) 959 warning("sending tcp msg: %r"); 960 break; 961 default: 962 sysfatal("mydnsquery: bad medium"); 963 } 964 return rv; 965 } 966 967 /* 968 * send query to all UDP destinations or one TCP destination, 969 * taken from obuf (udp packet) header 970 */ 971 static int 972 xmitquery(Query *qp, int medium, int depth, uchar *obuf, int inns, int len) 973 { 974 int j, n; 975 char buf[32]; 976 Dest *p; 977 978 queryck(qp); 979 if(time(nil) >= qp->req->aborttime) 980 return -1; 981 982 /* 983 * get a nameserver address if we need one. 984 * serveraddrs populates qp->dest. 985 */ 986 p = qp->dest; 987 destck(p); 988 if (qp->ndest < 0 || qp->ndest > Maxdest) 989 dnslog("qp->ndest %d out of range", qp->ndest); 990 if (qp->ndest > qp->curdest - p) 991 qp->curdest = &qp->dest[serveraddrs(qp, qp->curdest - p, depth)]; 992 destck(qp->curdest); 993 994 /* no servers, punt */ 995 if (qp->curdest == qp->dest) 996 if (cfg.straddle && cfg.inside) { 997 /* get ips of "outside-ns-ips" */ 998 p = qp->curdest = qp->dest; 999 for(n = 0; n < Maxdest; n++, qp->curdest++) 1000 if (setdestoutns(qp->curdest, n) < 0) 1001 break; 1002 } else { 1003 /* it's probably just a bogus domain, don't log it */ 1004 // dnslog("xmitquery: %s: no nameservers", qp->dp->name); 1005 return -1; 1006 } 1007 1008 /* send to first 'qp->ndest' destinations */ 1009 j = 0; 1010 if (medium == Tcp) { 1011 j++; 1012 queryck(qp); 1013 assert(qp->dp); 1014 procsetname("tcp %sside query for %s %s", (inns? "in": "out"), 1015 qp->dp->name, rrname(qp->type, buf, sizeof buf)); 1016 mydnsquery(qp, medium, obuf, len); /* sets qp->tcpip from obuf */ 1017 if(debug) 1018 logsend(qp->req->id, depth, qp->tcpip, "", qp->dp->name, 1019 qp->type); 1020 } else 1021 for(; p < &qp->dest[qp->ndest] && p < qp->curdest; p++){ 1022 /* skip destinations we've finished with */ 1023 if(p->nx >= Maxtrans) 1024 continue; 1025 1026 j++; 1027 1028 /* exponential backoff of requests */ 1029 if((1<<p->nx) > qp->ndest) 1030 continue; 1031 1032 procsetname("udp %sside query to %I/%s %s %s", 1033 (inns? "in": "out"), p->a, p->s->name, 1034 qp->dp->name, rrname(qp->type, buf, sizeof buf)); 1035 if(debug) 1036 logsend(qp->req->id, depth, p->a, p->s->name, 1037 qp->dp->name, qp->type); 1038 1039 /* fill in UDP destination addr & send it */ 1040 memmove(obuf, p->a, sizeof p->a); 1041 mydnsquery(qp, medium, obuf, len); 1042 p->nx++; 1043 } 1044 if(j == 0) { 1045 // dnslog("xmitquery: %s: no destinations left", qp->dp->name); 1046 return -1; 1047 } 1048 return 0; 1049 } 1050 1051 static int lckindex[Maxlcks] = { 1052 0, /* all others map here */ 1053 Ta, 1054 Tns, 1055 Tcname, 1056 Tsoa, 1057 Tptr, 1058 Tmx, 1059 Ttxt, 1060 Taaaa, 1061 }; 1062 1063 static int 1064 qtype2lck(int qtype) /* map query type to querylck index */ 1065 { 1066 int i; 1067 1068 for (i = 1; i < nelem(lckindex); i++) 1069 if (lckindex[i] == qtype) 1070 return i; 1071 return 0; 1072 } 1073 1074 /* is mp a cachable negative response (with Rname set)? */ 1075 static int 1076 isnegrname(DNSmsg *mp) 1077 { 1078 /* TODO: could add || cfg.justforw to RHS of && */ 1079 return mp->an == nil && (mp->flags & Rmask) == Rname; 1080 } 1081 1082 static int 1083 procansw(Query *qp, DNSmsg *mp, uchar *srcip, int depth, Dest *p) 1084 { 1085 int rv; 1086 // int lcktype; 1087 char buf[32]; 1088 DN *ndp; 1089 Query *nqp; 1090 RR *tp, *soarr; 1091 1092 if (mp->an == nil) 1093 stats.negans++; 1094 1095 /* ignore any error replies */ 1096 if((mp->flags & Rmask) == Rserver){ 1097 stats.negserver++; 1098 freeanswers(mp); 1099 if(p != qp->curdest) 1100 p->code = Rserver; 1101 return -1; 1102 } 1103 1104 /* ignore any bad delegations */ 1105 if(mp->ns && baddelegation(mp->ns, qp->nsrp, srcip)){ 1106 stats.negbaddeleg++; 1107 if(mp->an == nil){ 1108 stats.negbdnoans++; 1109 freeanswers(mp); 1110 if(p != qp->curdest) 1111 p->code = Rserver; 1112 return -1; 1113 } 1114 rrfreelist(mp->ns); 1115 mp->ns = nil; 1116 } 1117 1118 /* remove any soa's from the authority section */ 1119 soarr = rrremtype(&mp->ns, Tsoa); 1120 1121 /* incorporate answers */ 1122 unique(mp->an); 1123 unique(mp->ns); 1124 unique(mp->ar); 1125 if(mp->an) 1126 rrattach(mp->an, (mp->flags & Fauth) != 0); 1127 if(mp->ar) 1128 rrattach(mp->ar, Notauthoritative); 1129 if(mp->ns && !cfg.justforw){ 1130 ndp = mp->ns->owner; 1131 rrattach(mp->ns, Notauthoritative); 1132 } else { 1133 ndp = nil; 1134 rrfreelist(mp->ns); 1135 mp->ns = nil; 1136 } 1137 1138 /* free the question */ 1139 if(mp->qd) { 1140 rrfreelist(mp->qd); 1141 mp->qd = nil; 1142 } 1143 1144 /* 1145 * Any reply from an authoritative server, 1146 * or a positive reply terminates the search. 1147 * A negative response now also terminates the search. 1148 */ 1149 if(mp->an != nil || (mp->flags & Fauth)){ 1150 if(isnegrname(mp)) 1151 qp->dp->respcode = Rname; 1152 else 1153 qp->dp->respcode = 0; 1154 1155 /* 1156 * cache any negative responses, free soarr. 1157 * negative responses need not be authoritative: 1158 * they can legitimately come from a cache. 1159 */ 1160 if( /* (mp->flags & Fauth) && */ mp->an == nil) 1161 cacheneg(qp->dp, qp->type, (mp->flags & Rmask), soarr); 1162 else 1163 rrfreelist(soarr); 1164 return 1; 1165 } else if (isnegrname(mp)) { 1166 qp->dp->respcode = Rname; 1167 /* 1168 * cache negative response. 1169 * negative responses need not be authoritative: 1170 * they can legitimately come from a cache. 1171 */ 1172 cacheneg(qp->dp, qp->type, (mp->flags & Rmask), soarr); 1173 return 1; 1174 } 1175 stats.negnorname++; 1176 rrfreelist(soarr); 1177 1178 /* 1179 * if we've been given better name servers, recurse. 1180 * if we're a pure resolver, don't recurse, we have 1181 * to forward to a fixed set of named servers. 1182 */ 1183 if(!mp->ns || cfg.resolver && cfg.justforw) 1184 return 0; 1185 tp = rrlookup(ndp, Tns, NOneg); 1186 if(contains(qp->nsrp, tp)){ 1187 rrfreelist(tp); 1188 return 0; 1189 } 1190 procsetname("recursive query for %s %s", qp->dp->name, 1191 rrname(qp->type, buf, sizeof buf)); 1192 /* 1193 * we're called from udpquery, called from 1194 * netquery, which current holds qp->dp->querylck, 1195 * so release it now and acquire it upon return. 1196 */ 1197 // lcktype = qtype2lck(qp->type); 1198 // qunlock(&qp->dp->querylck[lcktype]); 1199 1200 nqp = emalloc(sizeof *nqp); 1201 queryinit(nqp, qp->dp, qp->type, qp->req); 1202 nqp->nsrp = tp; 1203 rv = netquery(nqp, depth+1); 1204 1205 // qlock(&qp->dp->querylck[lcktype]); 1206 rrfreelist(nqp->nsrp); 1207 querydestroy(nqp); 1208 free(nqp); 1209 return rv; 1210 } 1211 1212 /* 1213 * send a query via tcp to a single address (from ibuf's udp header) 1214 * and read the answer(s) into mp->an. 1215 */ 1216 static int 1217 tcpquery(Query *qp, DNSmsg *mp, int depth, uchar *ibuf, uchar *obuf, int len, 1218 int waitsecs, int inns, ushort req) 1219 { 1220 int rv = 0; 1221 ulong endtime; 1222 1223 endtime = time(nil) + waitsecs; 1224 if(endtime > qp->req->aborttime) 1225 endtime = qp->req->aborttime; 1226 1227 if (0) 1228 dnslog("%s: udp reply truncated; retrying query via tcp to %I", 1229 qp->dp->name, qp->tcpip); 1230 1231 qlock(&qp->tcplock); 1232 memmove(obuf, ibuf, IPaddrlen); /* send back to respondent */ 1233 /* sets qp->tcpip from obuf's udp header */ 1234 if (xmitquery(qp, Tcp, depth, obuf, inns, len) < 0 || 1235 readreply(qp, Tcp, req, ibuf, mp, endtime) < 0) 1236 rv = -1; 1237 if (qp->tcpfd > 0) { 1238 hangup(qp->tcpctlfd); 1239 close(qp->tcpctlfd); 1240 close(qp->tcpfd); 1241 } 1242 qp->tcpfd = qp->tcpctlfd = -1; 1243 qunlock(&qp->tcplock); 1244 return rv; 1245 } 1246 1247 /* 1248 * query name servers. If the name server returns a pointer to another 1249 * name server, recurse. 1250 */ 1251 static int 1252 queryns(Query *qp, int depth, uchar *ibuf, uchar *obuf, int waitsecs, int inns) 1253 { 1254 int ndest, len, replywaits, rv; 1255 ushort req; 1256 ulong endtime; 1257 char buf[12]; 1258 uchar srcip[IPaddrlen]; 1259 Dest *p, *np, *dest; 1260 // Dest dest[Maxdest]; 1261 1262 /* pack request into a udp message */ 1263 req = rand(); 1264 len = mkreq(qp->dp, qp->type, obuf, Frecurse|Oquery, req); 1265 1266 /* no server addresses yet */ 1267 queryck(qp); 1268 dest = emalloc(Maxdest * sizeof *dest); /* dest can't be on stack */ 1269 for (p = dest; p < dest + Maxdest; p++) 1270 destinit(p); 1271 /* this dest array is local to this call of queryns() */ 1272 free(qp->dest); 1273 qp->curdest = qp->dest = dest; 1274 1275 /* 1276 * transmit udp requests and wait for answers. 1277 * at most Maxtrans attempts to each address. 1278 * each cycle send one more message than the previous. 1279 * retry a query via tcp if its response is truncated. 1280 */ 1281 for(ndest = 1; ndest < Maxdest; ndest++){ 1282 qp->ndest = ndest; 1283 qp->tcpset = 0; 1284 if (xmitquery(qp, Udp, depth, obuf, inns, len) < 0) 1285 break; 1286 1287 endtime = time(nil) + waitsecs; 1288 if(endtime > qp->req->aborttime) 1289 endtime = qp->req->aborttime; 1290 1291 for(replywaits = 0; replywaits < ndest; replywaits++){ 1292 DNSmsg m; 1293 1294 procsetname("reading %sside reply from %I: %s %s from %s", 1295 (inns? "in": "out"), obuf, qp->dp->name, 1296 rrname(qp->type, buf, sizeof buf), qp->req->from); 1297 1298 /* read udp answer into m */ 1299 if (readreply(qp, Udp, req, ibuf, &m, endtime) >= 0) 1300 memmove(srcip, ibuf, IPaddrlen); 1301 else if (!(m.flags & Ftrunc)) { 1302 freeanswers(&m); 1303 break; /* timed out on this dest */ 1304 } else { 1305 /* whoops, it was truncated! ask again via tcp */ 1306 rv = tcpquery(qp, &m, depth, ibuf, obuf, len, 1307 waitsecs, inns, req); /* answer in m */ 1308 if (rv < 0) { 1309 freeanswers(&m); 1310 break; /* failed via tcp too */ 1311 } 1312 memmove(srcip, qp->tcpip, IPaddrlen); 1313 } 1314 1315 /* find responder */ 1316 // dnslog("queryns got reply from %I", srcip); 1317 for(p = qp->dest; p < qp->curdest; p++) 1318 if(memcmp(p->a, srcip, sizeof p->a) == 0) 1319 break; 1320 1321 /* remove all addrs of responding server from list */ 1322 for(np = qp->dest; np < qp->curdest; np++) 1323 if(np->s == p->s) 1324 p->nx = Maxtrans; 1325 1326 /* free or incorporate RRs in m */ 1327 rv = procansw(qp, &m, srcip, depth, p); 1328 if (rv > 0) { 1329 free(qp->dest); 1330 qp->dest = qp->curdest = nil; /* prevent accidents */ 1331 return rv; 1332 } 1333 } 1334 } 1335 1336 /* if all servers returned failure, propagate it */ 1337 qp->dp->respcode = Rserver; 1338 for(p = dest; p < qp->curdest; p++) { 1339 destck(p); 1340 if(p->code != Rserver) 1341 qp->dp->respcode = 0; 1342 p->magic = 0; /* prevent accidents */ 1343 } 1344 1345 // if (qp->dp->respcode) 1346 // dnslog("queryns setting Rserver for %s", qp->dp->name); 1347 1348 free(qp->dest); 1349 qp->dest = qp->curdest = nil; /* prevent accidents */ 1350 return 0; 1351 } 1352 1353 /* 1354 * run a command with a supplied fd as standard input 1355 */ 1356 char * 1357 system(int fd, char *cmd) 1358 { 1359 int pid, p, i; 1360 static Waitmsg msg; 1361 1362 if((pid = fork()) == -1) 1363 sysfatal("fork failed: %r"); 1364 else if(pid == 0){ 1365 dup(fd, 0); 1366 close(fd); 1367 for (i = 3; i < 200; i++) 1368 close(i); /* don't leak fds */ 1369 execl("/bin/rc", "rc", "-c", cmd, nil); 1370 sysfatal("exec rc: %r"); 1371 } 1372 for(p = waitpid(); p >= 0; p = waitpid()) 1373 if(p == pid) 1374 return msg.msg; 1375 return "lost child"; 1376 } 1377 1378 /* compute wait, weighted by probability of success, with minimum */ 1379 static ulong 1380 weight(ulong ms, unsigned pcntprob) 1381 { 1382 ulong wait; 1383 1384 wait = (ms * pcntprob) / 100; 1385 if (wait < 1500) 1386 wait = 1500; 1387 return wait; 1388 } 1389 1390 /* 1391 * in principle we could use a single descriptor for a udp port 1392 * to send all queries and receive all the answers to them, 1393 * but we'd have to sort out the answers by dns-query id. 1394 */ 1395 static int 1396 udpquery(Query *qp, char *mntpt, int depth, int patient, int inns) 1397 { 1398 int fd, rv; 1399 long now; 1400 ulong pcntprob, wait, reqtm; 1401 char *msg; 1402 uchar *obuf, *ibuf; 1403 static QLock mntlck; 1404 static ulong lastmount; 1405 1406 /* use alloced buffers rather than ones from the stack */ 1407 // ibuf = emalloc(Maxudpin+Udphdrsize); 1408 ibuf = emalloc(64*1024); /* max. tcp reply size */ 1409 obuf = emalloc(Maxudp+Udphdrsize); 1410 1411 fd = udpport(mntpt); 1412 while (fd < 0 && cfg.straddle && strcmp(mntpt, "/net.alt") == 0) { 1413 /* HACK: remount /net.alt */ 1414 now = time(nil); 1415 if (now < lastmount + Remntretry) 1416 sleep((lastmount + Remntretry - now)*1000); 1417 qlock(&mntlck); 1418 fd = udpport(mntpt); /* try again under lock */ 1419 if (fd < 0) { 1420 dnslog("[%d] remounting /net.alt", getpid()); 1421 unmount(nil, "/net.alt"); 1422 1423 msg = system(open("/dev/null", ORDWR), "outside"); 1424 1425 lastmount = time(nil); 1426 if (msg && *msg) { 1427 dnslog("[%d] can't remount /net.alt: %s", 1428 getpid(), msg); 1429 sleep(10*1000); /* don't spin wildly */ 1430 } else 1431 fd = udpport(mntpt); 1432 } 1433 qunlock(&mntlck); 1434 } 1435 if (fd < 0) { 1436 dnslog("can't get udpport for %s query of name %s: %r", 1437 mntpt, qp->dp->name); 1438 sysfatal("out of udp conversations"); /* we're buggered */ 1439 } 1440 1441 /* 1442 * Our QIP servers are busted, don't answer AAAA and 1443 * take forever to answer CNAME if there isn't one. 1444 * They rarely set Rname. 1445 * make time-to-wait proportional to estimated probability of an 1446 * RR of that type existing. 1447 */ 1448 if (qp->type >= nelem(likely)) 1449 pcntprob = 35; /* unpopular query type */ 1450 else 1451 pcntprob = likely[qp->type]; 1452 reqtm = (patient? 2*Maxreqtm: Maxreqtm); 1453 /* time for a single outgoing udp query */ 1454 wait = weight(S2MS(reqtm)/3, pcntprob); 1455 qp->req->aborttime = time(nil) + MS2S(3*wait); /* for all udp queries */ 1456 1457 qp->udpfd = fd; 1458 rv = queryns(qp, depth, ibuf, obuf, MS2S(wait), inns); 1459 close(fd); 1460 qp->udpfd = -1; 1461 1462 free(obuf); 1463 free(ibuf); 1464 return rv; 1465 } 1466 1467 /* look up (qp->dp->name,qp->type) rr in dns, via *nsrp with results in *reqp */ 1468 static int 1469 netquery(Query *qp, int depth) 1470 { 1471 int lock, rv, triedin, inname, cnt; 1472 // char buf[32]; 1473 RR *rp; 1474 DN *dp; 1475 Querylck *qlp; 1476 static int whined; 1477 1478 rv = 0; /* pessimism */ 1479 if(depth > 12) /* in a recursive loop? */ 1480 return 0; 1481 1482 slave(qp->req); 1483 /* 1484 * slave might have forked. if so, the parent process longjmped to 1485 * req->mret; we're usually the child slave, but if there are too 1486 * many children already, we're still the same process. 1487 */ 1488 1489 /* 1490 * don't lock before call to slave so only children can block. 1491 * just lock at top-level invocation. 1492 */ 1493 lock = depth <= 1 && qp->req->isslave; 1494 dp = qp->dp; /* ensure that it doesn't change underfoot */ 1495 qlp = nil; 1496 if(lock) { 1497 // procsetname("query lock wait: %s %s from %s", dp->name, 1498 // rrname(qp->type, buf, sizeof buf), qp->req->from); 1499 /* 1500 * don't make concurrent queries for this name. 1501 * dozens of processes blocking here probably indicates 1502 * an error in our dns data that causes us to not 1503 * recognise a zone (area) as one of our own, thus 1504 * causing us to query other nameservers. 1505 */ 1506 qlp = &dp->querylck[qtype2lck(qp->type)]; 1507 incref(qlp); 1508 qlock(qlp); 1509 cnt = qlp->Ref.ref; 1510 qunlock(qlp); 1511 if (cnt > 10) { 1512 decref(qlp); 1513 if (!whined) { 1514 whined = 1; 1515 dnslog("too many outstanding queries for %s; " 1516 "dropping this one; " 1517 "no further logging of drops", 1518 dp->name); 1519 } 1520 return 0; 1521 } 1522 } 1523 procsetname("netquery: %s", dp->name); 1524 1525 /* prepare server RR's for incremental lookup */ 1526 for(rp = qp->nsrp; rp; rp = rp->next) 1527 rp->marker = 0; 1528 1529 triedin = 0; 1530 1531 /* 1532 * normal resolvers and servers will just use mntpt for all addresses, 1533 * even on the outside. straddling servers will use mntpt (/net) 1534 * for inside addresses and /net.alt for outside addresses, 1535 * thus bypassing other inside nameservers. 1536 */ 1537 inname = insideaddr(dp->name); 1538 if (!cfg.straddle || inname) { 1539 rv = udpquery(qp, mntpt, depth, Hurry, (cfg.inside? Inns: Outns)); 1540 triedin = 1; 1541 } 1542 1543 /* 1544 * if we're still looking, are inside, and have an outside domain, 1545 * try it on our outside interface, if any. 1546 */ 1547 if (rv == 0 && cfg.inside && !inname) { 1548 if (triedin) 1549 dnslog( 1550 "[%d] netquery: internal nameservers failed for %s; trying external", 1551 getpid(), dp->name); 1552 1553 /* prepare server RR's for incremental lookup */ 1554 for(rp = qp->nsrp; rp; rp = rp->next) 1555 rp->marker = 0; 1556 1557 rv = udpquery(qp, "/net.alt", depth, Patient, Outns); 1558 } 1559 // if (rv == 0) /* could ask /net.alt/dns directly */ 1560 // askoutdns(dp, qp->type); 1561 1562 if(lock && qlp) 1563 decref(qlp); 1564 return rv; 1565 } 1566 1567 int 1568 seerootns(void) 1569 { 1570 int rv; 1571 char root[] = ""; 1572 Request req; 1573 Query *qp; 1574 1575 memset(&req, 0, sizeof req); 1576 req.isslave = 1; 1577 req.aborttime = now + Maxreqtm; 1578 req.from = "internal"; 1579 qp = emalloc(sizeof *qp); 1580 queryinit(qp, dnlookup(root, Cin, 1), Tns, &req); 1581 1582 qp->nsrp = dblookup(root, Cin, Tns, 0, 0); 1583 rv = netquery(qp, 0); 1584 1585 rrfreelist(qp->nsrp); 1586 querydestroy(qp); 1587 free(qp); 1588 return rv; 1589 } 1590