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