up moddata_client_get() etc -> findmoddata_byname().
Apparently we have 52 moddata registrations (that is without 3rd party modules)
so otherwise it is a loooong linked list.
This was done in lr_pre_command() and lr_post_command().
Nowadays we have BIGLINES stuff from servers that cause MAXLINELENGTH
to be 16k, so the LabeledResponseContext ended up being 16k+.
Although we normally have the policy to zero out complete structs
in UnrealIRCd instead of only individual members (for safety,
easy to overlook security bugs), in this case we will do zeroing
of struct members explicitly. Added some warnings about this too
in the source code. Zeroing 16k twice for each command is a bit
too much waste.
This fixes something like TLINE ~country:us not automatically converting
to ~country:US, since previously conv_param() was not called. But it also
means other code is used in the same way as GLINE (other type of rejections),
for example invalid server ext ban will print a better error with syntax
info (e.g. TLINE ~certfp:xx).
That ~country issue was reported by adamus1red in https://bugs.unrealircd.org/view.php?id=6581
Something like:
#ifdef TLS1_3_VERSION
w->minimum_tls_version = TLS1_3_VERSION;
#endif
url_start_async(w);
Require TLSv1.3 for central-blocklist and spamreport calls, unless your
OpenSSL does not support it, which should be rare.
At some point in the future I will make this endpoint TLSv1.3+ only.
allow {
mask *;
password "secret";
password "letmein";
}
This is always an "OR" type of match, any match means you pass.
I was actually doing this for the dual-cert stuff from previous commit,
where this can come in handy:
link irc1.example.org {
...
password "AHMYBevUxXKU/S3pdBSjXP4zi4VOetYQQVJXoNYiBR0=" { spkifp; };
password "jNw8P4QMg9tqjEJ4/lFikXBNHdIGSeN2B4/T322VjIo=" { spkifp; };
...
}
In the past a dual cert/key setup could have been useful for RSA + ECDSA
but nowadays all clients support ECDSA so that makes little sense.
The reason it is added now is so you can use ECDSA + ML-DSA or some
other [regular crypto] + [post quantum crypto] combination.
Actually, you could even use more than two.
To use this in the config file, simply use the certificate and key
directive multiple times. Just be sure to load the certificates and keys
in the same order. We will print a helpful error if you fail to do so.
Note that for Post Quantum Cryptography the most important step today
was/is to protect against the "Harvest now, decrypt later" scenario
https://en.wikipedia.org/wiki/Harvest_now,_decrypt_later which is a
"passive attack". That's why in UnrealIRCd 6.2.0 we enabled
X25519MLKEM768 if it is available (OpenSSL 3.5.0 and later).
While, this commit, and this talk about dual ECDSA and ML-DSA, is about
when a quantum computer exists and actively does a man in the middle
attack. That's not a realistic scenario in 2025 and according to experts
also not in the next few years. We just make the UnrealIRCd code-
base ready to have this feature for when it is needed / will be used,
and to get this tested properly.
For testing the dual ECDSA and ML-DSA setup I used the following
command to create the 2nd cert/key (self-signed):
openssl req -x509 -nodes -newkey mldsa65 \
-keyout ~/unrealircd/conf/tls/server.key.mdsa65.pem \
-out ~/unrealircd/conf/tls/server.cert.mdsa65.pem \
-days 3650
And then:
listen {
ip *;
port 6697;
options { tls; }
tls-options {
certificate "ssl/server.cert.pem";
key "ssl/server.key.pem";
certificate "ssl/server.cert.mdsa65.pem";
key "ssl/server.key.mdsa65.pem";
}
}
When running openssl s_client -connect 127.0.0.1:6697 it shows ML-DSA is used:
...
Peer signature type: mldsa65
Negotiated TLS1.3 group: X25519MLKEM768
...
And with openssl s_client -connect 127.0.0.1:6697 -sigalgs "RSA+SHA256:RSA+SHA384:ECDSA+SHA256:ECDSA+SHA384"
it shows ECDSA is used:
..
Peer signature type: ecdsa_secp384r1_sha384
Negotiated TLS1.3 group: X25519MLKEM768
..
This is just for testing purposes (self signed cert). As of right
now (Sep 2025), you can not get a trusted certificate with ML-DSA,
as the CA/Browser Forum only allows issueing RSA and ECDSA keys.
Also, all the trusted Certificate Authorities use RSA or ECDSA.
And, again, all this is not ML-DSA specific, it should work for
other dual/multi combinations, and.. who knows they even go for
something hybrid.
A downside of dual certs is that this makes the whole spkifp thing more
complicated because if you use 2 certs/keys you now have 2 possible
fingerprints (spkifp) that could match in e.g. server linking.
While coding this, I also changed the 'STATS P' output to use the txt
numeric instead of notice, and be more verbose in its output for TLS
listeners: printing the certificate(s) and key(s).
This function was added a short while ago, and well it seems to be
able to be possible in a module. Since the 'isupport' module is mandatory
and this is ISUPPORT related, it is the right place.
Can't move isupport_snapshot() because modules might not be loaded yet
or things are currently unloading, i think. Not important anyway.
Also, make things work if there are more changes than would fit
on one isupport line. Although I didn't really test this..
Ended up splitting things in 3 helper functions to avoid some
goto and/or duplicate code and stuff. The alternative was, surprisingly,
even more ugly.
Call the efunction from 005 introduction as well, so it uses the
batch, if needed. And yeah we opt to send the 005's always, even
if it was already sent in the handshake (or not).
Some re-indenting (spaces to tabs).
And call the efunction from VERSION as well.
For "VERSION remote.server" we don't send them in a batch as these
are not numeric 005 but 105. These are for information purposes only
and should not confuse the client (eg not to act upon).
users by server port (eg 6667, 6697, 8000, etc).
This also adds security-group::exclude-server-port for consistency.
And in crules the function server_port() returns the server port number,
so you can use rule 'server_port()>6690' for example.
Note that for remote clients this will only work after previous
commit (b2d0ec1af3) is loaded on all
servers, otherwise all remote clients are seen as having a server_port
of zero (0). Though you probably usually only care about this on local
users anyway.
in the EFunction but not in the actual function. That's bad since it
means the "const guarantee" got lost. And one or two similar cases with
incorrect parameter types and mismatching return types. This was
found with some analyzer, we had no bugreports with regards to this.
The 4 unicode blocks are now treated as one big Latin block
Latin-1 Supplement, Latin Extended-A, Latin Extended-B ==mapped=to==> Basic Latin
Reported by CrazyCat in https://bugs.unrealircd.org/view.php?id=6576
requests normally, unless the niche feature set::allow-user-stats is used)
The tld::motd was made optional in Jun 2022 commit 1fe6119026.
Not setting it is probably a bit rare, which explains why this bug was only
reported yesterday (Aug 2025) via the crash reporter.
Isn't that what it was supposed to do? Well, yes and no, previously
it only guaranteed that between reconnects (so the 2nd try not being
before class::connfreq than the 1st try), but there were no guarantees
for the first time period directly after a squit.
* When a netsplit happens and
[set::server-linking::autoconnect-strategy](https://www.unrealircd.org/docs/Set_block#set::server-linking)
is `sequential` (which is the default) or `sequential-fallback`
(which is a good value for leafs) then we now consistently wait for
[class::connfreq](https://www.unrealircd.org/docs/Class_block)
seconds before trying to connect to the (same or next) server.
By default this is 15 seconds in the example configuration
server class. The reason for this is to provide a consistent behavior.
Previously we waited semi-randomly for 0 to class::connfreq seconds.
The previous behavior caused the picking of 'next server to try' to
be inconsistent, which especially caused issues for `sequential-fallback`.
If you want quicker recovery times in case of a netsplit, simply lower
the value of [class::connfreq](https://www.unrealircd.org/docs/Class_block)
in your configuration file, e.g. to 5 instead of 15 seconds.
Oh yeah and for connect-strategy 'parallel' things stay as is, with
the wait of 0 to class::connfreq per-server, which seems fine for that.
Unless you want a 'BOOM!' effect of mass reconnects instantly, in
which case you can just set class::connfreq very low.
one could possibly miss this cert verification warning. And since
that will later become an error, it is even more important to
notice such a (hopefully unusual) case quickly.
On the incoming side it was correctly identified as link sec 2,
but on the outgoing side the localhost check failed and caused link sec 1 or 0.
Bug has beent here for a while but I don't think many people
link two UnrealIRCd servers over localhost that are on production
(i do, when dev'ing, but then I don't care about linksec, obviously)
Also, this wouldn't flag services from 2 to 0 because this bug only
affected outgoing UnrealIRCd server connections.
not verified. This changes the wording from "You may want to consider" to
a warning, makes it more strong and that in the future we will reject this
by default.
Actually still pondering to reject it now already by default, but let's start
with this commit first...
[Channel flood protection by default](https://www.unrealircd.org/docs/Channel_anti-flood_settings):
This is an important change that IRCOps and chanops should know about:
* By default we now apply the anti-flood profile "normal", which should be fine for most channels.
* If a chanop does not want this they can override this by setting
`MODE +F` with [another profile](https://www.unrealircd.org/docs/Channel_anti-flood_settings#Channel_mode_F_profiles).
* For example, for a channel with hundreds of users and lots of activity
`+F relaxed` may be more appropriate. Or, chanops can turn anti-flood
off entirely by setting `+F off`
* The reason for this change is that many admins and chanops in practice
don't seem to use `+f` or `+F`. With this change they are now protected "by default"
when no MODE `+f` or `+F` is set.
* Advanced users can can grab the detailed effective settings with `MODE #test F`
(there will be an error if you use `cloak_md5`, but everything
will work fine if you use `cloak_sha256`).
We phased out MD5 usage years ago, so it is only contained to
the old cloaking module. In fact that was the only reason we
started to provide the SHA256 cloaking module, simply so it
isn't using old MD5.
Of course, for module coders this means they should not call
DoMD5() or md5hash(), but that would be rare. Currently zero
modules in unrealircd contrib do this and it makes no sense
to start using it nowadays anyway.
Since UnrealIRCd 6.0.0 when a server connects, we like to drop the
existing link so they don't need to wait on "Ping timeout".
However, that goes against the JUPE stuff that Services tend to use,
it basically negates it.
We now check if the uplink is u-lined (like for services) and if that
is the case we deny the link with "Server Exists (Juped)". So just
like before U6, and with a slightly more helpful message even.
Reported by Jellis in https://bugs.unrealircd.org/view.php?id=6498
We now expire after 30d if score is <12 (so 1 hour of being online)
and we expire after 90d regardless of score.
Note that for this to work, all servers would need to be running
UnrealIRCd 6.2.0+ because when a score for an IP is still present
on any of the servers on a network, and a user with that IP connects,
then the score will be broadcasted from the server that still has
the score and it will be re-added by all servers with that score.
But eventually it should be like this... :D
Reported by armyn in https://bugs.unrealircd.org/view.php?id=6536
* Calling from source is now in a separate function: int can_use_nick(Client *client, const char *nick)
* For hooks: don't free the reject reason, must use static storage like all other hooks
(TODO: clarify in all hooks?)
* Move it up a bit, right before find_qline
TODO (not necessarily me :D):
* Make it an efunc
* Also call it from some other places that do find_qline, like rpc/user.c
* You may want to prod 3rd party modules like SANICK
This will return the number of characters that are in the unicode block
with that name.
spamfilter {
rule "unicode_count('Emoticons')>2";
target { private; channel; private-notice; channel-notice; }
action block;
reason "Too much emotion";
}
In this commit we also make it so we pass the ClientContext (including
clictx->textanalysis) in crule_context.
You will still get a score of +1 if afterwards changing back to Latin
or anything else, but at least the Latin/anything -> Emoticon
transition is free now (score 0). And if ending with an emoji it
also means a score 0 (as far as this is concerned).
Example output:
*** SPAMINFO ***
This will show the original text and the deconfused text which can be used in a spamfilter block with input-conversion deconfused;
Original spam text: ẔŽŽẐ𝞕ȤℤΖℨℨ𝒁𝓩ẒŹƵᏃŻẒŽℨŹ𝒵𝛧Ż𝝛𝛧ℨℤ𝜡Ƶ𝞕𝘡ŹẐ𝑍ẔẐẐΖ𝜡Ẕ𝜡Ẕ𝞕ꓜ𝚭ᏃẐẔ𝙕
Deconfused spam text: ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
AntiMixedUTF8 points: 64
Number of Unicode characters in total: 50
Number of different Unicode blocks used: 8
Unicode Block breakdown (name: bytes [capped at 255]):
- Latin Extended-A: 8
- Latin Extended-B: 3
- Greek and Coptic: 2
- Cherokee: 2
- Latin Extended Additional: 12
- Letterlike Symbols: 6
- Lisu: 1
- Mathematical Alphanumeric Symbols: 16