10 static int udpannounce(char*);
11 static void reply(int, uchar*, DNSmsg*, Request*);
13 typedef struct Inprogress Inprogress;
22 Inprogress inprog[Maxactive+2];
24 typedef struct Forwtarg Forwtarg;
27 uchar addr[IPaddrlen];
31 Forwtarg forwtarg[10];
34 static char *hmsg = "headers";
37 * record client id and ignore retransmissions.
38 * we're still single thread at this point.
41 clientrxmit(DNSmsg *req, uchar *buf)
43 Inprogress *p, *empty;
48 for(p = inprog; p < &inprog[Maxactive]; p++){
55 if(req->qd->owner == p->owner)
56 if(req->qd->type == p->type)
57 if(memcmp(uh, &p->uh, Udphdrsize) == 0)
61 return nil; /* shouldn't happen: see slave() & Maxactive def'n */
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);
74 addforwtarg(char *host)
78 if (currtarg >= nelem(forwtarg)) {
79 dnslog("too many forwarding targets");
82 tp = forwtarg + currtarg;
83 if (parseip(tp->addr, host) < 0) {
84 dnslog("can't parse ip %s", host);
87 tp->lastdial = time(nil);
88 tp->fd = udpport(mntpt);
93 tp->host = estrdup(host);
99 * fast forwarding of incoming queries to other dns servers.
100 * intended primarily for debugging.
103 redistrib(uchar *buf, int len)
105 static uchar outpkt[Udphdrsize + Maxudp + 1024];
109 assert(len <= sizeof outpkt);
110 memmove(outpkt, buf, len);
111 uh = (Udphdr *)outpkt;
112 for (tp = forwtarg; tp < forwtarg + currtarg; tp++)
114 memmove(outpkt, tp->addr, sizeof tp->addr);
115 hnputs(uh->rport, 53); /* dns port */
116 if (write(tp->fd, outpkt, len) != len) {
120 } else if (tp->host && time(nil) - tp->lastdial > 60) {
121 tp->lastdial = time(nil);
122 tp->fd = udpport(mntpt);
127 * a process to act as a dns server for outside reqeusts
130 dnudpserver(char *mntpt)
132 volatile int fd, len, op, rcode;
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;
142 * fork sharing text, data, and bss with parent.
143 * stay in the same note group.
145 switch(rfork(RFPROC|RFMEM|RFNOWAIT)){
156 procsetname("udp server announcing");
159 while((fd = udpannounce(mntpt)) < 0)
162 // procsetname("udp server");
163 memset(&req, 0, sizeof req);
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);
178 len = read(fd, buf, sizeof buf);
180 if(len <= Udphdrsize)
188 // dnslog("read received UDP from %I to %I",
189 // ((Udphdr*)buf)->raddr, ((Udphdr*)buf)->laddr);
190 getactivity(&req, 0);
191 req.aborttime = timems() + Maxreqtm;
192 req.from = smprint("%I", buf);
196 err = convM2DNS(&buf[Udphdrsize], len, &reqmsg, &rcode);
198 /* first bytes in buf are source IP addr */
199 dnslog("server: input error: %s from %I", err, buf);
204 if(reqmsg.qdcount < 1){
205 dnslog("server: no questions from %I", buf);
207 } else if(reqmsg.flags & Fresp){
208 dnslog("server: reply not request from %I", buf);
211 op = reqmsg.flags & Omask;
212 if(op != Oquery && op != Onotify){
213 dnslog("server: op %d from %I", reqmsg.flags & Omask,
218 if(reqmsg.qd == nil){
219 dnslog("server: no question RR from %I", buf);
223 if(debug || (trace && subsume(trace, reqmsg.qd->owner->name)))
224 dnslog("%d: serve (%I/%d) %d %s %s",
225 req.id, buf, uh->rport[0]<<8 | uh->rport[1],
226 reqmsg.id, reqmsg.qd->owner->name,
227 rrname(reqmsg.qd->type, tname, sizeof tname));
229 p = clientrxmit(&reqmsg, buf);
232 dnslog("%d: duplicate", req.id);
239 for (rr = reqmsg.qd; rr; rr = rr->next)
240 syslog(0, "dnsq", "id %d: (%I/%d) %d %s %s",
241 req.id, buf, uh->rport[0]<<8 |
242 uh->rport[1], reqmsg.id,
243 reqmsg.qd->owner->name,
244 rrname(reqmsg.qd->type, tname,
247 /* loop through each question */
249 memset(&repmsg, 0, sizeof repmsg);
252 dnserver(&reqmsg, &repmsg, &req, buf, rcode);
255 dnnotify(&reqmsg, &repmsg, &req);
258 /* send reply on fd to address in buf's udp hdr */
259 reply(fd, buf, &repmsg, &req);
260 freeanswers(&repmsg);
267 freeanswers(&reqmsg);
276 * announce on well-known dns udp port and set message style interface
279 udpannounce(char *mntpt)
282 char dir[64], datafile[64+6];
286 sprint(datafile, "%s/udp!*!dns", mntpt);
287 ctl = announce(datafile, dir);
290 warning("can't announce on %s", datafile);
294 /* turn on header style interface */
295 if(write(ctl, hmsg, strlen(hmsg)) != strlen(hmsg)){
298 warning("can't enable headers on %s", datafile);
302 snprint(datafile, sizeof(datafile), "%s/data", dir);
303 data = open(datafile, ORDWR);
307 warning("can't open %s to announce on dns udp port",
317 reply(int fd, uchar *buf, DNSmsg *rep, Request *reqp)
322 if(debug || (trace && subsume(trace, rep->qd->owner->name)))
323 dnslog("%d: reply (%I/%d) %d %s %s qd %R an %R ns %R ar %R",
324 reqp->id, buf, buf[4]<<8 | buf[5],
325 rep->id, rep->qd->owner->name,
326 rrname(rep->qd->type, tname, sizeof tname),
327 rep->qd, rep->an, rep->ns, rep->ar);
329 len = convDNS2M(rep, &buf[Udphdrsize], Maxudp);
331 if(write(fd, buf, len) != len)
332 dnslog("error sending reply: %r");