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