1 #include <u.h> 2 #include <libc.h> 3 #include "dns.h" 4 #include "ip.h" 5 6 enum 7 { 8 Maxdest= 24, /* maximum destinations for a request message */ 9 Maxtrans= 3, /* maximum transmissions to a server */ 10 }; 11 12 static int netquery(DN*, int, RR*, Request*, int); 13 static RR* dnresolve1(char*, int, int, Request*, int, int); 14 15 char *LOG = "dns"; 16 17 /* 18 * reading /proc/pid/args yields either "name" or "name [display args]", 19 * so return only display args, if any. 20 */ 21 static char * 22 procgetname(void) 23 { 24 int fd, n; 25 char *lp, *rp; 26 char buf[256]; 27 28 snprint(buf, sizeof buf, "#p/%d/args", getpid()); 29 if((fd = open(buf, OREAD)) < 0) 30 return strdup(""); 31 *buf = '\0'; 32 n = read(fd, buf, sizeof buf-1); 33 close(fd); 34 if (n >= 0) 35 buf[n] = '\0'; 36 if ((lp = strchr(buf, '[')) == nil || 37 (rp = strrchr(buf, ']')) == nil) 38 return strdup(""); 39 *rp = '\0'; 40 return strdup(lp+1); 41 } 42 43 /* 44 * lookup 'type' info for domain name 'name'. If it doesn't exist, try 45 * looking it up as a canonical name. 46 */ 47 RR* 48 dnresolve(char *name, int class, int type, Request *req, RR **cn, int depth, 49 int recurse, int rooted, int *status) 50 { 51 RR *rp, *nrp, *drp; 52 DN *dp; 53 int loops; 54 char *procname; 55 char nname[Domlen]; 56 57 if(status) 58 *status = 0; 59 60 procname = procgetname(); 61 /* 62 * hack for systems that don't have resolve search 63 * lists. Just look up the simple name in the database. 64 */ 65 if(!rooted && strchr(name, '.') == 0){ 66 rp = nil; 67 drp = domainlist(class); 68 for(nrp = drp; nrp != nil; nrp = nrp->next){ 69 snprint(nname, sizeof nname, "%s.%s", name, 70 nrp->ptr->name); 71 rp = dnresolve(nname, class, type, req, cn, depth, 72 recurse, rooted, status); 73 rrfreelist(rrremneg(&rp)); 74 if(rp != nil) 75 break; 76 } 77 if(drp != nil) 78 rrfree(drp); 79 procsetname(procname); 80 free(procname); 81 return rp; 82 } 83 84 /* 85 * try the name directly 86 */ 87 rp = dnresolve1(name, class, type, req, depth, recurse); 88 if(rp) { 89 procsetname(procname); 90 free(procname); 91 return randomize(rp); 92 } 93 94 /* try it as a canonical name if we weren't told the name didn't exist */ 95 dp = dnlookup(name, class, 0); 96 if(type != Tptr && dp->nonexistent != Rname) 97 for(loops=0; rp == nil && loops < 32; loops++){ 98 rp = dnresolve1(name, class, Tcname, req, depth, recurse); 99 if(rp == nil) 100 break; 101 102 if(rp->negative){ 103 rrfreelist(rp); 104 rp = nil; 105 break; 106 } 107 108 name = rp->host->name; 109 if(cn) 110 rrcat(cn, rp); 111 else 112 rrfreelist(rp); 113 114 rp = dnresolve1(name, class, type, req, depth, recurse); 115 } 116 117 /* distinction between not found and not good */ 118 if(rp == nil && status != nil && dp->nonexistent != 0) 119 *status = dp->nonexistent; 120 121 procsetname(procname); 122 free(procname); 123 return randomize(rp); 124 } 125 126 static RR* 127 dnresolve1(char *name, int class, int type, Request *req, int depth, 128 int recurse) 129 { 130 DN *dp, *nsdp; 131 RR *rp, *nsrp, *dbnsrp; 132 char *cp; 133 134 if(debug) 135 syslog(0, LOG, "[%d] dnresolve1 %s %d %d", 136 getpid(), name, type, class); 137 138 /* only class Cin implemented so far */ 139 if(class != Cin) 140 return nil; 141 142 dp = dnlookup(name, class, 1); 143 144 /* 145 * Try the cache first 146 */ 147 rp = rrlookup(dp, type, OKneg); 148 if(rp) 149 if(rp->db){ 150 /* unauthenticated db entries are hints */ 151 if(rp->auth) 152 return rp; 153 } else 154 /* cached entry must still be valid */ 155 if(rp->ttl > now) 156 /* but Tall entries are special */ 157 if(type != Tall || rp->query == Tall) 158 return rp; 159 160 rrfreelist(rp); 161 162 /* 163 * try the cache for a canonical name. if found punt 164 * since we'll find it during the canonical name search 165 * in dnresolve(). 166 */ 167 if(type != Tcname){ 168 rp = rrlookup(dp, Tcname, NOneg); 169 rrfreelist(rp); 170 if(rp) 171 return nil; 172 } 173 174 /* 175 * if we're running as just a resolver, go to our 176 * designated name servers 177 */ 178 if(resolver){ 179 nsrp = randomize(getdnsservers(class)); 180 if(nsrp != nil) { 181 if(netquery(dp, type, nsrp, req, depth+1)){ 182 rrfreelist(nsrp); 183 return rrlookup(dp, type, OKneg); 184 } 185 rrfreelist(nsrp); 186 } 187 } 188 189 /* 190 * walk up the domain name looking for 191 * a name server for the domain. 192 */ 193 for(cp = name; cp; cp = walkup(cp)){ 194 /* 195 * if this is a local (served by us) domain, 196 * return answer 197 */ 198 dbnsrp = randomize(dblookup(cp, class, Tns, 0, 0)); 199 if(dbnsrp && dbnsrp->local){ 200 rp = dblookup(name, class, type, 1, dbnsrp->ttl); 201 rrfreelist(dbnsrp); 202 return rp; 203 } 204 205 /* 206 * if recursion isn't set, just accept local 207 * entries 208 */ 209 if(recurse == Dontrecurse){ 210 if(dbnsrp) 211 rrfreelist(dbnsrp); 212 continue; 213 } 214 215 /* look for ns in cache */ 216 nsdp = dnlookup(cp, class, 0); 217 nsrp = nil; 218 if(nsdp) 219 nsrp = randomize(rrlookup(nsdp, Tns, NOneg)); 220 221 /* if the entry timed out, ignore it */ 222 if(nsrp && nsrp->ttl < now){ 223 rrfreelist(nsrp); 224 nsrp = nil; 225 } 226 227 if(nsrp){ 228 rrfreelist(dbnsrp); 229 230 /* try the name servers found in cache */ 231 if(netquery(dp, type, nsrp, req, depth+1)){ 232 rrfreelist(nsrp); 233 return rrlookup(dp, type, OKneg); 234 } 235 rrfreelist(nsrp); 236 continue; 237 } 238 239 /* use ns from db */ 240 if(dbnsrp){ 241 /* try the name servers found in db */ 242 if(netquery(dp, type, dbnsrp, req, depth+1)){ 243 /* we got an answer */ 244 rrfreelist(dbnsrp); 245 return rrlookup(dp, type, NOneg); 246 } 247 rrfreelist(dbnsrp); 248 } 249 } 250 251 /* settle for a non-authoritative answer */ 252 rp = rrlookup(dp, type, OKneg); 253 if(rp) 254 return rp; 255 256 /* noone answered. try the database, we might have a chance. */ 257 return dblookup(name, class, type, 0, 0); 258 } 259 260 /* 261 * walk a domain name one element to the right. 262 * return a pointer to that element. 263 * in other words, return a pointer to the parent domain name. 264 */ 265 char* 266 walkup(char *name) 267 { 268 char *cp; 269 270 cp = strchr(name, '.'); 271 if(cp) 272 return cp+1; 273 else if(*name) 274 return ""; 275 else 276 return 0; 277 } 278 279 /* 280 * Get a udpport for requests and replies. Put the port 281 * into "headers" mode. 282 */ 283 static char *hmsg = "headers"; 284 static char *ohmsg = "oldheaders"; 285 286 int 287 udpport(void) 288 { 289 int fd, ctl; 290 char ds[64], adir[64]; 291 292 /* get a udp port */ 293 snprint(ds, sizeof(ds), "%s/udp!*!0", mntpt); 294 ctl = announce(ds, adir); 295 if(ctl < 0){ 296 /* warning("can't get udp port"); */ 297 return -1; 298 } 299 300 /* turn on header style interface */ 301 if(write(ctl, hmsg, strlen(hmsg)) , 0){ 302 close(ctl); 303 warning(hmsg); 304 return -1; 305 } 306 write(ctl, ohmsg, strlen(ohmsg)); 307 308 /* grab the data file */ 309 snprint(ds, sizeof(ds), "%s/data", adir); 310 fd = open(ds, ORDWR); 311 close(ctl); 312 if(fd < 0) 313 warning("can't open udp port: %r"); 314 return fd; 315 } 316 317 int 318 mkreq(DN *dp, int type, uchar *buf, int flags, ushort reqno) 319 { 320 DNSmsg m; 321 int len; 322 OUdphdr *uh = (OUdphdr*)buf; 323 324 /* stuff port number into output buffer */ 325 memset(uh, 0, sizeof(*uh)); 326 hnputs(uh->rport, 53); 327 328 /* make request and convert it to output format */ 329 memset(&m, 0, sizeof(m)); 330 m.flags = flags; 331 m.id = reqno; 332 m.qd = rralloc(type); 333 m.qd->owner = dp; 334 m.qd->type = type; 335 len = convDNS2M(&m, &buf[OUdphdrsize], Maxudp); 336 if(len < 0) 337 abort(); /* "can't convert" */ 338 rrfree(m.qd); 339 return len; 340 } 341 342 /* for alarms in readreply */ 343 static void 344 ding(void *x, char *msg) 345 { 346 USED(x); 347 if(strcmp(msg, "alarm") == 0) 348 noted(NCONT); 349 else 350 noted(NDFLT); 351 } 352 353 static void 354 freeanswers(DNSmsg *mp) 355 { 356 rrfreelist(mp->qd); 357 rrfreelist(mp->an); 358 rrfreelist(mp->ns); 359 rrfreelist(mp->ar); 360 mp->qd = mp->an = mp->ns = mp->ar = nil; 361 } 362 363 /* 364 * read replies to a request. ignore any of the wrong type. 365 * wait at most 5 seconds. 366 */ 367 static int 368 readreply(int fd, DN *dp, int type, ushort req, 369 uchar *ibuf, DNSmsg *mp, ulong endtime, Request *reqp) 370 { 371 char *err; 372 int len; 373 ulong now; 374 RR *rp; 375 376 notify(ding); 377 378 for(; ; freeanswers(mp)){ 379 now = time(0); 380 if(now >= endtime) 381 return -1; /* timed out */ 382 383 /* timed read */ 384 alarm((endtime - now) * 1000); 385 len = read(fd, ibuf, OUdphdrsize+Maxudpin); 386 alarm(0); 387 len -= OUdphdrsize; 388 if(len < 0) 389 return -1; /* timed out */ 390 391 /* convert into internal format */ 392 memset(mp, 0, sizeof(*mp)); 393 err = convM2DNS(&ibuf[OUdphdrsize], len, mp, nil); 394 if(err){ 395 syslog(0, LOG, "input err: %s: %I", err, ibuf); 396 continue; 397 } 398 if(debug) 399 logreply(reqp->id, ibuf, mp); 400 401 /* answering the right question? */ 402 if(mp->id != req){ 403 syslog(0, LOG, "%d: id %d instead of %d: %I", reqp->id, 404 mp->id, req, ibuf); 405 continue; 406 } 407 if(mp->qd == 0){ 408 syslog(0, LOG, "%d: no question RR: %I", reqp->id, ibuf); 409 continue; 410 } 411 if(mp->qd->owner != dp){ 412 syslog(0, LOG, "%d: owner %s instead of %s: %I", 413 reqp->id, mp->qd->owner->name, dp->name, ibuf); 414 continue; 415 } 416 if(mp->qd->type != type){ 417 syslog(0, LOG, "%d: type %d instead of %d: %I", 418 reqp->id, mp->qd->type, type, ibuf); 419 continue; 420 } 421 422 /* remember what request this is in answer to */ 423 for(rp = mp->an; rp; rp = rp->next) 424 rp->query = type; 425 426 return 0; 427 } 428 } 429 430 /* 431 * return non-0 if first list includes second list 432 */ 433 int 434 contains(RR *rp1, RR *rp2) 435 { 436 RR *trp1, *trp2; 437 438 for(trp2 = rp2; trp2; trp2 = trp2->next){ 439 for(trp1 = rp1; trp1; trp1 = trp1->next){ 440 if(trp1->type == trp2->type) 441 if(trp1->host == trp2->host) 442 if(trp1->owner == trp2->owner) 443 break; 444 } 445 if(trp1 == nil) 446 return 0; 447 } 448 return 1; 449 } 450 451 452 typedef struct Dest Dest; 453 struct Dest 454 { 455 uchar a[IPaddrlen]; /* ip address */ 456 DN *s; /* name server */ 457 int nx; /* number of transmissions */ 458 int code; 459 }; 460 461 462 /* 463 * return multicast version if any 464 */ 465 int 466 ipisbm(uchar *ip) 467 { 468 if(isv4(ip)){ 469 if (ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0 || 470 ipcmp(ip, IPv4bcast) == 0) 471 return 4; 472 } else 473 if(ip[0] == 0xff) 474 return 6; 475 return 0; 476 } 477 478 /* 479 * Get next server address 480 */ 481 static int 482 serveraddrs(RR *nsrp, Dest *dest, int nd, int depth, Request *reqp) 483 { 484 RR *rp, *arp, *trp; 485 Dest *cur; 486 487 if(nd >= Maxdest) 488 return 0; 489 490 /* 491 * look for a server whose address we already know. 492 * if we find one, mark it so we ignore this on 493 * subsequent passes. 494 */ 495 arp = 0; 496 for(rp = nsrp; rp; rp = rp->next){ 497 assert(rp->magic == RRmagic); 498 if(rp->marker) 499 continue; 500 arp = rrlookup(rp->host, Ta, NOneg); 501 if(arp){ 502 rp->marker = 1; 503 break; 504 } 505 arp = dblookup(rp->host->name, Cin, Ta, 0, 0); 506 if(arp){ 507 rp->marker = 1; 508 break; 509 } 510 } 511 512 /* 513 * if the cache and database lookup didn't find any new 514 * server addresses, try resolving one via the network. 515 * Mark any we try to resolve so we don't try a second time. 516 */ 517 if(arp == 0) 518 for(rp = nsrp; rp; rp = rp->next){ 519 if(rp->marker) 520 continue; 521 rp->marker = 1; 522 523 /* 524 * avoid loops looking up a server under itself 525 */ 526 if(subsume(rp->owner->name, rp->host->name)) 527 continue; 528 529 arp = dnresolve(rp->host->name, Cin, Ta, reqp, 0, 530 depth+1, Recurse, 1, 0); 531 rrfreelist(rrremneg(&arp)); 532 if(arp) 533 break; 534 } 535 536 /* use any addresses that we found */ 537 for(trp = arp; trp; trp = trp->next){ 538 if(nd >= Maxdest) 539 break; 540 cur = &dest[nd]; 541 parseip(cur->a, trp->ip->name); 542 if(ipisbm(cur->a)) 543 continue; 544 cur->nx = 0; 545 cur->s = trp->owner; 546 cur->code = Rtimeout; 547 nd++; 548 } 549 rrfreelist(arp); 550 return nd; 551 } 552 553 /* 554 * cache negative responses 555 */ 556 static void 557 cacheneg(DN *dp, int type, int rcode, RR *soarr) 558 { 559 RR *rp; 560 DN *soaowner; 561 ulong ttl; 562 563 /* no cache time specified, don't make anything up */ 564 if(soarr != nil){ 565 if(soarr->next != nil){ 566 rrfreelist(soarr->next); 567 soarr->next = nil; 568 } 569 soaowner = soarr->owner; 570 } else 571 soaowner = nil; 572 573 /* the attach can cause soarr to be freed so mine it now */ 574 if(soarr != nil && soarr->soa != nil) 575 ttl = soarr->soa->minttl+now; 576 else 577 ttl = 5*Min; 578 579 /* add soa and negative RR to the database */ 580 rrattach(soarr, 1); 581 582 rp = rralloc(type); 583 rp->owner = dp; 584 rp->negative = 1; 585 rp->negsoaowner = soaowner; 586 rp->negrcode = rcode; 587 rp->ttl = ttl; 588 rrattach(rp, 1); 589 } 590 591 /* 592 * query name servers. If the name server returns a pointer to another 593 * name server, recurse. 594 */ 595 static int 596 netquery1(int fd, DN *dp, int type, RR *nsrp, Request *reqp, int depth, 597 uchar *ibuf, uchar *obuf) 598 { 599 int ndest, j, len, replywaits, rv; 600 ulong endtime; 601 ushort req; 602 char buf[12]; 603 DN *ndp; 604 DNSmsg m; 605 Dest *p, *l, *np; 606 Dest dest[Maxdest]; 607 RR *tp, *soarr; 608 609 /* pack request into a message */ 610 req = rand(); 611 len = mkreq(dp, type, obuf, Frecurse|Oquery, req); 612 613 /* no server addresses yet */ 614 l = dest; 615 616 /* 617 * transmit requests and wait for answers. 618 * at most Maxtrans attempts to each address. 619 * each cycle send one more message than the previous. 620 */ 621 for(ndest = 1; ndest < Maxdest; ndest++){ 622 p = dest; 623 624 endtime = time(0); 625 if(endtime >= reqp->aborttime) 626 break; 627 628 /* get a server address if we need one */ 629 if(ndest > l - p){ 630 j = serveraddrs(nsrp, dest, l - p, depth, reqp); 631 l = &dest[j]; 632 } 633 634 /* no servers, punt */ 635 if(l == dest) 636 break; 637 638 /* send to first 'ndest' destinations */ 639 j = 0; 640 for(; p < &dest[ndest] && p < l; p++){ 641 /* skip destinations we've finished with */ 642 if(p->nx >= Maxtrans) 643 continue; 644 645 j++; 646 647 /* exponential backoff of requests */ 648 if((1<<p->nx) > ndest) 649 continue; 650 651 procsetname("req slave: query to %I/%s %s %s", 652 obuf, p->s->name, dp->name, 653 rrname(type, buf, sizeof buf)); 654 memmove(obuf, p->a, sizeof p->a); 655 if(debug) 656 logsend(reqp->id, depth, obuf, p->s->name, 657 dp->name, type); 658 if(write(fd, obuf, len + OUdphdrsize) < 0) 659 warning("sending udp msg %r"); 660 p->nx++; 661 } 662 if(j == 0) 663 break; /* no destinations left */ 664 665 /* wait up to 5 seconds for replies */ 666 endtime = time(0) + 5; 667 if(endtime > reqp->aborttime) 668 endtime = reqp->aborttime; 669 670 for(replywaits = 0; replywaits < ndest; replywaits++){ 671 procsetname("req slave: reading reply from %I for %s %s", 672 obuf, dp->name, rrname(type, buf, sizeof buf)); 673 memset(&m, 0, sizeof m); 674 if(readreply(fd, dp, type, req, ibuf, &m, endtime, reqp) < 0) 675 break; /* timed out */ 676 677 /* find responder */ 678 for(p = dest; p < l; p++) 679 if(memcmp(p->a, ibuf, sizeof(p->a)) == 0) 680 break; 681 682 /* remove all addrs of responding server from list */ 683 for(np = dest; np < l; np++) 684 if(np->s == p->s) 685 p->nx = Maxtrans; 686 687 /* ignore any error replies */ 688 if((m.flags & Rmask) == Rserver){ 689 rrfreelist(m.qd); 690 rrfreelist(m.an); 691 rrfreelist(m.ar); 692 rrfreelist(m.ns); 693 if(p != l) 694 p->code = Rserver; 695 continue; 696 } 697 698 /* ignore any bad delegations */ 699 if(m.ns && baddelegation(m.ns, nsrp, ibuf)){ 700 rrfreelist(m.ns); 701 m.ns = nil; 702 if(m.an == nil){ 703 rrfreelist(m.qd); 704 rrfreelist(m.ar); 705 if(p != l) 706 p->code = Rserver; 707 continue; 708 } 709 } 710 711 712 /* remove any soa's from the authority section */ 713 soarr = rrremtype(&m.ns, Tsoa); 714 715 /* incorporate answers */ 716 if(m.an) 717 rrattach(m.an, (m.flags & Fauth) != 0); 718 if(m.ar) 719 rrattach(m.ar, 0); 720 if(m.ns){ 721 ndp = m.ns->owner; 722 rrattach(m.ns, 0); 723 } else 724 ndp = 0; 725 726 /* free the question */ 727 if(m.qd) 728 rrfreelist(m.qd); 729 730 /* 731 * Any reply from an authoritative server, 732 * or a positive reply terminates the search 733 */ 734 if(m.an != nil || (m.flags & Fauth)){ 735 if(m.an == nil && (m.flags & Rmask) == Rname) 736 dp->nonexistent = Rname; 737 else 738 dp->nonexistent = 0; 739 740 /* 741 * cache any negative responses, free soarr 742 */ 743 if((m.flags & Fauth) && m.an == nil) 744 cacheneg(dp, type, (m.flags & Rmask), 745 soarr); 746 else 747 rrfreelist(soarr); 748 return 1; 749 } 750 rrfreelist(soarr); 751 752 /* 753 * if we've been given better name servers 754 * recurse 755 */ 756 if(m.ns){ 757 tp = rrlookup(ndp, Tns, NOneg); 758 if(!contains(nsrp, tp)){ 759 procsetname( 760 "req slave: recursive query for %s %s", 761 dp->name, 762 rrname(type, buf, sizeof buf)); 763 rv = netquery(dp, type, tp, reqp, 764 depth + 1); 765 rrfreelist(tp); 766 return rv; 767 } else 768 rrfreelist(tp); 769 } 770 } 771 } 772 773 /* if all servers returned failure, propagate it */ 774 dp->nonexistent = Rserver; 775 for(p = dest; p < l; p++) 776 if(p->code != Rserver) 777 dp->nonexistent = 0; 778 779 return 0; 780 } 781 782 static int 783 netquery(DN *dp, int type, RR *nsrp, Request *reqp, int depth) 784 { 785 int fd, rv; 786 // int pid; 787 uchar *obuf, *ibuf; 788 RR *rp; 789 790 if(depth > 12) /* in a recursive loop? */ 791 return 0; 792 793 /* use alloced buffers rather than ones from the stack */ 794 ibuf = emalloc(Maxudpin+OUdphdrsize); 795 obuf = emalloc(Maxudp+OUdphdrsize); 796 797 // pid = getpid(); 798 slave(reqp); 799 /* parent process longjmped to req->mret; we're the child slave */ 800 801 /* prepare server RR's for incremental lookup */ 802 for(rp = nsrp; rp; rp = rp->next) 803 rp->marker = 0; 804 805 // if (pid != getpid()) 806 // syslog(0, LOG, "[%d] netquery: forked child for %s", 807 // getpid(), dp->name); 808 fd = udpport(); 809 if(fd < 0) 810 rv = 0; 811 else 812 rv = netquery1(fd, dp, type, nsrp, reqp, depth, ibuf, obuf); 813 close(fd); 814 free(ibuf); 815 free(obuf); 816 817 return rv; 818 } 819