203 lines · 4.4 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <ip.h>#include "dns.h" static RR*	doextquery(DNSmsg*, Request*, int);static void	hint(RR**, RR*); /* *  answer a dns request */voiddnserver(DNSmsg *reqp, DNSmsg *repp, Request *req, uchar *srcip, int rcode){	char tname[32], *cp;	DN *nsdp;	Area *myarea, *delegation;	RR *rp, *neg; 	repp->id = reqp->id;	repp->flags = Fresp | (reqp->flags & Omask);	setercode(repp, Rok); 	/* move one question from reqp to repp */	rp = reqp->qd;	reqp->qd = rp->next;	rp->next = nil;	repp->qd = rp; 	if(rcode != Rok || (reqp->flags & Omask) != Oquery){		dnslog("%d: server: response code %d %s, req from %I",			req->id, rcode, rcname(rcode), srcip);		/* provide feedback to clients who send us trash */		setercode(repp, rcode);		return;	}	if(repp->qd->type == Topt || !rrsupported(repp->qd->type)){		if(debug)			dnslog("%d: server: unsupported request %s from %I",				req->id, rrname(repp->qd->type, tname, sizeof tname), srcip);		setercode(repp, Runimplimented);		return;	}	if(repp->qd->owner->class != Cin){		if(debug)			dnslog("%d: server: unsupported class %d from %I",				req->id, repp->qd->owner->class, srcip);		setercode(repp, Runimplimented);		return;	} 	myarea = inmyarea(repp->qd->owner->name, &delegation);	if(myarea){		if(repp->qd->type == Tixfr || repp->qd->type == Taxfr){			if(debug)				dnslog("%d: server: unsupported xfr request %s for %s from %I",					req->id, rrname(repp->qd->type, tname, sizeof tname),					repp->qd->owner->name, srcip);			setercode(repp, Runimplimented);			return;		}		repp->flags |= Fauth;		neg = doextquery(repp, req, Dontrecurse);	} else {		if(cfg.nonrecursive		|| cfg.localrecursive && !localip(srcip)){			if(delegation == nil){				/*				 * we don't recurse and we're not authoritative				 * nor lies the domain in a delegated sub area.				 */				setercode(repp, Rrefused);				return;			}			neg = nil;		} else {			repp->flags |= Fcanrec;			if(reqp->flags & Frecurse){				neg = doextquery(repp, req, Recurse); 				/* pass on error codes */				if(repp->an == nil && repp->qd->owner->rr == nil){					repp->flags |= Fauth;					setercode(repp, repp->qd->owner->respcode);				}			} else				neg = doextquery(repp, req, Dontrecurse); 			/* authority is transitive */			if(repp->an && repp->an->auth)				repp->flags |= Fauth;		} 		/*		 *  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;			} 			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(rp = repp->ns; rp; rp = rp->next)			hint(&repp->ar, rp);		for(rp = repp->an; rp; rp = rp->next)			hint(&repp->ar, rp);	} 	/*	 *  add an soa to the authority section to help client	 *  with negative caching	 */	if(repp->an == nil){		if(myarea){			rrcopy(myarea->soarr, &rp);			rrcat(&repp->ns, rp);		} else if(neg != nil) {			if(neg->negsoaowner != nil) {				rp = rrlookup(neg->negsoaowner, Tsoa, NOneg);				rrcat(&repp->ns, rp);			}			setercode(repp, 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){	ushort 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, nil); 	/* 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 voidhint(RR **last, RR *rp){	RR *hp; 	switch(rp->type){	case Tns:	case Tmx:	case Tsrv:	case Tcname:		hp = rrlookup(rp->host, Ta, NOneg);		if(hp == nil)			hp = dblookup(rp->host->name, Cin, Ta, 0, 0);		rrcat(last, hp);		hp = rrlookup(rp->host, Taaaa, NOneg);		if(hp == nil)			hp = dblookup(rp->host->name, Cin, Taaaa, 0, 0);		rrcat(last, hp);		break;	}}