recpacketcache.hh base32.hh cachecleaner.hh json.hh version.hh \
ws-recursor.hh ws-api.hh secpoll-recursor.hh \
responsestats.hh webserver.hh dnsname.hh dnspacket.hh ednssubnet.hh \
-filterpo.hh rpzloader.hh"
+filterpo.hh rpzloader.hh ixfr.hh gss_context.hh resolver.hh dnssecinfra.hh \
+dnsseckeeper.hh statbag.hh ueberbackend.hh sha.hh dnsbackend.hh comment.hh"
CFILES="syncres.cc iputils.cc misc.cc unix_utility.cc qtype.cc \
logger.cc arguments.cc lwres.cc pdns_recursor.cc lua-iputils.cc \
devpollmplexer.cc recpacketcache.cc dns.cc reczones.cc base32.cc nsecrecords.cc \
dnslabeltext.cc json.cc ws-recursor.cc ws-api.cc version.cc dns_random.cc \
responsestats.cc webserver.cc rec-carbon.cc secpoll-recursor.cc dnsname.cc \
-filterpo.cc rpzloader.cc"
+filterpo.cc rpzloader.cc ixfr.cc dnssecinfra.cc gss_context.cc resolver.cc"
./mkpubsuffixcc
cp -a ../ext/rapidjson/include/rapidjson/*.h $DIRNAME/ext/rapidjson/include/rapidjson/
cp -a ../ext/rapidjson/include/rapidjson/internal/*.h $DIRNAME/ext/rapidjson/include/rapidjson/internal
mkdir -p $DIRNAME/ext/mbedtls/include/mbedtls
-cp -a ../ext/mbedtls/include/mbedtls/config.h ../ext/mbedtls/include/mbedtls/check_config.h ../ext/mbedtls/include/mbedtls/aes.h ../ext/mbedtls/include/mbedtls/base64.h ../ext/mbedtls/include/mbedtls/platform.h ../ext/mbedtls/include/mbedtls/version.h $DIRNAME/ext/mbedtls/include/mbedtls
+cp -a ../ext/mbedtls/include/mbedtls/{config.h,check_config.h,aes.h,ripemd160.h,sha1.h,md.h,md5.h,sha256.h,sha512.h,md_internal.h} ../ext/mbedtls/include/mbedtls/base64.h ../ext/mbedtls/include/mbedtls/platform.h ../ext/mbedtls/include/mbedtls/version.h $DIRNAME/ext/mbedtls/include/mbedtls
mkdir -p $DIRNAME/ext/mbedtls/library
-cp -a ../ext/mbedtls/library/aes.c ../ext/mbedtls/library/base64.c $DIRNAME/ext/mbedtls/library
+cp -a ../ext/mbedtls/library/{aes.c,base64.c,md.c,md_wrap.c,md5.c,sha1.c,sha256.c,sha512.c,ripemd160.c} $DIRNAME/ext/mbedtls/library
cp -a ../ext/yahttp/ $DIRNAME/ext/yahttp
echo '#include "../../../config.h"' > $DIRNAME/ext/yahttp/yahttp/yahttp-config.h
mkdir $DIRNAME/rrd
dnswriter.o dnsrecords.o rcpgenerator.o base64.o zoneparser-tng.o \
rec_channel.o rec_channel_rec.o selectmplexer.o sillyrecords.o \
dns_random.o pubsuffix.o ext/mbedtls/library/aes.o ext/mbedtls/library/base64.o dnslabeltext.o \
+ext/mbedtls/library/md5.o ext/mbedtls/library/sha1.o ext/mbedtls/library/sha256.o \
+ext/mbedtls/library/sha512.o ext/mbedtls/library/md.o ext/mbedtls/library/md_wrap.o \
+ext/mbedtls/library/ripemd160.o \
lua-pdns.o lua-recursor.o randomhelper.o recpacketcache.o dns.o \
reczones.o base32.o nsecrecords.o json.o ws-recursor.o ws-api.o \
version.o responsestats.o webserver.o ext/yahttp/yahttp/reqresp.o ext/yahttp/yahttp/router.o \
rec-carbon.o secpoll-recursor.o lua-iputils.o iputils.o dnsname.o \
-rpzloader.o filterpo.o
+rpzloader.o filterpo.o resolver.o ixfr.o dnssecinfra.o gss_context.o
REC_CONTROL_OBJECTS=rec_channel.o rec_control.o arguments.o misc.o \
unix_utility.o logger.o qtype.o dnslabeltext.o dnsname.o
qtype.cc \
rcpgenerator.cc rcpgenerator.hh \
resolver.cc \
+ ixfr.cc ixfr.hh \
ixplore.cc \
sillyrecords.cc \
sstuff.hh \
dnsname.cc dnsname.hh \
dnsparser.cc \
dnsrecords.cc dnsrecords.hh \
+ dnssecinfra.cc \
dnswriter.cc dnswriter.hh \
filterpo.cc filterpo.hh \
+ gss_context.cc gss_context.hh \
iputils.cc \
+ ixfr.cc ixfr.hh \
json.cc json.hh \
logger.cc \
lua-pdns.cc lua-pdns.hh lua-iputils.cc \
recpacketcache.cc recpacketcache.hh \
recursor_cache.cc recursor_cache.hh \
reczones.cc \
+ resolver.cc \
resolver.hh \
responsestats.cc \
rpzloader.cc rpzloader.hh \
#include <vector>
#include <map>
#include "misc.hh"
-#include "ueberbackend.hh"
+
+class UeberBackend;
// rules of the road: Algorithm must be set in 'make' for each KeyEngine, and will NEVER change!
DNSFilterEngine::Policy DNSFilterEngine::getProcessingPolicy(const DNSName& qname) const
{
- cout<<"Got question for nameserver name "<<qname<<endl;
- Policy pol = Policy::NoAction;
+ // cout<<"Got question for nameserver name "<<qname<<endl;
+ Policy pol{PolicyKind::NoAction};
for(const auto& z : d_zones) {
if(findNamedPolicy(z.propolName, qname, pol)) {
- cerr<<"Had a hit on the nameserver used to process the query"<<endl;
+ cerr<<"Had a hit on the nameserver ("<<qname<<") used to process the query"<<endl;
return pol;
}
}
{
cout<<"Got question for "<<qname<<" from "<<ca.toString()<<endl;
- Policy pol = Policy::NoAction;
+ Policy pol{PolicyKind::NoAction};
for(const auto& z : d_zones) {
if(findNamedPolicy(z.qpolName, qname, pol)) {
cerr<<"Had a hit on the name of the query"<<endl;
for(const auto& qa : z.qpolAddr) {
if(qa.first.match(ca)) {
- cerr<<"Had a hit on the IP address of the client"<<endl;
+ cerr<<"Had a hit on the IP address ("<<ca.toString()<<") of the client"<<endl;
return qa.second;
}
}
}
- return Policy::NoAction;
+ return pol;
}
DNSFilterEngine::Policy DNSFilterEngine::getPostPolicy(const vector<DNSRecord>& records) const
}
}
}
- return Policy::NoAction;
+ return Policy{PolicyKind::NoAction};
}
void DNSFilterEngine::assureZones(int zone)
assureZones(zone);
d_zones[zone].propolName[n]=pol;
}
+
+bool DNSFilterEngine::rmClientTrigger(const Netmask& nm, Policy pol, int zone)
+{
+ assureZones(zone);
+
+ auto& qpols = d_zones[zone].qpolAddr;
+ qpols.erase(remove(qpols.begin(), qpols.end(),pair<Netmask,Policy>(nm,pol)), qpols.end());
+ return true;
+}
+
+bool DNSFilterEngine::rmResponseTrigger(const Netmask& nm, Policy pol, int zone)
+{
+ assureZones(zone);
+ auto& postpols = d_zones[zone].postpolAddr;
+ postpols.erase(remove(postpols.begin(), postpols.end(),pair<Netmask,Policy>(nm,pol)), postpols.end());
+ return true;
+}
+
+bool DNSFilterEngine::rmQNameTrigger(const DNSName& n, Policy pol, int zone)
+{
+ assureZones(zone);
+ d_zones[zone].qpolName.erase(n); // XXX verify we had identical policy?
+ return true;
+}
+
+bool DNSFilterEngine::rmNSTrigger(const DNSName& n, Policy pol, int zone)
+{
+ assureZones(zone);
+ d_zones[zone].propolName.erase(n); // XXX verify policy matched? =pol;
+ return true;
+}
#pragma once
#include "iputils.hh"
#include "dns.hh"
+#include "dnsparser.hh"
#include <map>
/* This class implements a filtering policy that is able to fully implement RPZ, but is not bound to it.
class DNSFilterEngine
{
public:
- enum class Policy { NoAction, Drop, NXDOMAIN, NODATA, Truncate};
+ enum class PolicyKind { NoAction, Drop, NXDOMAIN, NODATA, Truncate, Custom};
+ struct Policy
+ {
+ bool operator==(const Policy& rhs) const
+ {
+ return d_kind == rhs.d_kind; // XXX check d_custom too!
+ }
+ PolicyKind d_kind;
+ std::shared_ptr<DNSRecordContent> d_custom;
+ };
DNSFilterEngine();
void clear();
void addNSTrigger(const DNSName& dn, Policy pol, int zone=0);
void addResponseTrigger(const Netmask& nm, Policy pol, int zone=0);
+ bool rmClientTrigger(const Netmask& nm, Policy pol, int zone=0);
+ bool rmQNameTrigger(const DNSName& nm, Policy pol, int zone=0);
+ bool rmNSTrigger(const DNSName& dn, Policy pol, int zone=0);
+ bool rmResponseTrigger(const Netmask& nm, Policy pol, int zone=0);
+
+
Policy getQueryPolicy(const DNSName& qname, const ComboAddress& nm) const;
Policy getProcessingPolicy(const DNSName& qname) const;
Policy getPostPolicy(const vector<DNSRecord>& records) const;
{
return tie(d_network, d_bits) < tie(rhs.d_network, rhs.d_bits);
}
+
+ bool operator==(const Netmask& rhs) const
+ {
+ return tie(d_network, d_bits) == tie(rhs.d_network, rhs.d_bits);
+ }
+
private:
ComboAddress d_network;
uint32_t d_mask;
--- /dev/null
+#include "ixfr.hh"
+#include "sstuff.hh"
+#include "dns_random.hh"
+#include "dnsrecords.hh"
+
+
+vector<pair<vector<DNSRecord>, vector<DNSRecord> > > getIXFRDeltas(const ComboAddress& master, const DNSName& zone, const DNSRecord& oursr)
+{
+ vector<pair<vector<DNSRecord>, vector<DNSRecord> > > ret;
+ vector<uint8_t> packet;
+ DNSPacketWriter pw(packet, zone, QType::IXFR);
+ pw.getHeader()->qr=0;
+ pw.getHeader()->rd=0;
+ pw.getHeader()->id=dns_random(0xffff);
+ pw.startRecord(zone, QType::SOA, 3600, QClass::IN, DNSPacketWriter::AUTHORITY);
+ oursr.d_content->toPacket(pw);
+ pw.commit();
+
+ uint16_t len=htons(packet.size());
+ string msg((const char*)&len, 2);
+ msg.append((const char*)&packet[0], packet.size());
+
+ Socket s(master.sin4.sin_family, SOCK_STREAM);
+ // cout<<"going to connect"<<endl;
+ s.connect(master);
+ // cout<<"Connected"<<endl;
+ s.writen(msg);
+
+ // CURRENT MASTER SOA
+ // REPEAT:
+ // SOA WHERE THIS DELTA STARTS
+ // RECORDS TO REMOVE
+ // SOA WHERE THIS DELTA GOES
+ // RECORDS TO ADD
+ // CURRENT MASTER SOA
+ shared_ptr<SOARecordContent> masterSOA;
+ vector<DNSRecord> records;
+ for(;;) {
+ if(s.read((char*)&len, 2)!=2)
+ break;
+ len=ntohs(len);
+ // cout<<"Got chunk of "<<len<<" bytes"<<endl;
+ if(!len)
+ break;
+ char reply[len];
+ readn2(s.getHandle(), reply, len);
+ MOADNSParser mdp(string(reply, len));
+ // cout<<"Got a response, rcode: "<<mdp.d_header.rcode<<", got "<<mdp.d_answers.size()<<" answers"<<endl;
+ for(auto& r: mdp.d_answers) {
+ // cout<<r.first.d_name<< " " <<r.first.d_content->getZoneRepresentation()<<endl;
+ r.first.d_name = r.first.d_name.makeRelative(zone);
+ records.push_back(r.first);
+ if(r.first.d_type == QType::SOA) {
+ auto sr = std::dynamic_pointer_cast<SOARecordContent>(r.first.d_content);
+ if(!masterSOA) {
+ if(sr->d_st.serial == std::dynamic_pointer_cast<SOARecordContent>(oursr.d_content)->d_st.serial) // we are up to date
+ goto done;
+ masterSOA=sr;
+
+ }
+ else if(sr->d_st.serial == masterSOA->d_st.serial)
+ goto done;
+
+ }
+ }
+ }
+ // cout<<"Got "<<records.size()<<" records"<<endl;
+ done:;
+ for(unsigned int pos = 1;pos < records.size();) {
+ auto sr = std::dynamic_pointer_cast<SOARecordContent>(records[pos].d_content);
+ if(sr->d_st.serial == masterSOA->d_st.serial)
+ break;
+
+ vector<DNSRecord> remove, add;
+ remove.push_back(records[pos]); // this adds the SOA
+ for(pos++; pos < records.size() && records[pos].d_type != QType::SOA; ++pos) {
+ remove.push_back(records[pos]);
+ }
+ sr = std::dynamic_pointer_cast<SOARecordContent>(records[pos].d_content);
+
+ add.push_back(records[pos]); // this adds the new SOA
+ for(pos++; pos < records.size() && records[pos].d_type != QType::SOA; ++pos) {
+ add.push_back(records[pos]);
+ }
+ ret.push_back(make_pair(remove,add));
+ }
+ return ret;
+}
--- /dev/null
+#include "namespaces.hh"
+#include "iputils.hh"
+#include "dnsparser.hh"
+
+vector<pair<vector<DNSRecord>, vector<DNSRecord> > > getIXFRDeltas(const ComboAddress& master, const DNSName& zone, const DNSRecord& sr);
#include <boost/multi_index_container.hpp>
#include "resolver.hh"
#include <fstream>
+#include "ixfr.hh"
using namespace boost::multi_index;
StatBag S;
return 0;
}
-vector<pair<vector<DNSRecord>, vector<DNSRecord> > > getIXFRDeltas(const ComboAddress& master, const DNSName& zone, const DNSRecord& sr)
-{
- vector<pair<vector<DNSRecord>, vector<DNSRecord> > > ret;
- vector<uint8_t> packet;
- DNSPacketWriter pw(packet, zone, QType::IXFR);
- pw.getHeader()->qr=0;
- pw.getHeader()->rd=0;
- pw.getHeader()->id=dns_random(0xffff);
- pw.startRecord(zone, QType::SOA, 3600, QClass::IN, DNSPacketWriter::AUTHORITY);
- sr.d_content->toPacket(pw);
- pw.commit();
-
- uint16_t len=htons(packet.size());
- string msg((const char*)&len, 2);
- msg.append((const char*)&packet[0], packet.size());
-
- Socket s(master.sin4.sin_family, SOCK_STREAM);
- s.connect(master);
- s.writen(msg);
-
- // CURRENT MASTER SOA
- // REPEAT:
- // SOA WHERE THIS DELTA STARTS
- // RECORDS TO REMOVE
- // SOA WHERE THIS DELTA GOES
- // RECORDS TO ADD
- // CURRENT MASTER SOA
- shared_ptr<SOARecordContent> masterSOA;
- vector<DNSRecord> records;
- for(;;) {
- if(s.read((char*)&len, 2)!=2)
- break;
- len=ntohs(len);
- // cout<<"Got chunk of "<<len<<" bytes"<<endl;
- if(!len)
- break;
- char reply[len];
- readn2(s.getHandle(), reply, len);
- MOADNSParser mdp(string(reply, len));
- // cout<<"Got a response, rcode: "<<mdp.d_header.rcode<<", got "<<mdp.d_answers.size()<<" answers"<<endl;
- for(auto& r: mdp.d_answers) {
- r.first.d_name = r.first.d_name.makeRelative(zone);
- records.push_back(r.first);
- if(r.first.d_type == QType::SOA) {
- auto sr = std::dynamic_pointer_cast<SOARecordContent>(r.first.d_content);
- if(!masterSOA) {
- masterSOA=sr;
- }
- else if(sr->d_st.serial == masterSOA->d_st.serial)
- goto done;
-
- }
- }
- }
- done:;
- for(unsigned int pos = 1;pos < records.size();) {
- auto sr = std::dynamic_pointer_cast<SOARecordContent>(records[pos].d_content);
- if(sr->d_st.serial == masterSOA->d_st.serial)
- break;
-
- vector<DNSRecord> remove, add;
- remove.push_back(records[pos]); // this adds the SOA
- for(pos++; pos < records.size() && records[pos].d_type != QType::SOA; ++pos) {
- remove.push_back(records[pos]);
- }
- sr = std::dynamic_pointer_cast<SOARecordContent>(records[pos].d_content);
-
- add.push_back(records[pos]); // this adds the new SOA
- for(pos++; pos < records.size() && records[pos].d_type != QType::SOA; ++pos) {
- add.push_back(records[pos]);
- }
- ret.push_back(make_pair(remove,add));
- }
- return ret;
-}
uint32_t getSerialsFromDir(const std::string& dir)
{
fprintf(fp, "$ORIGIN %s\n", zone.toString().c_str());
for(const auto& outer : {soarecord, records, soarecord} ) {
for(const auto& r: outer) {
- fprintf(fp, "%s\tIN\t%s\t%s\n", r.d_name.toStringNoDot().c_str(),
+ fprintf(fp, "%s\tIN\t%s\t%s\n",
+ r.d_name.isRoot() ? "@" : r.d_name.toStringNoDot().c_str(),
DNSRecordContent::NumberToType(r.d_type).c_str(),
r.d_content->getZoneRepresentation().c_str());
}
bool variableAnswer = false;
int res;
-
+ DNSFilterEngine::Policy dfepol;
+ DNSRecord spoofed;
if(dc->d_mdp.d_qtype==QType::ANY && !dc->d_tcp && g_anyToTcp) {
pw.getHeader()->tc = 1;
res = 0;
// if there is a RecursorLua active, and it 'took' the query in preResolve, we don't launch beginResolve
- switch(g_dfe.getQueryPolicy(dc->d_mdp.d_qname, dc->d_remote)) {
- case DNSFilterEngine::Policy::NoAction:
+ dfepol = g_dfe.getQueryPolicy(dc->d_mdp.d_qname, dc->d_remote);
+
+ switch(dfepol.d_kind) {
+ case DNSFilterEngine::PolicyKind::NoAction:
break;
- case DNSFilterEngine::Policy::Drop:
+ case DNSFilterEngine::PolicyKind::Drop:
g_stats.policyDrops++;
delete dc;
dc=0;
return;
- case DNSFilterEngine::Policy::NXDOMAIN:
+ case DNSFilterEngine::PolicyKind::NXDOMAIN:
res=RCode::NXDomain;
goto haveAnswer;
- case DNSFilterEngine::Policy::NODATA:
+ case DNSFilterEngine::PolicyKind::NODATA:
+ res=RCode::NoError;
+ goto haveAnswer;
+
+ case DNSFilterEngine::PolicyKind::Custom:
res=RCode::NoError;
+ spoofed.d_name=dc->d_mdp.d_qname;
+ spoofed.d_type=dfepol.d_custom->d_qtype;
+ spoofed.d_ttl = 1234;
+ spoofed.d_class = 1;
+ spoofed.d_content = dfepol.d_custom;
+ spoofed.d_place = DNSRecord::Answer;
+ ret.push_back(spoofed);
goto haveAnswer;
- case DNSFilterEngine::Policy::Truncate:
+
+ case DNSFilterEngine::PolicyKind::Truncate:
if(!dc->d_tcp) {
res=RCode::NoError;
pw.getHeader()->tc=1;
res = RCode::ServFail;
}
- switch(g_dfe.getPostPolicy(ret)) {
- case DNSFilterEngine::Policy::NoAction:
+ dfepol = g_dfe.getPostPolicy(ret);
+ switch(dfepol.d_kind) {
+ case DNSFilterEngine::PolicyKind::NoAction:
break;
- case DNSFilterEngine::Policy::Drop:
+ case DNSFilterEngine::PolicyKind::Drop:
g_stats.policyDrops++;
delete dc;
dc=0;
return;
- case DNSFilterEngine::Policy::NXDOMAIN:
+ case DNSFilterEngine::PolicyKind::NXDOMAIN:
ret.clear();
res=RCode::NXDomain;
goto haveAnswer;
- case DNSFilterEngine::Policy::NODATA:
+ case DNSFilterEngine::PolicyKind::NODATA:
ret.clear();
res=RCode::NoError;
goto haveAnswer;
- case DNSFilterEngine::Policy::Truncate:
+ case DNSFilterEngine::PolicyKind::Truncate:
if(!dc->d_tcp) {
ret.clear();
res=RCode::NoError;
goto haveAnswer;
}
break;
+
+ case DNSFilterEngine::PolicyKind::Custom:
+ res=RCode::NoError;
+ spoofed.d_name=dc->d_mdp.d_qname;
+ spoofed.d_type=dfepol.d_custom->d_qtype;
+ spoofed.d_ttl = 1234;
+ spoofed.d_class = 1;
+ spoofed.d_content = dfepol.d_custom;
+ spoofed.d_place = DNSRecord::Answer;
+ ret.push_back(spoofed);
+ goto haveAnswer;
}
if(t_pdl->get()) {
::arg().set("single-socket", "If set, only use a single socket for outgoing queries")="off";
::arg().set("auth-zones", "Zones for which we have authoritative data, comma separated domain=file pairs ")="";
::arg().set("rpz-files", "RPZ files to load in order, domain or domain=policy pairs separated by commas")="";
+ ::arg().set("rpz-masters", "RPZ master servers, address:name pairs separated by commas")="";
::arg().set("forward-zones", "Zones for which we forward queries, comma separated domain=ip pairs")="";
::arg().set("forward-zones-recurse", "Zones for which we forward queries with recursion bit, comma separated domain=ip pairs")="";
#include "logger.hh"
#include "dnsrecords.hh"
#include <boost/foreach.hpp>
+#include <thread>
+#include "ixfr.hh"
#include "rpzloader.hh"
extern int g_argc;
return "reloading failed, see log\n";
}
+void ixfrTracker(const ComboAddress& master, const DNSName& zone, shared_ptr<SOARecordContent> oursr)
+{
+ for(;;) {
+ DNSRecord dr;
+ dr.d_content=oursr;
+
+ sleep(oursr->d_st.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);
+ if(deltas.empty())
+ continue;
+ L<<Logger::Info<<"Processing "<<deltas.size()<<" deltas for RPZ "<<zone<<endl;
+
+ int totremove=0, totadd=0;
+ for(const auto& delta : deltas) {
+ const auto& remove = delta.first;
+ const auto& add = delta.second;
+
+ for(const auto& rr : remove) { // should always contain the SOA
+ totremove++;
+ if(rr.d_type == QType::SOA) {
+ auto oldsr = std::dynamic_pointer_cast<SOARecordContent>(rr.d_content);
+ if(oldsr->d_st.serial == oursr->d_st.serial) {
+ // cout<<"Got good removal of SOA serial "<<oldsr->d_st.serial<<endl;
+ }
+ else
+ cerr<<"GOT WRONG SOA SERIAL REMOVAL, SHOULD TRIGGER WHOLE RELOAD"<<endl;
+ }
+ else {
+ L<<Logger::Info<<"Had removal of "<<rr.d_name<<endl;
+ RPZRecordToPolicy(rr, g_dfe, false, 0);
+ }
+ }
+
+ for(const auto& rr : add) { // should always contain the new SOA
+ totadd++;
+ if(rr.d_type == QType::SOA) {
+ auto newsr = std::dynamic_pointer_cast<SOARecordContent>(rr.d_content);
+ // L<<Logger::Info<<"New SOA serial for "<<zone<<": "<<newsr->d_st.serial<<endl;
+ oursr = newsr;
+ }
+ else {
+ L<<Logger::Info<<"Had addition of "<<rr.d_name<<endl;
+ RPZRecordToPolicy(rr, g_dfe, true, 0);
+ }
+ }
+ }
+ L<<Logger::Info<<"Had "<<totremove<<" RPZ removals, "<<totadd<<" additions for "<<zone<<" New serial: "<<oursr->d_st.serial<<endl;
+ }
+}
+
+
void loadRPZFiles()
{
vector<string> fnames;
for(const auto& f : fnames) {
loadRPZFromFile(f, g_dfe, count++);
}
+
+ fnames.clear();
+ stringtok(fnames, ::arg()["rpz-masters"],",");
+
+ for(const auto& f : fnames) {
+ auto s = splitField(f, ':');
+ ComboAddress master(s.first, 53);
+ DNSName zone(s.second);
+ auto sr=loadRPZFromServer(master,zone, g_dfe, count++);
+ std::thread t(ixfrTracker, master, zone, sr);
+ t.detach();
+ }
+
}
SyncRes::domainmap_t* parseAuthAndForwards()
#include "dnsparser.hh"
#include "dnsrecords.hh"
#include "syncres.hh"
+#include "resolver.hh"
+#include "logger.hh"
static Netmask makeNetmaskFromRPZ(const DNSName& name)
{
return Netmask(parts[4]+"."+parts[3]+"."+parts[2]+"."+parts[1]+"/"+parts[0]);
}
-int loadRPZFromFile(const std::string& fname, DNSFilterEngine& target, int place)
+void RPZRecordToPolicy(const DNSRecord& dr, DNSFilterEngine& target, bool addOrRemove, int place)
{
- ZoneParserTNG zpt(fname);
- DNSResourceRecord drr;
-
static const DNSName drop("rpz-drop."), truncate("rpz-tcp-only."), noaction("rpz-passthru.");
-
static const DNSName rpzClientIP("rpz-client-ip"), rpzIP("rpz-ip"),
rpzNSDname("rpz-nsdname"), rpzNSIP("rpz-nsip.");
-
-
+
+ DNSFilterEngine::Policy pol{DNSFilterEngine::PolicyKind::NoAction};
+
+ if(dr.d_type == QType::CNAME) {
+ auto target=std::dynamic_pointer_cast<CNAMERecordContent>(dr.d_content)->getTarget();
+ if(target.isRoot()) {
+ // cerr<<"Wants NXDOMAIN for "<<dr.d_name<<": ";
+ pol.d_kind = DNSFilterEngine::PolicyKind::NXDOMAIN;
+ } else if(target==DNSName("*")) {
+ // cerr<<"Wants NODATA for "<<dr.d_name<<": ";
+ pol.d_kind = DNSFilterEngine::PolicyKind::NODATA;
+ }
+ else if(target==drop) {
+ // cerr<<"Wants DROP for "<<dr.d_name<<": ";
+ pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
+ }
+ else if(target==truncate) {
+ // cerr<<"Wants TRUNCATE for "<<dr.d_name<<": ";
+ pol.d_kind = DNSFilterEngine::PolicyKind::Truncate;
+ }
+ else if(target==noaction) {
+ // cerr<<"Wants NOACTION for "<<dr.d_name<<": ";
+ pol.d_kind = DNSFilterEngine::PolicyKind::NoAction;
+ }
+ else {
+ pol.d_kind = DNSFilterEngine::PolicyKind::Custom;
+ pol.d_custom = dr.d_content;
+ // cerr<<"Wants custom "<<target<<" for "<<dr.d_name<<": ";
+ }
+ }
+ else {
+ pol.d_kind = DNSFilterEngine::PolicyKind::Custom;
+ pol.d_custom = dr.d_content;
+ // cerr<<"Wants custom "<<dr.d_content->getZoneRepresentation()<<" for "<<dr.d_name<<": ";
+ }
+
+ // now to DO something with that
+ if(dr.d_name.isPartOf(rpzNSDname)) {
+ DNSName filt=dr.d_name.makeRelative(rpzNSDname);
+ if(addOrRemove)
+ g_dfe.addNSTrigger(filt, pol);
+ else
+ g_dfe.rmNSTrigger(filt, pol);
+ } else if(dr.d_name.isPartOf(rpzClientIP)) {
+
+ auto nm=makeNetmaskFromRPZ(dr.d_name);
+
+ if(addOrRemove)
+ g_dfe.addClientTrigger(nm, pol);
+ else
+ g_dfe.rmClientTrigger(nm, pol);
+
+ } else if(dr.d_name.isPartOf(rpzIP)) {
+ // cerr<<"Should apply answer content IP policy: "<<dr.d_name<<endl;
+ auto nm=makeNetmaskFromRPZ(dr.d_name);
+ if(addOrRemove)
+ g_dfe.addResponseTrigger(nm, pol);
+ else
+ g_dfe.rmResponseTrigger(nm, pol);
+ } else if(dr.d_name.isPartOf(rpzNSIP)) {
+ cerr<<"Should apply to nameserver IP address policy HAVE NOTHING HERE"<<endl;
+
+ } else {
+ if(addOrRemove)
+ g_dfe.addQNameTrigger(dr.d_name, pol);
+ else
+ g_dfe.rmQNameTrigger(dr.d_name, pol);
+ }
+}
+
+shared_ptr<SOARecordContent> loadRPZFromServer(const ComboAddress& master, const DNSName& zone, DNSFilterEngine& target, int place)
+{
+ L<<Logger::Warning<<"Loading RPZ zone '"<<zone<<"' from "<<master.toStringWithPort()<<endl;
+ ComboAddress local("0.0.0.0");
+ AXFRRetriever axfr(master, zone, DNSName(), DNSName(), "", &local);
+ unsigned int nrecords=0;
+ Resolver::res_t nop;
+ vector<DNSRecord> chunk;
+ time_t last=0;
+ shared_ptr<SOARecordContent> sr;
+ while(axfr.getChunk(nop, &chunk)) {
+ for(auto& dr : chunk) {
+ 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, place);
+ nrecords++;
+ }
+ if(last != time(0)) {
+ L<<Logger::Info<<"Loaded & indexed "<<nrecords<<" policy records so far"<<endl;
+ last=time(0);
+ }
+ }
+ L<<Logger::Info<<"Done: "<<nrecords<<" policy records active, SOA: "<<sr->getZoneRepresentation()<<endl;
+ return sr;
+}
+
+int loadRPZFromFile(const std::string& fname, DNSFilterEngine& target, int place)
+{
+ ZoneParserTNG zpt(fname);
+ DNSResourceRecord drr;
DNSName domain;
while(zpt.get(drr)) {
- DNSFilterEngine::Policy pol=DNSFilterEngine::Policy::NoAction;
-
try {
if(drr.qtype.getCode() == QType::CNAME && drr.content.empty())
drr.content=".";
domain = dr.d_name;
cerr<<"Origin is "<<domain<<endl;
}
- if(dr.d_type == QType::CNAME) {
+ else if(dr.d_type == QType::NS) {
+ continue;
+ }
+ else {
dr.d_name=dr.d_name.makeRelative(domain);
- auto target=std::dynamic_pointer_cast<CNAMERecordContent>(dr.d_content)->getTarget();
- if(target.isRoot()) {
- cerr<<"Wants NXDOMAIN for "<<dr.d_name<<": ";
- pol = DNSFilterEngine::Policy::NXDOMAIN;
- } else if(target==DNSName("*")) {
- cerr<<"Wants NODATA for "<<dr.d_name<<": ";
- pol = DNSFilterEngine::Policy::NODATA;
- }
- else if(target==drop) {
- cerr<<"Wants DROP for "<<dr.d_name<<": ";
- pol = DNSFilterEngine::Policy::Drop;
- }
- else if(target==truncate) {
- cerr<<"Wants TRUNCATE for "<<dr.d_name<<": ";
- pol = DNSFilterEngine::Policy::Truncate;
- }
- else if(target==noaction) {
- cerr<<"Wants NOACTION for "<<dr.d_name<<": ";
- pol = DNSFilterEngine::Policy::NoAction;
- }
- else
- cerr<<"Wants custom "<<target<<" for "<<dr.d_name<<": ";
-
- if(dr.d_name.isPartOf(rpzNSDname)) {
- DNSName filt=dr.d_name.makeRelative(rpzNSDname);
- cerr<<"Should apply '"<<filt<<"' to nameserver policy"<<endl;
- g_dfe.addNSTrigger(filt, pol);
- } else if(dr.d_name.isPartOf(rpzClientIP)) {
- cerr<<"Should apply to client IP policy"<<endl;
- auto nm=makeNetmaskFromRPZ(dr.d_name);
- cout<<"Parsed as "<<nm.toString()<<endl;
- g_dfe.addClientTrigger(nm, pol);
-
- } else if(dr.d_name.isPartOf(rpzIP)) {
- cerr<<"Should apply answer content IP policy: "<<dr.d_name<<endl;
- auto nm=makeNetmaskFromRPZ(dr.d_name);
- cout<<"Parsed as "<<nm.toString()<<endl;
- g_dfe.addResponseTrigger(nm, pol);
- } else if(dr.d_name.isPartOf(rpzNSIP)) {
- cerr<<"Should apply to nameserver IP address policy"<<endl;
- } else {
- cerr<<"Should apply to query names"<<endl;
- g_dfe.addQNameTrigger(dr.d_name, pol);
- }
-
+ RPZRecordToPolicy(dr, target, true, place);
}
}
catch(PDNSException& pe) {
#pragma once
#include "filterpo.hh"
#include <string>
+#include "dnsrecords.hh"
int loadRPZFromFile(const std::string& fname, DNSFilterEngine& target, int place);
+std::shared_ptr<SOARecordContent> loadRPZFromServer(const ComboAddress& master, const DNSName& zone, DNSFilterEngine& target, int place);
+void RPZRecordToPolicy(const DNSRecord& dr, DNSFilterEngine& target, bool addOrRemove, int place);
LOG(prefix<<qname.toString()<<": Trying to resolve NS '"<<tns->toString()<< "' ("<<1+tns-rnameservers.begin()<<"/"<<(unsigned int)rnameservers.size()<<")"<<endl);
;
- if(g_dfe.getProcessingPolicy(*tns) != DNSFilterEngine::Policy::NoAction)
+ // XXX NEED TO HANDLE OTHER POLICY KINDS HERE!
+ if(g_dfe.getProcessingPolicy(*tns).d_kind != DNSFilterEngine::PolicyKind::NoAction)
throw ImmediateServFailException("Dropped because of policy");
if(!isCanonical(*tns)) {