]> granicus.if.org Git - pdns/commitdiff
Allow Lua to modify the RPZ decision
authorPieter Lexis <pieter.lexis@powerdns.com>
Fri, 22 Jul 2016 18:56:44 +0000 (20:56 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 25 Aug 2016 08:44:33 +0000 (10:44 +0200)
in preResolve() and postResolve(), the user can now modify the whole
appliedPolicy. For clarity, the appliedPolicy elements have been named
policySomething. one can set the policyKind with the helper
pdns.policykinds.Name.

When the query is not marked as 'handled' by the Lua function, the
(possibly modified) policy is applied to the query.

docs/markdown/recursor/scripting.md
pdns/lua-recursor4.cc
pdns/lua-recursor4.hh
pdns/pdns_recursor.cc

index ebddb0e33356adb8846d91b8710c66566d1a4b85..62c1aa9c94761a4fcc1a6eec0f763cd5606c38dd 100644 (file)
@@ -92,6 +92,11 @@ The DNSQuestion object contains at least the following fields:
   * getFakeAAAARecords: Get a fake AAAA record, see [DNS64](#dns64)
   * getFakePTRRecords: Get a fake PTR record, see [DNS64](#dns64)
   * udpQueryResponse: Do a UDP query and call a handler, see [`udpQueryResponse`](#udpqueryresponse)
+* appliedPolicy - The decision that was made by the policy engine, see [Modifying policy decisions](#modifying-policy-decisions). It has the following fields:
+  * policyName: The name of the policy (used in e.g. protobuf logging)
+  * policyAction: The action taken by the engine
+  * policyCustom: The CNAME content for the `pdns.policyactions.Custom` response, a string
+  * policyTTL: The TTL in seconds for the `pdns.policyactions.Custom` response
 
 It also supports the following methods:
 
@@ -388,3 +393,63 @@ function preoutquery(dq)
        return false
 end
 ```
+
+## Modifying Policy Decisions
+The PowerDNS Recursor has a [policy engine based on Response Policy Zones (RPZ)](settings.md#response-policy-zone-rpz).
+Starting with version 4.0.1 of the recursor, it is possible to alter this decision inside the Lua hooks.
+If the decision is modified in a Lua hook, `false` should be returned, as the query is not actually handled by Lua so the decision is picked up by the Recursor.
+The result of the policy decision is checked after `preresolve` and `postresolve`.
+
+For example, if a decision is set to `pdns.policykinds.NODATA` by the policy engine and is unchanged in `preresolve`, the query is replied to with a NODATA response immediately after `preresolve`.
+
+### Example script
+```
+-- Dont ever block my own domain and IPs
+myDomain = newDN("example.com")
+
+myNetblock = newNMG()
+myNetblock:addMasks("192.0.2.0/24")
+
+function preresolve(dq)
+  if dq.qname:isPartOf(myDomain) and dq.appliedPolicy.policyKind != pdns.policykinds.NoAction then
+    pdnslog("Not blocking our own domain!")
+    dq.appliedPolicy.policyKind = pdns.policykinds.NoAction
+  end
+end
+
+function postresolve(dq)
+  if dq.appliedPolicy.policyKind != pdns.policykinds.NoAction then
+    local records = dq:getRecords()
+    for k,v in pairs(records) do
+      if v.type == pdns.A then
+        local blockedIP = newCA(v:getContent())
+        if myNetblock:match(blockedIP) then
+          pdnslog("Not blocking our IP space")
+          dq.appliedPolicy.policyKind = pdns.policykinds.NoAction
+        end
+      end
+    end
+  end
+end
+```
+
+The decision is contained in the `dq` object under `dq.appliedPolicy` and features 4 fields:
+
+### `dq.appliedPolicy.policyName`
+A string with the name of the policy (set by `polName=` in the `rpzFile` and `rpzMaster` configuration items).
+It is advised to overwrite this when modifying the `policyKind`
+
+### `dq.appliedPolicy.policyKind`
+The kind of policy response, there are several policy kinds:
+
+ * `pdns.policykinds.Custom` will return a NoError, CNAME answer with the value specified in `dq.appliedPolicy.policyCustom`
+ * `pdns.policykinds.Drop` will simply cause the query to be dropped
+ * `pdns.policykinds.NoAction` will continue normal processing of the query
+ * `pdns.policykinds.NODATA` will return a NoError response with no value in the answer section
+ * `pdns.policykinds.NXDOMAIN` will return a response with a NXDomain rcode
+ * `pdns.policykinds.Truncate` will return a NoError, no answer, truncated response over UDP. Normal processing will continue over TCP
+
+### `dq.appliedPolicy.policyCustom` and `dq.appliedPolicy.policyTTL`
+These fields are only used when `dq.appliedPolicy.policyKind` is set to `pdns.policykinds.Custom`.
+`dq.appliedPolicy.policyCustom` contains the name for the CNAME target as a string.
+And `dq.appliedPolicy.policyTTL` is the TTL field (in seconds) for the CNAME response.
index 40f056ac095ee59014ca242b98d2cc98c9458782..4018bd2b4ddbce5772ad8fb6b6a01e027dae8e25 100644 (file)
@@ -27,6 +27,7 @@
 #include "namespaces.hh"
 #include "rec_channel.hh" 
 #include "ednssubnet.hh"
+#include "filterpo.hh"
 #include <unordered_set>
 
 #if !defined(HAVE_LUA)
@@ -45,12 +46,12 @@ bool RecursorLua4::nodata(const ComboAddress& remote,const ComboAddress& local,
   return false;
 }
 
-bool RecursorLua4::postresolve(const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& ret, std::string* appliedPolicy, std::vector<std::string>* policyTags, int& res, bool* variable)
+bool RecursorLua4::postresolve(const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& ret, DNSFilterEngine::Policy* appliedPolicy, std::vector<std::string>* policyTags, int& res, bool* variable)
 {
   return false;
 }
 
-bool RecursorLua4::preresolve(const ComboAddress& remote, const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& ret, const vector<pair<uint16_t,string> >* ednsOpts, unsigned int tag, std::string* appliedPolicy, std::vector<std::string>* policyTags, int& res, bool* variable)
+bool RecursorLua4::preresolve(const ComboAddress& remote, const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& ret, const vector<pair<uint16_t,string> >* ednsOpts, unsigned int tag, DNSFilterEngine::Policy* appliedPolicy, std::vector<std::string>* policyTags, int& res, bool* variable)
 {
   return false;
 }
@@ -359,6 +360,18 @@ RecursorLua4::RecursorLua4(const std::string& fname)
   d_lw->registerMember("udpQueryDest", &DNSQuestion::udpQueryDest);
   d_lw->registerMember("udpCallback", &DNSQuestion::udpCallback);
   d_lw->registerMember("appliedPolicy", &DNSQuestion::appliedPolicy);
+  d_lw->registerMember("policyName", &DNSFilterEngine::Policy::d_name);
+  d_lw->registerMember("policyKind", &DNSFilterEngine::Policy::d_kind);
+  d_lw->registerMember("policyTTL", &DNSFilterEngine::Policy::d_ttl);
+  d_lw->registerMember<DNSFilterEngine::Policy, string>("policyCustom",
+    [](const DNSFilterEngine::Policy& pol) -> string {
+      return pol.d_custom->getZoneRepresentation();
+    },
+    [](DNSFilterEngine::Policy& pol, string content) {
+      // Only CNAMES for now, when we ever add a d_custom_type, there will be pain
+      pol.d_custom = shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(QType::CNAME, 1, content));
+    }
+  );
   d_lw->registerFunction("getEDNSOptions", &DNSQuestion::getEDNSOptions);
   d_lw->registerFunction("getEDNSOption", &DNSQuestion::getEDNSOption);
   d_lw->registerFunction("getEDNSSubnet", &DNSQuestion::getEDNSSubnet);
@@ -465,6 +478,15 @@ RecursorLua4::RecursorLua4(const std::string& fname)
        {"Error", LOG_ERR}
          }});
 
+  pd.push_back({"policykinds", in_t {
+    {"NoAction", (int)DNSFilterEngine::PolicyKind::NoAction},
+    {"Drop",     (int)DNSFilterEngine::PolicyKind::Drop    },
+    {"NXDOMAIN", (int)DNSFilterEngine::PolicyKind::NXDOMAIN},
+    {"NODATA",   (int)DNSFilterEngine::PolicyKind::NODATA  },
+    {"Truncate", (int)DNSFilterEngine::PolicyKind::Truncate},
+    {"Custom",   (int)DNSFilterEngine::PolicyKind::Custom  }
+    }});
+
   for(const auto& n : QType::names)
     pd.push_back({n.first, n.second});
   pd.push_back({"now", &g_now});
@@ -499,7 +521,7 @@ RecursorLua4::RecursorLua4(const std::string& fname)
   d_gettag = d_lw->readVariable<boost::optional<gettag_t>>("gettag").get_value_or(0);
 }
 
-bool RecursorLua4::preresolve(const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, const vector<pair<uint16_t,string> >* ednsOpts, unsigned int tag, std::string* appliedPolicy, std::vector<std::string>* policyTags, int& ret, bool* variable)
+bool RecursorLua4::preresolve(const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, const vector<pair<uint16_t,string> >* ednsOpts, unsigned int tag, DNSFilterEngine::Policy* appliedPolicy, std::vector<std::string>* policyTags, int& ret, bool* variable)
 {
   return genhook(d_preresolve, remote, local, query, qtype, isTcp, res, ednsOpts, tag, appliedPolicy, policyTags, ret, variable);
 }
@@ -514,7 +536,7 @@ bool RecursorLua4::nodata(const ComboAddress& remote,const ComboAddress& local,
   return genhook(d_nodata, remote, local, query, qtype, isTcp, res, 0, 0, nullptr, nullptr, ret, variable);
 }
 
-bool RecursorLua4::postresolve(const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, std::string* appliedPolicy, std::vector<std::string>* policyTags, int& ret, bool* variable)
+bool RecursorLua4::postresolve(const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, DNSFilterEngine::Policy* appliedPolicy, std::vector<std::string>* policyTags, int& ret, bool* variable)
 {
   return genhook(d_postresolve, remote, local, query, qtype, isTcp, res, 0, 0, appliedPolicy, policyTags, ret, variable);
 }
@@ -549,7 +571,7 @@ int RecursorLua4::gettag(const ComboAddress& remote, const Netmask& ednssubnet,
   return 0;
 }
 
-bool RecursorLua4::genhook(luacall_t& func, const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, const vector<pair<uint16_t,string> >* ednsOpts, unsigned int tag, std::string* appliedPolicy, std::vector<std::string>* policyTags, int& ret, bool* variable)
+bool RecursorLua4::genhook(luacall_t& func, const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, const vector<pair<uint16_t,string> >* ednsOpts, unsigned int tag, DNSFilterEngine::Policy* appliedPolicy, std::vector<std::string>* policyTags, int& ret, bool* variable)
 {
   if(!func)
     return false;
@@ -565,6 +587,7 @@ bool RecursorLua4::genhook(luacall_t& func, const ComboAddress& remote,const Com
   dq->isTcp = isTcp;
   dq->rcode = ret;
   dq->policyTags = policyTags;
+  dq->appliedPolicy = appliedPolicy;
   bool handled=func(dq);
   if(variable) *variable |= dq->variable; // could still be set to indicate this *name* is variable, even if not 'handled'
 
@@ -598,9 +621,6 @@ loop:;
       }
     }
     res=dq->records;
-    if (appliedPolicy) {
-      *appliedPolicy=dq->appliedPolicy;
-    }
   }
 
 
index 45e5409da744b2aad26b1171ca2d0848989aa69f..3d08a38666ab52d514eb440767fe3edf80835222 100644 (file)
@@ -24,6 +24,7 @@
 #include "dnsname.hh"
 #include "namespaces.hh"
 #include "dnsrecords.hh"
+#include "filterpo.hh"
 #include <unordered_map>
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -43,10 +44,10 @@ private:
 public:
   explicit RecursorLua4(const std::string& fname);
   ~RecursorLua4(); // this is so unique_ptr works with an incomplete type
-  bool preresolve(const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, const vector<pair<uint16_t,string> >* ednsOpts, unsigned int tag, std::string* appliedPolicy, std::vector<std::string>* policyTags, int& ret, bool* variable);
+  bool preresolve(const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, const vector<pair<uint16_t,string> >* ednsOpts, unsigned int tag, DNSFilterEngine::Policy* appliedPolicy, std::vector<std::string>* policyTags, int& ret, bool* variable);
   bool nxdomain(const ComboAddress& remote, const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret, bool* variable);
   bool nodata(const ComboAddress& remote, const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret, bool* variable);
-  bool postresolve(const ComboAddress& remote, const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, std::string* appliedPolicy, std::vector<std::string>* policyTags, int& ret, bool* variable);
+  bool postresolve(const ComboAddress& remote, const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, DNSFilterEngine::Policy* appliedPolicy, std::vector<std::string>* policyTags, int& ret, bool* variable);
 
   bool preoutquery(const ComboAddress& ns, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret);
   bool ipfilter(const ComboAddress& remote, const ComboAddress& local, const struct dnsheader&);
@@ -87,14 +88,14 @@ private:
     const std::vector<pair<uint16_t, string>>* ednsOptions;
     DNSName followupName;
 
-    string appliedPolicy;
+    DNSFilterEngine::Policy* appliedPolicy;
     std::vector<std::string>* policyTags;
     bool isTcp;
   };
 
   typedef std::function<bool(std::shared_ptr<DNSQuestion>)> luacall_t;
   luacall_t d_preresolve, d_nxdomain, d_nodata, d_postresolve, d_preoutquery, d_postoutquery;
-  bool genhook(luacall_t& func, const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res,  const vector<pair<uint16_t,string> >* ednsOpts, unsigned int tag, std::string* appliedPolicy, std::vector<std::string>* policyTags, int& ret, bool* variable);
+  bool genhook(luacall_t& func, const ComboAddress& remote,const ComboAddress& local, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res,  const vector<pair<uint16_t,string> >* ednsOpts, unsigned int tag, DNSFilterEngine::Policy* appliedPolicy, std::vector<std::string>* policyTags, int& ret, bool* variable);
   typedef std::function<bool(ComboAddress,ComboAddress, struct dnsheader)> ipfilter_t;
   ipfilter_t d_ipfilter;
 };
index 4649ca5d10699c2731d1883259ee248921156634..3d2957b4de1329fea51b89c472911ddbe0a6b6a9 100644 (file)
@@ -611,15 +611,15 @@ catch(...)
 }
 
 #ifdef HAVE_PROTOBUF
-static void protobufLogQuery(const std::shared_ptr<RemoteLogger>& logger, uint8_t maskV4, uint8_t maskV6, const boost::uuids::uuid& uniqueId, const ComboAddress& remote, const ComboAddress& local, const Netmask& ednssubnet, bool tcp, uint16_t id, size_t len, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::string appliedPolicy, const std::vector<std::string>& policyTags)
+static void protobufLogQuery(const std::shared_ptr<RemoteLogger>& logger, uint8_t maskV4, uint8_t maskV6, const boost::uuids::uuid& uniqueId, const ComboAddress& remote, const ComboAddress& local, const Netmask& ednssubnet, bool tcp, uint16_t id, size_t len, const DNSName& qname, uint16_t qtype, uint16_t qclass, const DNSFilterEngine::Policy appliedPolicy, const std::vector<std::string>& policyTags)
 {
   Netmask requestorNM(remote, remote.sin4.sin_family == AF_INET ? maskV4 : maskV6);
   const ComboAddress& requestor = requestorNM.getMaskedNetwork();
   RecProtoBufMessage message(DNSProtoBufMessage::Query, uniqueId, &requestor, &local, qname, qtype, qclass, id, tcp, len);
   message.setEDNSSubnet(ednssubnet, ednssubnet.isIpv4() ? maskV4 : maskV6);
 
-  if (!appliedPolicy.empty()) {
-    message.setAppliedPolicy(appliedPolicy);
+  if (!appliedPolicy.d_name.empty()) {
+    message.setAppliedPolicy(appliedPolicy.d_name);
   }
   if (!policyTags.empty()) {
     message.setPolicyTags(policyTags);
@@ -659,7 +659,7 @@ void startDoResolve(void *p)
     vector<uint8_t> packet;
 
     auto luaconfsLocal = g_luaconfs.getLocal();
-    std::string appliedPolicy;
+    DNSFilterEngine::Policy appliedPolicy;
     RecProtoBufMessage pbMessage(RecProtoBufMessage::Response);
 #ifdef HAVE_PROTOBUF
     if (luaconfsLocal->protobufServer) {
@@ -739,51 +739,47 @@ void startDoResolve(void *p)
     if(!dc->d_mdp.d_header.rd)
       sr.setCacheOnly();
 
+    // Check if the query has a policy attached to it
     dfepol = luaconfsLocal->dfe.getQueryPolicy(dc->d_mdp.d_qname, dc->d_remote);
-
-    switch(dfepol.d_kind) {
-    case DNSFilterEngine::PolicyKind::NoAction:
-      break;
-    case DNSFilterEngine::PolicyKind::Drop:
-      g_stats.policyDrops++;
-      delete dc;
-      dc=0;
-      return; 
-    case DNSFilterEngine::PolicyKind::NXDOMAIN:
-      res=RCode::NXDomain;
-      appliedPolicy=dfepol.d_name;
-      goto haveAnswer;
-
-    case DNSFilterEngine::PolicyKind::NODATA:
-      res=RCode::NoError;
-      appliedPolicy=dfepol.d_name;
-      goto haveAnswer;
-
-    case DNSFilterEngine::PolicyKind::Custom:
-      res=RCode::NoError;
-      spoofed.d_name=dc->d_mdp.d_qname;
-      spoofed.d_type=dfepol.d_custom->getType();
-      spoofed.d_ttl = dfepol.d_ttl;
-      spoofed.d_class = 1;
-      spoofed.d_content = dfepol.d_custom;
-      spoofed.d_place = DNSResourceRecord::ANSWER;
-      ret.push_back(spoofed);
-      appliedPolicy=dfepol.d_name;
-      goto haveAnswer;
-
-
-    case DNSFilterEngine::PolicyKind::Truncate:
-      if(!dc->d_tcp) {
-       res=RCode::NoError;     
-       pw.getHeader()->tc=1;
-        appliedPolicy=dfepol.d_name;
-       goto haveAnswer;
-      }
-      break;
-    }
+    appliedPolicy = dfepol;
 
     // if there is a RecursorLua active, and it 'took' the query in preResolve, we don't launch beginResolve
     if(!t_pdl->get() || !(*t_pdl)->preresolve(dc->d_remote, dc->d_local, dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_tcp, ret, dc->d_ednsOpts.empty() ? 0 : &dc->d_ednsOpts, dc->d_tag, &appliedPolicy, &dc->d_policyTags, res, &variableAnswer)) {
+
+      switch(appliedPolicy.d_kind) {
+        case DNSFilterEngine::PolicyKind::NoAction:
+          break;
+        case DNSFilterEngine::PolicyKind::Drop:
+          g_stats.policyDrops++;
+          delete dc;
+          dc=0;
+          return; 
+        case DNSFilterEngine::PolicyKind::NXDOMAIN:
+          res=RCode::NXDomain;
+          goto haveAnswer;
+        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=appliedPolicy.d_custom->getType();
+          spoofed.d_ttl = appliedPolicy.d_ttl;
+          spoofed.d_class = 1;
+          spoofed.d_content = appliedPolicy.d_custom;
+          spoofed.d_place = DNSResourceRecord::ANSWER;
+          ret.push_back(spoofed);
+          goto haveAnswer;
+        case DNSFilterEngine::PolicyKind::Truncate:
+          if(!dc->d_tcp) {
+            res=RCode::NoError;        
+            pw.getHeader()->tc=1;
+            goto haveAnswer;
+          }
+          break;
+      }
+
+      // Query got not handled for Policy reasons, now actually go out to find an answer
       try {
         res = sr.beginResolve(dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_mdp.d_qclass, ret);
         shouldNotValidate = sr.wasOutOfBand();
@@ -794,8 +790,26 @@ void startDoResolve(void *p)
         res = RCode::ServFail;
       }
 
-      dfepol = luaconfsLocal->dfe.getPostPolicy(ret); 
-      switch(dfepol.d_kind) {
+      dfepol = luaconfsLocal->dfe.getPostPolicy(ret);
+      appliedPolicy = dfepol;
+
+      if(t_pdl->get()) {
+        if(res == RCode::NoError) {
+               auto i=ret.cbegin();
+                for(; i!= ret.cend(); ++i)
+                  if(i->d_type == dc->d_mdp.d_qtype && i->d_place == DNSResourceRecord::ANSWER)
+                          break;
+                if(i == ret.cend())
+                  (*t_pdl)->nodata(dc->d_remote, dc->d_local, dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_tcp, ret, res, &variableAnswer);
+       }
+       else if(res == RCode::NXDomain)
+         (*t_pdl)->nxdomain(dc->d_remote, dc->d_local, dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_tcp, ret, res, &variableAnswer);
+       
+
+       (*t_pdl)->postresolve(dc->d_remote, dc->d_local, dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_tcp, ret, &appliedPolicy, &dc->d_policyTags, res, &variableAnswer);
+      }
+
+      switch(appliedPolicy.d_kind) {
       case DNSFilterEngine::PolicyKind::NoAction:
        break;
       case DNSFilterEngine::PolicyKind::Drop:
@@ -806,13 +820,11 @@ void startDoResolve(void *p)
       case DNSFilterEngine::PolicyKind::NXDOMAIN:
        ret.clear();
        res=RCode::NXDomain;
-        appliedPolicy=dfepol.d_name;
        goto haveAnswer;
        
       case DNSFilterEngine::PolicyKind::NODATA:
        ret.clear();
        res=RCode::NoError;
-        appliedPolicy=dfepol.d_name;
        goto haveAnswer;
        
       case DNSFilterEngine::PolicyKind::Truncate:
@@ -820,7 +832,6 @@ void startDoResolve(void *p)
          ret.clear();
          res=RCode::NoError;   
          pw.getHeader()->tc=1;
-          appliedPolicy=dfepol.d_name;
          goto haveAnswer;
        }
        break;
@@ -829,31 +840,14 @@ void startDoResolve(void *p)
        ret.clear();
        res=RCode::NoError;
        spoofed.d_name=dc->d_mdp.d_qname;
-       spoofed.d_type=dfepol.d_custom->getType();
-       spoofed.d_ttl = dfepol.d_ttl;
+       spoofed.d_type=appliedPolicy.d_custom->getType();
+       spoofed.d_ttl = appliedPolicy.d_ttl;
        spoofed.d_class = 1;
-       spoofed.d_content = dfepol.d_custom;
+       spoofed.d_content = appliedPolicy.d_custom;
        spoofed.d_place = DNSResourceRecord::ANSWER;
        ret.push_back(spoofed);
-        appliedPolicy=dfepol.d_name;
        goto haveAnswer;
       }
-
-      if(t_pdl->get()) {
-        if(res == RCode::NoError) {
-               auto i=ret.cbegin();
-                for(; i!= ret.cend(); ++i)
-                  if(i->d_type == dc->d_mdp.d_qtype && i->d_place == DNSResourceRecord::ANSWER)
-                          break;
-                if(i == ret.cend())
-                  (*t_pdl)->nodata(dc->d_remote, dc->d_local, dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_tcp, ret, res, &variableAnswer);
-       }
-       else if(res == RCode::NXDomain)
-         (*t_pdl)->nxdomain(dc->d_remote, dc->d_local, dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_tcp, ret, res, &variableAnswer);
-       
-
-       (*t_pdl)->postresolve(dc->d_remote, dc->d_local, dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_tcp, ret, &appliedPolicy, &dc->d_policyTags, res, &variableAnswer);
-      }
     }
   haveAnswer:;
     if(res == PolicyDecision::DROP) {
@@ -993,7 +987,7 @@ void startDoResolve(void *p)
     if (luaconfsLocal->protobufServer) {
       pbMessage.setBytes(packet.size());
       pbMessage.setResponseCode(pw.getHeader()->rcode);
-      pbMessage.setAppliedPolicy(appliedPolicy);
+      pbMessage.setAppliedPolicy(appliedPolicy.d_name);
       pbMessage.setPolicyTags(dc->d_policyTags);
       pbMessage.setQueryTime(dc->d_now.tv_sec, dc->d_now.tv_usec);
       protobufLogResponse(luaconfsLocal->protobufServer, pbMessage);
@@ -1240,7 +1234,7 @@ void handleRunningTCPQuestion(int fd, FDMultiplexer::funcparam_t& var)
           getQNameAndSubnet(std::string(conn->data, conn->qlen), &qname, &qtype, &qclass, &ednssubnet);
           dc->d_ednssubnet = ednssubnet;
 
-          protobufLogQuery(luaconfsLocal->protobufServer, luaconfsLocal->protobufMaskV4, luaconfsLocal->protobufMaskV6, dc->d_uuid, dest, conn->d_remote, ednssubnet, true, dh->id, conn->qlen, qname, qtype, qclass, std::string(), std::vector<std::string>());
+          protobufLogQuery(luaconfsLocal->protobufServer, luaconfsLocal->protobufMaskV4, luaconfsLocal->protobufMaskV6, dc->d_uuid, dest, conn->d_remote, ednssubnet, true, dh->id, conn->qlen, qname, qtype, qclass, DNSFilterEngine::Policy(), std::vector<std::string>());
         }
         catch(std::exception& e) {
           if(g_logCommonErrors)
@@ -1382,7 +1376,7 @@ string* doProcessUDPQuestion(const std::string& question, const ComboAddress& fr
     RecProtoBufMessage pbMessage(DNSProtoBufMessage::DNSProtoBufMessageType::Response);
 #ifdef HAVE_PROTOBUF
     if(luaconfsLocal->protobufServer) {
-      protobufLogQuery(luaconfsLocal->protobufServer, luaconfsLocal->protobufMaskV4, luaconfsLocal->protobufMaskV6, uniqueId, fromaddr, destaddr, ednssubnet, false, dh->id, question.size(), qname, qtype, qclass, std::string(), policyTags);
+      protobufLogQuery(luaconfsLocal->protobufServer, luaconfsLocal->protobufMaskV4, luaconfsLocal->protobufMaskV6, uniqueId, fromaddr, destaddr, ednssubnet, false, dh->id, question.size(), qname, qtype, qclass, DNSFilterEngine::Policy(), policyTags);
     }
 #endif /* HAVE_PROTOBUF */