]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
strip EDNS ping support, add detection of CD and DNSSEC-OK queries, harvest signature...
authorbert hubert <bert.hubert@netherlabs.nl>
Thu, 28 May 2015 21:21:11 +0000 (23:21 +0200)
committerbert hubert <bert.hubert@netherlabs.nl>
Thu, 28 May 2015 21:21:11 +0000 (23:21 +0200)
pdns/lwres.cc
pdns/lwres.hh
pdns/pdns_recursor.cc
pdns/recursor_cache.cc
pdns/recursor_cache.hh
pdns/reczones.cc
pdns/syncres.cc
pdns/syncres.hh

index fe4eb9dea4b72de3c9a8492d62cc492f2f5c14e2..7741cef360301b781f9329745c7b0219f1ccb2d3 100644 (file)
@@ -68,18 +68,11 @@ int asyncresolve(const ComboAddress& ip, const string& domain, int type, bool do
 
   if(EDNS0Level && !doTCP) {
     DNSPacketWriter::optvect_t opts;
-    if(EDNS0Level > 1) {
-      uint32_t nonce=dns_random(0xffffffff);
-      ping.assign((char*) &nonce, 4);
 
-      opts.push_back(make_pair(5, ping));
-    }
-
-    pw.addOpt(1200, 0, 0, opts); // 1200 bytes answer size
+    pw.addOpt(1200, 0, EDNSOpts::DNSSECOK, opts); // 1200 bytes answer size
     pw.commit();
   }
   lwr->d_rcode = 0;
-  lwr->d_pingCorrect = false;
   lwr->d_haveEDNS = false;
   int ret;
 
@@ -177,28 +170,12 @@ int asyncresolve(const ComboAddress& ip, const string& domain, int type, bool do
       goto out;
     }
 
-    for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {          
-      DNSResourceRecord rr;
-      rr.qtype=i->first.d_type;
-      rr.qname=i->first.d_label;
-      rr.ttl=i->first.d_ttl;
-      rr.content=i->first.d_content->getZoneRepresentation();  // this should be the serialised form
-      rr.d_place=(DNSResourceRecord::Place) i->first.d_place;
-      lwr->d_result.push_back(rr);
-    }
+    lwr->d_records = mdp.d_answers;
+    
 
     EDNSOpts edo;
-    if(EDNS0Level > 1 && getEDNSOpts(mdp, &edo)) {
+    if(EDNS0Level > 0 && getEDNSOpts(mdp, &edo)) {
       lwr->d_haveEDNS = true;
-      for(vector<pair<uint16_t, string> >::const_iterator iter = edo.d_options.begin();
-          iter != edo.d_options.end(); 
-          ++iter) {
-        if(iter->first == 5 || iter->first == 4) {// 'EDNS PING'
-          if(iter->second == ping)  {
-            lwr->d_pingCorrect = true;
-          }
-        }
-      }
     }
         
     return 1;
@@ -223,4 +200,18 @@ int asyncresolve(const ComboAddress& ip, const string& domain, int type, bool do
   return -1;
 }
 
-
+vector<DNSResourceRecord>& LWResult::getResult()
+{
+  if(d_result.empty()) {
+    for(auto i=d_records.begin(); i != d_records.end(); ++i) {          
+      DNSResourceRecord rr;
+      rr.qtype=i->first.d_type;
+      rr.qname=i->first.d_label;
+      rr.ttl=i->first.d_ttl;
+      rr.content=i->first.d_content->getZoneRepresentation();  // this should be the serialised form
+      rr.d_place=(DNSResourceRecord::Place) i->first.d_place;
+      d_result.push_back(rr);
+    }
+  }
+  return d_result;
+}
index 0d43249c8f8051dee5f7badd0a657a89d73639ce..23edb17c30b6516edab3897abca766b4e5d01b0d 100644 (file)
@@ -34,6 +34,7 @@
 #include <fcntl.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include "dnsparser.hh"
 #include <arpa/inet.h>
 #undef res_mkquery
 
@@ -58,13 +59,15 @@ class LWResult
 public:
   LWResult() : d_usec(0) {}
   typedef vector<DNSResourceRecord> res_t;
+  res_t& getResult();
 
-  vector<DNSResourceRecord> d_result;
+  vector<pair<DNSRecord, uint16_t>> d_records;
   int d_rcode;
   bool d_aabit, d_tcbit;
   uint32_t d_usec;
-  bool d_pingCorrect;
   bool d_haveEDNS;
+
+  vector<DNSResourceRecord> d_result;
 };
 
 int asyncresolve(const ComboAddress& ip, const string& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, LWResult* res);
index 7ae2b4080123a0b6a2bc40f124451c875147f70a..3bfd0b3290fa9d16a4b9b7c09727b91a6deb5f60 100644 (file)
@@ -555,6 +555,7 @@ void startDoResolve(void *p)
     pw.getHeader()->tc=0;
     pw.getHeader()->id=dc->d_mdp.d_header.id;
     pw.getHeader()->rd=dc->d_mdp.d_header.rd;
+    pw.getHeader()->cd=dc->d_mdp.d_header.cd;
 
     uint32_t minTTL=std::numeric_limits<uint32_t>::max();
 
@@ -563,6 +564,10 @@ void startDoResolve(void *p)
       sr.setLuaEngine(*t_pdl);
       sr.d_requestor=dc->d_remote;
     }
+    
+    if(pw.getHeader()->cd || edo.d_Z & EDNSOpts::DNSSECOK)
+      sr.d_doDNSSEC=true;
+
     bool tracedQuery=false; // we could consider letting Lua know about this too
     bool variableAnswer = false;
 
@@ -1987,12 +1992,6 @@ int serviceMain(int argc, char*argv[])
     exit(99);
   }
 
-  SyncRes::s_noEDNSPing = true; // ::arg().mustDo("disable-edns-ping");
-  SyncRes::s_noEDNS = ::arg().mustDo("disable-edns");
-  if(!SyncRes::s_noEDNS) {
-    L<<Logger::Warning<<"Running in experimental EDNS mode - may cause problems"<<endl;
-  }
-
   SyncRes::s_nopacketcache = ::arg().mustDo("disable-packetcache");
 
   SyncRes::s_maxnegttl=::arg().asNum("max-negative-ttl");
index c2b2c778d6e3d766622945b56a906d18b9f986b7..37a1bceaa5d2f80b1506c992df8af912b2144c89 100644 (file)
@@ -107,7 +107,7 @@ unsigned int MemRecursorCache::bytes()
   return ret;
 }
 
-int MemRecursorCache::get(time_t now, const string &qname, const QType& qt, set<DNSResourceRecord>* res)
+int MemRecursorCache::get(time_t now, const string &qname, const QType& qt, set<DNSResourceRecord>* res, vector<std::shared_ptr<RRSIGRecordContent>>* signatures)
 {
   unsigned int ttd=0;
   //  cerr<<"looking up "<< qname+"|"+qt.getName()<<"\n";
@@ -137,6 +137,8 @@ int MemRecursorCache::get(time_t now, const string &qname, const QType& qt, set<
             }
           }
         }
+       if(signatures)  // if you do an ANY lookup you are hosed XXXX
+         *signatures=i->d_signatures;
         if(res) {
           if(res->empty())
             moveCacheItemToFront(d_cache, i);
@@ -186,7 +188,7 @@ bool MemRecursorCache::attemptToRefreshNSTTL(const QType& qt, const set<DNSResou
 /* the code below is rather tricky - it basically replaces the stuff cached for qname by content, but it is special
    cased for when inserting identical records with only differing ttls, in which case the entry is not
    touched, but only given a new ttd */
-void MemRecursorCache::replace(time_t now, const string &qname, const QType& qt,  const set<DNSResourceRecord>& content, bool auth)
+void MemRecursorCache::replace(time_t now, const string &qname, const QType& qt,  const set<DNSResourceRecord>& content, const vector<shared_ptr<RRSIGRecordContent>>& signatures, bool auth)
 {
   d_cachecachevalid=false;
   boost::tuple<string, uint16_t> key=boost::make_tuple(qname, qt.getCode());
@@ -202,7 +204,7 @@ void MemRecursorCache::replace(time_t now, const string &qname, const QType& qt,
 
   StoredRecord dr;
   CacheEntry ce=*stored;
-
+  ce.d_signatures=signatures;
   //~ cerr<<"asked to store "<< qname+"|"+qt.getName()<<" -> '"<<content.begin()->content<<"', isnew="<<isNew<<", auth="<<auth<<", ce.auth="<<ce.d_auth<<"\n";
 
   if(qt.getCode()==QType::SOA || qt.getCode()==QType::CNAME)  { // you can only have one (1) each of these
index d8ce136d71b4f36d33dabe227053872fa86621cb..de92b702dcba2333712916fa18e20fdd60654225 100644 (file)
@@ -6,7 +6,7 @@
 #include "qtype.hh"
 #include "misc.hh"
 #include <iostream>
-
+#include "dnsrecords.hh"
 #include <boost/utility.hpp>
 #undef L
 #include <boost/multi_index_container.hpp>
@@ -31,10 +31,10 @@ public:
   }
   unsigned int size();
   unsigned int bytes();
-  int get(time_t, const string &qname, const QType& qt, set<DNSResourceRecord>* res);
+  int get(time_t, const string &qname, const QType& qt, set<DNSResourceRecord>* res, vector<std::shared_ptr<RRSIGRecordContent>>* signatures=0);
 
   int getDirect(time_t now, const char* qname, const QType& qt, uint32_t ttd[10], char* data[10], uint16_t len[10]);
-  void replace(time_t, const string &qname, const QType& qt,  const set<DNSResourceRecord>& content, bool auth);
+  void replace(time_t, const string &qname, const QType& qt,  const set<DNSResourceRecord>& content, const vector<std::shared_ptr<RRSIGRecordContent>>& signatures, bool auth);
   void doPrune(void);
   void doSlash(int perc);
   uint64_t doDump(int fd);
@@ -48,7 +48,6 @@ private:
   struct StoredRecord
   {
     mutable uint32_t d_ttd;
-
     string d_string;
 
     bool operator<(const StoredRecord& rhs) const
@@ -70,7 +69,7 @@ private:
     {}
 
     typedef vector<StoredRecord> records_t;
-
+    vector<std::shared_ptr<RRSIGRecordContent>> d_signatures;
     uint32_t getTTD() const
     {
       if(d_records.size()==1)
index a6e3291449e52b5e8d36b8561176d0d0b92860da..b38ea35f131797dc1b76e4da157026bd1f3159e8 100644 (file)
@@ -64,13 +64,13 @@ void primeHints(void)
       arr.content=ips[c-'a'];
       set<DNSResourceRecord> aset;
       aset.insert(arr);
-      t_RC->replace(time(0), string(templ), QType(QType::A), aset, true); // auth, nuke it all
+      t_RC->replace(time(0), string(templ), QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), true); // auth, nuke it all
       if (ip6s[c-'a'] != NULL) {
         aaaarr.content=ip6s[c-'a'];
 
         set<DNSResourceRecord> aaaaset;
         aaaaset.insert(aaaarr);
-        t_RC->replace(time(0), string(templ), QType(QType::AAAA), aaaaset, true);
+        t_RC->replace(time(0), string(templ), QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), true);
       }
       
       nsset.insert(nsrr);
@@ -85,18 +85,18 @@ void primeHints(void)
       if(rr.qtype.getCode()==QType::A) {
         set<DNSResourceRecord> aset;
         aset.insert(rr);
-        t_RC->replace(time(0), rr.qname, QType(QType::A), aset, true); // auth, etc see above
+        t_RC->replace(time(0), rr.qname, QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), true); // auth, etc see above
       } else if(rr.qtype.getCode()==QType::AAAA) {
         set<DNSResourceRecord> aaaaset;
         aaaaset.insert(rr);
-        t_RC->replace(time(0), rr.qname, QType(QType::AAAA), aaaaset, true);
+        t_RC->replace(time(0), rr.qname, QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), true);
       } else if(rr.qtype.getCode()==QType::NS) {
         rr.content=toLower(rr.content);
         nsset.insert(rr);
       }
     }
   }
-  t_RC->replace(time(0),".", QType(QType::NS), nsset, true); // and stuff in the cache (auth)
+  t_RC->replace(time(0),".", QType(QType::NS), nsset, vector<std::shared_ptr<RRSIGRecordContent>>(), true); // and stuff in the cache (auth)
 }
 
 static void makeNameToIPZone(SyncRes::domainmap_t* newMap, const string& hostname, const string& ip)
index 65908af370eb05376fe10ef352f8baab944bcd6f..86ae430934c3570ed28961526c2af1895727d668 100644 (file)
@@ -30,6 +30,7 @@
 #include "syncres.hh"
 #include <iostream>
 #include <map>
+#include "dnsrecords.hh"
 #include <algorithm>
 #include <set>
 #include <cerrno>
@@ -74,12 +75,11 @@ SyncRes::LogMode SyncRes::s_lm;
 
 #define LOG(x) if(d_lm == Log) { L <<Logger::Warning << x; } else if(d_lm == Store) { d_trace << x; }
 
-bool SyncRes::s_noEDNSPing;
 bool SyncRes::s_noEDNS;
 
 SyncRes::SyncRes(const struct timeval& now) :  d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0),
-                                              d_totUsec(0), d_now(now),
-                                              d_cacheonly(false), d_nocache(false),   d_doEDNS0(false), d_lm(s_lm)
+                                              d_totUsec(0), d_doDNSSEC(false), d_now(now),
+                                              d_cacheonly(false), d_nocache(false), d_doEDNS0(false), d_lm(s_lm)
                                                  
 { 
   if(!t_sstorage) {
@@ -243,9 +243,8 @@ void SyncRes::doEDNSDumpAndClose(int fd)
 {
   FILE* fp=fdopen(fd, "w");
   fprintf(fp,"IP Address\tMode\tMode last updated at\n");
-
-  for(ednsstatus_t::const_iterator iter = t_sstorage->ednsstatus.begin(); iter != t_sstorage->ednsstatus.end(); ++iter) {
-    fprintf(fp, "%s\t%d\t%s", iter->first.toString().c_str(), (int)iter->second.mode, ctime(&iter->second.modeSetAt));
+  for(const auto& eds : t_sstorage->ednsstatus) {
+    fprintf(fp, "%s\t%d\t%s", eds.first.toString().c_str(), (int)eds.second.mode, ctime(&eds.second.modeSetAt));
   }
 
   fclose(fp);
@@ -254,132 +253,77 @@ void SyncRes::doEDNSDumpAndClose(int fd)
 int SyncRes::asyncresolveWrapper(const ComboAddress& ip, const string& domain, int type, bool doTCP, bool sendRDQuery, struct timeval* now, LWResult* res) 
 {
   /* what is your QUEST?
-     the goal is to get as many remotes as possible on the highest level of hipness: EDNS PING responders.
+     the goal is to get as many remotes as possible on the highest level of EDNS support
      The levels are:
 
-     -1) CONFIRMEDPINGER: Confirmed pinger!
      0) UNKNOWN Unknown state 
-     1) EDNSNOPING: Honors EDNS0 if no PING is included
-     2) EDNSPINGOK: Ignores EDNS0+PING, but does generate EDNS0 response
-     3) EDNSIGNORANT: Ignores EDNS0+PING, gives replies without EDNS0 nor PING
-     4) NOEDNS: Generates FORMERR on EDNS queries
+     1) EDNS: Honors EDNS0
+     2) EDNSIGNORANT: Ignores EDNS0, gives replies without EDNS0
+     3) NOEDNS: Generates FORMERR on EDNS queries
 
      Everybody starts out assumed to be '0'.
-     If '-1', send out EDNS0+Ping
-        If we get a FormErr, ignore
-        If we get a incorrect PING, ignore
-        If we get no PING, ignore
-     If '0', send out EDNS0+Ping
-        If we get a pure EDNS response, you are downgraded to '2'. 
-        If you FORMERR us, go to '1', 
-        If no EDNS in response, go to '3' - 3 and 0 are really identical, except confirmed
-        If with correct PING, upgrade to -1
-     If '1', send out EDNS0, no PING
-        If FORMERR, downgrade to 4
-     If '2', keep on including EDNS0+PING, just don't expect PING to be correct
-        If PING correct, move to '0', and cheer in the log file!
-     If '3', keep on including EDNS0+PING, see what happens
+     If '0', send out EDNS0
+        If you FORMERR us, go to '3', 
+        If no EDNS in response, go to '2'
+     If '1', send out EDNS0
+        If FORMERR, downgrade to 3
+     If '2', keep on including EDNS0, see what happens
         Same behaviour as 0 
-     If '4', send bare queries
+     If '3', send bare queries
   */
 
-  if(s_noEDNS) {
-    g_stats.noEdnsOutQueries++;
-    return asyncresolve(ip, domain, type, doTCP, sendRDQuery, 0, now, res);
-  }
-
+  g_stats.noEdnsOutQueries++;
+  
   SyncRes::EDNSStatus* ednsstatus;
-  ednsstatus = &t_sstorage->ednsstatus[ip];
+  ednsstatus = &t_sstorage->ednsstatus[ip]; // does this include port? 
 
   if(ednsstatus->modeSetAt && ednsstatus->modeSetAt + 3600 < d_now.tv_sec) {
     *ednsstatus=SyncRes::EDNSStatus();
     //    cerr<<"Resetting EDNS Status for "<<ip.toString()<<endl);
   }
 
-  if(s_noEDNSPing && ednsstatus->mode == EDNSStatus::UNKNOWN)
-    ednsstatus->mode = EDNSStatus::EDNSNOPING;
-
   SyncRes::EDNSStatus::EDNSMode& mode=ednsstatus->mode;
   SyncRes::EDNSStatus::EDNSMode oldmode = mode;
   int EDNSLevel=0;
 
   int ret;
   for(int tries = 0; tries < 3; ++tries) {
-    //    cerr<<"Remote '"<<ip.toString()<<"' currently in mode "<<mode<<endl);
-
-    if(mode==EDNSStatus::CONFIRMEDPINGER || mode==EDNSStatus::UNKNOWN || mode==EDNSStatus::EDNSPINGOK || mode==EDNSStatus::EDNSIGNORANT)
-      EDNSLevel = 2;
-    else if(mode==EDNSStatus::EDNSNOPING) {
+    cerr<<"Remote '"<<ip.toString()<<"' currently in mode "<<mode<<endl;
+    
+    if(mode==EDNSStatus::UNKNOWN || mode==EDNSStatus::EDNSOK || mode==EDNSStatus::EDNSIGNORANT)
       EDNSLevel = 1;
-      g_stats.noPingOutQueries++;
-    }
     else if(mode==EDNSStatus::NOEDNS) {
       g_stats.noEdnsOutQueries++;
       EDNSLevel = 0;
     }
-
+    
     ret=asyncresolve(ip, domain, type, doTCP, sendRDQuery, EDNSLevel, now, res);
+
     if(ret == 0 || ret < 0) {
-      //      cerr<<"Transport error or timeout (ret="<<ret<<"), no change in mode"<<endl);
+      cerr<<"Transport error or timeout (ret="<<ret<<"), no change in mode"<<endl;
       return ret;
     }
-
-    if(mode== EDNSStatus::CONFIRMEDPINGER) {  // confirmed pinger!
-      if(!res->d_pingCorrect) {
-        L<<Logger::Error<<"Confirmed EDNS-PING enabled host "<<ip.toString()<<" did not send back correct ping"<<endl;
-        //        perhaps lower some kind of count here, don't want to punnish a downgrader too long!
-        ret = 0;
-        res->d_rcode = RCode::ServFail;
-        g_stats.ednsPingMismatches++;
-      }
-      else {
-        g_stats.ednsPingMatches++;
-        ednsstatus->modeSetAt=d_now.tv_sec; // only the very best mode self-perpetuates
-      }
-    }
-    else if(mode==EDNSStatus::UNKNOWN || mode==EDNSStatus::EDNSPINGOK || mode == EDNSStatus::EDNSIGNORANT ) {
-      if(res->d_rcode == RCode::FormErr)  {
-        //        cerr<<"Downgrading to EDNSNOPING because of FORMERR!"<<endl);
-        mode = EDNSStatus::EDNSNOPING;
-        continue;
-      }
-      else if(mode==EDNSStatus::UNKNOWN && (res->d_rcode == RCode::Refused || res->d_rcode == RCode::NotImp) ) { // this "fixes" F5
-        //        cerr<<"Downgrading an unknown status to EDNSNOPING because of RCODE="<<res->d_rcode<<endl;
-        mode = EDNSStatus::EDNSNOPING;
+    else if(mode==EDNSStatus::UNKNOWN || mode==EDNSStatus::EDNSOK || mode == EDNSStatus::EDNSIGNORANT ) {
+      if(res->d_rcode == RCode::FormErr || res->d_rcode == RCode::NotImp)  {
+       cerr<<"Downgrading to NOEDNS because of FORMERR or NotImp!"<<endl;
+        mode = EDNSStatus::NOEDNS;
         continue;
       }
-      else if(!res->d_pingCorrect && res->d_haveEDNS) 
-        mode = EDNSStatus::EDNSPINGOK;
-      else if(res->d_pingCorrect) {
-        L<<Logger::Warning<<"We welcome "<<ip.toString()<<" to the land of EDNS-PING!"<<endl;
-        mode = EDNSStatus::CONFIRMEDPINGER;
-        g_stats.ednsPingMatches++;
-      }
       else if(!res->d_haveEDNS) {
         if(mode != EDNSStatus::EDNSIGNORANT) {
           mode = EDNSStatus::EDNSIGNORANT;
-          //          cerr<<"We find that "<<ip.toString()<<" is an EDNS-ignorer, moving to mode 3"<<endl);
-        }
-      }
-    }
-    else if(mode==EDNSStatus::EDNSNOPING) {
-      if(res->d_rcode == RCode::FormErr) {
-        //                cerr<<"Downgrading to mode 4, FORMERR!"<<endl);
-        mode = EDNSStatus::NOEDNS;
-        continue;
+         cerr<<"We find that "<<ip.toString()<<" is an EDNS-ignorer, moving to mode 3"<<endl;
+       }
       }
-    }
-    else if(mode==EDNSStatus::EDNSPINGOK) {
-      if(res->d_pingCorrect) {
-        // an upgrade!
-        L<<Logger::Warning<<"We welcome "<<ip.toString()<<" to the land of EDNS-PING!"<<endl;
-        mode = EDNSStatus::CONFIRMEDPINGER;
+      else {
+       mode = EDNSStatus::EDNSOK;
+       cerr<<"We find that "<<ip.toString()<<" is EDNS OK!"<<endl;
       }
+      
     }
     if(oldmode != mode)
       ednsstatus->modeSetAt=d_now.tv_sec;
-    //        cerr<<"Result: ret="<<ret<<", EDNS-level: "<<EDNSLevel<<", haveEDNS: "<<res->d_haveEDNS<<", EDNS-PING correct: "<<res->d_pingCorrect<<", new mode: "<<mode<<endl);  
-    
+    cerr<<"Result: ret="<<ret<<", EDNS-level: "<<EDNSLevel<<", haveEDNS: "<<res->d_haveEDNS<<", new mode: "<<mode<<endl;  
     return ret;
   }
   return ret;
@@ -414,7 +358,7 @@ int SyncRes::doResolve(const string &qname, const QType &qtype, vector<DNSResour
           res=asyncresolveWrapper(remoteIP, qname, qtype.getCode(), false, false, &d_now, &lwr);    
           // filter out the good stuff from lwr.result()
 
-          for(LWResult::res_t::const_iterator i=lwr.d_result.begin();i!=lwr.d_result.end();++i) {
+          for(LWResult::res_t::const_iterator i=lwr.getResult().begin();i!=lwr.getResult().end();++i) {
             if(i->d_place == DNSResourceRecord::ANSWER)
               ret.push_back(*i);
           }
@@ -757,14 +701,15 @@ bool SyncRes::doCacheCheck(const string &qname, const QType &qtype, vector<DNSRe
   }
   set<DNSResourceRecord> cset;
   bool found=false, expired=false;
-
-  if(t_RC->get(d_now.tv_sec, sqname, sqt, &cset) > 0) {
+  vector<std::shared_ptr<RRSIGRecordContent>> signatures;
+  uint32_t ttl=0;
+  if(t_RC->get(d_now.tv_sec, sqname, sqt, &cset, d_doDNSSEC ? &signatures : 0) > 0) {
     LOG(prefix<<sqname<<": Found cache hit for "<<sqt.getName()<<": ");
     for(set<DNSResourceRecord>::const_iterator j=cset.begin();j!=cset.end();++j) {
       LOG(j->content);
       if(j->ttl>(unsigned int) d_now.tv_sec) {
         DNSResourceRecord rr=*j;
-        rr.ttl-=d_now.tv_sec;
+        ttl=rr.ttl-=d_now.tv_sec;
         if(giveNegative) {
           rr.d_place=DNSResourceRecord::AUTHORITY;
           rr.ttl=sttl;
@@ -778,6 +723,17 @@ bool SyncRes::doCacheCheck(const string &qname, const QType &qtype, vector<DNSRe
         expired=true;
       }
     }
+
+    for(const auto& signature : signatures) {
+      DNSResourceRecord rr;
+      rr.qtype=QType(QType::RRSIG);
+      rr.qname=sqname;
+      rr.ttl=ttl; 
+      rr.content=signature->getZoneRepresentation();  
+      rr.d_place=DNSResourceRecord::ANSWER;
+      
+      ret.push_back(rr);
+    }
   
     LOG(endl);
     if(found && !expired) {
@@ -912,7 +868,7 @@ int SyncRes::doResolveAt(set<string, CIStringCompare> nameservers, string auth,
       LWResult lwr;
       if(tns->empty()) {
         LOG(prefix<<qname<<": Domain is out-of-band"<<endl);
-        doOOBResolve(qname, qtype, lwr.d_result, depth, lwr.d_rcode);
+        doOOBResolve(qname, qtype, lwr.getResult(), depth, lwr.d_rcode);
         lwr.d_tcbit=false;
         lwr.d_aabit=true;
       }
@@ -986,7 +942,7 @@ int SyncRes::doResolveAt(set<string, CIStringCompare> nameservers, string auth,
            if(s_maxtotusec && d_totUsec > s_maxtotusec) 
              throw ImmediateServFailException("Too much time waiting for "+qname+"|"+qtype.getName()+", timeouts: "+boost::lexical_cast<string>(d_timeouts) +", throttles: "+boost::lexical_cast<string>(d_throttledqueries) + ", queries: "+lexical_cast<string>(d_outqueries)+", "+lexical_cast<string>(d_totUsec/1000)+"msec");
 
-           if(d_pdl && d_pdl->preoutquery(*remoteIP, d_requestor, qname, qtype, lwr.d_result, resolveret)) {
+           if(d_pdl && d_pdl->preoutquery(*remoteIP, d_requestor, qname, qtype, lwr.getResult(), resolveret)) {
              LOG(prefix<<qname<<": query handled by Lua"<<endl);
            }
            else 
@@ -1058,7 +1014,7 @@ int SyncRes::doResolveAt(set<string, CIStringCompare> nameservers, string auth,
           return RCode::ServFail;
         }
         
-        LOG(prefix<<qname<<": Got "<<(unsigned int)lwr.d_result.size()<<" answers from "<<*tns<<" ("<< remoteIP->toString() <<"), rcode="<<lwr.d_rcode<<" ("<<RCode::to_s(lwr.d_rcode)<<"), aa="<<lwr.d_aabit<<", in "<<lwr.d_usec/1000<<"ms"<<endl);
+        LOG(prefix<<qname<<": Got "<<(unsigned int)lwr.getResult().size()<<" answers from "<<*tns<<" ("<< remoteIP->toString() <<"), rcode="<<lwr.d_rcode<<" ("<<RCode::to_s(lwr.d_rcode)<<"), aa="<<lwr.d_aabit<<", in "<<lwr.d_usec/1000<<"ms"<<endl);
 
         /*  // for you IPv6 fanatics :-)
         if(remoteIP->sin4.sin_family==AF_INET6)
@@ -1070,16 +1026,31 @@ int SyncRes::doResolveAt(set<string, CIStringCompare> nameservers, string auth,
       }
 
       if(s_minimumTTL) {
-       for(LWResult::res_t::iterator i=lwr.d_result.begin();i != lwr.d_result.end();++i) {
+       for(LWResult::res_t::iterator i=lwr.getResult().begin();i != lwr.getResult().end();++i) {
          i->ttl = max(i->ttl, s_minimumTTL);
        }
       }
 
-      typedef map<pair<string, QType>, set<DNSResourceRecord>, TCacheComp > tcache_t;
+      struct CachePair
+      {
+       set<DNSResourceRecord> records;
+       vector<shared_ptr<RRSIGRecordContent>> signatures;
+      };
+      typedef map<pair<string, QType>, CachePair, TCacheComp > tcache_t;
       tcache_t tcache;
 
+      if(d_doDNSSEC) {
+       for(const auto& rec : lwr.d_records) {
+         if(rec.first.d_type == QType::RRSIG) {
+           auto rrsig = std::dynamic_pointer_cast<RRSIGRecordContent>(rec.first.d_content);
+           cerr<<"Got an RRSIG for "<<DNSRecordContent::NumberToType(rrsig->d_type)<<" with name '"<<stripDot(rec.first.d_label)<<"'"<<endl;
+           tcache[make_pair(rec.first.d_label, QType(rrsig->d_type))].signatures.push_back(rrsig);
+         }
+       }
+      }
+
       // reap all answers from this packet that are acceptable
-      for(LWResult::res_t::iterator i=lwr.d_result.begin();i != lwr.d_result.end();++i) {
+      for(LWResult::res_t::iterator i=lwr.getResult().begin();i != lwr.getResult().end();++i) {
         if(i->qtype.getCode() == QType::OPT) {
           LOG(prefix<<qname<<": skipping OPT answer '"<<i->qname<<"' from '"<<auth<<"' nameservers" <<endl);
           continue;
@@ -1096,6 +1067,9 @@ int SyncRes::doResolveAt(set<string, CIStringCompare> nameservers, string auth,
             s_nodelegated++;
             return RCode::NXDomain;
           }
+         else if(i->qtype.getCode() == QType::RRSIG) {
+           LOG("RRSIG - separate"<<endl);
+         }
           else {
             LOG("YES!"<<endl);
 
@@ -1109,7 +1083,7 @@ int SyncRes::doResolveAt(set<string, CIStringCompare> nameservers, string auth,
             if(rr.qtype.getCode() == QType::NS) // people fiddle with the case
               rr.content=toLower(rr.content); // this must stay! (the cache can't be case-insensitive on the RHS of records)
             
-            tcache[make_pair(i->qname,i->qtype)].insert(rr);
+            tcache[make_pair(i->qname,i->qtype)].records.insert(rr);
           }
         }          
         else
@@ -1118,24 +1092,27 @@ int SyncRes::doResolveAt(set<string, CIStringCompare> nameservers, string auth,
     
       // supplant
       for(tcache_t::iterator i=tcache.begin();i!=tcache.end();++i) {
-        if(i->second.size() > 1) {  // need to group the ttl to be the minimum of the RRSET (RFC 2181, 5.2)
+        if(i->second.records.size() > 1) {  // need to group the ttl to be the minimum of the RRSET (RFC 2181, 5.2)
           uint32_t lowestTTL=std::numeric_limits<uint32_t>::max();
-          for(tcache_t::value_type::second_type::iterator j=i->second.begin(); j != i->second.end(); ++j)
-            lowestTTL=min(lowestTTL, j->ttl);
+         for(auto& record : i->second.records) 
+            lowestTTL=min(lowestTTL, record.ttl);
           
-          for(tcache_t::value_type::second_type::iterator j=i->second.begin(); j != i->second.end(); ++j)
-            ((tcache_t::value_type::second_type::value_type*)&(*j))->ttl=lowestTTL;
+         for(auto& record : i->second.records) 
+           *const_cast<uint32_t*>(&record.ttl)=lowestTTL;
         }
 
-        t_RC->replace(d_now.tv_sec, i->first.first, i->first.second, i->second, lwr.d_aabit);
+       cout<<"Have "<<i->second.records.size()<<" records and "<<i->second.signatures.size()<<" signatures for "<<i->first.first;
+       cout<<'|'<<DNSRecordContent::NumberToType(i->first.second.getCode())<<endl;
+        t_RC->replace(d_now.tv_sec, i->first.first, i->first.second, i->second.records, i->second.signatures, lwr.d_aabit);
       }
       set<string, CIStringCompare> nsset;  
       LOG(prefix<<qname<<": determining status after receiving this packet"<<endl);
 
-      bool done=false, realreferral=false, negindic=false;
+      bool done=false, realreferral=false, negindic=false, sawDS=false;
       string newauth, soaname, newtarget;
 
-      for(LWResult::res_t::iterator i=lwr.d_result.begin();i!=lwr.d_result.end();++i) {
+
+      for(LWResult::res_t::iterator i=lwr.getResult().begin();i!=lwr.getResult().end();++i) {
         if(i->d_place==DNSResourceRecord::AUTHORITY && i->qtype.getCode()==QType::SOA && 
            lwr.d_rcode==RCode::NXDomain && dottedEndsOn(qname,i->qname) && dottedEndsOn(i->qname, auth)) {
           LOG(prefix<<qname<<": got negative caching indication for RECORD '"<<qname+"' (accept="<<dottedEndsOn(i->qname, auth)<<"), newtarget='"<<newtarget<<"'"<<endl);
@@ -1165,6 +1142,9 @@ int SyncRes::doResolveAt(set<string, CIStringCompare> nameservers, string auth,
           ret.push_back(*i);
           newtarget=i->content;
         }
+       else if(d_doDNSSEC && (i->qtype==QType::RRSIG || i->qtype==QType::NSEC || i->qtype==QType::NSEC3) && i->d_place==DNSResourceRecord::ANSWER){
+         ret.push_back(*i); // enjoy your DNSSEC
+       }
         // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
         else if(i->d_place==DNSResourceRecord::ANSWER && pdns_iequals(i->qname, qname) && 
                 (
@@ -1188,6 +1168,10 @@ int SyncRes::doResolveAt(set<string, CIStringCompare> nameservers, string auth,
             LOG(prefix<<qname<<": got upwards/level NS record '"<<i->qname<<"' -> '"<<i->content<<"', had '"<<auth<<"'"<<endl);
           nsset.insert(i->content);
         }
+        else if(i->d_place==DNSResourceRecord::AUTHORITY && dottedEndsOn(qname,i->qname) && i->qtype.getCode()==QType::DS) { 
+         LOG(prefix<<qname<<": got DS record '"<<i->qname<<"' -> '"<<i->content<<"'"<<endl);
+         sawDS=true;
+       }
         else if(!done && i->d_place==DNSResourceRecord::AUTHORITY && dottedEndsOn(qname,i->qname) && i->qtype.getCode()==QType::SOA && 
            lwr.d_rcode==RCode::NoError) {
           LOG(prefix<<qname<<": got negative caching indication for '"<< (qname+"|"+qtype.getName()+"'") <<endl);
@@ -1239,6 +1223,12 @@ int SyncRes::doResolveAt(set<string, CIStringCompare> nameservers, string auth,
       }
       else if(realreferral) {
         LOG(prefix<<qname<<": status=did not resolve, got "<<(unsigned int)nsset.size()<<" NS, looping to them"<<endl);
+       if(sawDS) {
+         t_sstorage->dnssecmap[newauth]=true;
+         for(const auto& e : t_sstorage->dnssecmap)
+           cout<<e.first<<' ';
+         cout<<endl;
+       }
         auth=newauth;
         nameservers=nsset;
         break; 
index 711bfa3c83c971e8ea6c94b7149db515002e1e96..403f3ed15c1b512150597a813ca2a046c84d6071 100644 (file)
@@ -308,6 +308,7 @@ public:
   unsigned int d_unreachables;
   unsigned int d_totUsec;
   ComboAddress d_requestor;
+  bool d_doDNSSEC;
 
   typedef multi_index_container <
     NegCacheEntry,
@@ -378,10 +379,9 @@ public:
 
   struct EDNSStatus
   {
-    EDNSStatus() : mode(UNKNOWN), modeSetAt(0), EDNSPingHitCount(0) {}
-    enum EDNSMode { CONFIRMEDPINGER=-1, UNKNOWN=0, EDNSNOPING=1, EDNSPINGOK=2, EDNSIGNORANT=3, NOEDNS=4 } mode;
+    EDNSStatus() : mode(UNKNOWN), modeSetAt(0) {}
+    enum EDNSMode { UNKNOWN=0, EDNSOK=1, EDNSIGNORANT=2, NOEDNS=3 } mode;
     time_t modeSetAt;
-    int EDNSPingHitCount;
   };
 
   typedef map<ComboAddress, EDNSStatus> ednsstatus_t;
@@ -434,6 +434,7 @@ public:
     throttle_t throttle;
     fails_t fails;
     domainmap_t* domainmap;
+    map<string,bool> dnssecmap;
   };
 
 private:
@@ -451,6 +452,7 @@ private:
   inline vector<string> shuffleInSpeedOrder(set<string, CIStringCompare> &nameservers, const string &prefix);
   bool moreSpecificThan(const string& a, const string &b);
   vector<ComboAddress> getAddrs(const string &qname, int depth, set<GetBestNSAnswer>& beenthere);
+
 private:
   ostringstream d_trace;
   shared_ptr<RecursorLua> d_pdl;
@@ -458,6 +460,7 @@ private:
   bool d_cacheonly;
   bool d_nocache;
   bool d_doEDNS0;
+
   static LogMode s_lm;
   LogMode d_lm;