From: Bert Hubert Date: Sun, 16 May 2010 21:00:34 +0000 (+0000) Subject: implement 'NSEC3', and enable it for NXDOMAIN responses - other cases have yet to... X-Git-Tag: rec-3.3~86 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c3c893617c977a81b93b5ef90614930187d25279;p=pdns implement 'NSEC3', and enable it for NXDOMAIN responses - other cases have yet to be hooked up. Only works for generic mysql right now. To test, run 'echo 1 0 100 ABCD > ./keys/yourdomain/nsec3param' And then run pdnssec order-zone yourdomain git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@1616 d19b8d6e-7fed-0310-83ef-9ca221ded41b --- diff --git a/modules/gmysqlbackend/gmysqlbackend.cc b/modules/gmysqlbackend/gmysqlbackend.cc index 911d03f09..c52186231 100644 --- a/modules/gmysqlbackend/gmysqlbackend.cc +++ b/modules/gmysqlbackend/gmysqlbackend.cc @@ -88,7 +88,7 @@ public: declare(suffix,"insert-slave-query","", "insert into domains (type,name,master,account) values('SLAVE','%s','%s','%s')"); declare(suffix,"insert-record-query","", "insert into records (content,ttl,prio,type,domain_id,name) values ('%s',%d,%d,'%s',%d,'%s')"); - declare(suffix,"get-order-before-query","DNSSEC Ordering Query, before", "select max(ordername) from records where ordername < '%s' and auth=1 and domain_id=%d"); + declare(suffix,"get-order-before-query","DNSSEC Ordering Query, before", "select ordername, name from records where ordername <= '%s' and auth=1 and domain_id=%d order by 1 desc limit 1"); declare(suffix,"get-order-after-query","DNSSEC Ordering Query, afer", "select min(ordername) from records where ordername > '%s' and auth=1 and domain_id=%d"); declare(suffix,"set-order-and-auth-query", "DNSSEC set ordering query", "update records set ordername='%s',auth=%d where name='%s' and domain_id='%d'"); diff --git a/pdns/backends/gsql/gsqlbackend.cc b/pdns/backends/gsql/gsqlbackend.cc index 970c2a59d..8f2f1c605 100644 --- a/pdns/backends/gsql/gsqlbackend.cc +++ b/pdns/backends/gsql/gsqlbackend.cc @@ -260,25 +260,44 @@ bool GSQLBackend::updateDNSSECOrderAndAuthAbsolute(uint32_t domain_id, const std d_db->doCommand(output); return true; } -bool GSQLBackend::getBeforeAndAfterNamesAbsolute(uint32_t id, const std::string& qname, std::string& before, std::string& after) +bool GSQLBackend::getBeforeAndAfterNamesAbsolute(uint32_t id, const std::string& qname, std::string& unhashed, std::string& before, std::string& after) { cerr<<"gsql before/after called for id="<doQuery(output); while(d_db->getRow(row)) { before=row[0]; + unhashed=row[1]; + } + + if(before.empty() && lcqname!="{") { + cerr<<"Oops, have to pick the last!"< *updatedDomains); bool getDomainInfo(const string &domain, DomainInfo &di); void setNotified(uint32_t domain_id, uint32_t serial); - virtual bool getBeforeAndAfterNamesAbsolute(uint32_t id, const std::string& qname, std::string& before, std::string& after); + virtual bool getBeforeAndAfterNamesAbsolute(uint32_t id, const std::string& qname, std::string& unhashed, std::string& before, std::string& after); bool updateDNSSECOrderAndAuth(uint32_t domain_id, const std::string& zonename, const std::string& qname, bool auth); virtual bool updateDNSSECOrderAndAuthAbsolute(uint32_t domain_id, const std::string& qname, const std::string& ordername, bool auth); diff --git a/pdns/dnsbackend.cc b/pdns/dnsbackend.cc index ad2cdc4c7..9143d1b32 100644 --- a/pdns/dnsbackend.cc +++ b/pdns/dnsbackend.cc @@ -260,7 +260,8 @@ bool DNSBackend::getBeforeAndAfterNames(uint32_t id, const std::string& zonename lcqname=makeRelative(qname, zonename); lcqname=labelReverse(lcqname); - bool ret = this->getBeforeAndAfterNamesAbsolute(id, lcqname, before, after); + string dnc; + bool ret = this->getBeforeAndAfterNamesAbsolute(id, lcqname, dnc, before, after); before=dotConcat(labelReverse(before), zonename); after=dotConcat(labelReverse(after), zonename); diff --git a/pdns/dnsbackend.hh b/pdns/dnsbackend.hh index 229b3be8c..eb30b06d4 100644 --- a/pdns/dnsbackend.hh +++ b/pdns/dnsbackend.hh @@ -74,7 +74,7 @@ public: virtual void lookup(const QType &qtype, const string &qdomain, DNSPacket *pkt_p=0, int zoneId=-1)=0; virtual bool get(DNSResourceRecord &)=0; //!< retrieves one DNSResource record, returns false if no more were available - virtual bool getBeforeAndAfterNamesAbsolute(uint32_t id, const std::string& qname, std::string& before, std::string& after) + virtual bool getBeforeAndAfterNamesAbsolute(uint32_t id, const std::string& qname, std::string& unhashed, std::string& before, std::string& after) { std::cerr<<"Default beforeAndAfterAbsolute called!"<(drc).getTag(); dsrc.d_digest.assign((const char*)hash, digest == 1 ? 20 : 32); return dsrc; } -DNSKEYRecordContent makeDNSKEYFromRSAKey(rsa_context* rc) +DNSKEYRecordContent makeDNSKEYFromRSAKey(rsa_context* rc, uint8_t algorithm) { DNSKEYRecordContent drc; char tmp[256]; @@ -176,7 +176,7 @@ DNSKEYRecordContent makeDNSKEYFromRSAKey(rsa_context* rc) drc.d_key.append(modulus); drc.d_protocol=3; - drc.d_algorithm = 5; + drc.d_algorithm = algorithm; drc.d_flags=256 + (modulus.length()>128); // oops, I just made this up.. @@ -246,6 +246,7 @@ void fillOutRRSIG(const std::string& keyrepodir, const std::string& signQName, R DNSKEYRecordContent drc =getDNSKEYFor(keyrepodir, rrc.d_signer, withKSK, &rc); rrc.d_tag = drc.getTag(); + rrc.d_algorithm = drc.d_algorithm; if(g_rrsigs.count(make_pair(hash, rrc.d_tag))) { cerr<<"RRSIG cache hit !"<& a, const shared_ptr& b); string getSHA1HashForRRSET(const std::string& qname, const RRSIGRecordContent& rrc, std::vector >& signRecords); -DNSKEYRecordContent makeDNSKEYFromRSAKey(rsa_context* rc); +DNSKEYRecordContent makeDNSKEYFromRSAKey(rsa_context* rc, uint8_t algorithm); DSRecordContent makeDSFromDNSKey(const std::string& qname, const DNSKEYRecordContent& drc, int digest=1); bool getSignerFor(const std::string& keyrepodir, const std::string& qname, std::string &signer); diff --git a/pdns/dnsseckeeper.cc b/pdns/dnsseckeeper.cc index 5e75ae88f..996767047 100644 --- a/pdns/dnsseckeeper.cc +++ b/pdns/dnsseckeeper.cc @@ -141,6 +141,53 @@ void DNSSECKeeper::deleteZSKFor(const std::string& zname, const std::string& fna unlink((d_dirname +"/"+ zname +"/zsks/"+fname).c_str()); } +bool DNSSECKeeper::getNSEC3PARAM(const std::string& zname, NSEC3PARAMRecordContent* ns3p) +{ + fs::path full_path = fs::system_complete( fs::path(d_dirname + "/" + zname + "/nsec3param" ) ); + ifstream ifs(full_path.external_directory_string().c_str()); + cerr<<"called for nsec3param..."<(DNSRecordContent::mastermake(QType::NSEC3PARAM, 1, descr)); + if(!tmp) { + cerr<<"Could not parse "<< full_path.external_directory_string() <d_salt)<d_algorithm=1; + ns3p->d_iterations= 100; + ns3p->d_salt.assign("\xab\xcd", 2); + ns3p->d_saltlength=2; + ns3p->d_flags=0; + */ + } + return true; +} + +void DNSSECKeeper::setNSEC3PARAM(const std::string& zname, const NSEC3PARAMRecordContent* ns3p) +{ + fs::path full_path = fs::system_complete( fs::path(d_dirname + "/" + zname + "/nsec3param" ) ); + if(ns3p) { + string descr = ns3p->getZoneRepresentation(); + + + ofstream of(full_path.external_directory_string().c_str()); + of << descr; + } + else { + unlink(full_path.external_directory_string().c_str()); + } +} + + DNSSECKeeper::zskset_t DNSSECKeeper::getZSKsFor(const std::string& zone, bool all) { zskset_t zskset; @@ -160,6 +207,13 @@ DNSSECKeeper::zskset_t DNSSECKeeper::getZSKsFor(const std::string& zone, bool al //cerr<<"Hit!"<path().file_string().c_str()); + + if(getNSEC3PARAM(zone)) { + dpk.d_algorithm = 7; + } + else { + dpk.d_algorithm = 5; + } struct tm ts1, ts2; @@ -194,7 +248,7 @@ DNSSECKeeper::zskset_t DNSSECKeeper::getZSKsFor(const std::string& zone, bool al DNSKEYRecordContent DNSSECPrivateKey::getDNSKEY() { - return makeDNSKEYFromRSAKey(&d_key.getContext()); + return makeDNSKEYFromRSAKey(&d_key.getContext(), d_algorithm); } diff --git a/pdns/dnsseckeeper.hh b/pdns/dnsseckeeper.hh index f2b027218..3ac5b372c 100644 --- a/pdns/dnsseckeeper.hh +++ b/pdns/dnsseckeeper.hh @@ -76,6 +76,7 @@ struct DNSSECPrivateKey RSAContext d_key; DNSKEYRecordContent getDNSKEY(); + uint8_t d_algorithm; }; class DNSSECKeeper @@ -97,8 +98,8 @@ public: void deleteZSKFor(const std::string& zname, const std::string& fname); void addZone(const std::string& fname); - - + bool getNSEC3PARAM(const std::string& zname, NSEC3PARAMRecordContent* n3p=0); + void setNSEC3PARAM(const std::string& zname, const NSEC3PARAMRecordContent* n3p); private: std::string d_dirname; diff --git a/pdns/packethandler.cc b/pdns/packethandler.cc index 437c92153..15792f55e 100644 --- a/pdns/packethandler.cc +++ b/pdns/packethandler.cc @@ -197,19 +197,19 @@ int PacketHandler::doFancyRecords(DNSPacket *p, DNSPacket *r, string &target) return 0; } -/** This catches version requests. Returns 1 if it was handled, 0 if it wasn't */ +/** This catches DNSKEY requests. Returns 1 if it was handled, 0 if it wasn't */ int PacketHandler::doDNSKEYRequest(DNSPacket *p, DNSPacket *r) { + if(p->qtype.getCode()!=QType::DNSKEY) + return false; + DNSResourceRecord rr; DNSSECKeeper dk(::arg()["key-repository"]); - if(p->qtype.getCode()!=QType::DNSKEY) - return false; bool haveOne=false; DNSSECPrivateKey dpk; - if(dk.haveKSKFor(p->qdomain, &dpk)) { rr.qtype=QType::DNSKEY; rr.ttl=3600; @@ -236,6 +236,29 @@ int PacketHandler::doDNSKEYRequest(DNSPacket *p, DNSPacket *r) } +/** This catches DNSKEY requests. Returns 1 if it was handled, 0 if it wasn't */ +int PacketHandler::doNSEC3PARAMRequest(DNSPacket *p, DNSPacket *r) +{ + if(p->qtype.getCode()!=QType::NSEC3PARAM) + return false; + + DNSResourceRecord rr; + DNSSECKeeper dk(::arg()["key-repository"]); + + NSEC3PARAMRecordContent ns3prc; + if(dk.getNSEC3PARAM(p->qdomain, &ns3prc)) { + rr.qtype=QType::NSEC3PARAM; + rr.ttl=3600; + rr.qname=p->qdomain; + rr.content=ns3prc.getZoneRepresentation(); + rr.auth = true; + r->addRecord(rr); + return true; + } + return false; +} + + /** This catches version requests. Returns 1 if it was handled, 0 if it wasn't */ int PacketHandler::doVersionRequest(DNSPacket *p, DNSPacket *r, string &target) { @@ -464,21 +487,25 @@ void PacketHandler::emitNSEC(const std::string& begin, const std::string& end, c r->addRecord(rr); } -void PacketHandler::emitNSEC3(NSEC3PARAMRecordContent *ns3rc, const std::string& auth, const std::string& begin, const std::string& end, const std::string& toNSEC3, DNSPacket *r, int mode) +void PacketHandler::emitNSEC3(const NSEC3PARAMRecordContent& ns3prc, const std::string& auth, const std::string& unhashed, const std::string& begin, const std::string& end, const std::string& toNSEC3, DNSPacket *r, int mode) { cerr<<"We should emit NSEC3 '"<d_salt; - n3rc.d_iterations = ns3rc->d_iterations; - n3rc.d_algorithm = 1; + n3rc.d_salt=ns3prc.d_salt; + n3rc.d_flags = 0; + n3rc.d_iterations = ns3prc.d_iterations; + n3rc.d_algorithm = 1; // ? DNSResourceRecord rr; - B.lookup(QType(QType::ANY), begin); + B.lookup(QType(QType::ANY), unhashed); while(B.get(rr)) { n3rc.d_set.insert(rr.qtype.getCode()); } + + if(unhashed == auth) { + n3rc.d_set.insert(QType::NSEC3PARAM); + } n3rc.d_nexthash=end; @@ -502,38 +529,46 @@ void PacketHandler::emitNSEC3(NSEC3PARAMRecordContent *ns3rc, const std::string& */ void PacketHandler::addNSECX(DNSPacket *p, DNSPacket *r, const string& target, const string& auth, int mode) { + DNSSECKeeper dk(::arg()["key-repository"]); + NSEC3PARAMRecordContent ns3rc; cerr<<"Doing NSEC3PARAM lookup for '"<(DNSRecordContent::mastermake(QType::NSEC3PARAM, 1, nsec3param.content)); - string hashed=toBase32Hex(hashQNameWithSalt(ns3rc->d_iterations, ns3rc->d_salt, p->qdomain)); - cerr<<"NSEC3 hash, "<d_iterations<<" iterations, salt '"<d_salt)<<"': "<getBeforeAndAfterNamesAbsolute(sd.domain_id, hashed, before, after); - cerr<<"Done calling, before='"<getBeforeAndAfterNamesAbsolute(sd.domain_id, hashed, unhashed, before, after); + cerr<<"Done calling for closest encloser, before='"<qdomain)); + sd.db->getBeforeAndAfterNamesAbsolute(sd.domain_id, hashed, unhashed, before, after); + cerr<<"Done calling for main, before='"<getBeforeAndAfterNamesAbsolute(sd.domain_id, hashed, unhashed, before, after); + cerr<<"Done calling for '*', before='"< '"<< hashed <<"'"<updateDNSSECOrderAndAuthAbsolute(sd.domain_id, qname, hashed, true); - // sd.db->updateDNSSECOrderAndAuth(sd.domain_id, zone, qname, true); + if(ns3pr.d_salt.empty()) // NSEC + sd.db->updateDNSSECOrderAndAuth(sd.domain_id, zone, qname, true); + else { + hashed=toLower(toBase32Hex(hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, qname))); + cerr<<"'"< '"<< hashed <<"'"<updateDNSSECOrderAndAuthAbsolute(sd.domain_id, qname, hashed, true); + } } cerr<<"Done listing"< >(); if(cmds.empty() || g_vm.count("help")) { - cerr<<"Usage: \npdnssec [options] [show-zone] [sign-zone] [update-zone-keys]\n"; + cerr<<"Usage: \npdnssec [options] [show-zone] [secure-zone] [alter-zone] [order-zone] [update-zone-keys]\n"; cerr<