14 Maxreply= 8192, /* was 512 */
15 Maxrrr= 32, /* was 16 */
18 Defmaxage= 60*60, /* default domain name max. age */
24 typedef struct Mfile Mfile;
25 typedef struct Job Job;
26 typedef struct Network Network;
28 int vers; /* incremented each clone/attach */
30 static volatile int stop;
32 /* holds data to be returned via read of /net/dns, perhaps multiple reads */
35 Mfile *next; /* next free mfile */
42 int type; /* reply type */
44 ushort rr[Maxrrr]; /* offset of rr's */
45 ushort nrr; /* number of rr's */
49 * active local requests
63 Mfile *inuse; /* active mfile's */
68 uchar ipaddr[IPaddrlen]; /* my ip address */
69 int maxage = Defmaxage;
78 char *zonerefreshprogram;
80 char *logfile = "dns"; /* or "dns.test" */
84 int addforwtarg(char *);
85 int fillreply(Mfile*, int);
88 void mountinit(char*, char*);
90 void rattach(Job*, Mfile*);
92 void rclunk(Job*, Mfile*);
93 void rcreate(Job*, Mfile*);
95 void ropen(Job*, Mfile*);
96 void rread(Job*, Mfile*);
97 void rremove(Job*, Mfile*);
98 void rstat(Job*, Mfile*);
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*);
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);
113 fprint(2, "usage: %s [-FnorRst] [-a maxage] [-f ndb-file] [-N target] "
114 "[-T forwip] [-x netmtpt] [-z refreshprog]\n", argv0);
119 main(int argc, char *argv[])
122 char servefile[Maxpath], ext[Maxpath];
125 setnetmtpt(mntpt, sizeof mntpt, nil);
129 maxage = atol(EARGF(usage()));
138 dbfile = EARGF(usage());
141 cfg.justforw = cfg.resolver = 1;
147 target = atol(EARGF(usage()));
152 cfg.straddle = 1; /* straddle inside & outside networks */
161 cfg.serve = 1; /* serve network */
168 addforwtarg(EARGF(usage()));
171 setnetmtpt(mntpt, sizeof mntpt, EARGF(usage()));
172 setext(ext, sizeof ext, mntpt);
175 zonerefreshprogram = EARGF(usage());
185 mainmem->flags |= POOL_NOREUSE | POOL_ANTAGONISM;
186 mainmem->flags |= POOL_ANTAGONISM;
187 rfork(RFREND|RFNOTEG);
189 cfg.inside = (*mntpt == '\0' || strcmp(mntpt, "/net") == 0);
191 /* start syslog before we fork */
192 fmtinstall('F', fcallfmt);
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);
205 now = time(nil); /* open time files before we fork */
208 snprint(servefile, sizeof servefile, "#s/dns%s", ext);
209 dir = dirstat(servefile);
211 sysfatal("%s exists; another dns instance is running",
214 // unmount(servefile, mntpt);
215 // remove(servefile);
217 mountinit(servefile, mntpt); /* forks, parent exits */
223 if (cfg.straddle && !seerootns())
224 dnslog("straddle server misconfigured; can't see root name servers");
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.
233 kid = rfork(RFPROC|RFFDG|RFNOTEG);
236 sysfatal("fork failed: %r");
245 while ((pid = waitpid()) != kid && pid != -1)
249 dnslog("dns restarting");
254 * if a mount point is specified, set the cs extension to be the mount point
255 * with '_'s replacing '/'s
258 setext(char *ext, int n, char *p)
263 for(i = 0; i < n; i++){
275 mountinit(char *service, char *mntpt)
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 */
287 procsetname("%s restarter", mntpt);
290 abort(); /* "fork failed\n" */;
291 default: /* parent: make /srv/dns, mount it, exit */
297 f = create(service, 1, 0666);
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 */;
306 * put ourselves into the file system
308 if(mount(p[1], -1, mntpt, MAFTER, "") < 0)
309 fprint(2, "dns mount failed: %r\n");
312 mfd[0] = mfd[1] = p[0];
316 newfid(int fid, int needunused)
321 for(mf = mfalloc.inuse; mf != nil; mf = mf->next)
328 mf = emalloc(sizeof(*mf));
330 mf->user = estrdup("dummy");
331 mf->next = mfalloc.inuse;
343 for(l = &mfalloc.inuse; *l != nil; l = &(*l)->next)
348 memset(mf, 0, sizeof *mf); /* cause trouble */
354 sysfatal("freeing unused fid");
358 copyfid(Mfile *mf, int fid)
362 nmf = newfid(fid, 1);
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++;
379 job = emalloc(sizeof *job);
383 job->request.tag = -1;
394 for(l = &joblist; *l; l = &(*l)->next)
397 memset(job, 0, sizeof *job); /* cause trouble */
410 for(job = joblist; job; job = job->next)
411 if(job->request.tag == tag && job->request.type != Tflush){
422 volatile uchar mdata[IOHDRSZ + Maxfdata];
425 volatile Request req;
427 memset(&req, 0, sizeof req);
429 * a slave process is sometimes forked to wait for replies from other
430 * servers. The master process returns immediately via a longjmp
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);
442 dnslog("error reading 9P from %s: %r", mntpt);
443 sleep(2000); /* don't thrash after read error */
449 if(convM2S(mdata, n, &job->request) != n){
453 mf = newfid(job->request.fid, 0);
455 dnslog("%F", &job->request);
457 getactivity(&req, 0);
458 req.aborttime = timems() + Maxreqtm;
461 switch(job->request.type){
463 warning("unknown request type %d", job->request.type);
490 /* &req is handed to dnresolve() */
491 rwrite(job, mf, &req);
510 * slave processes die after replying
519 /* kill any udp server, notifier, etc. processes */
520 postnote(PNGROUP, getpid(), "die");
527 if(job->request.msize > IOHDRSZ + Maxfdata)
528 job->reply.msize = IOHDRSZ + Maxfdata;
530 job->reply.msize = job->request.msize;
531 if(strncmp(job->request.version, "9P2000", 6) != 0)
532 sendmsg(job, "unknown 9P version");
534 job->reply.version = "9P2000";
542 sendmsg(job, "dns: authentication not required");
546 * don't flush till all the slaves are done
551 flushjob(job->request.oldtag);
556 rattach(Job *job, Mfile *mf)
560 mf->user = estrdup(job->request.uname);
561 mf->qid.vers = vers++;
562 mf->qid.type = QTDIR;
564 job->reply.qid = mf->qid;
569 rwalk(Job *job, Mfile *mf)
579 elems = job->request.wname;
580 nelems = job->request.nwname;
581 job->reply.nwqid = 0;
583 if(job->request.newfid != job->request.fid){
585 nmf = copyfid(mf, job->request.newfid);
587 err = "clone bad newfid";
592 /* else nmf will be nil */
597 for(i=0; i<nelems && i<MAXWELEM; i++){
598 if((qid.type & QTDIR) == 0){
599 err = "not a directory";
602 if (strcmp(elems[i], "..") == 0 ||
603 strcmp(elems[i], ".") == 0){
607 job->reply.wqid[i] = qid;
611 if(strcmp(elems[i], "dns") == 0){
616 err = "file does not exist";
621 if(nmf != nil && (err!=nil || job->reply.nwqid<nelems))
630 ropen(Job *job, Mfile *mf)
636 mode = job->request.mode;
637 if(mf->qid.type & QTDIR)
639 err = "permission denied";
640 job->reply.qid = mf->qid;
641 job->reply.iounit = 0;
646 rcreate(Job *job, Mfile *mf)
649 sendmsg(job, "creation permission denied");
653 rread(Job *job, Mfile *mf)
665 off = job->request.offset;
666 cnt = job->request.count;
668 job->reply.data = (char*)buf;
669 if(mf->qid.type & QTDIR){
672 memset(&dir, 0, sizeof dir);
674 dir.qid.type = QTFILE;
679 dir.uid = dir.gid = dir.muid = mf->user;
680 dir.atime = dir.mtime = clock; /* wrong */
681 n = convD2M(&dir, buf, sizeof buf);
684 err = "negative read offset";
686 /* first offset will always be zero */
687 for(i = 1; i <= mf->nrr; i++)
691 if(off + cnt > mf->rr[i])
696 job->reply.data = mf->reply + off;
699 job->reply.count = n;
704 rwrite(Job *job, Mfile *mf, Request *req)
706 int rooted, wantsav, send;
708 char *err, *p, *atype;
712 cnt = job->request.count;
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";
725 job->request.data[cnt] = 0;
726 if(cnt > 0 && job->request.data[cnt-1] == '\n')
727 job->request.data[cnt-1] = 0;
732 // dnslog("rwrite got: %s", job->request.data);
734 if(strcmp(job->request.data, "age")==0){
735 dnslog("dump, age & dump forced");
736 dndump("/lib/ndb/dnsdump1");
738 dndump("/lib/ndb/dnsdump2");
739 } else if(strcmp(job->request.data, "debug")==0)
741 else if(strcmp(job->request.data, "dump")==0)
742 dndump("/lib/ndb/dnsdump");
743 else if(strcmp(job->request.data, "poolcheck")==0)
745 else if(strcmp(job->request.data, "refresh")==0)
747 else if(strcmp(job->request.data, "restart")==0)
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);
760 * kill previous reply
766 * break up request (into a name and a type)
768 atype = strchr(job->request.data, ' ');
770 snprint(errbuf, sizeof errbuf, "illegal request %s",
780 if(strcmp(atype, "trace") == 0){
783 if(*job->request.data)
784 trace = estrdup(job->request.data);
790 /* normal request: domain [type] */
792 mf->type = rrtype(atype);
794 snprint(errbuf, sizeof errbuf, "unknown type %s", atype);
800 if(p >= job->request.data && *p == '.'){
806 p = job->request.data;
813 err = lookupqueryold(job, mf, req, errbuf, p, wantsav, rooted);
816 job->reply.count = cnt;
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);
826 * rp = dnresolve(name, Cin, type, req, &mp->an, 0, recurse, 1, 0);
828 * but here we just call dnresolve directly.
831 lookupqueryold(Job *job, Mfile *mf, Request *req, char *errbuf, char *p,
832 int wantsav, int rooted)
839 rp = dnresolve(p, Cin, mf->type, req, 0, 0, Recurse, rooted, &status);
845 status = neg->negrcode;
850 return respond(job, mf, rp, errbuf, status, wantsav);
854 respond(Job *job, Mfile *mf, RR *rp, char *errbuf, int status, int wantsav)
862 return "name does not exist";
864 return "dns failure";
867 snprint(errbuf, ERRMAX,
868 "resource does not exist; negrcode %d", status);
874 /* format data to be read later */
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;
881 n += snprint(mf->reply+n, Maxreply-n, "%Q", tp);
883 n += snprint(mf->reply+n, Maxreply-n, "%R", tp);
892 /* simulate what dnsudpserver does */
894 lookupquerynew(Job *job, Mfile *mf, Request *req, char *errbuf, char *p,
898 uchar buf[Udphdrsize + Maxudp + 1024];
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());
910 dnserver(mp, &repmsg, req, buf, Rok);
913 err = respond(job, mf, repmsg.an, errbuf, Rok, wantsav);
914 repmsg.an = nil; /* freed above */
915 freeanswers(&repmsg);
920 rclunk(Job *job, Mfile *mf)
927 rremove(Job *job, Mfile *mf)
930 sendmsg(job, "remove permission denied");
934 rstat(Job *job, Mfile *mf)
937 uchar buf[IOHDRSZ+Maxfdata];
939 memset(&dir, 0, sizeof dir);
940 if(mf->qid.type & QTDIR){
942 dir.mode = DMDIR|0555;
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;
957 rwstat(Job *job, Mfile *mf)
960 sendmsg(job, "wstat permission denied");
964 sendmsg(Job *job, char *err)
967 uchar mdata[IOHDRSZ + Maxfdata];
971 job->reply.type = Rerror;
972 snprint(ename, sizeof ename, "dns: %s", err);
973 job->reply.ename = ename;
975 job->reply.type = job->request.type+1;
976 job->reply.tag = job->request.tag;
977 n = convS2M(&job->reply, mdata, sizeof mdata);
979 warning("sendmsg convS2M of %F returns 0", &job->reply);
983 if(job->flushed == 0)
984 if(write(mfd[1], mdata, n)!=n)
985 sysfatal("mount write");
988 dnslog("%F %d", &job->reply, n);
992 * the following varies between dnsdebug and dns
995 logreply(int id, uchar *addr, DNSmsg *mp)
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);
1016 logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type)
1020 dnslog("[%d] %d.%d: sending to %I/%s %s %s",
1021 getpid(), id, subid, addr, sname, rname,
1022 rrname(type, buf, sizeof buf));
1026 getdnsservers(int class)
1028 return dnsservers(class);