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 }