12 Maxreply= 8192, /* was 512 */
13 Maxrrr= 32, /* was 16 */
16 Defmaxage= 60*60, /* default domain name max. age */
22 typedef struct Mfile Mfile;
23 typedef struct Job Job;
24 typedef struct Network Network;
26 int vers; /* incremented each clone/attach */
28 /* holds data to be returned via read of /net/dns, perhaps multiple reads */
31 Mfile *next; /* next free mfile */
37 int type; /* reply type */
39 ushort rr[Maxrrr]; /* offset of rr's */
40 ushort nrr; /* number of rr's */
44 * active local requests
58 Mfile *inuse; /* active mfile's */
63 int maxage = Defmaxage;
71 char *zonerefreshprogram;
73 char *logfile = "dns"; /* or "dns.test" */
78 int addforwtarg(char *);
79 int fillreply(Mfile*, int);
82 void mountinit(char*, char*);
84 void rattach(Job*, Mfile*);
86 void rclunk(Job*, Mfile*);
87 void rcreate(Job*, Mfile*);
89 void ropen(Job*, Mfile*);
90 void rread(Job*, Mfile*);
91 void rremove(Job*, Mfile*);
92 void rstat(Job*, Mfile*);
94 char* rwalk(Job*, Mfile*);
95 void rwrite(Job*, Mfile*, Request*);
96 void rwstat(Job*, Mfile*);
97 void sendmsg(Job*, char*);
98 void setext(char*, int, char*);
100 static char *lookupquery(Job*, Mfile*, Request*, char*, char*, int, int);
101 static char *respond(Job*, Mfile*, RR*, char*, int, int);
106 fprint(2, "usage: %s [-FnorRs] [-a maxage] [-f ndb-file] [-N target] "
107 "[-T forwip] [-x netmtpt] [-z refreshprog]\n", argv0);
112 main(int argc, char *argv[])
114 char servefile[Maxpath], ext[Maxpath];
117 setnetmtpt(mntpt, sizeof mntpt, nil);
121 maxage = atol(EARGF(usage()));
130 dbfile = EARGF(usage());
133 cfg.justforw = cfg.resolver = 1;
139 target = atol(EARGF(usage()));
144 cfg.straddle = 1; /* straddle inside & outside networks */
153 cfg.serve = 1; /* serve network */
157 addforwtarg(EARGF(usage()));
160 setnetmtpt(mntpt, sizeof mntpt, EARGF(usage()));
161 setext(ext, sizeof ext, mntpt);
164 zonerefreshprogram = EARGF(usage());
173 rfork(RFREND|RFNOTEG);
175 cfg.inside = (*mntpt == '\0' || strcmp(mntpt, "/net") == 0);
177 /* start syslog before we fork */
178 fmtinstall('F', fcallfmt);
180 dnslog("starting %s%sdns %s%s%son %s",
181 (cfg.straddle? "straddling ": ""),
182 (cfg.cachedb? "caching ": ""),
183 (cfg.serve? "udp server ": ""),
184 (cfg.justforw? "forwarding-only ": ""),
185 (cfg.resolver? "resolver ": ""), mntpt);
188 now = time(nil); /* open time files before we fork */
190 dnsuser = estrdup(getuser());
192 snprint(servefile, sizeof servefile, "#s/dns%s", ext);
193 dir = dirstat(servefile);
195 sysfatal("%s exists; another dns instance is running",
198 mountinit(servefile, mntpt); /* forks, parent exits */
203 if (cfg.straddle && !seerootns())
204 dnslog("straddle server misconfigured; can't see root name servers");
216 * if a mount point is specified, set the cs extension to be the mount point
217 * with '_'s replacing '/'s
220 setext(char *ext, int n, char *p)
225 for(i = 0; i < n; i++){
237 mountinit(char *service, char *mntpt)
244 sysfatal("pipe failed: %r");
249 if((f = create(service, OWRITE|ORCLOSE, 0666)) < 0)
250 sysfatal("create %s failed: %r", service);
251 snprint(buf, sizeof buf, "%d", p[1]);
252 if(write(f, buf, strlen(buf)) != strlen(buf))
253 sysfatal("write %s failed: %r", service);
255 /* copy namespace to avoid a deadlock */
256 switch(rfork(RFFDG|RFPROC|RFNAMEG)){
257 case 0: /* child: start main proc */
259 procsetname("%s", mntpt);
262 sysfatal("fork failed: %r");
263 default: /* parent: make /srv/dns, mount it, exit */
267 * put ourselves into the file system
269 if(mount(p[1], -1, mntpt, MAFTER, "") == -1)
270 fprint(2, "dns mount failed: %r\n");
273 mfd[0] = mfd[1] = p[0];
277 newfid(int fid, int needunused)
282 for(mf = mfalloc.inuse; mf != nil; mf = mf->next)
289 mf = emalloc(sizeof(*mf));
292 mf->qid.type = QTDIR;
294 mf->user = estrdup("none");
295 mf->next = mfalloc.inuse;
307 for(l = &mfalloc.inuse; *l != nil; l = &(*l)->next)
311 memset(mf, 0, sizeof *mf); /* cause trouble */
317 sysfatal("freeing unused fid");
321 copyfid(Mfile *mf, int fid)
325 nmf = newfid(fid, 1);
329 free(nmf->user); /* estrdup("none") */
330 nmf->user = estrdup(mf->user);
331 nmf->qid.type = mf->qid.type;
332 nmf->qid.path = mf->qid.path;
333 nmf->qid.vers = vers++;
342 job = emalloc(sizeof *job);
346 job->request.tag = -1;
357 for(l = &joblist; *l; l = &(*l)->next)
360 memset(job, 0, sizeof *job); /* cause trouble */
373 for(job = joblist; job; job = job->next)
374 if(job->request.tag == tag && job->request.type != Tflush){
385 volatile uchar mdata[IOHDRSZ + Maxfdata];
388 volatile Request req;
390 memset(&req, 0, sizeof req);
392 * a slave process is sometimes forked to wait for replies from other
393 * servers. The master process returns immediately via a longjmp
399 while((n = read9pmsg(mfd[0], mdata, sizeof mdata)) != 0){
401 dnslog("error reading 9P from %s: %r", mntpt);
407 if(convM2S(mdata, n, &job->request) != n){
408 dnslog("format error %ux %ux %ux %ux %ux",
409 mdata[0], mdata[1], mdata[2], mdata[3], mdata[4]);
413 mf = newfid(job->request.fid, 0);
415 dnslog("%F", &job->request);
417 getactivity(&req, 0);
418 req.aborttime = timems() + Maxreqtm;
421 switch(job->request.type){
423 warning("unknown request type %d", job->request.type);
450 /* &req is handed to dnresolve() */
451 rwrite(job, mf, &req);
470 * slave processes die after replying
484 if(job->request.msize > IOHDRSZ + Maxfdata)
485 job->reply.msize = IOHDRSZ + Maxfdata;
487 job->reply.msize = job->request.msize;
488 job->reply.version = "9P2000";
489 if(strncmp(job->request.version, "9P", 2) != 0)
490 job->reply.version = "unknown";
497 sendmsg(job, "dns: authentication not required");
501 * don't flush till all the slaves are done
506 flushjob(job->request.oldtag);
511 rattach(Job *job, Mfile *mf)
515 mf->user = estrdup(job->request.uname);
516 mf->qid.vers = vers++;
517 mf->qid.type = QTDIR;
519 job->reply.qid = mf->qid;
524 rwalk(Job *job, Mfile *mf)
534 elems = job->request.wname;
535 nelems = job->request.nwname;
536 job->reply.nwqid = 0;
538 if(job->request.newfid != job->request.fid){
540 nmf = copyfid(mf, job->request.newfid);
542 err = "clone bad newfid";
547 /* else nmf will be nil */
552 for(i=0; i<nelems && i<MAXWELEM; i++){
553 if((qid.type & QTDIR) == 0){
554 err = "not a directory";
557 if (strcmp(elems[i], "..") == 0 ||
558 strcmp(elems[i], ".") == 0){
562 job->reply.wqid[i] = qid;
566 if(strcmp(elems[i], "dns") == 0){
571 err = "file does not exist";
576 if(nmf != nil && (err!=nil || job->reply.nwqid<nelems))
585 ropen(Job *job, Mfile *mf)
591 mode = job->request.mode;
592 if(mf->qid.type & QTDIR)
594 err = "permission denied";
595 job->reply.qid = mf->qid;
596 job->reply.iounit = 0;
601 rcreate(Job *job, Mfile *mf)
604 sendmsg(job, "creation permission denied");
608 rread(Job *job, Mfile *mf)
620 off = job->request.offset;
621 cnt = job->request.count;
623 job->reply.data = (char*)buf;
624 if(mf->qid.type & QTDIR){
627 memset(&dir, 0, sizeof dir);
629 dir.qid.type = QTFILE;
634 dir.uid = dir.gid = dir.muid = mf->user;
635 dir.atime = dir.mtime = clock; /* wrong */
636 n = convD2M(&dir, buf, sizeof buf);
639 err = "negative read offset";
641 /* first offset will always be zero */
642 for(i = 1; i <= mf->nrr; i++)
646 if(off + cnt > mf->rr[i])
651 job->reply.data = mf->reply + off;
654 job->reply.count = n;
659 rwrite(Job *job, Mfile *mf, Request *req)
661 int rooted, wantsav, send;
663 char *err, *p, *atype;
667 cnt = job->request.count;
669 if(mf->qid.type & QTDIR)
670 err = "can't write directory";
671 else if (job->request.offset != 0)
672 err = "writing at non-zero offset";
673 else if(cnt >= Maxrequest)
674 err = "request too long";
680 job->request.data[cnt] = 0;
681 if(cnt > 0 && job->request.data[cnt-1] == '\n')
682 job->request.data[cnt-1] = 0;
684 if(strcmp(mf->user, "none") == 0 || strcmp(mf->user, dnsuser) != 0)
685 goto query; /* skip special commands if not owner */
691 dnslog("rwrite got: %s", job->request.data);
693 if(strcmp(job->request.data, "debug")==0)
695 else if(strcmp(job->request.data, "dump")==0)
696 dndump("/lib/ndb/dnsdump");
697 else if(strcmp(job->request.data, "refresh")==0)
699 else if(strcmp(job->request.data, "stats")==0)
700 dnstats("/lib/ndb/dnsstats");
701 else if(strncmp(job->request.data, "target ", 7)==0){
702 target = atol(job->request.data + 7);
703 dnslog("target set to %ld", target);
711 * kill previous reply
717 * break up request (into a name and a type)
719 atype = strchr(job->request.data, ' ');
721 snprint(errbuf, sizeof errbuf, "illegal request %s",
731 if(strcmp(atype, "trace") == 0){
734 if(*job->request.data)
735 trace = estrdup(job->request.data);
741 /* normal request: domain [type] */
743 mf->type = rrtype(atype);
745 snprint(errbuf, sizeof errbuf, "unknown type %s", atype);
751 if(p >= job->request.data && *p == '.'){
757 p = job->request.data;
764 err = lookupquery(job, mf, req, errbuf, p, wantsav, rooted);
766 job->reply.count = cnt;
772 * rr = dnresolve(buf, Cin, type, &req, nil, 0, Recurse, rooted, nil);
773 * which generates a UDP query, which eventually calls
774 * dnserver(&reqmsg, &repmsg, &req, buf, rcode);
776 * rp = dnresolve(name, Cin, type, req, &mp->an, 0, recurse, 1, nil);
778 * but here we just call dnresolve directly.
781 lookupquery(Job *job, Mfile *mf, Request *req, char *errbuf, char *p,
782 int wantsav, int rooted)
788 rp = dnresolve(p, Cin, mf->type, req, nil, 0, Recurse, rooted, &status);
792 status = neg->negrcode;
796 return respond(job, mf, rp, errbuf, status, wantsav);
800 respond(Job *job, Mfile *mf, RR *rp, char *errbuf, int status, int wantsav)
808 return "name does not exist";
810 return "dns failure";
813 snprint(errbuf, ERRMAX,
814 "resource does not exist; negrcode %d", status);
820 /* format data to be read later */
823 for(tp = rp; mf->nrr < Maxrrr-1 && n < Maxreply && tp &&
824 tsame(mf->type, tp->type); tp = tp->next){
825 mf->rr[mf->nrr++] = n;
827 n += snprint(mf->reply+n, Maxreply-n, "%Q", tp);
829 n += snprint(mf->reply+n, Maxreply-n, "%R", tp);
841 rclunk(Job *job, Mfile *mf)
848 rremove(Job *job, Mfile *mf)
851 sendmsg(job, "remove permission denied");
855 rstat(Job *job, Mfile *mf)
858 uchar buf[IOHDRSZ+Maxfdata];
860 memset(&dir, 0, sizeof dir);
861 if(mf->qid.type & QTDIR){
863 dir.mode = DMDIR|0555;
870 dir.uid = dir.gid = dir.muid = mf->user;
871 dir.atime = dir.mtime = time(nil);
872 job->reply.nstat = convD2M(&dir, buf, sizeof buf);
873 job->reply.stat = buf;
878 rwstat(Job *job, Mfile *mf)
881 sendmsg(job, "wstat permission denied");
885 sendmsg(Job *job, char *err)
888 uchar mdata[IOHDRSZ + Maxfdata];
892 job->reply.type = Rerror;
893 snprint(ename, sizeof ename, "dns: %s", err);
894 job->reply.ename = ename;
896 job->reply.type = job->request.type+1;
897 job->reply.tag = job->request.tag;
898 n = convS2M(&job->reply, mdata, sizeof mdata);
900 warning("sendmsg convS2M of %F returns 0", &job->reply);
904 if(job->flushed == 0)
905 if(write(mfd[1], mdata, n)!=n)
906 sysfatal("mount write");
909 dnslog("%F %d", &job->reply, n);
913 * the following varies between dnsdebug and dns
916 logreply(int id, uchar *addr, DNSmsg *mp)
920 dnslog("%d: rcvd %I flags:%s%s%s%s%s", id, addr,
921 mp->flags & Fauth? " auth": "",
922 mp->flags & Ftrunc? " trunc": "",
923 mp->flags & Frecurse? " rd": "",
924 mp->flags & Fcanrec? " ra": "",
925 (mp->flags & (Fauth|Rmask)) == (Fauth|Rname)? " nx": "");
926 for(rp = mp->qd; rp != nil; rp = rp->next)
927 dnslog("%d: rcvd %I qd %s", id, addr, rp->owner->name);
928 for(rp = mp->an; rp != nil; rp = rp->next)
929 dnslog("%d: rcvd %I an %R", id, addr, rp);
930 for(rp = mp->ns; rp != nil; rp = rp->next)
931 dnslog("%d: rcvd %I ns %R", id, addr, rp);
932 for(rp = mp->ar; rp != nil; rp = rp->next)
933 dnslog("%d: rcvd %I ar %R", id, addr, rp);
937 logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type)
941 dnslog("[%d] %d.%d: sending to %I/%s %s %s",
942 getpid(), id, subid, addr, sname, rname,
943 rrname(type, buf, sizeof buf));
947 getdnsservers(int class)
949 return dnsservers(class);