]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Add response flags to ERCodeAction, HTTPStatusAction and RCodeAction
authorRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 19 Nov 2019 10:49:25 +0000 (11:49 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 20 Jan 2020 09:16:24 +0000 (10:16 +0100)
pdns/dnsdist-lua-actions.cc
pdns/dnsdist-lua.hh
pdns/dnsdistdist/docs/rules-actions.rst

index a60bd1f77be5b12f9704232dea79df869fcc682e..cc714d23d36e1bc31dfe578eed317419f7c9d426 100644 (file)
@@ -306,6 +306,7 @@ public:
   {
     dq->dh->rcode = d_rcode;
     dq->dh->qr = true; // for good measure
+    setResponseHeadersFromConfig(*dq->dh, d_responseConfig);
     return Action::HeaderModify;
   }
   std::string toString() const override
@@ -313,6 +314,7 @@ public:
     return "set rcode "+std::to_string(d_rcode);
   }
 
+  ResponseConfig d_responseConfig;
 private:
   uint8_t d_rcode;
 };
@@ -326,6 +328,7 @@ public:
     dq->dh->rcode = (d_rcode & 0xF);
     dq->ednsRCode = ((d_rcode & 0xFFF0) >> 4);
     dq->dh->qr = true; // for good measure
+    setResponseHeadersFromConfig(*dq->dh, d_responseConfig);
     return Action::HeaderModify;
   }
   std::string toString() const override
@@ -333,6 +336,7 @@ public:
     return "set ercode "+ERCode::to_s(d_rcode);
   }
 
+  ResponseConfig d_responseConfig;
 private:
   uint8_t d_rcode;
 };
@@ -444,21 +448,7 @@ DNSAction::Action SpoofAction::operator()(DNSQuestion* dq, std::string* ruleresu
   char* dest = ((char*)dq->dh) + dq->len;
 
   dq->dh->qr = true; // for good measure
-  if (d_setAA) {
-    dq->dh->aa = *d_setAA;
-  }
-  if (d_setAD) {
-    dq->dh->ad = *d_setAD;
-  }
-  else {
-    dq->dh->ad = false;
-  }
-  if (d_setRA) {
-    dq->dh->ra = *d_setRA;
-  }
-  else {
-    dq->dh->ra = dq->dh->rd; // for good measure
-  }
+  setResponseHeadersFromConfig(*dq->dh, d_responseConfig);
   dq->dh->ancount = 0;
   dq->dh->arcount = 0; // for now, forget about your EDNS, we're marching over it
 
@@ -1192,6 +1182,7 @@ public:
 
     dq->du->setHTTPResponse(d_code, d_body, d_contentType);
     dq->dh->qr = true; // for good measure
+    setResponseHeadersFromConfig(*dq->dh, d_responseConfig);
     return Action::HeaderModify;
   }
 
@@ -1199,6 +1190,8 @@ public:
   {
     return "return an HTTP status of " + std::to_string(d_code);
   }
+
+  ResponseConfig d_responseConfig;
 private:
   std::string d_body;
   std::string d_contentType;
@@ -1257,23 +1250,42 @@ static void addAction(GlobalStateHolder<vector<T> > *someRulActions, const luadn
     });
 }
 
-typedef std::unordered_map<std::string, boost::variant<bool> > spoofparams_t;
+typedef std::unordered_map<std::string, boost::variant<bool> > responseParams_t;
 
-static void parseSpoofConfig(boost::optional<spoofparams_t> vars, boost::optional<bool>& setAA, boost::optional<bool>& setAD, boost::optional<bool>& setRA)
+static void parseResponseConfig(boost::optional<responseParams_t> vars, ResponseConfig& config)
 {
   if (vars) {
     if (vars->count("aa")) {
-      setAA = boost::get<bool>((*vars)["aa"]);
+      config.setAA = boost::get<bool>((*vars)["aa"]);
     }
     if (vars->count("ad")) {
-      setAD = boost::get<bool>((*vars)["ad"]);
+      config.setAD = boost::get<bool>((*vars)["ad"]);
     }
     if (vars->count("ra")) {
-      setRA = boost::get<bool>((*vars)["ra"]);
+      config.setRA = boost::get<bool>((*vars)["ra"]);
     }
   }
 }
 
+void setResponseHeadersFromConfig(dnsheader& dh, const ResponseConfig& config)
+{
+  if (config.setAA) {
+    dh.aa = *config.setAA;
+  }
+  if (config.setAD) {
+    dh.ad = *config.setAD;
+  }
+  else {
+    dh.ad = false;
+  }
+  if (config.setRA) {
+    dh.ra = *config.setRA;
+  }
+  else {
+    dh.ra = dh.rd; // for good measure
+  }
+}
+
 void setupLuaActions()
 {
   g_lua.writeFunction("newRuleAction", [](luadnsrule_t dnsrule, std::shared_ptr<DNSAction> action, boost::optional<luaruleparams_t> params) {
@@ -1366,7 +1378,7 @@ void setupLuaActions()
       return std::shared_ptr<DNSAction>(new QPSPoolAction(limit, a));
     });
 
-  g_lua.writeFunction("SpoofAction", [](boost::variant<std::string,vector<pair<int, std::string>>> inp, boost::optional<std::string> b, boost::optional<spoofparams_t> vars ) {
+  g_lua.writeFunction("SpoofAction", [](boost::variant<std::string,vector<pair<int, std::string>>> inp, boost::optional<std::string> b, boost::optional<responseParams_t> vars ) {
       vector<ComboAddress> addrs;
       if(auto s = boost::get<std::string>(&inp))
         addrs.push_back(ComboAddress(*s));
@@ -1380,41 +1392,18 @@ void setupLuaActions()
       }
 
       auto ret = std::shared_ptr<DNSAction>(new SpoofAction(addrs));
-      boost::optional<bool> setAA = boost::none;
-      boost::optional<bool> setAD = boost::none;
-      boost::optional<bool> setRA = boost::none;
-      parseSpoofConfig(vars, setAA, setAD, setRA);
       auto sa = std::dynamic_pointer_cast<SpoofAction>(ret);
-      if (setAA) {
-        sa->setAA(*setAA);
-      }
-      if (setAD) {
-        sa->setAD(*setAD);
-      }
-      if (setRA) {
-        sa->setRA(*setRA);
-      }
+      parseResponseConfig(vars, sa->d_responseConfig);
       return ret;
     });
 
-  g_lua.writeFunction("SpoofCNAMEAction", [](const std::string& a, boost::optional<spoofparams_t> vars) {
+  g_lua.writeFunction("SpoofCNAMEAction", [](const std::string& a, boost::optional<responseParams_t> vars) {
       auto ret = std::shared_ptr<DNSAction>(new SpoofAction(a));
-      boost::optional<bool> setAA = boost::none;
-      boost::optional<bool> setAD = boost::none;
-      boost::optional<bool> setRA = boost::none;
-      parseSpoofConfig(vars, setAA, setAD, setRA);
+      ResponseConfig responseConfig;
+      parseResponseConfig(vars, responseConfig);
       auto sa = std::dynamic_pointer_cast<SpoofAction>(ret);
-      if (setAA) {
-        sa->setAA(*setAA);
-      }
-      if (setAD) {
-        sa->setAD(*setAD);
-      }
-      if (setRA) {
-        sa->setRA(*setRA);
-      }
+      sa->d_responseConfig = responseConfig;
       return ret;
-
     });
 
   g_lua.writeFunction("DropAction", []() {
@@ -1449,12 +1438,18 @@ void setupLuaActions()
       return std::shared_ptr<DNSResponseAction>(new LogResponseAction(fname ? *fname : "", append ? *append : false, buffered ? *buffered : false, verboseOnly ? *verboseOnly : true, includeTimestamp ? *includeTimestamp : false));
     });
 
-  g_lua.writeFunction("RCodeAction", [](uint8_t rcode) {
-      return std::shared_ptr<DNSAction>(new RCodeAction(rcode));
+  g_lua.writeFunction("RCodeAction", [](uint8_t rcode, boost::optional<responseParams_t> vars) {
+      auto ret = std::shared_ptr<DNSAction>(new RCodeAction(rcode));
+      auto rca = std::dynamic_pointer_cast<RCodeAction>(ret);
+      parseResponseConfig(vars, rca->d_responseConfig);
+      return ret;
     });
 
-  g_lua.writeFunction("ERCodeAction", [](uint8_t rcode) {
-      return std::shared_ptr<DNSAction>(new ERCodeAction(rcode));
+  g_lua.writeFunction("ERCodeAction", [](uint8_t rcode, boost::optional<responseParams_t> vars) {
+      auto ret = std::shared_ptr<DNSAction>(new ERCodeAction(rcode));
+      auto erca = std::dynamic_pointer_cast<ERCodeAction>(ret);
+      parseResponseConfig(vars, erca->d_responseConfig);
+      return ret;
     });
 
   g_lua.writeFunction("SkipCacheAction", []() {
@@ -1606,8 +1601,11 @@ void setupLuaActions()
     });
 
 #ifdef HAVE_DNS_OVER_HTTPS
-  g_lua.writeFunction("HTTPStatusAction", [](uint16_t status, std::string body, boost::optional<std::string> contentType) {
-      return std::shared_ptr<DNSAction>(new HTTPStatusAction(status, body, contentType ? *contentType : ""));
+  g_lua.writeFunction("HTTPStatusAction", [](uint16_t status, std::string body, boost::optional<std::string> contentType, boost::optional<responseParams_t> vars) {
+      auto ret = std::shared_ptr<DNSAction>(new HTTPStatusAction(status, body, contentType ? *contentType : ""));
+      auto hsa = std::dynamic_pointer_cast<HTTPStatusAction>(ret);
+      parseResponseConfig(vars, hsa->d_responseConfig);
+      return ret;
     });
 #endif /* HAVE_DNS_OVER_HTTPS */
 
index 89f49c0ee905a075e51b0a4cbf7415ee735cd335..aa33859c8001f47c956ab50137893c1f70af6f90 100644 (file)
  */
 #pragma once
 
+struct ResponseConfig
+{
+  boost::optional<bool> setAA{boost::none};
+  boost::optional<bool> setAD{boost::none};
+  boost::optional<bool> setRA{boost::none};
+};
+void setResponseHeadersFromConfig(dnsheader& dh, const ResponseConfig& config);
+
 class LuaAction : public DNSAction
 {
 public:
@@ -73,26 +81,11 @@ public:
     return ret;
   }
 
-  void setAA(bool aa)
-  {
-    d_setAA = aa;
-  }
-
-  void setAD(bool ad)
-  {
-    d_setAD = ad;
-  }
 
-  void setRA(bool ra)
-  {
-    d_setRA = ra;
-  }
+  ResponseConfig d_responseConfig;
 private:
   std::vector<ComboAddress> d_addrs;
   DNSName d_cname;
-  boost::optional<bool> d_setAA{boost::none};
-  boost::optional<bool> d_setAD{boost::none};
-  boost::optional<bool> d_setRA{boost::none};
 };
 
 typedef boost::variant<string, vector<pair<int, string>>, std::shared_ptr<DNSRule>, DNSName, vector<pair<int, DNSName> > > luadnsrule_t;
index 9a2d68aa31b307fab56ba64998f18c4a45f5678b..1d698b69d5fc59466b646ebcc9fd8d1c0abc5658 100644 (file)
@@ -960,24 +960,44 @@ The following actions exist.
   :param int v6: The IPv6 netmask length
 
 
-.. function:: ERCodeAction(rcode)
+.. function:: ERCodeAction(rcode [, options])
 
   .. versionadded:: 1.4.0
 
+  .. versionchanged:: 1.5.0
+    Added the optional parameter ``options``.
+
   Reply immediately by turning the query into a response with the specified EDNS extended ``rcode``.
   ``rcode`` can be specified as an integer or as one of the built-in :ref:`DNSRCode`.
 
   :param int rcode: The extended RCODE to respond with.
+  :param table options: A table with key: value pairs with options.
 
-.. function:: HTTPStatusAction(status, body, contentType="")
+  Options:
+
+  * ``aa``: bool - Set the AA bit to this value (true means the bit is set, false means it's cleared). Default is to clear it.
+  * ``ad``: bool - Set the AD bit to this value (true means the bit is set, false means it's cleared). Default is to clear it.
+  * ``ra``: bool - Set the RA bit to this value (true means the bit is set, false means it's cleared). Default is to copy the value of the RD bit from the incoming query.
+
+.. function:: HTTPStatusAction(status, body, contentType="" [, options])
 
   .. versionadded:: 1.4.0
 
+  .. versionchanged:: 1.5.0
+    Added the optional parameter ``options``.
+
   Return an HTTP response with a status code of ''status''. For HTTP redirects, ''body'' should be the redirect URL.
 
   :param int status: The HTTP status code to return.
   :param string body: The body of the HTTP response, or a URL if the status code is a redirect (3xx).
   :param string contentType: The HTTP Content-Type header to return for a 200 response, ignored otherwise. Default is ''application/dns-message''.
+  :param table options: A table with key: value pairs with options.
+
+  Options:
+
+  * ``aa``: bool - Set the AA bit to this value (true means the bit is set, false means it's cleared). Default is to clear it.
+  * ``ad``: bool - Set the AD bit to this value (true means the bit is set, false means it's cleared). Default is to clear it.
+  * ``ra``: bool - Set the RA bit to this value (true means the bit is set, false means it's cleared). Default is to copy the value of the RD bit from the incoming query.
 
 .. function:: KeyValueStoreLookupAction(kvs, lookupKey, destinationTag)
 
@@ -1092,12 +1112,22 @@ The following actions exist.
   :param int maxqps: The QPS limit for that pool
   :param string poolname: The name of the pool
 
-.. function:: RCodeAction(rcode)
+.. function:: RCodeAction(rcode [, options])
+
+  .. versionchanged:: 1.5.0
+    Added the optional parameter ``options``.
 
   Reply immediately by turning the query into a response with the specified ``rcode``.
   ``rcode`` can be specified as an integer or as one of the built-in :ref:`DNSRCode`.
 
   :param int rcode: The RCODE to respond with.
+  :param table options: A table with key: value pairs with options.
+
+  Options:
+
+  * ``aa``: bool - Set the AA bit to this value (true means the bit is set, false means it's cleared). Default is to clear it.
+  * ``ad``: bool - Set the AD bit to this value (true means the bit is set, false means it's cleared). Default is to clear it.
+  * ``ra``: bool - Set the RA bit to this value (true means the bit is set, false means it's cleared). Default is to copy the value of the RD bit from the incoming query.
 
 .. function:: RemoteLogAction(remoteLogger[, alterFunction [, options]])