@cryptotaxi247 / netdata-1 / commits / d05b41b19

Add compatibility for TCP(SSL) multiplexing (#21715)

* Initial plan * Add SNI support for SSL streaming connections - Add sni_hostname field to ND_SOCK structure - Update nd_sock_close() to free sni_hostname memory - Modify nd_sock_open_ssl() to set SNI using SSL_set_tlsext_host_name() - Update nd_sock_connect_to_this() to extract hostname from destination Co-authored-by: ilyam8 <22274335+ilyam8@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: ilyam8 <22274335+ilyam8@users.noreply.github.com> Co-authored-by: Ilya Mashchenko <ilya@netdata.cloud>

Copilot committed Mar 3, 2026 at 21:22 UTC d05b41b19766a4184d0e7ec530f5416237cfa34a
2 files changed +49
src/libnetdata/socket/nd-sock.c
+44
@@ -34,6 +34,16 @@ static bool nd_sock_open_ssl(ND_SOCK *s) {
34 if(!s) return false;
35
36 if (netdata_ssl_open_ext(&s->ssl, s->ctx, s->fd, alpn_proto_list, sizeof(alpn_proto_list))) {
37 + // Set SNI hostname if available
38 + if(s->sni_hostname && *s->sni_hostname) {
39 + if(!SSL_set_tlsext_host_name(s->ssl.conn, s->sni_hostname)) {
40 + nd_log(NDLS_DAEMON, NDLP_WARNING,
41 + "Failed to set SNI hostname '%s' for SSL connection",
42 + s->sni_hostname);
43 + // Continue anyway - SNI failure is not fatal
44 + }
45 + }
46 +
47 if(!netdata_ssl_connect(&s->ssl)) {
48 // couldn't connect
49 s->error = ND_SOCK_ERR_SSL_CANT_ESTABLISH_SSL_CONNECTION;
@@ -56,6 +66,40 @@ static bool nd_sock_open_ssl(ND_SOCK *s) {
66 bool nd_sock_connect_to_this(ND_SOCK *s, const char *definition, int default_port, time_t timeout, bool ssl) {
67 nd_sock_close(s);
68
69 + // Extract hostname for SNI before establishing connection
70 + if(ssl && definition) {
71 + char buffer[strlen(definition) + 1];
72 + strcpy(buffer, definition);
73 +
74 + char *host = buffer;
75 +
76 + // Skip protocol prefix if present
77 + if(strncmp(host, "tcp:", 4) == 0)
78 + host += 4;
79 + else if(strncmp(host, "udp:", 4) == 0)
80 + host += 4;
81 +
82 + // Handle IPv6 addresses in brackets
83 + char *hostname_end = host;
84 + if(*host == '[') {
85 + host++; // Skip opening bracket
86 + while(*hostname_end && *hostname_end != ']') hostname_end++;
87 + if(*hostname_end == ']')
88 + *hostname_end = '\0';
89 + }
90 + else {
91 + // For IPv4 or hostnames, find the end (before port or interface)
92 + while(*hostname_end && *hostname_end != ':' && *hostname_end != '%') hostname_end++;
93 + if(*hostname_end)
94 + *hostname_end = '\0';
95 + }
96 +
97 + // Store the hostname for SNI if it's not empty
98 + if(host && *host) {
99 + s->sni_hostname = strdupz(host);
100 + }
101 + }
102 +
103 struct timeval tv = {
104 .tv_sec = timeout,
105 .tv_usec = 0
src/libnetdata/socket/nd-sock.h
+5
@@ -32,6 +32,7 @@ typedef struct nd_sock {
32 int fd;
33 NETDATA_SSL ssl;
34 SSL_CTX *ctx;
35 + char *sni_hostname; // hostname for SNI in SSL/TLS connections
36 } ND_SOCK;
37
38 #define ND_SOCK_INIT(ssl_ctx, ssl_verify) (ND_SOCK){ \
@@ -40,6 +41,7 @@ typedef struct nd_sock {
41 .fd = -1, \
42 .ssl = NETDATA_SSL_UNSET_CONNECTION, \
43 .ctx = ssl_ctx, \
44 + .sni_hostname = NULL, \
45 }
46
47 static inline void nd_sock_init(ND_SOCK *s, SSL_CTX *ctx, bool verify_certificate) {
@@ -48,6 +50,7 @@ static inline void nd_sock_init(ND_SOCK *s, SSL_CTX *ctx, bool verify_certificat
50 s->fd = -1;
51 s->ssl = NETDATA_SSL_UNSET_CONNECTION;
52 s->ctx = ctx;
53 + s->sni_hostname = NULL;
54 }
55
56 ALWAYS_INLINE
@@ -69,6 +72,8 @@ static void nd_sock_close(ND_SOCK *s) {
72 s->fd = -1;
73 }
74
75 + freez(s->sni_hostname);
76 + s->sni_hostname = NULL;
77 s->error = ND_SOCK_ERR_NONE;
78 }
79