]> granicus.if.org Git - pdns/commitdiff
hook up IXFR/AXFR policy slaving for Recursor. Sadly draws in some auth bits into...
authorbert hubert <bert.hubert@powerdns.com>
Sun, 25 Oct 2015 16:28:30 +0000 (17:28 +0100)
committerbert hubert <bert.hubert@powerdns.com>
Sun, 25 Oct 2015 16:28:30 +0000 (17:28 +0100)
15 files changed:
build-scripts/dist-recursor
pdns/Makefile-recursor
pdns/Makefile.am
pdns/dnssecinfra.hh
pdns/filterpo.cc
pdns/filterpo.hh
pdns/iputils.hh
pdns/ixfr.cc [new file with mode: 0644]
pdns/ixfr.hh [new file with mode: 0644]
pdns/ixplore.cc
pdns/pdns_recursor.cc
pdns/reczones.cc
pdns/rpzloader.cc
pdns/rpzloader.hh
pdns/syncres.cc

index e52f67a31cef6a91cc4ddec8e362d0b690b16eca..cd1946bf4df0fff1e93d233aa83407389ee784cc 100755 (executable)
@@ -36,7 +36,8 @@ dns_random.hh lua-pdns.hh lua-recursor.hh namespaces.hh \
 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 \
@@ -47,7 +48,7 @@ sillyrecords.cc pubsuffix.cc lua-pdns.cc lua-recursor.cc randomhelper.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
 
@@ -69,9 +70,9 @@ mkdir -p $DIRNAME/ext/rapidjson/include/rapidjson/internal
 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
index a3718521c7d7efa456bfe38b6e98a3e54bd65753..c3d41d8e8a2b70e64a1591cdf20715f6133fe5f5 100644 (file)
@@ -21,11 +21,14 @@ arguments.o lwres.o pdns_recursor.o recursor_cache.o dnsparser.o \
 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
index 8db0c57a8bd42149015188d2b8cc801609c3c489..b90559622c90220de340dcc5cbd0d4bb0249c465 100644 (file)
@@ -590,6 +590,7 @@ ixplore_SOURCES = \
        qtype.cc \
        rcpgenerator.cc rcpgenerator.hh \
        resolver.cc \
+       ixfr.cc ixfr.hh \
        ixplore.cc \
        sillyrecords.cc \
        sstuff.hh \
@@ -1111,9 +1112,12 @@ pdns_recursor_SOURCES = \
        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 \
@@ -1134,6 +1138,7 @@ pdns_recursor_SOURCES = \
        recpacketcache.cc recpacketcache.hh \
        recursor_cache.cc recursor_cache.hh \
        reczones.cc \
+       resolver.cc \
        resolver.hh \
        responsestats.cc \
        rpzloader.cc rpzloader.hh \
index 5a31e3d22cd2893e9e530d717c8742217731900d..9e053718fa37fb02bad3c6e0416a538bec7cadef 100644 (file)
@@ -7,7 +7,8 @@
 #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!
 
index 771e1ff277bc918e7300183f8dac55d2f714ce7f..164f4f7fc0f5c58ef81d2806162bd83f44136509 100644 (file)
@@ -41,11 +41,11 @@ bool findNamedPolicy(const map<DNSName, DNSFilterEngine::Policy>& polmap, const
 
 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;
     }
   }
@@ -57,7 +57,7 @@ DNSFilterEngine::Policy DNSFilterEngine::getQueryPolicy(const DNSName& qname, co
 {
   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;
@@ -66,13 +66,13 @@ DNSFilterEngine::Policy DNSFilterEngine::getQueryPolicy(const DNSName& qname, co
     
     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
@@ -98,7 +98,7 @@ DNSFilterEngine::Policy DNSFilterEngine::getPostPolicy(const vector<DNSRecord>&
       }
     }
   }
-  return Policy::NoAction;
+  return Policy{PolicyKind::NoAction};
 }
 
 void DNSFilterEngine::assureZones(int zone)
@@ -131,3 +131,34 @@ void DNSFilterEngine::addNSTrigger(const DNSName& n, Policy pol, 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;
+}
index c8ba699072d8bc83447cae8d7b62c191d0b3e25c..8633eb338ed2e8611ac1c1b3bfb20a4a4b661aaf 100644 (file)
@@ -1,6 +1,7 @@
 #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();
@@ -52,6 +62,12 @@ public:
   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;
index 672a9ff9dba1d9f8964d2720fa3d8b2548f8d97a..a461e0f08c555b571c26954cb27716276c6a297a 100644 (file)
@@ -352,6 +352,12 @@ public:
   {
     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;
diff --git a/pdns/ixfr.cc b/pdns/ixfr.cc
new file mode 100644 (file)
index 0000000..333909a
--- /dev/null
@@ -0,0 +1,88 @@
+#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;
+}
diff --git a/pdns/ixfr.hh b/pdns/ixfr.hh
new file mode 100644 (file)
index 0000000..27a9363
--- /dev/null
@@ -0,0 +1,5 @@
+#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);
index 69cde527dfda7d0201e7f82e900d71265ef3a141..208146416b730b312940ac0ff967967d9d0c701e 100644 (file)
@@ -18,6 +18,7 @@
 #include <boost/multi_index_container.hpp>
 #include "resolver.hh"
 #include <fstream>
+#include "ixfr.hh"
 using namespace boost::multi_index;
 StatBag S;
 
@@ -75,81 +76,6 @@ uint32_t getSerialFromMaster(const ComboAddress& master, const DNSName& zone, sh
   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)
 {
@@ -197,7 +123,8 @@ void writeZoneToDisk(const records_t& records, const DNSName& zone, const std::s
   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());
     }
index f3c7d9220a1bc10bd7a2c8cbf27a82fb3b60d20f..5c5f3dd6bf2aa0774c9e41d39b37a4c6543c3fa9 100644 (file)
@@ -578,7 +578,8 @@ void startDoResolve(void *p)
     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;
@@ -612,23 +613,37 @@ void startDoResolve(void *p)
 
     // 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;
@@ -647,25 +662,26 @@ void startDoResolve(void *p)
         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;   
@@ -673,6 +689,17 @@ void startDoResolve(void *p)
          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()) {
@@ -2396,6 +2423,7 @@ int main(int argc, char **argv)
     ::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")="";
index ca472ca53de1641eac39f050f02110597710ab76..6462ec4dac7fe9fa73e35e220d28b874e9a617b9 100644 (file)
@@ -29,6 +29,8 @@
 #include "logger.hh"
 #include "dnsrecords.hh"
 #include <boost/foreach.hpp>
+#include <thread>
+#include "ixfr.hh"
 #include "rpzloader.hh"
 
 extern int g_argc;
@@ -314,6 +316,61 @@ string reloadAuthAndForwards()
   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;
@@ -322,6 +379,19 @@ void loadRPZFiles()
   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()
index 088b263c389a46ee7526d65d17c3455c99b8abaf..8f7c36366968690ae5cc7247207d62efe282a5b3 100644 (file)
@@ -3,6 +3,8 @@
 #include "dnsparser.hh"
 #include "dnsrecords.hh"
 #include "syncres.hh"
+#include "resolver.hh"
+#include "logger.hh"
 
 static Netmask makeNetmaskFromRPZ(const DNSName& name)
 {
@@ -12,22 +14,121 @@ 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=".";
@@ -36,53 +137,12 @@ int loadRPZFromFile(const std::string& fname, DNSFilterEngine& target, int place
        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) {
index ac72e25f1a144c0c84c52dc02a5a086d90d8666a..57d7ce07c546406b816334c95272003a4e33e8f1 100644 (file)
@@ -1,5 +1,8 @@
 #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);
index df6c66fa78bc58bc34d6d8b9ca6bd2bedb516672..fedf1da268d7620dbe3c84b383bce65f0eeff8e0 100644 (file)
@@ -919,7 +919,8 @@ int SyncRes::doResolveAt(set<DNSName> nameservers, DNSName auth, bool flawedNSSe
         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)) {