From: bert hubert Date: Thu, 5 Nov 2015 08:58:33 +0000 (+0100) Subject: and the actual toysdig X-Git-Tag: dnsdist-1.0.0-alpha1~187^2~10 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5bb846feb0b4ebc9c2e9882c45368518248aeb9a;p=pdns and the actual toysdig --- diff --git a/pdns/Makefile.am b/pdns/Makefile.am index 41fe9a0ca..078e23245 100644 --- a/pdns/Makefile.am +++ b/pdns/Makefile.am @@ -721,10 +721,13 @@ toysdig_SOURCES = \ dnslabeltext.cc \ dnsparser.cc dnsparser.hh \ dnsrecords.cc \ + dnssecinfra.cc \ dnswriter.cc dnswriter.hh \ ednssubnet.cc ednssubnet.hh \ + gss_context.cc gss_context.hh \ logger.cc \ mbedtlscompat.hh \ + mbedtlssigners.cc \ misc.cc misc.hh \ nsecrecords.cc \ qtype.cc \ @@ -736,7 +739,12 @@ toysdig_SOURCES = \ toysdig.cc \ unix_utility.cc + toysdig_LDADD = $(MBEDTLS_LIBS) +if GSS_TSIG +toysdig_LDADD += $(GSS_LIBS) +endif + tsig_tests_SOURCES = \ arguments.cc \ diff --git a/pdns/toysdig.cc b/pdns/toysdig.cc index 5db9b7036..0b7d39506 100644 --- a/pdns/toysdig.cc +++ b/pdns/toysdig.cc @@ -8,44 +8,634 @@ #include "dnsrecords.hh" #include "statbag.hh" #include "ednssubnet.hh" +#include "dnssecinfra.hh" +#include "recursor_cache.hh" +#include "base32.hh" StatBag S; +class TCPResolver : public boost::noncopyable +{ +public: + TCPResolver(ComboAddress addr) : d_rsock(AF_INET, SOCK_STREAM) + { + d_rsock.connect(addr); + } + + string query(const DNSName& qname, uint16_t qtype) + { + cerr<<"Q "< packet; + DNSPacketWriter pw(packet, qname, qtype); + + // recurse + pw.getHeader()->rd=true; + + // we'll do the validation + pw.getHeader()->cd=true; + pw.getHeader()->ad=true; + + // we do require DNSSEC records to do that! + pw.addOpt(2800, 0, EDNSOpts::DNSSECOK); + pw.commit(); + + uint16_t len; + len = htons(packet.size()); + if(d_rsock.write((char *) &len, 2) != 2) + throw PDNSException("tcp write failed"); + + d_rsock.writen(string((char*)&*packet.begin(), (char*)&*packet.end())); + + if(d_rsock.read((char *) &len, 2) != 2) + throw PDNSException("tcp read failed"); + + len=ntohs(len); + char *creply = new char[len]; + int n=0; + int numread; + while(n g_anchors; + +vector getKeys(Socket& sock, const DNSName& name, uint16_t tag, bool* trusted) +{ + *trusted=false; + vector 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 ret; + shared_ptr root; + for(const auto& r : mdp.d_answers) { + cout<getZoneRepresentation()<(r.first)) { + if(dk->getTag() == tag) { + cout<<"Found key with tag "<getTag()<getTag()<<" and DS "; + auto ds=makeDSFromDNSKey(name, *dk, 2); + cout<(r.first)) { + if(root) { + cout<<"Had a signature on "<d_tag<d_tag<d_algorithm, root->d_key); + vector> toSign; + toSign.push_back(std::make_shared(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< getMDP(const ComboAddress& dest, const DNSName& qname, uint16_t qtype) +{ + TCPResolver tr(dest); + + string resp=tr.query(qname, qtype); + return unique_ptr(new 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 ;-)"< 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 content; + vector> signatures; + }; + + map, ContentPair > records; + + for(const auto& r : mdp.d_answers) { + cout<getZoneRepresentation()<(r.first)) { + records[make_pair(r.first.d_name, rrsig->d_type)].signatures.push_back(rrsig); + } + else if(auto opt = getRR(r.first)) { + continue; + } + + else + records[make_pair(r.first.d_name, r.first.d_type)].content.push_back(r.first); + + } + cout<<"Had "< > 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 "<d_signer<<" with tag "<d_tag<d_signer, sign->d_tag, &trusted); + cout<<"Got "<verify(msg, sign->d_signature)<d_signer<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 keymap_t; + + +string nsec3Hash(const DNSName &qname, const NSEC3RecordContent& nrc) +{ + NSEC3PARAMRecordContent ns3pr; + ns3pr.d_iterations = nrc.d_iterations; + ns3pr.d_salt = nrc.d_salt; + return toBase32Hex(hashQNameWithSalt(ns3pr, qname)); +} + + + + +typedef map, set > > rrsetmap_t; + +typedef pair NT; // Name/Type pair +typedef std::multimap > recmap_t; +typedef std::multimap sigmap_t; +typedef std::multimap > nsecmap_t; + +typedef pair ZT; //Zonename/keyTag pair +// recmap_t g_recs; // fetched recs for full chain validation +// keymap_t g_keys; // fetched keys +// 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) +{ + std::multimap nsec3s; + + for(rrsetmap_t::const_iterator i=validrrsets.begin(); i!=validrrsets.end(); ++i) + { + // FIXME also support NSEC + if(i->first.second != QType::NSEC3) continue; + + for(set >::const_iterator j=i->second.begin(); j!=i->second.end(); ++j) { + NSEC3RecordContent ns3r = dynamic_cast (**j); + // nsec3.insert(new nsec3() + // cerr<first.first, ns3r)); + } + } + cerr<<"got "< parts = i->first.getRawLabels(); + + string base=toLower(parts[0]); + string next=toLower(toBase32Hex(i->second.d_nexthash)); + string hashed = nsec3Hash(qname, i->second); + cerr<second.d_set.count(qtype)<second.d_set.count(qtype) == 0) return INSECURE; // FIXME need to require 'NS in bitmap' here, otherwise no delegation! (but first, make sure this is reliable - does not work that way for direct auth queries) + } else if ((hashed > base && hashed < next) || + (next < base && (hashed < next || hashed > base))) { + bool optout=(1 & i->second.d_flags); + cerr<<"negative name proof, optout = "< " + <first.first)<<"/"<first.second)< 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 >::const_iterator k=j->second.begin(); k!=j->second.end(); k++) { + vector > toSign; + set > rrs = rrsets[make_pair(j->first.first, j->first.second)]; + toSign.assign(rrs.begin(), rrs.end()); + + const RRSIGRecordContent rrc=dynamic_cast (*(*k)); + + if(!keys.count(rrc.d_tag)) continue; + + string msg=getMessageForRRSET(j->first.first, rrc, toSign); + pair 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); + if(isValid) { + validated[make_pair(j->first.first, j->first.second)] = rrs; + cerr<<"valid"<first.first<<"/"<(rrc.d_tag), + DNSRecordContent::NumberToType(rrc.d_type), j->first.first, "", isValid ? "green" : "red"); + */ + } + // FIXME: break out enough levels + } + } + } + } +} + +// returns vState +// should return vState, zone cut and validated keyset +// i.e. www.7bits.nl -> insecure/7bits.nl/[] +// www.powerdnssec.org -> secure/powerdnssec.org/[keys] +// www.dnssec-failed.org -> bogus/dnssec-failed.org/[] + +char *rootDS; + +vState getKeysFor(TCPResolver& tr, const DNSName& zone, keymap_t &keyset) +{ + vector labels = zone.getRawLabels(); + vState state; + + state = Indeterminate; + + DNSName qname; + typedef std::multimap dsmap_t; + dsmap_t dsmap; + keymap_t keymap; + recmap_t recs; + + state = Secure; + while(zone.isPartOf(qname)) + { + if(qname.isRoot()) + { + DSRecordContent rootanchor=dynamic_cast (*(DNSRecordContent::mastermake(QType::DS, 1, rootDS))); + dsmap.clear(); + dsmap.insert(make_pair(rootanchor.d_tag, rootanchor)); + } + + recs.clear(); + vector sigs; + vector > toSign; + vector toSignTags; + + keymap_t tkeymap; // tentative keys + keymap.clear(); + + // start of this iteration + // we can trust that dsmap has valid DS records for qname + + cerr<<"got DS for ["<first.d_name != qname) + continue; + + if(i->first.d_type == QType::RRSIG) + { + RRSIGRecordContent rrc=dynamic_cast (*(i->first.d_content)); + if(rrc.d_type != QType::DNSKEY) + continue; + sigs.push_back(rrc); + } + else if(i->first.d_type == QType::DNSKEY) + { + DNSKEYRecordContent drc=dynamic_cast (*(i->first.d_content)); + tkeymap.insert(make_pair(drc.getTag(), drc)); + // dotNode("DNSKEY", qname, lexical_cast(drc.getTag()), (boost::format("tag=%d, algo=%d") % drc.getTag() % static_cast(drc.d_algorithm)).str()); + + toSign.push_back(i->first.d_content); + toSignTags.push_back(drc.getTag()); + } + } + cerr<<"got "<second; + cerr<<"got DS with tag "<first<<", got "<first)<<" DNSKEYs for tag"< 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; + if(isValid) { + cerr<<"got valid DNSKEY"<(dsrc.d_tag)*/, (boost::format("tag=%d, digest algo=%d, algo=%d") % dsrc.d_tag % static_cast(dsrc.d_digesttype) % static_cast(dsrc.d_algorithm)).str()); + } + // cout<<" subgraph "< "<(dsrc.d_digesttype)<<"\" ]; label = \"zone: "<(dsrc.d_tag)*/, "DNSKEY", qname, lexical_cast(drc.getTag()), isValid ? "green" : "red"); + // dotNode("DNSKEY", qname, (boost::format("tag=%d, algo=%d") % drc.getTag() % static_cast(drc.d_algorithm)).str()); + } + } + + cerr<<"got "<d_tag<<" matching "<d_tag)<<" keys of which "<d_tag)<<" valid"< r = keymap.equal_range(i->d_tag); + for(keymap_t::const_iterator j=r.first; j!=r.second; j++) { + cerr<<"validating"<second.d_algorithm, j->second.d_key)->verify(msg, i->d_signature); + // for(uint16_t tag : toSignTags) { + // dotEdge(qname, + // "DNSKEY", qname, lexical_cast(i->d_tag), + // "DNSKEY", qname, lexical_cast(tag), isValid ? "green" : "red"); + // } + + if(isValid) + { + cerr<<"validation succeeded - whole DNSKEY set is valid"<d_signer))<<" -> "<first.d_name<<"/"<first.d_type<first.d_type == QType::OPT) continue; + + if(i->first.d_type == QType::RRSIG) { + RRSIGRecordContent rrc = dynamic_cast (*(i->first.d_content)); + rrsigs[make_pair(i->first.d_name,rrc.d_type)].insert(i->first.d_content); + } + else { + rrsets[make_pair(i->first.d_name,i->first.d_type)].insert(i->first.d_content); + } + } + + rrsetmap_t validrrsets; + validateWithKeySet(rrsets, rrsigs, validrrsets, keymap); + + cerr<<"got "< >::const_iterator j=i->second.begin(); j!=i->second.end(); j++) + { + const DSRecordContent dsrc=dynamic_cast (**j); + dsmap.insert(make_pair(dsrc.d_tag, dsrc)); + // dotEdge(keyqname, + // "DNSKEY", keyqname, , + // "DS", qname, lexical_cast(dsrc.d_tag)); + // cout<<" "< "< packet; - string qname; + auto mdp=getMDP(dest, qname, qtype); - if(!(n%20)) - qname=boost::lexical_cast(n)+".ds9a.nl"; - else - qname=boost::lexical_cast(n)+"."+argv[3]; - - DNSPacketWriter pw(packet, DNSName(qname), DNSRecordContent::TypeToNumber(argv[4])); + rrsetmap_t rrsets; + rrsetmap_t rrsigs; - pw.getHeader()->rd=1; + for(auto i = mdp->d_answers.begin(); i != mdp->d_answers.end(); ++i) { + cerr<<"res "<first.d_name<<"/"<first.d_type<first.d_type == QType::OPT) continue; - pw.getHeader()->id=n; - pw.addOpt(1800, 0, EDNSOpts::DNSSECOK); - pw.commit(); + if(i->first.d_type == QType::RRSIG) { + RRSIGRecordContent rrc = dynamic_cast (*(i->first.d_content)); + rrsigs[make_pair(i->first.d_name,rrc.d_type)].insert(i->first.d_content); + } + else { + rrsets[make_pair(i->first.d_name,i->first.d_type)].insert(i->first.d_content); + } + } + + cerr<<"got "< r = rrsigs.equal_range(make_pair(qname, qtype)); + cerr<<"got "< >::const_iterator j=i->second.begin(); j!=i->second.end(); j++) + { + cerr<<"B"< (*(*j)); + cerr<<"got rrsig "<first.first<<"/"<first.second)< >::const_iterator j=i->second.begin(); j!=i->second.end(); j++) { + cerr<<"% > "<<(*j)->getZoneRepresentation()<