2 * dnstcp - serve dns via tcp
14 uchar ipaddr[IPaddrlen]; /* my ip address */
15 char *logfile = "dns";
23 char *zonerefreshprogram;
25 static int readmsg(int, uchar*, int);
26 static void reply(int, DNSmsg*, Request*);
27 static void dnzone(DNSmsg*, DNSmsg*, Request*);
28 static void getcaller(char*);
29 static void refreshmain(char*);
34 fprint(2, "usage: %s [-rR] [-f ndb-file] [-x netmtpt] [conndir]\n", argv0);
39 main(int argc, char *argv[])
41 volatile int len, rcode;
42 volatile char tname[32];
43 char *volatile err, *volatile ext = "";
44 volatile uchar buf[64*1024], callip[IPaddrlen];
45 volatile DNSmsg reqmsg, repmsg;
55 dbfile = EARGF(usage());
80 snprint(mntpt, sizeof mntpt, "/net%s", ext);
81 if(myipaddr(ipaddr, mntpt) < 0)
82 sysfatal("can't read my ip address");
83 dnslog("dnstcp call from %s to %I", caller, ipaddr);
84 memset(callip, 0, sizeof callip);
85 parseip(callip, caller);
89 memset(&req, 0, sizeof req);
92 procsetname("main loop");
94 /* loop on requests */
95 for(;; putactivity(0)){
97 memset(&repmsg, 0, sizeof repmsg);
98 len = readmsg(0, buf, sizeof buf);
102 getactivity(&req, 0);
103 req.aborttime = timems() + S2MS(15*Min);
105 memset(&reqmsg, 0, sizeof reqmsg);
106 err = convM2DNS(buf, len, &reqmsg, &rcode);
108 dnslog("server: input error: %s from %s", err, caller);
113 if(reqmsg.qdcount < 1){
114 dnslog("server: no questions from %s", caller);
116 } else if(reqmsg.flags & Fresp){
117 dnslog("server: reply not request from %s",
120 } else if((reqmsg.flags & Omask) != Oquery){
121 dnslog("server: op %d from %s",
122 reqmsg.flags & Omask, caller);
126 if(reqmsg.qd == nil){
127 dnslog("server: no question RR from %s", caller);
132 dnslog("[%d] %d: serve (%s) %d %s %s",
133 getpid(), req.id, caller,
134 reqmsg.id, reqmsg.qd->owner->name,
135 rrname(reqmsg.qd->type, tname, sizeof tname));
137 /* loop through each question */
139 if(reqmsg.qd->type == Taxfr)
140 dnzone(&reqmsg, &repmsg, &req);
142 dnserver(&reqmsg, &repmsg, &req, callip, rcode);
143 reply(1, &repmsg, &req);
144 rrfreelist(repmsg.qd);
145 rrfreelist(repmsg.an);
146 rrfreelist(repmsg.ns);
147 rrfreelist(repmsg.ar);
149 rrfreelist(reqmsg.qd); /* qd will be nil */
150 rrfreelist(reqmsg.an);
151 rrfreelist(reqmsg.ns);
152 rrfreelist(reqmsg.ar);
163 readmsg(int fd, uchar *buf, int max)
168 if(readn(fd, x, 2) != 2)
173 if(readn(fd, buf, n) != n)
179 reply(int fd, DNSmsg *rep, Request *req)
187 dnslog("%d: reply (%s) %s %s %ux",
189 rep->qd->owner->name,
190 rrname(rep->qd->type, tname, sizeof tname),
192 for(rp = rep->an; rp; rp = rp->next)
194 for(rp = rep->ns; rp; rp = rp->next)
196 for(rp = rep->ar; rp; rp = rp->next)
201 len = convDNS2M(rep, buf+2, sizeof(buf) - 2);
204 rv = write(fd, buf, len+2);
206 dnslog("[%d] sending reply: %d instead of %d", getpid(), rv,
213 * Hash table for domain names. The hash is based only on the
214 * first element of the domain name.
216 extern DN *ht[HTLEN];
231 inzone(DN *dp, char *name, int namelen, int depth)
237 if(numelem(dp->name) != depth)
239 n = strlen(dp->name);
242 if(cistrcmp(name, dp->name + n - namelen) != 0)
244 if(n > namelen && dp->name[n - namelen - 1] != '.')
250 dnzone(DNSmsg *reqp, DNSmsg *repp, Request *req)
254 int h, depth, found, nlen;
256 memset(repp, 0, sizeof(*repp));
259 reqp->qd = reqp->qd->next;
261 repp->flags = Fauth | Fresp | Oquery;
263 repp->flags |= Fcanrec;
264 dp = repp->qd->owner;
267 repp->an = rrlookup(dp, Tsoa, NOneg);
271 rrfreelist(repp->an);
274 nlen = strlen(dp->name);
276 /* construct a breadth-first search of the name space (hard with a hash) */
278 for(depth = numelem(dp->name); ; depth++){
280 for(h = 0; h < HTLEN; h++)
281 for(ndp = ht[h]; ndp; ndp = ndp->next)
282 if(inzone(ndp, dp->name, nlen, depth)){
283 for(rp = ndp->rr; rp; rp = rp->next){
285 * there shouldn't be negatives,
287 * don't send any soa's,
304 repp->an = rrlookup(dp, Tsoa, NOneg);
306 rrfreelist(repp->an);
317 static char remote[128];
319 snprint(remote, sizeof(remote), "%s/remote", dir);
320 fd = open(remote, OREAD);
323 n = read(fd, remote, sizeof remote - 1);
327 if(remote[n-1] == '\n')
334 refreshmain(char *net)
339 snprint(file, sizeof(file), "%s/dns", net);
341 dnslog("refreshing %s", file);
342 fd = open(file, ORDWR);
344 dnslog("can't refresh %s", file);
346 fprint(fd, "refresh");
352 * the following varies between dnsdebug and dns
355 logreply(int id, uchar *addr, DNSmsg *mp)
359 dnslog("%d: rcvd %I flags:%s%s%s%s%s", id, addr,
360 mp->flags & Fauth? " auth": "",
361 mp->flags & Ftrunc? " trunc": "",
362 mp->flags & Frecurse? " rd": "",
363 mp->flags & Fcanrec? " ra": "",
364 (mp->flags & (Fauth|Rmask)) == (Fauth|Rname)? " nx": "");
365 for(rp = mp->qd; rp != nil; rp = rp->next)
366 dnslog("%d: rcvd %I qd %s", id, addr, rp->owner->name);
367 for(rp = mp->an; rp != nil; rp = rp->next)
368 dnslog("%d: rcvd %I an %R", id, addr, rp);
369 for(rp = mp->ns; rp != nil; rp = rp->next)
370 dnslog("%d: rcvd %I ns %R", id, addr, rp);
371 for(rp = mp->ar; rp != nil; rp = rp->next)
372 dnslog("%d: rcvd %I ar %R", id, addr, rp);
376 logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type)
380 dnslog("%d.%d: sending to %I/%s %s %s",
381 id, subid, addr, sname, rname, rrname(type, buf, sizeof buf));
385 getdnsservers(int class)
387 return dnsservers(class);