| Commit message (Expand) | Author | Age | Files | Lines |
| * | Only init solanum once in tests/sasl_abort1.c•••Calling solanum_main multiple times results in loading every
core/autoload module multiple times (because the check for "is the
module already loaded" always returns "no" due to solanum_main clearing
the list of loaded modules before attempting the load). Init only once,
and use other code to ensure that UIDs are consistent instead by
resetting the counter and ensuring we free the clients with the old UIDs
at the end of each test run.
HEAD main | Ryan Schmidt | 13 days | 1 | -11/+9 |
| * | Call the channel_lowerts hook on SJOIN too•••Previously this hook was called only when a remote join outside of a
netjoin burst to an existing channel happens, which is a fairly odd set
of criteria. By making it run for SJOIN too, it now covers every case
where a channel's TS is lowered, making the hook more reliable for use.
| Ryan Schmidt | 13 days | 2 | -11/+15 |
| * | Add user_welcome hook•••This hook is executed when the registration burst is being sent to a new
local user, after sending RPL_ISUPPORT but before sending LUSERS output.
Many IRCv3 specifications use this timing as the point to send
additional information during registration bursts, so having an easy
hook point to do that makes implementing such specs possible.
| Ryan Schmidt | 13 days | 4 | -1/+16 |
| * | Expand doing_whois/doing_whois_global hook data•••Use hook_data_client_approval instead of hook_data_client so that we can
pass whether operspy WHOIS is being performed as part of the hook data.
hook_data_client_approval is backwards compatible by having the same
beginning layout as hook_data_client, so modules compiled against the
old hook data should have no issues.
Unlike most hooks where an approval struct is passed, the approved field
is meant to be read-only here. The approval struct was simply used out
of convenience vs having to define a custom struct with identical layout
for the case of WHOIS.
| Ryan Schmidt | 13 days | 2 | -5/+10 |
| * | Add sendto_list_local_* and sendto_monitor_with_capability•••These are needed for METADATA support, and sendto_monitor was refactored
into a common sendto_list_local_internal method used by all of the
newly-added functions as well. Test cases were also added to excercise
the new functions.
| Ryan Schmidt | 13 days | 3 | -17/+432 |
| * | Expand monitor•••- new is_monitoring function that modules can use to determine if a
particular client is monitoring a particular nickname
- new hook that is fired when a user adds a nick to their monitor list
| Ryan Schmidt | 13 days | 4 | -1/+46 |
| * | Make change_isupport useful•••The function now accepts an optional pointer argument to a new struct
that contains all of the data of the previous isupport function (both
callback and data), rather than only returning the previous data
pointer. This in turn allows modules to both call this function to
overwrite an isupport handler in modinit as well as restore the previous
handler in moddeinit (something that was impossible before).
The return value was changed to int, returning 0 if the named isupport
method didn't previously exist and 1 if it did exist, so the caller can
judge whether this function actually accomplished anything.
There were no callers of this function due to it previously being of
questionable use, so no other code needed adjustment.
| Ryan Schmidt | 13 days | 2 | -8/+20 |
| * | Pass block name to conf_start callbacks•••Configuration blocks of the form block "name" { ... } previously were
unsupported in extensions calling add_top_conf because the name portion
was not exposed to anything within the extension. Pass the name along so
callbacks can use that data instead of relying on global state in
newconf.c with static storage duration.
| Ryan Schmidt | 13 days | 2 | -17/+37 |
| * | Meson: Decouple creation and generation data from version•••This fixes the generation counter being hardcoded at 0 and the
IRCd birth date being reported as "__DATE__ at __TIME__".
| Aaron Jones | 2026-07-19 | 13 | -83/+114 |
| * | Move setup.h include above rb_lib.h and fix meson assertion printout•••In autotools, NDEBUG is defined in setup.h, which means we need this included before we include any system headers which depend on it (i.e. assert.h). As such, make this the first include in stdinc.h instead of transitively including it from ircd_defs.h.
Also fix the assertions printout provided to the user as b_ndebug=true disables assertions, rather than enabling them. It also takes an if-release value, so detect that properly too.
| Ryan Schmidt | 2026-07-14 | 3 | -3/+9 |
| * | Fix authd crash with dnsbl•••If a dnsbl returned a hit, authd would reliably crash. While this still
results in the client being properly rejected, it is very noisy in
server notices/logs.
Also update reference.conf as it was still using the old (deprecated)
block name for DNSBLs. Copy over the updated wording from
ircd.conf.example.
| Ryan Schmidt | 2026-07-14 | 2 | -10/+13 |
| * | Clean up outgoing_response_info on parse end•••Failing to set outgoing_response_info to NULL after finishing parsing a
command means any future commands that do *not* have a label tag will
incorrectly inherit that labeled response context. This can cause, among
other things, crashes when sending an unlabeled remote command after a
labeled remote command.
Also add a regression test for this behaviour.
| Ryan Schmidt | 2026-07-04 | 2 | -21/+41 |
| * | Fix SERVICES cap name in ts6 docs•••Should be plural, not singular. This cap is unused in solanum's codebase yet advertised anyway so the only correction needed to happen is in the cap list table. | Ryan Schmidt | 2026-07-04 | 1 | -1/+1 |
| * | Address review comments | Ryan Schmidt | 2026-07-03 | 1 | -1/+1 |
| * | Add tests for labeled-response | Ryan Schmidt | 2026-07-03 | 4 | -0/+774 |
| * | Fix labeled-response issues•••- Solve crash in free_response_batch by not attempting to remove NULL
batch ids from the dictionary (indicating there was no response batch
to actually free)
- Specify the correct server mask for the solanum.chat/response tag when
using hunt_server based on whether the hunted param is a client vs a
server
| Ryan Schmidt | 2026-07-03 | 2 | -2/+3 |
| * | Fix narrowing conversion for caps in m_message | Ryan Schmidt | 2026-07-03 | 1 | -7/+7 |
| * | Avoid spurious printfs in sasl_abort1•••The TAP protocol doesn't allow extra stdout lines unless they're
commented (which these were not), and I don't see the value in printing
out every line we're munching, so instead use the new drain_client_sendq
function introduced in the previous commit to empty out the client's
sendq rather than these printf while loops.
| Ryan Schmidt | 2026-07-03 | 1 | -7/+2 |
| * | Test utility fixes and additions•••- Add helper method to drain a client's sendq without asserting on any
of its lines
- Add helper method to fetch a dictionary by name, as these are
typically static linkage but could be useful for inspection or
manipulation in tests
- Add helper method to run an event by name, as these are typically
static linkage but could be useful to run during tests
- Make the cleanup_remote functions work properly by exiting the correct
client with the correct parameters
- Add clients created by text utilities to relevant tracking variables
- New helper methods to create clients with IDs
- Fix return value of get_client_sendq to always be a char * (some cases
previously returned const char *)
| Ryan Schmidt | 2026-07-03 | 9 | -12/+103 |
| * | Use posix-compliant shell syntax•••Local dev env had /bin/sh aliased to /bin/bash but CI runs on Ubuntu
where /bin/sh is dash, and lacks array support. Debian is similar in
this regard, so ensure that the script works across any posix-compliant
shell rather than using bash-isms.
| Ryan Schmidt | 2026-07-03 | 1 | -6/+6 |
| * | Fix meson test•••A new custom build target sets up the runtime dir the way the
testsuite expects it so that it can run properly. Also fix the help
script as it was trying to treat a file as a symlink when it wasn't
which broke the new build target. Tests now also properly use the
TAP protocol in the meson build file, and fix a segfault in the
send1 tests that passes NULL to a function that previously assumed
that NULL would not be passed.
| Ryan Schmidt | 2026-07-03 | 5 | -3/+57 |
| * | Fix memory leak in /LIST processing•••The error path was not freeing memory allocated during earlier
loop invocations.
| Aaron Jones | 2026-06-23 | 1 | -0/+2 |
| * | Address review comments | Ryan Schmidt | 2026-06-06 | 1 | -29/+63 |
| * | Update TS6 documentation•••The new documentation is organized differently to (hopefully) introduce
the TS6 server-to-server protocol in an easy to understand manner while
also serving as a useful reference for ircd and services developers who
wish to make use of this protocol to link to solanum.
Other documentation files were updated as well to correct discrepancies
noticed while writing the updated TS6 documentation.
| Ryan Schmidt | 2026-06-06 | 4 | -1282/+2842 |
| * | Update labeled-response code•••The previous API was too error-prone, as evidenced by the large amount
of crash bugs discovered with it. New functions were added to response.h
to more easily manage labeled-response state, and some state tracking
was moved into core (such as CLICAP_RECEIVE_LABEL, which must only ever
be on one client at a time). Because this tracking is now in core,
cap_labeled_response needs to be a core module as having that bit
unloaded will cause issues. m_batch was also moved into being a core
module as more and more core things have depended on batch support
existing (and more will depend on it in the future).
m_list no longer re-uses remote response batches for SAFELIST, instead
making use of new APIs to suspend a labeled-response batch and more
easily resume it.
Batch resumption was made more focused as well, to ensure that we don't
accidentally lose batches due to setting outgoing_response_info to NULL.
The free_response_batch takes a resumption pointer to avoid cases where
we could introduce use-after-free by combining
free+resume_response_batch.
struct ResponseInfo now takes strduped pointers instead of directly
holding the buffers, and some fields were merged into a flags field or
omitted entirely due to new suspension/resumption support. This will
have a minor positive impact on memory usage as we no longer need to
allocate buffers for maximum-sized strings for every labeled-response.
Finally, shorten the dictionary label for pending responses. It was
overflowing its spot in STATS B, making the data after it misaligned.
| Ryan Schmidt | 2026-06-04 | 14 | -243/+201 |
| * | Fix null dereference in LIST•••Introduced in 66a8049e700c5c55ddd32cf211c1ceef06992ff3
| Valentin Lorentz | 2026-05-24 | 1 | -1/+2 |
| * | Prevent users from running CAPAB pre-registration•••We now disconnect the client if they attempt to run CAPAB before running
PASS (introducing themselves as a TS6 server with an SID) or if they've
already sent USER/NICK info. USER/NICK already has the other half of the
requisite checks by disconnecting the user if they have an SID. As such,
the logic flow of requiring an SID before CAPAB means users can never
have server caps set on them.
This prevents various issues such as a client sending CAPAB STAG
receiving all message tags, including those designed to be s2s-only.
| Ryan Schmidt | 2026-05-23 | 1 | -1/+10 |
| * | Fix missing send_multiline_reset in clicap_generate•••This commit adds a missing send_multiline_reset call
before a return in clicap_generate in m_cap.c.
Without this, if running CAP LIST, the send_multiline_init call
just above it would not be cleaned up.
It assumes that send_multiline_reset is always safe to call,
which is true at the time of this commit.
| daemoness | 2026-05-23 | 1 | -1/+4 |
| * | Don't auto-expire SAFELIST batches•••Avoids use-after-free if the client takes more than 10 seconds to fully
receive the LIST output.
| Ryan Schmidt | 2026-05-21 | 2 | -2/+3 |
| * | Fix timing of free_response_batch on cliexit•••free_response_batch will no-op if MyConnect(client_p) is false. This
would always be the case with the former timing, as it was called after
exit_local_client which clears the MyConnect flag. Do it before instead
so we can properly clean up the tracking vars (namely, the
pending_responses dict, which otherwise had a use after free when firing
the event to clean up a response for an exited client).
While we're at it, change the previous fix in cap_labeled_response from
IsIOError to IsAnyDead to catch more cases where a client cannot
receive data. This has not caused any crashes, but the expanded check
includes IOError so is safe to use, and all of the statuses checked by
IsAnyDead preclude the ability to send data to the client.
| Ryan Schmidt | 2026-05-21 | 2 | -6/+6 |
| * | Adjust order of operations•••Compare pointer values and set to NULL before freeing the pointer. Also
set outgoing_response_info to NULL as well (this is pointless at the
moment since it will always be followed by a call that resets it to the
orig_response_info pointer, but future-proofs it in the event that
future code doesn't do that)
| Ryan Schmidt | 2026-05-20 | 1 | -2/+4 |
| * | Fix use after free in LIST with labeled-response•••In the event that LIST output is small enough to complete without
invoking SAFELIST code (i.e. the buffer doesn't exceed half of the
client's SendQ), the stashed outgoing_response_info in struct ListClient
is the same pointer as the outgoing_response_info for the LIST command.
When we finish sending the LIST, we free the stashed struct ListClient's
outgoing_response_info and then restore the outgoing_response_info from
the LIST command, and attempt to do things with it. However, that memory
has already been freed. Detect the case when the pointers are the same
value and properly wipe them both so we no longer attempt to read from
it.
| Ryan Schmidt | 2026-05-20 | 1 | -7/+10 |
| * | Fix crash on labeled QUIT•••Trying to send things to disconnected clients turns out to be a bad
idea. This change effectively ignores any labels on QUIT.
| Ryan Schmidt | 2026-05-18 | 1 | -13/+17 |
| * | Clean up include/stdinc.h and librb/include/rb_lib.h•••- Unconditionally require stdbool.h in IRCd
We are a C99 project anyway (configure.ac and meson.build both
require a C99 compiler), so this header will always be present
This removes the awful hack defining bool, true, and false in
its absense, which was creating build errors when using meson,
because meson.build did not set the HAVE_STDBOOL_H macro
- Modernise definition of alloca(3) according to GNU guidance
This was in both librb and IRCd, while it only needs to be in
the former
- Fix missing endianness check in librb/meson.build
IRCd and librb both use the WORDS_BIGENDIAN macro, which was
only being set by their configure.ac (with the AC_C_BIGENDIAN
M4 macro)
Since IRCd's stdinc.h includes librb's rb_lib.h, which then
includes librb's librb-config.h, which would have the macro
defined there, we only need to check for it in librb, so we
can remove the endianness check from IRCd's configure.ac and
don't need to add it to IRCd's meson.build
- Use __has_attribute to detect whether compiler attributes are
available
This is supported by gcc (5+), clang (2.9+), and ICC (17+)
- Add a __noreturn macro for __attribute__((__noreturn__)) and
adjust the codebase to use that
- Remove inclusion of headers that are only used by librb
- Remove inclusion of headers that are included in rb_lib.h
because stdinc.h includes rb_lib.h anyway
- Remove the checks for headers and functions from the IRCd
configure.ac and meson.build that are only used by librb
- Alphabetise checks for headers and functions (by the name of
the macro they define) in the meson.build files
- Use check_header() instead of has_header() in meson to see if
it is actually possible to compile code using the header
- Remove dead code using srand48(3) which has never been
compiled because neither build system has ever set the
HAVE_SRAND48 macro and the surrounding code makes no use of
this libc RNG
- Remove the TLS defines from IRCd's meson.build because librb's
meson.build already defines them and IRCd pulls those in
| Aaron Jones | 2026-05-18 | 19 | -276/+132 |
| * | Remove some legacy cruft•••- The hurt extension doesn't work well and is now supplanted by
m_quarantine
- ip_cloaking_old has been broken (causes segfaults) for years now,
remove it
- ip_cloaking_3.0 has hardcoded keys that require .c file edits to be
secure. Anyone using it will probably maintain their fork of this file
anyway, but it's not good for new people to use. Remove that too
- Remove LOCOPS and umode +l entirely; they serve no useful purpose on
unified networks. This also removes the no_locops extension since it
is now useless
| Ryan Schmidt | 2026-05-13 | 20 | -1240/+12 |
| * | Fix s2s labeled-response batches•••Previously, batches would end prematurely if they traveled through an
intermediate server before reaching their destination because the
intermediate server would send ENCAP ACK multiple times, causing the
pending server count to go down way too fast. Solve this by introducing
two things:
- Check that the direction of the incoming command matches the direction
we'd be sending the ACK to (avoids sending additional ACKs for replies
from remote servers that we pass along)
- Add a mask parameter to the tracking metadata for remote responses and
only send an ACK if we match the mask. this way things like remote
WHOIS don't generate ACKs from intermediate servers
Additionally, fix our manipulation of outgoing_response_info in m_list
to properly set CLICAP_RECEIVE_LABEL during SAFELIST buffering. The
logic here largely matches that in m_batch.
| Ryan Schmidt | 2026-05-13 | 11 | -41/+120 |
| * | Add labeled-response support to m_message•••While base cases already worked fine with just cap_labeled_response, a
handful of special cases need batched responses, such as multi-target
messages. The module also needed updating to work properly with
echo-message, as the spec says that the echo is the one that needs the
label if the client messages themselves, rather than the main message,
and the echo is always sent last. This logic is also applied to mass
messages that include the oper sending it.
The handle_special method was broken up and made less special, treating
the various cases as additional target types rather than processing them
right away. The opers@server hack was also removed entirely since it is
obviated by other means of messaging opers on a server such as LOCOPS in
the event such is even necessary. Or, you know, just use the staff
channel.
| Ryan Schmidt | 2026-05-13 | 3 | -190/+248 |
| * | Add labeled-response support to LIST•••With SAFELIST, the labeled-response batch does not necessarily finish
right away. As such, save off the context for the client's LIST command
and restore it each time we send them more data.
| Ryan Schmidt | 2026-05-13 | 1 | -0/+21 |
| * | Add labeled-response support to BATCH•••This concerns client-initiated batches only. Save the labeled-response
context as part of the Batch so that we can restore that context later
once the batch is complete. The label is added to the batch start
message, but we only process batches once we receive the batch complete
message (which lacks a label tag), and we could potentially be finishing
a batch due to it timing out if the client never sends a batch complete
message. By restoring context, we ensure that hooks such as
outbound_msgbuf are operating with all of the state they would expect to
have in order to properly attach tags to outgoing messages.
| Ryan Schmidt | 2026-05-13 | 1 | -0/+55 |
| * | Batch labeled-response multiline responses•••Add calls to generate local or remote labeled-response batches to all
modules which generate multiple lines of response. In general, this is
only done once we've confirmed we will be sending multiple lines, to
avoid spurious batches which only contain single lines inside of the
batch, however some cases will always generate a batch regardless due to
ease of implementation.
This patch covers all of the "easy" cases; future patches will cover the
complicated ones: m_batch, m_message, and m_list.
| Ryan Schmidt | 2026-05-13 | 37 | -37/+180 |
| * | Add cap_labeled_response•••This module provides the labeled-response capability as well as an
internal non-propagated ?receive_label capability that is dynamically
added/removed from the client which should receive a labeled-response.
By using a second dummy capability, I don't need to rewrite our msgbuf
caching layer which is keyed entirely off the capmasks of the client in
order to vary who receives the label/batch tags.
It also introduces a s2s-only message tag solanum.chat/response which is
used to inform remote servers that their replies should be labelled.
Remote responses are always batched, and the batch is generated by the
local server to ensure that 100% of incoming labelled commands receive a
labeled-response. The solanum.chat/response tag is passed back in
replies so the local server can add the appropriate batch tag to the
response passed to the client. Remote servers will also send an ENCAP
ACK command to indicate they are done responding in the event that they
received an incoming s2s command with the solanum.chat/response tag.
The module keeps track of outgoing responses and if, by the end of
command processing (parse_end hook), it hasn't attached a label to
anything it will send a labelled ACK to the client. If it has begun a
labeled-response batch, it will also automatically close that batch,
reducing the likelihood of programming errors forgetting to close
batches.
| Ryan Schmidt | 2026-05-13 | 3 | -0/+232 |
| * | Expand `STATS t` to include batch info•••Two new lines were added at the end of STATS t output to list the number
of pending client-initiated batches (and pending lines in those batches)
as well as the number of pending remote labeled-response batches.
| Ryan Schmidt | 2026-05-13 | 2 | -0/+11 |
| * | Fix crash in allocate_batch_message()•••When allocate_batch_message is called on a batch containing valueless
tags (i.e. tag value is NULL), the ircd would core because we attempted
to call strlen on a NULL pointer. Properly detect NULL values and don't
attempt to copy them. Additionally, misbehaving hooks may set tag keys
to be NULL. While this is not documented or officially supported, other
parts of the codebase detect NULL keys as an indication that the tag
should be stripped; detect this as well and avoid copying those tags
entirely in the newly-allocated batch message for consistency and to
avoid spurious crashes.
This crash is currently not exploitable because allocate_batch_message()
is only called for client-initiated batches and batches sent s2s, of
which there are currently none.
| Ryan Schmidt | 2026-05-13 | 1 | -6/+22 |
| * | Add CLICAP_SERVONLY and CLICAP_FLAGS_NOPROP•••CLICAP_SERVONLY is a client capability that no clients will ever have
(it is not associated with any CAP string), but is included in the
server's client cap mask. Message tags with their capmask set to
CLICAP_SERVONLY will only ever be propagated s2s and will never be sent
or received c2s. This allows for the easy introduction of s2s-only
message tags.
Similarly, a new flag for client capabilities defined by modules was
introduced name CLICAP_FLAGS_NOPROP which indicates that message tags
having a capmask including such a capability MUST NOT be sent s2s.
The CLIENT_CAP_MASK macro in send.c was updated to omit capabilities
marked as CLICAP_FLAGS_NOPROP from what it will send s2s.
| Ryan Schmidt | 2026-05-13 | 4 | -3/+32 |
| * | Add core framework needed by labeled-response•••- new struct ResponseInfo that keeps track of all relevant state for a
labeled-response (whether local or remote)
- event to clean up pending remote labeled-responses that we haven't
gotten responses for (perhaps due to a bad network link with the
remote server, or it doesn't have labeled-response loaded)
- struct Batch grew a new field to track its labeled-response status
- struct Client grew a new linked list to track pending remote
labeled-responses for it, so we can abort them easily if the client
disconnects
- struct ListClient grew a new field to track labeled-response status
for a SAFELIST iteration
- remove arbitrary size limit on batch id generation; it will now
fill the passed-in buffer according to the passed-in buffer size,
leaving room for the null byte at the end.
NULL fields indicate that no responses are being labeled. The actual
population of those fields will happen in future patches; this one
simply provides the core support needed.
| Ryan Schmidt | 2026-05-13 | 9 | -6/+294 |
| * | Change outbound_msgbuf to use its own data struct•••The new struct is ABI-compatible with hook_data for the first 3 fields
so that modules compiled using the old hook definition will continue to
work. The new data enables much richer evaluation during outbound_msgbuf
hook functions by exposing the target or channel the message is being
sent to (if known) as well as whether the message source is a recipient
of the message being sent.
| Ryan Schmidt | 2026-05-13 | 8 | -53/+141 |
| * | Add parse_end hook•••This hook runs after parsing and processing a command, so that any
cleanup that needs to happen after we're finished with parsing can
happen. Some reorganization happened so that we ensure the hook and any
tags processing happens for every event that isn't a parse error.
This will be used by labeled-response in order to automatically send
ACKs or close labeled-response BATCHes after processing client commands.
| Ryan Schmidt | 2026-05-13 | 4 | -26/+46 |
| * | include/serno.h.SH: correct check for git directory•••Commit 6ba61b33f7ec557c02c1 split this logic up from the top
level Makefile.am but then failed to adjust the path to the
directory in the check
The result is that all builds now use a datecode of 0 and a
revision of "unknown"
| Aaron Jones | 2026-05-12 | 1 | -1/+1 |
| * | Add "bypass" capability to spamfilter•••A new flag ACT_BYPASS was added as a generic flag to bypass +u if set.
Opers remain immune, both as senders and recipients, so that spamfilter
cannot be abused to lock people out of managing filters, talking to
services, etc.
Three new configuration items were added to the general section of
ircd.conf to control filter behaviour:
- filter_sees_user_info: This replaces the old #defines for FILTER_NICK,
FILTER_IDENT, and FILTER_HOST to determine whether the hostmask of the
user is passed to the spamfilter or whether we pass a dummy *!*@*.
- filter_bypass_all: If set, the new ACT_BYPASS can allow every filter
action (DROP, KILL, ALARM) to bypass +u if set in conjunction with
those flags. If unset, only the DROP action can bypass +u and
ACT_BYPASS has no effect on other actions.
- filter_exit_message: This is the quit reason displayed, to move it out
of a #define (we still keep a define around for a default reason in
case it is unspecified).
If either filter_sees_user_info or filter_bypass_all are set, the
VERSION command will display a new 'F' flag to indicate the ability for
filter to spy on users.
| Ryan Schmidt | 2026-05-11 | 3 | -58/+167 |
| * | Automatically rehash when modules change conf•••When loading a module that modifies config (add/remove conf items or top
conf sections), we now queue a rehash operation so that new config can
be immediately applied. A new rb_defer_once() function was added to
deduplicate these rehash requests so that at most one rehash will occur
regardless of how many modules change conf.
| Ryan Schmidt | 2026-04-29 | 7 | -5/+36 |