From fcb939e0752b73eaa49989a33868fb565301ad44 Mon Sep 17 00:00:00 2001 From: Aaron Sethman Date: Fri, 30 Jan 2026 11:22:35 -0500 Subject: [PATCH 01/18] Fix up rb_rawbuf_get's cpylen, nothing calls rb_rawbuf_get at this point --- libratbox/src/rawbuf.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/libratbox/src/rawbuf.c b/libratbox/src/rawbuf.c index 25f3859b..5edf8d97 100644 --- a/libratbox/src/rawbuf.c +++ b/libratbox/src/rawbuf.c @@ -226,18 +226,13 @@ rb_rawbuf_get(rb_rawbuf_head_t * rb, void *data, size_t len) else ptr = buf->data; - if(len > buf->len) - cpylen = buf->len; - else - cpylen = len; - - memcpy(data, ptr, cpylen); + cpylen = IRCD_MIN(len, buf->len); if(cpylen == buf->len) { rb->written = 0; rb_rawbuf_done(rb, buf); - rb->len -= len; + rb->len -= cpylen; return cpylen; } From a7d718d5178e821c2ddc32c51261cfc5e2439627 Mon Sep 17 00:00:00 2001 From: Aaron Sethman Date: Fri, 30 Jan 2026 11:43:04 -0500 Subject: [PATCH 02/18] Don't compile the rb_rawbuf_get code, its still buggy and nothing currently uses it --- libratbox/include/rb_rawbuf.h | 2 ++ libratbox/src/export-syms.txt | 1 - libratbox/src/rawbuf.c | 6 +++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/libratbox/include/rb_rawbuf.h b/libratbox/include/rb_rawbuf.h index 2586cc18..6b03a0a7 100644 --- a/libratbox/include/rb_rawbuf.h +++ b/libratbox/include/rb_rawbuf.h @@ -36,7 +36,9 @@ typedef struct _rb_rawbuf_head rb_rawbuf_head_t; void rb_init_rawbuffers(void); void rb_free_rawbuffer(rb_rawbuf_head_t *); rb_rawbuf_head_t *rb_new_rawbuffer(void); +#if 0 size_t rb_rawbuf_get(rb_rawbuf_head_t *, void *data, size_t len); +#endif void rb_rawbuf_append(rb_rawbuf_head_t *, void *data, size_t len); ssize_t rb_rawbuf_flush(rb_rawbuf_head_t *, rb_fde_t *F); size_t rb_rawbuf_length(rb_rawbuf_head_t * rb); diff --git a/libratbox/src/export-syms.txt b/libratbox/src/export-syms.txt index d669f2cb..6f4cdd42 100644 --- a/libratbox/src/export-syms.txt +++ b/libratbox/src/export-syms.txt @@ -104,7 +104,6 @@ rb_patricia_search_exact rb_pipe rb_rawbuf_append rb_rawbuf_flush -rb_rawbuf_get rb_rawbuf_length rb_read rb_recv_fd_buf diff --git a/libratbox/src/rawbuf.c b/libratbox/src/rawbuf.c index 5edf8d97..172334ca 100644 --- a/libratbox/src/rawbuf.c +++ b/libratbox/src/rawbuf.c @@ -209,7 +209,8 @@ rb_rawbuf_append(rb_rawbuf_head_t * rb, void *in, size_t len) } } - +#if 0 +/* this is still broken..if somebody wants to use it, they need to fix it */ size_t rb_rawbuf_get(rb_rawbuf_head_t * rb, void *data, size_t len) { @@ -228,6 +229,8 @@ rb_rawbuf_get(rb_rawbuf_head_t * rb, void *data, size_t len) cpylen = IRCD_MIN(len, buf->len); + memcpy(data, ptr, cpylen); + if(cpylen == buf->len) { rb->written = 0; @@ -242,6 +245,7 @@ rb_rawbuf_get(rb_rawbuf_head_t * rb, void *data, size_t len) rb->written += cpylen; return cpylen; } +#endif size_t rb_rawbuf_length(rb_rawbuf_head_t * rb) From 85fe3c6691da53c192b0ad591fe06f120fe8cfc4 Mon Sep 17 00:00:00 2001 From: Aaron Sethman Date: Fri, 30 Jan 2026 13:38:34 -0500 Subject: [PATCH 03/18] Track rawbuf buffer stage in the individual buffer rather than the buffer head. This is a legacy from its origin in linebuf.c where the buffers could be refcounted. That doesn't make any sense here for rawbufs. Also change the rawbuf allocation code to malloc the buffer head and then do a straight malloc/copy of the input buffer rather than trying to block it out. The only caller of rb_rawbuf_append() is ssld.c and it usually feeds it nice sized blocks anyways. --- libratbox/src/rawbuf.c | 73 +++++++++++++++--------------------------- 1 file changed, 26 insertions(+), 47 deletions(-) diff --git a/libratbox/src/rawbuf.c b/libratbox/src/rawbuf.c index 172334ca..8157777e 100644 --- a/libratbox/src/rawbuf.c +++ b/libratbox/src/rawbuf.c @@ -28,8 +28,9 @@ struct _rb_rawbuf { rb_dlink_node node; - uint8_t data[RAWBUF_SIZE]; + void *data; size_t len; + size_t written; bool flushing; }; @@ -37,7 +38,6 @@ struct _rb_rawbuf_head { rb_dlink_list list; size_t len; - size_t written; }; @@ -55,6 +55,9 @@ static void rb_rawbuf_done(rb_rawbuf_head_t * rb, rb_rawbuf_t * buf) { rb_rawbuf_t *ptr = buf; + if(buf->data != NULL) + rb_free(buf->data); + rb_dlinkDelete(&buf->node, &rb->list); rb_free(ptr); } @@ -83,8 +86,8 @@ rb_rawbuf_flush_writev(rb_rawbuf_head_t * rb, rb_fde_t *F) buf = ptr->data; if(buf->flushing == true) { - vec[x].iov_base = buf->data + rb->written; - vec[x++].iov_len = buf->len - rb->written; + vec[x].iov_base = buf->data + buf->written; + vec[x++].iov_len = buf->len - buf->written; continue; } vec[x].iov_base = buf->data; @@ -108,10 +111,10 @@ rb_rawbuf_flush_writev(rb_rawbuf_head_t * rb, rb_fde_t *F) break; if(buf->flushing == true) { - if(xret >= (ssize_t)(buf->len - rb->written)) + if(xret >= (ssize_t)(buf->len - buf->written)) { - xret -= buf->len - rb->written; - rb->len -= buf->len - rb->written; + xret -= buf->len - buf->written; + rb->len -= buf->len - buf->written; rb_rawbuf_done(rb, buf); continue; } @@ -126,7 +129,7 @@ rb_rawbuf_flush_writev(rb_rawbuf_head_t * rb, rb_fde_t *F) else { buf->flushing = true; - rb->written = (size_t)xret; + buf->written = (size_t)xret; rb->len -= (size_t)xret; break; } @@ -140,6 +143,7 @@ rb_rawbuf_flush(rb_rawbuf_head_t * rb, rb_fde_t *F) { rb_rawbuf_t *buf; ssize_t retval; + if(rb->list.head == NULL) { errno = EAGAIN; @@ -153,19 +157,17 @@ rb_rawbuf_flush(rb_rawbuf_head_t * rb, rb_fde_t *F) if(buf->flushing == false) { buf->flushing = true; - rb->written = 0; + buf->written = 0; } - retval = rb_write(F, buf->data + rb->written, buf->len - rb->written); + retval = rb_write(F, buf->data + buf->written, buf->len - buf->written); if(retval <= 0) return retval; - rb->written += (size_t)retval; - if(rb->written == buf->len) + buf->written += (size_t)retval; + if(buf->written == buf->len) { - rb->written = 0; - rb_dlinkDelete(&buf->node, &rb->list); - rb_free(buf); + rb_rawbuf_done(rb, buf); } rb->len -= (size_t)retval; return retval; @@ -178,35 +180,12 @@ rb_rawbuf_flush(rb_rawbuf_head_t * rb, rb_fde_t *F) void rb_rawbuf_append(rb_rawbuf_head_t * rb, void *in, size_t len) { - rb_rawbuf_t *buf = NULL; - size_t clen; - void *ptr; - uint8_t *data = in; - - if(rb->list.tail != NULL) - buf = rb->list.tail->data; - - if(buf != NULL && buf->len < sizeof(buf->data) && buf->flushing == false) - { - ptr = (void *)((uintptr_t)buf->data + buf->len); - clen = IRCD_MIN((sizeof(buf->data) - buf->len), len); - memcpy(ptr, data, clen); - buf->len += clen; - rb->len += clen; - len -= clen; - data = (data + clen); - } - - while(len > 0) - { - buf = rb_rawbuf_newbuf(rb); - clen = IRCD_MIN(sizeof(buf->data), len); - memcpy(buf->data, data, clen); - buf->len += clen; - rb->len += clen; - len -= clen; - data = (data + clen); - } + rb_rawbuf_t *buf; + buf = rb_rawbuf_newbuf(rb); + buf->data = rb_malloc(len); + buf->len = len; + memcpy(buf->data, in, len); + rb->len += buf->len; } #if 0 @@ -223,7 +202,7 @@ rb_rawbuf_get(rb_rawbuf_head_t * rb, void *data, size_t len) buf = rb->list.head->data; if(buf->flushing == true) - ptr = (void *)(buf->data + rb->written); + ptr = (void *)(buf->data + buf->written); else ptr = buf->data; @@ -233,7 +212,7 @@ rb_rawbuf_get(rb_rawbuf_head_t * rb, void *data, size_t len) if(cpylen == buf->len) { - rb->written = 0; + buf->written = 0; rb_rawbuf_done(rb, buf); rb->len -= cpylen; return cpylen; @@ -242,7 +221,7 @@ rb_rawbuf_get(rb_rawbuf_head_t * rb, void *data, size_t len) buf->flushing = true; buf->len -= cpylen; rb->len -= cpylen; - rb->written += cpylen; + buf->written += cpylen; return cpylen; } #endif From 99853959b178b2adeb649d14a73e78b67920212c Mon Sep 17 00:00:00 2001 From: Aaron Sethman Date: Fri, 30 Jan 2026 15:04:28 -0500 Subject: [PATCH 04/18] validate that ssld has been passed a unix socket and fifo for control --- ssld/ssld.c | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/ssld/ssld.c b/ssld/ssld.c index 7d826c6d..37144619 100644 --- a/ssld/ssld.c +++ b/ssld/ssld.c @@ -1236,11 +1236,53 @@ read_pipe_ctl(rb_fde_t *F, void *data) rb_setselect(F, RB_SELECT_READ, read_pipe_ctl, NULL); } +static void +check_control(int control_fd) +{ + struct sockaddr_in addr; + socklen_t len; + + if(control_fd < 0) + { + fprintf(stderr, "No control socket\n"); + exit(1); + } + + len = sizeof(addr); + if(getsockname(control_fd, (struct sockaddr *)&addr, &len) == -1) + { + fprintf(stderr, "Control descriptor is not a socket!\n"); + exit(1); + } + if(addr.sin_family != AF_UNIX) + { + fprintf(stderr, "Control descriptor is not a unix socket!\n"); + exit(1); + } +} + +static void +check_pipe(int pipefd) +{ + struct stat st; + + if(fstat(pipefd, &st) < 0) + { + fprintf(stderr, "No control pipe\n"); + exit(1); + } + if(!S_ISFIFO(st.st_mode)) + { + fprintf(stderr, "Control pipe is not a pipe\n"); + exit(1); + } +} + int main(int argc, char **argv) { const char *s_ctlfd, *s_pipe, *s_pid; - int ctlfd, pipefd, maxfd; + int ctlfd, pipefd, maxfd, x; mod_ctl_t *mod_ctl; maxfd = maxconn(); @@ -1260,7 +1302,8 @@ main(int argc, char **argv) pipefd = atoi(s_pipe); ppid = atoi(s_pid); - int x; + check_pipe(pipefd); + check_control(ctlfd); for(x = 0; x < maxfd; x++) { From e2880f841a922b44d996683b333dfd4d00307e37 Mon Sep 17 00:00:00 2001 From: Aaron Sethman Date: Fri, 30 Jan 2026 17:54:12 -0500 Subject: [PATCH 05/18] Get the timestamp of ConfigFileEntry.motd_path and not the hard coded MPATH, also check if motd_path and oper_motd_path are null or not --- src/cache.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/cache.c b/src/cache.c index fd98d1c9..cacf242a 100644 --- a/src/cache.c +++ b/src/cache.c @@ -347,7 +347,10 @@ cache_user_motd(void) struct stat sb; struct tm *local_tm; - if(stat(MPATH, &sb) == 0) + if(ConfigFileEntry.motd_path == NULL) + return; + + if(stat(ConfigFileEntry.motd_path, &sb) == 0) { local_tm = gmtime(&sb.st_mtime); @@ -367,6 +370,8 @@ cache_user_motd(void) void cache_oper_motd(void) { + if(ConfigFileEntry.oper_motd_path == NULL) + return; free_cachefile(oper_motd); oper_motd = cache_file(ConfigFileEntry.oper_motd_path, "oper.motd", 0); } From 21dddd5ec632fab5c3713a92fc66e21c257781a3 Mon Sep 17 00:00:00 2001 From: Aaron Sethman Date: Fri, 30 Jan 2026 18:21:53 -0500 Subject: [PATCH 06/18] Don't leak memory from posix_spawnattr_init...call posix_spawnattr_destroy. not a major memory leak --- libratbox/src/unix.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/libratbox/src/unix.c b/libratbox/src/unix.c index 840fa2ea..7e84616a 100644 --- a/libratbox/src/unix.c +++ b/libratbox/src/unix.c @@ -41,6 +41,7 @@ extern char **environ; pid_t rb_spawn_process(const char *path, const char **argv) { + int ret; pid_t pid; const void *arghack = argv; char **myenviron; @@ -54,11 +55,13 @@ rb_spawn_process(const char *path, const char **argv) #else myenviron = environ; #endif - if(posix_spawn(&pid, path, NULL, &spattr, arghack, myenviron)) - { + ret = posix_spawn(&pid, path, NULL, &spattr, arghack, myenviron); + posix_spawnattr_destroy(&spattr); + + if(ret) return -1; - } - return pid; + else + return pid; } #else pid_t From 11f467278803fff59b0ec3f841e69d7c3b59c06f Mon Sep 17 00:00:00 2001 From: Aaron Sethman Date: Fri, 30 Jan 2026 18:22:29 -0500 Subject: [PATCH 07/18] Add support for settings minimum tls version of 1.3 --- libratbox/include/rb_commio.h | 1 + libratbox/src/openssl.c | 11 +++++++++++ src/newconf.c | 1 + 3 files changed, 13 insertions(+) diff --git a/libratbox/include/rb_commio.h b/libratbox/include/rb_commio.h index 870c6bc2..79f60f47 100644 --- a/libratbox/include/rb_commio.h +++ b/libratbox/include/rb_commio.h @@ -68,6 +68,7 @@ typedef enum _rb_tls_ver RB_TLS_VER_TLS1, RB_TLS_VER_TLS1_1, RB_TLS_VER_TLS1_2, + RB_TLS_VER_TLS1_3, RB_TLS_VER_LAST, } rb_tls_ver_t; diff --git a/libratbox/src/openssl.c b/libratbox/src/openssl.c index 49cb51f5..22d22cd9 100644 --- a/libratbox/src/openssl.c +++ b/libratbox/src/openssl.c @@ -492,6 +492,17 @@ rb_setup_ssl_server(const char *cacert, const char *cert, const char *keyfile, c #endif #ifdef SSL_OP_NO_TLSv1_1 tls_opts |= SSL_OP_NO_TLSv1_1; +#endif + break; + case RB_TLS_VER_TLS1_3: +#ifdef SSL_OP_NO_TLSv1 + tls_opts |= SSL_OP_NO_TLSv1; +#endif +#ifdef SSL_OP_NO_TLSv1_1 + tls_opts |= SSL_OP_NO_TLSv1_1; +#endif +#ifdef SSL_OP_NO_TLSv1_2 + tls_opts |= SSL_OP_NO_TLSv1_2; #endif break; case RB_TLS_VER_LAST: diff --git a/src/newconf.c b/src/newconf.c index 3df529f8..ce7c527d 100644 --- a/src/newconf.c +++ b/src/newconf.c @@ -1117,6 +1117,7 @@ static const char *ver_table[] = { [RB_TLS_VER_TLS1] = "tls1.0", [RB_TLS_VER_TLS1_1] = "tls1.1", [RB_TLS_VER_TLS1_2] = "tls1.2", + [RB_TLS_VER_TLS1_3] = "tls1.3", [RB_TLS_VER_LAST] = NULL, }; From b13ee04e2f378d5f16a3c07fec3a1e9abad2df31 Mon Sep 17 00:00:00 2001 From: Aaron Sethman Date: Fri, 30 Jan 2026 18:42:25 -0500 Subject: [PATCH 08/18] rb_ssl_accept_common and rb_ssl_tryaccept were effectively the same code, remove rb_ssl_accept_common and use rb_ssl_tryaccept. No harm in calling SSL_is_init_finished() before we've called SSL_accept() --- libratbox/src/openssl.c | 34 ++-------------------------------- 1 file changed, 2 insertions(+), 32 deletions(-) diff --git a/libratbox/src/openssl.c b/libratbox/src/openssl.c index 22d22cd9..3bb5643e 100644 --- a/libratbox/src/openssl.c +++ b/libratbox/src/openssl.c @@ -195,36 +195,6 @@ rb_ssl_tryaccept(rb_fde_t *F, void *data) } -static void -rb_ssl_accept_common(rb_fde_t *new_F) -{ - int ssl_err; - if((ssl_err = SSL_accept((SSL *) new_F->ssl)) <= 0) - { - switch (ssl_err = SSL_get_error((SSL *) new_F->ssl, ssl_err)) - { - case SSL_ERROR_SYSCALL: - if(rb_ignore_errno(errno)) - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: - { - new_F->sslerr.ssl_errno = get_last_err(); - rb_setselect(new_F, RB_SELECT_READ | RB_SELECT_WRITE, - rb_ssl_tryaccept, NULL); - return; - } - default: - new_F->sslerr.ssl_errno = get_last_err(); - new_F->accept->callback(new_F, RB_ERROR_SSL, NULL, 0, new_F->accept->data); - return; - } - } - else - { - rb_ssl_tryaccept(new_F, NULL); - } -} - void rb_ssl_start_accepted(rb_fde_t *new_F, ACCB * cb, void *data, int timeout) { @@ -250,7 +220,7 @@ rb_ssl_start_accepted(rb_fde_t *new_F, ACCB * cb, void *data, int timeout) new_F->accept->addrlen = 0; SSL_set_fd((SSL *) new_F->ssl, rb_get_fd(new_F)); rb_setup_ssl_cb(new_F); - rb_ssl_accept_common(new_F); + rb_ssl_tryaccept(new_F, NULL); } @@ -285,7 +255,7 @@ rb_ssl_accept_setup(rb_fde_t *F, rb_fde_t *new_F, struct sockaddr *st, rb_sockle SSL_set_fd((SSL *) new_F->ssl, rb_get_fd(new_F)); rb_setup_ssl_cb(new_F); - rb_ssl_accept_common(new_F); + rb_ssl_tryaccept(new_F, NULL); } typedef enum { From 4d8532b7d5f0f9bdb4355e495f74d32070f40a7d Mon Sep 17 00:00:00 2001 From: Aaron Sethman Date: Mon, 2 Feb 2026 13:05:56 -0500 Subject: [PATCH 09/18] Remove a few alloca calls --- resolver/res.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/resolver/res.c b/resolver/res.c index 4acfadfc..c4bde9e1 100644 --- a/resolver/res.c +++ b/resolver/res.c @@ -588,13 +588,13 @@ do_query_number(struct DNSQuery *query, const struct rb_sockaddr_storage *addr, static void query_name(struct reslist *request) { - void *buf = alloca(MAXPACKET); + char buf[MAXPACKET]; int request_len = 0; - memset(buf, 0, MAXPACKET); + memset(buf, 0, sizeof(buf)); if((request_len = - irc_res_mkquery(request->queryname, C_IN, request->type, buf, MAXPACKET)) > 0) + irc_res_mkquery(request->queryname, C_IN, request->type, buf, sizeof(buf))) > 0) { HEADER *header = (HEADER *) buf; /* @@ -799,8 +799,7 @@ proc_answer(struct reslist *request, HEADER * header, char *buf, char *eob) static int res_read_single_reply(rb_fde_t *F, void *data) { - int buflen = sizeof(HEADER) + MAXPACKET; - void *buf = alloca(buflen); + char buf[sizeof(HEADER) + MAXPACKET]; HEADER *header; struct reslist *request = NULL; @@ -810,7 +809,7 @@ res_read_single_reply(rb_fde_t *F, void *data) rb_socklen_t len = sizeof(struct rb_sockaddr_storage); struct rb_sockaddr_storage lsin; - rc = recvfrom(rb_get_fd(F), buf, buflen, 0, (struct sockaddr *)&lsin, &len); + rc = recvfrom(rb_get_fd(F), buf, sizeof(buf), 0, (struct sockaddr *)&lsin, &len); /* No packet */ if(rc == 0 || rc == -1) From 93a743943183a93f7fbec1b7137ebbd66a58eaf5 Mon Sep 17 00:00:00 2001 From: Aaron Sethman Date: Mon, 2 Feb 2026 14:19:01 -0500 Subject: [PATCH 10/18] truncate the correct string if we have comma in do_whois --- modules/m_whois.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/m_whois.c b/modules/m_whois.c index 1f6a0769..1aa718e5 100644 --- a/modules/m_whois.c +++ b/modules/m_whois.c @@ -182,7 +182,7 @@ do_whois(struct Client *client_p, struct Client *source_p, int parc, const char int operspy = 0; nick = LOCAL_COPY(parv[1]); - if((p = strchr(parv[1], ','))) + if((p = strchr(nick, ','))) *p = '\0'; if(IsOperSpy(source_p) && *nick == '!') From 3d094c37e2b75c72125664562b750aeb909c7277 Mon Sep 17 00:00:00 2001 From: Aaron Sethman Date: Mon, 2 Feb 2026 14:21:16 -0500 Subject: [PATCH 11/18] unconditionally use our own LOCAL_COPY implementation based on glibc strdupa/strndupa. Don't compile unless we have something suitable otherwise --- include/stdinc.h | 57 +++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/include/stdinc.h b/include/stdinc.h index 5d410122..6bf8f132 100644 --- a/include/stdinc.h +++ b/include/stdinc.h @@ -164,40 +164,37 @@ extern int errno; #endif - -#ifdef strdupa -#define LOCAL_COPY(s) strdupa(s) -#else -#if defined(__INTEL_COMPILER) || defined(__GNUC__) -# define LOCAL_COPY(s) __extension__({ char *_s = alloca(strlen(s) + 1); strcpy(_s, s); _s; }) +/* unconditionally use our own strdupa/strndupa. + * if you use a compiler other than these, fix it yourself + * these macros were lifted from glibc + */ +#if defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__clang__) +#define LOCAL_COPY(s) \ + (__extension__ \ + ({ \ + const char *__old = (s); \ + size_t __len = strlen (__old) + 1; \ + char *__new = (char *) __builtin_alloca (__len); \ + (char *) memcpy (__new, __old, __len); \ + })) #else -# define LOCAL_COPY(s) strcpy(alloca(strlen(s) + 1), s) /* XXX Is that allowed? */ -#endif /* defined(__INTEL_COMPILER) || defined(__GNUC__) */ -#endif /* strdupa */ +#error "does your compiler support strdup/alloca?" +#endif /* defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__clang__) */ /* LOCAL_COPY_N copies n part of string and adds one to terminate the string */ -#ifdef strndupa -#define LOCAL_COPY_N(s, n) strndupa(s, n) -#else -#if defined(__INTEL_COMPILER) || defined(__GNUC__) -#define LOCAL_COPY_N(s, n) __extension__({ size_t _l = strlen(s); _l = n > _l ? _l : n; char *_s = alloca(_l+1); memcpy(_s, s, _l); _s[_l] = '\0' ; _s; }) +#if defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__clang__) +# define LOCAL_COPY_N(s, n) \ + (__extension__ \ + ({ \ + const char *__old = (s); \ + size_t __len = strnlen (__old, (n)); \ + char *__new = (char *) __builtin_alloca (__len + 1); \ + __new[__len] = '\0'; \ + (char *) memcpy (__new, __old, __len); \ + })) #else -#define LOCAL_COPY_N(s, n) xc_strlcpy(alloca(strlen(s)+1), s, n) -INLINE_FUNC size_t -xc_strlcpy(char *dest, const char *src, size_t size) -{ - size_t ret = strlen(src); - - if(size) - { - size_t len = (ret >= size) ? size - 1 : ret; - memcpy(dest, src, len); - dest[len] = '\0'; - } - return dest; -} -#endif /* defined(__INTEL_COMPILER) || defined(__GNUC__) */ -#endif /* strndupa */ +#error "does your compiler support strndup/alloca?" +#endif /* defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__clang__) */ #ifndef INADDR_NONE # define INADDR_NONE ((in_addr_t) 0xffffffff) From 685b83dc529fdaa7ffcc9eadf8f94f695e14124e Mon Sep 17 00:00:00 2001 From: Aaron Sethman Date: Mon, 2 Feb 2026 14:39:39 -0500 Subject: [PATCH 12/18] Pass the buffer sizes down through find_user_host rather than assuming their size. no change otherwise --- modules/m_kline.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/m_kline.c b/modules/m_kline.c index c284216e..81edbe57 100644 --- a/modules/m_kline.c +++ b/modules/m_kline.c @@ -81,7 +81,7 @@ mapi_clist_av1 kline_clist[] = { &kline_msgtab, &unkline_msgtab, &adminkline_msg DECLARE_MODULE_AV1(kline, NULL, NULL, kline_clist, NULL, NULL, "$Revision$"); /* Local function prototypes */ -static int find_user_host(struct Client *source_p, const char *userhost, char *user, char *host); +static int find_user_host(struct Client *source_p, const char *userhost, char *user, size_t usersz, char *host, size_t hostsz); static int valid_user_host(struct Client *source_p, const char *user, const char *host); static int valid_wild_card(struct Client *source_p, const char *user, const char *host); @@ -127,7 +127,7 @@ mo_kline(struct Client *client_p, struct Client *source_p, int parc, const char else tkline_time = 0; - if(find_user_host(source_p, parv[loc], user, host) == 0) + if(find_user_host(source_p, parv[loc], user, sizeof(user), host, sizeof(host)) == 0) return 0; loc++; @@ -216,7 +216,7 @@ mo_adminkline(struct Client *client_p, struct Client *source_p, int parc, const return 0; } - if(find_user_host(source_p, parv[1], user, host) == 0) + if(find_user_host(source_p, parv[1], user, sizeof(user), host, sizeof(host)) == 0) return 0; set_kline(source_p, user, host, parv[2], 0, 1); @@ -523,7 +523,7 @@ mangle_wildcard_to_cidr(const char *text) * side effects - */ static int -find_user_host(struct Client *source_p, const char *userhost, char *luser, char *lhost) +find_user_host(struct Client *source_p, const char *userhost, char *luser, size_t lusersz, char *lhost, size_t lhostsz) { char *hostp; const char *ptr; @@ -534,7 +534,7 @@ find_user_host(struct Client *source_p, const char *userhost, char *luser, char { *(hostp++) = '\0'; /* short and squat */ if(*userhost) - rb_strlcpy(luser, userhost, USERLEN + 1); /* here is my user */ + rb_strlcpy(luser, userhost, lusersz); /* here is my user */ else strcpy(luser, "*"); if(*hostp) @@ -542,7 +542,7 @@ find_user_host(struct Client *source_p, const char *userhost, char *luser, char ptr = mangle_wildcard_to_cidr(hostp); if(ptr == NULL) ptr = hostp; - rb_strlcpy(lhost, ptr, HOSTLEN + 1); /* here is my host */ + rb_strlcpy(lhost, ptr, lhostsz); /* here is my host */ } else strcpy(lhost, "*"); @@ -565,7 +565,7 @@ find_user_host(struct Client *source_p, const char *userhost, char *luser, char if(ptr == NULL) ptr = userhost; - rb_strlcpy(lhost, ptr, HOSTLEN + 1); + rb_strlcpy(lhost, ptr, lhostsz); } return 1; From 25e860ff703595fed53551cef460d7e3d33f8f3f Mon Sep 17 00:00:00 2001 From: Aaron Sethman Date: Mon, 2 Feb 2026 15:03:55 -0500 Subject: [PATCH 13/18] strchr breaks const char by casting a pointer from a string to a non-const pointer, copy the string first --- modules/m_kline.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/m_kline.c b/modules/m_kline.c index 81edbe57..dbfbf615 100644 --- a/modules/m_kline.c +++ b/modules/m_kline.c @@ -523,10 +523,11 @@ mangle_wildcard_to_cidr(const char *text) * side effects - */ static int -find_user_host(struct Client *source_p, const char *userhost, char *luser, size_t lusersz, char *lhost, size_t lhostsz) +find_user_host(struct Client *source_p, const char *uh, char *luser, size_t lusersz, char *lhost, size_t lhostsz) { char *hostp; const char *ptr; + char *userhost = LOCAL_COPY(uh); hostp = strchr(userhost, '@'); @@ -536,7 +537,7 @@ find_user_host(struct Client *source_p, const char *userhost, char *luser, size_ if(*userhost) rb_strlcpy(luser, userhost, lusersz); /* here is my user */ else - strcpy(luser, "*"); + rb_strlcpy(luser, "*", lusersz); if(*hostp) { ptr = mangle_wildcard_to_cidr(hostp); @@ -545,7 +546,7 @@ find_user_host(struct Client *source_p, const char *userhost, char *luser, size_ rb_strlcpy(lhost, ptr, lhostsz); /* here is my host */ } else - strcpy(lhost, "*"); + rb_strlcpy(lhost, "*", lhostsz); } else { @@ -558,8 +559,7 @@ find_user_host(struct Client *source_p, const char *userhost, char *luser, size_ return 0; } - luser[0] = '*'; /* no @ found, assume its *@somehost */ - luser[1] = '\0'; + rb_strlcpy(luser, "*", lusersz); /* no @ found, assume its *@somehost */ ptr = mangle_wildcard_to_cidr(userhost); if(ptr == NULL) From 877a07f72b081aa16ad04d775ec98c964820f91a Mon Sep 17 00:00:00 2001 From: Aaron Sethman Date: Mon, 2 Feb 2026 15:09:30 -0500 Subject: [PATCH 14/18] Split nick on a local copy and use said local copy throughout consistently in whowas, mirroring whois --- modules/m_whowas.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/modules/m_whowas.c b/modules/m_whowas.c index ff533e7b..55c5d6ae 100644 --- a/modules/m_whowas.c +++ b/modules/m_whowas.c @@ -90,18 +90,16 @@ m_whowas(struct Client *client_p, struct Client *source_p, int parc, const char return 0; #endif - if((p = strchr(parv[1], ','))) + nick = LOCAL_COPY(parv[1]); + if((p = strchr(nick, ','))) *p = '\0'; - nick = parv[1]; - - whowas_list = whowas_get_list(nick); if(whowas_list == NULL) { sendto_one_numeric(source_p, s_RPL(ERR_WASNOSUCHNICK), nick); - sendto_one_numeric(source_p, s_RPL(RPL_ENDOFWHOWAS), parv[1]); + sendto_one_numeric(source_p, s_RPL(RPL_ENDOFWHOWAS), nick); return 0; } @@ -130,6 +128,6 @@ m_whowas(struct Client *client_p, struct Client *source_p, int parc, const char if(max > 0 && cur >= max) break; } - sendto_one_numeric(source_p, s_RPL(RPL_ENDOFWHOWAS), parv[1]); + sendto_one_numeric(source_p, s_RPL(RPL_ENDOFWHOWAS), nick); return 0; } From c04fdc4dcb4a5e9adf7bed4be17cf60bfd425720 Mon Sep 17 00:00:00 2001 From: Aaron Sethman Date: Mon, 2 Feb 2026 19:10:17 -0500 Subject: [PATCH 15/18] close on exec for openssl and gnutls opens --- libratbox/src/gnutls.c | 2 +- libratbox/src/openssl.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index afd7a80d..51c99617 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -292,7 +292,7 @@ rb_load_file_into_datum_t(const char *file) FILE *f; gnutls_datum_t *datum; struct stat fileinfo; - if((f = fopen(file, "r")) == NULL) + if((f = fopen(file, "re")) == NULL) return NULL; if(fstat(fileno(f), &fileinfo)) return NULL; diff --git a/libratbox/src/openssl.c b/libratbox/src/openssl.c index 3bb5643e..d44f7d5b 100644 --- a/libratbox/src/openssl.c +++ b/libratbox/src/openssl.c @@ -539,7 +539,7 @@ rb_setup_ssl_server(const char *cacert, const char *cert, const char *keyfile, c if(dhfile != NULL) { /* DH parameters aren't necessary, but they are nice..if they didn't pass one..that is their problem */ - BIO *bio = BIO_new_file(dhfile, "r"); + BIO *bio = BIO_new_file(dhfile, "re"); if(bio != NULL) { DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); From a253791a4ed4283d174f458f8b87b73668eddae8 Mon Sep 17 00:00:00 2001 From: Aaron Sethman Date: Tue, 3 Feb 2026 07:25:19 -0500 Subject: [PATCH 16/18] It's possible for the callback to free the request, so stash the values and clear them before calling the callback, not after. --- src/dns.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/dns.c b/src/dns.c index 8c47d539..0331d81e 100644 --- a/src/dns.c +++ b/src/dns.c @@ -156,6 +156,8 @@ lookup_ip(const char *addr, int aftype, DNSCB * callback, void *data) static void results_callback(const char *callid, const char *status, const char *aftype, const char *results) { + DNSCB *cb; + void *data; struct dnsreq *req; uint16_t nid; int st; @@ -181,9 +183,11 @@ results_callback(const char *callid, const char *status, const char *aftype, con #endif aft = AF_INET; - req->callback(results, st, aft, req->data); + cb = req->callback; + data = req->data; req->callback = NULL; req->data = NULL; + cb(results, st, aft, data); } From a9669679831e163f045b3c92de00fe4e1631bf5f Mon Sep 17 00:00:00 2001 From: Aaron Sethman Date: Tue, 3 Feb 2026 07:26:21 -0500 Subject: [PATCH 17/18] calculate the hashlen correctlyn --- src/hash.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/hash.c b/src/hash.c index ca057908..f17f34b3 100644 --- a/src/hash.c +++ b/src/hash.c @@ -422,13 +422,19 @@ hash_node * hash_add_len(hash_f *hf, const void *hashindex, size_t indexlen, void *pointer) { rb_dlink_list *bucket; // = hash_function[type].table; + size_t hashlen; hash_node *hnode; uint32_t hashv; if(hf == NULL || hashindex == NULL || pointer == NULL) return NULL; - hashv = do_hfunc(hf, hashindex, IRCD_MIN(indexlen, hf->hashlen)); + if(hf->hashlen == 0) + hashlen = indexlen; + else + hashlen = IRCD_MIN(indexlen, hf->hashlen); + + hashv = do_hfunc(hf, hashindex, hashlen); bucket = hash_allocate_bucket(hf, hashv); hnode = rb_malloc(sizeof(hash_node)); hnode->key = rb_malloc(indexlen); From f7c6c3edb530b98e82fe360fb72002bac990561d Mon Sep 17 00:00:00 2001 From: Aaron Sethman Date: Tue, 3 Feb 2026 12:05:04 -0500 Subject: [PATCH 18/18] Make the resolver IDs be a 32bit counter and the generated ID. The concern is that we could have enough RBL requests in flight that the smaller counter we were using could wrap under high load --- include/dns.h | 6 +- include/s_newconf.h | 2 +- src/dns.c | 168 +++++++++++++++++++++++++++----------------- src/s_auth.c | 2 +- 4 files changed, 107 insertions(+), 71 deletions(-) diff --git a/include/dns.h b/include/dns.h index ba501e0a..23a88f51 100644 --- a/include/dns.h +++ b/include/dns.h @@ -30,9 +30,9 @@ typedef void DNSCB(const char *res, int status, int aftype, void *data); void init_resolver(void); void restart_resolver(void); void rehash_resolver(void); -uint16_t __rb_must_check lookup_hostname(const char *hostname, int aftype, DNSCB * callback, void *data); -uint16_t __rb_must_check lookup_ip(const char *hostname, int aftype, DNSCB * callback, void *data); -void cancel_lookup(uint16_t xid); +uint32_t __rb_must_check lookup_hostname(const char *hostname, int aftype, DNSCB * callback, void *data); +uint32_t __rb_must_check lookup_ip(const char *hostname, int aftype, DNSCB * callback, void *data); +void cancel_lookup(uint32_t xid); void report_dns_servers(struct Client *); void rehash_dns_vhost(void); diff --git a/include/s_newconf.h b/include/s_newconf.h index 9e24d931..590e68e4 100644 --- a/include/s_newconf.h +++ b/include/s_newconf.h @@ -200,7 +200,7 @@ struct server_conf int flags; int servers; - uint16_t dns_query; + uint32_t dns_query; }; #define SERVER_ILLEGAL 0x0001 diff --git a/src/dns.c b/src/dns.c index 0331d81e..b018ab36 100644 --- a/src/dns.c +++ b/src/dns.c @@ -32,12 +32,11 @@ #include "send.h" #include "numeric.h" -#define DNS_IDTABLE_SIZE 0x2000 #define DNS_HOST ((char)'H') #define DNS_REVERSE ((char)'I') -static void submit_dns(const char, uint16_t id, int aftype, const char *addr); +static void submit_dns(const char, uint32_t id, int aftype, const char *addr); static int start_resolver(void); static void parse_dns_reply(rb_helper * helper); static void restart_resolver_cb(rb_helper * helper); @@ -46,31 +45,68 @@ static rb_helper *dns_helper; struct dnsreq { + rb_dlink_node node; DNSCB *callback; void *data; + uint32_t id; + uint32_t hashv; }; -static struct dnsreq querytable[DNS_IDTABLE_SIZE]; -static uint16_t -assign_dns_id(void) +#define RB_DNS_HASH_BITS 12 +#define RB_DNS_HASH_SIZE (1UL << RB_DNS_HASH_BITS) +#define RB_DNS_HASH_MASK (RB_DNS_HASH_SIZE-1) + + +#define rb_hash_dns(x) (((unsigned long)x ^ ((unsigned long)x >> RB_DNS_HASH_BITS) ^ ((unsigned long)x >> (RB_DNS_HASH_BITS * 2))) & RB_DNS_HASH_MASK) + + +static rb_dlink_list query_hash[RB_DNS_HASH_SIZE]; + + +static __rb_must_check struct dnsreq * +get_request_from_id(uint32_t id) { - static uint16_t id = 1; - int loopcnt = 0; - while(1) - { - if(++loopcnt > DNS_IDTABLE_SIZE) - return 0; - if(id < DNS_IDTABLE_SIZE - 1 || id == 0) - id++; - else - id = 1; - if(querytable[id].callback == NULL) - break; - } - return (id); + struct dnsreq *req; + rb_dlink_list *hlist; + rb_dlink_node *ptr; + + hlist = &query_hash[rb_hash_dns(id)]; + + if(hlist->head == NULL) + return NULL; + + RB_DLINK_FOREACH(ptr, hlist->head) + { + req = ptr->data; + if(req->id == id) + return req; + } + return NULL; +} + + + +static struct dnsreq * +allocate_dns_request(DNSCB *cb, void *data) +{ + struct dnsreq *req; + static uint32_t id = 0; + + id++; + if(id == 0) + id++; + + req = rb_malloc(sizeof(struct dnsreq)); + req->id = id; + req->hashv = rb_hash_dns(id); + req->callback = cb; + req->data = data; + rb_dlinkAdd(req, &req->node, &query_hash[req->hashv]); + return req; } + static inline void check_resolver(void) { @@ -79,41 +115,49 @@ check_resolver(void) } static void -failed_resolver(uint16_t xid) +failed_resolver(uint32_t xid) { struct dnsreq *req; + DNSCB *cb; + void *data; + uint32_t hashv; + + req = get_request_from_id(xid); - req = &querytable[xid]; - if(req->callback == NULL) + if(req == NULL) return; - req->callback("FAILED", 0, 0, req->data); - req->callback = NULL; - req->data = NULL; + cb = req->callback; + data = req->data; + hashv = req->hashv; + + rb_dlinkDelete(&req->node, &query_hash[hashv]); + rb_free(req); + + if(cb != NULL) + cb("FAILED", 0, 0, data); + } void -cancel_lookup(uint16_t xid) +cancel_lookup(uint32_t xid) { - querytable[xid].callback = NULL; - querytable[xid].data = NULL; + struct dnsreq *req; + req = get_request_from_id(xid); + if(req == NULL) + return; + rb_dlinkDelete(&req->node, &query_hash[req->hashv]); + rb_free(req); } -uint16_t +uint32_t lookup_hostname(const char *hostname, int aftype, DNSCB * callback, void *data) { struct dnsreq *req; int aft; - uint16_t nid; check_resolver(); - if((nid = assign_dns_id()) == 0) - return 0; - - req = &querytable[nid]; - - req->callback = callback; - req->data = data; + req = allocate_dns_request(callback, data); #ifdef RB_IPV6 if(aftype == AF_INET6) @@ -122,25 +166,18 @@ lookup_hostname(const char *hostname, int aftype, DNSCB * callback, void *data) #endif aft = 4; - submit_dns(DNS_HOST, nid, aft, hostname); - return (nid); + submit_dns(DNS_HOST, req->id, aft, hostname); + return (req->id); } -uint16_t +uint32_t lookup_ip(const char *addr, int aftype, DNSCB * callback, void *data) { struct dnsreq *req; int aft; - uint16_t nid; check_resolver(); - if((nid = assign_dns_id()) == 0) - return 0; - - req = &querytable[nid]; - - req->callback = callback; - req->data = data; + req = allocate_dns_request(callback, data); #ifdef RB_IPV6 if(aftype == AF_INET6) @@ -149,8 +186,8 @@ lookup_ip(const char *addr, int aftype, DNSCB * callback, void *data) #endif aft = 4; - submit_dns(DNS_REVERSE, nid, aft, addr); - return (nid); + submit_dns(DNS_REVERSE, req->id, aft, addr); + return (req->id); } static void @@ -159,35 +196,34 @@ results_callback(const char *callid, const char *status, const char *aftype, con DNSCB *cb; void *data; struct dnsreq *req; - uint16_t nid; + uint32_t nid; int st; int aft; - long lnid = strtol(callid, NULL, 16); - if(lnid > DNS_IDTABLE_SIZE || lnid == 0) + nid = strtoul(callid, 0, 16); + + req = get_request_from_id(nid); + if(req == NULL) return; - nid = (uint16_t)lnid; - req = &querytable[nid]; + st = atoi(status); aft = atoi(aftype); - if(req->callback == NULL) - { - /* got cancelled..oh well */ - req->data = NULL; - return; - } + #ifdef RB_IPV6 if(aft == 6) aft = AF_INET6; else #endif aft = AF_INET; - + cb = req->callback; data = req->data; - req->callback = NULL; - req->data = NULL; - cb(results, st, aft, data); + + rb_dlinkDelete(&req->node, &query_hash[req->hashv]); + rb_free(req); + + if(cb != NULL) + cb(results, st, aft, data); } @@ -305,7 +341,7 @@ parse_dns_reply(rb_helper * helper) } static void -submit_dns(char type, uint16_t nid, int aftype, const char *addr) +submit_dns(char type, uint32_t nid, int aftype, const char *addr) { if(dns_helper == NULL) { diff --git a/src/s_auth.c b/src/s_auth.c index 1b221c0d..94dffd7f 100644 --- a/src/s_auth.c +++ b/src/s_auth.c @@ -76,7 +76,7 @@ struct AuthRequest { rb_dlink_node node; struct Client *client; /* pointer to client struct for request */ - uint16_t dns_query; /* DNS Query */ + uint32_t dns_query; /* DNS Query */ rb_dlink_list rbl_queries; rb_fde_t *authF; unsigned int flags; /* current state of request */