]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
rec: Add bindings to craft answers from the FFI version of gettag
authorRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 23 May 2019 14:18:16 +0000 (16:18 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 8 Jul 2019 13:59:06 +0000 (15:59 +0200)
This will not skip the creation of a MThread since we will need it
to follow CNAME records, if any, and we don't want to worry about
a full parsing of the query and records creation in gettag, but
it prevents the need of calling 'preresolve' which has no FFI
equivalent, as well as the need to carry data around from one
hook to another.

pdns/lua-recursor4-ffi.hh
pdns/lua-recursor4.cc
pdns/lua-recursor4.hh
pdns/pdns_recursor.cc
pdns/syncres.hh

index fb9f63d04f557a5f761f39db6c988e6b20e80ba1..a6e82ccab471f31b95f08d561f7dc47336ddcaab 100644 (file)
@@ -29,6 +29,13 @@ extern "C" {
     const void* data;
   } pdns_ednsoption_t;
 
+  typedef enum
+  {
+    answer = 1,
+    authority = 2,
+    additional = 3
+  } pdns_record_place_t;
+
   const char* pdns_ffi_param_get_qname(pdns_ffi_param_t* ref) __attribute__ ((visibility ("default")));
   void pdns_ffi_param_get_qname_raw(pdns_ffi_param_t* ref, const char** qname, size_t* qnameSize) __attribute__ ((visibility ("default")));
   uint16_t pdns_ffi_param_get_qtype(const pdns_ffi_param_t* ref) __attribute__ ((visibility ("default")));
@@ -54,4 +61,7 @@ extern "C" {
   void pdns_ffi_param_set_variable(pdns_ffi_param_t* ref, bool variable) __attribute__ ((visibility ("default")));
   void pdns_ffi_param_set_ttl_cap(pdns_ffi_param_t* ref, uint32_t ttl) __attribute__ ((visibility ("default")));
   void pdns_ffi_param_set_log_query(pdns_ffi_param_t* ref, bool logQuery) __attribute__ ((visibility ("default")));
+  void pdns_ffi_param_set_rcode(pdns_ffi_param_t* ref, int rcode) __attribute__ ((visibility ("default")));
+  void pdns_ffi_param_set_follow_cname_records(pdns_ffi_param_t* ref, bool follow) __attribute__ ((visibility ("default")));
+  bool pdns_ffi_param_add_record(pdns_ffi_param_t *ref, const char* name, uint16_t type, uint32_t ttl, const char* content, size_t contentSize, pdns_record_place_t place) __attribute__ ((visibility ("default")));
 }
index 7c96133f5369095864caedaec7e220c41f5bf081..ead175a3755ce077d4436687f23df71b721123fd 100644 (file)
 
 RecursorLua4::RecursorLua4() { prepareContext(); }
 
-static int followCNAMERecords(vector<DNSRecord>& ret, const QType& qtype)
-{
-  vector<DNSRecord> resolved;
-  DNSName target;
-  for(const DNSRecord& rr :  ret) {
-    if(rr.d_type == QType::CNAME) {
-      auto rec = getRR<CNAMERecordContent>(rr);
-      if(rec) {
-        target=rec->getTarget();
-        break;
-      }
-    }
-  }
-  if(target.empty())
-    return 0;
-  
-  int rcode=directResolve(target, qtype, 1, resolved); // 1 == class
-  
-  for(const DNSRecord& rr :  resolved) {
-    ret.push_back(rr);
-  }
-  return rcode;
-}
-
 static int getFakeAAAARecords(const DNSName& qname, const std::string& prefix, vector<DNSRecord>& ret)
 {
   int rcode=directResolve(qname, QType(QType::A), 1, ret);
@@ -573,7 +548,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_, const EDNSOptionViewMap& ednsOptions_, std::string& requestorId_, std::string& deviceId_, std::string& deviceName_, uint32_t& ttlCap_, bool& variable_, bool tcp_, bool& logQuery_): qname(qname_), local(local_), remote(remote_), ednssubnet(ednssubnet_), policyTags(policyTags_), ednsOptions(ednsOptions_), requestorId(requestorId_), deviceId(deviceId_), deviceName(deviceName_), ttlCap(ttlCap_), variable(variable_), logQuery(logQuery_), 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_, std::string& requestorId_, std::string& deviceId_, std::string& deviceName_, boost::optional<int>& rcode_, uint32_t& ttlCap_, bool& variable_, bool tcp_, bool& logQuery_, 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_), followCNAMERecords(followCNAMERecords_), qtype(qtype_), tcp(tcp_)
   {
   }
 
@@ -588,23 +563,26 @@ public:
   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& logQuery;
+  bool& followCNAMERecords;
 
   unsigned int tag{0};
   uint16_t qtype;
   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, LuaContext::LuaObject& data, const EDNSOptionViewMap& ednsOptions, bool tcp, std::string& requestorId, std::string& deviceId, std::string& deviceName, uint32_t& ttlCap, bool& variable, bool& logQuery) 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, std::string& requestorId, std::string& deviceId, std::string& deviceName, boost::optional<int>& rcode, uint32_t& ttlCap, bool& variable, bool& logQuery, bool& followCNAMERecords) const
 {
   if (d_gettag_ffi) {
-    pdns_ffi_param_t param(qname, qtype, local, remote, ednssubnet, *policyTags, ednsOptions, requestorId, deviceId, deviceName, ttlCap, variable, tcp, logQuery);
+    pdns_ffi_param_t param(qname, qtype, local, remote, ednssubnet, *policyTags, records, ednsOptions, requestorId, deviceId, deviceName, rcode, ttlCap, variable, tcp, logQuery, followCNAMERecords);
 
     auto ret = d_gettag_ffi(&param);
     if (ret) {
@@ -873,3 +851,33 @@ void pdns_ffi_param_set_log_query(pdns_ffi_param_t* ref, bool logQuery)
 {
   ref->logQuery = logQuery;
 }
+
+void pdns_ffi_param_set_rcode(pdns_ffi_param_t* ref, int rcode)
+{
+  ref->rcode = rcode;
+}
+
+void pdns_ffi_param_set_follow_cname_records(pdns_ffi_param_t* ref, bool follow)
+{
+  ref->followCNAMERecords = follow;
+}
+
+bool pdns_ffi_param_add_record(pdns_ffi_param_t *ref, const char* name, uint16_t type, uint32_t ttl, const char* content, size_t contentSize, pdns_record_place_t place)
+{
+  try {
+    DNSRecord dr;
+    dr.d_name = DNSName(name);
+    dr.d_ttl = ttl;
+    dr.d_type = type;
+    dr.d_class = QClass::IN;
+    dr.d_place = DNSResourceRecord::Place(place);
+    dr.d_content = DNSRecordContent::mastermake(type, QClass::IN, std::string(content, contentSize));
+    ref->records.push_back(std::move(dr));
+
+    return true;
+  }
+  catch (const std::exception& e) {
+    g_log<<Logger::Error<<"Error attempting to add a record from Lua via pdns_ffi_param_add_record(): "<<e.what()<<endl;
+    return false;
+  }
+}
index 7a8a2539b9a62f038af8a87af307b4c0467e5518..91c01fc4ca5fe2c2dd90d20fdc0ae20be635de9c 100644 (file)
@@ -112,7 +112,7 @@ public:
   };
 
   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, LuaContext::LuaObject& data, const EDNSOptionViewMap&, bool tcp, std::string& requestorId, std::string& deviceId, std::string& deviceName, uint32_t& ttlCap, bool& variable, bool& logQuery) 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& followCNAMERecords) const;
 
   void maintenance() const;
   bool prerpz(DNSQuestion& dq, int& ret) const;
index 03e7c05236ca75c87f958d31ee4fe226b10a6c45..7a5fb2d883e151d30eeb35113cc494b905e6d786 100644 (file)
@@ -266,7 +266,7 @@ struct DNSComboWriter {
   {
   }
 
-  DNSComboWriter(const std::string& query, const struct timeval& now, std::vector<std::string>&& policyTags, LuaContext::LuaObject&& data): d_mdp(true, query), d_now(now), d_query(query), d_policyTags(std::move(policyTags)), d_data(std::move(data))
+  DNSComboWriter(const std::string& query, const struct timeval& now, std::vector<std::string>&& policyTags, LuaContext::LuaObject&& data, std::vector<DNSRecord>&& records): d_mdp(true, query), d_now(now), d_query(query), d_policyTags(std::move(policyTags)), d_records(std::move(records)), d_data(std::move(data))
   {
   }
 
@@ -326,9 +326,11 @@ struct DNSComboWriter {
 #endif
   std::string d_query;
   std::vector<std::string> d_policyTags;
+  std::vector<DNSRecord> d_records;
   LuaContext::LuaObject d_data;
   EDNSSubnetOpts d_ednssubnet;
   shared_ptr<TCPConnection> d_tcpConnection;
+  boost::optional<int> d_rcode{boost::none};
   int d_socket;
   unsigned int d_tag{0};
   uint32_t d_qhash{0};
@@ -338,6 +340,7 @@ struct DNSComboWriter {
   bool d_variable{false};
   bool d_ecsFound{false};
   bool d_ecsParsed{false};
+  bool d_followCNAMERecords{false};
   bool d_tcp;
 };
 
@@ -1099,6 +1102,32 @@ static bool udrCheckUniqueDNSRecord(const DNSName& dname, uint16_t qtype, const
 }
 #endif /* NOD_ENABLED */
 
+int followCNAMERecords(vector<DNSRecord>& ret, const QType& qtype)
+{
+  vector<DNSRecord> resolved;
+  DNSName target;
+  for(const DNSRecord& rr :  ret) {
+    if(rr.d_type == QType::CNAME) {
+      auto rec = getRR<CNAMERecordContent>(rr);
+      if(rec) {
+        target=rec->getTarget();
+        break;
+      }
+    }
+  }
+
+  if(target.empty()) {
+    return 0;
+  }
+
+  int rcode = directResolve(target, qtype, QClass::IN, resolved);
+
+  for(DNSRecord& rr :  resolved) {
+    ret.push_back(std::move(rr));
+  }
+  return rcode;
+}
+
 static void startDoResolve(void *p)
 {
   auto dc=std::unique_ptr<DNSComboWriter>(reinterpret_cast<DNSComboWriter*>(p));
@@ -1188,6 +1217,7 @@ static void startDoResolve(void *p)
     uint32_t minTTL = dc->d_ttlCap;
 
     SyncRes sr(dc->d_now);
+    sr.setId(MT->getTid());
 
     bool DNSSECOK=false;
     if(t_pdl) {
@@ -1236,6 +1266,7 @@ static void startDoResolve(void *p)
 
     /* preresolve expects res (dq.rcode) to be set to RCode::NoError by default */
     int res = RCode::NoError;
+
     DNSFilterEngine::Policy appliedPolicy;
     std::vector<DNSRecord> spoofed;
     RecursorLua4::DNSQuestion dq(dc->d_source, dc->d_destination, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_tcp, variableAnswer, wantsRPZ, logResponse);
@@ -1270,7 +1301,6 @@ static void startDoResolve(void *p)
       tracedQuery=true;
     }
 
-
     if(!g_quiet || tracedQuery) {
       g_log<<Logger::Warning<<t_id<<" ["<<MT->getTid()<<"/"<<MT->numProcesses()<<"] " << (dc->d_tcp ? "TCP " : "") << "question for '"<<dc->d_mdp.d_qname<<"|"
        <<DNSRecordContent::NumberToType(dc->d_mdp.d_qtype)<<"' from "<<dc->getRemote();
@@ -1280,9 +1310,19 @@ static void startDoResolve(void *p)
       g_log<<endl;
     }
 
-    sr.setId(MT->getTid());
-    if(!dc->d_mdp.d_header.rd)
+    if(!dc->d_mdp.d_header.rd) {
       sr.setCacheOnly();
+    }
+
+    if (dc->d_rcode != boost::none) {
+      /* we have a response ready to go, most likely from gettag_ffi */
+      ret = std::move(dc->d_records);
+      res = *dc->d_rcode;
+      if (res == RCode::NoError && dc->d_followCNAMERecords) {
+        res = followCNAMERecords(ret, QType(dc->d_mdp.d_qtype));
+      }
+      goto haveAnswer;
+    }
 
     if (t_pdl) {
       t_pdl->prerpz(dq, res);
@@ -2022,7 +2062,7 @@ 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_data, ednsOptions, true, requestorId, deviceId, deviceName, dc->d_ttlCap, dc->d_variable, logQuery);
+                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_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);
@@ -2211,8 +2251,11 @@ static string* doProcessUDPQuestion(const std::string& question, const ComboAddr
   bool ecsParsed = false;
   uint16_t ecsBegin = 0;
   uint16_t ecsEnd = 0;
+  std::vector<DNSRecord> records;
+  boost::optional<int> rcode = boost::none;
   uint32_t ttlCap = std::numeric_limits<uint32_t>::max();
   bool variable = false;
+  bool followCNAMEs = false;
   try {
     DNSName qname;
     uint16_t qtype=0;
@@ -2248,7 +2291,7 @@ 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, data, ednsOptions, false, requestorId, deviceId, deviceName, ttlCap, variable, logQuery);
+              ctag = t_pdl->gettag_ffi(source, ednssubnet.source, destination, qname, qtype, &policyTags, records, data, ednsOptions, false, requestorId, deviceId, deviceName, rcode, ttlCap, variable, logQuery, followCNAMEs);
             }
             else if (t_pdl->d_gettag) {
               ctag = t_pdl->gettag(source, ednssubnet.source, destination, qname, qtype, &policyTags, data, ednsOptions, false, requestorId, deviceId, deviceName);
@@ -2366,7 +2409,7 @@ static string* doProcessUDPQuestion(const std::string& question, const ComboAddr
     return 0;
   }
 
-  auto dc = std::unique_ptr<DNSComboWriter>(new DNSComboWriter(question, g_now, std::move(policyTags), std::move(data)));
+  auto dc = std::unique_ptr<DNSComboWriter>(new DNSComboWriter(question, g_now, std::move(policyTags), std::move(data), std::move(records)));
   dc->setSocket(fd);
   dc->d_tag=ctag;
   dc->d_qhash=qhash;
@@ -2382,6 +2425,8 @@ static string* doProcessUDPQuestion(const std::string& question, const ComboAddr
   dc->d_ednssubnet = ednssubnet;
   dc->d_ttlCap = ttlCap;
   dc->d_variable = variable;
+  dc->d_followCNAMERecords = followCNAMEs;
+  dc->d_rcode = rcode;
 #ifdef HAVE_PROTOBUF
   if (t_protobufServers || t_outgoingProtobufServers) {
     dc->d_uuid = std::move(uniqueId);
index 06626f710cf3e563e2d8ace76c3c48ece54b053d..8adae910acf3da262ce72ca2dc632aff02dea49e 100644 (file)
@@ -1052,6 +1052,7 @@ void broadcastFunction(const pipefunc_t& func);
 void distributeAsyncFunction(const std::string& question, const pipefunc_t& func);
 
 int directResolve(const DNSName& qname, const QType& qtype, int qclass, vector<DNSRecord>& ret);
+int followCNAMERecords(std::vector<DNSRecord>& ret, const QType& qtype);
 
 template<class T> T broadcastAccFunction(const boost::function<T*()>& func);