1 #include <u.h> 2 #include <libc.h> 3 #include <ip.h> 4 #include "dns.h" 5 6 enum { 7 Logqueries = 0, 8 }; 9 10 static int udpannounce(char*); 11 static void reply(int, uchar*, DNSmsg*, Request*); 12 13 typedef struct Inprogress Inprogress; 14 struct Inprogress 15 { 16 int inuse; 17 Udphdr uh; 18 DN *owner; 19 ushort type; 20 int id; 21 }; 22 Inprogress inprog[Maxactive+2]; 23 24 typedef struct Forwtarg Forwtarg; 25 struct Forwtarg { 26 char *host; 27 uchar addr[IPaddrlen]; 28 int fd; 29 ulong lastdial; 30 }; 31 Forwtarg forwtarg[10]; 32 int currtarg; 33 34 static char *hmsg = "headers"; 35 36 /* 37 * record client id and ignore retransmissions. 38 * we're still single thread at this point. 39 */ 40 static Inprogress* 41 clientrxmit(DNSmsg *req, uchar *buf) 42 { 43 Inprogress *p, *empty; 44 Udphdr *uh; 45 46 uh = (Udphdr *)buf; 47 empty = nil; 48 for(p = inprog; p < &inprog[Maxactive]; p++){ 49 if(p->inuse == 0){ 50 if(empty == nil) 51 empty = p; 52 continue; 53 } 54 if(req->id == p->id) 55 if(req->qd->owner == p->owner) 56 if(req->qd->type == p->type) 57 if(memcmp(uh, &p->uh, Udphdrsize) == 0) 58 return nil; 59 } 60 if(empty == nil) 61 return nil; /* shouldn't happen: see slave() & Maxactive def'n */ 62 63 empty->id = req->id; 64 empty->owner = req->qd->owner; 65 empty->type = req->qd->type; 66 if (empty->type != req->qd->type) 67 dnslog("clientrxmit: bogus req->qd->type %d", req->qd->type); 68 memmove(&empty->uh, uh, Udphdrsize); 69 empty->inuse = 1; 70 return empty; 71 } 72 73 int 74 addforwtarg(char *host) 75 { 76 Forwtarg *tp; 77 78 if (currtarg >= nelem(forwtarg)) { 79 dnslog("too many forwarding targets"); 80 return -1; 81 } 82 tp = forwtarg + currtarg; 83 if (parseip(tp->addr, host) < 0) { 84 dnslog("can't parse ip %s", host); 85 return -1; 86 } 87 tp->lastdial = time(nil); 88 tp->fd = udpport(mntpt); 89 if (tp->fd < 0) 90 return -1; 91 92 free(tp->host); 93 tp->host = estrdup(host); 94 currtarg++; 95 return 0; 96 } 97 98 /* 99 * fast forwarding of incoming queries to other dns servers. 100 * intended primarily for debugging. 101 */ 102 static void 103 redistrib(uchar *buf, int len) 104 { 105 Forwtarg *tp; 106 Udphdr *uh; 107 static uchar outpkt[1500]; 108 109 assert(len <= sizeof outpkt); 110 memmove(outpkt, buf, len); 111 uh = (Udphdr *)outpkt; 112 for (tp = forwtarg; tp < forwtarg + currtarg; tp++) 113 if (tp->fd > 0) { 114 memmove(outpkt, tp->addr, sizeof tp->addr); 115 hnputs(uh->rport, 53); /* dns port */ 116 if (write(tp->fd, outpkt, len) != len) { 117 close(tp->fd); 118 tp->fd = -1; 119 } 120 } else if (tp->host && time(nil) - tp->lastdial > 60) { 121 tp->lastdial = time(nil); 122 tp->fd = udpport(mntpt); 123 } 124 } 125 126 /* 127 * a process to act as a dns server for outside reqeusts 128 */ 129 void 130 dnudpserver(char *mntpt) 131 { 132 volatile int fd, len, op, rcode; 133 char *volatile err; 134 volatile char tname[32]; 135 volatile uchar buf[Udphdrsize + Maxudp + 1024]; 136 volatile DNSmsg reqmsg, repmsg; 137 Inprogress *volatile p; 138 volatile Request req; 139 Udphdr *volatile uh; 140 141 /* 142 * fork sharing text, data, and bss with parent. 143 * stay in the same note group. 144 */ 145 switch(rfork(RFPROC|RFMEM|RFNOWAIT)){ 146 case -1: 147 break; 148 case 0: 149 break; 150 default: 151 return; 152 } 153 154 fd = -1; 155 restart: 156 procsetname("udp server announcing"); 157 if(fd >= 0) 158 close(fd); 159 while((fd = udpannounce(mntpt)) < 0) 160 sleep(5000); 161 162 // procsetname("udp server"); 163 memset(&req, 0, sizeof req); 164 if(setjmp(req.mret)) 165 putactivity(0); 166 req.isslave = 0; 167 req.id = 0; 168 req.aborttime = 0; 169 170 /* loop on requests */ 171 for(;; putactivity(0)){ 172 procsetname("served %d udp; %d alarms", 173 stats.qrecvdudp, stats.alarms); 174 memset(&repmsg, 0, sizeof repmsg); 175 memset(&reqmsg, 0, sizeof reqmsg); 176 177 alarm(60*1000); 178 len = read(fd, buf, sizeof buf); 179 alarm(0); 180 if(len <= Udphdrsize) 181 goto restart; 182 183 redistrib(buf, len); 184 185 uh = (Udphdr*)buf; 186 len -= Udphdrsize; 187 188 // dnslog("read received UDP from %I to %I", 189 // ((Udphdr*)buf)->raddr, ((Udphdr*)buf)->laddr); 190 getactivity(&req, 0); 191 req.aborttime = now + Maxreqtm; 192 // req.from = smprint("%I", ((Udphdr*)buf)->raddr); 193 req.from = smprint("%I", buf); 194 rcode = 0; 195 stats.qrecvdudp++; 196 197 err = convM2DNS(&buf[Udphdrsize], len, &reqmsg, &rcode); 198 if(err){ 199 /* first bytes in buf are source IP addr */ 200 dnslog("server: input error: %s from %I", err, buf); 201 free(err); 202 goto freereq; 203 } 204 if (rcode == 0) 205 if(reqmsg.qdcount < 1){ 206 dnslog("server: no questions from %I", buf); 207 goto freereq; 208 } else if(reqmsg.flags & Fresp){ 209 dnslog("server: reply not request from %I", buf); 210 goto freereq; 211 } 212 op = reqmsg.flags & Omask; 213 if(op != Oquery && op != Onotify){ 214 dnslog("server: op %d from %I", reqmsg.flags & Omask, 215 buf); 216 goto freereq; 217 } 218 219 if(debug || (trace && subsume(trace, reqmsg.qd->owner->name))) 220 dnslog("%d: serve (%I/%d) %d %s %s", 221 req.id, buf, uh->rport[0]<<8 | uh->rport[1], 222 reqmsg.id, reqmsg.qd->owner->name, 223 rrname(reqmsg.qd->type, tname, sizeof tname)); 224 225 p = clientrxmit(&reqmsg, buf); 226 if(p == nil){ 227 if(debug) 228 dnslog("%d: duplicate", req.id); 229 goto freereq; 230 } 231 232 if (Logqueries) { 233 RR *rr; 234 235 for (rr = reqmsg.qd; rr; rr = rr->next) 236 syslog(0, "dnsq", "id %d: (%I/%d) %d %s %s", 237 req.id, buf, uh->rport[0]<<8 | 238 uh->rport[1], reqmsg.id, 239 reqmsg.qd->owner->name, 240 rrname(reqmsg.qd->type, tname, 241 sizeof tname)); // DEBUG 242 } 243 /* loop through each question */ 244 while(reqmsg.qd){ 245 memset(&repmsg, 0, sizeof repmsg); 246 switch(op){ 247 case Oquery: 248 dnserver(&reqmsg, &repmsg, &req, buf, rcode); 249 break; 250 case Onotify: 251 dnnotify(&reqmsg, &repmsg, &req); 252 break; 253 } 254 /* send reply on fd to address in buf's udp hdr */ 255 reply(fd, buf, &repmsg, &req); 256 freeanswers(&repmsg); 257 } 258 259 p->inuse = 0; 260 freereq: 261 free(req.from); 262 req.from = nil; 263 freeanswers(&reqmsg); 264 if(req.isslave){ 265 putactivity(0); 266 _exits(0); 267 } 268 } 269 } 270 271 /* 272 * announce on well-known dns udp port and set message style interface 273 */ 274 static int 275 udpannounce(char *mntpt) 276 { 277 int data, ctl; 278 char dir[64], datafile[64+6]; 279 static int whined; 280 281 /* get a udp port */ 282 sprint(datafile, "%s/udp!*!dns", mntpt); 283 ctl = announce(datafile, dir); 284 if(ctl < 0){ 285 if(!whined++) 286 warning("can't announce on dns udp port"); 287 return -1; 288 } 289 snprint(datafile, sizeof(datafile), "%s/data", dir); 290 291 /* turn on header style interface */ 292 if(write(ctl, hmsg, strlen(hmsg)) != strlen(hmsg)) 293 abort(); /* hmsg */ 294 data = open(datafile, ORDWR); 295 if(data < 0){ 296 close(ctl); 297 if(!whined++) 298 warning("can't announce on dns udp port"); 299 return -1; 300 } 301 302 close(ctl); 303 return data; 304 } 305 306 static void 307 reply(int fd, uchar *buf, DNSmsg *rep, Request *reqp) 308 { 309 int len; 310 char tname[32]; 311 312 if(debug || (trace && subsume(trace, rep->qd->owner->name))) 313 dnslog("%d: reply (%I/%d) %d %s %s qd %R an %R ns %R ar %R", 314 reqp->id, buf, buf[4]<<8 | buf[5], 315 rep->id, rep->qd->owner->name, 316 rrname(rep->qd->type, tname, sizeof tname), 317 rep->qd, rep->an, rep->ns, rep->ar); 318 319 len = convDNS2M(rep, &buf[Udphdrsize], Maxudp); 320 len += Udphdrsize; 321 if(write(fd, buf, len) != len) 322 dnslog("error sending reply: %r"); 323 } 324