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