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());
78 snprint(mntpt, sizeof mntpt, "%s", ext);
80 snprint(mntpt, sizeof mntpt, "/net%s", ext);
82 if(myipaddr(ipaddr, mntpt) < 0)
83 sysfatal("can't read my ip address");
84 dnslog("dnstcp call from %s to %I", caller, ipaddr);
85 memset(callip, 0, sizeof callip);
86 parseip(callip, caller);
90 memset(&req, 0, sizeof req);
93 procsetname("main loop");
95 /* loop on requests */
96 for(;; putactivity(0)){
98 memset(&repmsg, 0, sizeof repmsg);
99 len = readmsg(0, buf, sizeof buf);
103 getactivity(&req, 0);
104 req.aborttime = timems() + S2MS(15*Min);
106 memset(&reqmsg, 0, sizeof reqmsg);
107 err = convM2DNS(buf, len, &reqmsg, &rcode);
109 dnslog("server: input error: %s from %s", err, caller);
114 if(reqmsg.qdcount < 1){
115 dnslog("server: no questions from %s", caller);
117 } else if(reqmsg.flags & Fresp){
118 dnslog("server: reply not request from %s",
121 } else if((reqmsg.flags & Omask) != Oquery){
122 dnslog("server: op %d from %s",
123 reqmsg.flags & Omask, caller);
127 if(reqmsg.qd == nil){
128 dnslog("server: no question RR from %s", caller);
133 dnslog("[%d] %d: serve (%s) %d %s %s",
134 getpid(), req.id, caller,
135 reqmsg.id, reqmsg.qd->owner->name,
136 rrname(reqmsg.qd->type, tname, sizeof tname));
138 /* loop through each question */
140 if(reqmsg.qd->type == Taxfr)
141 dnzone(&reqmsg, &repmsg, &req);
143 dnserver(&reqmsg, &repmsg, &req, callip, rcode);
144 reply(1, &repmsg, &req);
145 rrfreelist(repmsg.qd);
146 rrfreelist(repmsg.an);
147 rrfreelist(repmsg.ns);
148 rrfreelist(repmsg.ar);
150 rrfreelist(reqmsg.qd); /* qd will be nil */
151 rrfreelist(reqmsg.an);
152 rrfreelist(reqmsg.ns);
153 rrfreelist(reqmsg.ar);
164 readmsg(int fd, uchar *buf, int max)
169 if(readn(fd, x, 2) != 2)
174 if(readn(fd, buf, n) != n)
180 reply(int fd, DNSmsg *rep, Request *req)
188 dnslog("%d: reply (%s) %s %s %ux",
190 rep->qd->owner->name,
191 rrname(rep->qd->type, tname, sizeof tname),
193 for(rp = rep->an; rp; rp = rp->next)
195 for(rp = rep->ns; rp; rp = rp->next)
197 for(rp = rep->ar; rp; rp = rp->next)
202 len = convDNS2M(rep, buf+2, sizeof(buf) - 2);
205 rv = write(fd, buf, len+2);
207 dnslog("[%d] sending reply: %d instead of %d", getpid(), rv,
214 * Hash table for domain names. The hash is based only on the
215 * first element of the domain name.
217 extern DN *ht[HTLEN];
232 inzone(DN *dp, char *name, int namelen, int depth)
238 if(numelem(dp->name) != depth)
240 n = strlen(dp->name);
243 if(cistrcmp(name, dp->name + n - namelen) != 0)
245 if(n > namelen && dp->name[n - namelen - 1] != '.')
251 dnzone(DNSmsg *reqp, DNSmsg *repp, Request *req)
255 int h, depth, found, nlen;
257 memset(repp, 0, sizeof(*repp));
260 reqp->qd = reqp->qd->next;
262 repp->flags = Fauth | Fresp | Oquery;
264 repp->flags |= Fcanrec;
265 dp = repp->qd->owner;
268 repp->an = rrlookup(dp, Tsoa, NOneg);
272 rrfreelist(repp->an);
275 nlen = strlen(dp->name);
277 /* construct a breadth-first search of the name space (hard with a hash) */
279 for(depth = numelem(dp->name); ; depth++){
281 for(h = 0; h < HTLEN; h++)
282 for(ndp = ht[h]; ndp; ndp = ndp->next)
283 if(inzone(ndp, dp->name, nlen, depth)){
284 for(rp = ndp->rr; rp; rp = rp->next){
286 * there shouldn't be negatives,
288 * don't send any soa's,
305 repp->an = rrlookup(dp, Tsoa, NOneg);
307 rrfreelist(repp->an);
318 static char remote[128];
320 snprint(remote, sizeof(remote), "%s/remote", dir);
321 fd = open(remote, OREAD);
324 n = read(fd, remote, sizeof remote - 1);
328 if(remote[n-1] == '\n')
335 refreshmain(char *net)
340 snprint(file, sizeof(file), "%s/dns", net);
342 dnslog("refreshing %s", file);
343 fd = open(file, ORDWR);
345 dnslog("can't refresh %s", file);
347 fprint(fd, "refresh");
353 * the following varies between dnsdebug and dns
356 logreply(int id, uchar *addr, DNSmsg *mp)
360 dnslog("%d: rcvd %I flags:%s%s%s%s%s", id, addr,
361 mp->flags & Fauth? " auth": "",
362 mp->flags & Ftrunc? " trunc": "",
363 mp->flags & Frecurse? " rd": "",
364 mp->flags & Fcanrec? " ra": "",
365 (mp->flags & (Fauth|Rmask)) == (Fauth|Rname)? " nx": "");
366 for(rp = mp->qd; rp != nil; rp = rp->next)
367 dnslog("%d: rcvd %I qd %s", id, addr, rp->owner->name);
368 for(rp = mp->an; rp != nil; rp = rp->next)
369 dnslog("%d: rcvd %I an %R", id, addr, rp);
370 for(rp = mp->ns; rp != nil; rp = rp->next)
371 dnslog("%d: rcvd %I ns %R", id, addr, rp);
372 for(rp = mp->ar; rp != nil; rp = rp->next)
373 dnslog("%d: rcvd %I ar %R", id, addr, rp);
377 logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type)
381 dnslog("%d.%d: sending to %I/%s %s %s",
382 id, subid, addr, sname, rname, rrname(type, buf, sizeof buf));
386 getdnsservers(int class)
388 return dnsservers(class);