]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
auth: only apply backupSelector to the first non-empty group 17239/head
authorDaniel Micay <daniel.micay@grapheneos.org>
Wed, 13 May 2026 00:15:22 +0000 (20:15 -0400)
committerDaniel Micay <daniel.micay@grapheneos.org>
Wed, 13 May 2026 23:02:18 +0000 (19:02 -0400)
Example:

    local ips = {{}, {ip_dallas}}, {}, {ip_frankfurt}}
    return ifurlup(url, ips, {selector='all', backupSelector='all'})

The previous behavior results in returning {ip_dallas, ip_frankfurt} if
every IP is detected as down. Health checks start out in the down state
so every IP is considered down after a server restart or changes to the
health check configuration. For GeoDNS configurations, this means GeoDNS
doesn't work when the service is first started or if health checks start
failing for every server due to a network or configuration issue.

This changes the behavior to returning {ip_dallas} when every IP is down
which matches the behavior when every IP is up. It makes much more sense
to have the same result for every IP being up and every IP being down.

Signed-off-by: Daniel Micay <daniel.micay@grapheneos.org>
pdns/lua-record.cc

index 8d80a32a23232749471de150c372c3154eace3c2..3067898687cc106e14a4441bcd2803f25f7a84d1 100644 (file)
@@ -967,13 +967,14 @@ static vector<string> genericIfUp(Logr::log_t slog, const boost::variant<iplist_
     throw std::runtime_error("if{url,port}up health check has not completed yet");
   }
 
-  // Apply backupSelector on all candidates
-  vector<ComboAddress> ret{};
-  for(const auto& unit : candidates) {
-    ret.insert(ret.end(), unit.begin(), unit.end());
+  // Apply backupSelector on all candidates in the first non-empty group
+  vector<ComboAddress> res;
+  for (const auto& unit : candidates) {
+    if (!unit.empty()) {
+      res = useSelector(slog, getOptionValue<string>(options, "backupSelector", "random"), s_lua_record_ctx->bestwho, unit);
+      break;
+    }
   }
-
-  vector<ComboAddress> res = useSelector(slog, getOptionValue<string>(options, "backupSelector", "random"), s_lua_record_ctx->bestwho, ret);
   return convComboAddressListToString(res);
 }
 
@@ -1338,8 +1339,18 @@ static vector<string> lua_ifurlextup(Logr::log_t slog, const vector<pair<int, op
     throw std::runtime_error("ifexturlup health check has not completed yet");
   }
 
-  // Apply backupSelector on all candidates
-  vector<ComboAddress> res = useSelector(slog, getOptionValue<string>(options, "backupSelector", "random"), s_lua_record_ctx->bestwho, candidates);
+  // Apply backupSelector on all candidates in the first non-empty group
+  vector<ComboAddress> first;
+  for (const auto& [count, unitmap] : ipurls) {
+    if (!unitmap.empty()) {
+      first.reserve(unitmap.size());
+      for (const auto& [ipStr, url] : unitmap) {
+        first.emplace_back(ipStr);
+      }
+      break;
+    }
+  }
+  vector<ComboAddress> res = useSelector(slog, getOptionValue<string>(options, "backupSelector", "random"), s_lua_record_ctx->bestwho, first);
   return convComboAddressListToString(res);
 }