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