]>
Commit | Line | Data |
---|---|---|
86c152f2 BH |
1 | /* |
2 | PowerDNS Versatile Database Driven Nameserver | |
20177d1d | 3 | Copyright (C) 2003 PowerDNS.COM BV |
86c152f2 BH |
4 | |
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 2 of the License, or | |
8 | (at your option) any later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program; if not, write to the Free Software | |
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 | */ | |
19 | #include <iostream> | |
20 | #include <map> | |
21 | #include <algorithm> | |
afbe2787 | 22 | #include <set> |
86c152f2 BH |
23 | #include <cerrno> |
24 | #include <cstdio> | |
25 | #include <cstdlib> | |
86c152f2 | 26 | #include <utility> |
20177d1d | 27 | #include "misc.hh" |
86c152f2 BH |
28 | #include "arguments.hh" |
29 | #include "lwres.hh" | |
30 | ||
ac539791 | 31 | typedef map<string,set<DNSResourceRecord> > cache_t; |
86c152f2 | 32 | cache_t cache; |
20177d1d | 33 | map<string,string> negcache; |
86c152f2 | 34 | |
7bf26383 BH |
35 | struct GetBestNSAnswer |
36 | { | |
37 | string qname; | |
38 | set<DNSResourceRecord> bestns; | |
39 | bool operator<(const GetBestNSAnswer &b) const | |
40 | { | |
41 | if(qname<b.qname) | |
42 | return true; | |
43 | if(qname==b.qname) | |
44 | return bestns<b.bestns; | |
45 | return false; | |
46 | } | |
47 | }; | |
48 | ||
728485ca | 49 | /** dramatis personae */ |
7bf26383 BH |
50 | int doResolveAt(set<string> nameservers, string auth, const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, |
51 | int depth, set<GetBestNSAnswer>&beenthere); | |
52 | int doResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, set<GetBestNSAnswer>& beenthere); | |
728485ca BH |
53 | bool doCNAMECacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res); |
54 | bool doCacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res); | |
7bf26383 | 55 | void getBestNSFromCache(const string &qname, set<DNSResourceRecord>&bestns, int depth, set<GetBestNSAnswer>& beenthere); |
728485ca | 56 | void addCruft(const string &qname, vector<DNSResourceRecord>& ret); |
7bf26383 | 57 | string getBestNSNamesFromCache(const string &qname,set<string>& nsset, int depth, set<GetBestNSAnswer>&beenthere); |
728485ca BH |
58 | void addAuthorityRecords(const string& qname, vector<DNSResourceRecord>& ret, int depth); |
59 | ||
60 | /** everything begins here - this is the entry point just after receiving a packet */ | |
61 | int beginResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret) | |
62 | { | |
7bf26383 BH |
63 | set<GetBestNSAnswer> beenthere; |
64 | int res=doResolve(qname, qtype, ret,0,beenthere); | |
728485ca BH |
65 | if(!res) |
66 | addCruft(qname, ret); | |
67 | cout<<endl; | |
68 | return res; | |
69 | } | |
afbe2787 | 70 | |
7bf26383 | 71 | int doResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, set<GetBestNSAnswer>& beenthere) |
afbe2787 | 72 | { |
728485ca BH |
73 | string prefix; |
74 | prefix.assign(3*depth, ' '); | |
75 | ||
76 | int res; | |
77 | if(doCNAMECacheCheck(qname,qtype,ret,depth,res)) // will reroute us if needed | |
78 | return res; | |
afbe2787 | 79 | |
728485ca BH |
80 | if(doCacheCheck(qname,qtype,ret,depth,res)) // we done |
81 | return res; | |
afbe2787 | 82 | |
728485ca BH |
83 | cout<<prefix<<qname<<": No cache hit for '"<<qname<<"|"<<qtype.getName()<<"', trying to find an appropriate NS record"<<endl; |
84 | ||
85 | string subdomain(qname); | |
86 | ||
87 | set<string> nsset; | |
7bf26383 BH |
88 | subdomain=getBestNSNamesFromCache(subdomain,nsset,depth, beenthere); // pass beenthere to both occasions/ |
89 | if(!(res=doResolveAt(nsset,subdomain,qname,qtype,ret,depth, beenthere))) | |
728485ca BH |
90 | return 0; |
91 | ||
92 | cout<<prefix<<qname<<": failed"<<endl; | |
20177d1d | 93 | return res<0 ? RCode::ServFail : res; |
afbe2787 BH |
94 | } |
95 | ||
7bf26383 | 96 | string getA(const string &qname, int depth, set<GetBestNSAnswer>& beenthere) |
75b49099 | 97 | { |
728485ca BH |
98 | vector<DNSResourceRecord> res; |
99 | string ret; | |
75b49099 | 100 | |
7bf26383 | 101 | if(!doResolve(qname,QType(QType::A), res,depth+1,beenthere) && !res.empty()) |
728485ca | 102 | ret=res[res.size()-1].content; // last entry, in case of CNAME in between |
75b49099 | 103 | |
728485ca | 104 | return ret; |
75b49099 BH |
105 | } |
106 | ||
7bf26383 BH |
107 | int getCache(const string &qname, const QType& qt, set<DNSResourceRecord>* res=0) |
108 | { | |
109 | cache_t::const_iterator j=cache.find(toLower(qname)+"|"+qt.getName()); | |
110 | if(j!=cache.end() && j->first==toLower(qname)+"|"+qt.getName() && j->second.begin()->ttl>(unsigned int)time(0)) { | |
111 | if(res) | |
112 | *res=j->second; | |
113 | return (unsigned int)j->second.begin()->ttl-time(0); | |
114 | } | |
115 | return -1; | |
116 | } | |
117 | ||
118 | void replaceCache(const string &tuple, const set<DNSResourceRecord>& content) | |
119 | { | |
120 | cache[tuple]=content; | |
121 | } | |
122 | ||
123 | ||
124 | void getBestNSFromCache(const string &qname, set<DNSResourceRecord>&bestns, int depth, set<GetBestNSAnswer>& beenthere) | |
86c152f2 | 125 | { |
20177d1d | 126 | string prefix, subdomain(qname); |
afbe2787 | 127 | prefix.assign(3*depth, ' '); |
75b49099 BH |
128 | bestns.clear(); |
129 | ||
75b49099 BH |
130 | do { |
131 | cout<<prefix<<qname<<": Checking if we have NS in cache for '"<<subdomain<<"'"<<endl; | |
7bf26383 BH |
132 | set<DNSResourceRecord>ns; |
133 | if(getCache(subdomain,QType(QType::NS),&ns)>0) { | |
134 | for(set<DNSResourceRecord>::const_iterator k=ns.begin();k!=ns.end();++k) { | |
135 | if(k->ttl>(unsigned int)time(0)) { | |
136 | set<DNSResourceRecord>aset; | |
137 | if(!endsOn(k->content,subdomain) || getCache(k->content,QType(QType::A),&aset) > 5) { | |
20177d1d | 138 | bestns.insert(*k); |
0d8612f2 BH |
139 | cout<<prefix<<qname<<": NS (with ip, or non-glue) in cache for '"<<subdomain<<"' -> '"<<k->content<<"'"<<endl; |
140 | cout<<prefix<<qname<<": endson: "<<endsOn(k->content,subdomain); | |
7bf26383 BH |
141 | if(!aset.empty()) |
142 | cout<<", in cache, ttl="<<((time_t)aset.begin()->ttl-time(0))<<endl; | |
0d8612f2 BH |
143 | else |
144 | cout<<", not in cache"<<endl; | |
145 | } | |
20177d1d | 146 | else |
7bf26383 | 147 | cout<<prefix<<qname<<": NS in cache for '"<<subdomain<<"', but needs glue ("<<k->content<<") which we miss or is expired"<<endl; |
ac539791 | 148 | } |
afbe2787 | 149 | } |
75b49099 | 150 | if(!bestns.empty()) { |
7bf26383 BH |
151 | GetBestNSAnswer answer; |
152 | answer.qname=toLower(qname); answer.bestns=bestns; | |
153 | if(beenthere.count(answer)) { | |
154 | cout<<prefix<<qname<<": We have NS in cache for '"<<subdomain<<"' but part of LOOP! Trying less specific NS"<<endl; | |
155 | for(set<GetBestNSAnswer>::const_iterator j=beenthere.begin();j!=beenthere.end();++j) | |
156 | cout<<prefix<<qname<<": beenthere: "<<j->qname<<" ("<<j->bestns.size()<<")"<<endl; | |
157 | bestns.clear(); | |
158 | } | |
159 | else { | |
160 | beenthere.insert(answer); | |
161 | cout<<prefix<<qname<<": We have NS in cache for '"<<subdomain<<"'"<<endl; | |
162 | return; | |
163 | } | |
75b49099 | 164 | } |
afbe2787 | 165 | } |
75b49099 BH |
166 | }while(chopOff(subdomain)); |
167 | } | |
168 | ||
169 | void addAuthorityRecords(const string& qname, vector<DNSResourceRecord>& ret, int depth) | |
170 | { | |
171 | set<DNSResourceRecord> bestns; | |
7bf26383 BH |
172 | set<GetBestNSAnswer>beenthere; |
173 | getBestNSFromCache(qname, bestns, depth,beenthere); | |
75b49099 BH |
174 | for(set<DNSResourceRecord>::const_iterator k=bestns.begin();k!=bestns.end();++k) { |
175 | DNSResourceRecord ns=*k; | |
176 | ns.d_place=DNSResourceRecord::AUTHORITY; | |
177 | ns.ttl-=time(0); | |
178 | ret.push_back(ns); | |
179 | } | |
180 | } | |
7bf26383 BH |
181 | /** doesn't actually do the work, leaves that to getBestNSFromCache */ |
182 | string getBestNSNamesFromCache(const string &qname,set<string>& nsset, int depth, set<GetBestNSAnswer>&beenthere) | |
75b49099 BH |
183 | { |
184 | string subdomain(qname); | |
185 | ||
186 | set<DNSResourceRecord> bestns; | |
7bf26383 | 187 | getBestNSFromCache(subdomain, bestns, depth, beenthere); |
75b49099 BH |
188 | |
189 | for(set<DNSResourceRecord>::const_iterator k=bestns.begin();k!=bestns.end();++k) { | |
190 | nsset.insert(k->content); | |
191 | subdomain=k->qname; | |
86c152f2 | 192 | } |
75b49099 | 193 | return subdomain; |
afbe2787 BH |
194 | } |
195 | ||
728485ca | 196 | bool doCNAMECacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res) |
afbe2787 | 197 | { |
75b49099 | 198 | string prefix, tuple=toLower(qname)+"|CNAME"; |
afbe2787 | 199 | prefix.assign(3*depth, ' '); |
afbe2787 | 200 | |
75b49099 | 201 | cout<<prefix<<qname<<": Looking for CNAME cache hit of '"<<tuple<<"'"<<endl; |
7bf26383 BH |
202 | set<DNSResourceRecord> cset; |
203 | if(getCache(qname,QType(QType::CNAME),&cset) > 0) { | |
204 | for(set<DNSResourceRecord>::const_iterator j=cset.begin();j!=cset.end();++j) { | |
75b49099 | 205 | if(j->ttl>(unsigned int)time(0)) { |
7bf26383 | 206 | cout<<prefix<<qname<<": Found cache CNAME hit for '"<<tuple<<"' to '"<<j->content<<"'"<<endl; |
ac539791 BH |
207 | DNSResourceRecord rr=*j; |
208 | rr.ttl-=time(0); | |
209 | ret.push_back(rr); | |
7bf26383 BH |
210 | if(!(qtype==QType(QType::CNAME))) {// perhaps they really wanted a CNAME! |
211 | set<GetBestNSAnswer>beenthere; | |
212 | res=doResolve(j->content, qtype, ret, depth, beenthere); | |
213 | } | |
75b49099 | 214 | return true; |
ac539791 BH |
215 | } |
216 | } | |
afbe2787 | 217 | } |
75b49099 BH |
218 | cout<<prefix<<qname<<": No CNAME cache hit of '"<<tuple<<"' found"<<endl; |
219 | return false; | |
220 | } | |
221 | ||
222 | bool doCacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res) | |
223 | { | |
224 | string prefix, tuple; | |
225 | prefix.assign(3*depth, ' '); | |
afbe2787 BH |
226 | |
227 | tuple=toLower(qname)+"|"+qtype.getName(); | |
75b49099 | 228 | cout<<prefix<<qname<<": Looking for direct cache hit of '"<<tuple<<"'"<<endl; |
afbe2787 | 229 | |
20177d1d BH |
230 | res=0; |
231 | map<string,string>::const_iterator ni=negcache.find(tuple); | |
232 | if(ni!=negcache.end()) { | |
233 | cout<<prefix<<qname<<": is negatively cached, will return immediately if we still have SOA to prove it"<<endl; | |
234 | res=RCode::NXDomain; | |
235 | tuple=ni->second+"|SOA"; | |
236 | } | |
237 | ||
7bf26383 | 238 | set<DNSResourceRecord> cset; |
75b49099 | 239 | bool found=false, expired=false; |
7bf26383 | 240 | if(getCache(qname,qtype,&cset)>0) { |
6e059b95 | 241 | cout<<prefix<<qname<<": Found cache hit for "<<qtype.getName()<<": "; |
7bf26383 | 242 | for(set<DNSResourceRecord>::const_iterator j=cset.begin();j!=cset.end();++j) { |
ac539791 | 243 | cout<<j->content; |
75b49099 | 244 | if(j->ttl>(unsigned int)time(0)) { |
ac539791 BH |
245 | DNSResourceRecord rr=*j; |
246 | rr.ttl-=time(0); | |
20177d1d BH |
247 | if(res==RCode::NXDomain) |
248 | rr.d_place=DNSResourceRecord::AUTHORITY; | |
ac539791 BH |
249 | ret.push_back(rr); |
250 | cout<<"[fresh] "; | |
75b49099 | 251 | found=true; |
ac539791 | 252 | } |
75b49099 | 253 | else { |
ac539791 | 254 | cout<<"[expired] "; |
75b49099 BH |
255 | expired=true; |
256 | } | |
afbe2787 | 257 | } |
ac539791 | 258 | |
afbe2787 | 259 | cout<<endl; |
20177d1d | 260 | if(found && !expired) |
75b49099 | 261 | return true; |
75b49099 | 262 | else |
20177d1d | 263 | cout<<prefix<<qname<<": cache had only stale entries"<<endl; |
afbe2787 | 264 | } |
75b49099 BH |
265 | return false; |
266 | } | |
afbe2787 | 267 | |
728485ca | 268 | inline bool moreSpecificThan(const string& a, const string &b) |
75b49099 | 269 | { |
728485ca | 270 | int counta=!a.empty(), countb=!b.empty(); |
afbe2787 | 271 | |
728485ca BH |
272 | for(string::size_type n=0;n<a.size();++n) |
273 | if(a[n]=='.') | |
274 | counta++; | |
275 | for(string::size_type n=0;n<b.size();++n) | |
276 | if(b[n]=='.') | |
277 | countb++; | |
278 | return counta>countb; | |
afbe2787 BH |
279 | } |
280 | ||
728485ca | 281 | inline vector<string>shuffle(set<string> &nameservers) |
afbe2787 | 282 | { |
728485ca BH |
283 | vector<string> rnameservers; |
284 | for(set<string>::const_iterator i=nameservers.begin();i!=nameservers.end();++i) | |
285 | rnameservers.push_back(*i); | |
286 | ||
287 | random_shuffle(rnameservers.begin(),rnameservers.end()); | |
288 | return rnameservers; | |
afbe2787 BH |
289 | } |
290 | ||
ac539791 | 291 | /** returns -1 in case of no results, rcode otherwise */ |
7bf26383 BH |
292 | int doResolveAt(set<string> nameservers, string auth, const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, |
293 | int depth, set<GetBestNSAnswer>&beenthere) | |
86c152f2 BH |
294 | { |
295 | string prefix; | |
296 | prefix.assign(3*depth, ' '); | |
297 | ||
298 | LWRes r; | |
299 | LWRes::res_t result; | |
86c152f2 | 300 | |
7bf26383 | 301 | cout<<prefix<<qname<<": Cache consultations done, have "<<nameservers.size()<<" NS to contact"<<endl; |
afbe2787 BH |
302 | |
303 | for(;;) { // we may get more specific nameservers | |
75b49099 | 304 | bool aabit=false; |
86c152f2 BH |
305 | result.clear(); |
306 | ||
728485ca | 307 | vector<string>rnameservers=shuffle(nameservers); |
86c152f2 | 308 | |
20177d1d BH |
309 | // what if we don't have an A for an NS anymore, but do have an NS for that NS? |
310 | ||
728485ca BH |
311 | for(vector<string>::const_iterator tns=rnameservers.begin();;++tns) { |
312 | if(tns==rnameservers.end()) { | |
75b49099 | 313 | cout<<prefix<<qname<<": Failed to resolve via any of the "<<rnameservers.size()<<" offered NS"<<endl; |
ac539791 | 314 | return -1; |
afbe2787 | 315 | } |
20177d1d BH |
316 | if(qname==*tns) { |
317 | cout<<prefix<<qname<<": Not using NS to resolve itself!"<<endl; | |
318 | continue; | |
319 | } | |
7bf26383 BH |
320 | cout<<prefix<<qname<<": Trying to resolve NS "<<*tns<<" ("<<1+tns-rnameservers.begin()<<"/"<<rnameservers.size()<<")"<<endl; |
321 | string remoteIP=getA(*tns, depth+1,beenthere); | |
afbe2787 | 322 | if(remoteIP.empty()) { |
728485ca | 323 | cout<<prefix<<qname<<": Failed to get IP for NS "<<*tns<<", trying next if available"<<endl; |
afbe2787 BH |
324 | continue; |
325 | } | |
728485ca | 326 | cout<<prefix<<qname<<": Resolved NS "<<*tns<<" to "<<remoteIP<<", asking '"<<qname<<"|"<<qtype.getName()<<"'"<<endl; |
86c152f2 | 327 | |
ac539791 | 328 | if(r.asyncresolve(remoteIP,qname.c_str(),qtype.getCode())!=1) { // <- we go out on the wire! |
728485ca BH |
329 | cout<<prefix<<qname<<": error resolving (perhaps timeout?)"<<endl; |
330 | continue; | |
afbe2787 | 331 | } |
20177d1d BH |
332 | |
333 | if(r.d_rcode==RCode::ServFail) { | |
334 | cout<<prefix<<qname<<": "<<*tns<<" returned a ServFail, trying sibling NS"<<endl; | |
335 | continue; | |
336 | } | |
728485ca | 337 | result=r.result(aabit); |
20177d1d BH |
338 | cout<<prefix<<qname<<": Got "<<result.size()<<" answers from "<<*tns<<" ("<<remoteIP<<"), rcode="<<r.d_rcode<<endl; |
339 | ||
728485ca BH |
340 | cache_t tcache; |
341 | // reap all answers from this packet that are acceptable | |
342 | for(LWRes::res_t::const_iterator i=result.begin();i!=result.end();++i) { | |
343 | cout<<prefix<<qname<<": accept answer '"<<i->qname<<"|"<<i->qtype.getName()<<"|"<<i->content<<"' from '"<<auth<<"' nameservers? "; | |
344 | cout.flush(); | |
345 | if(endsOn(i->qname, auth)) { | |
346 | cout<<"YES!"<<endl; | |
347 | ||
348 | DNSResourceRecord rr=*i; | |
349 | rr.d_place=DNSResourceRecord::ANSWER; | |
350 | rr.ttl+=time(0); | |
7bf26383 | 351 | // rr.ttl=time(0)+10+10*rr.qtype.getCode(); |
728485ca BH |
352 | tcache[toLower(i->qname)+"|"+i->qtype.getName()].insert(rr); |
353 | } | |
354 | else | |
355 | cout<<"NO!"<<endl; | |
86c152f2 | 356 | } |
728485ca BH |
357 | |
358 | // supplant | |
359 | for(cache_t::const_iterator i=tcache.begin();i!=tcache.end();++i) | |
7bf26383 | 360 | replaceCache(i->first,i->second); |
728485ca BH |
361 | |
362 | set<string> nsset; | |
363 | cout<<prefix<<qname<<": determining status after receiving this packet"<<endl; | |
364 | ||
20177d1d | 365 | bool done=false, realreferral=false, negindic=false; |
728485ca BH |
366 | string newauth; |
367 | ||
368 | for(LWRes::res_t::const_iterator i=result.begin();i!=result.end();++i) { | |
369 | if(i->d_place==DNSResourceRecord::AUTHORITY && endsOn(qname,i->qname) && i->qtype.getCode()==QType::SOA) { | |
370 | cout<<prefix<<qname<<": got negative caching indication"<<endl; | |
371 | ret.push_back(*i); | |
20177d1d BH |
372 | negcache[toLower(qname)+"|"+qtype.getName()]=i->qname; |
373 | negindic=true; | |
728485ca BH |
374 | } |
375 | else if(i->d_place==DNSResourceRecord::ANSWER && i->qname==qname && i->qtype.getCode()==QType::CNAME && (!(qtype==QType(QType::CNAME)))) { | |
376 | cout<<prefix<<qname<<": got a CNAME referral, starting over with "<<i->content<<endl<<endl; | |
377 | ret.push_back(*i); | |
7bf26383 BH |
378 | set<GetBestNSAnswer>beenthere2; |
379 | return doResolve(i->content, qtype, ret,0,beenthere2); | |
728485ca BH |
380 | } |
381 | // for ANY answers we *must* have an authoritive answer | |
382 | else if(i->d_place==DNSResourceRecord::ANSWER && i->qname==qname && (i->qtype==qtype || ( qtype==QType(QType::ANY) && aabit))) { | |
383 | cout<<prefix<<qname<<": answer is in: resolved to '"<<i->content<<"|"<<i->qtype.getName()<<"'"<<endl; | |
384 | done=true; | |
385 | ret.push_back(*i); | |
386 | } | |
387 | else if(i->d_place==DNSResourceRecord::AUTHORITY && endsOn(qname,i->qname) && i->qtype.getCode()==QType::NS) { | |
388 | if(moreSpecificThan(i->qname,auth)) { | |
389 | newauth=i->qname; | |
390 | cout<<prefix<<qname<<": got NS record '"<<i->qname<<"' -> '"<<i->content<<"'"<<endl; | |
391 | realreferral=true; | |
392 | } | |
7bf26383 BH |
393 | else |
394 | cout<<prefix<<qname<<": got upwards/level NS record '"<<i->qname<<"' -> '"<<i->content<<"', had '"<<auth<<"'"<<endl; | |
728485ca BH |
395 | nsset.insert(toLower(i->content)); |
396 | } | |
86c152f2 | 397 | } |
86c152f2 | 398 | |
728485ca BH |
399 | if(done){ |
400 | cout<<prefix<<qname<<": status=got results, this level of recursion done"<<endl; | |
401 | return 0; | |
ac539791 | 402 | } |
728485ca | 403 | if(r.d_rcode==RCode::NXDomain) { |
20177d1d | 404 | cout<<prefix<<qname<<": status=NXDOMAIN, we are done "<<(negindic ? "(have negative SOA)" : "")<<endl; |
728485ca | 405 | return RCode::NXDomain; |
86c152f2 | 406 | } |
728485ca | 407 | if(nsset.empty() && !r.d_rcode) { |
20177d1d | 408 | cout<<prefix<<qname<<": status=noerror, other types may exist, but we are done "<<(negindic ? "(have negative SOA)" : "")<<endl; |
728485ca | 409 | return 0; |
86c152f2 | 410 | } |
728485ca BH |
411 | else if(realreferral) { |
412 | cout<<prefix<<qname<<": status=did not resolve, got "<<nsset.size()<<" NS, looping to them"<<endl; | |
413 | auth=newauth; | |
414 | nameservers=nsset; | |
415 | break; | |
416 | } | |
417 | else { | |
7bf26383 | 418 | cout<<prefix<<qname<<": status=NS "<<*tns<<" is lame for '"<<auth<<"', trying sibling NS"<<endl; |
86c152f2 BH |
419 | } |
420 | } | |
86c152f2 | 421 | } |
ac539791 | 422 | return -1; |
86c152f2 BH |
423 | } |
424 | ||
728485ca BH |
425 | void addCruft(const string &qname, vector<DNSResourceRecord>& ret) |
426 | { | |
427 | for(vector<DNSResourceRecord>::const_iterator k=ret.begin();k!=ret.end();++k) // don't add stuff to an NXDOMAIN! | |
428 | if(k->d_place==DNSResourceRecord::AUTHORITY && k->qtype==QType(QType::SOA)) | |
429 | return; | |
430 | ||
431 | cout<<qname<<": Adding best authority records from cache"<<endl; | |
432 | addAuthorityRecords(qname,ret,0); | |
433 | cout<<qname<<": Done adding best authority records."<<endl; | |
434 | ||
435 | cout<<qname<<": Starting additional processing"<<endl; | |
436 | vector<DNSResourceRecord> addit; | |
437 | for(vector<DNSResourceRecord>::const_iterator k=ret.begin();k!=ret.end();++k) | |
438 | if((k->d_place==DNSResourceRecord::ANSWER && k->qtype==QType(QType::MX)) || | |
439 | (k->d_place==DNSResourceRecord::AUTHORITY && k->qtype==QType(QType::NS))) { | |
440 | cout<<qname<<": record '"<<k->content<<"|"<<k->qtype.getName()<<"' needs an IP address"<<endl; | |
7bf26383 BH |
441 | set<GetBestNSAnswer>beenthere; |
442 | doResolve(k->content,QType(QType::A),addit,1,beenthere); | |
728485ca BH |
443 | } |
444 | ||
445 | for(vector<DNSResourceRecord>::iterator k=addit.begin();k!=addit.end();++k) { | |
446 | k->d_place=DNSResourceRecord::ADDITIONAL; | |
447 | ret.push_back(*k); | |
448 | } | |
449 | cout<<qname<<": Done with additional processing"<<endl; | |
450 | } | |
451 | ||
86c152f2 BH |
452 | void init(void) |
453 | { | |
454 | // prime root cache | |
728485ca BH |
455 | static char*ips[]={"198.41.0.4", "128.9.0.107", "192.33.4.12", "128.8.10.90", "192.203.230.10", "192.5.5.241", "192.112.36.4", "128.63.2.53", |
456 | "192.36.148.17","198.41.0.10", "193.0.14.129", "198.32.64.12", "202.12.27.33"}; | |
ac539791 BH |
457 | DNSResourceRecord arr, nsrr; |
458 | arr.qtype=QType::A; | |
459 | arr.ttl=time(0)+86400; | |
ac539791 BH |
460 | nsrr.qtype=QType::NS; |
461 | nsrr.ttl=time(0)+86400; | |
ac539791 | 462 | |
86c152f2 BH |
463 | for(char c='a';c<='m';++c) { |
464 | static char templ[40]; | |
465 | strncpy(templ,"a.root-servers.net", sizeof(templ) - 1); | |
466 | *templ=c; | |
728485ca | 467 | arr.qname=nsrr.content=templ; |
ac539791 BH |
468 | arr.content=ips[c-'a']; |
469 | cache[string(templ)+"|A"].insert(arr); | |
ac539791 | 470 | cache["|NS"].insert(nsrr); |
86c152f2 BH |
471 | } |
472 | } |