dnudpserver.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 }