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