]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/syncres.cc
recursorrr
[thirdparty/pdns.git] / pdns / syncres.cc
CommitLineData
86c152f2
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2002 PowerDNS.COM BV
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
24#include <cerrno>
25#include <cstdio>
26#include <cstdlib>
27
28#include <utility>
29#include "statbag.hh"
30#include "arguments.hh"
31#include "lwres.hh"
32
afbe2787
BH
33typedef map<string, set<string> > nscache_t;
34nscache_t nscache;
35
36typedef map<string,vector<DNSResourceRecord> > cache_t;
86c152f2
BH
37cache_t cache;
38
39vector<string>rootservers;
86c152f2 40
86c152f2 41
afbe2787
BH
42bool doResolve(set<string> nameservers, string auth, const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret,int depth=0);
43bool doResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth=0);
44
45string getA(const string &qname, int depth=0)
46{
47 vector<DNSResourceRecord> res;
48 string ret;
49
50 if(doResolve(qname,QType(QType::A), res,depth+1))
51 ret=res[0].content;
52
53 return ret;
54}
55
56void getBestNSFromCache(const string &qname, vector<DNSResourceRecord>&ret, int depth=0)
86c152f2 57{
afbe2787
BH
58 string prefix;
59 prefix.assign(3*depth, ' ');
86c152f2 60
afbe2787
BH
61 vector<string>parts;
62 stringtok(parts,qname,"."); // www.us.powerdns.com -> 'www' 'us' 'powerdns' 'com'
63
64 unsigned int spos=0;
65 string subdomain;
66
67 while(spos<=parts.size()) {
68 if(spos<parts.size()) { // www.us.powerdns.com -> us.powerdns.com -> powerdns.com -> com ->
69 subdomain=parts[spos++];
70 for(unsigned int i=spos;i<parts.size();++i) {
71 subdomain+=".";
72 subdomain+=parts[i];
73 }
74 }
75 else {
76 subdomain=""; // ROOT!
77 spos++;
78 }
79 cout<<prefix<<qname<<": Checking if we have NS for '"<<subdomain<<"'"<<endl;
80 nscache_t::const_iterator j=nscache.find(toLower(subdomain));
81 if(j!=nscache.end() && j->first==toLower(subdomain)) {
82 cout<<prefix<<qname<<": Adding authority records for '"<<subdomain<<"'"<<endl;
83 for(set<string>::const_iterator k=j->second.begin();k!=j->second.end();++k) {
84 DNSResourceRecord rr;
85 rr.qname=subdomain;
86 rr.content=*k;
87 rr.ttl=1234;
88 rr.qtype=QType(QType::NS);
89 rr.d_place=DNSResourceRecord::AUTHORITY;
90 ret.push_back(rr);
91 }
92 return;
93 }
86c152f2 94 }
afbe2787
BH
95}
96
97
98
99void addCruft(const string &qname, vector<DNSResourceRecord>& ret)
100{
101 getBestNSFromCache(qname,ret);
102
103 cout<<qname<<": Additional processing"<<endl;
104 vector<DNSResourceRecord> addit;
105 for(vector<DNSResourceRecord>::const_iterator k=ret.begin();k!=ret.end();++k)
106 if((k->d_place==DNSResourceRecord::ANSWER && k->qtype==QType(QType::MX)) ||
107 (k->d_place==DNSResourceRecord::AUTHORITY && k->qtype==QType(QType::NS))) {
108 cout<<qname<<": record '"<<k->content<<"|"<<k->qtype.getCode()<<"' needs an IP address"<<endl;
109 doResolve(k->content,QType(QType::A),addit,1);
110 }
111
86c152f2 112
afbe2787
BH
113 for(vector<DNSResourceRecord>::iterator k=addit.begin();k!=addit.end();++k) {
114 k->d_place=DNSResourceRecord::ADDITIONAL;
115 ret.push_back(*k);
116 }
117}
118
119bool beginResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret)
120{
121 bool res=doResolve(qname, qtype, ret,0);
122 if(res)
123 addCruft(qname, ret);
124 return res;
86c152f2
BH
125}
126
afbe2787
BH
127
128bool doResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth)
129{
130 string prefix;
131 prefix.assign(3*depth, ' ');
132
133 // see if we have a CNAME hit
134 string tuple=toLower(qname)+"|CNAME";
135 cout<<prefix<<"Looking for CNAME cache hit of '"<<tuple<<"'"<<endl;
136
137 cache_t::const_iterator i=cache.find(tuple);
138 if(i!=cache.end() && i->first==tuple) { // found it
139 cout<<prefix<<"Found cache CNAME hit for '"<<tuple<<"' to '"<<i->second.begin()->content<<"'"<<endl;
140 for(vector<DNSResourceRecord>::const_iterator j=i->second.begin();j!=i->second.end();++j)
141 ret.push_back(*j);
142 return doResolve(i->second.begin()->content, qtype, ret, depth);
143 }
144
145 tuple=toLower(qname)+"|"+qtype.getName();
146 cout<<prefix<<"Looking for direct cache hit of '"<<tuple<<"'"<<endl;
147
148 i=cache.find(tuple);
149 if(i!=cache.end() && i->first==tuple) { // found it
150 cout<<prefix<<"Found cache hit for '"<<tuple<<"': ";
151 for(vector<DNSResourceRecord>::const_iterator j=i->second.begin();j!=i->second.end();++j) {
152 cout<<j->content<<" ";
153 ret.push_back(*j);
154 }
155 cout<<endl;
156 return true;
157 }
158
159
160 cout<<prefix<<"No cache hit for '"<<tuple<<"', trying to find an appropriate NS record"<<endl;
161 // bummer, get the best NS record then
162
163 vector<string>parts;
164 stringtok(parts,qname,"."); // www.us.powerdns.com -> 'www' 'us' 'powerdns' 'com'
165
166 unsigned int spos=0;
167 string subdomain;
168
169 while(spos<=parts.size()) {
170 if(spos<parts.size()) { // www.us.powerdns.com -> us.powerdns.com -> powerdns.com -> com ->
171 subdomain=parts[spos++];
172 for(unsigned int i=spos;i<parts.size();++i) {
173 subdomain+=".";
174 subdomain+=parts[i];
175 }
176 }
177 else {
178 subdomain=""; // ROOT!
179 spos++;
180 }
181 cout<<prefix<<qname<<": Checking if we have NS for '"<<subdomain<<"'"<<endl;
182 nscache_t::const_iterator j=nscache.find(toLower(subdomain));
183 if(j!=nscache.end() && j->first==toLower(subdomain)) {
184 cout<<prefix<<"Found NS for '"<<subdomain<<"', heading there for further questions"<<endl;
185 bool hasResults=doResolve(j->second,subdomain,qname,qtype,ret,depth);
186 if(!hasResults)
187 continue; // perhaps less specific nameservers can help us
188
189 return true;
190 }
191 }
192 return false;
193}
194
195bool endsOn(const string &domain, const string &suffix)
196{
197 if(domain==suffix || suffix.empty())
198 return true;
199 if(domain.size()<suffix.size())
200 return false;
201 return (domain.substr(domain.size()-suffix.size()-1,suffix.size()+1)=="."+suffix);
202}
203
204bool doResolve(set<string> nameservers, string auth, const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth)
86c152f2
BH
205{
206 string prefix;
207 prefix.assign(3*depth, ' ');
208
209 LWRes r;
210 LWRes::res_t result;
211 vector<DNSResourceRecord>usefulrrs;
afbe2787
BH
212 set<string> nsset;
213 cout<<prefix<<qname<<": start of recursion!"<<endl;
86c152f2 214
afbe2787
BH
215
216 for(;;) { // we may get more specific nameservers
86c152f2
BH
217 result.clear();
218
afbe2787
BH
219 vector<string>rnameservers;
220 for(set<string>::const_iterator i=nameservers.begin();i!=nameservers.end();++i)
221 rnameservers.push_back(*i);
86c152f2 222
afbe2787
BH
223 random_shuffle(rnameservers.begin(),rnameservers.end());
224 for(vector<string>::const_iterator i=rnameservers.begin();;++i){
225 if(i==rnameservers.end()) {
226 cout<<prefix<<qname<<": failed to resolve via any of the "<<rnameservers.size()<<" offered nameservers"<<endl;
227 return false;
228 }
229 cout<<prefix<<qname<<": trying to resolve nameserver "<<*i<<endl;
230 string remoteIP=getA(*i, depth+1);
231 if(remoteIP.empty()) {
232 cout<<prefix<<qname<<": failed to resolve nameserver "<<*i<<", trying next if available"<<endl;
233 continue;
234 }
235 cout<<prefix<<qname<<": resolved nameserver "<<*i<<" to "<<remoteIP<<endl;
86c152f2 236
afbe2787
BH
237 if(r.asyncresolve(remoteIP,qname.c_str(),qtype.getCode())!=1) { // <- shouldn't this be internal?
238 cout<<prefix<<qname<<": error resolving"<<endl;
239 }
240 else {
241 result=r.result();
242
243 cout<<prefix<<qname<<": got "<<result.size()<<" answers from "<<*i<<" ("<<remoteIP<<")"<<endl;
86c152f2
BH
244 break;
245 }
246 }
86c152f2 247
afbe2787
BH
248
249 cache_t tcache;
250 // reap all answers from this packet that are acceptable
251 for(LWRes::res_t::const_iterator i=result.begin();i!=result.end();++i) {
252 cout<<prefix<<qname<<": accept answer '"<<i->qname<<"|"<<i->qtype.getName()<<"|"<<i->content<<"' from '"<<auth<<"' nameservers? ";
253 if(endsOn(i->qname, auth)) {
254 cout<<"YES!"<<endl;
255
256 if(i->qtype.getCode()==QType::NS)
257 nscache[toLower(i->qname)].insert(toLower(i->content));
258 DNSResourceRecord rr=*i;
259 rr.d_place=DNSResourceRecord::ANSWER;
260 tcache[toLower(i->qname)+"|"+i->qtype.getName()].push_back(rr);
86c152f2 261 }
afbe2787
BH
262 else
263 cout<<"NO!"<<endl;
86c152f2 264
afbe2787
BH
265 }
266
267 for(cache_t::const_iterator i=tcache.begin();i!=tcache.end();++i)
268 cache[i->first]=i->second;
269
86c152f2 270 nsset.clear();
afbe2787 271
86c152f2 272 for(LWRes::res_t::const_iterator i=result.begin();i!=result.end();++i) {
afbe2787 273
86c152f2 274 if(i->d_place==DNSResourceRecord::ANSWER && i->qname==qname && i->qtype.getCode()==QType::CNAME) {
afbe2787
BH
275 cout<<prefix<<qname<<": got a CNAME referral, starting over with "<<i->content<<endl<<endl;
276 ret.push_back(*i);
277 return doResolve(i->content, qtype, ret,0);
86c152f2 278 }
afbe2787
BH
279 if(i->d_place==DNSResourceRecord::ANSWER && i->qname==qname && i->qtype==qtype) {
280 cout<<prefix<<qname<<": resolved to "<<i->content<<endl;
281 ret.push_back(*i);
86c152f2 282 }
afbe2787
BH
283 if(i->d_place==DNSResourceRecord::AUTHORITY && i->qtype.getCode()==QType::NS) { // XXX FIXME check if suffix!
284 auth=i->qname;
285 cout<<prefix<<qname<<": got NS record "<<i->content<<endl;
286 nsset.insert(toLower(i->content));
86c152f2
BH
287 }
288 }
afbe2787
BH
289 if(!ret.empty()){
290 cout<<prefix<<qname<<": got results, returning"<<endl;
291 return true;
292 }
86c152f2 293 if(nsset.empty()) {
afbe2787
BH
294 cout<<prefix<<qname<<": did not resolve "<<qname<<", did not get referral"<<endl;
295 return false;
86c152f2 296 }
afbe2787
BH
297
298 cout<<prefix<<qname<<": did not resolve "<<qname<<", did get "<<nsset.size()<<" nameservers, looping to them"<<endl;
86c152f2
BH
299 nameservers=nsset;
300 }
afbe2787 301 return false;
86c152f2
BH
302}
303
304void init(void)
305{
306 // prime root cache
307 static char*ips[]={"198.41.0.4", "128.9.0.107", "192.33.4.12", "128.8.10.90", "192.203.230.10",
308 "192.5.5.241", "192.112.36.4", "128.63.2.53", "192.36.148.17",
309 "198.41.0.10", "193.0.14.129", "198.32.64.12", "202.12.27.33"};
afbe2787
BH
310 DNSResourceRecord rr;
311 rr.qtype=QType::A;
312 rr.ttl=86400;
86c152f2
BH
313 for(char c='a';c<='m';++c) {
314 static char templ[40];
315 strncpy(templ,"a.root-servers.net", sizeof(templ) - 1);
316 *templ=c;
afbe2787
BH
317 nscache[""].insert(string(templ));
318 rr.qname=templ;
319 rr.content=ips[c-'a'];
320 cache[string(templ)+"|A"].push_back(rr);
86c152f2
BH
321 }
322}