plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

dnserver.c (3719B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <ip.h>
      4 #include <bio.h>
      5 #include <ndb.h>
      6 #include "dns.h"
      7 
      8 static RR*	doextquery(DNSmsg*, Request*, int);
      9 static void	hint(RR**, RR*);
     10 
     11 extern char *logfile;
     12 
     13 /*
     14  *  answer a dns request
     15  */
     16 void
     17 dnserver(DNSmsg *reqp, DNSmsg *repp, Request *req)
     18 {
     19 	RR *tp, *neg;
     20 	char *cp;
     21 	DN *nsdp, *dp;
     22 	Area *myarea;
     23 	char tname[32];
     24 
     25 	dncheck(nil, 1);
     26 
     27 	memset(repp, 0, sizeof(*repp));
     28 	repp->id = reqp->id;
     29 	repp->flags = Fresp | Fcanrec | Oquery;
     30 
     31 	/* move one question from reqp to repp */
     32 	tp = reqp->qd;
     33 	reqp->qd = tp->next;
     34 	tp->next = 0;
     35 	repp->qd = tp;
     36 
     37 	if(!rrsupported(repp->qd->type)){
     38 		syslog(0, logfile, "server: request %s", rrname(repp->qd->type, tname, sizeof tname));
     39 		repp->flags = Runimplimented | Fresp | Fcanrec | Oquery;
     40 		return;
     41 	}
     42 
     43 	if(repp->qd->owner->class != Cin){
     44 		syslog(0, logfile, "server: class %d", repp->qd->owner->class);
     45 		repp->flags = Runimplimented | Fresp | Fcanrec | Oquery;
     46 		return;
     47 	}
     48 
     49 	myarea = inmyarea(repp->qd->owner->name);
     50 	if(myarea != nil && (repp->qd->type == Tixfr || repp->qd->type == Taxfr)){
     51 		syslog(0, logfile, "server: request %s", rrname(repp->qd->type, tname, sizeof tname));
     52 		repp->flags = Runimplimented | Fresp | Fcanrec | Oquery;
     53 		return;
     54 	}
     55 
     56 	/*
     57 	 *  get the answer if we can
     58 	 */
     59 	if(reqp->flags & Frecurse)
     60 		neg = doextquery(repp, req, Recurse);
     61 	else
     62 		neg = doextquery(repp, req, Dontrecurse);
     63 
     64 	/* authority is transitive */
     65 	if(myarea != nil || (repp->an && repp->an->auth))
     66 		repp->flags |= Fauth;
     67 
     68 	/* pass on error codes */
     69 	if(repp->an == 0){
     70 		dp = dnlookup(repp->qd->owner->name, repp->qd->owner->class, 0);
     71 		if(dp->rr == 0)
     72 			if(reqp->flags & Frecurse)
     73 				repp->flags |= dp->nonexistent|Fauth;
     74 	}
     75 
     76 	if(myarea == nil){
     77 		/*
     78 		 *  add name server if we know
     79 		 */
     80 		for(cp = repp->qd->owner->name; cp; cp = walkup(cp)){
     81 			nsdp = dnlookup(cp, repp->qd->owner->class, 0);
     82 			if(nsdp == 0)
     83 				continue;
     84 
     85 			repp->ns = rrlookup(nsdp, Tns, OKneg);
     86 			if(repp->ns){
     87 				/* don't pass on anything we know is wrong */
     88 				if(repp->ns->negative){
     89 					rrfreelist(repp->ns);
     90 					repp->ns = nil;
     91 				}
     92 				break;
     93 			}
     94 
     95 			repp->ns = dblookup(cp, repp->qd->owner->class, Tns, 0, 0);
     96 			if(repp->ns)
     97 				break;
     98 		}
     99 	}
    100 
    101 	/*
    102 	 *  add ip addresses as hints
    103 	 */
    104 	if(repp->qd->type != Taxfr && repp->qd->type != Tixfr){
    105 		for(tp = repp->ns; tp; tp = tp->next)
    106 			hint(&repp->ar, tp);
    107 		for(tp = repp->an; tp; tp = tp->next)
    108 			hint(&repp->ar, tp);
    109 	}
    110 
    111 	/*
    112 	 *  add an soa to the authority section to help client with negative caching
    113 	 */
    114 	if(repp->an == nil){
    115 		if(myarea != nil){
    116 			rrcopy(myarea->soarr, &tp);
    117 			rrcat(&repp->ns, tp);
    118 		} else if(neg != nil) {
    119 			if(neg->negsoaowner != nil)
    120 				rrcat(&repp->ns, rrlookup(neg->negsoaowner, Tsoa, NOneg));
    121 			repp->flags |= neg->negrcode;
    122 		}
    123 	}
    124 
    125 	/*
    126 	 *  get rid of duplicates
    127 	 */
    128 	unique(repp->an);
    129 	unique(repp->ns);
    130 	unique(repp->ar);
    131 
    132 	rrfreelist(neg);
    133 
    134 	dncheck(nil, 1);
    135 }
    136 
    137 /*
    138  *  satisfy a recursive request.  dnlookup will handle cnames.
    139  */
    140 static RR*
    141 doextquery(DNSmsg *mp, Request *req, int recurse)
    142 {
    143 	int type;
    144 	char *name;
    145 	RR *rp, *neg;
    146 
    147 	name = mp->qd->owner->name;
    148 	type = mp->qd->type;
    149 	rp = dnresolve(name, Cin, type, req, &mp->an, 0, recurse, 1, 0);
    150 
    151 	/* don't return soa hints as answers, it's wrong */
    152 	if(rp && rp->db && !rp->auth && rp->type == Tsoa)
    153 		rrfreelist(rp);
    154 
    155 	/* don't let negative cached entries escape */
    156 	neg = rrremneg(&rp);
    157 	rrcat(&mp->an, rp);
    158 	return neg;
    159 }
    160 
    161 static void
    162 hint(RR **last, RR *rp)
    163 {
    164 	RR *hp;
    165 
    166 	switch(rp->type){
    167 	case Tns:
    168 	case Tmx:
    169 	case Tmb:
    170 	case Tmf:
    171 	case Tmd:
    172 		hp = rrlookup(rp->host, Ta, NOneg);
    173 		if(hp == nil)
    174 			hp = dblookup(rp->host->name, Cin, Ta, 0, 0);
    175 		rrcat(last, hp);
    176 		break;
    177 	}
    178 }