From: Remi Gacogne Date: Fri, 20 Jun 2025 12:06:22 +0000 (+0200) Subject: dnsdist: Prevent Lua bindings for backend from crashing on empty backend X-Git-Tag: rec-5.3.0-alpha2~25^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a12bea636790a3be73516a2a24af1a8351c016c5;p=thirdparty%2Fpdns.git dnsdist: Prevent Lua bindings for backend from crashing on empty backend We currently return an empty `std::shared_ptr` when the backend is not set (self-answered response, for example), and unfortunately LuaWrapper is not smart enough to make that equivalent to `nil`, so testing whether the backend is valid from Lua is not possible. While I would prefer to fix that, this fix prevents us from crashing when calling the bindings associated to a backend with an empty shared pointer. Signed-off-by: Remi Gacogne --- diff --git a/pdns/dnsdistdist/dnsdist-lua-bindings.cc b/pdns/dnsdistdist/dnsdist-lua-bindings.cc index a210eb10ab..7f019e7528 100644 --- a/pdns/dnsdistdist/dnsdist-lua-bindings.cc +++ b/pdns/dnsdistdist/dnsdist-lua-bindings.cc @@ -110,82 +110,193 @@ void setupLuaBindings(LuaContext& luaCtx, bool client, bool configCheck) #ifndef DISABLE_DOWNSTREAM_BINDINGS /* DownstreamState */ - luaCtx.registerFunction("setQPS", [](DownstreamState& state, int lim) { state.qps = lim > 0 ? QPSLimiter(lim, lim) : QPSLimiter(); }); + luaCtx.registerFunction::*)(int)>("setQPS", [](std::shared_ptr& state, int lim) { + if (state) { + state->qps = lim > 0 ? QPSLimiter(lim, lim) : QPSLimiter(); + } + }); luaCtx.registerFunction::*)(string)>("addPool", [](const std::shared_ptr& state, const string& pool) { - addServerToPool(pool, state); - state->d_config.pools.insert(pool); + if (state) { + addServerToPool(pool, state); + state->d_config.pools.insert(pool); + } }); luaCtx.registerFunction::*)(string)>("rmPool", [](const std::shared_ptr& state, const string& pool) { - removeServerFromPool(pool, state); - state->d_config.pools.erase(pool); - }); - luaCtx.registerFunction("getOutstanding", [](const DownstreamState& state) { return state.outstanding.load(); }); - luaCtx.registerFunction("getDrops", [](const DownstreamState& state) { return state.reuseds.load(); }); - luaCtx.registerFunction("getQueries", [](const DownstreamState& state) { return state.queries.load(); }); - luaCtx.registerFunction("getLatency", [](const DownstreamState& state) { return state.getRelevantLatencyUsec(); }); - luaCtx.registerFunction("isUp", &DownstreamState::isUp); - luaCtx.registerFunction("setDown", &DownstreamState::setDown); - luaCtx.registerFunction("setUp", &DownstreamState::setUp); - luaCtx.registerFunction("getHealthCheckMode", [](const DownstreamState& state) -> std::string { - if (state.d_config.d_healthCheckMode == DownstreamState::HealthCheckMode::Active) { + if (state) { + removeServerFromPool(pool, state); + state->d_config.pools.erase(pool); + } + }); + luaCtx.registerFunction::*)() const>("getOutstanding", [](const std::shared_ptr& state) -> uint64_t { + if (state) { + return state->outstanding.load(); + } + return 0U; + }); + luaCtx.registerFunction::*)() const>("getDrops", [](const std::shared_ptr& state) -> uint64_t { + if (state) { + return state->reuseds.load(); + } + return 0U; + }); + luaCtx.registerFunction::*)() const>("getQueries", [](const std::shared_ptr& state) -> uint64_t { + if (state) { + return state->queries.load(); + } + return 0U; + }); + luaCtx.registerFunction::*)() const>("getLatency", [](const std::shared_ptr& state) -> double { + if (state) { + return state->getRelevantLatencyUsec(); + } + return 0.0; + }); + luaCtx.registerFunction::*)() const>("isUp", [](const std::shared_ptr& state) -> bool { + if (!state) { + return false; + } + return state->isUp(); + }); + luaCtx.registerFunction::*)()>("setDown", [](const std::shared_ptr& state) { + if (state) { + state->setDown(); + } + }); + luaCtx.registerFunction::*)()>("setUp", [](const std::shared_ptr& state) { + if (state) { + state->setUp(); + } + }); + luaCtx.registerFunction::*)() const>("getHealthCheckMode", [](const std::shared_ptr& state) -> std::string { + if (!state) { + return ""; + } + if (state->d_config.d_healthCheckMode == DownstreamState::HealthCheckMode::Active) { return "active"; } return "lazy"; }); - luaCtx.registerFunction newStatus)>("setAuto", [](DownstreamState& state, boost::optional newStatus) { + luaCtx.registerFunction::*)(boost::optional newStatus)>("setAuto", [](std::shared_ptr& state, boost::optional newStatus) { + if (!state) { + return; + } if (newStatus) { - state.setUpStatus(*newStatus); + state->setUpStatus(*newStatus); } - state.setAuto(); + state->setAuto(); }); - luaCtx.registerFunction newStatus)>("setActiveAuto", [](DownstreamState& state, boost::optional newStatus) { + luaCtx.registerFunction::*)(boost::optional newStatus)>("setActiveAuto", [](std::shared_ptr& state, boost::optional newStatus) { + if (!state) { + return; + } if (newStatus) { - state.setUpStatus(*newStatus); + state->setUpStatus(*newStatus); } - state.setActiveAuto(); + state->setActiveAuto(); }); - luaCtx.registerFunction newStatus)>("setLazyAuto", [](DownstreamState& state, boost::optional newStatus) { + luaCtx.registerFunction::*)(boost::optional newStatus)>("setLazyAuto", [](std::shared_ptr& state, boost::optional newStatus) { + if (!state) { + return; + } if (newStatus) { - state.setUpStatus(*newStatus); + state->setUpStatus(*newStatus); } - state.setLazyAuto(); + state->setLazyAuto(); }); - luaCtx.registerFunction>>)>("setHealthCheckParams", [](DownstreamState& state, boost::optional>> vars) { + luaCtx.registerFunction::*)(boost::optional>>)>("setHealthCheckParams", [](std::shared_ptr& state, boost::optional>> vars) { + if (!state) { + return; + } size_t value = 0; getOptionalValue(vars, "maxCheckFailures", value); if (value > 0) { - state.d_config.maxCheckFailures.store(value); + state->d_config.maxCheckFailures.store(value); } getOptionalValue(vars, "rise", value); if (value > 0) { - state.d_config.minRiseSuccesses.store(value); + state->d_config.minRiseSuccesses.store(value); } getOptionalValue(vars, "checkTimeout", value); if (value > 0) { - state.d_config.checkTimeout.store(value); + state->d_config.checkTimeout.store(value); } getOptionalValue(vars, "checkInterval", value); if (value > 0) { - state.d_config.checkInterval.store(value); + state->d_config.checkInterval.store(value); + } + }); + luaCtx.registerFunction::*)() const>("getName", [](const std::shared_ptr& state) -> const std::string& { + static const std::string empty; + if (!state) { + return empty; + } + return state->getName(); + }); + luaCtx.registerFunction::*)() const>("getNameWithAddr", [](const std::shared_ptr& state) -> const std::string& { + static const std::string empty; + if (!state) { + return empty; } + return state->getNameWithAddr(); }); - luaCtx.registerFunction("getName", [](const DownstreamState& state) -> const std::string& { return state.getName(); }); - luaCtx.registerFunction("getNameWithAddr", [](const DownstreamState& state) -> const std::string& { return state.getNameWithAddr(); }); - luaCtx.registerMember( + luaCtx.registerMember::*)>( "upStatus", - [](const DownstreamState& state) -> bool { return state.upStatus.load(std::memory_order_relaxed); }, - [](DownstreamState& state, bool newStatus) { state.upStatus.store(newStatus); }); - luaCtx.registerMember( + [](const std::shared_ptr& state) -> bool { + if (!state) { + return false; + } + return state->upStatus.load(std::memory_order_relaxed); + }, + [](std::shared_ptr& state, bool newStatus) { + if (state) { + state->upStatus.store(newStatus); + } + }); + luaCtx.registerMember::*)>( "weight", - [](const DownstreamState& state) -> int { return state.d_config.d_weight; }, - [](DownstreamState& state, int newWeight) { state.setWeight(newWeight); }); - luaCtx.registerMember( + [](const std::shared_ptr& state) -> int { + if (!state) { + return 0; + } + return state->d_config.d_weight; + }, + [](std::shared_ptr& state, int newWeight) { + if (state) { + state->setWeight(newWeight); + } + }); + luaCtx.registerMember::*)>( "order", - [](const DownstreamState& state) -> int { return state.d_config.order; }, - [](DownstreamState& state, int newOrder) { state.d_config.order = newOrder; }); - luaCtx.registerMember( - "name", [](const DownstreamState& backend) -> std::string { return backend.getName(); }, [](DownstreamState& backend, const std::string& newName) { backend.setName(newName); }); - luaCtx.registerFunction("getID", [](const DownstreamState& state) { return boost::uuids::to_string(*state.d_config.id); }); + [](const std::shared_ptr& state) -> int { + if (!state) { + return 0; + } + return state->d_config.order; + }, + [](std::shared_ptr& state, int newOrder) { + if (state) { + state->d_config.order = newOrder; + } + }); + luaCtx.registerMember::*)>( + "name", + [](const std::shared_ptr& backend) -> std::string { + if (!backend) { + return ""; + } + return backend->getName(); + }, + [](std::shared_ptr& backend, const std::string& newName) { + if (backend) { + backend->setName(newName); + } + }); + luaCtx.registerFunction::*)() const>("getID", [](const std::shared_ptr& state) -> std::string { + if (!state) { + return ""; + } + return boost::uuids::to_string(*state->d_config.id); + }); #endif /* DISABLE_DOWNSTREAM_BINDINGS */ #ifndef DISABLE_DNSHEADER_BINDINGS