Blob


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"
9 static int udpannounce(char*);
10 static void reply(int, uchar*, DNSmsg*, Request*);
12 extern char *logfile;
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;
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;
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 }
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 }
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;
81 fd = (uintptr)v;
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;
102 if(reqmsg.flags & Fresp){
103 syslog(0, logfile, "server: reply not request from %I", buf);
104 goto freereq;
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;
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));
120 p = clientrxmit(&reqmsg, buf);
121 if(p == 0){
122 if(debug)
123 syslog(0, logfile, "%d: duplicate", req.id);
124 goto freereq;
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;
138 reply(fd, buf, &repmsg, &req);
139 rrfreelist(repmsg.qd);
140 rrfreelist(repmsg.an);
141 rrfreelist(repmsg.ns);
142 rrfreelist(repmsg.ar);
145 p->inuse = 0;
147 freereq:
148 rrfreelist(reqmsg.qd);
149 rrfreelist(reqmsg.an);
150 rrfreelist(reqmsg.ns);
151 rrfreelist(reqmsg.ar);
155 /*
156 * announce on udp port
157 */
158 static int
159 udpannounce(char *mntpt)
161 int fd;
162 char buf[40];
163 USED(mntpt);
165 if((fd=announce(udpaddr, buf)) < 0)
166 warning("announce %s: %r", buf);
167 return fd;
170 static void
171 reply(int fd, uchar *buf, DNSmsg *rep, Request *reqp)
173 int len;
174 char tname[32];
175 RR *rp;
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);
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;
195 if(udpwrite(fd, (Udphdr*)buf, buf+Udphdrsize, len) != len)
196 syslog(0, logfile, "error sending reply: %r");
199 void
200 dnudpserver(void *v)
202 int i, fd;
204 while((fd = udpannounce(v)) < 0)
205 sleep(5*1000);
206 for(i=0; i<Maxactive; i++)
207 proccreate(udpproc, (void*)(uintptr)fd, STACK);