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