URI: 
       tdntcpserver.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tdntcpserver.c (5554B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <ip.h>
            4 #include <bio.h>
            5 #include <ndb.h>
            6 #include <thread.h>
            7 #include "dns.h"
            8 
            9 static char adir[40];
           10 
           11 static int
           12 readmsg(int fd, uchar *buf, int max)
           13 {
           14         int n;
           15         uchar x[2];
           16 
           17         if(readn(fd, x, 2) != 2)
           18                 return -1;
           19         n = (x[0]<<8) | x[1];
           20         if(n > max)
           21                 return -1;
           22         if(readn(fd, buf, n) != n)
           23                 return -1;
           24         return n;
           25 }
           26 
           27 static int
           28 connreadmsg(int tfd, int *fd, uchar *buf, int max)
           29 {
           30         int n;
           31         int lfd;
           32         char ldir[40];
           33 
           34         lfd = listen(adir, ldir);
           35         if (lfd < 0)
           36                 return -1;
           37         *fd = accept(lfd, ldir);
           38         if (*fd >= 0)
           39                 n = readmsg(*fd, buf, max);
           40         else
           41                 n = -1;
           42         close(lfd);
           43         return n;
           44 }
           45 
           46 static int
           47 reply(int fd, DNSmsg *rep, Request *req, NetConnInfo *caller)
           48 {
           49         int len;
           50         char tname[32];
           51         uchar buf[4096];
           52         RR *rp;
           53 
           54         if(debug){
           55                 syslog(0, logfile, "%d: reply (%s) %s %s %ux",
           56                         req->id, caller ? caller->raddr : "unk",
           57                         rep->qd->owner->name,
           58                         rrname(rep->qd->type, tname, sizeof tname),
           59                         rep->flags);
           60                 for(rp = rep->an; rp; rp = rp->next)
           61                         syslog(0, logfile, "an %R", rp);
           62                 for(rp = rep->ns; rp; rp = rp->next)
           63                         syslog(0, logfile, "ns %R", rp);
           64                 for(rp = rep->ar; rp; rp = rp->next)
           65                         syslog(0, logfile, "ar %R", rp);
           66         }
           67 
           68 
           69         len = convDNS2M(rep, buf+2, sizeof(buf) - 2);
           70         if(len <= 0)
           71                 abort(); /* "dnserver: converting reply" */;
           72         buf[0] = len>>8;
           73         buf[1] = len;
           74         if(write(fd, buf, len+2) < 0){
           75                 syslog(0, logfile, "sending reply: %r");
           76                 return -1;
           77         }
           78         return 0;
           79 }
           80 
           81 /*
           82  *  Hash table for domain names.  The hash is based only on the
           83  *  first element of the domain name.
           84  */
           85 extern DN        *ht[HTLEN];
           86 
           87 static int
           88 numelem(char *name)
           89 {
           90         int i;
           91 
           92         i = 1;
           93         for(; *name; name++)
           94                 if(*name == '.')
           95                         i++;
           96         return i;
           97 }
           98 
           99 static int
          100 inzone(DN *dp, char *name, int namelen, int depth)
          101 {
          102         int n;
          103 
          104         if(dp->name == 0)
          105                 return 0;
          106         if(numelem(dp->name) != depth)
          107                 return 0;
          108         n = strlen(dp->name);
          109         if(n < namelen)
          110                 return 0;
          111         if(strcmp(name, dp->name + n - namelen) != 0)
          112                 return 0;
          113         if(n > namelen && dp->name[n - namelen - 1] != '.')
          114                 return 0;
          115         return 1;
          116 }
          117 
          118 static int
          119 dnzone(DNSmsg *reqp, DNSmsg *repp, Request *req, int rfd, NetConnInfo *caller)
          120 {
          121         DN *dp, *ndp;
          122         RR r, *rp;
          123         int h, depth, found, nlen, rv;
          124 
          125         rv = 0;
          126         memset(repp, 0, sizeof(*repp));
          127         repp->id = reqp->id;
          128         repp->flags = Fauth | Fresp | Fcanrec | Oquery;
          129         repp->qd = reqp->qd;
          130         reqp->qd = reqp->qd->next;
          131         repp->qd->next = 0;
          132         dp = repp->qd->owner;
          133 
          134         /* send the soa */
          135         repp->an = rrlookup(dp, Tsoa, NOneg);
          136         rv = reply(rfd, repp, req, caller);
          137         if(repp->an == 0 || rv < 0)
          138                 goto out;
          139         rrfreelist(repp->an);
          140 
          141         nlen = strlen(dp->name);
          142 
          143         /* construct a breadth first search of the name space (hard with a hash) */
          144         repp->an = &r;
          145         for(depth = numelem(dp->name); ; depth++){
          146                 found = 0;
          147                 for(h = 0; h < HTLEN; h++)
          148                         for(ndp = ht[h]; ndp; ndp = ndp->next)
          149                                 if(inzone(ndp, dp->name, nlen, depth)){
          150                                         for(rp = ndp->rr; rp; rp = rp->next){
          151                                                 /* there shouldn't be negatives, but just in case */
          152                                                 if(rp->negative)
          153                                                         continue;
          154 
          155                                                 /* don't send an soa's, ns's are enough */
          156                                                 if(rp->type == Tsoa)
          157                                                         continue;
          158 
          159                                                 r = *rp;
          160                                                 r.next = 0;
          161                                                 rv = reply(rfd, repp, req, caller);
          162                                                 if(rv < 0)
          163                                                         goto out;
          164                                         }
          165                                         found = 1;
          166                                 }
          167                 if(!found)
          168                         break;
          169         }
          170 
          171         /* resend the soa */
          172         repp->an = rrlookup(dp, Tsoa, NOneg);
          173         rv = reply(rfd, repp, req, caller);
          174 out:
          175         if (repp->an)
          176                 rrfreelist(repp->an);
          177         rrfree(repp->qd);
          178         return rv;
          179 }
          180 
          181 void
          182 tcpproc(void *v)
          183 {
          184         int len, rv;
          185         Request req;
          186         DNSmsg reqmsg, repmsg;
          187         char *err;
          188         uchar buf[512];
          189         char tname[32];
          190         int fd, rfd;
          191         NetConnInfo *caller;
          192 
          193         rfd = -1;
          194         fd = (uintptr)v;
          195         caller = 0;
          196         /* loop on requests */
          197         for(;; putactivity()){
          198                 if (rfd == 1)
          199                         return;
          200                 close(rfd);
          201                 now = time(0);
          202                 memset(&repmsg, 0, sizeof(repmsg));
          203                 if (fd == 0) {
          204                         len = readmsg(fd, buf, sizeof buf);
          205                         rfd = 1;
          206                 } else {
          207                         len = connreadmsg(fd, &rfd, buf, sizeof buf);
          208                 }
          209                 if(len <= 0)
          210                         continue;
          211                 freenetconninfo(caller);
          212                 caller = getnetconninfo(0, fd);
          213                 getactivity(&req);
          214                 req.aborttime = now + 15*Min;
          215                 err = convM2DNS(buf, len, &reqmsg);
          216                 if(err){
          217                         syslog(0, logfile, "server: input error: %s from %I", err, buf);
          218                         continue;
          219                 }
          220                 if(reqmsg.qdcount < 1){
          221                         syslog(0, logfile, "server: no questions from %I", buf);
          222                         continue;
          223                 }
          224                 if(reqmsg.flags & Fresp){
          225                         syslog(0, logfile, "server: reply not request from %I", buf);
          226                         continue;
          227                 }
          228                 if((reqmsg.flags & Omask) != Oquery){
          229                         syslog(0, logfile, "server: op %d from %I", reqmsg.flags & Omask, buf);
          230                         continue;
          231                 }
          232 
          233                 if(debug)
          234                         syslog(0, logfile, "%d: serve (%s) %d %s %s",
          235                                 req.id, caller ? caller->raddr : 0,
          236                                 reqmsg.id,
          237                                 reqmsg.qd->owner->name,
          238                                 rrname(reqmsg.qd->type, tname, sizeof tname));
          239 
          240                 /* loop through each question */
          241                 while(reqmsg.qd){
          242                         if(reqmsg.qd->type == Taxfr){
          243                                 if(dnzone(&reqmsg, &repmsg, &req, rfd, caller) < 0)
          244                                         break;
          245                         } else {
          246                                 dnserver(&reqmsg, &repmsg, &req);
          247                                 rv = reply(rfd, &repmsg, &req, caller);
          248                                 rrfreelist(repmsg.qd);
          249                                 rrfreelist(repmsg.an);
          250                                 rrfreelist(repmsg.ns);
          251                                 rrfreelist(repmsg.ar);
          252                                 if(rv < 0)
          253                                         break;
          254                         }
          255                 }
          256 
          257                 rrfreelist(reqmsg.qd);
          258                 rrfreelist(reqmsg.an);
          259                 rrfreelist(reqmsg.ns);
          260                 rrfreelist(reqmsg.ar);
          261         }
          262 }
          263 
          264 enum {
          265         Maxactivetcp = 4
          266 };
          267 
          268 static int
          269 tcpannounce(char *mntpt)
          270 {
          271         int fd;
          272 
          273         USED(mntpt);
          274         if((fd=announce(tcpaddr, adir)) < 0)
          275                 warning("announce %s: %r", tcpaddr);
          276         return fd;
          277 }
          278 
          279 void
          280 dntcpserver(void *v)
          281 {
          282         int i, fd;
          283 
          284         while((fd = tcpannounce(v)) < 0)
          285                 sleep(5*1000);
          286 
          287         for(i=0; i<Maxactivetcp; i++)
          288                 proccreate(tcpproc, (void*)(uintptr)fd, STACK);
          289 }