226 lines
5.4 KiB
C
226 lines
5.4 KiB
C
/*
|
|
* This file is part of the UCB release of Plan 9. It is subject to the license
|
|
* terms in the LICENSE file found in the top-level directory of this
|
|
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
|
* part of the UCB release of Plan 9, including this file, may be copied,
|
|
* modified, propagated, or distributed except according to the terms contained
|
|
* in the LICENSE file.
|
|
*/
|
|
/* Portions of this file are Copyright (C) 2015-2018 Giacomo Tesio <giacomo@tesio.it>
|
|
* See /doc/license/gpl-2.0.txt for details about the licensing.
|
|
*/
|
|
/* Portions of this file are Copyright (C) 9front's team.
|
|
* See /doc/license/9front-mit for details about the licensing.
|
|
* See http://git.9front.org/plan9front/plan9front/HEAD/info.html for a list of authors.
|
|
*/
|
|
#include <u.h>
|
|
#include <lib9.h>
|
|
#include <ip.h>
|
|
#include "dns.h"
|
|
|
|
static RR* doextquery(DNSmsg*, Request*, int);
|
|
static void hint(RR**, RR*);
|
|
|
|
/* set in dns.c */
|
|
int norecursion; /* don't allow recursive requests */
|
|
|
|
/*
|
|
* answer a dns request
|
|
*/
|
|
void
|
|
dnserver(DNSmsg *reqp, DNSmsg *repp, Request *req, uint8_t *srcip, int rcode)
|
|
{
|
|
int recursionflag;
|
|
char *cp, *errmsg;
|
|
char tname[32];
|
|
DN *nsdp, *dp;
|
|
Area *myarea;
|
|
RR *tp, *neg, *rp;
|
|
|
|
recursionflag = norecursion? 0: Fcanrec;
|
|
memset(repp, 0, sizeof(*repp));
|
|
repp->id = reqp->id;
|
|
repp->flags = Fresp | recursionflag | Oquery;
|
|
|
|
/* move one question from reqp to repp */
|
|
tp = reqp->qd;
|
|
reqp->qd = tp->next;
|
|
tp->next = nil;
|
|
repp->qd = tp;
|
|
|
|
if (rcode) {
|
|
errmsg = "";
|
|
if (rcode >= 0 && rcode < nrname)
|
|
errmsg = rname[rcode];
|
|
dnslog("server: response code 0%o (%s), req from %I",
|
|
rcode, errmsg, srcip);
|
|
/* provide feedback to clients who send us trash */
|
|
repp->flags = (rcode&Rmask) | Fresp | Fcanrec | Oquery;
|
|
return;
|
|
}
|
|
if(!rrsupported(repp->qd->type)){
|
|
dnslog("server: unsupported request %s from %I",
|
|
rrname(repp->qd->type, tname, sizeof tname), srcip);
|
|
repp->flags = Runimplimented | Fresp | Fcanrec | Oquery;
|
|
return;
|
|
}
|
|
|
|
if(repp->qd->owner->class != Cin){
|
|
dnslog("server: unsupported class %d from %I",
|
|
repp->qd->owner->class, srcip);
|
|
repp->flags = Runimplimented | Fresp | Fcanrec | Oquery;
|
|
return;
|
|
}
|
|
|
|
myarea = inmyarea(repp->qd->owner->name);
|
|
if(myarea != nil) {
|
|
if(repp->qd->type == Tixfr || repp->qd->type == Taxfr){
|
|
dnslog("server: unsupported xfr request %s for %s from %I",
|
|
rrname(repp->qd->type, tname, sizeof tname),
|
|
repp->qd->owner->name, srcip);
|
|
repp->flags = Runimplimented | Fresp | recursionflag |
|
|
Oquery;
|
|
return;
|
|
}
|
|
} else
|
|
if(norecursion) {
|
|
/* we don't recurse and we're not authoritative */
|
|
repp->flags = Rok | Fresp | Oquery;
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* get the answer if we can, in *repp
|
|
*/
|
|
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 == nil){
|
|
dp = dnlookup(repp->qd->owner->name, repp->qd->owner->class, 0);
|
|
if(dp->rr == nil)
|
|
if(reqp->flags & Frecurse)
|
|
repp->flags |= dp->respcode | 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 == nil)
|
|
continue;
|
|
|
|
repp->ns = rrlookup(nsdp, Tns, OKneg);
|
|
if(repp->ns){
|
|
/* don't pass on anything we know is wrong */
|
|
if(repp->ns->negative){
|
|
rp = repp->ns;
|
|
repp->ns = nil;
|
|
rrfreelist(rp);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (strncmp(nsdp->name, "local#", 6) == 0)
|
|
dnslog("returning %s as nameserver", nsdp->name);
|
|
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) {
|
|
tp = rrlookup(neg->negsoaowner, Tsoa, NOneg);
|
|
rrcat(&repp->ns, tp);
|
|
}
|
|
repp->flags |= neg->negrcode;
|
|
}
|
|
|
|
/*
|
|
* get rid of duplicates
|
|
*/
|
|
unique(repp->an);
|
|
unique(repp->ns);
|
|
unique(repp->ar);
|
|
|
|
rrfreelist(neg);
|
|
}
|
|
|
|
/*
|
|
* satisfy a recursive request. dnlookup will handle cnames.
|
|
*/
|
|
static RR*
|
|
doextquery(DNSmsg *mp, Request *req, int recurse)
|
|
{
|
|
uint16_t 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);
|
|
rp = nil;
|
|
}
|
|
|
|
/* 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);
|
|
if(hp == nil)
|
|
hp = rrlookup(rp->host, Taaaa, NOneg);
|
|
if(hp == nil)
|
|
hp = dblookup(rp->host->name, Cin, Taaaa, 0, 0);
|
|
if (hp && strncmp(hp->owner->name, "local#", 6) == 0)
|
|
dnslog("returning %s as hint", hp->owner->name);
|
|
rrcat(last, hp);
|
|
break;
|
|
}
|
|
}
|