From bbdbc636f3333ce498428bf53b6d4898021a53b2 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Fri, 23 Oct 2026 17:49:04 +0900 Subject: [PATCH 1/7] network: bound TCP DNS lookups with the cancellation timer Signed-off-by: Hiroshi Hatake --- src/flb_network.c | 75 +++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 42 deletions(-) diff --git a/src/flb_network.c b/src/flb_network.c index 61bfdb07f06..4729ab79bdc 100644 --- a/src/flb_network.c +++ b/src/flb_network.c @@ -71,14 +71,12 @@ struct flb_dns_lookup_context { struct mk_event response_event; /* c-ares socket event */ int ares_socket_registered; struct ares_socket_functions ares_socket_functions; - int *udp_timeout_detected; int ares_socket_created; - int ares_socket_type; void *ares_channel; int *result_code; struct mk_event_loop *event_loop; struct flb_coro *coroutine; - struct flb_sched_timer *udp_timer; + struct flb_sched_timer *dns_timer; int finished; int dropped; struct flb_net_dns *dns_ctx; @@ -694,11 +692,11 @@ static void flb_net_dns_lookup_context_drop(struct flb_dns_lookup_context *looku mk_list_del(&lookup_context->_head); mk_list_add(&lookup_context->_head, &lookup_context->dns_ctx->lookups_drop); - if (lookup_context->udp_timer != NULL && - lookup_context->udp_timer->active) { - flb_sched_timer_invalidate(lookup_context->udp_timer); + if (lookup_context->dns_timer != NULL && + lookup_context->dns_timer->active) { + flb_sched_timer_invalidate(lookup_context->dns_timer); - lookup_context->udp_timer = NULL; + lookup_context->dns_timer = NULL; } } } @@ -943,13 +941,12 @@ static void flb_net_getaddrinfo_timeout_handler(struct flb_config *config, void return; } - *(lookup_context->udp_timeout_detected) = FLB_TRUE; lookup_context->finished = FLB_TRUE; - lookup_context->udp_timer = NULL; + lookup_context->dns_timer = NULL; - /* We deliverately set udp_timer because we don't want flb_net_dns_lookup_context_drop - * to call flb_sched_timer_invalidate on the timer which was already disabled and - * is about to be destroyed after this this callback returns. + /* Clear dns_timer so flb_net_dns_lookup_context_drop does not invalidate + * the timer which was already disabled and will be destroyed after this + * callback returns. */ ares_cancel(lookup_context->ares_channel); @@ -996,7 +993,6 @@ static ares_socket_t flb_dns_ares_socket(int af, int type, int protocol, void *u return -1; } - lookup_context->ares_socket_type = type; lookup_context->ares_socket_created = FLB_TRUE; lookup_context->response_event.mask = MK_EVENT_EMPTY; @@ -1121,7 +1117,7 @@ static struct flb_dns_lookup_context *flb_net_dns_lookup_context_create( lookup_context->ares_socket_functions.asendv = flb_dns_ares_send; lookup_context->ares_socket_created = 0; lookup_context->event_loop = evl; - lookup_context->udp_timer = NULL; + lookup_context->dns_timer = NULL; lookup_context->coroutine = coroutine; lookup_context->finished = 0; lookup_context->dropped = 0; @@ -1141,7 +1137,6 @@ static struct flb_dns_lookup_context *flb_net_dns_lookup_context_create( int flb_net_getaddrinfo(const char *node, const char *service, struct addrinfo *hints, struct addrinfo **res, char *dns_mode_textual, int timeout) { - int udp_timeout_detected; struct flb_dns_lookup_context *lookup_context; int errno_backup; int result_code; @@ -1179,7 +1174,6 @@ int flb_net_getaddrinfo(const char *node, const char *service, struct addrinfo * return result; } - lookup_context->udp_timeout_detected = &udp_timeout_detected; lookup_context->result_code = &result_code; lookup_context->result = &result_data; @@ -1190,7 +1184,6 @@ int flb_net_getaddrinfo(const char *node, const char *service, struct addrinfo * */ result_code = ARES_ESERVFAIL; result_data = NULL; - udp_timeout_detected = 0; /* The timeout we get is expressed in seconds so we need to convert it to * milliseconds @@ -1216,36 +1209,34 @@ int flb_net_getaddrinfo(const char *node, const char *service, struct addrinfo * if (!lookup_context->finished) { if (lookup_context->ares_socket_created) { - if (lookup_context->ares_socket_type == SOCK_DGRAM) { - /* If the socket type created by c-ares is UDP then we need to create our - * own timeout mechanism before yielding and cancel it if things go as - * expected. + /* Bound both UDP and TCP lookups, including a TCP connection to a + * DNS server that never completes. Cancellation schedules cleanup + * and resumes the waiting coroutine. + */ + sched = flb_sched_ctx_get(); + assert(sched != NULL); + + result = flb_sched_timer_cb_create(sched, FLB_SCHED_TIMER_CB_ONESHOT, + timeout, + flb_net_getaddrinfo_timeout_handler, + lookup_context, + &lookup_context->dns_timer); + if (result == -1) { + /* Timer creation failed, it happen because of file descriptor or memory + * exhaustion (ulimits usually) */ - sched = flb_sched_ctx_get(); - assert(sched != NULL); - - result = flb_sched_timer_cb_create(sched, FLB_SCHED_TIMER_CB_ONESHOT, - timeout, - flb_net_getaddrinfo_timeout_handler, - lookup_context, - &lookup_context->udp_timer); - if (result == -1) { - /* Timer creation failed, it happen because of file descriptor or memory - * exhaustion (ulimits usually) - */ - - result_code = ARES_ENOMEM; + /* Cancellation invokes the callback synchronously. Preserve the + * allocation error instead of replacing it with ARES_ECANCELLED. + */ + lookup_context->finished = FLB_TRUE; + result_code = ARES_ENOMEM; - ares_cancel(lookup_context->ares_channel); + ares_cancel(lookup_context->ares_channel); - lookup_context->coroutine = NULL; + lookup_context->coroutine = NULL; - flb_net_dns_lookup_context_drop(lookup_context); - } - else { - flb_coro_yield(coroutine, FLB_FALSE); - } + flb_net_dns_lookup_context_drop(lookup_context); } else { flb_coro_yield(coroutine, FLB_FALSE); From cca6587afa47f8a6166676e3a6a8a64cf77ab224 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Fri, 23 Oct 2026 17:49:04 +0900 Subject: [PATCH 2/7] upstream: identify configured endpoints in timeout logs Signed-off-by: Hiroshi Hatake --- src/flb_upstream.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/flb_upstream.c b/src/flb_upstream.c index 5248c6e3d61..b8157066b9c 100644 --- a/src/flb_upstream.c +++ b/src/flb_upstream.c @@ -1083,18 +1083,18 @@ int flb_upstream_conn_timeouts(struct mk_list *list) if (drop) { if (!flb_upstream_is_shutting_down(u)) { if (u->base.net.connect_timeout_log_error) { - flb_error("[upstream] connection #%i to %s timed " + flb_error("[upstream] connection #%i to %s:%i timed " "out after %i seconds (%s)", u_conn->fd, - flb_connection_get_remote_address(u_conn), + u->tcp_host, u->tcp_port, elapsed_time, reason); } else { - flb_debug("[upstream] connection #%i to %s timed " + flb_debug("[upstream] connection #%i to %s:%i timed " "out after %i seconds (%s)", u_conn->fd, - flb_connection_get_remote_address(u_conn), + u->tcp_host, u->tcp_port, elapsed_time, reason); } From 2f7ba5af93971941f68abd5cb2538a272367c8d4 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Fri, 23 Oct 2026 17:49:05 +0900 Subject: [PATCH 3/7] tests: internal: cover DNS cancellation and timeout ordering Signed-off-by: Hiroshi Hatake --- tests/internal/CMakeLists.txt | 1 + tests/internal/network_dns.c | 203 ++++++++++++++++++++++++++++++++++ 2 files changed, 204 insertions(+) create mode 100644 tests/internal/network_dns.c diff --git a/tests/internal/CMakeLists.txt b/tests/internal/CMakeLists.txt index 9160a47cf27..c539891c904 100644 --- a/tests/internal/CMakeLists.txt +++ b/tests/internal/CMakeLists.txt @@ -17,6 +17,7 @@ set(UNIT_TESTS_FILES router.c router_config.c network.c + network_dns.c unit_sizes.c hashtable.c http_client.c diff --git a/tests/internal/network_dns.c b/tests/internal/network_dns.c new file mode 100644 index 00000000000..d5c8d8b1055 --- /dev/null +++ b/tests/internal/network_dns.c @@ -0,0 +1,203 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "flb_tests_internal.h" + +struct dns_timeout_context { + char *mode; + int result; + int done; + int resumptions; + struct flb_upstream *upstream; +}; + +static void dns_timeout_coro(void) +{ + struct flb_coro *coro; + struct dns_timeout_context *context; + struct addrinfo hints; + struct addrinfo *result; + + coro = flb_coro_get(); + context = coro->data; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + result = NULL; + + if (context->upstream != NULL) { + TEST_CHECK(flb_upstream_conn_get(context->upstream) == NULL); + } + else { + context->result = flb_net_getaddrinfo("fluent-bit-timeout-test.invalid.", "9200", + &hints, &result, context->mode, 1); + } + context->done = FLB_TRUE; + TEST_CHECK(result == NULL); + + while (FLB_TRUE) { + context->resumptions++; + flb_coro_yield(coro, FLB_FALSE); + } +} + +static void test_dns_timeout(char *mode, int upstream_first) +{ + size_t stack_size; + time_t limit; + void (*timeout_callback)(struct flb_config *, void *); + void *timeout_data; + struct flb_connection *connection; + struct mk_event *event; + struct dns_timeout_context context = {0}; + struct flb_net_dns dns; + struct flb_coro *coro; + struct flb_sched *sched; + struct flb_sched_timer *timer; + struct flb_sched_timer *deadline = NULL; + struct mk_list *head; + struct mk_event_loop *evl; +#ifdef FLB_SYSTEM_WINDOWS + WSADATA wsa_data; + + TEST_ASSERT(WSAStartup(MAKEWORD(2, 2), &wsa_data) == 0); +#endif + + flb_coro_init(); + flb_coro_thread_init(); + flb_engine_evl_init(); + flb_sched_ctx_init(); + flb_net_dns_ctx_init(); + flb_net_lib_init(); + flb_net_ctx_init(&dns); + flb_net_dns_ctx_set(&dns); + + evl = mk_event_loop_create(32); + TEST_ASSERT(evl != NULL); + flb_engine_evl_set(evl); + sched = flb_sched_create(test_env_config, evl); + TEST_ASSERT(sched != NULL); + flb_sched_ctx_set(sched); + + context.mode = mode; + if (upstream_first) { + context.upstream = flb_upstream_create(test_env_config, + "fluent-bit-timeout-test.invalid.", + 9200, FLB_IO_TCP, NULL); + TEST_ASSERT(context.upstream != NULL); + context.upstream->base.net.connect_timeout = 1; + context.upstream->base.net.dns_mode = mode; + } + coro = flb_coro_create(&context); + TEST_ASSERT(coro != NULL); + coro->caller = co_active(); + coro->callee = co_create(test_env_config->coro_stack_size, dns_timeout_coro, &stack_size); + TEST_ASSERT(coro->callee != NULL); +#ifdef FLB_HAVE_VALGRIND + coro->valgrind_stack_id = VALGRIND_STACK_REGISTER( + coro->callee, ((char *) coro->callee) + stack_size); +#endif + flb_coro_resume(coro); + TEST_ASSERT(context.done == FLB_FALSE); + + /* Do not dispatch DNS socket events: simulate a server that never answers. + * The lookup must install its own deadline for either transport. Only the + * scheduler frame timer exists before the lookup starts. + */ + mk_list_foreach(head, &sched->timers) { + timer = mk_list_entry(head, struct flb_sched_timer, _head); + if (timer->type == FLB_SCHED_TIMER_CB_ONESHOT) { + deadline = timer; + } + } + TEST_ASSERT(deadline != NULL); + timeout_callback = deadline->cb; + timeout_data = deadline->data; + + if (upstream_first) { + connection = mk_list_entry_first(&context.upstream->queue.busy_queue, + struct flb_connection, _head); + TEST_ASSERT(connection != NULL); + TEST_CHECK(connection->fd == FLB_INVALID_SOCKET); + connection->ts_connect_timeout = time(NULL) - 1; + flb_upstream_conn_timeouts(&test_env_config->upstreams); + flb_upstream_conn_pending_destroy(context.upstream); + TEST_CHECK(context.done == FLB_FALSE); + TEST_CHECK(mk_list_size(&context.upstream->queue.destroy_queue) == 1); + } + + /* Dispatch only scheduler events. Pumping the loop also lets timer-based + * backends deliver their notifications. Bound the test if the timer fails. + */ + limit = time(NULL) + 5; + while (!context.done && time(NULL) < limit) { + mk_event_wait_2(evl, 100); + mk_event_foreach(event, evl) { + if (event->type & FLB_ENGINE_EV_SCHED) { + flb_sched_event_handler(test_env_config, event); + } + } + if (mk_list_is_empty(&dns.lookups_drop) != 0) { + /* A late cancellation must be harmless before deferred cleanup. */ + timeout_callback(test_env_config, timeout_data); + } + flb_net_dns_lookup_context_cleanup(&dns); + flb_time_msleep(10); + } + TEST_CHECK(context.done == FLB_TRUE); + if (!upstream_first) { + TEST_CHECK(context.result == ARES_ETIMEOUT); + } + else { + flb_upstream_conn_pending_destroy(context.upstream); + TEST_CHECK(mk_list_is_empty(&context.upstream->queue.destroy_queue) == 0); + flb_upstream_destroy(context.upstream); + } + TEST_CHECK(mk_list_is_empty(&dns.lookups) == 0); + TEST_CHECK(mk_list_is_empty(&dns.lookups_drop) == 0); + + /* A second cleanup must not resume the coroutine or free the lookup again. */ + flb_net_dns_lookup_context_cleanup(&dns); + TEST_CHECK(context.resumptions == 1); + flb_coro_destroy(coro); + flb_sched_destroy(sched); + flb_sched_ctx_set(NULL); + flb_engine_evl_set(NULL); + flb_net_dns_ctx_set(NULL); + mk_event_loop_destroy(evl); + ares_library_cleanup(); +#ifdef FLB_SYSTEM_WINDOWS + WSACleanup(); +#endif +} + +static void test_tcp_dns_timeout(void) +{ + test_dns_timeout("TCP", FLB_FALSE); +} + +static void test_udp_dns_timeout(void) +{ + test_dns_timeout("UDP", FLB_FALSE); +} + +static void test_upstream_timeout_before_dns(void) +{ + test_dns_timeout("TCP", FLB_TRUE); +} + +TEST_LIST = { + { "upstream_timeout_before_dns", test_upstream_timeout_before_dns}, + { "tcp_dns_timeout", test_tcp_dns_timeout}, + { "udp_dns_timeout", test_udp_dns_timeout}, + { 0 } +}; From 6e42a5488430ed2b0100c34065066c1d281ded5f Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Fri, 23 Oct 2026 17:49:05 +0900 Subject: [PATCH 4/7] tests: integration: verify upstream timeout logging Signed-off-by: Hiroshi Hatake --- .../networking/tests/test_upstream_timeout.py | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 tests/integration/scenarios/networking/tests/test_upstream_timeout.py diff --git a/tests/integration/scenarios/networking/tests/test_upstream_timeout.py b/tests/integration/scenarios/networking/tests/test_upstream_timeout.py new file mode 100644 index 00000000000..fdfea6ddf74 --- /dev/null +++ b/tests/integration/scenarios/networking/tests/test_upstream_timeout.py @@ -0,0 +1,80 @@ +"""Exercise upstream timeout logging and retry completion against a silent peer.""" + +from pathlib import Path +import socketserver +import threading + +import pytest +import yaml + +from utils.test_service import FluentBitTestService + + +class SilentPeer(socketserver.BaseRequestHandler): + def handle(self): + # Accept TCP but never answer the TLS handshake. + self.server.release.wait(30) + + +class SilentServer(socketserver.ThreadingTCPServer): + daemon_threads = True + allow_reuse_address = True + + +@pytest.mark.parametrize("log_error", [True, False]) +def test_timeout_logs_configured_host_and_port(tmp_path, log_error): + server = SilentServer(("127.0.0.1", 0), SilentPeer) + server.release = threading.Event() + thread = threading.Thread(target=server.serve_forever, daemon=True) + thread.start() + port = server.server_address[1] + config = { + "service": { + "flush": 0.2, + "grace": 1, + "log_level": "debug", + "http_server": "on", + "http_port": "${FLUENT_BIT_HTTP_MONITORING_PORT}", + }, + "pipeline": { + "inputs": [{"name": "dummy", "samples": 1, "tag": "timeout"}], + "outputs": [{ + "name": "http", + "match": "*", + "host": "localhost", + "port": port, + "tls": "on", + "tls.verify": "off", + "net.dns.resolver": "LEGACY", + "net.connect_timeout": 2, + "net.connect_timeout_log_error": "on" if log_error else "off", + "retry_limit": "no_retries", + }], + }, + } + config_path = tmp_path / "timeout.yaml" + config_path.write_text(yaml.safe_dump(config), encoding="utf-8") + service = FluentBitTestService(str(config_path)) + try: + service.start() + + def completed(): + logs = Path(service.flb.log_file).read_text(encoding="utf-8", errors="replace") + return logs if "is not retried (no retry config)" in logs else None + + logs = service.wait_for_condition(completed, timeout=30, description="timed-out flush") + timeout_lines = [line for line in logs.splitlines() + if "[upstream]" in line and "timed out" in line] + assert timeout_lines, logs + assert any(f"to localhost:{port} timed out" in line for line in timeout_lines), logs + assert any(("[error]" if log_error else "[debug]") in line + for line in timeout_lines), logs + assert "unavailable:0" not in logs + finally: + try: + service.stop() + finally: + server.release.set() + server.shutdown() + server.server_close() + thread.join(timeout=5) From 5c15d2e7928fb4a5b313445ee15f5ae3ee4dcb0b Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Fri, 23 Oct 2026 20:11:15 +0900 Subject: [PATCH 5/7] network: honor disabled connect timeout during DNS lookup Signed-off-by: Hiroshi Hatake --- src/flb_network.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/flb_network.c b/src/flb_network.c index 4729ab79bdc..8b586737c56 100644 --- a/src/flb_network.c +++ b/src/flb_network.c @@ -1208,7 +1208,7 @@ int flb_net_getaddrinfo(const char *node, const char *service, struct addrinfo * flb_net_getaddrinfo_callback, lookup_context); if (!lookup_context->finished) { - if (lookup_context->ares_socket_created) { + if (lookup_context->ares_socket_created && timeout > 0) { /* Bound both UDP and TCP lookups, including a TCP connection to a * DNS server that never completes. Cancellation schedules cleanup * and resumes the waiting coroutine. @@ -1242,6 +1242,10 @@ int flb_net_getaddrinfo(const char *node, const char *service, struct addrinfo * flb_coro_yield(coroutine, FLB_FALSE); } } + else if (lookup_context->ares_socket_created) { + /* A non-positive connect timeout disables the DNS deadline too. */ + flb_coro_yield(coroutine, FLB_FALSE); + } else { /* Do we want to do anything special for this condition? */ } From dc8690574b079afe70d4ff87da64d0b35b147262 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Fri, 23 Oct 2026 20:11:15 +0900 Subject: [PATCH 6/7] tests: internal: cover disabled TCP DNS deadlines Signed-off-by: Hiroshi Hatake --- tests/internal/network_dns.c | 52 ++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/tests/internal/network_dns.c b/tests/internal/network_dns.c index d5c8d8b1055..659cf0a4482 100644 --- a/tests/internal/network_dns.c +++ b/tests/internal/network_dns.c @@ -15,6 +15,7 @@ struct dns_timeout_context { char *mode; int result; + int timeout; int done; int resumptions; struct flb_upstream *upstream; @@ -39,7 +40,7 @@ static void dns_timeout_coro(void) } else { context->result = flb_net_getaddrinfo("fluent-bit-timeout-test.invalid.", "9200", - &hints, &result, context->mode, 1); + &hints, &result, context->mode, context->timeout); } context->done = FLB_TRUE; TEST_CHECK(result == NULL); @@ -50,7 +51,7 @@ static void dns_timeout_coro(void) } } -static void test_dns_timeout(char *mode, int upstream_first) +static void test_dns_timeout(char *mode, int upstream_first, int timeout) { size_t stack_size; time_t limit; @@ -89,6 +90,7 @@ static void test_dns_timeout(char *mode, int upstream_first) flb_sched_ctx_set(sched); context.mode = mode; + context.timeout = timeout; if (upstream_first) { context.upstream = flb_upstream_create(test_env_config, "fluent-bit-timeout-test.invalid.", @@ -119,9 +121,16 @@ static void test_dns_timeout(char *mode, int upstream_first) deadline = timer; } } - TEST_ASSERT(deadline != NULL); - timeout_callback = deadline->cb; - timeout_data = deadline->data; + timeout_callback = NULL; + timeout_data = NULL; + if (timeout > 0) { + TEST_ASSERT(deadline != NULL); + timeout_callback = deadline->cb; + timeout_data = deadline->data; + } + else { + TEST_CHECK(deadline == NULL); + } if (upstream_first) { connection = mk_list_entry_first(&context.upstream->queue.busy_queue, @@ -135,27 +144,36 @@ static void test_dns_timeout(char *mode, int upstream_first) TEST_CHECK(mk_list_size(&context.upstream->queue.destroy_queue) == 1); } - /* Dispatch only scheduler events. Pumping the loop also lets timer-based - * backends deliver their notifications. Bound the test if the timer fails. + /* With a deadline, withhold DNS events to simulate an unresponsive server. + * Without one, let the configured resolver complete the .invalid lookup so + * the coroutine and lookup context can be cleaned up normally. */ limit = time(NULL) + 5; while (!context.done && time(NULL) < limit) { mk_event_wait_2(evl, 100); mk_event_foreach(event, evl) { - if (event->type & FLB_ENGINE_EV_SCHED) { + if (timeout <= 0 && event->type == FLB_ENGINE_EV_CUSTOM) { + event->handler(event); + } + else if (event->type & FLB_ENGINE_EV_SCHED) { flb_sched_event_handler(test_env_config, event); } } - if (mk_list_is_empty(&dns.lookups_drop) != 0) { + if (timeout_callback != NULL && mk_list_is_empty(&dns.lookups_drop) != 0) { /* A late cancellation must be harmless before deferred cleanup. */ timeout_callback(test_env_config, timeout_data); } flb_net_dns_lookup_context_cleanup(&dns); flb_time_msleep(10); } - TEST_CHECK(context.done == FLB_TRUE); + TEST_ASSERT(context.done == FLB_TRUE); if (!upstream_first) { - TEST_CHECK(context.result == ARES_ETIMEOUT); + if (timeout > 0) { + TEST_CHECK(context.result == ARES_ETIMEOUT); + } + else { + TEST_CHECK(context.result != ARES_ETIMEOUT); + } } else { flb_upstream_conn_pending_destroy(context.upstream); @@ -182,20 +200,26 @@ static void test_dns_timeout(char *mode, int upstream_first) static void test_tcp_dns_timeout(void) { - test_dns_timeout("TCP", FLB_FALSE); + test_dns_timeout("TCP", FLB_FALSE, 1); } static void test_udp_dns_timeout(void) { - test_dns_timeout("UDP", FLB_FALSE); + test_dns_timeout("UDP", FLB_FALSE, 1); } static void test_upstream_timeout_before_dns(void) { - test_dns_timeout("TCP", FLB_TRUE); + test_dns_timeout("TCP", FLB_TRUE, 1); +} + +static void test_tcp_dns_timeout_disabled(void) +{ + test_dns_timeout("TCP", FLB_FALSE, 0); } TEST_LIST = { + { "tcp_dns_timeout_disabled", test_tcp_dns_timeout_disabled}, { "upstream_timeout_before_dns", test_upstream_timeout_before_dns}, { "tcp_dns_timeout", test_tcp_dns_timeout}, { "udp_dns_timeout", test_udp_dns_timeout}, From 01e24eb561417a40d13abf0830b9892d3f21a4d3 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Fri, 23 Oct 2026 22:53:12 +0900 Subject: [PATCH 7/7] network: declare asynchronous DNS lookup in the public header Signed-off-by: Hiroshi Hatake --- include/fluent-bit/flb_network.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/fluent-bit/flb_network.h b/include/fluent-bit/flb_network.h index 6cec5bf3a87..131e53b5d70 100644 --- a/include/fluent-bit/flb_network.h +++ b/include/fluent-bit/flb_network.h @@ -137,6 +137,8 @@ void flb_net_setup_init(struct flb_net_setup *net); int flb_net_host_set(const char *plugin_name, struct flb_net_host *host, const char *address); /* DNS handling */ +int flb_net_getaddrinfo(const char *node, const char *service, struct addrinfo *hints, + struct addrinfo **res, char *dns_mode_textual, int timeout); void flb_net_dns_lookup_context_cleanup(struct flb_net_dns *dns_ctx); /* TCP options */