aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/ndb
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2006-02-15 18:34:50 +0000
committerrsc <devnull@localhost>2006-02-15 18:34:50 +0000
commit27b457ae8ac1d0e7816f7a683dc8814a0f11e9cb (patch)
treee168572f34712c785923980f20ae7300e951dd80 /src/cmd/ndb
parent941e17134e92de7f12977f1899860b57bbf83330 (diff)
downloadplan9port-27b457ae8ac1d0e7816f7a683dc8814a0f11e9cb.tar.gz
plan9port-27b457ae8ac1d0e7816f7a683dc8814a0f11e9cb.tar.bz2
plan9port-27b457ae8ac1d0e7816f7a683dc8814a0f11e9cb.zip
forgot
Diffstat (limited to 'src/cmd/ndb')
-rw-r--r--src/cmd/ndb/dntcpserver.c294
1 files changed, 294 insertions, 0 deletions
diff --git a/src/cmd/ndb/dntcpserver.c b/src/cmd/ndb/dntcpserver.c
new file mode 100644
index 00000000..4ae787a8
--- /dev/null
+++ b/src/cmd/ndb/dntcpserver.c
@@ -0,0 +1,294 @@
+#include <u.h>
+#include <libc.h>
+#include <ip.h>
+#include <bio.h>
+#include <ndb.h>
+#include <thread.h>
+#include "dns.h"
+
+static char adir[40];
+
+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 int
+connreadmsg(int tfd, int *fd, uchar *buf, int max)
+{
+ int n;
+ int lfd;
+ char ldir[40];
+
+ lfd = listen(adir, ldir);
+ if (lfd < 0)
+ return -1;
+ *fd = accept(lfd, ldir);
+ n = -1;
+ if (*fd < 0)
+ n = readmsg(*fd, buf, max);
+ //close(fd);
+ close(lfd);
+ return n;
+}
+
+static int
+reply(int fd, DNSmsg *rep, Request *req, NetConnInfo *caller)
+{
+ int len;
+ char tname[32];
+ uchar buf[4096];
+ RR *rp;
+
+ if(debug){
+ syslog(0, logfile, "%d: reply (%s) %s %s %ux",
+ req->id, caller ? caller->raddr : "unk",
+ 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;
+ if(write(fd, buf, len+2) < 0){
+ syslog(0, logfile, "sending reply: %r");
+ return -1;
+ }
+ return 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;
+}
+
+static 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 int
+dnzone(DNSmsg *reqp, DNSmsg *repp, Request *req, int rfd, NetConnInfo *caller)
+{
+ DN *dp, *ndp;
+ RR r, *rp;
+ int h, depth, found, nlen, rv;
+
+ rv = 0;
+ 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);
+ rv = reply(rfd, repp, req, caller);
+ if(repp->an == 0 || rv < 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;
+ rv = reply(rfd, repp, req, caller);
+ if(rv < 0)
+ goto out;
+ }
+ found = 1;
+ }
+ if(!found)
+ break;
+ }
+
+ /* resend the soa */
+ repp->an = rrlookup(dp, Tsoa, NOneg);
+ rv = reply(rfd, repp, req, caller);
+out:
+ if (repp->an)
+ rrfreelist(repp->an);
+ rrfree(repp->qd);
+ return rv;
+}
+
+void
+tcpproc(void *v)
+{
+ int len;
+ Request req;
+ DNSmsg reqmsg, repmsg;
+ char *err;
+ uchar buf[512];
+ char tname[32];
+ int fd, rfd;
+ NetConnInfo *caller;
+
+ rfd = -1;
+ fd = (int)v;
+ caller = 0;
+ /* loop on requests */
+ for(;; putactivity()){
+ if (rfd == 1)
+ return;
+ close(rfd);
+ now = time(0);
+ memset(&repmsg, 0, sizeof(repmsg));
+ freenetconninfo(caller);
+ caller = getnetconninfo(0, fd);
+ if (fd == 0) {
+ len = readmsg(fd, buf, sizeof buf);
+ rfd = 1;
+ } else {
+ len = connreadmsg(fd, &rfd, buf, sizeof buf);
+ }
+ if(len <= 0)
+ continue;
+ 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);
+ continue;
+ }
+ if(reqmsg.qdcount < 1){
+ syslog(0, logfile, "server: no questions from %I", buf);
+ continue;
+ }
+ if(reqmsg.flags & Fresp){
+ syslog(0, logfile, "server: reply not request from %I", buf);
+ continue;
+ }
+ if((reqmsg.flags & Omask) != Oquery){
+ syslog(0, logfile, "server: op %d from %I", reqmsg.flags & Omask, buf);
+ continue;
+ }
+
+ if(debug)
+ syslog(0, logfile, "%d: serve (%s) %d %s %s",
+ req.id, caller ? caller->raddr : 0,
+ 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){
+ if(dnzone(&reqmsg, &repmsg, &req, rfd, caller) < 0)
+ break;
+ } else {
+ dnserver(&reqmsg, &repmsg, &req);
+ if(reply(rfd, &repmsg, &req, caller) < 0)
+ break;
+ rrfreelist(repmsg.qd);
+ rrfreelist(repmsg.an);
+ rrfreelist(repmsg.ns);
+ rrfreelist(repmsg.ar);
+ }
+ }
+
+ rrfreelist(reqmsg.qd);
+ rrfreelist(reqmsg.an);
+ rrfreelist(reqmsg.ns);
+ rrfreelist(reqmsg.ar);
+ }
+}
+
+enum {
+ Maxactivetcp = 4,
+};
+
+extern char *portname;
+
+static int
+tcpannounce(char *mntpt)
+{
+ int fd;
+ char an[40];
+
+ USED(mntpt);
+ snprint(an, sizeof an, "tcp!*!%s", portname);
+ if((fd=announce(an, adir)) < 0)
+ warning("announce %s: %r", an);
+ return fd;
+}
+
+void
+dntcpserver(void *v)
+{
+ int i, fd;
+ char *mntpt;
+
+ mntpt = v;
+ while((fd = tcpannounce(mntpt)) < 0)
+ sleep(5*1000);
+
+ for(i=0; i<Maxactivetcp; i++)
+ proccreate(tcpproc, (void*)fd, STACK);
+}