tforgot - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 27b457ae8ac1d0e7816f7a683dc8814a0f11e9cb
 (DIR) parent 941e17134e92de7f12977f1899860b57bbf83330
 (HTM) Author: rsc <devnull@localhost>
       Date:   Wed, 15 Feb 2006 18:34:50 +0000
       
       forgot
       
       Diffstat:
         A src/cmd/ndb/dntcpserver.c           |     294 +++++++++++++++++++++++++++++++
       
       1 file changed, 294 insertions(+), 0 deletions(-)
       ---
 (DIR) diff --git a/src/cmd/ndb/dntcpserver.c b/src/cmd/ndb/dntcpserver.c
       t@@ -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);
       +}