diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/ndb/dns.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/ndb/dns.c')
-rwxr-xr-x | sys/src/cmd/ndb/dns.c | 1029 |
1 files changed, 1029 insertions, 0 deletions
diff --git a/sys/src/cmd/ndb/dns.c b/sys/src/cmd/ndb/dns.c new file mode 100755 index 000000000..1bab66875 --- /dev/null +++ b/sys/src/cmd/ndb/dns.c @@ -0,0 +1,1029 @@ +#include <u.h> +#include <libc.h> +#include <auth.h> +#include <fcall.h> +#include <bio.h> +#include <ctype.h> +#include <ip.h> +#include <pool.h> +#include "dns.h" + +enum +{ + Maxrequest= 1024, + Maxreply= 8192, /* was 512 */ + Maxrrr= 32, /* was 16 */ + Maxfdata= 8192, + + Defmaxage= 60*60, /* default domain name max. age */ + + Qdir= 0, + Qdns= 1, +}; + +typedef struct Mfile Mfile; +typedef struct Job Job; +typedef struct Network Network; + +int vers; /* incremented each clone/attach */ + +static volatile int stop; + +/* holds data to be returned via read of /net/dns, perhaps multiple reads */ +struct Mfile +{ + Mfile *next; /* next free mfile */ + int ref; + + char *user; + Qid qid; + int fid; + + int type; /* reply type */ + char reply[Maxreply]; + ushort rr[Maxrrr]; /* offset of rr's */ + ushort nrr; /* number of rr's */ +}; + +/* + * active local requests + */ +struct Job +{ + Job *next; + int flushed; + Fcall request; + Fcall reply; +}; +Lock joblock; +Job *joblist; + +struct { + Lock; + Mfile *inuse; /* active mfile's */ +} mfalloc; + +Cfg cfg; +int debug; +uchar ipaddr[IPaddrlen]; /* my ip address */ +int maxage = Defmaxage; +int mfd[2]; +int needrefresh; +ulong now; +vlong nowns; +int sendnotifies; +int testing; +char *trace; +int traceactivity; +char *zonerefreshprogram; + +char *logfile = "dns"; /* or "dns.test" */ +char *dbfile; +char mntpt[Maxpath]; + +int addforwtarg(char *); +int fillreply(Mfile*, int); +void freejob(Job*); +void io(void); +void mountinit(char*, char*); +Job* newjob(void); +void rattach(Job*, Mfile*); +void rauth(Job*); +void rclunk(Job*, Mfile*); +void rcreate(Job*, Mfile*); +void rflush(Job*); +void ropen(Job*, Mfile*); +void rread(Job*, Mfile*); +void rremove(Job*, Mfile*); +void rstat(Job*, Mfile*); +void rversion(Job*); +char* rwalk(Job*, Mfile*); +void rwrite(Job*, Mfile*, Request*); +void rwstat(Job*, Mfile*); +void sendmsg(Job*, char*); +void setext(char*, int, char*); + +static char *lookupqueryold(Job*, Mfile*, Request*, char*, char*, int, int); +static char *lookupquerynew(Job*, Mfile*, Request*, char*, char*, int, int); +static char *respond(Job*, Mfile*, RR*, char*, int, int); + +void +usage(void) +{ + fprint(2, "usage: %s [-FnorRst] [-a maxage] [-f ndb-file] [-N target] " + "[-T forwip] [-x netmtpt] [-z refreshprog]\n", argv0); + exits("usage"); +} + +void +main(int argc, char *argv[]) +{ + int kid, pid; + char servefile[Maxpath], ext[Maxpath]; + Dir *dir; + + setnetmtpt(mntpt, sizeof mntpt, nil); + ext[0] = 0; + ARGBEGIN{ + case 'a': + maxage = atol(EARGF(usage())); + if (maxage <= 0) + maxage = Defmaxage; + break; + case 'd': + debug = 1; + traceactivity = 1; + break; + case 'f': + dbfile = EARGF(usage()); + break; + case 'F': + cfg.justforw = cfg.resolver = 1; + break; + case 'n': + sendnotifies = 1; + break; + case 'N': + target = atol(EARGF(usage())); + if (target < 1000) + target = 1000; + break; + case 'o': + cfg.straddle = 1; /* straddle inside & outside networks */ + break; + case 'r': + cfg.resolver = 1; + break; + case 'R': + norecursion = 1; + break; + case 's': + cfg.serve = 1; /* serve network */ + cfg.cachedb = 1; + break; + case 't': + testing = 1; + break; + case 'T': + addforwtarg(EARGF(usage())); + break; + case 'x': + setnetmtpt(mntpt, sizeof mntpt, EARGF(usage())); + setext(ext, sizeof ext, mntpt); + break; + case 'z': + zonerefreshprogram = EARGF(usage()); + break; + default: + usage(); + break; + }ARGEND + if(argc != 0) + usage(); + + if(testing) + mainmem->flags |= POOL_NOREUSE | POOL_ANTAGONISM; + mainmem->flags |= POOL_ANTAGONISM; + rfork(RFREND|RFNOTEG); + + cfg.inside = (*mntpt == '\0' || strcmp(mntpt, "/net") == 0); + + /* start syslog before we fork */ + fmtinstall('F', fcallfmt); + dninit(); + /* this really shouldn't be fatal */ + if(myipaddr(ipaddr, mntpt) < 0) + sysfatal("can't read my ip address"); + dnslog("starting %s%sdns %s%s%son %I's %s", + (cfg.straddle? "straddling ": ""), + (cfg.cachedb? "caching ": ""), + (cfg.serve? "udp server ": ""), + (cfg.justforw? "forwarding-only ": ""), + (cfg.resolver? "resolver ": ""), ipaddr, mntpt); + + opendatabase(); + now = time(nil); /* open time files before we fork */ + nowns = nsec(); + + snprint(servefile, sizeof servefile, "#s/dns%s", ext); + dir = dirstat(servefile); + if (dir) + sysfatal("%s exists; another dns instance is running", + servefile); + free(dir); +// unmount(servefile, mntpt); +// remove(servefile); + + mountinit(servefile, mntpt); /* forks, parent exits */ + + srand(now*getpid()); + db2cache(1); +// dnageallnever(); + + if (cfg.straddle && !seerootns()) + dnslog("straddle server misconfigured; can't see root name servers"); + /* + * fork without sharing heap. + * parent waits around for child to die, then forks & restarts. + * child may spawn udp server, notify procs, etc.; when it gets too + * big, it kills itself and any children. + * /srv/dns and /net/dns remain open and valid. + */ + for (;;) { + kid = rfork(RFPROC|RFFDG|RFNOTEG); + switch (kid) { + case -1: + sysfatal("fork failed: %r"); + case 0: + if(cfg.serve) + dnudpserver(mntpt); + if(sendnotifies) + notifyproc(); + io(); + _exits("restart"); + default: + while ((pid = waitpid()) != kid && pid != -1) + continue; + break; + } + dnslog("dns restarting"); + } +} + +/* + * if a mount point is specified, set the cs extension to be the mount point + * with '_'s replacing '/'s + */ +void +setext(char *ext, int n, char *p) +{ + int i, c; + + n--; + for(i = 0; i < n; i++){ + c = p[i]; + if(c == 0) + break; + if(c == '/') + c = '_'; + ext[i] = c; + } + ext[i] = 0; +} + +void +mountinit(char *service, char *mntpt) +{ + int f; + int p[2]; + char buf[32]; + + if(pipe(p) < 0) + abort(); /* "pipe failed" */; + /* copy namespace to avoid a deadlock */ + switch(rfork(RFFDG|RFPROC|RFNAMEG)){ + case 0: /* child: hang around and (re)start main proc */ + close(p[1]); + procsetname("%s restarter", mntpt); + break; + case -1: + abort(); /* "fork failed\n" */; + default: /* parent: make /srv/dns, mount it, exit */ + close(p[0]); + + /* + * make a /srv/dns + */ + f = create(service, 1, 0666); + if(f < 0) + abort(); /* service */; + snprint(buf, sizeof buf, "%d", p[1]); + if(write(f, buf, strlen(buf)) != strlen(buf)) + abort(); /* "write %s", service */; + close(f); + + /* + * put ourselves into the file system + */ + if(mount(p[1], -1, mntpt, MAFTER, "") < 0) + fprint(2, "dns mount failed: %r\n"); + _exits(0); + } + mfd[0] = mfd[1] = p[0]; +} + +Mfile* +newfid(int fid, int needunused) +{ + Mfile *mf; + + lock(&mfalloc); + for(mf = mfalloc.inuse; mf != nil; mf = mf->next) + if(mf->fid == fid){ + unlock(&mfalloc); + if(needunused) + return nil; + return mf; + } + mf = emalloc(sizeof(*mf)); + mf->fid = fid; + mf->user = estrdup("dummy"); + mf->next = mfalloc.inuse; + mfalloc.inuse = mf; + unlock(&mfalloc); + return mf; +} + +void +freefid(Mfile *mf) +{ + Mfile **l; + + lock(&mfalloc); + for(l = &mfalloc.inuse; *l != nil; l = &(*l)->next) + if(*l == mf){ + *l = mf->next; + if(mf->user) + free(mf->user); + memset(mf, 0, sizeof *mf); /* cause trouble */ + free(mf); + unlock(&mfalloc); + return; + } + unlock(&mfalloc); + sysfatal("freeing unused fid"); +} + +Mfile* +copyfid(Mfile *mf, int fid) +{ + Mfile *nmf; + + nmf = newfid(fid, 1); + if(nmf == nil) + return nil; + nmf->fid = fid; + free(nmf->user); /* estrdup("dummy") */ + nmf->user = estrdup(mf->user); + nmf->qid.type = mf->qid.type; + nmf->qid.path = mf->qid.path; + nmf->qid.vers = vers++; + return nmf; +} + +Job* +newjob(void) +{ + Job *job; + + job = emalloc(sizeof *job); + lock(&joblock); + job->next = joblist; + joblist = job; + job->request.tag = -1; + unlock(&joblock); + return job; +} + +void +freejob(Job *job) +{ + Job **l; + + lock(&joblock); + for(l = &joblist; *l; l = &(*l)->next) + if(*l == job){ + *l = job->next; + memset(job, 0, sizeof *job); /* cause trouble */ + free(job); + break; + } + unlock(&joblock); +} + +void +flushjob(int tag) +{ + Job *job; + + lock(&joblock); + for(job = joblist; job; job = job->next) + if(job->request.tag == tag && job->request.type != Tflush){ + job->flushed = 1; + break; + } + unlock(&joblock); +} + +void +io(void) +{ + volatile long n; + volatile uchar mdata[IOHDRSZ + Maxfdata]; + Job *volatile job; + Mfile *volatile mf; + volatile Request req; + + memset(&req, 0, sizeof req); + /* + * a slave process is sometimes forked to wait for replies from other + * servers. The master process returns immediately via a longjmp + * through 'mret'. + */ + if(setjmp(req.mret)) + putactivity(0); + req.isslave = 0; + stop = 0; + while(!stop){ + procsetname("%d %s/dns Twrites of %d 9p rpcs read; %d alarms", + stats.qrecvd9p, mntpt, stats.qrecvd9prpc, stats.alarms); + n = read9pmsg(mfd[0], mdata, sizeof mdata); + if(n<=0){ + dnslog("error reading 9P from %s: %r", mntpt); + sleep(2000); /* don't thrash after read error */ + return; + } + + stats.qrecvd9prpc++; + job = newjob(); + if(convM2S(mdata, n, &job->request) != n){ + freejob(job); + continue; + } + mf = newfid(job->request.fid, 0); + if(debug) + dnslog("%F", &job->request); + + getactivity(&req, 0); + req.aborttime = timems() + Maxreqtm; + req.from = "9p"; + + switch(job->request.type){ + default: + warning("unknown request type %d", job->request.type); + break; + case Tversion: + rversion(job); + break; + case Tauth: + rauth(job); + break; + case Tflush: + rflush(job); + break; + case Tattach: + rattach(job, mf); + break; + case Twalk: + rwalk(job, mf); + break; + case Topen: + ropen(job, mf); + break; + case Tcreate: + rcreate(job, mf); + break; + case Tread: + rread(job, mf); + break; + case Twrite: + /* &req is handed to dnresolve() */ + rwrite(job, mf, &req); + break; + case Tclunk: + rclunk(job, mf); + break; + case Tremove: + rremove(job, mf); + break; + case Tstat: + rstat(job, mf); + break; + case Twstat: + rwstat(job, mf); + break; + } + + freejob(job); + + /* + * slave processes die after replying + */ + if(req.isslave){ + putactivity(0); + _exits(0); + } + + putactivity(0); + } + /* kill any udp server, notifier, etc. processes */ + postnote(PNGROUP, getpid(), "die"); + sleep(1000); +} + +void +rversion(Job *job) +{ + if(job->request.msize > IOHDRSZ + Maxfdata) + job->reply.msize = IOHDRSZ + Maxfdata; + else + job->reply.msize = job->request.msize; + if(strncmp(job->request.version, "9P2000", 6) != 0) + sendmsg(job, "unknown 9P version"); + else{ + job->reply.version = "9P2000"; + sendmsg(job, 0); + } +} + +void +rauth(Job *job) +{ + sendmsg(job, "dns: authentication not required"); +} + +/* + * don't flush till all the slaves are done + */ +void +rflush(Job *job) +{ + flushjob(job->request.oldtag); + sendmsg(job, 0); +} + +void +rattach(Job *job, Mfile *mf) +{ + if(mf->user != nil) + free(mf->user); + mf->user = estrdup(job->request.uname); + mf->qid.vers = vers++; + mf->qid.type = QTDIR; + mf->qid.path = 0LL; + job->reply.qid = mf->qid; + sendmsg(job, 0); +} + +char* +rwalk(Job *job, Mfile *mf) +{ + int i, nelems; + char *err; + char **elems; + Mfile *nmf; + Qid qid; + + err = 0; + nmf = nil; + elems = job->request.wname; + nelems = job->request.nwname; + job->reply.nwqid = 0; + + if(job->request.newfid != job->request.fid){ + /* clone fid */ + nmf = copyfid(mf, job->request.newfid); + if(nmf == nil){ + err = "clone bad newfid"; + goto send; + } + mf = nmf; + } + /* else nmf will be nil */ + + qid = mf->qid; + if(nelems > 0) + /* walk fid */ + for(i=0; i<nelems && i<MAXWELEM; i++){ + if((qid.type & QTDIR) == 0){ + err = "not a directory"; + break; + } + if (strcmp(elems[i], "..") == 0 || + strcmp(elems[i], ".") == 0){ + qid.type = QTDIR; + qid.path = Qdir; +Found: + job->reply.wqid[i] = qid; + job->reply.nwqid++; + continue; + } + if(strcmp(elems[i], "dns") == 0){ + qid.type = QTFILE; + qid.path = Qdns; + goto Found; + } + err = "file does not exist"; + break; + } + +send: + if(nmf != nil && (err!=nil || job->reply.nwqid<nelems)) + freefid(nmf); + if(err == nil) + mf->qid = qid; + sendmsg(job, err); + return err; +} + +void +ropen(Job *job, Mfile *mf) +{ + int mode; + char *err; + + err = 0; + mode = job->request.mode; + if(mf->qid.type & QTDIR) + if(mode) + err = "permission denied"; + job->reply.qid = mf->qid; + job->reply.iounit = 0; + sendmsg(job, err); +} + +void +rcreate(Job *job, Mfile *mf) +{ + USED(mf); + sendmsg(job, "creation permission denied"); +} + +void +rread(Job *job, Mfile *mf) +{ + int i, n; + long clock; + ulong cnt; + vlong off; + char *err; + uchar buf[Maxfdata]; + Dir dir; + + n = 0; + err = nil; + off = job->request.offset; + cnt = job->request.count; + *buf = '\0'; + job->reply.data = (char*)buf; + if(mf->qid.type & QTDIR){ + clock = time(nil); + if(off == 0){ + memset(&dir, 0, sizeof dir); + dir.name = "dns"; + dir.qid.type = QTFILE; + dir.qid.vers = vers; + dir.qid.path = Qdns; + dir.mode = 0666; + dir.length = 0; + dir.uid = dir.gid = dir.muid = mf->user; + dir.atime = dir.mtime = clock; /* wrong */ + n = convD2M(&dir, buf, sizeof buf); + } + } else if (off < 0) + err = "negative read offset"; + else { + /* first offset will always be zero */ + for(i = 1; i <= mf->nrr; i++) + if(mf->rr[i] > off) + break; + if(i <= mf->nrr) { + if(off + cnt > mf->rr[i]) + n = mf->rr[i] - off; + else + n = cnt; + assert(n >= 0); + job->reply.data = mf->reply + off; + } + } + job->reply.count = n; + sendmsg(job, err); +} + +void +rwrite(Job *job, Mfile *mf, Request *req) +{ + int rooted, wantsav, send; + ulong cnt; + char *err, *p, *atype; + char errbuf[ERRMAX]; + + err = nil; + cnt = job->request.count; + send = 1; + if(mf->qid.type & QTDIR) + err = "can't write directory"; + else if (job->request.offset != 0) + err = "writing at non-zero offset"; + else if(cnt >= Maxrequest) + err = "request too long"; + else + send = 0; + if (send) + goto send; + + job->request.data[cnt] = 0; + if(cnt > 0 && job->request.data[cnt-1] == '\n') + job->request.data[cnt-1] = 0; + + /* + * special commands + */ +// dnslog("rwrite got: %s", job->request.data); + send = 1; + if(strcmp(job->request.data, "age")==0){ + dnslog("dump, age & dump forced"); + dndump("/lib/ndb/dnsdump1"); + dnforceage(); + dndump("/lib/ndb/dnsdump2"); + } else if(strcmp(job->request.data, "debug")==0) + debug ^= 1; + else if(strcmp(job->request.data, "dump")==0) + dndump("/lib/ndb/dnsdump"); + else if(strcmp(job->request.data, "poolcheck")==0) + poolcheck(mainmem); + else if(strcmp(job->request.data, "refresh")==0) + needrefresh = 1; + else if(strcmp(job->request.data, "restart")==0) + stop = 1; + else if(strcmp(job->request.data, "stats")==0) + dnstats("/lib/ndb/dnsstats"); + else if(strncmp(job->request.data, "target ", 7)==0){ + target = atol(job->request.data + 7); + dnslog("target set to %ld", target); + } else + send = 0; + if (send) + goto send; + + /* + * kill previous reply + */ + mf->nrr = 0; + mf->rr[0] = 0; + + /* + * break up request (into a name and a type) + */ + atype = strchr(job->request.data, ' '); + if(atype == 0){ + snprint(errbuf, sizeof errbuf, "illegal request %s", + job->request.data); + err = errbuf; + goto send; + } else + *atype++ = 0; + + /* + * tracing request + */ + if(strcmp(atype, "trace") == 0){ + if(trace) + free(trace); + if(*job->request.data) + trace = estrdup(job->request.data); + else + trace = 0; + goto send; + } + + /* normal request: domain [type] */ + stats.qrecvd9p++; + mf->type = rrtype(atype); + if(mf->type < 0){ + snprint(errbuf, sizeof errbuf, "unknown type %s", atype); + err = errbuf; + goto send; + } + + p = atype - 2; + if(p >= job->request.data && *p == '.'){ + rooted = 1; + *p = 0; + } else + rooted = 0; + + p = job->request.data; + if(*p == '!'){ + wantsav = 1; + p++; + } else + wantsav = 0; + + err = lookupqueryold(job, mf, req, errbuf, p, wantsav, rooted); +send: + dncheck(0, 1); + job->reply.count = cnt; + sendmsg(job, err); +} + +/* + * dnsdebug calls + * rr = dnresolve(buf, Cin, type, &req, 0, 0, Recurse, rooted, 0); + * which generates a UDP query, which eventually calls + * dnserver(&reqmsg, &repmsg, &req, buf, rcode); + * which calls + * rp = dnresolve(name, Cin, type, req, &mp->an, 0, recurse, 1, 0); + * + * but here we just call dnresolve directly. + */ +static char * +lookupqueryold(Job *job, Mfile *mf, Request *req, char *errbuf, char *p, + int wantsav, int rooted) +{ + int status; + RR *rp, *neg; + + dncheck(0, 1); + status = Rok; + rp = dnresolve(p, Cin, mf->type, req, 0, 0, Recurse, rooted, &status); + + dncheck(0, 1); + lock(&dnlock); + neg = rrremneg(&rp); + if(neg){ + status = neg->negrcode; + rrfreelist(neg); + } + unlock(&dnlock); + + return respond(job, mf, rp, errbuf, status, wantsav); +} + +static char * +respond(Job *job, Mfile *mf, RR *rp, char *errbuf, int status, int wantsav) +{ + long n; + RR *tp; + + if(rp == nil) + switch(status){ + case Rname: + return "name does not exist"; + case Rserver: + return "dns failure"; + case Rok: + default: + snprint(errbuf, ERRMAX, + "resource does not exist; negrcode %d", status); + return errbuf; + } + + lock(&joblock); + if(!job->flushed){ + /* format data to be read later */ + n = 0; + mf->nrr = 0; + for(tp = rp; mf->nrr < Maxrrr-1 && n < Maxreply && tp && + tsame(mf->type, tp->type); tp = tp->next){ + mf->rr[mf->nrr++] = n; + if(wantsav) + n += snprint(mf->reply+n, Maxreply-n, "%Q", tp); + else + n += snprint(mf->reply+n, Maxreply-n, "%R", tp); + } + mf->rr[mf->nrr] = n; + } + unlock(&joblock); + rrfreelist(rp); + return nil; +} + +/* simulate what dnsudpserver does */ +static char * +lookupquerynew(Job *job, Mfile *mf, Request *req, char *errbuf, char *p, + int wantsav, int) +{ + char *err; + uchar buf[Udphdrsize + Maxudp + 1024]; + DNSmsg *mp; + DNSmsg repmsg; + RR *rp; + + dncheck(0, 1); + + memset(&repmsg, 0, sizeof repmsg); + rp = rralloc(mf->type); + rp->owner = dnlookup(p, Cin, 1); + mp = newdnsmsg(rp, Frecurse|Oquery, (ushort)rand()); + + dnserver(mp, &repmsg, req, buf, Rok); + + freeanswers(mp); + err = respond(job, mf, repmsg.an, errbuf, Rok, wantsav); + repmsg.an = nil; /* freed above */ + freeanswers(&repmsg); + return err; +} + +void +rclunk(Job *job, Mfile *mf) +{ + freefid(mf); + sendmsg(job, 0); +} + +void +rremove(Job *job, Mfile *mf) +{ + USED(mf); + sendmsg(job, "remove permission denied"); +} + +void +rstat(Job *job, Mfile *mf) +{ + Dir dir; + uchar buf[IOHDRSZ+Maxfdata]; + + memset(&dir, 0, sizeof dir); + if(mf->qid.type & QTDIR){ + dir.name = "."; + dir.mode = DMDIR|0555; + } else { + dir.name = "dns"; + dir.mode = 0666; + } + dir.qid = mf->qid; + dir.length = 0; + dir.uid = dir.gid = dir.muid = mf->user; + dir.atime = dir.mtime = time(nil); + job->reply.nstat = convD2M(&dir, buf, sizeof buf); + job->reply.stat = buf; + sendmsg(job, 0); +} + +void +rwstat(Job *job, Mfile *mf) +{ + USED(mf); + sendmsg(job, "wstat permission denied"); +} + +void +sendmsg(Job *job, char *err) +{ + int n; + uchar mdata[IOHDRSZ + Maxfdata]; + char ename[ERRMAX]; + + if(err){ + job->reply.type = Rerror; + snprint(ename, sizeof ename, "dns: %s", err); + job->reply.ename = ename; + }else + job->reply.type = job->request.type+1; + job->reply.tag = job->request.tag; + n = convS2M(&job->reply, mdata, sizeof mdata); + if(n == 0){ + warning("sendmsg convS2M of %F returns 0", &job->reply); + abort(); + } + lock(&joblock); + if(job->flushed == 0) + if(write(mfd[1], mdata, n)!=n) + sysfatal("mount write"); + unlock(&joblock); + if(debug) + dnslog("%F %d", &job->reply, n); +} + +/* + * the following varies between dnsdebug and dns + */ +void +logreply(int id, uchar *addr, DNSmsg *mp) +{ + RR *rp; + + dnslog("%d: rcvd %I flags:%s%s%s%s%s", id, addr, + mp->flags & Fauth? " auth": "", + mp->flags & Ftrunc? " trunc": "", + mp->flags & Frecurse? " rd": "", + mp->flags & Fcanrec? " ra": "", + (mp->flags & (Fauth|Rmask)) == (Fauth|Rname)? " nx": ""); + for(rp = mp->qd; rp != nil; rp = rp->next) + dnslog("%d: rcvd %I qd %s", id, addr, rp->owner->name); + for(rp = mp->an; rp != nil; rp = rp->next) + dnslog("%d: rcvd %I an %R", id, addr, rp); + for(rp = mp->ns; rp != nil; rp = rp->next) + dnslog("%d: rcvd %I ns %R", id, addr, rp); + for(rp = mp->ar; rp != nil; rp = rp->next) + dnslog("%d: rcvd %I ar %R", id, addr, rp); +} + +void +logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type) +{ + char buf[12]; + + dnslog("[%d] %d.%d: sending to %I/%s %s %s", + getpid(), id, subid, addr, sname, rname, + rrname(type, buf, sizeof buf)); +} + +RR* +getdnsservers(int class) +{ + return dnsservers(class); +} |