diff options
author | rsc <devnull@localhost> | 2005-12-27 04:30:05 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2005-12-27 04:30:05 +0000 |
commit | 3e0d8fb3ea83b2b65a6425c65beda887140f9349 (patch) | |
tree | ce1579f6999c0e4adad35b75c498ddc714b40c1e /src/cmd/ndb/dnserver.c | |
parent | cff43a06f21a674b2b16e72f8853aac5fd24f48d (diff) | |
download | plan9port-3e0d8fb3ea83b2b65a6425c65beda887140f9349.tar.gz plan9port-3e0d8fb3ea83b2b65a6425c65beda887140f9349.tar.bz2 plan9port-3e0d8fb3ea83b2b65a6425c65beda887140f9349.zip |
add dns
Diffstat (limited to 'src/cmd/ndb/dnserver.c')
-rwxr-xr-x | src/cmd/ndb/dnserver.c | 178 |
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; + } +} |