]> granicus.if.org Git - pdns/commitdiff
it is a wip, doesn't even compile
authorbert hubert <bert.hubert@powerdns.com>
Wed, 18 Nov 2015 15:36:49 +0000 (16:36 +0100)
committerbert hubert <bert.hubert@powerdns.com>
Wed, 18 Nov 2015 15:36:49 +0000 (16:36 +0100)
pdns/Makefile.am
pdns/toysdig.cc

index f0d0a23e301fc852044d2da5ae19806bd1f08deb..20983d984d5c3810ea53e65f054dae7509dd3fc7 100644 (file)
@@ -711,6 +711,11 @@ if GSS_TSIG
 toysdig_LDADD += $(GSS_LIBS)
 endif
 
+if BOTAN110
+toysdig_SOURCES += botan110signers.cc botansigners.cc
+toysdig_LDADD += $(BOTAN110_LIBS)
+endif
+
 
 tsig_tests_SOURCES = \
        arguments.cc \
index 740b8d43dc634ebf8c42038e8e0b7a396b7926e1..97fec8efd731401f1528dd609bb2280c3c0c343a 100644 (file)
@@ -45,8 +45,11 @@ public:
 
     d_rsock.writen(string((char*)&*packet.begin(), (char*)&*packet.end()));
     
-    if(d_rsock.read((char *) &len, 2) != 2)
-      throw PDNSException("tcp read failed");
+    int bread=d_rsock.read((char *) &len, 2);
+    if( bread <0)
+      throw PDNSException("tcp read failed: "+std::string(strerror(errno)));
+    if(bread != 2) 
+      throw PDNSException("EOF on TCP read");
 
     len=ntohs(len);
     char *creply = new char[len];
@@ -55,7 +58,7 @@ public:
     while(n<len) {
       numread=d_rsock.read(creply+n, len-n);
       if(numread<0)
-        throw PDNSException("tcp read failed");
+        throw PDNSException("tcp read failed: "+std::string(strerror(errno)));
       n+=numread;
     }
 
@@ -68,162 +71,26 @@ public:
   Socket d_rsock;
 };
 
-
-set<DSRecordContent> g_anchors;
-
-vector<DNSKEYRecordContent> getKeys(Socket& sock, const DNSName& name, uint16_t tag, bool* trusted)
-{
-  *trusted=false;
-  vector<uint8_t> packet;
-  DNSPacketWriter pw(packet, name, QType::DNSKEY);
-  pw.getHeader()->rd=1;
-  pw.getHeader()->cd=1;
-  pw.getHeader()->id=getpid();
-  pw.addOpt(1800, 0, EDNSOpts::DNSSECOK);
-  pw.commit();
-  
-  sock.send(string((char*)&*packet.begin(), (char*)&*packet.end()));
-  string resp;
-  sock.read(resp);
-  MOADNSParser mdp(resp);
-  vector<DNSKEYRecordContent> ret;
-  shared_ptr<DNSKEYRecordContent> root;
-  for(const auto& r : mdp.d_answers) {
-    cout<<r.first.d_place-1<<"\t"<<r.first.d_name.toString()<<"\tIN\t"<<DNSRecordContent::NumberToType(r.first.d_type);
-    cout<<"\t"<<r.first.d_content->getZoneRepresentation()<<endl;
-
-    if(auto dk = getRR<DNSKEYRecordContent>(r.first)) {
-      if(dk->getTag() == tag) {
-       cout<<"Found key with tag "<<dk->getTag()<<endl;
-       ret.push_back(*dk);
-      }
-      else {
-       cout<<"Also got other key with tag "<<dk->getTag()<<" and DS ";
-       auto ds=makeDSFromDNSKey(name, *dk, 2);
-       cout<<ds.getZoneRepresentation()<<endl;
-       if(g_anchors.count(ds)) {
-         cout<<"THIS IS THE ROOT"<<endl;
-         root = dk;
-       }
-      }
-    }
-    else if(auto rrsig = getRR<RRSIGRecordContent>(r.first)) {
-      if(root) {
-       cout<<"Had a signature on "<<r.first.d_name<<" "<<DNSRecordContent::NumberToType(r.first.d_type)<<" with tag "<<rrsig->d_tag<<endl;
-       cout<<"Have a root dnskey with tag "<<rrsig->d_tag<<endl;
-       auto engine = DNSCryptoKeyEngine::makeFromPublicKeyString(rrsig->d_algorithm, root->d_key);
-       vector<shared_ptr<DNSRecordContent>> toSign;
-       toSign.push_back(std::make_shared<DNSKEYRecordContent>(ret[0]));
-       toSign.push_back(root);
-       string msg = getMessageForRRSET(r.first.d_name, *rrsig, toSign);        
-       *trusted=engine->verify(msg, rrsig->d_signature);
-       cout<<"Result for signature in DNSKEY: "<<*trusted<<endl;
-      }
-    }
-  }
-  return ret;
-}
-
-
 unique_ptr<MOADNSParser> getMDP(const ComboAddress& dest, const DNSName& qname, uint16_t qtype)
 {
   TCPResolver tr(dest);
-
   string resp=tr.query(qname, qtype);
-  return unique_ptr<MOADNSParser>(new MOADNSParser(resp));
-
+  return make_unique<MOADNSParser>(resp);
 }
 
 
-void lookup(const ComboAddress& dest, const DNSName& qname, uint16_t qtype)
-{
-  if(qname==DNSName(".") && qtype == QType::DS) {
-    cerr<<"Hit root, should stop somehow ;-)"<<endl;
-    exit(0);
-  }
-  Socket sock(dest.sin4.sin_family, SOCK_DGRAM);
-  sock.connect(dest);
-  vector<uint8_t> packet;
-
-  DNSPacketWriter pw(packet, qname, qtype);
-  pw.getHeader()->rd=1;
-  pw.getHeader()->cd=1;
-  pw.getHeader()->id=getpid();
-  pw.addOpt(1800, 0, EDNSOpts::DNSSECOK);
-  pw.commit();
-
-  sock.send(string((char*)&*packet.begin(), (char*)&*packet.end()));
-  string resp;
-  sock.read(resp);
-  MOADNSParser mdp(resp);
-
-  struct ContentPair {
-    vector<DNSRecord> content;
-    vector<shared_ptr<RRSIGRecordContent>> signatures;
-  };
-
-  map<pair<DNSName,uint16_t>, ContentPair > records;
-
-  for(const auto& r : mdp.d_answers) {
-    cout<<r.first.d_place-1<<"\t"<<r.first.d_name.toString()<<"\tIN\t"<<DNSRecordContent::NumberToType(r.first.d_type);
-    cout<<"\t"<<r.first.d_content->getZoneRepresentation()<<endl;
-
-    if(auto rrsig = getRR<RRSIGRecordContent>(r.first)) {
-      records[make_pair(r.first.d_name, rrsig->d_type)].signatures.push_back(rrsig);
-    }
-    else if(auto opt = getRR<OPTRecordContent>(r.first)) {
-      continue;
-    }
-
-    else
-      records[make_pair(r.first.d_name, r.first.d_type)].content.push_back(r.first);
-
-  }
-  cout<<"Had "<<records.size()<<" RRSETs"<<endl;
-  for(auto& rrset : records) {
-    vector<shared_ptr<DNSRecordContent> > toSign;
-    for(const auto& c : rrset.second.content) 
-      toSign.push_back(c.d_content);
-
-    for(auto& sign : rrset.second.signatures) {
-      cout<<"Seeing if we can retrieve DNSKEY for "<<sign->d_signer<<" with tag "<<sign->d_tag<<endl;
-      bool trusted=false;
-      auto keys=getKeys(sock, sign->d_signer, sign->d_tag, &trusted);
-      cout<<"Got "<<keys.size()<<" keys"<<endl;
-      for(const auto& key : keys) {
-       auto engine = DNSCryptoKeyEngine::makeFromPublicKeyString(key.d_algorithm, key.d_key);
-       string msg = getMessageForRRSET(rrset.first.first, *sign, toSign);        
-       cout<<"Result for signature on "<<rrset.first.first<<" "<<DNSRecordContent::NumberToType(rrset.first.second)<<": "<<engine->verify(msg, sign->d_signature)<<endl;
-
-       if(trusted) {
-         cerr<<"This key is trusted ultimately"<<endl;
-         return;
-       }
-       else {
-
-         cerr<<"Should go looking for DS on DNSKEY "<<sign->d_signer<<endl;
-         lookup(dest, sign->d_signer, QType::DS);
-       }
-      }
-    }
-  }
-}
-
 // 4033 5
-// FIXME: namespace this
 enum vState { Indeterminate, Bogus, Insecure, Secure };
 const char *vStates[]={"Indeterminate", "Bogus", "Insecure", "Secure"};
 
 // NSEC(3) results
-// FIXME: namespace this
 enum dState { NODATA, NXDOMAIN, ENT, INSECURE };
 const char *dStates[]={"nodata", "nxdomain", "empty non-terminal", "insecure (no-DS proof)"};
 
 
 typedef std::multimap<uint16_t, DNSKEYRecordContent> keymap_t;
 
-
-string nsec3Hash(const DNSName &qname, const NSEC3RecordContent& nrc)
+static string nsec3Hash(const DNSName &qname, const NSEC3RecordContent& nrc)
 {
   NSEC3PARAMRecordContent ns3pr;
   ns3pr.d_iterations = nrc.d_iterations;
@@ -231,11 +98,15 @@ string nsec3Hash(const DNSName &qname, const NSEC3RecordContent& nrc)
   return toBase32Hex(hashQNameWithSalt(ns3pr, qname));
 }
 
-
+struct ContentSigPair
+{
+  vector<shared_ptr<DNSRecordContent>> records;
+  vector<shared_ptr<RRSIGRecordContent>> signatures;
+};
+typedef map<pair<DNSName,uint16_t>, ContentSigPair> cspmap_t;
 
 
 typedef map<pair<DNSName, uint16_t>, set<shared_ptr<DNSRecordContent> > > rrsetmap_t;
-
 typedef pair<DNSName, uint16_t> NT; // Name/Type pair
 typedef std::multimap<NT, shared_ptr<DNSRecordContent> > recmap_t;
 typedef std::multimap<NT, RRSIGRecordContent> sigmap_t;
@@ -247,7 +118,7 @@ typedef pair<DNSName, uint16_t> ZT; //Zonename/keyTag pair
 // keymap_t g_vkeys; // validated keys
 
 // FIXME: needs a zone argument, to avoid things like 6840 4.1
-dState getDenial(rrsetmap_t &validrrsets, DNSName qname, uint16_t qtype)
+static dState getDenial(rrsetmap_t &validrrsets, DNSName qname, uint16_t qtype)
 {
   std::multimap<DNSName, NSEC3RecordContent> nsec3s;
 
@@ -295,9 +166,9 @@ string dotEscape(string name)
 string dotName(string type, DNSName name, string tag)
 {
   if(tag == "")
-    return type+" "+name.toStringNoDot();
+    return type+" "+name.toString();
   else
-    return type+" "+name.toStringNoDot()+"/"+tag;
+    return type+" "+name.toString()+"/"+tag;
 }
 void dotNode(string type, DNSName name, string tag, string content)
 {
@@ -309,36 +180,43 @@ void dotNode(string type, DNSName name, string tag, string content)
 void dotEdge(DNSName zone, string type1, DNSName name1, string tag1, string type2, DNSName name2, string tag2, string color="")
 {
   cout<<"    ";
-  if(zone != DNSName(".")) cout<<"subgraph "<<dotEscape("cluster "+zone.toStringNoDot())<<" { ";
+  if(zone != DNSName(".")) cout<<"subgraph "<<dotEscape("cluster "+zone.toString())<<" { ";
   cout<<dotEscape(dotName(type1, name1, tag1))
       <<" -> "
       <<dotEscape(dotName(type2, name2, tag2));
   if(color != "") cout<<" [ color=\""<<color<<"\" ]; ";
   else cout<<"; ";
-  if(zone != DNSName(".")) cout<<"label = "<<dotEscape("zone: "+zone.toStringNoDot())<<";"<<"}";
+  if(zone != DNSName(".")) cout<<"label = "<<dotEscape("zone: "+zone.toString())<<";"<<"}";
   cout<<endl;
 }
 
-void validateWithKeySet(rrsetmap_t& rrsets, rrsetmap_t& rrsigs, rrsetmap_t& validated, keymap_t& keys)
+static void validateWithKeySet(const cspmap& rrsets, cspmap_t& validated, keymap_t& keys)
 {
-  for(rrsetmap_t::const_iterator i=rrsets.begin(); i!=rrsets.end(); i++)
+  for(auto i=rrsets.begin(); i!=rrsets.end(); i++)
   {
-    cerr<<"validating "<<(i->first.first)<<"/"<<DNSRecordContent::NumberToType(i->first.second)<<endl;
-    pair<rrsetmap_t::const_iterator, rrsetmap_t::const_iterator> r = rrsigs.equal_range(make_pair(i->first.first, i->first.second));
-    for(rrsetmap_t::const_iterator j=r.first; j!=r.second; j++) {
-      for(set<shared_ptr<DNSRecordContent> >::const_iterator k=j->second.begin(); k!=j->second.end(); k++) {
-        vector<shared_ptr<DNSRecordContent> > toSign;
-        set<shared_ptr<DNSRecordContent> > rrs = rrsets[make_pair(j->first.first, j->first.second)];
-        toSign.assign(rrs.begin(), rrs.end());
-
-        const RRSIGRecordContent rrc=dynamic_cast<const RRSIGRecordContent&> (*(*k));
-
-        if(!keys.count(rrc.d_tag)) continue;
+    cerr<<"validating "<<(i->first.first)<<"/"<<DNSRecordContent::NumberToType(i->first.second)<<" with "<<i->second.signatures.size()<<" sigs: ";
+    for(const auto& signature : i->second.signatures) {
+      for(auto k=i->second.records.begin(); k!=j->second.records.end(); k++) {
+        vector<shared_ptr<DNSRecordContent> > toSign = j->records;
+       auto rrc = *signature->d_content;
+
+        if(!keys.count(rrc.d_tag)) {
+         cerr<<"No key provided for "<<rrc.d_tag<<endl;
+         continue;
+       }
 
         string msg=getMessageForRRSET(j->first.first, rrc, toSign);
-        pair<keymap_t::const_iterator, keymap_t::const_iterator> r = keys.equal_range(rrc.d_tag); // FIXME: also take algorithm into account? right now we wrongly validate unknownalgorithm.bad-dnssec.wb.sidnlabs.nl
+        auto r = keys.equal_range(rrc.d_tag); // FIXME: also take algorithm into account? right now we wrongly validate unknownalgorithm.bad-dnssec.wb.sidnlabs.nl
         for(keymap_t::const_iterator l=r.first; l!=r.second; l++) {
-          bool isValid = DNSCryptoKeyEngine::makeFromPublicKeyString(l->second.d_algorithm, l->second.d_key)->verify(msg, rrc.d_signature);
+          bool isValid = false;
+         try {
+           unsigned int now=time(0);
+           if(rrc.d_siginception < now && rrc.d_sigexpire > now)
+             isValid = DNSCryptoKeyEngine::makeFromPublicKeyString(l->second.d_algorithm, l->second.d_key)->verify(msg, rrc.d_signature);
+         }
+         catch(std::exception& e) {
+           cerr<<"Error validating with engine: "<<e.what()<<endl;
+         }
           if(isValid) {
             validated[make_pair(j->first.first, j->first.second)] = rrs;
             cerr<<"valid"<<endl;
@@ -363,9 +241,9 @@ void validateWithKeySet(rrsetmap_t& rrsets, rrsetmap_t& rrsigs, rrsetmap_t& vali
 //      www.powerdnssec.org -> secure/powerdnssec.org/[keys]
 //      www.dnssec-failed.org -> bogus/dnssec-failed.org/[]
 
-char *rootDS;
+const char *rootDS;
 
-vState getKeysFor(TCPResolver& tr, const DNSName& zone, keymap_t &keyset)
+static vState getKeysFor(TCPResolver& tr, const DNSName& zone, keymap_t &keyset)
 {
   vector<string> labels = zone.getRawLabels();
   vState state;
@@ -408,38 +286,50 @@ vState getKeysFor(TCPResolver& tr, const DNSName& zone, keymap_t &keyset)
 
       if(i->first.d_type == QType::RRSIG)
       {
-        RRSIGRecordContent rrc=dynamic_cast<RRSIGRecordContent&> (*(i->first.d_content));
-        if(rrc.d_type != QType::DNSKEY)
+        auto rrc=getRR<RRSIGRecordContent> (i->first);
+        if(rrc->d_type != QType::DNSKEY)
           continue;
-        sigs.push_back(rrc);
+        sigs.push_back(*rrc);
       }
       else if(i->first.d_type == QType::DNSKEY)
       {
-        DNSKEYRecordContent drc=dynamic_cast<DNSKEYRecordContent&> (*(i->first.d_content));
-        tkeymap.insert(make_pair(drc.getTag(), drc));
-              dotNode("DNSKEY", qname, lexical_cast<string>(drc.getTag()), (boost::format("tag=%d, algo=%d") % drc.getTag() % static_cast<int>(drc.d_algorithm)).str());
+        auto drc=getRR<DNSKEYRecordContent> (i->first);
+        tkeymap.insert(make_pair(drc->getTag(), *drc));
+         
+       dotNode("DNSKEY", qname, lexical_cast<string>(drc->getTag()), (boost::format("tag=%d, algo=%d") % drc->getTag() % static_cast<int>(drc->d_algorithm)).str());
 
         toSign.push_back(i->first.d_content);
-        toSignTags.push_back(drc.getTag());
+        toSignTags.push_back(drc->getTag());
       }
     }
-    cerr<<"got "<<tkeymap.size()<<" keys and "<<sigs.size()<<" sigs"<<endl;
+    cerr<<"got "<<tkeymap.size()<<" keys and "<<sigs.size()<<" sigs from server"<<endl;
 
     for(dsmap_t::const_iterator i=dsmap.begin(); i!=dsmap.end(); i++)
     {
       DSRecordContent dsrc=i->second;
-      cerr<<"got DS with tag "<<dsrc.d_tag<<"/"<<i->first<<", got "<<tkeymap.count(i->first)<<" DNSKEYs for tag"<<endl;
-      pair<keymap_t::const_iterator, keymap_t::const_iterator> r = tkeymap.equal_range(i->first);
+      cerr<<"looking at DS with tag "<<dsrc.d_tag<<"/"<<i->first<<", got "<<tkeymap.count(i->first)<<" DNSKEYs for tag"<<endl;
+      auto r = tkeymap.equal_range(i->first);
       for(keymap_t::const_iterator j=r.first; j!=r.second; j++)
       {
         DNSKEYRecordContent drc=j->second;
-        DSRecordContent dsrc2=makeDSFromDNSKey(qname, drc, dsrc.d_digesttype);
-        bool isValid = dsrc == dsrc2;
+       bool isValid = false;
+       DSRecordContent dsrc2;
+       try {
+         dsrc2=makeDSFromDNSKey(qname, drc, dsrc.d_digesttype);
+         isValid = dsrc == dsrc2;
+       } 
+       catch(std::exception &e) {
+         cerr<<"Unable to make DS from DNSKey: "<<e.what()<<endl;
+       }
+
         if(isValid) {
-          cerr<<"got valid DNSKEY"<<endl;
+          cerr<<"got valid DNSKEY (it matches the DS) for "<<qname<<endl;
           keymap.insert(make_pair(drc.getTag(), drc));
                   dotNode("DS", qname, "" /*lexical_cast<string>(dsrc.d_tag)*/, (boost::format("tag=%d, digest algo=%d, algo=%d") % dsrc.d_tag % static_cast<int>(dsrc.d_digesttype) % static_cast<int>(dsrc.d_algorithm)).str());
         }
+       else {
+         cerr<<"DNSKEY did not match the DS, parent DS: "<<drc.getZoneRepresentation() << " ! = "<<dsrc2.getZoneRepresentation()<<endl;
+       }
         // cout<<"    subgraph "<<dotEscape("cluster "+qname)<<" { "<<dotEscape("DS "+qname)<<" -> "<<dotEscape("DNSKEY "+qname)<<" [ label = \""<<dsrc.d_tag<<"/"<<static_cast<int>(dsrc.d_digesttype)<<"\" ]; label = \"zone: "<<qname<<"\"; }"<<endl;
               dotEdge(DNSName("."), "DS", qname, "" /*lexical_cast<string>(dsrc.d_tag)*/, "DNSKEY", qname, lexical_cast<string>(drc.getTag()), isValid ? "green" : "red");
         // dotNode("DNSKEY", qname, (boost::format("tag=%d, algo=%d") % drc.getTag() % static_cast<int>(drc.d_algorithm)).str());
@@ -461,14 +351,22 @@ vState getKeysFor(TCPResolver& tr, const DNSName& zone, keymap_t &keyset)
         string msg=getMessageForRRSET(qname, *i, toSign);
         pair<keymap_t::const_iterator, keymap_t::const_iterator> r = keymap.equal_range(i->d_tag);
         for(keymap_t::const_iterator j=r.first; j!=r.second; j++) {
-          cerr<<"validating"<<endl;
-          bool isValid = DNSCryptoKeyEngine::makeFromPublicKeyString(j->second.d_algorithm, j->second.d_key)->verify(msg, i->d_signature);
-                  for(uint16_t tag : toSignTags) {
-                      dotEdge(qname,
-                "DNSKEY", qname, lexical_cast<string>(i->d_tag),
-                "DNSKEY", qname, lexical_cast<string>(tag), isValid ? "green" : "red");
-                  }
-
+          cerr<<"validating : ";
+          bool isValid = false;
+         try {
+           unsigned int now = time(0);
+           if(i->d_siginception < now && i->d_sigexpire > now)
+             isValid = DNSCryptoKeyEngine::makeFromPublicKeyString(j->second.d_algorithm, j->second.d_key)->verify(msg, i->d_signature);
+         }
+         catch(std::exception& e) {
+           cerr<<"Could not make a validator for signature: "<<e.what()<<endl;
+         }
+         for(uint16_t tag : toSignTags) {
+           dotEdge(qname,
+                   "DNSKEY", qname, lexical_cast<string>(i->d_tag),
+                   "DNSKEY", qname, lexical_cast<string>(tag), isValid ? "green" : "red");
+         }
+         
           if(isValid)
           {
             cerr<<"validation succeeded - whole DNSKEY set is valid"<<endl;
@@ -476,12 +374,14 @@ vState getKeysFor(TCPResolver& tr, const DNSName& zone, keymap_t &keyset)
             keymap=tkeymap;
             break;
           }
+         else
+           cerr<<"Validation did not succeed!"<<endl;
         }
-        if(!keymap.size()) cerr<<"did not manage to validate DNSKEY set based on DS-validated KSK, only passing KSK on"<<endl;
+        if(keymap.empty()) cerr<<"did not manage to validate DNSKEY set based on DS-validated KSK, only passing KSK on"<<endl;
       }
     }
 
-    if(!keymap.size())
+    if(keymap.empty())
     {
       cerr<<"ended up with zero valid DNSKEYs, going Bogus"<<endl;
       state=Bogus;
@@ -509,33 +409,31 @@ vState getKeysFor(TCPResolver& tr, const DNSName& zone, keymap_t &keyset)
 
       MOADNSParser mdp(tr.query(qname, QType::DS));
 
-      rrsetmap_t rrsets;
-      rrsetmap_t rrsigs;
-
+      cspmap_t cspmap;
       for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
-        cerr<<"res "<<i->first.d_name<<"/"<<i->first.d_type<<endl;
+       //        cerr<<"res "<<i->first.d_name<<"/"<<i->first.d_type<<endl;
         if(i->first.d_type == QType::OPT) continue;
 
         if(i->first.d_type == QType::RRSIG) {
-          RRSIGRecordContent rrc = dynamic_cast<RRSIGRecordContent&> (*(i->first.d_content));
-          rrsigs[make_pair(i->first.d_name,rrc.d_type)].insert(i->first.d_content);
+          auto rrc = getRR<RRSIGRecordContent>(i->first);
+         cspmap[{i->first.d_name,rrc->d_type}].signatures.push_back(getRR<RRSIGRecordContent>(i->first));
         }
         else {
-          rrsets[make_pair(i->first.d_name,i->first.d_type)].insert(i->first.d_content);
+         cspmap[{i->first.d_name, i->first.d_type}].push_back(i->first.d_content);
         }
       }
 
-      rrsetmap_t validrrsets;
-      validateWithKeySet(rrsets, rrsigs, validrrsets, keymap);
+      cspmap_t validrrsets;
+      validateWithKeySet(cspmap, validrrsets, keymap);
 
-      cerr<<"got "<<rrsets.count(make_pair(qname,QType::DS))<<" DS of which "<<validrrsets.count(make_pair(qname,QType::DS))<<" valid "<<endl;
+      cerr<<"got "<<cspmap.count(make_pair(qname,QType::DS))<<" DS of which "<<validrrsets.count(make_pair(qname,QType::DS))<<" valid "<<endl;
 
       auto r = validrrsets.equal_range(make_pair(qname, QType::DS));
-      for(rrsetmap_t::const_iterator i=r.first; i!=r.second; i++) {
-        for(set<shared_ptr<DNSRecordContent> >::const_iterator j=i->second.begin(); j!=i->second.end(); j++)
+      for(auto cspiter =r.first; i!=r.second; i++) {
+        for(auto j=cspiter->second.records.cbegin(); j!=cspiter->second.records.cend(); j++)
         {
-          const DSRecordContent dsrc=dynamic_cast<const DSRecordContent&> (**j);
-          dsmap.insert(make_pair(dsrc.d_tag, dsrc));
+          const auto dsrc=getRR<DSRecordContent>(*j);
+          dsmap.insert(make_pair(dsrc->d_tag, *dsrc));
           // dotEdge(keyqname,
           //         "DNSKEY", keyqname, ,
           //         "DS", qname, lexical_cast<string>(dsrc.d_tag));
@@ -555,9 +453,6 @@ vState getKeysFor(TCPResolver& tr, const DNSName& zone, keymap_t &keyset)
   return state;
 }
 
-
-
-
 int main(int argc, char** argv)
 try
 {
@@ -566,9 +461,9 @@ try
 
   if(argv[5])
     rootDS = argv[5];
-  g_anchors.insert(DSRecordContent("19036 8 2 49aac11d7b6f6446702e54a1607371607a1a41855200fd2ce1cdde32f24e8fb5"));
+  //  g_anchors.insert(DSRecordContent("19036 8 2 49aac11d7b6f6446702e54a1607371607a1a41855200fd2ce1cdde32f24e8fb5"));
   if(argc < 4) {
-    cerr<<"Syntax: sdig IP-address port question question-type\n";
+    cerr<<"Syntax: toysdig IP-address port question question-type [rootDS]\n";
     exit(EXIT_FAILURE);
   }
   ComboAddress dest(argv[1] + (*argv[1]=='@'), atoi(argv[2]));
@@ -584,7 +479,7 @@ try
   rrsetmap_t rrsigs;
 
   for(auto i = mdp->d_answers.begin(); i != mdp->d_answers.end(); ++i) {
-    cerr<<"res "<<i->first.d_name<<"/"<<i->first.d_type<<endl;
+    //    cerr<<"res "<<i->first.d_name<<"/"<<i->first.d_type<<endl;
     if(i->first.d_type == QType::OPT) continue;
 
     if(i->first.d_type == QType::RRSIG) {
@@ -598,8 +493,8 @@ try
 
   cerr<<"got "<<rrsigs.size()<<" sigs for "<<rrsets.size()<<" sets"<<endl;
 
-  pair<rrsetmap_t::const_iterator, rrsetmap_t::const_iterator> r = rrsigs.equal_range(make_pair(qname, qtype));
-  cerr<<"got "<<rrsigs.count(make_pair(qname, qtype))<<" applicable sigs"<<endl;
+  auto r = rrsigs.equal_range(make_pair(qname, qtype));
+  cerr<<"got "<<std::distance(r.second, r.first)<<" applicable sigs"<<endl;
 
   keymap_t keys;
   rrsetmap_t validrrsets;
@@ -607,7 +502,7 @@ try
   if(rrsigs.size()) {
     for(rrsetmap_t::const_iterator i=rrsigs.begin(); i!=rrsigs.end(); i++) {
       cerr<<"A"<<endl;
-      for(set<shared_ptr<DNSRecordContent> >::const_iterator j=i->second.begin(); j!=i->second.end(); j++)
+      for(auto j=i->second.begin(); j!=i->second.end(); j++)
       {
         cerr<<"B"<<endl;
         const RRSIGRecordContent rrc=dynamic_cast<const RRSIGRecordContent&> (*(*j));
@@ -630,17 +525,100 @@ try
   for(rrsetmap_t::const_iterator i=validrrsets.begin(); i!=validrrsets.end(); i++) {
     cerr<<"% "<<i->first.first<<"/"<<DNSRecordContent::NumberToType(i->first.second)<<endl;
     for(set<shared_ptr<DNSRecordContent> >::const_iterator j=i->second.begin(); j!=i->second.end(); j++) {
-      cerr<<"% > "<<(*j)->getZoneRepresentation()<<endl;
+      cerr<<"\t% > "<<(*j)->getZoneRepresentation()<<endl;
     }
   }
 
   cout<<"}"<<endl;
   exit(0);
-
-
-
 }
 catch(std::exception &e)
 {
   cerr<<"Fatal: "<<e.what()<<endl;
 }
+catch(PDNSException &pe)
+{
+  cerr<<"Fatal: "<<pe.reason<<endl;
+}
+
+
+#if 0
+static void lookup(const ComboAddress& dest, const DNSName& qname, uint16_t qtype)
+{
+  if(qname==DNSName(".") && qtype == QType::DS) {
+    cerr<<"Hit root, should stop somehow ;-)"<<endl;
+    exit(0);
+  }
+  Socket sock(dest.sin4.sin_family, SOCK_DGRAM);
+  sock.connect(dest);
+  vector<uint8_t> packet;
+
+  DNSPacketWriter pw(packet, qname, qtype);
+  pw.getHeader()->rd=1;
+  pw.getHeader()->cd=1;
+  pw.getHeader()->id=getpid();
+  pw.addOpt(1800, 0, EDNSOpts::DNSSECOK);
+  pw.commit();
+
+  sock.send(string((char*)&*packet.begin(), (char*)&*packet.end()));
+  string resp;
+  sock.read(resp);
+  MOADNSParser mdp(resp);
+
+  struct ContentPair {
+    vector<DNSRecord> content;
+    vector<shared_ptr<RRSIGRecordContent>> signatures;
+  };
+
+  map<pair<DNSName,uint16_t>, ContentPair > records;
+
+  for(const auto& r : mdp.d_answers) {
+    cout<<r.first.d_place-1<<"\t"<<r.first.d_name.toString()<<"\tIN\t"<<DNSRecordContent::NumberToType(r.first.d_type);
+    cout<<"\t"<<r.first.d_content->getZoneRepresentation()<<endl;
+
+    if(auto rrsig = getRR<RRSIGRecordContent>(r.first)) {
+      records[make_pair(r.first.d_name, rrsig->d_type)].signatures.push_back(rrsig);
+    }
+    else if(auto opt = getRR<OPTRecordContent>(r.first)) {
+      continue;
+    }
+
+    else
+      records[make_pair(r.first.d_name, r.first.d_type)].content.push_back(r.first);
+
+  }
+  cout<<"Had "<<records.size()<<" RRSETs"<<endl;
+  for(auto& rrset : records) {
+    vector<shared_ptr<DNSRecordContent> > toSign;
+    for(const auto& c : rrset.second.content) 
+      toSign.push_back(c.d_content);
+
+    for(auto& sign : rrset.second.signatures) {
+      cout<<"Seeing if we can retrieve DNSKEY for "<<sign->d_signer<<" with tag "<<sign->d_tag<<endl;
+      bool trusted=false;
+      auto keys=getKeys(sock, sign->d_signer, sign->d_tag, &trusted);
+      cout<<"Got "<<keys.size()<<" keys"<<endl;
+      for(const auto& key : keys) {
+       try {
+         auto engine = DNSCryptoKeyEngine::makeFromPublicKeyString(key.d_algorithm, key.d_key);
+         string msg = getMessageForRRSET(rrset.first.first, *sign, toSign);        
+         cout<<"Result for signature on "<<rrset.first.first<<" "<<DNSRecordContent::NumberToType(rrset.first.second)<<": "<<engine->verify(msg, sign->d_signature)<<endl;
+       }
+       catch(std::exception& e) {
+         cerr<<"Could not verify: "<<e.what()<<endl;
+         return;
+       }
+
+       if(trusted) {
+         cerr<<"This key is trusted ultimately"<<endl;
+         return;
+       }
+       else {
+         cerr<<"Should go looking for DS on DNSKEY "<<sign->d_signer<<endl;
+         lookup(dest, sign->d_signer, QType::DS);
+       }
+      }
+    }
+  }
+}
+#endif