merge the triplet 'tsigname, tsigalgo, tsigsecret' into a handy TSIGTriplet, and move most of the TSIG apis to this struct.
/*
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
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 <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <time.h>
#include <sys/types.h>
class DNSBackend;
-class DNSName; // FIXME400
struct SOAData
{
}
+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
#include "dnsrecords.hh"
#include "dnssecinfra.hh"
-vector<pair<vector<DNSRecord>, vector<DNSRecord> > > getIXFRDeltas(const ComboAddress& master, const DNSName& zone, const DNSRecord& oursr, const DNSName& tsigalgo, const DNSName& tsigname, const std::string& tsigsecret)
+vector<pair<vector<DNSRecord>, vector<DNSRecord> > > getIXFRDeltas(const ComboAddress& master, const DNSName& zone, const DNSRecord& oursr, const TSIGTriplet& tt)
{
vector<pair<vector<DNSRecord>, vector<DNSRecord> > > ret;
vector<uint8_t> packet;
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);
#include "dnsparser.hh"
vector<pair<vector<DNSRecord>, vector<DNSRecord> > > 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());
>
>records_t;
-uint32_t getSerialFromMaster(const ComboAddress& master, const DNSName& zone, shared_ptr<SOARecordContent>& sr, const DNSName& tsigalgo=DNSName(), const DNSName& tsigname=DNSName(), const std::string& tsigsecret="")
+uint32_t getSerialFromMaster(const ComboAddress& master, const DNSName& zone, shared_ptr<SOARecordContent>& sr, const TSIGTriplet& tt = TSIGTriplet())
{
vector<uint8_t> 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);
cout<<"Loading zone, our highest available serial is "<< ourSerial<<endl;
- DNSName tsigkey, tsigalgo;
+ TSIGTriplet tt;
if(argc > 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!"<<endl;
exit(EXIT_FAILURE);
}
cout<<"Could not load zone from disk: "<<e.what()<<endl;
cout<<"Retrieving latest from master "<<master.toStringWithPort()<<endl;
ComboAddress local = master.sin4.sin_family == AF_INET ? ComboAddress("0.0.0.0") : ComboAddress("::");
- AXFRRetriever axfr(master, zone, tsigkey, tsigalgo, tsigsecret, &local);
+ AXFRRetriever axfr(master, zone, tt, &local);
unsigned int nrecords=0;
Resolver::res_t nop;
vector<DNSRecord> chunk;
cout<<"Checking for update, our serial number is "<<ourSerial<<".. ";
cout.flush();
shared_ptr<SOARecordContent> 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 "<<serial<<", sleeping "<<sr->d_st.refresh<<" seconds"<<endl;
sleep(sr->d_st.refresh);
}
cout<<"got new serial: "<<serial<<", initiating IXFR!"<<endl;
- auto deltas = getIXFRDeltas(master, zone, ourSoa, tsigalgo, tsigkey, tsigsecret);
+ auto deltas = getIXFRDeltas(master, zone, ourSoa, tt);
cout<<"Got "<<deltas.size()<<" deltas, applying.."<<endl;
for(const auto& delta : deltas) {
#include "filterpo.hh"
#include "syncres.hh"
#include "rpzloader.hh"
+#include "base64.hh"
GlobalStateHolder<LuaConfigItems> g_luaconfs;
Lua.writeFunction("rpzMaster", [&lci](const string& master_, const string& zone_, const boost::optional<std::unordered_map<string,boost::variant<int, string>>>& options) {
try {
boost::optional<DNSFilterEngine::Policy> defpol;
+ TSIGTriplet tt;
+ int refresh=0;
if(options) {
auto& have = *options;
+
if(have.count("defpol")) {
// cout<<"Set a default policy"<<endl;
defpol=DNSFilterEngine::Policy();
}
}
-
+ if(have.count("tsigname")) {
+ tt.name=DNSName(toLower(boost::get<string>(constGet(have, "tsigname"))));
+ tt.algo=DNSName(toLower(boost::get<string>(constGet(have, "tsigalgo"))));
+ if(B64Decode(boost::get<string>(constGet(have, "tsigsecret")), tt.secret))
+ throw std::runtime_error("TSIG secret is not valid Base-64 encoded");
+ }
+ if(have.count("refresh")) {
+ refresh = boost::get<int>(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) {
}
-void RPZIXFRTracker(const ComboAddress& master, const DNSName& zone, shared_ptr<SOARecordContent> oursr)
+void RPZIXFRTracker(const ComboAddress& master, const DNSName& zone, const TSIGTriplet& tt, shared_ptr<SOARecordContent> oursr)
{
+ int refresh = oursr->d_st.refresh;
for(;;) {
DNSRecord dr;
dr.d_content=oursr;
- sleep(oursr->d_st.refresh);
+ sleep(refresh);
L<<Logger::Info<<"Getting IXFR deltas for "<<zone<<" from "<<master.toStringWithPort()<<", our serial: "<<std::dynamic_pointer_cast<SOARecordContent>(dr.d_content)->d_st.serial<<endl;
- auto deltas = getIXFRDeltas(master, zone, dr);
+ auto deltas = getIXFRDeltas(master, zone, dr, tt);
if(deltas.empty())
continue;
L<<Logger::Info<<"Processing "<<deltas.size()<<" delta"<<addS(deltas)<<" for RPZ "<<zone<<endl;
}
AXFRRetriever::AXFRRetriever(const ComboAddress& remote,
- const DNSName& domain,
- const DNSName& tsigkeyname,
- const DNSName& tsigalgorithm,
- const string& tsigsecret,
- const ComboAddress* laddr)
-: d_tsigkeyname(tsigkeyname), d_tsigsecret(tsigsecret), d_tsigPos(0), d_nonSignedMessages(0)
+ const DNSName& domain,
+ const TSIGTriplet& tt,
+ const ComboAddress* laddr)
+ : d_tt(tt), d_tsigPos(0), d_nonSignedMessages(0)
{
ComboAddress local;
if (laddr != NULL) {
DNSPacketWriter pw(packet, domain, QType::AXFR);
pw.getHeader()->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());
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);
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;
}
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()+"'");
}
}
{
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<DNSRecord>* records=0);
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;
}
}
-shared_ptr<SOARecordContent> loadRPZFromServer(const ComboAddress& master, const DNSName& zone, DNSFilterEngine& target, boost::optional<DNSFilterEngine::Policy> defpol, int place)
+shared_ptr<SOARecordContent> loadRPZFromServer(const ComboAddress& master, const DNSName& zone, DNSFilterEngine& target, boost::optional<DNSFilterEngine::Policy> defpol, int place, const TSIGTriplet& tt)
{
L<<Logger::Warning<<"Loading RPZ zone '"<<zone<<"' from "<<master.toStringWithPort()<<endl;
- ComboAddress local("0.0.0.0");
- AXFRRetriever axfr(master, zone, DNSName(), DNSName(), "", &local);
+ if(!tt.name.empty())
+ L<<Logger::Warning<<"With TSIG key '"<<tt.name<<"' of algorithm '"<<tt.algo<<"'"<<endl;
+
+ ComboAddress local= master.sin4.sin_family == AF_INET ? ComboAddress("0.0.0.0") : ComboAddress("::"); // should be configurable
+ AXFRRetriever axfr(master, zone, tt, &local);
unsigned int nrecords=0;
Resolver::res_t nop;
vector<DNSRecord> chunk;
shared_ptr<SOARecordContent> 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<SOARecordContent>(dr.d_content);
continue;
}
- if(dr.d_type==QType::NS) {
- continue;
- }
RPZRecordToPolicy(dr, target, true, defpol, place);
nrecords++;
#include "dnsrecords.hh"
int loadRPZFromFile(const std::string& fname, DNSFilterEngine& target, boost::optional<DNSFilterEngine::Policy> defpol, int place);
-std::shared_ptr<SOARecordContent> loadRPZFromServer(const ComboAddress& master, const DNSName& zone, DNSFilterEngine& target, boost::optional<DNSFilterEngine::Policy> defpol, int place);
+std::shared_ptr<SOARecordContent> loadRPZFromServer(const ComboAddress& master, const DNSName& zone, DNSFilterEngine& target, boost::optional<DNSFilterEngine::Policy> defpol, int place, const TSIGTriplet& tt);
void RPZRecordToPolicy(const DNSRecord& dr, DNSFilterEngine& target, bool addOrRemove, boost::optional<DNSFilterEngine::Policy> defpol, int place);
-void RPZIXFRTracker(const ComboAddress& master, const DNSName& zone, shared_ptr<SOARecordContent> oursr);
+void RPZIXFRTracker(const ComboAddress& master, const DNSName& zone, const TSIGTriplet &tt, shared_ptr<SOARecordContent> oursr);
}
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<<Logger::Error<<"Unable to Base-64 decode TSIG key '"<<tt.name<<"' for domain '"<<domain<<"' not found"<<endl;
+ return;
+ }
} else {
- L<<Logger::Error<<"TSIG key '"<<tsigkeyname<<"' for domain '"<<domain<<"' not found"<<endl;
+ L<<Logger::Error<<"TSIG key '"<<tt.name<<"' for domain '"<<domain<<"' not found"<<endl;
return;
}
}
vector<DNSResourceRecord> 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) {