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