From a54558e50a99f61192f17b65e72b5ab7812db47c Mon Sep 17 00:00:00 2001 From: Michael Ponomarenko Date: Mon, 1 Jun 2026 10:09:31 -0400 Subject: [PATCH] Check replicant hostname validity Signed-off-by: Michael Ponomarenko --- cmake/FindLibEvent.cmake | 5 +-- db/comdb2.c | 1 + db/db_tunables.c | 1 + db/db_tunables.h | 4 +++ net/net_evbuffer.c | 73 +++++++++++++++++++++++++++++++++------- 5 files changed, 70 insertions(+), 14 deletions(-) diff --git a/cmake/FindLibEvent.cmake b/cmake/FindLibEvent.cmake index 4bc464be35..fb9a6b009e 100644 --- a/cmake/FindLibEvent.cmake +++ b/cmake/FindLibEvent.cmake @@ -1,8 +1,9 @@ find_path(LIBEVENT_INCLUDE_DIR NAMES event2/event.h) find_library(LIBEVENT_CORE_LIBRARY NAMES event_core) +find_library(LIBEVENT_EXTRA_LIBRARY NAMES event_extra) find_library(LIBEVENT_PTHREADS_LIBRARY NAMES event_pthreads) include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(LibEvent DEFAULT_MSG LIBEVENT_INCLUDE_DIR LIBEVENT_CORE_LIBRARY LIBEVENT_PTHREADS_LIBRARY) +find_package_handle_standard_args(LibEvent DEFAULT_MSG LIBEVENT_INCLUDE_DIR LIBEVENT_CORE_LIBRARY LIBEVENT_EXTRA_LIBRARY LIBEVENT_PTHREADS_LIBRARY) -list(APPEND LIBEVENT_LIBRARIES ${LIBEVENT_CORE_LIBRARY} ${LIBEVENT_PTHREADS_LIBRARY}) +list(APPEND LIBEVENT_LIBRARIES ${LIBEVENT_CORE_LIBRARY} ${LIBEVENT_EXTRA_LIBRARY} ${LIBEVENT_PTHREADS_LIBRARY}) diff --git a/db/comdb2.c b/db/comdb2.c index eae7b01e12..31aa855ce4 100644 --- a/db/comdb2.c +++ b/db/comdb2.c @@ -371,6 +371,7 @@ int gbl_debug_pb_connectmsg_dbname_check = 0; int gbl_debug_pb_connectmsg_gibberish = 0; double gbl_query_plan_percentage = 50; int gbl_readonly = 0; +int gbl_check_replicant_hostname = 1; int gbl_init_single_meta = 1; int gbl_schedule = 0; diff --git a/db/db_tunables.c b/db/db_tunables.c index c38fdaf753..b5758fbbc2 100644 --- a/db/db_tunables.c +++ b/db/db_tunables.c @@ -151,6 +151,7 @@ extern int gbl_debug_lock_get_list_copy_compare; extern int gbl_rep_mon_threshold; extern int gbl_repdebug; extern int gbl_replicant_latches; +extern int gbl_check_replicant_hostname; extern int gbl_return_long_column_names; extern int gbl_round_robin_stripes; extern int skip_clear_queue_extents; diff --git a/db/db_tunables.h b/db/db_tunables.h index ecdffa63cd..f6c517ee32 100644 --- a/db/db_tunables.h +++ b/db/db_tunables.h @@ -1053,6 +1053,10 @@ REGISTER_TUNABLE("replicant_latches", "Also acquire latches on replicants. (Default: off)", TUNABLE_BOOLEAN, &gbl_replicant_latches, READONLY | NOARG, NULL, NULL, NULL, NULL); +REGISTER_TUNABLE("check_replicant_hostname", + "Verify that the connecting peer's IP reverse-resolves to the " + "hostname claimed in its connect message. (Default: off)", + TUNABLE_BOOLEAN, &gbl_check_replicant_hostname, 0, NULL, NULL, NULL, NULL); REGISTER_TUNABLE("replicate_local", "When enabled, record all database events to a comdb2_oplog " "table. This can be used to set clusters/instances that are " diff --git a/net/net_evbuffer.c b/net/net_evbuffer.c index 16acfa9096..77e38e6c3e 100644 --- a/net/net_evbuffer.c +++ b/net/net_evbuffer.c @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -115,6 +116,7 @@ int gbl_libevent_rte_only = 0; extern char gbl_dbname[MAX_DBNAME_LENGTH]; extern char *gbl_myhostname; extern int gbl_accept_on_child_nets; +extern int gbl_check_replicant_hostname; extern int gbl_create_mode; extern int gbl_debug_pb_connectmsg_dbname_check; extern int gbl_debug_pb_connectmsg_gibberish; @@ -154,6 +156,7 @@ struct policy_info { static struct policy_info single; static pthread_t base_thd; static struct event_base *base; +static struct evdns_base *dns_base; static pthread_t timer_thd; static struct event_base *timer_base; @@ -1276,6 +1279,10 @@ static void exit_once_func(void) } } net_stop = 1; + if (dns_base) { + evdns_base_free(dns_base, 0); + dns_base = NULL; + } stop_base(base); if (dedicated_timer) { stop_base(timer_base); @@ -2547,6 +2554,55 @@ static void net_accept_ssl_error(void *data) accept_info_free(a); } +static int validate_host_finish(struct accept_info *a) +{ + if (a->c.flags & CONNECT_MSG_SSL) { + if (!SSL_IS_ABLE(gbl_rep_ssl_mode)) { + logmsg(LOGMSG_ERROR, "Peer requested SSL, but I don't have an SSL key pair.\n"); + return -1; + } + a->origin = get_hostname_by_fileno(a->fd); + a->ssl_data = ssl_data_new(a->fd, a->origin); + accept_ssl_evbuffer(a->ssl_data, base, net_accept_ssl_error, net_accept_ssl_success, a); + return 0; + } else if (SSL_IS_REQUIRED(gbl_rep_ssl_mode)) { + logmsg(LOGMSG_ERROR, "Replicant SSL connections are required.\n"); + return -1; + } + return accept_host(a); +} + +static void hostname_check_cb(int result, struct evutil_addrinfo *res, void *arg) +{ + struct accept_info *a = arg; + if (result != 0) { + logmsg(LOGMSG_ERROR, "%s fd:%d DNS lookup failed for claimed host:%s: %s\n", + __func__, a->fd, a->from_host, evutil_gai_strerror(result)); + accept_info_free(a); + return; + } + int match = 0; + for (struct evutil_addrinfo *r = res; r; r = r->ai_next) { + struct sockaddr_in *sin = (struct sockaddr_in *)r->ai_addr; + if (sin->sin_addr.s_addr == a->ss.sin_addr.s_addr) { + match = 1; + break; + } + } + evutil_freeaddrinfo(res); + if (!match) { + char ip[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &a->ss.sin_addr, ip, sizeof(ip)); + logmsg(LOGMSG_ERROR, "%s fd:%d hostname mismatch: claimed:%s does not resolve to ip:%s\n", + __func__, a->fd, a->from_host, ip); + accept_info_free(a); + return; + } + if (validate_host_finish(a) != 0) { + accept_info_free(a); + } +} + static int validate_host(struct accept_info *a) { if (strcmp(a->from_host, gbl_myhostname) == 0) { @@ -2590,20 +2646,12 @@ static int validate_host(struct accept_info *a) logmsg(LOGMSG_ERROR, "connection from node:%d host:%s not allowed\n", a->c.from_nodenum, host); return -1; } - if (a->c.flags & CONNECT_MSG_SSL) { - if (!SSL_IS_ABLE(gbl_rep_ssl_mode)) { - logmsg(LOGMSG_ERROR, "Peer requested SSL, but I don't have an SSL key pair.\n"); - return -1; - } - a->origin = get_hostname_by_fileno(a->fd); - a->ssl_data = ssl_data_new(a->fd, a->origin); - accept_ssl_evbuffer(a->ssl_data, base, net_accept_ssl_error, net_accept_ssl_success, a); + if (gbl_check_replicant_hostname) { + struct evutil_addrinfo hints = {.ai_family = AF_INET, .ai_socktype = SOCK_STREAM}; + evdns_getaddrinfo(dns_base, a->from_host, NULL, &hints, hostname_check_cb, a); return 0; - } else if (SSL_IS_REQUIRED(gbl_rep_ssl_mode)) { - logmsg(LOGMSG_ERROR, "Replicant SSL connections are required.\n"); - return -1; } - return accept_host(a); + return validate_host_finish(a); } static int process_long_hostname(struct accept_info *a) @@ -3548,6 +3596,7 @@ static void setup_bases(void) { event_set_fatal_callback(libevent_fatal_cb); init_base(&base_thd, &base, "main", NULL); + dns_base = evdns_base_new(base, EVDNS_BASE_INITIALIZE_NAMESERVERS); if (dedicated_timer) { gettimeofday(&timer_tick, NULL); init_base(&timer_thd, &timer_base, "timer", &timer_tick);