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