Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include <bio.h>
5 #include <ndb.h>
6 #include "dns.h"
8 static int udpannounce(char*);
9 static void reply(int, uchar*, DNSmsg*, Request*);
11 extern char *logfile;
13 static void
14 ding(void *x, char *msg)
15 {
16 USED(x);
17 if(strcmp(msg, "alarm") == 0)
18 noted(NCONT);
19 else
20 noted(NDFLT);
21 }
23 typedef struct Inprogress Inprogress;
24 struct Inprogress
25 {
26 int inuse;
27 OUdphdr uh;
28 DN *owner;
29 int type;
30 int id;
31 };
32 Inprogress inprog[Maxactive+2];
34 /*
35 * record client id and ignore retransmissions.
36 * we're still single thread at this point.
37 */
38 static Inprogress*
39 clientrxmit(DNSmsg *req, uchar *buf)
40 {
41 Inprogress *p, *empty;
42 OUdphdr *uh;
44 uh = (OUdphdr *)buf;
45 empty = 0;
46 for(p = inprog; p < &inprog[Maxactive]; p++){
47 if(p->inuse == 0){
48 if(empty == 0)
49 empty = p;
50 continue;
51 }
52 if(req->id == p->id)
53 if(req->qd->owner == p->owner)
54 if(req->qd->type == p->type)
55 if(memcmp(uh, &p->uh, OUdphdrsize) == 0)
56 return 0;
57 }
58 if(empty == 0)
59 return 0; /* shouldn't happen - see slave() and definition of Maxactive */
61 empty->id = req->id;
62 empty->owner = req->qd->owner;
63 empty->type = req->qd->type;
64 memmove(&empty->uh, uh, OUdphdrsize);
65 empty->inuse = 1;
66 return empty;
67 }
69 /*
70 * a process to act as a dns server for outside reqeusts
71 */
72 void
73 dnudpserver(char *mntpt)
74 {
75 int fd, len, op;
76 Request req;
77 DNSmsg reqmsg, repmsg;
78 uchar buf[OUdphdrsize + Maxudp + 1024];
79 char *err;
80 Inprogress *p;
81 char tname[32];
82 OUdphdr *uh;
84 /* fork sharing text, data, and bss with parent */
85 switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
86 case -1:
87 break;
88 case 0:
89 break;
90 default:
91 return;
92 }
94 fd = -1;
95 notify(ding);
96 restart:
97 if(fd >= 0)
98 close(fd);
99 while((fd = udpannounce(mntpt)) < 0)
100 sleep(5000);
101 if(setjmp(req.mret))
102 putactivity();
103 req.isslave = 0;
105 /* loop on requests */
106 for(;; putactivity()){
107 memset(&repmsg, 0, sizeof(repmsg));
108 memset(&reqmsg, 0, sizeof(reqmsg));
109 alarm(60*1000);
110 len = udpread(fd, (OUdphdr*)buf, buf+OUdphdrsize, sizeof(buf)-OUdphdrsize);
111 alarm(0);
112 if(len <= 0)
113 goto restart;
114 uh = (OUdphdr*)buf;
115 getactivity(&req);
116 req.aborttime = now + 30; /* don't spend more than 30 seconds */
117 err = convM2DNS(&buf[OUdphdrsize], len, &reqmsg);
118 if(err){
119 syslog(0, logfile, "server: input error: %s from %I", err, buf);
120 continue;
122 if(reqmsg.qdcount < 1){
123 syslog(0, logfile, "server: no questions from %I", buf);
124 goto freereq;
126 if(reqmsg.flags & Fresp){
127 syslog(0, logfile, "server: reply not request from %I", buf);
128 goto freereq;
130 op = reqmsg.flags & Omask;
131 if(op != Oquery && op != Onotify){
132 syslog(0, logfile, "server: op %d from %I", reqmsg.flags & Omask, buf);
133 goto freereq;
136 if(debug || (trace && subsume(trace, reqmsg.qd->owner->name))){
137 syslog(0, logfile, "%d: serve (%I/%d) %d %s %s",
138 req.id, buf, ((uh->rport[0])<<8)+uh->rport[1],
139 reqmsg.id,
140 reqmsg.qd->owner->name,
141 rrname(reqmsg.qd->type, tname, sizeof tname));
144 p = clientrxmit(&reqmsg, buf);
145 if(p == 0){
146 if(debug)
147 syslog(0, logfile, "%d: duplicate", req.id);
148 goto freereq;
151 /* loop through each question */
152 while(reqmsg.qd){
153 memset(&repmsg, 0, sizeof(repmsg));
154 switch(op){
155 case Oquery:
156 dnserver(&reqmsg, &repmsg, &req);
157 break;
158 case Onotify:
159 dnnotify(&reqmsg, &repmsg, &req);
160 break;
162 reply(fd, buf, &repmsg, &req);
163 rrfreelist(repmsg.qd);
164 rrfreelist(repmsg.an);
165 rrfreelist(repmsg.ns);
166 rrfreelist(repmsg.ar);
169 p->inuse = 0;
171 freereq:
172 rrfreelist(reqmsg.qd);
173 rrfreelist(reqmsg.an);
174 rrfreelist(reqmsg.ns);
175 rrfreelist(reqmsg.ar);
177 if(req.isslave){
178 putactivity();
179 _exits(0);
185 /*
186 * announce on udp port
187 */
188 static int
189 udpannounce(char *mntpt)
191 int fd;
192 char buf[40];
194 USED(mntpt);
196 if((fd=announce("udp!*!nameserver", buf)) < 0)
197 warning("can't announce on dns udp port");
198 return fd;
201 static void
202 reply(int fd, uchar *buf, DNSmsg *rep, Request *reqp)
204 int len;
205 char tname[32];
206 RR *rp;
208 if(debug || (trace && subsume(trace, rep->qd->owner->name)))
209 syslog(0, logfile, "%d: reply (%I/%d) %d %s %s an %R ns %R ar %R",
210 reqp->id, buf, ((buf[4])<<8)+buf[5],
211 rep->id, rep->qd->owner->name,
212 rrname(rep->qd->type, tname, sizeof tname), rep->an, rep->ns, rep->ar);
214 len = convDNS2M(rep, &buf[OUdphdrsize], Maxudp);
215 if(len <= 0){
216 syslog(0, logfile, "error converting reply: %s %d", rep->qd->owner->name,
217 rep->qd->type);
218 for(rp = rep->an; rp; rp = rp->next)
219 syslog(0, logfile, "an %R", rp);
220 for(rp = rep->ns; rp; rp = rp->next)
221 syslog(0, logfile, "ns %R", rp);
222 for(rp = rep->ar; rp; rp = rp->next)
223 syslog(0, logfile, "ar %R", rp);
224 return;
226 if(udpwrite(fd, (OUdphdr*)buf, buf+OUdphdrsize, len) != len)
227 syslog(0, logfile, "error sending reply: %r");