blob: 13161548142617471439724ff69d5ba3cc4c9521 [file] [log] [blame]
rsc27b457a2006-02-15 18:34:50 +00001#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"
8
9static char adir[40];
10
11static int
12readmsg(int fd, uchar *buf, int max)
13{
14 int n;
15 uchar x[2];
16
17 if(readn(fd, x, 2) != 2)
18 return -1;
19 n = (x[0]<<8) | x[1];
20 if(n > max)
21 return -1;
22 if(readn(fd, buf, n) != n)
23 return -1;
24 return n;
25}
26
27static int
28connreadmsg(int tfd, int *fd, uchar *buf, int max)
29{
30 int n;
31 int lfd;
32 char ldir[40];
33
34 lfd = listen(adir, ldir);
35 if (lfd < 0)
36 return -1;
37 *fd = accept(lfd, ldir);
rsc19256e02006-02-17 19:21:49 +000038 if (*fd >= 0)
rsc27b457a2006-02-15 18:34:50 +000039 n = readmsg(*fd, buf, max);
rsc19256e02006-02-17 19:21:49 +000040 else
41 n = -1;
rsc27b457a2006-02-15 18:34:50 +000042 close(lfd);
43 return n;
44}
45
46static int
47reply(int fd, DNSmsg *rep, Request *req, NetConnInfo *caller)
48{
49 int len;
50 char tname[32];
51 uchar buf[4096];
52 RR *rp;
53
54 if(debug){
55 syslog(0, logfile, "%d: reply (%s) %s %s %ux",
56 req->id, caller ? caller->raddr : "unk",
57 rep->qd->owner->name,
58 rrname(rep->qd->type, tname, sizeof tname),
59 rep->flags);
60 for(rp = rep->an; rp; rp = rp->next)
61 syslog(0, logfile, "an %R", rp);
62 for(rp = rep->ns; rp; rp = rp->next)
63 syslog(0, logfile, "ns %R", rp);
64 for(rp = rep->ar; rp; rp = rp->next)
65 syslog(0, logfile, "ar %R", rp);
66 }
67
68
69 len = convDNS2M(rep, buf+2, sizeof(buf) - 2);
70 if(len <= 0)
71 abort(); /* "dnserver: converting reply" */;
72 buf[0] = len>>8;
73 buf[1] = len;
74 if(write(fd, buf, len+2) < 0){
75 syslog(0, logfile, "sending reply: %r");
76 return -1;
77 }
78 return 0;
79}
80
81/*
82 * Hash table for domain names. The hash is based only on the
83 * first element of the domain name.
84 */
85extern DN *ht[HTLEN];
86
87static int
88numelem(char *name)
89{
90 int i;
91
92 i = 1;
93 for(; *name; name++)
94 if(*name == '.')
95 i++;
96 return i;
97}
98
99static int
100inzone(DN *dp, char *name, int namelen, int depth)
101{
102 int n;
103
104 if(dp->name == 0)
105 return 0;
106 if(numelem(dp->name) != depth)
107 return 0;
108 n = strlen(dp->name);
109 if(n < namelen)
110 return 0;
111 if(strcmp(name, dp->name + n - namelen) != 0)
112 return 0;
113 if(n > namelen && dp->name[n - namelen - 1] != '.')
114 return 0;
115 return 1;
116}
117
118static int
119dnzone(DNSmsg *reqp, DNSmsg *repp, Request *req, int rfd, NetConnInfo *caller)
120{
121 DN *dp, *ndp;
122 RR r, *rp;
123 int h, depth, found, nlen, rv;
124
125 rv = 0;
126 memset(repp, 0, sizeof(*repp));
127 repp->id = reqp->id;
128 repp->flags = Fauth | Fresp | Fcanrec | Oquery;
129 repp->qd = reqp->qd;
130 reqp->qd = reqp->qd->next;
131 repp->qd->next = 0;
132 dp = repp->qd->owner;
133
134 /* send the soa */
135 repp->an = rrlookup(dp, Tsoa, NOneg);
136 rv = reply(rfd, repp, req, caller);
137 if(repp->an == 0 || rv < 0)
138 goto out;
139 rrfreelist(repp->an);
140
141 nlen = strlen(dp->name);
142
143 /* construct a breadth first search of the name space (hard with a hash) */
144 repp->an = &r;
145 for(depth = numelem(dp->name); ; depth++){
146 found = 0;
147 for(h = 0; h < HTLEN; h++)
148 for(ndp = ht[h]; ndp; ndp = ndp->next)
149 if(inzone(ndp, dp->name, nlen, depth)){
150 for(rp = ndp->rr; rp; rp = rp->next){
151 /* there shouldn't be negatives, but just in case */
152 if(rp->negative)
153 continue;
154
155 /* don't send an soa's, ns's are enough */
156 if(rp->type == Tsoa)
157 continue;
158
159 r = *rp;
160 r.next = 0;
161 rv = reply(rfd, repp, req, caller);
162 if(rv < 0)
163 goto out;
164 }
165 found = 1;
166 }
167 if(!found)
168 break;
169 }
170
171 /* resend the soa */
172 repp->an = rrlookup(dp, Tsoa, NOneg);
173 rv = reply(rfd, repp, req, caller);
174out:
175 if (repp->an)
176 rrfreelist(repp->an);
177 rrfree(repp->qd);
178 return rv;
179}
180
181void
182tcpproc(void *v)
183{
rsc19256e02006-02-17 19:21:49 +0000184 int len, rv;
rsc27b457a2006-02-15 18:34:50 +0000185 Request req;
186 DNSmsg reqmsg, repmsg;
187 char *err;
188 uchar buf[512];
189 char tname[32];
190 int fd, rfd;
191 NetConnInfo *caller;
192
193 rfd = -1;
rsc19256e02006-02-17 19:21:49 +0000194 fd = (uintptr)v;
rsc27b457a2006-02-15 18:34:50 +0000195 caller = 0;
196 /* loop on requests */
197 for(;; putactivity()){
198 if (rfd == 1)
199 return;
200 close(rfd);
201 now = time(0);
202 memset(&repmsg, 0, sizeof(repmsg));
rsc27b457a2006-02-15 18:34:50 +0000203 if (fd == 0) {
204 len = readmsg(fd, buf, sizeof buf);
205 rfd = 1;
206 } else {
207 len = connreadmsg(fd, &rfd, buf, sizeof buf);
208 }
209 if(len <= 0)
210 continue;
rscb7f150b2006-02-24 17:40:15 +0000211 freenetconninfo(caller);
212 caller = getnetconninfo(0, fd);
rsc27b457a2006-02-15 18:34:50 +0000213 getactivity(&req);
214 req.aborttime = now + 15*Min;
215 err = convM2DNS(buf, len, &reqmsg);
216 if(err){
217 syslog(0, logfile, "server: input error: %s from %I", err, buf);
218 continue;
219 }
220 if(reqmsg.qdcount < 1){
221 syslog(0, logfile, "server: no questions from %I", buf);
222 continue;
223 }
224 if(reqmsg.flags & Fresp){
225 syslog(0, logfile, "server: reply not request from %I", buf);
226 continue;
227 }
228 if((reqmsg.flags & Omask) != Oquery){
229 syslog(0, logfile, "server: op %d from %I", reqmsg.flags & Omask, buf);
230 continue;
231 }
232
233 if(debug)
234 syslog(0, logfile, "%d: serve (%s) %d %s %s",
235 req.id, caller ? caller->raddr : 0,
236 reqmsg.id,
237 reqmsg.qd->owner->name,
238 rrname(reqmsg.qd->type, tname, sizeof tname));
239
240 /* loop through each question */
241 while(reqmsg.qd){
242 if(reqmsg.qd->type == Taxfr){
243 if(dnzone(&reqmsg, &repmsg, &req, rfd, caller) < 0)
244 break;
245 } else {
246 dnserver(&reqmsg, &repmsg, &req);
rsc19256e02006-02-17 19:21:49 +0000247 rv = reply(rfd, &repmsg, &req, caller);
rsc27b457a2006-02-15 18:34:50 +0000248 rrfreelist(repmsg.qd);
249 rrfreelist(repmsg.an);
250 rrfreelist(repmsg.ns);
251 rrfreelist(repmsg.ar);
rsc19256e02006-02-17 19:21:49 +0000252 if(rv < 0)
253 break;
rsc27b457a2006-02-15 18:34:50 +0000254 }
255 }
256
257 rrfreelist(reqmsg.qd);
258 rrfreelist(reqmsg.an);
259 rrfreelist(reqmsg.ns);
260 rrfreelist(reqmsg.ar);
261 }
262}
263
264enum {
rsc226d80b2006-04-01 15:35:09 +0000265 Maxactivetcp = 4
rsc27b457a2006-02-15 18:34:50 +0000266};
267
rsc27b457a2006-02-15 18:34:50 +0000268static int
269tcpannounce(char *mntpt)
270{
271 int fd;
rsc27b457a2006-02-15 18:34:50 +0000272
273 USED(mntpt);
rsc49a14962006-02-20 19:38:29 +0000274 if((fd=announce(tcpaddr, adir)) < 0)
275 warning("announce %s: %r", tcpaddr);
rsc27b457a2006-02-15 18:34:50 +0000276 return fd;
277}
278
279void
280dntcpserver(void *v)
281{
282 int i, fd;
rsc27b457a2006-02-15 18:34:50 +0000283
rsc19256e02006-02-17 19:21:49 +0000284 while((fd = tcpannounce(v)) < 0)
rsc27b457a2006-02-15 18:34:50 +0000285 sleep(5*1000);
286
287 for(i=0; i<Maxactivetcp; i++)
rsc19256e02006-02-17 19:21:49 +0000288 proccreate(tcpproc, (void*)(uintptr)fd, STACK);
rsc27b457a2006-02-15 18:34:50 +0000289}