]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Implement a small MAC address cache
authorRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 24 Jun 2022 14:39:16 +0000 (16:39 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Wed, 21 Sep 2022 15:31:30 +0000 (17:31 +0200)
pdns/dnsdist-lua-actions.cc
pdns/dnsdist-rings.hh
pdns/dnsdistdist/Makefile.am
pdns/dnsdistdist/dnsdist-lua-ffi.cc
pdns/dnsdistdist/dnsdist-mac-address.cc [new file with mode: 0644]
pdns/dnsdistdist/dnsdist-mac-address.hh [new file with mode: 0644]

index 207058bdb27a329d98fadc20590679717d863973..f94a42119f9d6a961162d6fa96a0fdb863345317 100644 (file)
@@ -25,6 +25,7 @@
 #include "dnsdist-ecs.hh"
 #include "dnsdist-lua.hh"
 #include "dnsdist-lua-ffi.hh"
+#include "dnsdist-mac-address.hh"
 #include "dnsdist-protobuf.hh"
 #include "dnsdist-kvs.hh"
 #include "dnsdist-svc.hh"
@@ -932,8 +933,9 @@ public:
 
   DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
   {
-    std::string mac = getMACAddress(*dq->remote);
-    if (mac.empty()) {
+    char mac[6];
+    int res = dnsdist::MacAddressesCache::get(*dq->remote, mac, sizeof(mac));
+    if (res != 0) {
       return Action::None;
     }
 
index c8b0d32dd0c4771312cff2b6a3493fc02559201f..c0b058f8530a7b3288094b2f4b9f840613fb77e1 100644 (file)
@@ -32,6 +32,7 @@
 #include "lock.hh"
 #include "stat_t.hh"
 #include "dnsdist-protocols.hh"
+#include "dnsdist-mac-address.hh"
 
 struct Rings {
   struct Query
@@ -105,7 +106,7 @@ struct Rings {
 #if defined(DNSDIST_RINGS_WITH_MACADDRESS)
     char macaddress[6];
     bool hasmac{false};
-    if (getMACAddress(requestor, macaddress, sizeof(macaddress)) == 0) {
+    if (dnsdist::MacAddressesCache::get(requestor, macaddress, sizeof(macaddress)) == 0) {
       hasmac = true;
     }
 #endif
index 28b9d587073e75e75ec4e030c7d2479f260d4076..68fc61d9a5432eba36d4b654571dabd7039b5b59 100644 (file)
@@ -163,6 +163,7 @@ dnsdist_SOURCES = \
        dnsdist-lua-vars.cc \
        dnsdist-lua-web.cc \
        dnsdist-lua.cc dnsdist-lua.hh \
+       dnsdist-mac-address.cc dnsdist-mac-address.hh \
        dnsdist-nghttp2.cc dnsdist-nghttp2.hh \
        dnsdist-prometheus.hh \
        dnsdist-protobuf.cc dnsdist-protobuf.hh \
@@ -251,6 +252,7 @@ testrunner_SOURCES = \
        dnsdist-lua-ffi-interface.h dnsdist-lua-ffi-interface.inc \
        dnsdist-lua-ffi.cc dnsdist-lua-ffi.hh \
        dnsdist-lua-vars.cc \
+       dnsdist-mac-address.cc dnsdist-mac-address.hh \
        dnsdist-nghttp2.cc dnsdist-nghttp2.hh \
        dnsdist-protocols.cc dnsdist-protocols.hh \
        dnsdist-proxy-protocol.cc dnsdist-proxy-protocol.hh \
index 4a61e942f7b673167f6dc068281f4d5d825fea66..1b4c6ce4790b5be33e23547504c596e5c08ac567 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 #include "dnsdist-lua-ffi.hh"
+#include "dnsdist-mac-address.hh"
 #include "dnsdist-lua.hh"
 #include "dnsdist-ecs.hh"
 #include "dolog.hh"
@@ -63,7 +64,7 @@ size_t dnsdist_ffi_dnsquestion_get_mac_addr(const dnsdist_ffi_dnsquestion_t* dq,
     return 0;
   }
 
-  auto ret = getMACAddress(*dq->dq->remote, reinterpret_cast<char*>(buffer), bufferSize);
+  auto ret = dnsdist::MacAddressesCache::get(*dq->dq->remote, reinterpret_cast<char*>(buffer), bufferSize);
   if (ret != 0) {
     return 0;
   }
diff --git a/pdns/dnsdistdist/dnsdist-mac-address.cc b/pdns/dnsdistdist/dnsdist-mac-address.cc
new file mode 100644 (file)
index 0000000..6f87b66
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dnsdist-mac-address.hh"
+#include "misc.hh"
+
+namespace dnsdist
+{
+LockGuarded<boost::circular_buffer<MacAddressesCache::Entry>> MacAddressesCache::s_cache;
+
+int MacAddressesCache::get(const ComboAddress& ca, char* dest, size_t destLen)
+{
+  if (dest == nullptr || destLen < sizeof(Entry::mac)) {
+    return EINVAL;
+  }
+
+  auto compare = ComboAddress::addressOnlyEqual();
+  time_t now = time(nullptr);
+
+  {
+    auto cache = s_cache.lock();
+    for (const auto& entry : *cache) {
+      if (entry.ttd >= now && compare(entry.ca, ca) == true) {
+        if (!entry.found) {
+          // negative entry
+          return ENOENT;
+        }
+        memcpy(dest, entry.mac, sizeof(entry.mac));
+        return 0;
+      }
+    }
+  }
+
+  auto res = getMACAddress(ca, dest, destLen);
+  {
+    auto cache = s_cache.lock();
+    if (cache->capacity() == 0) {
+      cache->set_capacity(MacAddressesCache::s_cacheSize);
+    }
+    Entry entry;
+    entry.ca = ca;
+    if (res == 0) {
+      memcpy(entry.mac, dest, sizeof(entry.mac));
+      entry.found = true;
+    }
+    else {
+      memset(entry.mac, 0, sizeof(entry.mac));
+      entry.found = false;
+    }
+    entry.ttd = now + MacAddressesCache::s_cacheValiditySeconds;
+    cache->push_back(std::move(entry));
+  }
+
+  return res;
+}
+}
diff --git a/pdns/dnsdistdist/dnsdist-mac-address.hh b/pdns/dnsdistdist/dnsdist-mac-address.hh
new file mode 100644 (file)
index 0000000..f155e19
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+#include "circular_buffer.hh"
+#include "iputils.hh"
+#include "lock.hh"
+
+namespace dnsdist
+{
+class MacAddressesCache
+{
+public:
+  static int get(const ComboAddress& ca, char* dest, size_t len);
+
+private:
+  struct Entry
+  {
+    ComboAddress ca;
+    char mac[6];
+    time_t ttd;
+    bool found;
+  };
+
+  static constexpr size_t s_cacheSize{10};
+  static constexpr time_t s_cacheValiditySeconds{60};
+  static LockGuarded<boost::circular_buffer<Entry>> s_cache;
+};
+}