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