diff options
Diffstat (limited to 'src/cmd/ndb/dnstcp.c')
-rwxr-xr-x | src/cmd/ndb/dnstcp.c | 286 |
1 files changed, 10 insertions, 276 deletions
diff --git a/src/cmd/ndb/dnstcp.c b/src/cmd/ndb/dnstcp.c index 19a7540d..f3fea1b0 100755 --- a/src/cmd/ndb/dnstcp.c +++ b/src/cmd/ndb/dnstcp.c @@ -1,6 +1,9 @@ #include <u.h> #include <libc.h> #include <ip.h> +#include <bio.h> +#include <ndb.h> +#include <thread.h> #include "dns.h" enum @@ -13,312 +16,43 @@ char *dbfile; int debug; int cachedb = 1; int testing; -int traceactivity; +int traceactivity; int needrefresh; int resolver; char mntpt[Maxpath]; -char *caller = ""; ulong now; int maxage; uchar ipaddr[IPaddrlen]; /* my ip address */ char *LOG; char *zonerefreshprogram; - -static int readmsg(int, uchar*, int); -static void reply(int, DNSmsg*, Request*); -static void dnzone(DNSmsg*, DNSmsg*, Request*); -static void getcaller(char*); -static void refreshmain(char*); +char *portname = "domain"; void -main(int argc, char *argv[]) +threadmain(int argc, char *argv[]) { - int len; - Request req; - DNSmsg reqmsg, repmsg; - uchar buf[512]; - char tname[32]; - char *err; char *ext = ""; ARGBEGIN{ + default: + usage(); case 'd': debug++; break; case 'f': - dbfile = ARGF(); + dbfile = EARGF(usage()); break; case 'r': resolver = 1; break; - case 'x': - ext = ARGF(); - break; }ARGEND if(debug < 2) debug = 0; - if(argc > 0) - getcaller(argv[0]); - dninit(); - snprint(mntpt, sizeof(mntpt), "/net%s", ext); - if(myipaddr(ipaddr, mntpt) < 0) - sysfatal("can't read my ip address"); - syslog(0, logfile, "dnstcp call from %s to %I", caller, ipaddr); - db2cache(1); - - setjmp(req.mret); - req.isslave = 0; - - /* loop on requests */ - for(;; putactivity()){ - now = time(0); - memset(&repmsg, 0, sizeof(repmsg)); - alarm(10*60*1000); - len = readmsg(0, buf, sizeof(buf)); - alarm(0); - if(len <= 0) - break; - getactivity(&req); - req.aborttime = now + 15*Min; - err = convM2DNS(buf, len, &reqmsg); - if(err){ - syslog(0, logfile, "server: input error: %s from %I", err, buf); - break; - } - if(reqmsg.qdcount < 1){ - syslog(0, logfile, "server: no questions from %I", buf); - break; - } - if(reqmsg.flags & Fresp){ - syslog(0, logfile, "server: reply not request from %I", buf); - break; - } - if((reqmsg.flags & Omask) != Oquery){ - syslog(0, logfile, "server: op %d from %I", reqmsg.flags & Omask, buf); - break; - } - - if(debug) - syslog(0, logfile, "%d: serve (%s) %d %s %s", - req.id, caller, - reqmsg.id, - reqmsg.qd->owner->name, - rrname(reqmsg.qd->type, tname, sizeof tname)); - - /* loop through each question */ - while(reqmsg.qd){ - if(reqmsg.qd->type == Taxfr){ - dnzone(&reqmsg, &repmsg, &req); - } else { - dnserver(&reqmsg, &repmsg, &req); - reply(1, &repmsg, &req); - rrfreelist(repmsg.qd); - rrfreelist(repmsg.an); - rrfreelist(repmsg.ns); - rrfreelist(repmsg.ar); - } - } - - rrfreelist(reqmsg.qd); - rrfreelist(reqmsg.an); - rrfreelist(reqmsg.ns); - rrfreelist(reqmsg.ar); - - if(req.isslave){ - putactivity(); - _exits(0); - } - } - refreshmain(mntpt); -} - -static int -readmsg(int fd, uchar *buf, int max) -{ - int n; - uchar x[2]; - - if(readn(fd, x, 2) != 2) - return -1; - n = (x[0]<<8) | x[1]; - if(n > max) - return -1; - if(readn(fd, buf, n) != n) - return -1; - return n; -} - -static void -reply(int fd, DNSmsg *rep, Request *req) -{ - int len, rv; - char tname[32]; - uchar buf[4096]; - RR *rp; - - if(debug){ - syslog(0, logfile, "%d: reply (%s) %s %s %ux", - req->id, caller, - rep->qd->owner->name, - rrname(rep->qd->type, tname, sizeof tname), - rep->flags); - for(rp = rep->an; rp; rp = rp->next) - syslog(0, logfile, "an %R", rp); - for(rp = rep->ns; rp; rp = rp->next) - syslog(0, logfile, "ns %R", rp); - for(rp = rep->ar; rp; rp = rp->next) - syslog(0, logfile, "ar %R", rp); - } - - - len = convDNS2M(rep, buf+2, sizeof(buf) - 2); - if(len <= 0) - abort(); /* "dnserver: converting reply" */; - buf[0] = len>>8; - buf[1] = len; - rv = write(fd, buf, len+2); - if(rv != len+2){ - syslog(0, logfile, "sending reply: %d instead of %d", rv, len+2); - exits(0); - } -} - -/* - * Hash table for domain names. The hash is based only on the - * first element of the domain name. - */ -extern DN *ht[HTLEN]; - -static int -numelem(char *name) -{ - int i; - - i = 1; - for(; *name; name++) - if(*name == '.') - i++; - return i; -} - -int -inzone(DN *dp, char *name, int namelen, int depth) -{ - int n; - - if(dp->name == 0) - return 0; - if(numelem(dp->name) != depth) - return 0; - n = strlen(dp->name); - if(n < namelen) - return 0; - if(strcmp(name, dp->name + n - namelen) != 0) - return 0; - if(n > namelen && dp->name[n - namelen - 1] != '.') - return 0; - return 1; -} - -static void -dnzone(DNSmsg *reqp, DNSmsg *repp, Request *req) -{ - DN *dp, *ndp; - RR r, *rp; - int h, depth, found, nlen; - - memset(repp, 0, sizeof(*repp)); - repp->id = reqp->id; - repp->flags = Fauth | Fresp | Fcanrec | Oquery; - repp->qd = reqp->qd; - reqp->qd = reqp->qd->next; - repp->qd->next = 0; - dp = repp->qd->owner; - - /* send the soa */ - repp->an = rrlookup(dp, Tsoa, NOneg); - reply(1, repp, req); - if(repp->an == 0) - goto out; - rrfreelist(repp->an); - - nlen = strlen(dp->name); - - /* construct a breadth first search of the name space (hard with a hash) */ - repp->an = &r; - for(depth = numelem(dp->name); ; depth++){ - found = 0; - for(h = 0; h < HTLEN; h++) - for(ndp = ht[h]; ndp; ndp = ndp->next) - if(inzone(ndp, dp->name, nlen, depth)){ - for(rp = ndp->rr; rp; rp = rp->next){ - /* there shouldn't be negatives, but just in case */ - if(rp->negative) - continue; - - /* don't send an soa's, ns's are enough */ - if(rp->type == Tsoa) - continue; - - r = *rp; - r.next = 0; - reply(1, repp, req); - } - found = 1; - } - if(!found) - break; - } - - /* resend the soa */ - repp->an = rrlookup(dp, Tsoa, NOneg); - reply(1, repp, req); - rrfreelist(repp->an); -out: - rrfree(repp->qd); -} - -static void -getcaller(char *dir) -{ - int fd, n; - static char remote[128]; - - snprint(remote, sizeof(remote), "%s/remote", dir); - fd = open(remote, OREAD); - if(fd < 0) - return; - n = read(fd, remote, sizeof(remote)-1); - close(fd); - if(n <= 0) - return; - if(remote[n-1] == '\n') - n--; - remote[n] = 0; - caller = remote; -} - -static void -refreshmain(char *net) -{ - int fd; - char file[128]; - - snprint(file, sizeof(file), "%s/dns", net); - if(debug) - syslog(0, logfile, "refreshing %s", file); - fd = open(file, ORDWR); - if(fd < 0){ - syslog(0, logfile, "can't refresh %s", file); - return; - } - fprint(fd, "refresh"); - close(fd); + tcpproc(0); } /* |