aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/ndb/dnserver.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2005-12-27 04:30:05 +0000
committerrsc <devnull@localhost>2005-12-27 04:30:05 +0000
commit3e0d8fb3ea83b2b65a6425c65beda887140f9349 (patch)
treece1579f6999c0e4adad35b75c498ddc714b40c1e /src/cmd/ndb/dnserver.c
parentcff43a06f21a674b2b16e72f8853aac5fd24f48d (diff)
downloadplan9port-3e0d8fb3ea83b2b65a6425c65beda887140f9349.tar.gz
plan9port-3e0d8fb3ea83b2b65a6425c65beda887140f9349.tar.bz2
plan9port-3e0d8fb3ea83b2b65a6425c65beda887140f9349.zip
add dns
Diffstat (limited to 'src/cmd/ndb/dnserver.c')
-rwxr-xr-xsrc/cmd/ndb/dnserver.c178
1 files changed, 178 insertions, 0 deletions
diff --git a/src/cmd/ndb/dnserver.c b/src/cmd/ndb/dnserver.c
new file mode 100755
index 00000000..509734b0
--- /dev/null
+++ b/src/cmd/ndb/dnserver.c
@@ -0,0 +1,178 @@
+#include <u.h>
+#include <libc.h>
+#include <ip.h>
+#include <bio.h>
+#include <ndb.h>
+#include "dns.h"
+
+static RR* doextquery(DNSmsg*, Request*, int);
+static void hint(RR**, RR*);
+
+extern char *logfile;
+
+/*
+ * answer a dns request
+ */
+void
+dnserver(DNSmsg *reqp, DNSmsg *repp, Request *req)
+{
+ RR *tp, *neg;
+ char *cp;
+ DN *nsdp, *dp;
+ Area *myarea;
+ char tname[32];
+
+ dncheck(nil, 1);
+
+ memset(repp, 0, sizeof(*repp));
+ repp->id = reqp->id;
+ repp->flags = Fresp | Fcanrec | Oquery;
+
+ /* move one question from reqp to repp */
+ tp = reqp->qd;
+ reqp->qd = tp->next;
+ tp->next = 0;
+ repp->qd = tp;
+
+ if(!rrsupported(repp->qd->type)){
+ syslog(0, logfile, "server: request %s", rrname(repp->qd->type, tname, sizeof tname));
+ repp->flags = Runimplimented | Fresp | Fcanrec | Oquery;
+ return;
+ }
+
+ if(repp->qd->owner->class != Cin){
+ syslog(0, logfile, "server: class %d", repp->qd->owner->class);
+ repp->flags = Runimplimented | Fresp | Fcanrec | Oquery;
+ return;
+ }
+
+ myarea = inmyarea(repp->qd->owner->name);
+ if(myarea != nil && (repp->qd->type == Tixfr || repp->qd->type == Taxfr)){
+ syslog(0, logfile, "server: request %s", rrname(repp->qd->type, tname, sizeof tname));
+ repp->flags = Runimplimented | Fresp | Fcanrec | Oquery;
+ return;
+ }
+
+ /*
+ * get the answer if we can
+ */
+ if(reqp->flags & Frecurse)
+ neg = doextquery(repp, req, Recurse);
+ else
+ neg = doextquery(repp, req, Dontrecurse);
+
+ /* authority is transitive */
+ if(myarea != nil || (repp->an && repp->an->auth))
+ repp->flags |= Fauth;
+
+ /* pass on error codes */
+ if(repp->an == 0){
+ dp = dnlookup(repp->qd->owner->name, repp->qd->owner->class, 0);
+ if(dp->rr == 0)
+ if(reqp->flags & Frecurse)
+ repp->flags |= dp->nonexistent|Fauth;
+ }
+
+ if(myarea == nil){
+ /*
+ * add name server if we know
+ */
+ for(cp = repp->qd->owner->name; cp; cp = walkup(cp)){
+ nsdp = dnlookup(cp, repp->qd->owner->class, 0);
+ if(nsdp == 0)
+ continue;
+
+ repp->ns = rrlookup(nsdp, Tns, OKneg);
+ if(repp->ns){
+ /* don't pass on anything we know is wrong */
+ if(repp->ns->negative){
+ rrfreelist(repp->ns);
+ repp->ns = nil;
+ }
+ break;
+ }
+
+ repp->ns = dblookup(cp, repp->qd->owner->class, Tns, 0, 0);
+ if(repp->ns)
+ break;
+ }
+ }
+
+ /*
+ * add ip addresses as hints
+ */
+ if(repp->qd->type != Taxfr && repp->qd->type != Tixfr){
+ for(tp = repp->ns; tp; tp = tp->next)
+ hint(&repp->ar, tp);
+ for(tp = repp->an; tp; tp = tp->next)
+ hint(&repp->ar, tp);
+ }
+
+ /*
+ * add an soa to the authority section to help client with negative caching
+ */
+ if(repp->an == nil){
+ if(myarea != nil){
+ rrcopy(myarea->soarr, &tp);
+ rrcat(&repp->ns, tp);
+ } else if(neg != nil) {
+ if(neg->negsoaowner != nil)
+ rrcat(&repp->ns, rrlookup(neg->negsoaowner, Tsoa, NOneg));
+ repp->flags |= neg->negrcode;
+ }
+ }
+
+ /*
+ * get rid of duplicates
+ */
+ unique(repp->an);
+ unique(repp->ns);
+ unique(repp->ar);
+
+ rrfreelist(neg);
+
+ dncheck(nil, 1);
+}
+
+/*
+ * satisfy a recursive request. dnlookup will handle cnames.
+ */
+static RR*
+doextquery(DNSmsg *mp, Request *req, int recurse)
+{
+ int type;
+ char *name;
+ RR *rp, *neg;
+
+ name = mp->qd->owner->name;
+ type = mp->qd->type;
+ rp = dnresolve(name, Cin, type, req, &mp->an, 0, recurse, 1, 0);
+
+ /* don't return soa hints as answers, it's wrong */
+ if(rp && rp->db && !rp->auth && rp->type == Tsoa)
+ rrfreelist(rp);
+
+ /* don't let negative cached entries escape */
+ neg = rrremneg(&rp);
+ rrcat(&mp->an, rp);
+ return neg;
+}
+
+static void
+hint(RR **last, RR *rp)
+{
+ RR *hp;
+
+ switch(rp->type){
+ case Tns:
+ case Tmx:
+ case Tmb:
+ case Tmf:
+ case Tmd:
+ hp = rrlookup(rp->host, Ta, NOneg);
+ if(hp == nil)
+ hp = dblookup(rp->host->name, Cin, Ta, 0, 0);
+ rrcat(last, hp);
+ break;
+ }
+}