]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Support multiple ip addresses for dnsdist-resolver lua script 10414/head
authorWim <wim@42.be>
Sat, 15 May 2021 18:53:44 +0000 (20:53 +0200)
committerWim <wim@42.be>
Sat, 15 May 2021 18:58:58 +0000 (20:58 +0200)
dockerdata/dnsdist-resolver.lua

index 965e6b92a60be4ef521818d8e09ff2d8dce2b73b..89e24b319e6e0640fd58d81653b06234b57115ba 100644 (file)
@@ -1,6 +1,5 @@
 -- testing oneliner:
 -- resolver = require 'dnsdist-resolver' resolver.maintenance() resolver.servers['www.7bits.nl']={pool='blabla'} resolver.maintenance() os.execute('sleep 3') resolver.maintenance() showServers() resolver.servers['www.7bits.nl']=nil resolver.maintenance() os.execute('sleep 3') resolver.maintenance() showServers()
-
 local _M = {}
 
 -- these are the servers we want - somebody should populate it
@@ -16,102 +15,138 @@ _M.verbose = false
 -- key = name
 -- value = {address, serverObject} (should make these named members)
 local ourservers = {}
+local ourcount = {}
 
 local resolverpipe = io.popen('/usr/local/bin/dnsdist-resolver', 'w')
 
 local function tablecopy(t)
     local t2 = {}
-    for k, v in pairs(t)
-    do
+    for k, v in pairs(t) do
         t2[k] = v
     end
     return t2
 end
 
+local function has_value(tab, val)
+    for _, value in ipairs(tab) do
+        if value == val then
+            return true
+        end
+    end
+
+    return false
+end
+
 local function removeServer(name)
+    if _M.verbose then
+        infolog("removing " .. name)
+    end
+
     rmServer(ourservers[name][2])
     ourservers[name] = nil
 end
 
 local function setServer(name, ip)
     -- adds a server or changes its IP
-    local existing = ourservers[name]
-    if existing ~= nil
-    then
+    local existing = ourservers[name .. "#" .. ip]
+    if existing ~= nil then
         if _M.verbose then
-          infolog(string.format("existing[1] [%s] == ip [%s] ??", existing[1], ip))
+            infolog(string.format("existing[1] [%s] == ip [%s] ??", existing[1], ip))
         end
         -- it exists, check IP
-        if existing[1] == ip
-        then
+        if existing[1] == ip then
             -- IP is correct, done!
             return
         else
             -- IP is wrong, drop and re-add it
-            removeServer(name)
+            removeServer(name .. "#" .. ip)
         end
     end
 
     -- it does not exist, let's add it
     local settings = tablecopy(_M.servers[name])
-    settings.name = name
-    -- TODO: we only take the first IP
+    settings.name = name .. "#" .. ip
     settings.address = ip
-    ourservers[name] = {ip, newServer(settings)}
+    ourservers[name .. "#" .. ip] = {ip, newServer(settings)}
 end
 
 function _M.maintenance()
     -- TODO: only do this if the list has changed
     -- TODO: check return values
-    for k, v in pairs(_M.servers)
-    do
-        resolverpipe:write(k..' ')
+    for k in pairs(_M.servers) do
+        resolverpipe:write(k .. ' ')
     end
     resolverpipe:write('\n')
     resolverpipe:flush()
 
     -- TODO: maybe this failure should be quiet for the first X seconds?
     local ret, resout = pcall(loadfile, '/tmp/dnsdist-resolver.out')
-    if not ret
-    then
+    if not ret then
         error(resout)
     end
 
     -- on purpose no pcall, an error here is a bug
     resout = resout()
 
+    local activeservers = {}
     -- check for servers removed by controller
-    for name, v in pairs(ourservers)
-    do
-        if _M.servers[name] == nil
-        then
+    for ourserver in pairs(ourservers) do
+        activeservers[ourserver] = false
+        for server in pairs(_M.servers) do
+            -- use plain because a dash is a special character ..
+            if ourserver:find(server, 1, true) == 1 then
+                activeservers[ourserver] = true
+            end
+        end
+    end
+
+    for name, active in pairs(activeservers) do
+        if active == false then
             removeServer(name)
         end
     end
 
-    for name, ips in pairs(resout)
-    do
+    for name, ips in pairs(resout) do
         if _M.verbose then
-          infolog("name="..name)
-          for _, ip in ipairs(ips)
-          do
-              infolog("  ip="..ip)
-          end
+            infolog("name=" .. name)
+            for _, ip in ipairs(ips) do
+                infolog("  ip=" .. ip)
+            end
+        end
+
+        -- init our current count
+        if ourcount[name] == nil then
+            ourcount[name] = #ips
+        end
+
+        -- increase our current count if necessary
+        if #ips > ourcount[name] then
+            ourcount[name] = #ips
+            if _M.verbose then
+                infolog("increasing count to " .. ourcount[name] .. " for " .. name)
+            end
         end
 
-        if #ips == 0
-        then
-            -- server has left the building
-            if ourservers[name] ~= nil
-            then
-                removeServer(name)
+        -- remove servers when we've lost ips
+        if #ips < ourcount[name] then
+            for ourserver, server in pairs(ourservers) do
+                -- check if we match the prefix and the ip is gone
+                if ourserver:find(name, 1, true) == 1 and has_value(ips, server[1]) == false then
+                    ourcount[name] = #ips
+                    if _M.verbose then
+                        infolog("ip address not found anymore " .. server[1])
+                        infolog("decreasing count to " .. ourcount[name])
+                    end
+                    removeServer(ourserver)
+                end
             end
         else
-            -- it has IPs
-            if _M.servers[name] ~= nil
-            then
-                -- we want this server
-                setServer(name, ips[1])
+            for _, ip in ipairs(ips) do
+                -- it has IPs
+                if _M.servers[name] ~= nil then
+                    -- we want this server
+                    setServer(name, ip)
+                end
             end
         end
     end