25 typedef struct Mfile Mfile;
26 typedef struct Job Job;
27 typedef struct Network Network;
29 int vers; /* incremented each clone/attach */
33 Mfile *next; /* next free mfile */
40 int type; /* reply type */
42 ushort rr[Maxrrr]; /* offset of rr's */
43 ushort nrr; /* number of rr's */
47 * active local requests
61 Mfile *inuse; /* active mfile's */
73 uchar ipaddr[IPaddrlen]; /* my ip address */
75 char *zonerefreshprogram;
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*);
94 int fillreply(Mfile*, int);
97 void setext(char*, int, char*);
99 char *tcpaddr = "tcp!*!domain";
100 char *udpaddr = "udp!*!domain";
101 char *logfile = "dns";
109 fprint(2, "usage: dns [-dnrst] [-a maxage] [-f ndb-file] [-T tcpaddr] [-U udpaddr] [-x service] [-z zoneprog]\n");
110 threadexitsall("usage");
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);
125 threadmain(int argc, char *argv[])
127 int serveudp, servetcp;
139 dbfile = EARGF(usage());
142 service = EARGF(usage());
156 maxage = atoi(EARGF(usage()));
159 zonerefreshprogram = EARGF(usage());
165 udpaddr = estrdup(netmkaddr(EARGF(usage()), "udp", "domain"));
168 tcpaddr = estrdup(netmkaddr(EARGF(usage()), "tcp", "domain"));
176 if(serveudp && servetcp)
181 /* start syslog before we fork */
182 fmtinstall('F', fcallfmt);
184 if(myipaddr(ipaddr, mntpt) < 0)
185 sysfatal("can't read my ip address");
187 syslog(0, logfile, "starting dns on %I", ipaddr);
198 proccreate(dnudpserver, nil, STACK);
200 proccreate(dntcpserver, nil, STACK);
202 proccreate(notifyproc, nil, STACK);
208 * if a mount point is specified, set the cs extention to be the mount point
209 * with '_'s replacing '/'s
212 setext(char *ext, int n, char *p)
217 for(i = 0; i < n; i++){
229 mountinit(char *service)
234 abort(); /* "pipe failed" */;
235 if(post9pservice(p[1], service) < 0)
236 fprint(2, "post9pservice dns: %r\n");
238 mfd[0] = mfd[1] = p[0];
242 newfid(int fid, int needunused)
247 for(mf = mfalloc.inuse; mf != nil; mf = mf->next){
259 mf = emalloc(sizeof(*mf));
261 sysfatal("out of memory");
263 mf->next = mfalloc.inuse;
275 for(l = &mfalloc.inuse; *l != nil; l = &(*l)->next){
285 sysfatal("freeing unused fid");
289 copyfid(Mfile *mf, int fid)
293 nmf = newfid(fid, 1);
297 nmf->user = estrdup(mf->user);
298 nmf->qid.type = mf->qid.type;
299 nmf->qid.path = mf->qid.path;
300 nmf->qid.vers = vers++;
309 job = emalloc(sizeof(*job));
313 job->request.tag = -1;
324 for(l = &joblist; *l; l = &(*l)->next){
340 for(job = joblist; job; job = job->next){
341 if(job->request.tag == tag && job->request.type != Tflush){
354 uchar mdata[IOHDRSZ + Maxfdata];
361 n = read9pmsg(mfd[0], mdata, sizeof mdata);
363 syslog(0, logfile, "error reading mntpt: %r");
367 if(convM2S(mdata, n, &job->request) != n){
372 syslog(0, logfile, "%F", &job->request);
375 req.aborttime = now + 60; /* don't spend more than 60 seconds */
378 switch(job->request.type){
384 mf = newfid(job->request.fid, 1);
386 sendmsg(job, "fid in use");
391 mf = newfid(job->request.fid, 0);
393 sendmsg(job, "unknown fid");
399 switch(job->request.type){
401 syslog(1, logfile, "unknown request type %d", job->request.type);
428 rwrite(job, mf, &req);
454 for(i=0; i<Maxactive; i++)
455 proccreate(ioproc0, 0, STACK);
461 if(job->request.msize > IOHDRSZ + Maxfdata)
462 job->reply.msize = IOHDRSZ + Maxfdata;
464 job->reply.msize = job->request.msize;
465 if(strncmp(job->request.version, "9P2000", 6) != 0)
466 sendmsg(job, "unknown 9P version");
468 job->reply.version = "9P2000";
476 sendmsg(job, "dns: authentication not required");
480 * don't flush till all the slaves are done
485 flushjob(job->request.oldtag);
490 rattach(Job *job, Mfile *mf)
494 mf->user = estrdup(job->request.uname);
495 mf->qid.vers = vers++;
496 mf->qid.type = QTDIR;
498 job->reply.qid = mf->qid;
503 rwalk(Job *job, Mfile *mf)
514 elems = job->request.wname;
515 nelems = job->request.nwname;
516 job->reply.nwqid = 0;
518 if(job->request.newfid != job->request.fid){
520 if(job->request.newfid<0){
521 err = "clone newfid out of range";
524 nmf = copyfid(mf, job->request.newfid);
526 err = "clone bad newfid";
531 /* else nmf will be nil */
536 for(i=0; i<nelems && i<MAXWELEM; i++){
537 if((qid.type & QTDIR) == 0){
538 err = "not a directory";
541 if(strcmp(elems[i], "..") == 0 || strcmp(elems[i], ".") == 0){
545 job->reply.wqid[i] = qid;
549 if(strcmp(elems[i], "dns") == 0){
554 err = "file does not exist";
560 if(nmf != nil && (err!=nil || job->reply.nwqid<nelems))
569 ropen(Job *job, Mfile *mf)
575 mode = job->request.mode;
576 if(mf->qid.type & QTDIR){
578 err = "permission denied";
580 job->reply.qid = mf->qid;
581 job->reply.iounit = 0;
586 rcreate(Job *job, Mfile *mf)
589 sendmsg(job, "creation permission denied");
593 rread(Job *job, Mfile *mf)
604 off = job->request.offset;
605 cnt = job->request.count;
606 if(mf->qid.type & QTDIR){
610 dir.qid.type = QTFILE;
618 dir.atime = clock; /* wrong */
619 dir.mtime = clock; /* wrong */
620 n = convD2M(&dir, buf, sizeof buf);
622 job->reply.data = (char*)buf;
624 for(i = 1; i <= mf->nrr; i++)
629 if(off + cnt > mf->rr[i])
633 job->reply.data = mf->reply + off;
636 job->reply.count = n;
641 rwrite(Job *job, Mfile *mf, Request *req)
643 int cnt, rooted, status;
645 char *err, *p, *atype;
648 static char *dumpfile;
651 cnt = job->request.count;
652 if(mf->qid.type & QTDIR){
653 err = "can't write directory";
656 if(cnt >= Maxrequest){
657 err = "request too long";
660 job->request.data[cnt] = 0;
661 if(cnt > 0 && job->request.data[cnt-1] == '\n')
662 job->request.data[cnt-1] = 0;
667 p = job->request.data;
668 if(strcmp(p, "debug")==0){
671 } else if(strcmp(p, "dump")==0){
673 dumpfile = unsharp("#9/ndb/dnsdump");
676 } else if(strncmp(p, "dump ", 5) == 0){
680 err = "bad filename";
682 } else if(strcmp(p, "refresh")==0){
688 * kill previous reply
694 * break up request (into a name and a type)
696 atype = strchr(job->request.data, ' ');
698 err = "illegal request";
706 if(strcmp(atype, "trace") == 0){
709 if(*job->request.data)
710 trace = estrdup(job->request.data);
716 mf->type = rrtype(atype);
718 err = "unknown type";
723 if(p >= job->request.data && *p == '.'){
729 p = job->request.data;
736 rp = dnresolve(p, Cin, mf->type, req, 0, 0, Recurse, rooted, &status);
740 status = neg->negrcode;
746 err = "name does not exist";
752 err = "resource does not exist";
758 /* format data to be read later */
761 for(tp = rp; mf->nrr < Maxrrr-1 && n < Maxreply && tp &&
762 tsame(mf->type, tp->type); tp = tp->next){
763 mf->rr[mf->nrr++] = n;
765 n += snprint(mf->reply+n, Maxreply-n, "%Q", tp);
767 n += snprint(mf->reply+n, Maxreply-n, "%R", tp);
777 job->reply.count = cnt;
782 rclunk(Job *job, Mfile *mf)
789 rremove(Job *job, Mfile *mf)
792 sendmsg(job, "remove permission denied");
796 rstat(Job *job, Mfile *mf)
799 uchar buf[IOHDRSZ+Maxfdata];
801 if(mf->qid.type & QTDIR){
803 dir.mode = DMDIR|0555;
813 dir.atime = dir.mtime = time(0);
814 job->reply.nstat = convD2M(&dir, buf, sizeof buf);
815 job->reply.stat = buf;
820 rwstat(Job *job, Mfile *mf)
823 sendmsg(job, "wstat permission denied");
827 sendmsg(Job *job, char *err)
830 uchar mdata[IOHDRSZ + Maxfdata];
834 job->reply.type = Rerror;
835 snprint(ename, sizeof(ename), "dns: %s", err);
836 job->reply.ename = ename;
838 job->reply.type = job->request.type+1;
840 job->reply.tag = job->request.tag;
841 n = convS2M(&job->reply, mdata, sizeof mdata);
843 syslog(1, logfile, "sendmsg convS2M of %F returns 0", &job->reply);
847 if(job->flushed == 0)
848 if(write(mfd[1], mdata, n)!=n)
849 sysfatal("mount write");
852 syslog(0, logfile, "%F %d", &job->reply, n);
856 * the following varies between dnsdebug and dns
859 logreply(int id, uchar *addr, DNSmsg *mp)
863 syslog(0, LOG, "%d: rcvd %I flags:%s%s%s%s%s", id, addr,
864 mp->flags & Fauth ? " auth" : "",
865 mp->flags & Ftrunc ? " trunc" : "",
866 mp->flags & Frecurse ? " rd" : "",
867 mp->flags & Fcanrec ? " ra" : "",
868 mp->flags & (Fauth|Rname) == (Fauth|Rname) ?
870 for(rp = mp->qd; rp != nil; rp = rp->next)
871 syslog(0, LOG, "%d: rcvd %I qd %s", id, addr, rp->owner->name);
872 for(rp = mp->an; rp != nil; rp = rp->next)
873 syslog(0, LOG, "%d: rcvd %I an %R", id, addr, rp);
874 for(rp = mp->ns; rp != nil; rp = rp->next)
875 syslog(0, LOG, "%d: rcvd %I ns %R", id, addr, rp);
876 for(rp = mp->ar; rp != nil; rp = rp->next)
877 syslog(0, LOG, "%d: rcvd %I ar %R", id, addr, rp);
881 logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type)
885 syslog(0, LOG, "%d.%d: sending to %I/%s %s %s",
886 id, subid, addr, sname, rname, rrname(type, buf, sizeof buf));
890 getdnsservers(int class)
892 return dnsservers(class);