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