]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Add `NetmaskGroup:addNMG()` to merge Netmask groups
authorRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 16 Nov 2023 16:16:14 +0000 (17:16 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 4 Dec 2023 09:47:49 +0000 (10:47 +0100)
pdns/dnsdist-lua-bindings.cc
pdns/dnsdist-lua.cc
pdns/dnsdist-web.cc
pdns/dnsdist.cc
pdns/dnsdistdist/docs/reference/netmaskgroup.rst
pdns/iputils.hh
pdns/recursordist/ws-recursor.cc
regression-tests.dnsdist/test_RulesActions.py

index c0339deabad962d4fbecea46cc3210046eaee10b..5d9fe9a3c6f9ee39e6a3582850c4733a2198a740 100644 (file)
@@ -382,10 +382,17 @@ void setupLuaBindings(LuaContext& luaCtx, bool client, bool configCheck)
 
   /* NetmaskGroup */
   luaCtx.writeFunction("newNMG", []() { return NetmaskGroup(); });
-  luaCtx.registerFunction<void(NetmaskGroup::*)(const std::string&mask)>("addMask", [](NetmaskGroup&nmg, const std::string& mask)
+  luaCtx.registerFunction<void(NetmaskGroup::*)(const std::string& mask)>("addMask", [](NetmaskGroup&nmg, const std::string& mask)
                          {
                            nmg.addMask(mask);
                          });
+  luaCtx.registerFunction<void(NetmaskGroup::*)(const NetmaskGroup& otherNMG)>("addNMG", [](NetmaskGroup& nmg, const NetmaskGroup& otherNMG) {
+    /* this is not going to be very efficient, sorry */
+    auto entries = otherNMG.toStringVector();
+    for (const auto& entry : entries) {
+      nmg.addMask(entry);
+    }
+  });
   luaCtx.registerFunction<void(NetmaskGroup::*)(const std::map<ComboAddress,int>& map)>("addMasks", [](NetmaskGroup&nmg, const std::map<ComboAddress,int>& map)
                          {
                            for (const auto& entry : map) {
index a943f2b9d34879d2ea03ab61f8067cc8f4c0cfc0..5bca935b2d1fcacaaafd3db0b2b9861836654c46 100644 (file)
@@ -840,12 +840,11 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 
   luaCtx.writeFunction("showACL", []() {
     setLuaNoSideEffect();
-    vector<string> vec;
+    auto aclEntries = g_ACL.getLocal()->toStringVector();
 
-    g_ACL.getLocal()->toStringVector(&vec);
-
-    for (const auto& s : vec)
-      g_outputBuffer += s + "\n";
+    for (const auto& entry : aclEntries) {
+      g_outputBuffer += entry + "\n";
+    }
   });
 
   luaCtx.writeFunction("shutdown", []() {
@@ -1164,11 +1163,10 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     warnlog("Allowing remote access to the console while libsodium support has not been enabled is not secure, and will result in cleartext communications");
 #endif
 
-    vector<string> vec;
-    g_consoleACL.getLocal()->toStringVector(&vec);
+    auto aclEntries = g_consoleACL.getLocal()->toStringVector();
 
-    for (const auto& s : vec) {
-      g_outputBuffer += s + "\n";
+    for (const auto& entry : aclEntries) {
+      g_outputBuffer += entry + "\n";
     }
   });
 
index d0890b5462de8bd3b6db961db71638e29c533be2..066b5c177f5475ef3689a83315161f6804fcdbab 100644 (file)
@@ -253,15 +253,14 @@ static bool apiWriteConfigFile(const string& filebasename, const string& content
 
 static void apiSaveACL(const NetmaskGroup& nmg)
 {
-  vector<string> vec;
-  nmg.toStringVector(&vec);
+  auto aclEntries = nmg.toStringVector();
 
   string acl;
-  for(const auto& s : vec) {
+  for (const auto& entry : aclEntries) {
     if (!acl.empty()) {
       acl += ", ";
     }
-    acl += "\"" + s + "\"";
+    acl += "\"" + entry + "\"";
   }
 
   string content = "setACL({" + acl + "})";
@@ -1284,14 +1283,13 @@ static void handleStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
 
   string acl;
   {
-    vector<string> vec;
-    g_ACL.getLocal()->toStringVector(&vec);
+    auto aclEntries = g_ACL.getLocal()->toStringVector();
 
-    for (const auto& s : vec) {
+    for (const auto& entry : aclEntries) {
       if (!acl.empty()) {
         acl += ", ";
       }
-      acl += s;
+      acl += entry;
     }
   }
 
@@ -1526,18 +1524,12 @@ static void handleAllowFrom(const YaHTTP::Request& req, YaHTTP::Response& resp)
     }
   }
   if (resp.status == 200) {
-    Json::array acl;
-    vector<string> vec;
-    g_ACL.getLocal()->toStringVector(&vec);
-
-    for(const auto& s : vec) {
-      acl.push_back(s);
-    }
+    auto aclEntries = g_ACL.getLocal()->toStringVector();
 
     Json::object obj{
       { "type", "ConfigSetting" },
       { "name", "allow-from" },
-      { "value", acl }
+      { "value", aclEntries }
     };
     Json my_json = obj;
     resp.body = my_json.dump();
index b5f8cc0f3fa8377cc7aafd298971681959e0332d..bfaa81bd9fa2cf3762e676c6f32f12b423a200bb 100644 (file)
@@ -2948,26 +2948,28 @@ int main(int argc, char** argv)
       }
     }
 
-    vector<string> vec;
-    std::string acls;
-    g_ACL.getLocal()->toStringVector(&vec);
-    for (const auto& aclEntry : vec) {
-      if (!acls.empty()) {
-        acls += ", ";
-      }
-      acls += aclEntry;
-    }
-    infolog("ACL allowing queries from: %s", acls);
-    vec.clear();
-    acls.clear();
-    g_consoleACL.getLocal()->toStringVector(&vec);
-    for (const auto& entry : vec) {
-      if (!acls.empty()) {
-        acls += ", ";
-      }
-      acls += entry;
-    }
-    infolog("Console ACL allowing connections from: %s", acls.c_str());
+    {
+      std::string acls;
+      auto aclEntries = g_ACL.getLocal()->toStringVector();
+      for (const auto& aclEntry : aclEntries) {
+        if (!acls.empty()) {
+          acls += ", ";
+        }
+        acls += aclEntry;
+      }
+      infolog("ACL allowing queries from: %s", acls);
+    }
+    {
+      std::string acls;
+      auto aclEntries = g_consoleACL.getLocal()->toStringVector();
+      for (const auto& entry : aclEntries) {
+        if (!acls.empty()) {
+          acls += ", ";
+        }
+        acls += entry;
+      }
+      infolog("Console ACL allowing connections from: %s", acls.c_str());
+    }
 
 #ifdef HAVE_LIBSODIUM
     if (g_consoleEnabled && g_consoleKey.empty()) {
index b6d19b97ac1e23eb9c0fb8c3ae34b1712f886b4e..568bb95b6ad83d0404ee89c7b73563c4994e9fcf 100644 (file)
@@ -17,6 +17,14 @@ NetmaskGroup
     :param string mask: Add this mask, prefix with `!` to exclude this mask from matching.
     :param table masks: Adds the keys of the table to the :class:`NetmaskGroup`. It should be a table whose keys are :class:`ComboAddress` objects and whose values are integers. The integer values of the table entries are ignored. The table is of the same type as the table returned by the `exceed*` functions.
 
+  .. method:: NetmaskGroup:addNMG(otherNMG)
+
+    .. versionadded:: 1.9.0
+
+    Add one or more masks from an existing to this NMG.
+
+    :param NetmaskGroup otherNMG: Add the masks from a :class:`NetmaskGroup` to this one.
+
   .. method:: NetmaskGroup:match(address) -> bool
 
     Checks if ``address`` is matched by this NetmaskGroup.
index 47ca071a4780a978821a8371dd1e7cb8df19cb22..18c15bcc5343eb2d8a61d3e6e3cee975d561e948 100644 (file)
@@ -1462,11 +1462,14 @@ public:
     return str.str();
   }
 
-  void toStringVector(vector<string>* vec) const
+  std::vector<std::string> toStringVector() const
   {
-    for(auto iter = tree.begin(); iter != tree.end(); ++iter) {
-      vec->push_back((iter->second ? "" : "!") + iter->first.toString());
+    std::vector<std::string> out;
+    out.reserve(tree.size());
+    for (const auto& entry : tree) {
+      out.push_back((entry.second ? "" : "!") + entry.first.toString());
     }
+    return out;
   }
 
   void toMasks(const string &ips)
index 5214c57e322062ce164fb73778643689782559a1..34313fa493392fc9a5b52d858d77deb3dd9eee50 100644 (file)
@@ -151,10 +151,10 @@ static void apiServerConfigACL(const std::string& aclType, HttpRequest* req, Htt
   // Return currently configured ACLs
   vector<string> entries;
   if (t_allowFrom && aclType == "allow-from") {
-    t_allowFrom->toStringVector(&entries);
+    entries = t_allowFrom->toStringVector();
   }
   else if (t_allowNotifyFrom && aclType == "allow-notify-from") {
-    t_allowNotifyFrom->toStringVector(&entries);
+    entries = t_allowNotifyFrom->toStringVector();
   }
 
   resp->setJsonBody(Json::object{
index 4ce1178649e82e6e22e86dd527b1a6278fc64e24..14f64d9218ed0d08b077fd4f7af53efae391358e 100644 (file)
@@ -751,6 +751,37 @@ class TestAdvancedNMGRule(DNSDistTest):
             (_, receivedResponse) = sender(query, response=None, useQueue=False)
             self.assertEqual(receivedResponse, expectedResponse)
 
+class TestAdvancedNMGAddNMG(DNSDistTest):
+    _config_template = """
+    oneNMG = newNMG()
+    anotherNMG = newNMG()
+    anotherNMG:addMask('127.0.0.1/32')
+    oneNMG:addNMG(anotherNMG)
+    addAction(NotRule(NetmaskGroupRule(oneNMG)), DropAction())
+    addAction(AllRule(), SpoofAction('192.0.2.1'))
+    newServer{address="127.0.0.1:%s"}
+    """
+
+    def testAdvancedNMGRuleAddNMG(self):
+        """
+        Advanced: NMGRule:addNMG()
+        """
+        name = 'nmgrule-addnmg.advanced.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+        query.flags &= ~dns.flags.RD
+        expectedResponse = dns.message.make_response(query)
+        rrset = dns.rrset.from_text(name,
+                                    60,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.A,
+                                    '192.0.2.1')
+        expectedResponse.answer.append(rrset)
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (_,receivedResponse) = sender(query, response=expectedResponse, useQueue=False)
+            self.assertEqual(receivedResponse, expectedResponse)
+
 class TestDSTPortRule(DNSDistTest):
 
     _config_params = ['_dnsDistPort', '_testServerPort']