| 37 | | map<string,string> hints; |
| 38 | | |
| 39 | | string doResolve(vector<string> nameservers, const string &qname, int depth=0); |
| 40 | | |
| 41 | | string doResolve(const string &qname, int depth=0) |
| 42 | | { |
| 43 | | if(hints.find(toLower(qname))!=hints.end()) { |
| 44 | | string prefix; |
| 45 | | prefix.assign(3*depth, ' '); |
| 46 | | |
| 47 | | cerr<<prefix<<qname<<": resolved via hint cache to "<<hints[toLower(qname)]<<endl; |
| 48 | | return hints[toLower(qname)]; |
| 49 | | } |
| 50 | | |
| 51 | | return doResolve(rootservers, qname,depth); |
| 52 | | } |
| 53 | | |
| 54 | | string doResolve(vector<string> nameservers, const string &qname, int depth) |
| | 40 | |
| | 41 | |
| | 42 | bool doResolve(set<string> nameservers, string auth, const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret,int depth=0); |
| | 43 | bool doResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth=0); |
| | 44 | |
| | 45 | string 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 | |
| | 56 | void getBestNSFromCache(const string &qname, vector<DNSResourceRecord>&ret, int depth=0) |
| | 57 | { |
| | 58 | string prefix; |
| | 59 | prefix.assign(3*depth, ' '); |
| | 60 | |
| | 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 | } |
| | 94 | } |
| | 95 | } |
| | 96 | |
| | 97 | |
| | 98 | |
| | 99 | void 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 | |
| | 112 | |
| | 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 | |
| | 119 | bool 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; |
| | 125 | } |
| | 126 | |
| | 127 | |
| | 128 | bool 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 | |
| | 195 | bool 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 | |
| | 204 | bool doResolve(set<string> nameservers, string auth, const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth) |
| 68 | | for(cache_t::const_iterator i=cache.find(qname);i!=cache.end() && i->first==qname;++i) { |
| 69 | | cerr<<prefix<<qname<<": potential cache hit!"<<endl; |
| 70 | | |
| 71 | | sort(nameservers.begin(),nameservers.end()); |
| 72 | | if(nameservers==i->second.first) { |
| 73 | | cerr<<prefix<<qname<<": REAL cache hit, "<<i->second.second.size()<<" records"<<endl; |
| 74 | | result=i->second.second; |
| 75 | | |
| | 219 | vector<string>rnameservers; |
| | 220 | for(set<string>::const_iterator i=nameservers.begin();i!=nameservers.end();++i) |
| | 221 | rnameservers.push_back(*i); |
| | 222 | |
| | 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; |
| | 236 | |
| | 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; |
| 79 | | if(result.empty()) { |
| 80 | | |
| 81 | | cerr<<prefix<<qname<<": no cache hit"<<endl; |
| 82 | | |
| 83 | | random_shuffle(nameservers.begin(),nameservers.end()); |
| 84 | | for(vector<string>::const_iterator i=nameservers.begin();;++i){ |
| 85 | | if(i==nameservers.end()) { |
| 86 | | cerr<<prefix<<qname<<": failed to resolve via any of the "<<nameservers.size()<<" offered nameservers"<<endl; |
| 87 | | return ""; |
| 88 | | } |
| 89 | | cerr<<prefix<<qname<<": trying to resolve nameserver "<<*i<<endl; |
| 90 | | string remoteIP=doResolve(*i,depth+1); |
| 91 | | if(remoteIP.empty()) { |
| 92 | | cerr<<prefix<<qname<<": failed to resolve nameserver "<<*i<<", trying next if available"<<endl; |
| 93 | | continue; |
| 94 | | } |
| 95 | | cerr<<prefix<<qname<<": resolved nameserver "<<*i<<" to "<<remoteIP<<endl; |
| 96 | | |
| 97 | | if(r.asyncresolve(remoteIP,qname.c_str(),QType::A)!=1) { |
| 98 | | cerr<<prefix<<qname<<": error resolving"<<endl; |
| 99 | | } |
| 100 | | else { |
| 101 | | result=r.result(); |
| 102 | | |
| 103 | | cerr<<prefix<<qname<<": got "<<result.size()<<" answers from "<<*i<<" ("<<remoteIP<<")"<<endl; |
| 104 | | break; |
| 105 | | } |
| 106 | | } |
| 107 | | usefulrrs.clear(); |
| 108 | | for(LWRes::res_t::const_iterator i=result.begin();i!=result.end();++i) |
| 109 | | if(i->d_place==DNSResourceRecord::ANSWER || (i->d_place==DNSResourceRecord::AUTHORITY && i->qtype.getCode()==QType::NS)) |
| 110 | | usefulrrs.push_back(*i); |
| | 247 | |
| | 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); |
| | 261 | } |
| | 262 | else |
| | 263 | cout<<"NO!"<<endl; |
| | 264 | |
| | 265 | } |
| | 266 | |
| | 267 | for(cache_t::const_iterator i=tcache.begin();i!=tcache.end();++i) |
| | 268 | cache[i->first]=i->second; |
| | 269 | |
| | 270 | nsset.clear(); |
| | 271 | |
| | 272 | for(LWRes::res_t::const_iterator i=result.begin();i!=result.end();++i) { |