]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
rec: Export Proxy Protocol values to gettag hooks
authorRemi Gacogne <remi.gacogne@powerdns.com>
Wed, 26 Feb 2020 17:25:24 +0000 (18:25 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 17 Mar 2020 13:12:55 +0000 (14:12 +0100)
pdns/lua-recursor4-ffi.hh
pdns/lua-recursor4.cc
pdns/lua-recursor4.hh
pdns/pdns_recursor.cc

index 47396a8386ecaa3607122712f6b7cba4de403e81..d852fbeb05703287e480c6c0e80da6c17f8f7e24 100644 (file)
@@ -29,6 +29,12 @@ extern "C" {
     const void* data;
   } pdns_ednsoption_t;
 
+  typedef struct pdns_proxyprotocol_value {
+    uint8_t     type;
+    uint16_t    len;
+    const void* data;
+  } pdns_proxyprotocol_value_t;
+
   typedef enum
   {
     answer = 1,
@@ -53,6 +59,9 @@ extern "C" {
   size_t pdns_ffi_param_get_edns_options(pdns_ffi_param_t* ref, const pdns_ednsoption_t** out) __attribute__ ((visibility ("default")));
   size_t pdns_ffi_param_get_edns_options_by_code(pdns_ffi_param_t* ref, uint16_t optionCode, const pdns_ednsoption_t** out) __attribute__ ((visibility ("default")));
 
+  // returns the length of the resulting 'out' array. 'out' is not set if the length is 0
+  size_t pdns_ffi_param_get_proxy_protocol_values(pdns_ffi_param_t* ref, const pdns_proxyprotocol_value_t** out) __attribute__ ((visibility ("default")));
+
   void pdns_ffi_param_set_tag(pdns_ffi_param_t* ref, unsigned int tag) __attribute__ ((visibility ("default")));
   void pdns_ffi_param_add_policytag(pdns_ffi_param_t *ref, const char* name) __attribute__ ((visibility ("default")));
   void pdns_ffi_param_set_requestorid(pdns_ffi_param_t* ref, const char* name) __attribute__ ((visibility ("default")));
index e8b413f2ebd9b75388738efd6e6ffbd1d8a78d16..404a773d8dd91b530283b96b713e9df41c15052b 100644 (file)
@@ -183,14 +183,15 @@ boost::optional<Netmask>  RecursorLua4::DNSQuestion::getEDNSSubnet() const
   return boost::optional<Netmask>();
 }
 
-std::vector<std::pair<uint8_t, string>> RecursorLua4::DNSQuestion::getProxyProtocolValues() const
+std::vector<std::pair<int, ProxyProtocolValue>> RecursorLua4::DNSQuestion::getProxyProtocolValues() const
 {
-  std::vector<std::pair<uint8_t, string>> result;
+  std::vector<std::pair<int, ProxyProtocolValue>> result;
   if (proxyProtocolValues) {
     result.reserve(proxyProtocolValues->size());
 
+    int idx = 1;
     for (const auto& value: *proxyProtocolValues) {
-      result.push_back({ value.type, value.content });
+      result.push_back({ idx++, value });
     }
   }
 
@@ -350,6 +351,8 @@ void RecursorLua4::postPrepareContext()
       return ret;
     });
 
+  d_lw->registerFunction<const ProxyProtocolValue, std::string()>("getContent", [](const ProxyProtocolValue& value) { return value.content; });
+  d_lw->registerFunction<const ProxyProtocolValue, uint8_t()>("getType", [](const ProxyProtocolValue& value) { return value.type; });
 
   d_lw->registerFunction<void(DNSRecord::*)(const std::string&)>("changeContent", [](DNSRecord& dr, const std::string& newContent) { dr.d_content = DNSRecordContent::mastermake(dr.d_type, 1, newContent); });
   d_lw->registerFunction("addAnswer", &DNSQuestion::addAnswer);
@@ -534,10 +537,17 @@ bool RecursorLua4::ipfilter(const ComboAddress& remote, const ComboAddress& loca
   return false; // don't block
 }
 
-unsigned int RecursorLua4::gettag(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::vector<std::string>* policyTags, LuaContext::LuaObject& data, const EDNSOptionViewMap& ednsOptions, bool tcp, std::string& requestorId, std::string& deviceId, std::string& deviceName) const
+unsigned int RecursorLua4::gettag(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::vector<std::string>* policyTags, LuaContext::LuaObject& data, const EDNSOptionViewMap& ednsOptions, bool tcp, std::string& requestorId, std::string& deviceId, std::string& deviceName, const std::vector<ProxyProtocolValue>& proxyProtocolValues) const
 {
   if(d_gettag) {
-    auto ret = d_gettag(remote, ednssubnet, local, qname, qtype, ednsOptions, tcp);
+    std::vector<std::pair<int, const ProxyProtocolValue*>> proxyProtocolValuesMap;
+    proxyProtocolValuesMap.reserve(proxyProtocolValues.size());
+    int num = 1;
+    for (const auto& value : proxyProtocolValues) {
+      proxyProtocolValuesMap.emplace_back(num++, &value);
+    }
+
+    auto ret = d_gettag(remote, ednssubnet, local, qname, qtype, ednsOptions, tcp, proxyProtocolValuesMap);
 
     if (policyTags) {
       const auto& tags = std::get<1>(ret);
@@ -572,7 +582,7 @@ unsigned int RecursorLua4::gettag(const ComboAddress& remote, const Netmask& edn
 struct pdns_ffi_param
 {
 public:
-  pdns_ffi_param(const DNSName& qname_, uint16_t qtype_, const ComboAddress& local_, const ComboAddress& remote_, const Netmask& ednssubnet_, std::vector<std::string>& policyTags_, std::vector<DNSRecord>& records_, const EDNSOptionViewMap& ednsOptions_, std::string& requestorId_, std::string& deviceId_, std::string& deviceName_, boost::optional<int>& rcode_, uint32_t& ttlCap_, bool& variable_, bool tcp_, bool& logQuery_, bool& logResponse_, bool& followCNAMERecords_): qname(qname_), local(local_), remote(remote_), ednssubnet(ednssubnet_), policyTags(policyTags_), records(records_), ednsOptions(ednsOptions_), requestorId(requestorId_), deviceId(deviceId_), deviceName(deviceName_), rcode(rcode_), ttlCap(ttlCap_), variable(variable_), logQuery(logQuery_), logResponse(logResponse_), followCNAMERecords(followCNAMERecords_), qtype(qtype_), tcp(tcp_)
+  pdns_ffi_param(const DNSName& qname_, uint16_t qtype_, const ComboAddress& local_, const ComboAddress& remote_, const Netmask& ednssubnet_, std::vector<std::string>& policyTags_, std::vector<DNSRecord>& records_, const EDNSOptionViewMap& ednsOptions_, const std::vector<ProxyProtocolValue>& proxyProtocolValues_, std::string& requestorId_, std::string& deviceId_, std::string& deviceName_, boost::optional<int>& rcode_, uint32_t& ttlCap_, bool& variable_, bool tcp_, bool& logQuery_, bool& logResponse_, bool& followCNAMERecords_): qname(qname_), local(local_), remote(remote_), ednssubnet(ednssubnet_), policyTags(policyTags_), records(records_), ednsOptions(ednsOptions_), proxyProtocolValues(proxyProtocolValues_), requestorId(requestorId_), deviceId(deviceId_), deviceName(deviceName_), rcode(rcode_), ttlCap(ttlCap_), variable(variable_), logQuery(logQuery_), logResponse(logResponse_), followCNAMERecords(followCNAMERecords_), qtype(qtype_), tcp(tcp_)
   {
   }
 
@@ -581,6 +591,7 @@ public:
   std::unique_ptr<std::string> remoteStr{nullptr};
   std::unique_ptr<std::string> ednssubnetStr{nullptr};
   std::vector<pdns_ednsoption_t> ednsOptionsVect;
+  std::vector<pdns_proxyprotocol_value_t> proxyProtocolValuesVect;
 
   const DNSName& qname;
   const ComboAddress& local;
@@ -589,6 +600,7 @@ public:
   std::vector<std::string>& policyTags;
   std::vector<DNSRecord>& records;
   const EDNSOptionViewMap& ednsOptions;
+  const std::vector<ProxyProtocolValue>& proxyProtocolValues;
   std::string& requestorId;
   std::string& deviceId;
   std::string& deviceName;
@@ -604,10 +616,10 @@ public:
   bool tcp;
 };
 
-unsigned int RecursorLua4::gettag_ffi(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::vector<std::string>* policyTags, std::vector<DNSRecord>& records, LuaContext::LuaObject& data, const EDNSOptionViewMap& ednsOptions, bool tcp, std::string& requestorId, std::string& deviceId, std::string& deviceName, boost::optional<int>& rcode, uint32_t& ttlCap, bool& variable, bool& logQuery, bool& logResponse, bool& followCNAMERecords) const
+unsigned int RecursorLua4::gettag_ffi(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::vector<std::string>* policyTags, std::vector<DNSRecord>& records, LuaContext::LuaObject& data, const EDNSOptionViewMap& ednsOptions, bool tcp, const std::vector<ProxyProtocolValue>& proxyProtocolValues, std::string& requestorId, std::string& deviceId, std::string& deviceName, boost::optional<int>& rcode, uint32_t& ttlCap, bool& variable, bool& logQuery, bool& logResponse, bool& followCNAMERecords) const
 {
   if (d_gettag_ffi) {
-    pdns_ffi_param_t param(qname, qtype, local, remote, ednssubnet, *policyTags, records, ednsOptions, requestorId, deviceId, deviceName, rcode, ttlCap, variable, tcp, logQuery, logResponse, followCNAMERecords);
+    pdns_ffi_param_t param(qname, qtype, local, remote, ednssubnet, *policyTags, records, ednsOptions, proxyProtocolValues, requestorId, deviceId, deviceName, rcode, ttlCap, variable, tcp, logQuery, logResponse, followCNAMERecords);
 
     auto ret = d_gettag_ffi(&param);
     if (ret) {
@@ -837,6 +849,30 @@ size_t pdns_ffi_param_get_edns_options_by_code(pdns_ffi_param_t* ref, uint16_t o
   return pos;
 }
 
+size_t pdns_ffi_param_get_proxy_protocol_values(pdns_ffi_param_t* ref, const pdns_proxyprotocol_value_t** out)
+{
+  if (ref->proxyProtocolValues.empty()) {
+    return 0;
+  }
+
+  ref->proxyProtocolValuesVect.resize(ref->proxyProtocolValues.size());
+
+  size_t pos = 0;
+  for (const auto& value : ref->proxyProtocolValues) {
+    auto& dest = ref->proxyProtocolValuesVect.at(pos);
+    dest.type = value.type;
+    dest.len = value.content.size();
+    if (dest.len > 0) {
+      dest.data = value.content.data();
+    }
+    pos++;
+  }
+
+  *out = ref->proxyProtocolValuesVect.data();
+
+  return ref->proxyProtocolValuesVect.size();
+}
+
 void pdns_ffi_param_set_tag(pdns_ffi_param_t* ref, unsigned int tag)
 {
   ref->tag = tag;
index 8e3e082bd7d65f227f797e1474664604cbb8ba1e..88bf6fea8ccd908f0fa54b04d4b46a1698ea0770 100644 (file)
@@ -94,7 +94,7 @@ public:
     vector<pair<uint16_t, string> > getEDNSOptions() const;
     boost::optional<string> getEDNSOption(uint16_t code) const;
     boost::optional<Netmask> getEDNSSubnet() const;
-    std::vector<std::pair<uint8_t, string>> getProxyProtocolValues() const;
+    std::vector<std::pair<int, ProxyProtocolValue>> getProxyProtocolValues() const;
     vector<string> getEDNSFlags() const;
     bool getEDNSFlag(string flag) const;
     void setRecords(const vector<pair<int,DNSRecord> >& records);
@@ -115,8 +115,8 @@ public:
     DNSName followupName;
   };
 
-  unsigned int gettag(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::vector<std::string>* policyTags, LuaContext::LuaObject& data, const EDNSOptionViewMap&, bool tcp, std::string& requestorId, std::string& deviceId, std::string& deviceName) const;
-  unsigned int gettag_ffi(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::vector<std::string>* policyTags, std::vector<DNSRecord>& records, LuaContext::LuaObject& data, const EDNSOptionViewMap& ednsOptions, bool tcp, std::string& requestorId, std::string& deviceId, std::string& deviceName, boost::optional<int>& rcode, uint32_t& ttlCap, bool& variable, bool& logQuery, bool& logResponse, bool& followCNAMERecords) const;
+  unsigned int gettag(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::vector<std::string>* policyTags, LuaContext::LuaObject& data, const EDNSOptionViewMap&, bool tcp, std::string& requestorId, std::string& deviceId, std::string& deviceName, const std::vector<ProxyProtocolValue>& proxyProtocolValues) const;
+  unsigned int gettag_ffi(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::vector<std::string>* policyTags, std::vector<DNSRecord>& records, LuaContext::LuaObject& data, const EDNSOptionViewMap& ednsOptions, bool tcp, const std::vector<ProxyProtocolValue>& proxyProtocolValues, std::string& requestorId, std::string& deviceId, std::string& deviceName, boost::optional<int>& rcode, uint32_t& ttlCap, bool& variable, bool& logQuery, bool& logResponse, bool& followCNAMERecords) const;
 
   void maintenance() const;
   bool prerpz(DNSQuestion& dq, int& ret) const;
@@ -137,7 +137,7 @@ public:
             d_postresolve);
   }
 
-  typedef std::function<std::tuple<unsigned int,boost::optional<std::unordered_map<int,string> >,boost::optional<LuaContext::LuaObject>,boost::optional<std::string>,boost::optional<std::string>,boost::optional<std::string> >(ComboAddress, Netmask, ComboAddress, DNSName, uint16_t, const EDNSOptionViewMap&, bool)> gettag_t;
+  typedef std::function<std::tuple<unsigned int,boost::optional<std::unordered_map<int,string> >,boost::optional<LuaContext::LuaObject>,boost::optional<std::string>,boost::optional<std::string>,boost::optional<std::string> >(ComboAddress, Netmask, ComboAddress, DNSName, uint16_t, const EDNSOptionViewMap&, bool, const std::vector<std::pair<int, const ProxyProtocolValue*>>&)> gettag_t;
   gettag_t d_gettag; // public so you can query if we have this hooked
   typedef std::function<boost::optional<LuaContext::LuaObject>(pdns_ffi_param_t*)> gettag_ffi_t;
   gettag_ffi_t d_gettag_ffi;
index f20c1174e4d89e31f69d5e7fa4c3b3ceb1365a70..24a94fcd88b6155b7b27fcc74a07aa6747f6ae00 100644 (file)
@@ -2032,6 +2032,9 @@ static void handleRunningTCPQuestion(int fd, FDMultiplexer::funcparam_t& var)
     conn->data.resize(conn->proxyProtocolGot);
     ssize_t remaining = isProxyHeaderComplete(conn->data);
     if (remaining == 0) {
+      if (g_logCommonErrors) {
+        g_log<<Logger::Error<<"Unable to consume proxy protocol header in packet from TCP client "<< conn->d_remote.toStringWithPort() <<endl;
+      }
       ++g_stats.proxyProtocolInvalidCount;
       t_fdm->removeReadFD(fd);
       return;
@@ -2048,6 +2051,10 @@ static void handleRunningTCPQuestion(int fd, FDMultiplexer::funcparam_t& var)
       bool tcp;
       bool proxy = false;
       if (parseProxyHeader(conn->data, proxy, conn->d_source, conn->d_destination, tcp, conn->proxyProtocolValues) <= 0) {
+        if (g_logCommonErrors) {
+          g_log<<Logger::Error<<"Unable to parse proxy protocol header in packet from TCP client "<< conn->d_remote.toStringWithPort() <<endl;
+        }
+        ++g_stats.proxyProtocolInvalidCount;
         t_fdm->removeReadFD(fd);
         return;
       }
@@ -2182,10 +2189,10 @@ static void handleRunningTCPQuestion(int fd, FDMultiplexer::funcparam_t& var)
           if(t_pdl) {
             try {
               if (t_pdl->d_gettag_ffi) {
-                dc->d_tag = t_pdl->gettag_ffi(dc->d_source, dc->d_ednssubnet.source, dc->d_destination, qname, qtype, &dc->d_policyTags, dc->d_records, dc->d_data, ednsOptions, true, requestorId, deviceId, deviceName, dc->d_rcode, dc->d_ttlCap, dc->d_variable, logQuery, dc->d_logResponse, dc->d_followCNAMERecords);
+                dc->d_tag = t_pdl->gettag_ffi(dc->d_source, dc->d_ednssubnet.source, dc->d_destination, qname, qtype, &dc->d_policyTags, dc->d_records, dc->d_data, ednsOptions, true, dc->d_proxyProtocolValues, requestorId, deviceId, deviceName, dc->d_rcode, dc->d_ttlCap, dc->d_variable, logQuery, dc->d_logResponse, dc->d_followCNAMERecords);
               }
               else if (t_pdl->d_gettag) {
-                dc->d_tag = t_pdl->gettag(dc->d_source, dc->d_ednssubnet.source, dc->d_destination, qname, qtype, &dc->d_policyTags, dc->d_data, ednsOptions, true, requestorId, deviceId, deviceName);
+                dc->d_tag = t_pdl->gettag(dc->d_source, dc->d_ednssubnet.source, dc->d_destination, qname, qtype, &dc->d_policyTags, dc->d_data, ednsOptions, true, requestorId, deviceId, deviceName, dc->d_proxyProtocolValues);
               }
             }
             catch(const std::exception& e)  {
@@ -2440,10 +2447,10 @@ static string* doProcessUDPQuestion(const std::string& question, const ComboAddr
         if(t_pdl) {
           try {
             if (t_pdl->d_gettag_ffi) {
-              ctag = t_pdl->gettag_ffi(source, ednssubnet.source, destination, qname, qtype, &policyTags, records, data, ednsOptions, false, requestorId, deviceId, deviceName, rcode, ttlCap, variable, logQuery, logResponse, followCNAMEs);
+              ctag = t_pdl->gettag_ffi(source, ednssubnet.source, destination, qname, qtype, &policyTags, records, data, ednsOptions, false, proxyProtocolValues, requestorId, deviceId, deviceName, rcode, ttlCap, variable, logQuery, logResponse, followCNAMEs);
             }
             else if (t_pdl->d_gettag) {
-              ctag = t_pdl->gettag(source, ednssubnet.source, destination, qname, qtype, &policyTags, data, ednsOptions, false, requestorId, deviceId, deviceName);
+              ctag = t_pdl->gettag(source, ednssubnet.source, destination, qname, qtype, &policyTags, data, ednsOptions, false, requestorId, deviceId, deviceName, proxyProtocolValues);
             }
           }
           catch(const std::exception& e)  {
@@ -2638,7 +2645,7 @@ static void handleNewUDPQuestion(int fd, FDMultiplexer::funcparam_t& var)
         if (used <= 0) {
           ++g_stats.proxyProtocolInvalidCount;
           if (!g_quiet) {
-            g_log<<Logger::Error<<"Ignoring invalid proxy protocol ("<<std::to_string(len)<<") query from "<<fromaddr.toString()<<endl;
+            g_log<<Logger::Error<<"Ignoring invalid proxy protocol ("<<std::to_string(len)<<", "<<std::to_string(used)<<") query from "<<fromaddr.toString()<<endl;
           }
           return;
         }
@@ -2671,12 +2678,13 @@ static void handleNewUDPQuestion(int fd, FDMultiplexer::funcparam_t& var)
 
       if(t_allowFrom && !t_allowFrom->match(&source)) {
         if(!g_quiet) {
-          g_log<<Logger::Error<<"["<<MT->getTid()<<"] dropping UDP query from "<<fromaddr.toString()<<", address not matched by allow-from"<<endl;
+          g_log<<Logger::Error<<"["<<MT->getTid()<<"] dropping UDP query from "<<source.toString()<<", address not matched by allow-from"<<endl;
         }
 
         g_stats.unauthorizedUDP++;
         return;
       }
+
       BOOST_STATIC_ASSERT(offsetof(sockaddr_in, sin_port) == offsetof(sockaddr_in6, sin6_port));
       if(!fromaddr.sin4.sin_port) { // also works for IPv6
         if(!g_quiet) {