Skip to content

Commit 69f8479

Browse files
authored
config: clean error for empty/unresolvable bind address (#459) (#461)
1 parent 33e87b5 commit 69f8479

2 files changed

Lines changed: 67 additions & 0 deletions

File tree

src/config/ConfigResolver.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <unordered_map>
1414
#include <unordered_set>
1515

16+
#include <folly/SocketAddress.h>
1617
#include <folly/String.h>
1718

1819
namespace openmoq::moqx::config {
@@ -169,6 +170,28 @@ std::string makeCompositeKey(
169170

170171
// --- Listener validation ---
171172

173+
// Validate a bind address so an empty or unresolvable value fails as a clean
174+
// config error rather than letting folly::SocketAddress throw uncaught at
175+
// resolution time, which aborts the process (#459). Literal IPs cost nothing;
176+
// a hostname is resolved once here.
177+
void validateBindAddress(
178+
const std::string& address,
179+
uint16_t port,
180+
const std::string& context,
181+
std::vector<std::string>& errors
182+
) {
183+
if (address.empty()) {
184+
errors.push_back(context + ": address must be non-empty");
185+
return;
186+
}
187+
try {
188+
folly::SocketAddress probe(address, port);
189+
(void)probe;
190+
} catch (const std::exception& e) {
191+
errors.push_back(context + ": invalid bind address '" + address + "': " + e.what());
192+
}
193+
}
194+
172195
void validateListener(
173196
const ParsedListenerConfig& listener,
174197
std::vector<std::string>& errors,
@@ -178,6 +201,12 @@ void validateListener(
178201
if (sock.port.value() == 0) {
179202
errors.push_back("Listener '" + listener.name.value() + "' port must be 1-65535, got 0");
180203
}
204+
validateBindAddress(
205+
sock.address.value(),
206+
sock.port.value(),
207+
"Listener '" + listener.name.value() + "'",
208+
errors
209+
);
181210

182211
// TLS validation
183212
validateListenerTlsConfig(
@@ -212,6 +241,12 @@ void validateAdmin(const ParsedConfig& config, std::vector<std::string>& errors)
212241
if (adminOptional->port.value() == 0) {
213242
errors.push_back("admin.port must be 1-65535, got 0");
214243
}
244+
validateBindAddress(
245+
adminOptional->address.value(),
246+
adminOptional->port.value(),
247+
"admin",
248+
errors
249+
);
215250
bool hasTls = adminOptional->tls.value().has_value();
216251
bool hasPlaintext = adminOptional->plaintext.value();
217252
if (hasTls && hasPlaintext) {

test/config/ConfigResolverTest.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,38 @@ TEST(ResolveConfig, InsecureWithCertsWarning) {
187187
EXPECT_THAT(result.value().warnings[0], HasSubstr("ignored"));
188188
}
189189

190+
// #459: an empty/unresolvable bind address must fail as a clean config error,
191+
// not let folly::SocketAddress throw uncaught and abort the process.
192+
TEST(ResolveConfig, ListenerEmptyAddressRejected) {
193+
auto cfg = makeMinimalInsecureConfig();
194+
cfg.listeners.value()[0].udp.value().socket.value().address = std::string("");
195+
196+
auto result = resolveConfig(cfg);
197+
ASSERT_TRUE(result.hasError());
198+
EXPECT_THAT(result.error(), HasSubstr("address must be non-empty"));
199+
}
200+
201+
TEST(ResolveConfig, ListenerUnresolvableAddressRejected) {
202+
auto cfg = makeMinimalInsecureConfig();
203+
// .invalid is a reserved TLD (RFC 2606): guaranteed to fail resolution fast.
204+
cfg.listeners.value()[0].udp.value().socket.value().address = std::string("no.such.host.invalid");
205+
206+
auto result = resolveConfig(cfg);
207+
ASSERT_TRUE(result.hasError());
208+
EXPECT_THAT(result.error(), HasSubstr("invalid bind address"));
209+
}
210+
211+
TEST(ResolveConfig, AdminEmptyAddressRejected) {
212+
auto cfg = makeMinimalInsecureConfig();
213+
auto admin = makeDefaultAdmin();
214+
admin.address = std::string("");
215+
cfg.admin = std::optional<ParsedAdminConfig>{std::move(admin)};
216+
217+
auto result = resolveConfig(cfg);
218+
ASSERT_TRUE(result.hasError());
219+
EXPECT_THAT(result.error(), HasSubstr("address must be non-empty"));
220+
}
221+
190222
// --- Service validation error tests ---
191223

192224
TEST(ResolveConfig, NoServices) {

0 commit comments

Comments
 (0)