From ecbf33367948d5cd3fa850aaeaf890ecab773a30 Mon Sep 17 00:00:00 2001 From: Michael Ortmann Date: Sat, 16 May 2026 23:34:24 +0200 Subject: [PATCH 01/20] Fix response status --- src/tls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tls.c b/src/tls.c index 5b8cc72a3..f26b8ee20 100644 --- a/src/tls.c +++ b/src/tls.c @@ -1105,7 +1105,7 @@ int ssl_handshake(int sock, int flags, int verify, int loglevel, char *host, char *response; char *body = "Error: HTTP request received on an SSL port, please try HTTPS"; j = snprintf(NULL, 0, - "HTTP/1.1 200 \r\n" /* textual phrase is OPTIONAL */ + "HTTP/1.1 400 \r\n" /* textual phrase is OPTIONAL */ "Content-Length: %zu\r\n" "Content-Type: text/plain; charset=utf-8\r\n" "Server: %s\r\n" @@ -1114,7 +1114,7 @@ int ssl_handshake(int sock, int flags, int verify, int loglevel, char *host, body); response = nmalloc(j + 1); sprintf(response, - "HTTP/1.1 200 \r\n" /* textual phrase is OPTIONAL */ + "HTTP/1.1 400 \r\n" /* textual phrase is OPTIONAL */ "Content-Length: %zu\r\n" "Content-Type: text/plain; charset=utf-8\r\n" "Server: %s\r\n" From b0ee5e089b5f35fe5bb33d18b825dfb1dbae68ea Mon Sep 17 00:00:00 2001 From: Michael Ortmann Date: Sun, 17 May 2026 02:51:56 +0200 Subject: [PATCH 02/20] Fix use after free / fingerprint logging --- src/tls.c | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/src/tls.c b/src/tls.c index f26b8ee20..72b0eae89 100644 --- a/src/tls.c +++ b/src/tls.c @@ -136,21 +136,19 @@ static X509 *ssl_getcert(int sock) * Return value: ptr to the hexadecimal representation of the fingerprint or * NULL in case of error. */ -static char *ssl_getfp_from_cert(X509 *cert) +static char *ssl_getfp_from_cert(X509 *cert, const EVP_MD* type) { char *p; unsigned int i; - static char fp[SHA_DIGEST_LENGTH * 3]; - unsigned char md[SHA_DIGEST_LENGTH]; + static char fp[EVP_MAX_MD_SIZE * 3]; + unsigned char md[EVP_MAX_MD_SIZE]; - if (!X509_digest(cert, EVP_sha1(), md, &i)) { + if (!X509_digest(cert, type, md, &i)) { putlog(LOG_MISC, "*", "ERROR: TLS: ssl_getfp_from_cert(): X509_digest()"); - X509_free(cert); return NULL; } if (!(p = OPENSSL_buf2hexstr(md, i))) { putlog(LOG_MISC, "*", "ERROR: TLS: ssl_getfp_from_cert(): OPENSSL_buf2hexstr()"); - X509_free(cert); return NULL; } strlcpy(fp, p, sizeof fp); @@ -173,7 +171,7 @@ char *ssl_getfp(int sock) if (!(cert = ssl_getcert(sock))) return NULL; - fp = ssl_getfp_from_cert(cert); + fp = ssl_getfp_from_cert(cert, EVP_sha1()); #if OPENSSL_VERSION_NUMBER < 0x30000000L /* 3.0.0 */ X509_free(cert); #endif @@ -182,6 +180,7 @@ char *ssl_getfp(int sock) void verify_cert_expiry(int idx) { X509 *x509; + static char last_tls_certfile[sizeof tls_certfile]; #if OPENSSL_VERSION_NUMBER >= 0x10002000L /* 1.0.2 */ x509 = SSL_CTX_get0_certificate(ssl_ctx); /* The returned pointer must not be freed by the caller. */ #else @@ -191,6 +190,11 @@ void verify_cert_expiry(int idx) { x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); #endif if (x509) { + if (strcmp(tls_certfile, last_tls_certfile)) { + putlog(LOG_MISC, "*", "Certificate loaded: %s (sha256 fingerprint %s)", + tls_certfile, ssl_getfp_from_cert(x509, EVP_sha256())); + strlcpy(last_tls_certfile, tls_certfile, sizeof last_tls_certfile); + } #if OPENSSL_VERSION_NUMBER >= 0x40000000L /* 4.0.0 */ int e; if (!X509_check_certificate_times(NULL, x509, &e) && (e == X509_V_ERR_CERT_HAS_EXPIRED)) { @@ -264,23 +268,6 @@ int ssl_init() tls_certfile, ERR_error_string(ERR_get_error(), NULL)); fatal("Unable to load TLS certificate (ssl-certificate config setting)!", 0); } - - /* TODO: sha256 fingerprint - * print this fingerprint to every user / every partyline login - * maybe only print it when webui is enabled - * compatibility to older openssl is possible, similar to #1411 - * this functionality could be sepped into a side-PR - * or functionality of #1411 can be reused once merged - * - * for now, just disable the fingerprint for openssl < 1.0.2 - */ -#if OPENSSL_VERSION_NUMBER >= 0x10002000L /* 1.0.2 */ - // TODO: ssl_getfp_from_cert() must not free the cert from SSL_CTX_get0_certificate() - putlog(LOG_MISC, "*", "Certificate loaded: %s (sha1 fingerprint %s)", - tls_certfile, - ssl_getfp_from_cert(SSL_CTX_get0_certificate(ssl_ctx))); -#endif - verify_cert_expiry(0); if (SSL_CTX_use_PrivateKey_file(ssl_ctx, tls_keyfile, SSL_FILETYPE_PEM) != 1) { putlog(LOG_MISC, "*", "ERROR: TLS: unable to load private key from %s: %s", From f4ee14260838ebbd671e08ab5e11d6a8ba58da06 Mon Sep 17 00:00:00 2001 From: Michael Ortmann Date: Sun, 17 May 2026 05:53:52 +0200 Subject: [PATCH 03/20] Init function pointer to null_func instead of 0 --- src/modules.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules.c b/src/modules.c index 1388ae9f6..9c42f4da7 100644 --- a/src/modules.c +++ b/src/modules.c @@ -162,7 +162,7 @@ int (*rfc_toupper) (int) = _rfc_toupper; int (*rfc_tolower) (int) = _rfc_tolower; void (*dns_hostbyip) (sockname_t *) = core_dns_hostbyip; void (*dns_ipbyhost) (char *) = core_dns_ipbyhost; -void (*webui_dcc_telnet_hostresolved) (int, int) = 0; +void (*webui_dcc_telnet_hostresolved) (int, int) = (void (*)(int, int)) null_func; size_t (*webui_frame) (char **, char *, size_t) = 0; void (*webui_unframe) (int, char *, int *) = 0; From b3a08ffc855e7f6c09d8e7ab56041e24c42143e5 Mon Sep 17 00:00:00 2001 From: Michael Ortmann Date: Sun, 17 May 2026 17:35:42 +0200 Subject: [PATCH 04/20] Removed comment, because connection is properly closed with SO_LINGER + close(), verified with strace and tcpdump --- src/tls.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tls.c b/src/tls.c index 72b0eae89..03fc03fc5 100644 --- a/src/tls.c +++ b/src/tls.c @@ -1110,7 +1110,6 @@ int ssl_handshake(int sock, int flags, int verify, int loglevel, char *host, body); if (write(sock, response, j) < 0) /* tputs() cannot be used here */ putlog(LOG_MISC, "*", "TLS: error: write(sock %i): %s", sock, strerror(errno)); - // TODO: after reading of remaining bytes / ssl shutdown ? nfree(response); } else { putlog(data->loglevel, "*", From 01e85f776d49881eb4447332ebbdb3a7fbcc7680 Mon Sep 17 00:00:00 2001 From: Michael Ortmann Date: Sun, 17 May 2026 18:56:44 +0200 Subject: [PATCH 05/20] Write SSL_R_HTTP_REQUEST error msg only to webui ports --- src/tls.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tls.c b/src/tls.c index 03fc03fc5..40d23919d 100644 --- a/src/tls.c +++ b/src/tls.c @@ -1084,7 +1084,8 @@ int ssl_handshake(int sock, int flags, int verify, int loglevel, char *host, return 0; } if ((err = ERR_peek_error())) { - if (ERR_GET_LIB(ERR_peek_error()) == ERR_LIB_SSL && + if ((td->socklist[i].flags &= SOCK_WEBUI) && + ERR_GET_LIB(ERR_peek_error()) == ERR_LIB_SSL && ERR_GET_REASON(err) == SSL_R_HTTP_REQUEST) { /* We dont have access to real port, host or dcc information here */ putlog(LOG_MISC, "*", "TLS: error: HTTP request received on an SSL port"); From 590675d01b003f987dbc02567fde82d1f7c4cdb7 Mon Sep 17 00:00:00 2001 From: Michael Ortmann Date: Sun, 17 May 2026 19:15:51 +0200 Subject: [PATCH 06/20] Write SSL_R_HTTP_REQUEST error msg only to webui ports --- src/dcc.c | 5 ++++- src/eggdrop.h | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/dcc.c b/src/dcc.c index f65a5b360..7a085d975 100644 --- a/src/dcc.c +++ b/src/dcc.c @@ -1284,7 +1284,10 @@ static void dcc_telnet(int idx, char *buf, int i) return; } /* Buffer data received on this socket. */ - sockoptions(sock, EGG_OPTION_SET, SOCK_BUFFER); + if (!strcmp(dcc[idx].nick, "(webui)")) + sockoptions(sock, EGG_OPTION_SET, SOCK_BUFFER | SOCK_WEBUI); + else + sockoptions(sock, EGG_OPTION_SET, SOCK_BUFFER); if (port < 1024) { putlog(LOG_BOTS, "*", DCC_BADSRC, iptostr(&dcc[i].sockname.addr.sa), port); diff --git a/src/eggdrop.h b/src/eggdrop.h index 37c7a69a2..f4fe3bcf3 100644 --- a/src/eggdrop.h +++ b/src/eggdrop.h @@ -594,7 +594,8 @@ typedef struct { #define SOCK_VIRTUAL 0x0200 /* not-connected socket (dont read it!) */ #define SOCK_BUFFER 0x0400 /* buffer data; don't notify dcc funcs */ #define SOCK_TCL 0x0800 /* tcl socket, don't do anything on it */ -#define SOCK_WS 0x1000 /* webui websocket */ +#define SOCK_WEBUI 0x1000 /* webui websocket */ +#define SOCK_WS 0x2000 /* webui websocket */ /* Flags to sock_has_data */ From 31f779f95d181e4b24f169d9ae50001776208a5f Mon Sep 17 00:00:00 2001 From: Michael Ortmann Date: Mon, 18 May 2026 00:37:42 +0200 Subject: [PATCH 07/20] killsock(): dont kill stdout, so that we keep stdout logging until the very last cycle of .die waving killsock(), it just doesnt make sense to kill stdout. puts(): fix memleak / recursion openssl error logging --- src/net.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/net.c b/src/net.c index 8099f962b..3fa4fffbe 100644 --- a/src/net.c +++ b/src/net.c @@ -420,8 +420,8 @@ void killsock(int sock) int i; struct threaddata *td = threaddata(); - /* Ignore invalid sockets. */ - if (sock < 0) + /* Ignore invalid sockets and stdout */ + if ((sock < 0) || (sock == 1)) return; for (i = 0; i < td->MAXSOCKS; i++) { @@ -1366,18 +1366,25 @@ void tputs(int z, char *s, unsigned int len) else len = webui_frame(&s2, s, len); if (socklist[i].ssl) { - x = SSL_write(socklist[i].ssl, s2, len); - if (x < 0) { - int err = SSL_get_error(socklist[i].ssl, x); - if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) - errno = EAGAIN; - else if (!inhere) { /* Out there, somewhere */ - inhere = 1; - debug1("tputs(): SSL error = %s", - ERR_error_string(ERR_get_error(), 0)); - inhere = 0; + if (!inhere) { + ERR_clear_error(); + x = SSL_write(socklist[i].ssl, s2, len); + if (x < 0) { + int err = SSL_get_error(socklist[i].ssl, x); + if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) + errno = EAGAIN; + else { + inhere = 1; /* Out there, somewhere */ + unsigned long e; + while ((e = ERR_get_error()) != 0) + debug1("tputs(): SSL error = %s", ERR_error_string(e, 0)); + inhere = 0; + } + x = -1; } - x = -1; + } else { + inhere = 0; + return; } } else /* not ssl, use regular write() */ #else From 4e5065f4170def14eb7f72d46cbe02aef8aa7be8 Mon Sep 17 00:00:00 2001 From: Michael Ortmann Date: Mon, 18 May 2026 00:45:08 +0200 Subject: [PATCH 08/20] cleanup --- src/net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net.c b/src/net.c index 3fa4fffbe..87f466adc 100644 --- a/src/net.c +++ b/src/net.c @@ -1376,7 +1376,7 @@ void tputs(int z, char *s, unsigned int len) else { inhere = 1; /* Out there, somewhere */ unsigned long e; - while ((e = ERR_get_error()) != 0) + while ((e = ERR_get_error())) debug1("tputs(): SSL error = %s", ERR_error_string(e, 0)); inhere = 0; } From 76fc9662e2ee26e46e0d6cfbd6d64b76b99e728d Mon Sep 17 00:00:00 2001 From: Michael Ortmann Date: Mon, 18 May 2026 01:00:02 +0200 Subject: [PATCH 09/20] Revert "cleanup" This reverts commit 4e5065f4170def14eb7f72d46cbe02aef8aa7be8. --- src/net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net.c b/src/net.c index 87f466adc..3fa4fffbe 100644 --- a/src/net.c +++ b/src/net.c @@ -1376,7 +1376,7 @@ void tputs(int z, char *s, unsigned int len) else { inhere = 1; /* Out there, somewhere */ unsigned long e; - while ((e = ERR_get_error())) + while ((e = ERR_get_error()) != 0) debug1("tputs(): SSL error = %s", ERR_error_string(e, 0)); inhere = 0; } From 2c96b4bcb500a3c68894b8ed0c2ee6dc88904c75 Mon Sep 17 00:00:00 2001 From: Michael Ortmann Date: Mon, 18 May 2026 01:00:12 +0200 Subject: [PATCH 10/20] Revert "killsock(): dont kill stdout, so that we keep stdout logging until the very last cycle of .die waving killsock(), it just doesnt make sense to kill stdout. puts(): fix memleak / recursion openssl error logging" This reverts commit 31f779f95d181e4b24f169d9ae50001776208a5f. --- src/net.c | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/src/net.c b/src/net.c index 3fa4fffbe..8099f962b 100644 --- a/src/net.c +++ b/src/net.c @@ -420,8 +420,8 @@ void killsock(int sock) int i; struct threaddata *td = threaddata(); - /* Ignore invalid sockets and stdout */ - if ((sock < 0) || (sock == 1)) + /* Ignore invalid sockets. */ + if (sock < 0) return; for (i = 0; i < td->MAXSOCKS; i++) { @@ -1366,25 +1366,18 @@ void tputs(int z, char *s, unsigned int len) else len = webui_frame(&s2, s, len); if (socklist[i].ssl) { - if (!inhere) { - ERR_clear_error(); - x = SSL_write(socklist[i].ssl, s2, len); - if (x < 0) { - int err = SSL_get_error(socklist[i].ssl, x); - if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) - errno = EAGAIN; - else { - inhere = 1; /* Out there, somewhere */ - unsigned long e; - while ((e = ERR_get_error()) != 0) - debug1("tputs(): SSL error = %s", ERR_error_string(e, 0)); - inhere = 0; - } - x = -1; + x = SSL_write(socklist[i].ssl, s2, len); + if (x < 0) { + int err = SSL_get_error(socklist[i].ssl, x); + if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) + errno = EAGAIN; + else if (!inhere) { /* Out there, somewhere */ + inhere = 1; + debug1("tputs(): SSL error = %s", + ERR_error_string(ERR_get_error(), 0)); + inhere = 0; } - } else { - inhere = 0; - return; + x = -1; } } else /* not ssl, use regular write() */ #else From 70b5c281b3bd6eb7f65fe5adcfb8738082136cff Mon Sep 17 00:00:00 2001 From: Michael Ortmann Date: Mon, 18 May 2026 01:05:14 +0200 Subject: [PATCH 11/20] killsock(): dont kill stdout, so that we keep stdout logging until the very last cycle of .die waving killsock(), it just doesnt make sense to kill stdout. --- src/net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/net.c b/src/net.c index 8099f962b..41309e23b 100644 --- a/src/net.c +++ b/src/net.c @@ -420,8 +420,8 @@ void killsock(int sock) int i; struct threaddata *td = threaddata(); - /* Ignore invalid sockets. */ - if (sock < 0) + /* Ignore invalid sockets and stdout. */ + if ((sock < 0) || (sock == 1)) return; for (i = 0; i < td->MAXSOCKS; i++) { From 8f1f62f177034e5414e1e8d22e3e8f945afcb5b8 Mon Sep 17 00:00:00 2001 From: Michael Ortmann Date: Mon, 18 May 2026 01:07:09 +0200 Subject: [PATCH 12/20] tputs(): Fix openssl error logging --- src/net.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/net.c b/src/net.c index 41309e23b..12082756b 100644 --- a/src/net.c +++ b/src/net.c @@ -1366,6 +1366,7 @@ void tputs(int z, char *s, unsigned int len) else len = webui_frame(&s2, s, len); if (socklist[i].ssl) { + ERR_clear_error(); x = SSL_write(socklist[i].ssl, s2, len); if (x < 0) { int err = SSL_get_error(socklist[i].ssl, x); From c0c987fbaec8f19d7b4339e37052f616df42f492 Mon Sep 17 00:00:00 2001 From: Michael Ortmann Date: Mon, 18 May 2026 03:10:42 +0200 Subject: [PATCH 13/20] tputs(): Fix memleak --- src/net.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/net.c b/src/net.c index 12082756b..bf2b39f9f 100644 --- a/src/net.c +++ b/src/net.c @@ -1377,6 +1377,7 @@ void tputs(int z, char *s, unsigned int len) debug1("tputs(): SSL error = %s", ERR_error_string(ERR_get_error(), 0)); inhere = 0; + return; } x = -1; } From d4cac15a7a17018be7493c3889f8c11b060214ce Mon Sep 17 00:00:00 2001 From: Michael Ortmann Date: Mon, 18 May 2026 03:15:04 +0200 Subject: [PATCH 14/20] More ERR_clear_error() --- src/net.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/net.c b/src/net.c index bf2b39f9f..97329a390 100644 --- a/src/net.c +++ b/src/net.c @@ -1471,6 +1471,7 @@ void dequeue_sockets() errno = 0; #ifdef TLS if (socklist[i].ssl) { + ERR_clear_error(); x = SSL_write(socklist[i].ssl, socklist[i].handler.sock.outbuf, socklist[i].handler.sock.outbuflen); if (x < 0) { From cecea56e1761847f797b5469f067daa0c2d7501a Mon Sep 17 00:00:00 2001 From: Michael Ortmann Date: Mon, 18 May 2026 05:50:33 +0200 Subject: [PATCH 15/20] Stop writing to sock after close notify during write and enhance logging --- src/tls.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/tls.c b/src/tls.c index 40d23919d..d36037207 100644 --- a/src/tls.c +++ b/src/tls.c @@ -937,9 +937,14 @@ static void ssl_info(const SSL *ssl, int where, int ret) !strcmp(SSL_alert_desc_string(ret), "RO")) putlog(LOG_MISC, "*", "TLS: Long TLSCiphertext field received, connection failed. Is this really a TLS port?"); } else { - /* Ignore close notify warnings */ - debug1("TLS: Received close notify during %s", - (where & SSL_CB_READ) ? "read" : "write"); + /* Ignore close notify warnings and stop writing to sock */ + sock = SSL_get_fd(ssl); + debug2("TLS: Received close notify during %s sock %i", + (where & SSL_CB_READ) ? "read" : "write", sock); + if (where & SSL_CB_WRITE) { + int idx = findidx(sock); + lostdcc(idx); + } } } else if (where & SSL_CB_EXIT) { /* SSL_CB_EXIT may point to soft error for non-blocking! */ From 5883021f4ba232cde0c05e656b6e7fa2b30c3c1b Mon Sep 17 00:00:00 2001 From: Michael Ortmann Date: Mon, 18 May 2026 05:55:41 +0200 Subject: [PATCH 16/20] Fix fatal(): end all logging to dcc for killed sock --- src/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index 0847138b0..4b58342aa 100644 --- a/src/main.c +++ b/src/main.c @@ -163,8 +163,10 @@ void fatal(const char *s, int recoverable) putlog(LOG_MISC, "*", "* %s", s); for (i = 0; i < dcc_total; i++) - if (dcc[i].sock >= 0) + if (dcc[i].sock >= 0) { killsock(dcc[i].sock); + dcc[i].sock = -1; + } #ifdef TLS ssl_cleanup(); #endif From fa6d9efddc97ce616ab236f90991efa9cc5367cf Mon Sep 17 00:00:00 2001 From: Michael Ortmann Date: Mon, 18 May 2026 08:22:46 +0200 Subject: [PATCH 17/20] Fix memleak --- src/dcc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/dcc.c b/src/dcc.c index 30eb7f473..09ae20027 100644 --- a/src/dcc.c +++ b/src/dcc.c @@ -1452,6 +1452,13 @@ static void dcc_telnet_hostresolved(int i) } #endif + /* dcc type is DNSWAIT + * free its dcc[i].u.dns_info + * because lostdcc() is not called on it + * but its type is changed and dcc[i].u is reused + */ + dcc[i].type->kill(i, dcc[i].u.other); + /* Skip ident lookup for public script listeners */ if ((dcc[idx].status & LSTN_PUBLIC) && !strcmp(dcc[idx].nick, "(script)")) { changeover_dcc(i, &DCC_SOCKET, 0); From 16bdb16548880a9ef262f01bebb631610ed0f6f6 Mon Sep 17 00:00:00 2001 From: Michael Ortmann Date: Mon, 18 May 2026 08:32:56 +0200 Subject: [PATCH 18/20] Proper memleak fix --- src/dcc.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/dcc.c b/src/dcc.c index 09ae20027..ffee55230 100644 --- a/src/dcc.c +++ b/src/dcc.c @@ -1346,6 +1346,8 @@ void dcc_telnet_hostresolved2(int i, int idx) { ident_target_port = getenv("EGGDROP_TEST") ? 1113 : 113; snprintf(userhost, sizeof userhost, "telnet@%s", dcc[i].host); + changeover_dcc(i, &DCC_IDENTWAIT, 0); + /* Skip ident lookup if disabled */ if (identtimeout <= 0) { dcc[i].u.ident_sock = dcc[idx].sock; @@ -1353,7 +1355,6 @@ void dcc_telnet_hostresolved2(int i, int idx) { return; } - changeover_dcc(i, &DCC_IDENTWAIT, 0); dcc[i].timeval = now; dcc[i].u.ident_sock = dcc[idx].sock; sock = -1; @@ -1452,13 +1453,6 @@ static void dcc_telnet_hostresolved(int i) } #endif - /* dcc type is DNSWAIT - * free its dcc[i].u.dns_info - * because lostdcc() is not called on it - * but its type is changed and dcc[i].u is reused - */ - dcc[i].type->kill(i, dcc[i].u.other); - /* Skip ident lookup for public script listeners */ if ((dcc[idx].status & LSTN_PUBLIC) && !strcmp(dcc[idx].nick, "(script)")) { changeover_dcc(i, &DCC_SOCKET, 0); From e30327f172c7dc42d20c3351fa4a5e1edf070a5a Mon Sep 17 00:00:00 2001 From: Thomas Sader Date: Sat, 23 May 2026 18:42:28 +0200 Subject: [PATCH 19/20] Fix more issues --- src/dccutil.c | 18 ++++++++++++++++++ src/eggdrop.h | 5 +++-- src/modules.c | 4 ++-- src/net.c | 13 ++++++++----- src/proto.h | 1 + src/tls.c | 15 ++++++++++----- 6 files changed, 42 insertions(+), 14 deletions(-) diff --git a/src/dccutil.c b/src/dccutil.c index 3ae31b242..eef06e67b 100644 --- a/src/dccutil.c +++ b/src/dccutil.c @@ -353,6 +353,18 @@ void lostdcc(int n) dcc[n].type = &DCC_LOST; } +/* Mark an entry as lost, to be reaped in the mainloop asynchronously. + * Avoids reentrancy issues + */ +void lostdcc_deferred(int n) +{ + /* sanity check */ + if (n < 0 || n >= max_dcc) { + return; + } + dcc[n].status |= STAT_LOSTDCC; +} + /* Remove entry from dcc list. Think twice before using this function, * because it invalidates any variables that point to a specific dcc * entry! @@ -385,6 +397,12 @@ void dcc_remove_lost(void) dcc[i].sock = -1; removedcc(i); i--; + } else if (dcc[i].status & STAT_LOSTDCC) { + /* intentionally after DCC_LOST cleanup, + * so it doesn't clean immediately + */ + dcc[i].status &= ~STAT_LOSTDCC; + lostdcc(i); } } } diff --git a/src/eggdrop.h b/src/eggdrop.h index f4fe3bcf3..3ee93309b 100644 --- a/src/eggdrop.h +++ b/src/eggdrop.h @@ -482,6 +482,7 @@ struct dupwait_info { #define STAT_PAGE 0x00080 /* page output to the user */ #define STAT_SERV 0x00100 /* this is a server connection */ #define STAT_WS 0x00200 /* webui websocket */ +#define STAT_LOSTDCC 0x00400 /* closed by remote, call lostdcc() */ /* For stripping out mIRC codes. */ #define STRIP_COLOR 0x00001 /* remove mIRC color codes */ @@ -594,8 +595,8 @@ typedef struct { #define SOCK_VIRTUAL 0x0200 /* not-connected socket (dont read it!) */ #define SOCK_BUFFER 0x0400 /* buffer data; don't notify dcc funcs */ #define SOCK_TCL 0x0800 /* tcl socket, don't do anything on it */ -#define SOCK_WEBUI 0x1000 /* webui websocket */ -#define SOCK_WS 0x2000 /* webui websocket */ +#define SOCK_WEBUI 0x1000 /* webui websocket pre-upgrade */ +#define SOCK_WS 0x2000 /* webui websocket after framed upgrade */ /* Flags to sock_has_data */ diff --git a/src/modules.c b/src/modules.c index 9c42f4da7..9509aa32e 100644 --- a/src/modules.c +++ b/src/modules.c @@ -163,8 +163,8 @@ int (*rfc_tolower) (int) = _rfc_tolower; void (*dns_hostbyip) (sockname_t *) = core_dns_hostbyip; void (*dns_ipbyhost) (char *) = core_dns_ipbyhost; void (*webui_dcc_telnet_hostresolved) (int, int) = (void (*)(int, int)) null_func; -size_t (*webui_frame) (char **, char *, size_t) = 0; -void (*webui_unframe) (int, char *, int *) = 0; +size_t (*webui_frame) (char **, char *, size_t) = (void (*)(char **, char * ,size_t)) null_func; +void (*webui_unframe) (int, char *, int *) = (void (*)(int, char *, int *)) null_func; module_entry *module_list; dependancy *dependancy_list = NULL; diff --git a/src/net.c b/src/net.c index 97329a390..032461f68 100644 --- a/src/net.c +++ b/src/net.c @@ -420,8 +420,8 @@ void killsock(int sock) int i; struct threaddata *td = threaddata(); - /* Ignore invalid sockets and stdout. */ - if ((sock < 0) || (sock == 1)) + /* Ignore invalid sockets and stdout/stderr. */ + if ((sock < 0) || (sock == STDOUT) || (sock == STDERR)) return; for (i = 0; i < td->MAXSOCKS; i++) { @@ -1370,14 +1370,17 @@ void tputs(int z, char *s, unsigned int len) x = SSL_write(socklist[i].ssl, s2, len); if (x < 0) { int err = SSL_get_error(socklist[i].ssl, x); - if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) + if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) { errno = EAGAIN; - else if (!inhere) { /* Out there, somewhere */ + } else if (err == SSL_ERROR_ZERO_RETURN) { + /* Peer sent close notify, lostdcc_deferred() was already + * scheduled from ssl_info(). Don't queue more data. */ + return; + } else if (!inhere) { /* Out there, somewhere */ inhere = 1; debug1("tputs(): SSL error = %s", ERR_error_string(ERR_get_error(), 0)); inhere = 0; - return; } x = -1; } diff --git a/src/proto.h b/src/proto.h index 5b834e884..f7a641e17 100644 --- a/src/proto.h +++ b/src/proto.h @@ -154,6 +154,7 @@ extern void (*sharein) (int, char *); void chanout_but(int x, int chan, const char *format, ...) ATTRIBUTE_FORMAT(printf,3,4); void dcc_chatter(int); void lostdcc(int); +void lostdcc_deferred(int); void killtransfer(int); void removedcc(int); void makepass(char *); diff --git a/src/tls.c b/src/tls.c index d36037207..e8d7429a7 100644 --- a/src/tls.c +++ b/src/tls.c @@ -136,7 +136,7 @@ static X509 *ssl_getcert(int sock) * Return value: ptr to the hexadecimal representation of the fingerprint or * NULL in case of error. */ -static char *ssl_getfp_from_cert(X509 *cert, const EVP_MD* type) +static char *ssl_getfp_from_cert(X509 *cert, const EVP_MD *type) { char *p; unsigned int i; @@ -178,6 +178,7 @@ char *ssl_getfp(int sock) return fp; } +// FIXME: Assumption is fingerprint stays the same if path doesn't change void verify_cert_expiry(int idx) { X509 *x509; static char last_tls_certfile[sizeof tls_certfile]; @@ -191,8 +192,9 @@ void verify_cert_expiry(int idx) { #endif if (x509) { if (strcmp(tls_certfile, last_tls_certfile)) { + const char *fp = ssl_getfp_from_cert(x509, EVP_sha256()); putlog(LOG_MISC, "*", "Certificate loaded: %s (sha256 fingerprint %s)", - tls_certfile, ssl_getfp_from_cert(x509, EVP_sha256())); + tls_certfile, fp ? fp : "(error getting fp)"); strlcpy(last_tls_certfile, tls_certfile, sizeof last_tls_certfile); } #if OPENSSL_VERSION_NUMBER >= 0x40000000L /* 4.0.0 */ @@ -942,8 +944,11 @@ static void ssl_info(const SSL *ssl, int where, int ret) debug2("TLS: Received close notify during %s sock %i", (where & SSL_CB_READ) ? "read" : "write", sock); if (where & SSL_CB_WRITE) { - int idx = findidx(sock); - lostdcc(idx); + int i = findsock(sock); + if (i >= 0 && (threaddata()->socklist[i].flags & SOCK_WEBUI)) { + int idx = findidx(sock); + lostdcc_deferred(idx); + } } } } else if (where & SSL_CB_EXIT) { @@ -1089,7 +1094,7 @@ int ssl_handshake(int sock, int flags, int verify, int loglevel, char *host, return 0; } if ((err = ERR_peek_error())) { - if ((td->socklist[i].flags &= SOCK_WEBUI) && + if ((td->socklist[i].flags & SOCK_WEBUI) && ERR_GET_LIB(ERR_peek_error()) == ERR_LIB_SSL && ERR_GET_REASON(err) == SSL_R_HTTP_REQUEST) { /* We dont have access to real port, host or dcc information here */ From 610eba3cc8725c3eef601da95723081a8d03fe28 Mon Sep 17 00:00:00 2001 From: Thomas Sader Date: Sat, 23 May 2026 19:46:39 +0200 Subject: [PATCH 20/20] Fix compiler warning --- src/modules.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules.c b/src/modules.c index 9509aa32e..00c7770e3 100644 --- a/src/modules.c +++ b/src/modules.c @@ -163,7 +163,7 @@ int (*rfc_tolower) (int) = _rfc_tolower; void (*dns_hostbyip) (sockname_t *) = core_dns_hostbyip; void (*dns_ipbyhost) (char *) = core_dns_ipbyhost; void (*webui_dcc_telnet_hostresolved) (int, int) = (void (*)(int, int)) null_func; -size_t (*webui_frame) (char **, char *, size_t) = (void (*)(char **, char * ,size_t)) null_func; +size_t (*webui_frame) (char **, char *, size_t) = (size_t (*)(char **, char * ,size_t)) null_func; void (*webui_unframe) (int, char *, int *) = (void (*)(int, char *, int *)) null_func; module_entry *module_list;