URI:
       tdnudpserver.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
       ---
       tdnudpserver.c (4507B)
       ---
            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 int        udpannounce(char*);
           10 static void        reply(int, uchar*, DNSmsg*, Request*);
           11 
           12 extern char *logfile;
           13 
           14 typedef struct Inprogress Inprogress;
           15 struct Inprogress
           16 {
           17         int        inuse;
           18         Udphdr        uh;
           19         DN        *owner;
           20         int        type;
           21         int        id;
           22 };
           23 Inprogress inprog[Maxactive+2];
           24 QLock inproglk;
           25 
           26 /*
           27  *  record client id and ignore retransmissions.
           28  */
           29 static Inprogress*
           30 clientrxmit(DNSmsg *req, uchar *buf)
           31 {
           32         Inprogress *p, *empty;
           33         Udphdr *uh;
           34 
           35         qlock(&inproglk);
           36         uh = (Udphdr *)buf;
           37         empty = 0;
           38         for(p = inprog; p < &inprog[Maxactive]; p++){
           39                 if(p->inuse == 0){
           40                         if(empty == 0)
           41                                 empty = p;
           42                         continue;
           43                 }
           44                 if(req->id == p->id)
           45                 if(req->qd->owner == p->owner)
           46                 if(req->qd->type == p->type)
           47                 if(memcmp(uh, &p->uh, Udphdrsize) == 0){
           48                         qunlock(&inproglk);
           49                         return 0;
           50                 }
           51         }
           52         if(empty == 0){
           53                 qunlock(&inproglk);
           54                 return 0;        /* shouldn't happen - see slave() and definition of Maxactive */
           55         }
           56 
           57         empty->id = req->id;
           58         empty->owner = req->qd->owner;
           59         empty->type = req->qd->type;
           60         memmove(&empty->uh, uh, Udphdrsize);
           61         empty->inuse = 1;
           62         qunlock(&inproglk);
           63         return empty;
           64 }
           65 
           66 /*
           67  *  a process to act as a dns server for outside reqeusts
           68  */
           69 static void
           70 udpproc(void *v)
           71 {
           72         int fd, len, op;
           73         Request req;
           74         DNSmsg reqmsg, repmsg;
           75         uchar buf[Udphdrsize + Maxudp + 1024];
           76         char *err;
           77         Inprogress *p;
           78         char tname[32];
           79         Udphdr *uh;
           80 
           81         fd = (uintptr)v;
           82 
           83         /* loop on requests */
           84         for(;; putactivity()){
           85                 memset(&repmsg, 0, sizeof(repmsg));
           86                 memset(&reqmsg, 0, sizeof(reqmsg));
           87                 len = udpread(fd, (Udphdr*)buf, buf+Udphdrsize, sizeof(buf)-Udphdrsize);
           88                 if(len <= 0)
           89                         continue;
           90                 uh = (Udphdr*)buf;
           91                 getactivity(&req);
           92                 req.aborttime = now + 30;        /* don't spend more than 30 seconds */
           93                 err = convM2DNS(&buf[Udphdrsize], len, &reqmsg);
           94                 if(err){
           95                         syslog(0, logfile, "server: input error: %s from %I", err, buf);
           96                         continue;
           97                 }
           98                 if(reqmsg.qdcount < 1){
           99                         syslog(0, logfile, "server: no questions from %I", buf);
          100                         goto freereq;
          101                 }
          102                 if(reqmsg.flags & Fresp){
          103                         syslog(0, logfile, "server: reply not request from %I", buf);
          104                         goto freereq;
          105                 }
          106                 op = reqmsg.flags & Omask;
          107                 if(op != Oquery && op != Onotify){
          108                         syslog(0, logfile, "server: op %d from %I", reqmsg.flags & Omask, buf);
          109                         goto freereq;
          110                 }
          111 
          112                 if(debug || (trace && subsume(trace, reqmsg.qd->owner->name))){
          113                         syslog(0, logfile, "%d: serve (%I/%d) %d %s %s",
          114                                 req.id, buf, ((uh->rport[0])<<8)+uh->rport[1],
          115                                 reqmsg.id,
          116                                 reqmsg.qd->owner->name,
          117                                 rrname(reqmsg.qd->type, tname, sizeof tname));
          118                 }
          119 
          120                 p = clientrxmit(&reqmsg, buf);
          121                 if(p == 0){
          122                         if(debug)
          123                                 syslog(0, logfile, "%d: duplicate", req.id);
          124                         goto freereq;
          125                 }
          126 
          127                 /* loop through each question */
          128                 while(reqmsg.qd){
          129                         memset(&repmsg, 0, sizeof(repmsg));
          130                         switch(op){
          131                         case Oquery:
          132                                 dnserver(&reqmsg, &repmsg, &req);
          133                                 break;
          134                         case Onotify:
          135                                 dnnotify(&reqmsg, &repmsg, &req);
          136                                 break;
          137                         }
          138                         reply(fd, buf, &repmsg, &req);
          139                         rrfreelist(repmsg.qd);
          140                         rrfreelist(repmsg.an);
          141                         rrfreelist(repmsg.ns);
          142                         rrfreelist(repmsg.ar);
          143                 }
          144 
          145                 p->inuse = 0;
          146 
          147 freereq:
          148                 rrfreelist(reqmsg.qd);
          149                 rrfreelist(reqmsg.an);
          150                 rrfreelist(reqmsg.ns);
          151                 rrfreelist(reqmsg.ar);
          152         }
          153 }
          154 
          155 /*
          156  *  announce on udp port
          157  */
          158 static int
          159 udpannounce(char *mntpt)
          160 {
          161         int fd;
          162         char buf[40];
          163         USED(mntpt);
          164 
          165         if((fd=announce(udpaddr, buf)) < 0)
          166                 warning("announce %s: %r", buf);
          167         return fd;
          168 }
          169 
          170 static void
          171 reply(int fd, uchar *buf, DNSmsg *rep, Request *reqp)
          172 {
          173         int len;
          174         char tname[32];
          175         RR *rp;
          176 
          177         if(debug || (trace && subsume(trace, rep->qd->owner->name)))
          178                 syslog(0, logfile, "%d: reply (%I/%d) %d %s %s an %R ns %R ar %R",
          179                         reqp->id, buf, ((buf[4])<<8)+buf[5],
          180                         rep->id, rep->qd->owner->name,
          181                         rrname(rep->qd->type, tname, sizeof tname), rep->an, rep->ns, rep->ar);
          182 
          183         len = convDNS2M(rep, &buf[Udphdrsize], Maxudp);
          184         if(len <= 0){
          185                 syslog(0, logfile, "error converting reply: %s %d", rep->qd->owner->name,
          186                         rep->qd->type);
          187                 for(rp = rep->an; rp; rp = rp->next)
          188                         syslog(0, logfile, "an %R", rp);
          189                 for(rp = rep->ns; rp; rp = rp->next)
          190                         syslog(0, logfile, "ns %R", rp);
          191                 for(rp = rep->ar; rp; rp = rp->next)
          192                         syslog(0, logfile, "ar %R", rp);
          193                 return;
          194         }
          195         if(udpwrite(fd, (Udphdr*)buf, buf+Udphdrsize, len) != len)
          196                 syslog(0, logfile, "error sending reply: %r");
          197 }
          198 
          199 void
          200 dnudpserver(void *v)
          201 {
          202         int i, fd;
          203 
          204         while((fd = udpannounce(v)) < 0)
          205                 sleep(5*1000);
          206         for(i=0; i<Maxactive; i++)
          207                 proccreate(udpproc, (void*)(uintptr)fd, STACK);
          208 }