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
usage(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
justremount(char * service,char * mntpt)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
main(int argc,char * argv[])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
setext(char * ext,int n,char * p)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
mountinit(char * service,char * mntpt)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*
newfid(int fid,int needunused)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
freefid(Mfile * mf)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*
copyfid(Mfile * mf,int fid)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*
newjob(void)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
freejob(Job * job)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
flushjob(int tag)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
io(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
rversion(Job * job)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
rauth(Job * job)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
rflush(Job * job)574 rflush(Job *job)
575 {
576 flushjob(job->request.oldtag);
577 sendmsg(job, 0);
578 }
579
580 void
rattach(Job * job,Mfile * mf)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*
rwalk(Job * job,Mfile * mf)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
ropen(Job * job,Mfile * mf)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
rcreate(Job * job,Mfile * mf)671 rcreate(Job *job, Mfile *mf)
672 {
673 USED(mf);
674 sendmsg(job, "creation permission denied");
675 }
676
677 void
rread(Job * job,Mfile * mf)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
rwrite(Job * job,Mfile * mf,Request * req)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 *
lookupqueryold(Job * job,Mfile * mf,Request * req,char * errbuf,char * p,int wantsav,int rooted)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 *
respond(Job * job,Mfile * mf,RR * rp,char * errbuf,int status,int wantsav)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 *
lookupquerynew(Job * job,Mfile * mf,Request * req,char * errbuf,char * p,int wantsav,int)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
rclunk(Job * job,Mfile * mf)948 rclunk(Job *job, Mfile *mf)
949 {
950 freefid(mf);
951 sendmsg(job, 0);
952 }
953
954 void
rremove(Job * job,Mfile * mf)955 rremove(Job *job, Mfile *mf)
956 {
957 USED(mf);
958 sendmsg(job, "remove permission denied");
959 }
960
961 void
rstat(Job * job,Mfile * mf)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
rwstat(Job * job,Mfile * mf)985 rwstat(Job *job, Mfile *mf)
986 {
987 USED(mf);
988 sendmsg(job, "wstat permission denied");
989 }
990
991 void
sendmsg(Job * job,char * err)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
logreply(int id,uchar * addr,DNSmsg * mp)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
logsend(int id,int subid,uchar * addr,char * sname,char * rname,int type)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*
getdnsservers(int class)1054 getdnsservers(int class)
1055 {
1056 return dnsservers(class);
1057 }
1058