From 98c9ec39088d02c557065d65a02bd2181f7ba584 Mon Sep 17 00:00:00 2001 From: bert hubert Date: Thu, 7 Jan 2016 23:13:43 +0100 Subject: [PATCH] Introduce TSIGTriple struct, hook up IXFR config in recursor to TSIG code for IXFR merge the triplet 'tsigname, tsigalgo, tsigsecret' into a handy TSIGTriplet, and move most of the TSIG apis to this struct. --- pdns/dns.hh | 12 ++++++++---- pdns/ixfr.cc | 8 ++++---- pdns/ixfr.hh | 2 +- pdns/ixplore.cc | 24 ++++++++++++------------ pdns/rec-lua-conf.cc | 21 ++++++++++++++++++--- pdns/reczones.cc | 7 ++++--- pdns/resolver.cc | 38 ++++++++++++++++++-------------------- pdns/resolver.hh | 11 ++++------- pdns/rpzloader.cc | 16 ++++++++++------ pdns/rpzloader.hh | 4 ++-- pdns/slavecommunicator.cc | 17 +++++++++-------- 11 files changed, 90 insertions(+), 70 deletions(-) diff --git a/pdns/dns.hh b/pdns/dns.hh index cdd8fa042..1125b8d2a 100644 --- a/pdns/dns.hh +++ b/pdns/dns.hh @@ -1,6 +1,6 @@ /* PowerDNS Versatile Database Driven Nameserver - Copyright (C) 2002 - 2011 PowerDNS.COM BV + Copyright (C) 2002 - 2016 PowerDNS.COM BV This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 @@ -19,8 +19,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -// $Id$ -/* (C) 2002 POWERDNS.COM BV */ + #pragma once #include #include @@ -32,7 +31,6 @@ #include #include class DNSBackend; -class DNSName; // FIXME400 struct SOAData { @@ -330,6 +328,12 @@ inline bool dnspacketLessThan(const std::string& a, const std::string& b) } +struct TSIGTriplet +{ + DNSName name, algo; + string secret; +}; + /** for use by DNSPacket, converts a SOAData class to a ascii line again */ string serializeSOAData(const SOAData &data); string &attodot(string &str); //!< for when you need to insert an email address in the SOA diff --git a/pdns/ixfr.cc b/pdns/ixfr.cc index ca31143ce..c9bb5e48f 100644 --- a/pdns/ixfr.cc +++ b/pdns/ixfr.cc @@ -4,7 +4,7 @@ #include "dnsrecords.hh" #include "dnssecinfra.hh" -vector, vector > > getIXFRDeltas(const ComboAddress& master, const DNSName& zone, const DNSRecord& oursr, const DNSName& tsigalgo, const DNSName& tsigname, const std::string& tsigsecret) +vector, vector > > getIXFRDeltas(const ComboAddress& master, const DNSName& zone, const DNSRecord& oursr, const TSIGTriplet& tt) { vector, vector > > ret; vector packet; @@ -16,14 +16,14 @@ vector, vector > > getIXFRDeltas(const Combo oursr.d_content->toPacket(pw); pw.commit(); - if(!tsigalgo.empty()) { + if(!tt.algo.empty()) { TSIGRecordContent trc; - trc.d_algoName = tsigalgo; + trc.d_algoName = tt.algo; trc.d_time = time((time_t*)NULL); trc.d_fudge = 300; trc.d_origID=ntohs(pw.getHeader()->id); trc.d_eRcode=0; - addTSIG(pw, &trc, tsigname, tsigsecret, "", false); + addTSIG(pw, &trc, tt.name, tt.secret, "", false); } uint16_t len=htons(packet.size()); string msg((const char*)&len, 2); diff --git a/pdns/ixfr.hh b/pdns/ixfr.hh index 40d70659c..db708586c 100644 --- a/pdns/ixfr.hh +++ b/pdns/ixfr.hh @@ -3,4 +3,4 @@ #include "dnsparser.hh" vector, vector > > getIXFRDeltas(const ComboAddress& master, const DNSName& zone, const DNSRecord& sr, - const DNSName& tsigalgo=DNSName(), const DNSName& tsigname=DNSName(), const std::string& tsigsecret=""); + const TSIGTriplet& tt=TSIGTriplet()); diff --git a/pdns/ixplore.cc b/pdns/ixplore.cc index 4e77c22de..ca663495e 100644 --- a/pdns/ixplore.cc +++ b/pdns/ixplore.cc @@ -56,18 +56,18 @@ typedef multi_index_container< > >records_t; -uint32_t getSerialFromMaster(const ComboAddress& master, const DNSName& zone, shared_ptr& sr, const DNSName& tsigalgo=DNSName(), const DNSName& tsigname=DNSName(), const std::string& tsigsecret="") +uint32_t getSerialFromMaster(const ComboAddress& master, const DNSName& zone, shared_ptr& sr, const TSIGTriplet& tt = TSIGTriplet()) { vector packet; DNSPacketWriter pw(packet, zone, QType::SOA); - if(!tsigalgo.empty()) { + if(!tt.algo.empty()) { TSIGRecordContent trc; - trc.d_algoName = tsigalgo; + trc.d_algoName = tt.algo; trc.d_time = time((time_t*)NULL); trc.d_fudge = 300; trc.d_origID=ntohs(pw.getHeader()->id); trc.d_eRcode=0; - addTSIG(pw, &trc, tsigname, tsigsecret, "", false); + addTSIG(pw, &trc, tt.name, tt.secret, "", false); } Socket s(master.sin4.sin_family, SOCK_DGRAM); @@ -229,14 +229,14 @@ try cout<<"Loading zone, our highest available serial is "<< ourSerial< 6) - tsigkey=DNSName(toLower(argv[6])); + tt.name=DNSName(toLower(argv[6])); if(argc > 7) - tsigalgo=DNSName(toLower(argv[7])); - string tsigsecret; + tt.algo=DNSName(toLower(argv[7])); + if(argc > 8) { - if(B64Decode(argv[8], tsigsecret) < 0) { + if(B64Decode(argv[8], tt.secret) < 0) { cerr<<"Could not decode tsig secret!"< chunk; @@ -288,7 +288,7 @@ try cout<<"Checking for update, our serial number is "< sr; - uint32_t serial = getSerialFromMaster(master, zone, sr, tsigalgo, tsigkey, tsigsecret); + uint32_t serial = getSerialFromMaster(master, zone, sr, tt); if(ourSerial == serial) { cout<<"still up to date, their serial is "<d_st.refresh<<" seconds"<d_st.refresh); @@ -296,7 +296,7 @@ try } cout<<"got new serial: "< g_luaconfs; @@ -119,8 +120,11 @@ void loadRecursorLuaConfig(const std::string& fname) Lua.writeFunction("rpzMaster", [&lci](const string& master_, const string& zone_, const boost::optional>>& options) { try { boost::optional defpol; + TSIGTriplet tt; + int refresh=0; if(options) { auto& have = *options; + if(have.count("defpol")) { // cout<<"Set a default policy"<(constGet(have, "tsigname")))); + tt.algo=DNSName(toLower(boost::get(constGet(have, "tsigalgo")))); + if(B64Decode(boost::get(constGet(have, "tsigsecret")), tt.secret)) + throw std::runtime_error("TSIG secret is not valid Base-64 encoded"); + } + if(have.count("refresh")) { + refresh = boost::get(constGet(have,"refresh")); + } } ComboAddress master(master_, 53); DNSName zone(zone_); - auto sr=loadRPZFromServer(master,zone, lci.dfe, defpol, 0); - std::thread t(RPZIXFRTracker, master, zone, sr); + + auto sr=loadRPZFromServer(master,zone, lci.dfe, defpol, 0, tt); + if(refresh) + sr->d_st.refresh=refresh; + std::thread t(RPZIXFRTracker, master, zone, tt, sr); t.detach(); } catch(std::exception& e) { diff --git a/pdns/reczones.cc b/pdns/reczones.cc index 8590c5ae3..9861a7183 100644 --- a/pdns/reczones.cc +++ b/pdns/reczones.cc @@ -317,17 +317,18 @@ string reloadAuthAndForwards() } -void RPZIXFRTracker(const ComboAddress& master, const DNSName& zone, shared_ptr oursr) +void RPZIXFRTracker(const ComboAddress& master, const DNSName& zone, const TSIGTriplet& tt, shared_ptr oursr) { + int refresh = oursr->d_st.refresh; for(;;) { DNSRecord dr; dr.d_content=oursr; - sleep(oursr->d_st.refresh); + sleep(refresh); L<(dr.d_content)->d_st.serial<id = dns_random(0xffff); - if(!tsigkeyname.empty()) { - if (tsigalgorithm == DNSName("hmac-md5")) - d_trc.d_algoName = tsigalgorithm + DNSName("sig-alg.reg.int"); + if(!tt.name.empty()) { + if (tt.algo == DNSName("hmac-md5")) + d_trc.d_algoName = tt.algo + DNSName("sig-alg.reg.int"); else - d_trc.d_algoName = tsigalgorithm; + d_trc.d_algoName = tt.algo; d_trc.d_time = time(0); d_trc.d_fudge = 300; d_trc.d_origID=ntohs(pw.getHeader()->id); d_trc.d_eRcode=0; - addTSIG(pw, &d_trc, tsigkeyname, tsigsecret, "", false); + addTSIG(pw, &d_trc, tt.name, tt.secret, "", false); } uint16_t replen=htons(packet.size()); @@ -471,7 +469,7 @@ int AXFRRetriever::getChunk(Resolver::res_t &res, vector* records) // if (answer.first.d_type == QType::SOA) d_soacount++; - if(!d_tsigkeyname.empty()) { // TSIG verify message + if(!d_tt.name.empty()) { // TSIG verify message // If we have multiple messages, we need to concatenate them together. We also need to make sure we know the location of // the TSIG record so we can remove it in makeTSIGMessageFromTSIGPacket d_signData.append(d_buf.get(), len); @@ -501,13 +499,13 @@ int AXFRRetriever::getChunk(Resolver::res_t &res, vector* records) // if (checkTSIG) { if (theirMac.empty()) - throw ResolverException("No TSIG on AXFR response from "+d_remote.toStringWithPort()+" , should be signed with TSIG key '"+d_tsigkeyname.toString()+"'"); + throw ResolverException("No TSIG on AXFR response from "+d_remote.toStringWithPort()+" , should be signed with TSIG key '"+d_tt.name.toString()+"'"); string message; if (!d_prevMac.empty()) { - message = makeTSIGMessageFromTSIGPacket(d_signData, d_tsigPos, d_tsigkeyname, d_trc, d_prevMac, true, d_signData.size()-len); + message = makeTSIGMessageFromTSIGPacket(d_signData, d_tsigPos, d_tt.name, d_trc, d_prevMac, true, d_signData.size()-len); } else { - message = makeTSIGMessageFromTSIGPacket(d_signData, d_tsigPos, d_tsigkeyname, d_trc, d_trc.d_mac, false); + message = makeTSIGMessageFromTSIGPacket(d_signData, d_tsigPos, d_tt.name, d_trc, d_trc.d_mac, false); } TSIGHashEnum algo; @@ -516,16 +514,16 @@ int AXFRRetriever::getChunk(Resolver::res_t &res, vector* records) // } if (algo == TSIG_GSS) { - GssContext gssctx(d_tsigkeyname); - if (!gss_verify_signature(d_tsigkeyname, message, theirMac)) { - throw ResolverException("Signature failed to validate on AXFR response from "+d_remote.toStringWithPort()+" signed with TSIG key '"+d_tsigkeyname.toString()+"'"); + GssContext gssctx(d_tt.name); + if (!gss_verify_signature(d_tt.name, message, theirMac)) { + throw ResolverException("Signature failed to validate on AXFR response from "+d_remote.toStringWithPort()+" signed with TSIG key '"+d_tt.name.toString()+"'"); } } else { - string ourMac=calculateHMAC(d_tsigsecret, message, algo); + string ourMac=calculateHMAC(d_tt.secret, message, algo); // ourMac[0]++; // sabotage == for testing :-) if(ourMac != theirMac) { - throw ResolverException("Signature failed to validate on AXFR response from "+d_remote.toStringWithPort()+" signed with TSIG key '"+d_tsigkeyname.toString()+"'"); + throw ResolverException("Signature failed to validate on AXFR response from "+d_remote.toStringWithPort()+" signed with TSIG key '"+d_tt.name.toString()+"'"); } } diff --git a/pdns/resolver.hh b/pdns/resolver.hh index 1a234c682..24e45454d 100644 --- a/pdns/resolver.hh +++ b/pdns/resolver.hh @@ -84,11 +84,9 @@ class AXFRRetriever : public boost::noncopyable { public: AXFRRetriever(const ComboAddress& remote, - const DNSName& zone, - const DNSName& tsigkeyname=DNSName(), - const DNSName& tsigalgorithm=DNSName(), - const string& tsigsecret=string(), - const ComboAddress* laddr = NULL); + const DNSName& zone, + const TSIGTriplet& tt = TSIGTriplet(), + const ComboAddress* laddr = NULL); ~AXFRRetriever(); int getChunk(Resolver::res_t &res, vector* records=0); @@ -103,8 +101,7 @@ class AXFRRetriever : public boost::noncopyable int d_soacount; ComboAddress d_remote; - DNSName d_tsigkeyname; - string d_tsigsecret; + TSIGTriplet d_tt; string d_prevMac; // RFC2845 4.4 string d_signData; uint32_t d_tsigPos; diff --git a/pdns/rpzloader.cc b/pdns/rpzloader.cc index 0784b1c32..1cc909f18 100644 --- a/pdns/rpzloader.cc +++ b/pdns/rpzloader.cc @@ -97,11 +97,14 @@ void RPZRecordToPolicy(const DNSRecord& dr, DNSFilterEngine& target, bool addOrR } } -shared_ptr loadRPZFromServer(const ComboAddress& master, const DNSName& zone, DNSFilterEngine& target, boost::optional defpol, int place) +shared_ptr loadRPZFromServer(const ComboAddress& master, const DNSName& zone, DNSFilterEngine& target, boost::optional defpol, int place, const TSIGTriplet& tt) { L< chunk; @@ -109,14 +112,15 @@ shared_ptr loadRPZFromServer(const ComboAddress& master, const shared_ptr sr; while(axfr.getChunk(nop, &chunk)) { for(auto& dr : chunk) { + if(dr.d_type==QType::NS || dr.d_type==QType::TSIG) { + continue; + } + dr.d_name.makeUsRelative(zone); if(dr.d_type==QType::SOA) { sr = std::dynamic_pointer_cast(dr.d_content); continue; } - if(dr.d_type==QType::NS) { - continue; - } RPZRecordToPolicy(dr, target, true, defpol, place); nrecords++; diff --git a/pdns/rpzloader.hh b/pdns/rpzloader.hh index 42b8fba11..113410188 100644 --- a/pdns/rpzloader.hh +++ b/pdns/rpzloader.hh @@ -4,6 +4,6 @@ #include "dnsrecords.hh" int loadRPZFromFile(const std::string& fname, DNSFilterEngine& target, boost::optional defpol, int place); -std::shared_ptr loadRPZFromServer(const ComboAddress& master, const DNSName& zone, DNSFilterEngine& target, boost::optional defpol, int place); +std::shared_ptr loadRPZFromServer(const ComboAddress& master, const DNSName& zone, DNSFilterEngine& target, boost::optional defpol, int place, const TSIGTriplet& tt); void RPZRecordToPolicy(const DNSRecord& dr, DNSFilterEngine& target, bool addOrRemove, boost::optional defpol, int place); -void RPZIXFRTracker(const ComboAddress& master, const DNSName& zone, shared_ptr oursr); +void RPZIXFRTracker(const ComboAddress& master, const DNSName& zone, const TSIGTriplet &tt, shared_ptr oursr); diff --git a/pdns/slavecommunicator.cc b/pdns/slavecommunicator.cc index 0e261a8a9..c4956410d 100644 --- a/pdns/slavecommunicator.cc +++ b/pdns/slavecommunicator.cc @@ -81,15 +81,16 @@ void CommunicatorClass::suck(const DNSName &domain,const string &remote) } uint32_t domain_id=di.id; - - DNSName tsigkeyname, tsigalgorithm; - string tsigsecret; - if(dk.getTSIGForAccess(domain, remote, &tsigkeyname)) { + TSIGTriplet tt; + if(dk.getTSIGForAccess(domain, remote, &tt.name)) { string tsigsecret64; - if(B.getTSIGKey(tsigkeyname, &tsigalgorithm, &tsigsecret64)) { - B64Decode(tsigsecret64, tsigsecret); + if(B.getTSIGKey(tt.name, &tt.algo, &tsigsecret64)) { + if(B64Decode(tsigsecret64, tt.secret)) { + L< rrs; ComboAddress raddr(remote, 53); - AXFRRetriever retriever(raddr, domain, tsigkeyname, tsigalgorithm, tsigsecret, (laddr.sin4.sin_family == 0) ? NULL : &laddr); + AXFRRetriever retriever(raddr, domain, tt, (laddr.sin4.sin_family == 0) ? NULL : &laddr); Resolver::res_t recs; while(retriever.getChunk(recs)) { if(first) { -- 2.40.0