2 * dnstcp - serve dns via tcp
14 char *logfile = "dns";
22 char *zonerefreshprogram;
24 static int readmsg(int, uchar*, int);
25 static void reply(int, DNSmsg*, Request*);
26 static void dnzone(DNSmsg*, DNSmsg*, Request*);
27 static void getcaller(char*);
28 static void refreshmain(char*);
33 fprint(2, "usage: %s [-rR] [-f ndb-file] [-x netmtpt] [conndir]\n", argv0);
38 main(int argc, char *argv[])
40 volatile int len, rcode;
41 volatile char tname[32];
42 char *volatile err, *volatile ext = "";
43 volatile uchar buf[64*1024], callip[IPaddrlen];
44 volatile DNSmsg reqmsg, repmsg;
54 dbfile = EARGF(usage());
77 snprint(mntpt, sizeof mntpt, "%s", ext);
79 snprint(mntpt, sizeof mntpt, "/net%s", ext);
81 dnslog("dnstcp call from %s", caller);
82 memset(callip, 0, sizeof callip);
83 parseip(callip, caller);
87 memset(&req, 0, sizeof req);
90 procsetname("main loop");
92 /* loop on requests */
93 for(;; putactivity(0)){
95 memset(&repmsg, 0, sizeof repmsg);
96 len = readmsg(0, buf, sizeof buf);
100 getactivity(&req, 0);
101 req.aborttime = timems() + S2MS(15*Min);
103 memset(&reqmsg, 0, sizeof reqmsg);
104 err = convM2DNS(buf, len, &reqmsg, &rcode);
106 dnslog("server: input error: %s from %s", err, caller);
111 if(reqmsg.qdcount < 1){
112 dnslog("server: no questions from %s", caller);
114 } else if(reqmsg.flags & Fresp){
115 dnslog("server: reply not request from %s",
118 } else if((reqmsg.flags & Omask) != Oquery){
119 dnslog("server: op %d from %s",
120 reqmsg.flags & Omask, caller);
124 if(reqmsg.qd == nil){
125 dnslog("server: no question RR from %s", caller);
130 dnslog("[%d] %d: serve (%s) %d %s %s",
131 getpid(), req.id, caller,
132 reqmsg.id, reqmsg.qd->owner->name,
133 rrname(reqmsg.qd->type, tname, sizeof tname));
135 /* loop through each question */
137 if(reqmsg.qd->type == Taxfr)
138 dnzone(&reqmsg, &repmsg, &req);
140 dnserver(&reqmsg, &repmsg, &req, callip, rcode);
141 reply(1, &repmsg, &req);
142 rrfreelist(repmsg.qd);
143 rrfreelist(repmsg.an);
144 rrfreelist(repmsg.ns);
145 rrfreelist(repmsg.ar);
147 rrfreelist(reqmsg.qd); /* qd will be nil */
148 rrfreelist(reqmsg.an);
149 rrfreelist(reqmsg.ns);
150 rrfreelist(reqmsg.ar);
161 readmsg(int fd, uchar *buf, int max)
166 if(readn(fd, x, 2) != 2)
171 if(readn(fd, buf, n) != n)
177 reply(int fd, DNSmsg *rep, Request *req)
185 dnslog("%d: reply (%s) %s %s %ux",
187 rep->qd->owner->name,
188 rrname(rep->qd->type, tname, sizeof tname),
190 for(rp = rep->an; rp; rp = rp->next)
192 for(rp = rep->ns; rp; rp = rp->next)
194 for(rp = rep->ar; rp; rp = rp->next)
199 len = convDNS2M(rep, buf+2, sizeof(buf) - 2);
202 rv = write(fd, buf, len+2);
204 dnslog("[%d] sending reply: %d instead of %d", getpid(), rv,
211 * Hash table for domain names. The hash is based only on the
212 * first element of the domain name.
214 extern DN *ht[HTLEN];
229 inzone(DN *dp, char *name, int namelen, int depth)
235 if(numelem(dp->name) != depth)
237 n = strlen(dp->name);
240 if(cistrcmp(name, dp->name + n - namelen) != 0)
242 if(n > namelen && dp->name[n - namelen - 1] != '.')
248 dnzone(DNSmsg *reqp, DNSmsg *repp, Request *req)
252 int h, depth, found, nlen;
254 memset(repp, 0, sizeof(*repp));
257 reqp->qd = reqp->qd->next;
259 repp->flags = Fauth | Fresp | Oquery;
261 repp->flags |= Fcanrec;
262 dp = repp->qd->owner;
265 repp->an = rrlookup(dp, Tsoa, NOneg);
269 rrfreelist(repp->an);
272 nlen = strlen(dp->name);
274 /* construct a breadth-first search of the name space (hard with a hash) */
276 for(depth = numelem(dp->name); ; depth++){
278 for(h = 0; h < HTLEN; h++)
279 for(ndp = ht[h]; ndp; ndp = ndp->next)
280 if(inzone(ndp, dp->name, nlen, depth)){
281 for(rp = ndp->rr; rp; rp = rp->next){
283 * there shouldn't be negatives,
285 * don't send any soa's,
302 repp->an = rrlookup(dp, Tsoa, NOneg);
304 rrfreelist(repp->an);
315 static char remote[128];
317 snprint(remote, sizeof(remote), "%s/remote", dir);
318 fd = open(remote, OREAD);
321 n = read(fd, remote, sizeof remote - 1);
325 if(remote[n-1] == '\n')
332 refreshmain(char *net)
337 snprint(file, sizeof(file), "%s/dns", net);
339 dnslog("refreshing %s", file);
340 fd = open(file, ORDWR);
342 dnslog("can't refresh %s", file);
344 fprint(fd, "refresh");
350 * the following varies between dnsdebug and dns
353 logreply(int id, uchar *addr, DNSmsg *mp)
357 dnslog("%d: rcvd %I flags:%s%s%s%s%s", id, addr,
358 mp->flags & Fauth? " auth": "",
359 mp->flags & Ftrunc? " trunc": "",
360 mp->flags & Frecurse? " rd": "",
361 mp->flags & Fcanrec? " ra": "",
362 (mp->flags & (Fauth|Rmask)) == (Fauth|Rname)? " nx": "");
363 for(rp = mp->qd; rp != nil; rp = rp->next)
364 dnslog("%d: rcvd %I qd %s", id, addr, rp->owner->name);
365 for(rp = mp->an; rp != nil; rp = rp->next)
366 dnslog("%d: rcvd %I an %R", id, addr, rp);
367 for(rp = mp->ns; rp != nil; rp = rp->next)
368 dnslog("%d: rcvd %I ns %R", id, addr, rp);
369 for(rp = mp->ar; rp != nil; rp = rp->next)
370 dnslog("%d: rcvd %I ar %R", id, addr, rp);
374 logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type)
378 dnslog("%d.%d: sending to %I/%s %s %s",
379 id, subid, addr, sname, rname, rrname(type, buf, sizeof buf));
383 getdnsservers(int class)
385 return dnsservers(class);