1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-06-30 23:26:39 +02:00
Commit Graph

10617 Commits

Author SHA1 Message Date
Bram Matthys b0dba4bede Add draft/multiline support with a default max-lines of 15 for known-users
and 7 for unknown-users (with max-bytes 5250 and 1500 respectively). This
allows pasting a short snippet of code, config file, text from a site, etc.

With multiline you have the guarantee that:
1) You will see the entire text with no delay between lines
2) You won't see another persons chat half-way through such a paste
3) For multiline supporting clients it is now clear that all the text
   belongs to each other, which can make selecting/copying it easier.
This basically means short snippets/pastes like that can be completely on
IRC again. No need for a pastebin for it. Though, you may still need such
a service if you are pasting more lines.

Regarding the implementation in UnrealIRCd:
* Clients without multiline get individual fallback lines (concat lines
  merged, blank lines skipped, as per spec). And we know that clients like
  weechat - which does support multiline - also shows all lines and not
  only a few plus snippet style "[.."]. That is another reason for only
  allowing 15 lines by default and not something much more. Otherwise all
  those clients would get a big wall of text, which just sucks.
* Spamfilter (also) runs on the full text of all lines together, so
  splitting a phrase across lines does not evade spamfilter.
* Fakelag: a client can send the BATCH start+PRIVMSG (or NOTICE)+BATCH end
  at full speed. We impose no fake lag there. Also, the multiline default
  max-lines and max-bytes are lower than the example class::recvq of 8000,
  so should be perfectly safe. If the entire BATCH is accepted then we
  will impose fake-lag afterwards, with a cap of 15 seconds maximum.
  If the BATCH is rejected, we impose half the fakelag plus 2sec.
* If the time between BATCH start and BATCH end is more than 15 seconds
  then the BATCH is rejected (set::multiline::batch-timeout).
* The BATCH is atomic (either you see it all, or you see none of it):
  * When the client sends it to server, it is buffered first.
  * Only after the batch close the server indicates if it is accepted
    or rejected. This has various reasons, two of them are: 1) The client
    is going to send everything in one go anyway and not wait for a
    response between each PRIVMSG, and 2) we can't do many checks in the
    buffering stage and skip those after, that would cause a TOCTOU
    problem (eg. a banned user still being able to speak).
  * If any line gets rejected due to spamfilter or other case
    (eg +c, +b ~text with block, etc etc), the entire batch is rejected
  * Locally we deliver all or nothing (as said)
  * S2S we buffer the batch as well, so if a server splits after having
    received 10 lines out of 15, then clients will not see anything.
* We send max-lines and max-bytes, this is the hard upper limit.
* A multiline can still be limited more tight if:
  * +f with 't' or 'm' restricts to fewer lines,
    eg +f [5t]:15, which means max 5 lines per 15 seconds,
    means the max accepted multiline is 5 for that channel.
  * +F works the same, except that default +F normal does not
    have a 't' at the moment and 'm' is very high (50) so
    practically not limited by default.
  * There will be a future +f flood subtype for some more control

TODO: we will send CAP NEW on unknown-users <-> known-users to
      indicate the new max-lines value if you transition security groups

TODO: chat history does not yet include multiline batches.
2026-03-30 13:16:48 +02:00
Bram Matthys 8bfc599697 Guard against EfunctionAdd() from outside MOD_TEST.
As this can keep someone busy for half an hour wondering why things crash...
2026-03-28 10:35:05 +01:00
Bram Matthys eb798510fd Pass the fake lag added msec in ClientContext and add subtract_fake_lag() 2026-03-27 07:46:29 +01:00
Bram Matthys f329a64991 The IsFloodLimit() used a hardcoded channel parameter. This was not a problem.
But is dangerous if the macro would be used where it mattered.
2026-03-26 17:28:51 +01:00
Bram Matthys 14cb15c632 Don't call -m upgrade or -m compile-all if zero src/modules/third/*.c
Reported by bss.
2026-03-25 14:01:42 +01:00
Bram Matthys 6ad7f7dccf And use binary search now that we have so many crule functions... 2026-03-24 19:37:12 +01:00
Bram Matthys ed16dad40e Add a bunch of crule functions:
* Boolean checks: is_oper, is_local, has_swhois
* Match functions: match_class, match_server, match_vhost,
  match_realhost, match_away, match_asname, match_operlogin,
  match_operclass, match_sni, match_tls_cipher
* Numeric counters: connections_from_ip, channel_count,
  channel_member_count, idle_time
* Traffic stats: messages_sent, messages_received, bytes_sent,
  bytes_received
* Text analysis: text_byte_count, text_character_count, word_count,
  uppercase_percentage, digit_percentage, non_ascii_percentage,
  max_repeat_count, mixed_utf8_score, unicode_block_count

Will do a more thorough audit and look at adding some kind of
tests tomorrow.
2026-03-24 19:33:55 +01:00
Bram Matthys 3dd449139b Conditional Config: add @warning "aaa" and @error "bbb"
As usual, this is mostly for configuration templates that you use for
multiple servers, that sort of things, eg.

@if !environment("ADMIN")
@error "Environment variable ADMIN is not set"
@endif

This also adds a change in conf.c so @define, @error and
@warning are skipped in @if blocks that evaluate to false
(that's obviously what everyone wants :D). So that fixes a
previous bug with @define in @if.
2026-03-23 18:47:16 +01:00
Bram Matthys 8adfdf95a0 Little code cleanup in config preprocessor. 2026-03-23 18:13:14 +01:00
Bram Matthys 3521d96f9d This adds module-version("examplemod") and using functions in $define,
such as $define ADMIN environment("ADMIN")
2026-03-23 17:58:36 +01:00
Bram Matthys cf101ca114 Conditional Config: add @if environment("VARNAME") == "something"
to check environment variables.

This also means functions can now return values, so some changes
under the hood. This also moves the <=, >=, <, > ops code.
2026-03-23 17:33:02 +01:00
Bram Matthys 93a485db21 Conditional Config: add support for @else
Actually surprisingly easy due to simply flipping item->negative :D
2026-03-22 19:36:54 +01:00
Bram Matthys 100abaa82d Conditional Config: add support for <, >, <= and >= in @if $SOMETHING ...
And also don't require double quotes on the right hand side.

So you now use something like: @if $MAXCONNECTIONS >= 1024
2026-03-22 19:16:51 +01:00
Bram Matthys 2346aa3977 Code cleanup in conf_preprocessor.c (Conditional Config) 2026-03-22 19:02:29 +01:00
Bram Matthys 17a8182efc Condition Config: add minimum-version() and file-exists().
So: `@if minimum-version("6.2.4")` and `@if file-exists("filename")`.
2026-03-22 18:41:30 +01:00
Bram Matthys 9258875d0f Add @if module-exists("third/coolmod") so you can conditionally
loadmodule + set config items

This checks the file on-disk, which is slightly different than
@if module-loaded("third/coolmod") which checks if it is loaded.
2026-03-22 18:20:36 +01:00
Bram Matthys 27864e8d0e Add new variables in Conditional Config (https://www.unrealircd.org/docs/Conditional_config):
$CONFDIR, $DATADIR, $LOGDIR, $TMPDIR, $DOCDIR, $MODULESDIR, $MAXCONNECTIONS.
2026-03-22 18:07:17 +01:00
Bram Matthys 82481cc083 NO_GEOIP_CONFIG => NO_DEFAULT_GEOIP to make it consistent
As we also have NO_DEFAULT_RPC_SOCKET and NO_DEFAULT_LOG_MEMORY_BLOCK
2026-03-22 17:58:36 +01:00
Bram Matthys ba3fa1d7b6 Update GeoIP question in ./Config and use some magic to support both
geoip_classic and geoip_mmdb in modules.default.conf with Conditional
Config, a dynamic loadmodule line, and auto-updates.

Somewhere in a later version, probably 6.2.5, we will default to mmdb
for all cases.
2026-03-22 17:52:57 +01:00
Bram Matthys b7cd383186 Fix nested @if blocks in config file not working correctly
When using nested @if blocks (e.g. @if module-loaded() inside
@if defined()), only the outermost condition was evaluated.
Inner conditions were silently ignored, causing blocks to be
included even when the inner condition was false.

Also walk the full chain in the loadmodule @if module-loaded()
restriction check.
2026-03-22 17:36:28 +01:00
Bram Matthys 9b83fc0db9 Allow @if with loadmodule, just not module-loaded(). We need this. 2026-03-22 17:07:46 +01:00
Bram Matthys d467005816 Bleh :) 2026-03-22 16:20:25 +01:00
Bram Matthys 69c9130da1 Bump version to 6.2.4-git 2026-03-22 13:45:28 +01:00
Bram Matthys d150da8ea5 Make "geoip_mmdb" the default GEOIP module. So it receives testing.
I still need to update ./Config. I guess we will remove that question
entirely.
2026-03-22 13:38:20 +01:00
Bram Matthys f884bfe755 Another workaround for test suite. 2026-03-22 13:25:36 +01:00
Bram Matthys d6f93e8566 Test suite: update extras/tests/tls/testssl_profiles/pqc.txt
Due to commit 7b48fdca1a
2026-03-22 13:13:30 +01:00
Bram Matthys 806c883a7f Rename geoip_maxmind to geoip_mmdb with a backwards-compatible warn.
This is a mmdb backend which supports various GeoIP providers,
and we no longer use the maxmind library, so this makes sense.
2026-03-22 12:29:00 +01:00
Bram Matthys 172ace9750 geoip_maxmind: use our own mmdb implementation
This is mainly due to licensing. The libmaxminddb library uses the
Apache license, which meant if we would compile it in by default it
would effectively transform our "GPLv2 or later" to "GPLv3 or later".
Our implementation is ISC licensed, so we can include and enable it
by default and keep things at "GPLv2 or later". This is also why we
used geoip_classic in the first place as default and compiled in,
and not the mmdb variant.

The mmdb.c is based on the specification, using the Go implementation
as a reference during development (ISC licensed), initially implemented
with the help of Claude Opus 4.6. After that substantial changes were
made to make it match UnrealIRCd's style and to make things less error
prone: C style changes, allocation and zero termination of strings in
the library, auto-NULL in variadic functions so the caller cannot
forget NULL there (similar to our unreal_log/do_unreal_log), using
enums as the return type instead of int (similar to curl), adding
doxygen docs, etc.

This also means the old mmdb library dependency has been dropped,
including from configure/autoconf.

At the moment we still use the geoip classic library by default,
including those DB files. The idea is we will switch over sometime
later after this current new MMDB stuff has received more testing.

This also makes us more flexible, since .mmdb files have become the
de-facto standard for pretty much all geoip vendors.
2026-03-22 12:10:18 +01:00
Bram Matthys 89bce01c31 Fix OOB write in geoip_csv if the .csv file is bad / malicious.
This module is rarely used but analysis showed that there was an
OOB write in the country name, and two small off-by-ones in code
and continent.

Again, this only matters if the CSV file you are importing is bad
or malicious. And we use stack protection in UnrealIRCd so this
should then "only" cause a crash.
2026-03-16 14:10:29 +01:00
Bram Matthys f944990c54 Fix some flagged stray semicolon in C code (;;) 2026-03-16 09:53:22 +01:00
Bram Matthys 198c9279e1 Fix a check in hash_get_chan_bucket(). The only caller is from list.c
which already ensures in bounds, so not an issue. But who knows in the
future there will be other functions that use it and then the check
is misleading as it doesn't cover all cases.
2026-03-16 09:14:07 +01:00
Bram Matthys e4d6b51d04 Add certificate/key check to CONFIG INIT. So we properly stop booting
or rehashing if there is an error loading them (at least try harder).
Right now they are only in CONFIG LOAD, which is too late to stop things.

Previously "./unrealircd configtest" showed an error but still said
"Configuration test passed OK". And REHASH passed similar. Now, it
is a real error.

This is not to be confused with a "file does not exist" error, which
we already handled properly. It's the less usual ones, like wrong key.

Only downside is more init_ctx() calls, which can be a bit heavy on
various platforms, slowing boot or REHASH down. Should be fine though...
2026-03-15 15:59:09 +01:00
Bram Matthys 08f90d4006 Make certificate_quality_check() work on OpenSSL 3+.
This isn't really important, as you can read below, but was a FIXME item.

This function checks for RSA keys that are less than 2048 bits, so
RSA 1024 is rejected. This was added in UnrealIRCd 5.0.0 (Dec 2019).
RSA 1024 was already looong considered insecure. And those using it
should have been flagged from there on.

OpenSSL 3 changed the API, and this function was never updated to have
the same check with OpenSSL 3+ until now. Fortunately, OpenSSL 3.0.0
onwards reject 1024 bit RSA by default, so that doesn't really matter.
For reference, OpenSSL 3 was released in Sep 2021 and first appeared
in Ubuntu LTS 22.04 (Apr 2022) and Debian 12 (Jun 2023).
However, if you set SECLEVEL to 0 (eg in system-wide openssl.cnf),
it would allow those keys, which is pretty much expected but also not
what we want at UnrealIRCd. From now on, for those rare situations,
we reject it as well.
2026-03-15 10:54:16 +01:00
Bram Matthys 7b48fdca1a Default TLS groups: use tuple syntax with slash to prefer X25519MLKEM768,
even if it costs an extra round-trip due to HRR (Hello Retry Request).
This is IRC after all, where connections live minutes, hours, days,
so that extra round trip is worth it if it means better security.

The TL;DR is: we try harder to use X25519MLKEM768.

The longer story is as follows:

In TLSv1.3, the client will indicate which groups it supports (eg
a list of 4 items) and which ones it speculates to be used (very
often just 2 items). Some TLS clients may not include X25519MLKEM768
in this initial speculation, but only f.e. X25519 and prime256v1
even though X25519MLKEM768 is communicated via their "supported" list.
Without this patch, we would then settle with one of those 2.
With this patch, we will send a Hello Retry Request, allowing to
use X25519MLKEM768.

This is rare, though, most TLS client implementations that have
X25519MLKEM768 will bet on it to be used (the 2 they bet on is
often X25519MLKEM768 & X25519). That's many browsers like Chrome,
OpenSSL, Go, etc.

GnuTLS usually will do this as well, but under some configurations
it may bet on 2 classic crypto to be used. For that specific (type
of) situation, this patch will help to use X25519MLKEM768.
This can be tested with OpenSSL to simulate such an implementation:
openssl s_client -connect 127.0.0.1:6697 -groups X25519MLKEM768:*X25519
Before this patch, it would result in X25519 (because that is the
speculated group, with the asterisk). After this patch it will
cause X25519MLKEM768 to be used.

The tuple syntax is in 3.5.0+ and our UNREALIRCD_DEFAULT_TLS_GROUPS_PRIMARY
with X25519MLKEM768 also requires 3.5.0+ so this is an easy change.

Oh and, this commit comment is rather long for a 1 byte change :D
2026-03-15 07:06:46 +01:00
Bram Matthys 27a3fb8d97 unreal_server_compat: fix always using EXBTYPE_BAN even for +e/+I.
For the extbans that we ship, no problem, as this isn't used in
any of our extbans, but for third party it may matter, or for us
in the future.

Just something we came across while looking into the issue from
previous commit.
2026-03-14 10:20:24 +01:00
Bram Matthys 31005e18b1 Fix extbans in +I not being converted to letter bans to older servers.
This affects servers without NEXTBANS, such as anope 2.0.x series
(anope 2.1.x is not affected as it supports NEXTBANS).

Non-NEXTBANS servers only support letter extbans so we are supposed
to convert ~security-group:known-users to ~G:known-users when sending
to such a server, in unreal_server_compat. And we did this well for
the MODE command for +beI. In SJOIN we did this correctly for +b/+e
but not for +I due to a silly code mistake.

This bug is present since 6.0.0 but wasn't noticed until now.

To be a real problem you need something like:
1. Anope 2.0.x series (or other services without NEXTBANS)
2. A channel with +I extbans
3. KEEPMODES set on that channel

Then what happens is when services boot:
1. UnrealIRCd will sync with anope 2.0.x and incorrectly send
   named bans, which will confuse anope. But nothing strange
   happens yet at this point.
2. Then on next server sync (eg anope restart or unreal restart)
   anope will try to restore these but they end up with weird
   entries like +I *!*@~security-group:known-users
   (note the *!*@ prefix)

And it should be noted that this would also happen in a situation
with UnrealIRCd 5 + UnrealIRCd 6 servers, but UnrealIRCd 5 is
End Of Life anyway.

Reported by BlackBishop and Sadie two days ago. Thanks!
2026-03-13 13:57:41 +01:00
Bram Matthys bcaaaa5949 Fix crash on Windows because of missing MODVAR / __declspec(dllimport)
on 'known_users', which is accessed by the reputation module.
2026-03-11 14:39:15 +01:00
Bram Matthys c3600f0f3a CI: If $USE_SHIPPED_LIBS is 1, then build with shipped libraries from extra/ 2026-03-07 18:34:55 +01:00
Bram Matthys 2d145b0f2c ** UnrealIRCd 6.2.3 ** 2026-03-06 08:23:30 +01:00
Bram Matthys 98709af7a3 modules.optional.conf: extjwt::service::method is required
(which is fine, i think)
2026-03-06 08:22:53 +01:00
Bram Matthys cc1c1c5a73 Update doc/unrealircd_wiki.zim for 6.2.3
[skip ci]
2026-03-06 08:02:19 +01:00
Bram Matthys a841911882 Mention extjwt { } in the release notes: it had API updates, build tests
and we now have documentation on the wiki.

Plus some other textual changes.

[skip ci]
2026-03-06 07:44:13 +01:00
Bram Matthys 7865675917 Fix OOB write if a trusted linked server sends malicious data.
NOTE: Linked servers are considered trusted in UnrealIRCd.

This is not exploitable beyond a crash, due to -fstack-protector-all,
a hardening compiler flag we added many years ago. Even without
that flag it would be rather difficult, and i didn't manage to,
but this should never happen anyway since this flag is only
missing in gcc/clang versions that are more than 15 years old.

This issue was introduced by the move to CMD_BIGLINES in
6c5de62c18 in 6.2.2 release.
2026-03-06 07:14:10 +01:00
Bram Matthys 87e4249a09 extjwt: don't free modes/umodes, they are taken care of by payload. 2026-03-04 17:07:06 +01:00
Bram Matthys c4c082d0b7 And restore this LDFLAGS as well
This completes the fix from e1211adb3b
2026-03-04 11:01:05 +01:00
Bram Matthys e1211adb3b Restore LDFLAGS after setting it in library compiles
But is this enough...?
2026-03-04 10:49:20 +01:00
k4be deff636c74 extjwt: Remove OpenSSL deprecation warnings 2026-03-04 09:38:05 +01:00
Bram Matthys 9289ef7c83 Mention JSON-RPC there as well
[skip ci]
2026-03-04 09:18:20 +01:00
Bram Matthys fc82176cd0 Update README with Mastodon and tell at least something about supported systems.
Mention tested systems as well (which is narrower than supported systems).
And merge documentation and support, since users will usually be after both.
2026-03-04 09:15:36 +01:00
Bram Matthys 7a46caa1da tls-tests: pin to a specific testssl.sh commit hash. 2026-03-03 17:08:35 +01:00