From 3674a436f68fb521aa4675c6fa7e1c8b3006854b Mon Sep 17 00:00:00 2001 From: Jeremie Leska Date: Fri, 22 May 2026 17:19:34 +0200 Subject: [PATCH] session server UPDATE allow binding on missing address Add a cmake option to use IP_FREEBIND/IPV6_FREEBIND options. Use the IP_FREEBIND/IPV6_FREEBIND on the socket to allow the bind even if the address is not ready. Signed-off-by: Jeremie Leska --- CMakeLists.txt | 6 ++++++ src/config.h.in | 3 +++ src/session_server.c | 20 ++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 42cb799e..ae347f2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ include(GNUInstallDirs) include(CheckFunctionExists) include(CheckCSourceCompiles) include(CheckIncludeFile) +include(CheckSymbolExists) include(UseCompat) include(ABICheck) include(SourceFormat) @@ -94,6 +95,7 @@ option(ENABLE_SSH_TLS "Enable NETCONF over SSH and TLS support (via libssh and O option(ENABLE_DNSSEC "Enable support for SSHFP retrieval using DNSSEC for SSH (requires OpenSSL and libval)" OFF) option(ENABLE_PAM "Detect and use PAM" ON) option(ENABLE_COMMON_TARGETS "Define common custom target names such as 'doc' or 'uninstall', may cause conflicts when using add_subdirectory() to build this project" ON) +option(ENABLE_IP_FREEBIND "Enable the IP_FREEBIND/IPV6_FREEBIND options on the listening TCP socket" OFF) option(BUILD_SHARED_LIBS "By default, shared libs are enabled. Turn off for a static build." ON) set(READ_INACTIVE_TIMEOUT 20 CACHE STRING "Maximum number of seconds waiting for new data once some data have arrived") set(READ_ACTIVE_TIMEOUT 300 CACHE STRING "Maximum number of seconds for receiving a full message") @@ -128,6 +130,10 @@ if(ENABLE_SSH_TLS) set(SSH_TLS_MACRO "#ifndef NC_ENABLED_SSH_TLS\n#define NC_ENABLED_SSH_TLS\n#endif") endif() +if(ENABLE_IP_FREEBIND) + check_symbol_exists(IP_FREEBIND "netinet/in.h" NC_ENABLE_IP_FREEBIND) +endif() + set(headers src/log.h src/netconf.h diff --git a/src/config.h.in b/src/config.h.in index d366e0d9..3b2dc484 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -83,4 +83,7 @@ /* Portability feature-check macros. */ #cmakedefine HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP +/* Enable IP_FREEBIND/IPV6_FREEBIND on listening sockets. */ +#cmakedefine NC_ENABLE_IP_FREEBIND + #endif /* NC_CONFIG_H_ */ diff --git a/src/session_server.c b/src/session_server.c index c49a9012..b7c888af 100644 --- a/src/session_server.c +++ b/src/session_server.c @@ -289,6 +289,10 @@ nc_sock_bind_inet(int sock, const char *address, uint16_t port, int is_ipv4) struct sockaddr_in *saddr4; struct sockaddr_in6 *saddr6; +#ifdef NC_ENABLE_IP_FREEBIND + int opt; +#endif + memset(&saddr, 0, sizeof(struct sockaddr_storage)); if (is_ipv4) { @@ -307,6 +311,14 @@ nc_sock_bind_inet(int sock, const char *address, uint16_t port, int is_ipv4) return -1; } +#ifdef NC_ENABLE_IP_FREEBIND + opt = 1; + if (setsockopt(sock, IPPROTO_IP, IP_FREEBIND, &opt, sizeof(opt))) { + ERR(NULL, "Could not add IP_FREEBIND option (%s).", strerror(errno)); + return -1; + } +#endif + if (bind(sock, (struct sockaddr *)saddr4, sizeof(struct sockaddr_in)) == -1) { ERR(NULL, "Could not bind %s:%" PRIu16 " (%s).", address, port, strerror(errno)); return -1; @@ -328,6 +340,14 @@ nc_sock_bind_inet(int sock, const char *address, uint16_t port, int is_ipv4) return -1; } +#ifdef NC_ENABLE_IP_FREEBIND + opt = 1; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_FREEBIND, &opt, sizeof(opt))) { + ERR(NULL, "Could not add IPV6_FREEBIND option (%s).", strerror(errno)); + return -1; + } +#endif + if (bind(sock, (struct sockaddr *)saddr6, sizeof(struct sockaddr_in6)) == -1) { ERR(NULL, "Could not bind [%s]:%" PRIu16 " (%s).", address, port, strerror(errno)); return -1;