2 * dnstcp - serve dns via tcp
17 char *logfile = "dns";
24 char *zonerefreshprogram;
26 static int readmsg(int, uchar*, int);
27 static void reply(int, DNSmsg*, Request*);
28 static void dnzone(DNSmsg*, DNSmsg*, Request*, uchar*);
29 static void getcaller(char*);
30 static void refreshmain(char*);
35 fprint(2, "usage: %s [-adrR] [-f ndbfile] [-x netmtpt] [conndir]\n", argv0);
40 main(int argc, char *argv[])
42 volatile int len, rcode;
43 volatile char tname[32];
44 char *volatile err, *volatile ext = "";
45 volatile uchar buf[64*1024], callip[IPaddrlen];
46 volatile DNSmsg reqmsg, repmsg;
58 dbfile = EARGF(usage());
81 snprint(mntpt, sizeof mntpt, "%s", ext);
83 snprint(mntpt, sizeof mntpt, "/net%s", ext);
85 dnslog("dnstcp call from %s", caller);
86 memset(callip, 0, sizeof callip);
87 parseip(callip, caller);
92 memset(&req, 0, sizeof req);
95 procsetname("main loop");
99 /* loop on requests */
100 for(;; putactivity(0)){
102 memset(&repmsg, 0, sizeof repmsg);
103 len = readmsg(0, buf, sizeof buf);
107 getactivity(&req, 0);
108 req.aborttime = timems() + S2MS(15*Min);
110 memset(&reqmsg, 0, sizeof reqmsg);
111 err = convM2DNS(buf, len, &reqmsg, &rcode);
113 dnslog("server: input error: %s from %s", err, caller);
118 if(reqmsg.qdcount < 1){
119 dnslog("server: no questions from %s", caller);
121 } else if(reqmsg.flags & Fresp){
122 dnslog("server: reply not request from %s",
125 } else if((reqmsg.flags & Omask) != Oquery){
126 dnslog("server: op %d from %s",
127 reqmsg.flags & Omask, caller);
131 if(reqmsg.qd == nil){
132 dnslog("server: no question RR from %s", caller);
137 dnslog("[%d] %d: serve (%s) %d %s %s",
138 getpid(), req.id, caller,
139 reqmsg.id, reqmsg.qd->owner->name,
140 rrname(reqmsg.qd->type, tname, sizeof tname));
142 /* loop through each question */
144 if(reqmsg.qd->type == Taxfr)
145 dnzone(&reqmsg, &repmsg, &req, callip);
147 dnserver(&reqmsg, &repmsg, &req, callip, rcode);
148 reply(1, &repmsg, &req);
149 rrfreelist(repmsg.qd);
150 rrfreelist(repmsg.an);
151 rrfreelist(repmsg.ns);
152 rrfreelist(repmsg.ar);
154 rrfreelist(reqmsg.qd); /* qd will be nil */
155 rrfreelist(reqmsg.an);
156 rrfreelist(reqmsg.ns);
157 rrfreelist(reqmsg.ar);
168 readmsg(int fd, uchar *buf, int max)
173 if(readn(fd, x, 2) != 2)
178 if(readn(fd, buf, n) != n)
184 reply(int fd, DNSmsg *rep, Request *req)
192 dnslog("%d: reply (%s) %s %s %ux",
194 rep->qd->owner->name,
195 rrname(rep->qd->type, tname, sizeof tname),
197 for(rp = rep->an; rp; rp = rp->next)
199 for(rp = rep->ns; rp; rp = rp->next)
201 for(rp = rep->ar; rp; rp = rp->next)
206 len = convDNS2M(rep, buf+2, sizeof(buf) - 2);
209 rv = write(fd, buf, len+2);
211 dnslog("[%d] sending reply: %d instead of %d", getpid(), rv,
218 * Hash table for domain names. The hash is based only on the
219 * first element of the domain name.
221 extern DN *ht[HTLEN];
236 inzone(DN *dp, char *name, int namelen, int depth)
242 if(numelem(dp->name) != depth)
244 n = strlen(dp->name);
247 if(cistrcmp(name, dp->name + n - namelen) != 0)
249 if(n > namelen && dp->name[n - namelen - 1] != '.')
255 findserver(uchar *srcip, Server *servers, Request *req)
260 for(; servers != nil; servers = servers->next){
261 if(strcmp(ipattr(servers->name), "ip") == 0){
262 if(parseip(ip, servers->name) == -1)
264 if(ipcmp(srcip, ip) == 0)
268 list = dnresolve(servers->name, Cin, Ta, req, nil, 0, 1, 1, nil);
269 rrcat(&list, dnresolve(servers->name, Cin, Taaaa, req, nil, 0, 1, 1, nil));
270 for(rp = list; rp != nil; rp = rp->next){
271 if(parseip(ip, rp->ip->name) == -1)
273 if(ipcmp(srcip, ip) == 0)
284 dnzone(DNSmsg *reqp, DNSmsg *repp, Request *req, uchar *srcip)
288 int h, depth, found, nlen;
290 memset(repp, 0, sizeof(*repp));
293 reqp->qd = reqp->qd->next;
295 repp->flags = Fauth | Fresp | Oquery;
297 repp->flags |= Fcanrec;
298 dp = repp->qd->owner;
301 repp->an = rrlookup(dp, Tsoa, NOneg);
302 if(repp->an != nil && !anyone && !myip(srcip)
303 && findserver(srcip, repp->an->soa->slaves, req) == nil){
304 dnslog("dnstcp: %I axfr %s - not a dnsslave", srcip, dp->name);
305 rrfreelist(repp->an);
311 rrfreelist(repp->an);
314 nlen = strlen(dp->name);
316 /* construct a breadth-first search of the name space (hard with a hash) */
318 for(depth = numelem(dp->name); ; depth++){
320 for(h = 0; h < HTLEN; h++)
321 for(ndp = ht[h]; ndp; ndp = ndp->next)
322 if(inzone(ndp, dp->name, nlen, depth)){
323 for(rp = ndp->rr; rp; rp = rp->next){
325 * there shouldn't be negatives,
327 * don't send any soa's,
344 repp->an = rrlookup(dp, Tsoa, NOneg);
346 rrfreelist(repp->an);
357 static char remote[128];
359 snprint(remote, sizeof(remote), "%s/remote", dir);
360 fd = open(remote, OREAD);
363 n = read(fd, remote, sizeof remote - 1);
367 if(remote[n-1] == '\n')
374 refreshmain(char *net)
379 snprint(file, sizeof(file), "%s/dns", net);
381 dnslog("refreshing %s", file);
382 fd = open(file, ORDWR);
384 dnslog("can't refresh %s", file);
386 fprint(fd, "refresh");
392 * the following varies between dnsdebug and dns
395 logreply(int id, uchar *addr, DNSmsg *mp)
399 dnslog("%d: rcvd %I flags:%s%s%s%s%s", id, addr,
400 mp->flags & Fauth? " auth": "",
401 mp->flags & Ftrunc? " trunc": "",
402 mp->flags & Frecurse? " rd": "",
403 mp->flags & Fcanrec? " ra": "",
404 (mp->flags & (Fauth|Rmask)) == (Fauth|Rname)? " nx": "");
405 for(rp = mp->qd; rp != nil; rp = rp->next)
406 dnslog("%d: rcvd %I qd %s", id, addr, rp->owner->name);
407 for(rp = mp->an; rp != nil; rp = rp->next)
408 dnslog("%d: rcvd %I an %R", id, addr, rp);
409 for(rp = mp->ns; rp != nil; rp = rp->next)
410 dnslog("%d: rcvd %I ns %R", id, addr, rp);
411 for(rp = mp->ar; rp != nil; rp = rp->next)
412 dnslog("%d: rcvd %I ar %R", id, addr, rp);
416 logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type)
420 dnslog("%d.%d: sending to %I/%s %s %s",
421 id, subid, addr, sname, rname, rrname(type, buf, sizeof buf));
425 getdnsservers(int class)
427 return dnsservers(class);