1 #include <u.h> 2 #include <libc.h> 3 #include <auth.h> 4 #include <fcall.h> 5 #include <bio.h> 6 #include <ctype.h> 7 #include <ip.h> 8 #include <pool.h> 9 #include "dns.h" 10 11 enum 12 { 13 Maxrequest= 1024, 14 Maxreply= 8192, /* was 512 */ 15 Maxrrr= 32, /* was 16 */ 16 Maxfdata= 8192, 17 18 Defmaxage= 60*60, /* default domain name max. age */ 19 20 Qdir= 0, 21 Qdns= 1, 22 }; 23 24 typedef struct Mfile Mfile; 25 typedef struct Job Job; 26 typedef struct Network Network; 27 28 int vers; /* incremented each clone/attach */ 29 30 static volatile int stop; 31 32 /* holds data to be returned via read of /net/dns, perhaps multiple reads */ 33 struct Mfile 34 { 35 Mfile *next; /* next free mfile */ 36 int ref; 37 38 char *user; 39 Qid qid; 40 int fid; 41 42 int type; /* reply type */ 43 char reply[Maxreply]; 44 ushort rr[Maxrrr]; /* offset of rr's */ 45 ushort nrr; /* number of rr's */ 46 }; 47 48 /* 49 * active local requests 50 */ 51 struct Job 52 { 53 Job *next; 54 int flushed; 55 Fcall request; 56 Fcall reply; 57 }; 58 Lock joblock; 59 Job *joblist; 60 61 struct { 62 Lock; 63 Mfile *inuse; /* active mfile's */ 64 } mfalloc; 65 66 Cfg cfg; 67 int debug; 68 uchar ipaddr[IPaddrlen]; /* my ip address */ 69 int maxage = Defmaxage; 70 int mfd[2]; 71 int needrefresh; 72 ulong now; 73 vlong nowns; 74 int sendnotifies; 75 int testing; 76 char *trace; 77 int traceactivity; 78 char *zonerefreshprogram; 79 80 char *logfile = "dns"; /* or "dns.test" */ 81 char *dbfile; 82 char mntpt[Maxpath]; 83 84 int fillreply(Mfile*, int); 85 void freejob(Job*); 86 void io(void); 87 void mountinit(char*, char*); 88 Job* newjob(void); 89 void rattach(Job*, Mfile*); 90 void rauth(Job*); 91 void rclunk(Job*, Mfile*); 92 void rcreate(Job*, Mfile*); 93 void rflush(Job*); 94 void ropen(Job*, Mfile*); 95 void rread(Job*, Mfile*); 96 void rremove(Job*, Mfile*); 97 void rstat(Job*, Mfile*); 98 void rversion(Job*); 99 char* rwalk(Job*, Mfile*); 100 void rwrite(Job*, Mfile*, Request*); 101 void rwstat(Job*, Mfile*); 102 void sendmsg(Job*, char*); 103 void setext(char*, int, char*); 104 105 void 106 usage(void) 107 { 108 fprint(2, "usage: %s [-FnorRst] [-a maxage] [-f ndb-file] [-N target] " 109 "[-T forwip] [-x netmtpt] [-z refreshprog]\n", argv0); 110 exits("usage"); 111 } 112 113 int addforwtarg(char *); 114 115 void 116 main(int argc, char *argv[]) 117 { 118 int kid, pid; 119 char servefile[Maxpath], ext[Maxpath]; 120 Dir *dir; 121 122 setnetmtpt(mntpt, sizeof mntpt, nil); 123 ext[0] = 0; 124 ARGBEGIN{ 125 case 'a': 126 maxage = atol(EARGF(usage())); 127 if (maxage <= 0) 128 maxage = Defmaxage; 129 break; 130 case 'd': 131 debug = 1; 132 traceactivity = 1; 133 break; 134 case 'f': 135 dbfile = EARGF(usage()); 136 break; 137 case 'F': 138 cfg.justforw = cfg.resolver = 1; 139 break; 140 case 'n': 141 sendnotifies = 1; 142 break; 143 case 'N': 144 target = atol(EARGF(usage())); 145 if (target < 1000) 146 target = 1000; 147 break; 148 case 'o': 149 cfg.straddle = 1; /* straddle inside & outside networks */ 150 break; 151 case 'r': 152 cfg.resolver = 1; 153 break; 154 case 'R': 155 norecursion = 1; 156 break; 157 case 's': 158 cfg.serve = 1; /* serve network */ 159 cfg.cachedb = 1; 160 break; 161 case 't': 162 testing = 1; 163 break; 164 case 'T': 165 addforwtarg(EARGF(usage())); 166 break; 167 case 'x': 168 setnetmtpt(mntpt, sizeof mntpt, EARGF(usage())); 169 setext(ext, sizeof ext, mntpt); 170 break; 171 case 'z': 172 zonerefreshprogram = EARGF(usage()); 173 break; 174 }ARGEND 175 USED(argc); 176 USED(argv); 177 178 if(testing) 179 mainmem->flags |= POOL_NOREUSE | POOL_ANTAGONISM; 180 mainmem->flags |= POOL_ANTAGONISM; 181 rfork(RFREND|RFNOTEG); 182 183 cfg.inside = (*mntpt == '\0' || strcmp(mntpt, "/net") == 0); 184 185 /* start syslog before we fork */ 186 fmtinstall('F', fcallfmt); 187 dninit(); 188 /* this really shouldn't be fatal */ 189 if(myipaddr(ipaddr, mntpt) < 0) 190 sysfatal("can't read my ip address"); 191 dnslog("starting %s%sdns %s%s%son %I's %s", 192 (cfg.straddle? "straddling ": ""), 193 (cfg.cachedb? "caching ": ""), 194 (cfg.serve? "udp server ": ""), 195 (cfg.justforw? "forwarding-only ": ""), 196 (cfg.resolver? "resolver ": ""), ipaddr, mntpt); 197 198 opendatabase(); 199 now = time(nil); /* open time files before we fork */ 200 nowns = nsec(); 201 202 snprint(servefile, sizeof servefile, "#s/dns%s", ext); 203 dir = dirstat(servefile); 204 if (dir) 205 sysfatal("%s exists; another dns instance is running", 206 servefile); 207 free(dir); 208 // unmount(servefile, mntpt); 209 // remove(servefile); 210 211 mountinit(servefile, mntpt); /* forks, parent exits */ 212 213 srand(now*getpid()); 214 db2cache(1); 215 // dnageallnever(); 216 217 if (cfg.straddle && !seerootns()) 218 dnslog("straddle server misconfigured; can't see root name servers"); 219 /* 220 * fork without sharing heap. 221 * parent waits around for child to die, then forks & restarts. 222 * child may spawn udp server, notify procs, etc.; when it gets too 223 * big, it kills itself and any children. 224 * /srv/dns and /net/dns remain open and valid. 225 */ 226 for (;;) { 227 kid = rfork(RFPROC|RFFDG|RFNOTEG); 228 switch (kid) { 229 case -1: 230 sysfatal("fork failed: %r"); 231 case 0: 232 if(cfg.serve) 233 dnudpserver(mntpt); 234 if(sendnotifies) 235 notifyproc(); 236 io(); 237 _exits("restart"); 238 default: 239 while ((pid = waitpid()) != kid && pid != -1) 240 continue; 241 break; 242 } 243 dnslog("dns restarting"); 244 } 245 } 246 247 /* 248 * if a mount point is specified, set the cs extension to be the mount point 249 * with '_'s replacing '/'s 250 */ 251 void 252 setext(char *ext, int n, char *p) 253 { 254 int i, c; 255 256 n--; 257 for(i = 0; i < n; i++){ 258 c = p[i]; 259 if(c == 0) 260 break; 261 if(c == '/') 262 c = '_'; 263 ext[i] = c; 264 } 265 ext[i] = 0; 266 } 267 268 void 269 mountinit(char *service, char *mntpt) 270 { 271 int f; 272 int p[2]; 273 char buf[32]; 274 275 if(pipe(p) < 0) 276 abort(); /* "pipe failed" */; 277 /* copy namespace to avoid a deadlock */ 278 switch(rfork(RFFDG|RFPROC|RFNAMEG)){ 279 case 0: /* child: hang around and (re)start main proc */ 280 close(p[1]); 281 procsetname("%s restarter", mntpt); 282 break; 283 case -1: 284 abort(); /* "fork failed\n" */; 285 default: /* parent: make /srv/dns, mount it, exit */ 286 close(p[0]); 287 288 /* 289 * make a /srv/dns 290 */ 291 f = create(service, 1, 0666); 292 if(f < 0) 293 abort(); /* service */; 294 snprint(buf, sizeof buf, "%d", p[1]); 295 if(write(f, buf, strlen(buf)) != strlen(buf)) 296 abort(); /* "write %s", service */; 297 close(f); 298 299 /* 300 * put ourselves into the file system 301 */ 302 if(mount(p[1], -1, mntpt, MAFTER, "") < 0) 303 fprint(2, "dns mount failed: %r\n"); 304 _exits(0); 305 } 306 mfd[0] = mfd[1] = p[0]; 307 } 308 309 Mfile* 310 newfid(int fid, int needunused) 311 { 312 Mfile *mf; 313 314 lock(&mfalloc); 315 for(mf = mfalloc.inuse; mf != nil; mf = mf->next) 316 if(mf->fid == fid){ 317 unlock(&mfalloc); 318 if(needunused) 319 return nil; 320 return mf; 321 } 322 mf = emalloc(sizeof(*mf)); 323 mf->fid = fid; 324 mf->next = mfalloc.inuse; 325 mf->user = estrdup("dummy"); 326 mfalloc.inuse = mf; 327 unlock(&mfalloc); 328 return mf; 329 } 330 331 void 332 freefid(Mfile *mf) 333 { 334 Mfile **l; 335 336 lock(&mfalloc); 337 for(l = &mfalloc.inuse; *l != nil; l = &(*l)->next) 338 if(*l == mf){ 339 *l = mf->next; 340 if(mf->user) 341 free(mf->user); 342 memset(mf, 0, sizeof *mf); /* cause trouble */ 343 free(mf); 344 unlock(&mfalloc); 345 return; 346 } 347 sysfatal("freeing unused fid"); 348 } 349 350 Mfile* 351 copyfid(Mfile *mf, int fid) 352 { 353 Mfile *nmf; 354 355 nmf = newfid(fid, 1); 356 if(nmf == nil) 357 return nil; 358 nmf->fid = fid; 359 nmf->user = estrdup(mf->user); 360 nmf->qid.type = mf->qid.type; 361 nmf->qid.path = mf->qid.path; 362 nmf->qid.vers = vers++; 363 return nmf; 364 } 365 366 Job* 367 newjob(void) 368 { 369 Job *job; 370 371 job = emalloc(sizeof *job); 372 lock(&joblock); 373 job->next = joblist; 374 joblist = job; 375 job->request.tag = -1; 376 unlock(&joblock); 377 return job; 378 } 379 380 void 381 freejob(Job *job) 382 { 383 Job **l; 384 385 lock(&joblock); 386 for(l = &joblist; *l; l = &(*l)->next) 387 if(*l == job){ 388 *l = job->next; 389 memset(job, 0, sizeof *job); /* cause trouble */ 390 free(job); 391 break; 392 } 393 unlock(&joblock); 394 } 395 396 void 397 flushjob(int tag) 398 { 399 Job *job; 400 401 lock(&joblock); 402 for(job = joblist; job; job = job->next) 403 if(job->request.tag == tag && job->request.type != Tflush){ 404 job->flushed = 1; 405 break; 406 } 407 unlock(&joblock); 408 } 409 410 void 411 io(void) 412 { 413 volatile long n; 414 volatile uchar mdata[IOHDRSZ + Maxfdata]; 415 Job *volatile job; 416 Mfile *volatile mf; 417 volatile Request req; 418 419 memset(&req, 0, sizeof req); 420 /* 421 * a slave process is sometimes forked to wait for replies from other 422 * servers. The master process returns immediately via a longjmp 423 * through 'mret'. 424 */ 425 if(setjmp(req.mret)) 426 putactivity(0); 427 // procsetname("9p server"); 428 req.isslave = 0; 429 stop = 0; 430 while(!stop){ 431 procsetname("%d %s/dns Twrites of %d 9p rpcs read; %d alarms", 432 stats.qrecvd9p, mntpt, stats.qrecvd9prpc, stats.alarms); 433 n = read9pmsg(mfd[0], mdata, sizeof mdata); 434 if(n<=0){ 435 dnslog("error reading 9P from %s: %r", mntpt); 436 sleep(2000); /* don't thrash */ 437 return; 438 } 439 440 stats.qrecvd9prpc++; 441 job = newjob(); 442 if(convM2S(mdata, n, &job->request) != n){ 443 freejob(job); 444 continue; 445 } 446 mf = newfid(job->request.fid, 0); 447 if(debug) 448 dnslog("%F", &job->request); 449 450 getactivity(&req, 0); 451 req.aborttime = time(nil) + Maxreqtm; 452 req.from = "9p"; 453 454 switch(job->request.type){ 455 default: 456 warning("unknown request type %d", job->request.type); 457 break; 458 case Tversion: 459 rversion(job); 460 break; 461 case Tauth: 462 rauth(job); 463 break; 464 case Tflush: 465 rflush(job); 466 break; 467 case Tattach: 468 rattach(job, mf); 469 break; 470 case Twalk: 471 rwalk(job, mf); 472 break; 473 case Topen: 474 ropen(job, mf); 475 break; 476 case Tcreate: 477 rcreate(job, mf); 478 break; 479 case Tread: 480 rread(job, mf); 481 break; 482 case Twrite: 483 /* &req is handed to dnresolve() */ 484 rwrite(job, mf, &req); 485 break; 486 case Tclunk: 487 rclunk(job, mf); 488 break; 489 case Tremove: 490 rremove(job, mf); 491 break; 492 case Tstat: 493 rstat(job, mf); 494 break; 495 case Twstat: 496 rwstat(job, mf); 497 break; 498 } 499 500 freejob(job); 501 502 /* 503 * slave processes die after replying 504 */ 505 if(req.isslave){ 506 putactivity(0); 507 _exits(0); 508 } 509 510 putactivity(0); 511 } 512 /* kill any udp server, notifier, etc. processes */ 513 postnote(PNGROUP, getpid(), "die"); 514 sleep(1000); 515 } 516 517 void 518 rversion(Job *job) 519 { 520 if(job->request.msize > IOHDRSZ + Maxfdata) 521 job->reply.msize = IOHDRSZ + Maxfdata; 522 else 523 job->reply.msize = job->request.msize; 524 if(strncmp(job->request.version, "9P2000", 6) != 0) 525 sendmsg(job, "unknown 9P version"); 526 else{ 527 job->reply.version = "9P2000"; 528 sendmsg(job, 0); 529 } 530 } 531 532 void 533 rauth(Job *job) 534 { 535 sendmsg(job, "dns: authentication not required"); 536 } 537 538 /* 539 * don't flush till all the slaves are done 540 */ 541 void 542 rflush(Job *job) 543 { 544 flushjob(job->request.oldtag); 545 sendmsg(job, 0); 546 } 547 548 void 549 rattach(Job *job, Mfile *mf) 550 { 551 if(mf->user != nil) 552 free(mf->user); 553 mf->user = estrdup(job->request.uname); 554 mf->qid.vers = vers++; 555 mf->qid.type = QTDIR; 556 mf->qid.path = 0LL; 557 job->reply.qid = mf->qid; 558 sendmsg(job, 0); 559 } 560 561 char* 562 rwalk(Job *job, Mfile *mf) 563 { 564 int i, nelems; 565 char *err; 566 char **elems; 567 Mfile *nmf; 568 Qid qid; 569 570 err = 0; 571 nmf = nil; 572 elems = job->request.wname; 573 nelems = job->request.nwname; 574 job->reply.nwqid = 0; 575 576 if(job->request.newfid != job->request.fid){ 577 /* clone fid */ 578 nmf = copyfid(mf, job->request.newfid); 579 if(nmf == nil){ 580 err = "clone bad newfid"; 581 goto send; 582 } 583 mf = nmf; 584 } 585 /* else nmf will be nil */ 586 587 qid = mf->qid; 588 if(nelems > 0) 589 /* walk fid */ 590 for(i=0; i<nelems && i<MAXWELEM; i++){ 591 if((qid.type & QTDIR) == 0){ 592 err = "not a directory"; 593 break; 594 } 595 if (strcmp(elems[i], "..") == 0 || 596 strcmp(elems[i], ".") == 0){ 597 qid.type = QTDIR; 598 qid.path = Qdir; 599 Found: 600 job->reply.wqid[i] = qid; 601 job->reply.nwqid++; 602 continue; 603 } 604 if(strcmp(elems[i], "dns") == 0){ 605 qid.type = QTFILE; 606 qid.path = Qdns; 607 goto Found; 608 } 609 err = "file does not exist"; 610 break; 611 } 612 613 send: 614 if(nmf != nil && (err!=nil || job->reply.nwqid<nelems)) 615 freefid(nmf); 616 if(err == nil) 617 mf->qid = qid; 618 sendmsg(job, err); 619 return err; 620 } 621 622 void 623 ropen(Job *job, Mfile *mf) 624 { 625 int mode; 626 char *err; 627 628 err = 0; 629 mode = job->request.mode; 630 if(mf->qid.type & QTDIR) 631 if(mode) 632 err = "permission denied"; 633 job->reply.qid = mf->qid; 634 job->reply.iounit = 0; 635 sendmsg(job, err); 636 } 637 638 void 639 rcreate(Job *job, Mfile *mf) 640 { 641 USED(mf); 642 sendmsg(job, "creation permission denied"); 643 } 644 645 void 646 rread(Job *job, Mfile *mf) 647 { 648 int i, n; 649 long clock; 650 ulong cnt; 651 vlong off; 652 char *err; 653 uchar buf[Maxfdata]; 654 Dir dir; 655 656 n = 0; 657 err = nil; 658 off = job->request.offset; 659 cnt = job->request.count; 660 *buf = '\0'; 661 job->reply.data = (char*)buf; 662 if(mf->qid.type & QTDIR){ 663 clock = time(nil); 664 if(off == 0){ 665 memset(&dir, 0, sizeof dir); 666 dir.name = "dns"; 667 dir.qid.type = QTFILE; 668 dir.qid.vers = vers; 669 dir.qid.path = Qdns; 670 dir.mode = 0666; 671 dir.length = 0; 672 dir.uid = dir.gid = dir.muid = mf->user; 673 dir.atime = dir.mtime = clock; /* wrong */ 674 n = convD2M(&dir, buf, sizeof buf); 675 } 676 } else if (off < 0) 677 err = "negative read offset"; 678 else { 679 /* first offset will always be zero */ 680 for(i = 1; i <= mf->nrr; i++) 681 if(mf->rr[i] > off) 682 break; 683 if(i <= mf->nrr) { 684 if(off + cnt > mf->rr[i]) 685 n = mf->rr[i] - off; 686 else 687 n = cnt; 688 assert(n >= 0); 689 job->reply.data = mf->reply + off; 690 } 691 } 692 job->reply.count = n; 693 sendmsg(job, err); 694 } 695 696 void 697 rwrite(Job *job, Mfile *mf, Request *req) 698 { 699 int rooted, status, wantsav; 700 long n; 701 ulong cnt; 702 char *err, *p, *atype; 703 RR *rp, *tp, *neg; 704 705 err = nil; 706 cnt = job->request.count; 707 if(mf->qid.type & QTDIR){ 708 err = "can't write directory"; 709 goto send; 710 } 711 if (job->request.offset != 0) { 712 err = "writing at non-zero offset"; 713 goto send; 714 } 715 if(cnt >= Maxrequest){ 716 err = "request too long"; 717 goto send; 718 } 719 job->request.data[cnt] = 0; 720 if(cnt > 0 && job->request.data[cnt-1] == '\n') 721 job->request.data[cnt-1] = 0; 722 723 /* 724 * special commands 725 */ 726 // dnslog("rwrite got: %s", job->request.data); 727 if(strcmp(job->request.data, "debug")==0){ 728 debug ^= 1; 729 goto send; 730 } else if(strcmp(job->request.data, "dump")==0){ 731 dndump("/lib/ndb/dnsdump"); 732 goto send; 733 } else if(strcmp(job->request.data, "poolcheck")==0){ 734 poolcheck(mainmem); 735 goto send; 736 } else if(strcmp(job->request.data, "refresh")==0){ 737 needrefresh = 1; 738 goto send; 739 } else if(strcmp(job->request.data, "restart")==0){ 740 stop = 1; 741 goto send; 742 } else if(strcmp(job->request.data, "stats")==0){ 743 dnstats("/lib/ndb/dnsstats"); 744 goto send; 745 } else if(strncmp(job->request.data, "target ", 7)==0){ 746 target = atol(job->request.data + 7); 747 dnslog("target set to %ld", target); 748 goto send; 749 } else if(strcmp(job->request.data, "age")==0){ 750 dnslog("dump, age & dump forced"); 751 dndump("/lib/ndb/dnsdump1"); 752 dnforceage(); 753 dndump("/lib/ndb/dnsdump2"); 754 goto send; 755 } 756 757 /* 758 * kill previous reply 759 */ 760 mf->nrr = 0; 761 mf->rr[0] = 0; 762 763 /* 764 * break up request (into a name and a type) 765 */ 766 atype = strchr(job->request.data, ' '); 767 if(atype == 0){ 768 err = "illegal request"; 769 goto send; 770 } else 771 *atype++ = 0; 772 773 /* 774 * tracing request 775 */ 776 if(strcmp(atype, "trace") == 0){ 777 if(trace) 778 free(trace); 779 if(*job->request.data) 780 trace = estrdup(job->request.data); 781 else 782 trace = 0; 783 goto send; 784 } 785 786 /* normal request: domain [type] */ 787 stats.qrecvd9p++; 788 mf->type = rrtype(atype); 789 if(mf->type < 0){ 790 err = "unknown type"; 791 goto send; 792 } 793 794 p = atype - 2; 795 if(p >= job->request.data && *p == '.'){ 796 rooted = 1; 797 *p = 0; 798 } else 799 rooted = 0; 800 801 p = job->request.data; 802 if(*p == '!'){ 803 wantsav = 1; 804 p++; 805 } else 806 wantsav = 0; 807 808 dncheck(0, 1); 809 status = 0; 810 rp = dnresolve(p, Cin, mf->type, req, 0, 0, Recurse, rooted, &status); 811 812 dncheck(0, 1); 813 neg = rrremneg(&rp); 814 if(neg){ 815 status = neg->negrcode; 816 rrfreelist(neg); 817 } 818 819 if(rp == nil) 820 switch(status){ 821 case Rname: 822 err = "name does not exist"; 823 break; 824 case Rserver: 825 err = "dns failure"; 826 break; 827 default: 828 err = "resource does not exist"; 829 break; 830 } 831 else { 832 lock(&joblock); 833 if(!job->flushed){ 834 /* format data to be read later */ 835 n = 0; 836 mf->nrr = 0; 837 for(tp = rp; mf->nrr < Maxrrr-1 && n < Maxreply && tp && 838 tsame(mf->type, tp->type); tp = tp->next){ 839 mf->rr[mf->nrr++] = n; 840 if(wantsav) 841 n += snprint(mf->reply+n, Maxreply-n, 842 "%Q", tp); 843 else 844 n += snprint(mf->reply+n, Maxreply-n, 845 "%R", tp); 846 } 847 mf->rr[mf->nrr] = n; 848 } 849 unlock(&joblock); 850 rrfreelist(rp); 851 } 852 send: 853 dncheck(0, 1); 854 job->reply.count = cnt; 855 sendmsg(job, err); 856 } 857 858 void 859 rclunk(Job *job, Mfile *mf) 860 { 861 freefid(mf); 862 sendmsg(job, 0); 863 } 864 865 void 866 rremove(Job *job, Mfile *mf) 867 { 868 USED(mf); 869 sendmsg(job, "remove permission denied"); 870 } 871 872 void 873 rstat(Job *job, Mfile *mf) 874 { 875 Dir dir; 876 uchar buf[IOHDRSZ+Maxfdata]; 877 878 memset(&dir, 0, sizeof dir); 879 if(mf->qid.type & QTDIR){ 880 dir.name = "."; 881 dir.mode = DMDIR|0555; 882 } else { 883 dir.name = "dns"; 884 dir.mode = 0666; 885 } 886 dir.qid = mf->qid; 887 dir.length = 0; 888 dir.uid = dir.gid = dir.muid = mf->user; 889 dir.atime = dir.mtime = time(nil); 890 job->reply.nstat = convD2M(&dir, buf, sizeof buf); 891 job->reply.stat = buf; 892 sendmsg(job, 0); 893 } 894 895 void 896 rwstat(Job *job, Mfile *mf) 897 { 898 USED(mf); 899 sendmsg(job, "wstat permission denied"); 900 } 901 902 void 903 sendmsg(Job *job, char *err) 904 { 905 int n; 906 uchar mdata[IOHDRSZ + Maxfdata]; 907 char ename[ERRMAX]; 908 909 if(err){ 910 job->reply.type = Rerror; 911 snprint(ename, sizeof ename, "dns: %s", err); 912 job->reply.ename = ename; 913 }else 914 job->reply.type = job->request.type+1; 915 job->reply.tag = job->request.tag; 916 n = convS2M(&job->reply, mdata, sizeof mdata); 917 if(n == 0){ 918 warning("sendmsg convS2M of %F returns 0", &job->reply); 919 abort(); 920 } 921 lock(&joblock); 922 if(job->flushed == 0) 923 if(write(mfd[1], mdata, n)!=n) 924 sysfatal("mount write"); 925 unlock(&joblock); 926 if(debug) 927 dnslog("%F %d", &job->reply, n); 928 } 929 930 /* 931 * the following varies between dnsdebug and dns 932 */ 933 void 934 logreply(int id, uchar *addr, DNSmsg *mp) 935 { 936 RR *rp; 937 938 dnslog("%d: rcvd %I flags:%s%s%s%s%s", id, addr, 939 mp->flags & Fauth? " auth": "", 940 mp->flags & Ftrunc? " trunc": "", 941 mp->flags & Frecurse? " rd": "", 942 mp->flags & Fcanrec? " ra": "", 943 (mp->flags & (Fauth|Rmask)) == (Fauth|Rname)? " nx": ""); 944 for(rp = mp->qd; rp != nil; rp = rp->next) 945 dnslog("%d: rcvd %I qd %s", id, addr, rp->owner->name); 946 for(rp = mp->an; rp != nil; rp = rp->next) 947 dnslog("%d: rcvd %I an %R", id, addr, rp); 948 for(rp = mp->ns; rp != nil; rp = rp->next) 949 dnslog("%d: rcvd %I ns %R", id, addr, rp); 950 for(rp = mp->ar; rp != nil; rp = rp->next) 951 dnslog("%d: rcvd %I ar %R", id, addr, rp); 952 } 953 954 void 955 logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type) 956 { 957 char buf[12]; 958 959 dnslog("[%d] %d.%d: sending to %I/%s %s %s", 960 getpid(), id, subid, addr, sname, rname, 961 rrname(type, buf, sizeof buf)); 962 } 963 964 RR* 965 getdnsservers(int class) 966 { 967 return dnsservers(class); 968 } 969