1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-06-12 19:14:46 +02:00
Commit Graph

2879 Commits

Author SHA1 Message Date
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 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 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 69c9130da1 Bump version to 6.2.4-git 2026-03-22 13:45:28 +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 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 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 2d145b0f2c ** UnrealIRCd 6.2.3 ** 2026-03-06 08:23:30 +01:00
Bram Matthys bd1ccde9c3 ** UnrealIRCd 6.2.3-rc2 ** 2026-02-25 08:28:20 +01:00
Bram Matthys 3a96bdf6ec Add set::allow-setident (default: 'no'), set::allow-setname ('yes')
Two new settings that control the use of `SETIDENT` and `SETNAME`:
* [set::allow-setident](https://www.unrealircd.org/docs/Set_block#set::allow-setident)
  now defaults to 'no'. Previously all users were allowed to change their
  ident (taking into account
  [set::allow-userhost-change](https://www.unrealircd.org/docs/Set_block#set::allow-userhost-change)
  restrictions).
* [set::allow-setname])(https://www.unrealircd.org/docs/Set_block#set::allow-setname)
  has a default of 'yes' which matches older UnrealIRCd versions (no change).
  Perhaps some admins who use controlled (web)chats may want to set this
  to 'no' if users are not supposed to change their realname/gecos.
  This is probably rare, but they have the option now.
2026-02-23 08:58:39 +01:00
Bram Matthys 7d45e69fd2 Use C99 flexible array members, like name[], instead of name[1]
in NameList, Tag, Watch and HistoryLogLine.
This does mean the allocation routines need a +1 everywhere, but
I think I got all of them. I also don't see them being used directly
in such a way in 3rd party modules (which is logical, as they
should use the API and not allocate such structs directly).

Also, SpamExcept has been removed as it was not used anywhere.
2026-02-22 16:11:41 +01:00
Bram Matthys 19d17832fe Remove set::restrict-extendedbans as it didn't work. Simply don't load
the particular extended ban module if you don't want it.

For example, if you include the default modules.default.conf and, say,
you don't want ~quiet extbans then you add this in your unrealircd.conf:

blacklist-module "extbans/quiet";
2026-02-22 13:07:57 +01:00
Bram Matthys d38a106879 Enforce MAXBANLEN (which is MODEBUFLEN) at some more places.
This shouldn't be needed except for some corner cases, like if some
third party module does not limit their stuff properly, in S2S
or if channeldb contains some weird long entry or something.
2026-02-22 12:38:01 +01:00
Bram Matthys bb4d1b528f ** UnrealIRCd 6.2.2-rc1 **
(Actually the Windows build is still building :D)
2026-01-31 09:44:57 +01:00
Bram Matthys e083852e86 Create separate resolver channel resolver_channel_https for HTTPS requests.
This one has DNS caching enabled[*], which makes sense for this case.

[*] If using c-ares 1.31.0 or later. That version was released in June 2024.
The shipped-with-UnrealIRCd library version is 1.34.6, so qualifies.
However, if using system c-ares (which is automatically the case, if detected)
then many systems don't have it. The first Linux distro versions that qualify:
* Fedora 40
* Debian 13
* Ubuntu 25.04 (non-LTS) and future Ubuntu 26.04 (LTS)
* Etc...
2026-01-26 09:57:07 +01:00
Bram Matthys 2dd23d13b7 Silently drop TAGMSG to users who refuse PRIVMSG/NOTICE also (umode +D, +R),
since the message/notice would not make it through either.
This also means someone can no longer iterate through users to see who
is +D/+R by sending a "silent" TAGMSG. (Silent in the sense that the
end-user usually would not have noticed)

Suggested in https://bugs.unrealircd.org/view.php?id=6579 by zw32h (I think)

This also means HOOKTYPE_CAN_SEND_TO_USER now allows you to NOT to
set errmsg, to silently drop a message. Previously we would crash
deliberately on such a situation to enforce that all modules would
set a proper errmsg.
2026-01-23 08:23:22 +01:00
Bram Matthys 76aa3a12a6 Add SecurityGroup *known_users, to more quickly fetch those settings.
And use this in a couple of core routines.

This is to speed things up a liiittle.
2026-01-10 10:14:47 +01:00
Bram Matthys 7374fcc83f Add client->known_user_cached as a quick way to determine if the
user is in known-users or in unknown-users. Not used anywhere yet.

Every 2 minutes we rescore all users. Or more specifically: every
5 seconds we rescore 1/24th of all users. That's the slow update path.

On certain events that cause a likely/possible transition, we update
the cache immediately. At the moment that is on IP change and account
login/logout. More will be added later.
2026-01-10 09:57:18 +01:00
Bram Matthys de05bb9654 Bump version to 6.2.3-git and write some early release notes 2026-01-04 10:20:46 +01:00
Bram Matthys c990848d2f Make json_expand_security_groups() really expand all and reorder some.
* Add some missing fields, such as destination, but mostly in the
  exclude- area where a bunch were missing (some of those are a bit
  far fetched, but hey, they exist, so should be shown if in use).
* Re-order fields to more closely match the struct (still not 100%)
* Extended fields, such as "account" and "country", now show up
  directly under the security group, just like the other fields,
  such as "reputation_score". This is also how they show up in the
  config file, so hide the the fact that internally in the struct it
  is stored differently.
* Add a comment in SecurityGroup struct in include/struct.h to make
  it clear you have to add/update stuff at 7 places if you are adding
  something new.
2025-12-14 10:11:09 +01:00
Bram Matthys 426040d870 Move json_expand_security_group() from rpc/security_group to core
and don't include name/priority if it is called for a match item
(which don't have a name or priority).
2025-12-14 09:43:52 +01:00
Bram Matthys 806fa83dd7 ** UnrealIRCd 6.2.2 ** 2025-12-12 12:16:31 +01:00
Valerie Liu 7964345c0b Add RPC methods for security_group and connthrottle (#328)
New RPC methods:
- security_group.list: List all security groups
- security_group.get: Get details of a specific security group
- connthrottle.status: Get full connection throttle status, counters, and config
- connthrottle.set: Enable/disable connection throttling
- connthrottle.reset: Reset connection throttling counts

This also adds json_expand_mask_list(), json_expand_name_list(), and
json_expand_nvplist() to src/json.c for reuse by RPC modules.
2025-12-06 14:58:57 +01:00
Bram Matthys 61ebd34a1e Fix compile error and add URL validation: valid UTF8, no spaces, no low ASCII 2025-11-12 10:53:43 +01:00
Bram Matthys 68f01814be Some minor updates to previous.
* We try to keep the dynconf variables the same name as in the conf
  (well, with hyphens to underscores, and there are some exceptions)
* Remove unnecessary but otherwise harmless second safe_free()
* The URL could have been too long. It is now limited to 360 characters,
  which should be plenty.
2025-11-12 10:14:27 +01:00
Valerie Liu 557595fd1c Implement IRCv3 network icon support (PR #326)
set { network-icon 'https://...........'; }
https://ircv3.net/specs/extensions/network-icon
2025-11-12 10:01:42 +01:00
Valerie Liu c723292ec9 Add HOOKTYPE_MOTD so modules can add their own MOTD lines before RPL_ENDOFMOTD (PR #324) 2025-11-09 09:16:23 +01:00
Bram Matthys d7a6868950 Bump version to 6.2.2-git 2025-11-09 09:01:34 +01:00
Bram Matthys 09032ec868 ** UnrealIRCd 6.2.1 ** 2025-11-02 16:10:26 +01:00
Valerie Liu c16d602cc2 Add webhooks functionality to log blocks (PR #322) 2025-10-27 08:50:38 +01:00
Bram Matthys 58c37b67f9 ** UnrealIRCd 6.2.1-rc2 ** 2025-10-23 18:02:43 +02:00
Bram Matthys 1d774de862 Add MODDATATYPE_* to MODULE for IRCOps 2025-10-17 08:19:15 +02:00
Bram Matthys c1dff43c8d Make the "ModDataAdd: out of space" error message more helpful 2025-10-15 08:31:27 +02:00
Bram Matthys 15e367a822 ** UnrealIRCd 6.2.1-rc1 ** 2025-10-12 15:10:32 +02:00
Bram Matthys fa8a0b2083 Make IsSynched() check if both the "far" server and the "near" server are
synched. Both need to be checked, because:
* The "far" server may be fully synched to "near" (and thus tagged as synced)
  but the "near" server may be introducing the "far" server, when
  we are connecting to "near"
* The "near" server may be fully synched but the "far" server is connecting
  in and may thus not be synched yet

In reality, things are even more complex, since one would have to verify
the whole chain of links. But.. yeah.

Long-story short: this fixes things like "User xyz joined #xxxxx" logging
where this showed up while the server was linking in. It is not supposed to
log that, similar to how we not log all 1000 users as newly connecting when
a 1000-user-server links in. In fact, it didn't already log that for
directly-connected-servers, but for far servers it did previously.

And... that again gave performance issues if you were connecting like a
100k-user far server.. since you suddenly had 100k * numchannels join events
being logged (which surprisingly still only took 6 seconds for 100k entries,
but still, it is wrong to do so and can be avoided).
2025-10-05 10:26:01 +02:00
Bram Matthys c729d18a8c Add (faster) remove_user_from_channel_withmb() and use it from various places.
We can use this when we already have the Membership struct, which is the
case for PART, (SA)JOIN 0 and QUIT. Saves a couple of iterations.
2025-10-05 09:01:08 +02:00
Bram Matthys af0a784464 Make member & membership point to each other so lookups can be much faster.
This also makes them proper list items, again to make certain fast operations
possible. Main thing is that removing an entry does not require us to walk
all of those lists. Not all code has been modified yet to benefit this,
actually only very little, the most performance-impacting ones.

This fixes SQUIT of a server with 100k users in a single channel taking
40 seconds of 100% CPU. It now takes only 1 second.
Reported by craftxbox in https://bugs.unrealircd.org/view.php?id=6484

(Can't make member & membership one entry atm, that would be too much change in U6)
2025-10-05 08:32:43 +02:00
Bram Matthys 68ef88c0c4 Move from HOOKTYPE_VISIBLE_IN_CHANNEL to invisible setting in member->memb_flags.
This so we can use fast(er) techniques here and there.

New functions are:
channel_has_invisible_users(client)
set_user_invisible(client, channel, 1|0)
Existing functions:
invisible_user_in_channel(client, channel)
user_can_see_member(user, target, channel)
user_can_see_member_fast()

This is work in progress, although the tests seem to pass atm.
2025-10-04 20:33:46 +02:00
Bram Matthys 569a12055f Add channel->local_members and use it in sendto_channel().
This makes things a lot faster on multi-server networks, especially for
big channels where most of the clients in the channel are remote users.

This should be non-module-API-breaking, as all code uses the
add_user_to_channel() and remove_user_from_channel() functions.

Still need to spread this to other code, more optimizations possible.
2025-10-03 18:11:03 +02:00
Bram Matthys 86e7ab307a Bump dbufs from 4k to 8k. Gives a 5% performance improvement.
That is, during my tests with 1000 TLS clients doing a couple of commands,
including one big one (WHO #channel on a 1000 user channel).

I also tested an SSL_writev() implementation (which would gather up to 16k)
but it gives very comparable speed and caries more risk of doing so in a
stable series. I think we can live with the 4 kilobyte extra per local
client in the year 2025 (and later).
2025-10-03 16:11:52 +02:00
Bram Matthys c0a46abd60 ModData API: add ModDataInfo .priority item and use it to speed up
things by making the keys with the most lookups first, e.g. "reputation",
"geoip", "certfp". This order is based on actual lookup counts during a
quick test with 250 clones doing some typical IRC traffic.

Key:		Lookups:	Position before:	After split:	After split+order:
"reputation"	20362		37			14		1
"geoip"		10555		44			15		2
"certfp"	9264		23			8		3
"webirc"	7407		27			10		4
"websocket"	7110		55			19		5

We could also consider going for a hash table, but this may be "good enough" for now.
2025-09-29 16:50:44 +02:00
Bram Matthys db6476e1ab ModData API (internal): split the single linked list into 7 lists, to speed
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.
2025-09-29 16:22:08 +02:00
Bram Matthys c8431b7cb8 Make client->local->caps a 64 bit unsigned int on all archs.
This was previously a "long", which could cause issues on 32 bit archs.
We ship with 28 CAPs now, and that's without 3rd party modules, so...

This is similar to the client->flags bumping in 2023
(a3ed1eabd9).
2025-09-28 10:03:04 +02:00
Bram Matthys 602f6c7238 URL API: add .minimum_tls_version, and use TLS1_3_VERSION for central-blocklist.
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.
2025-09-21 14:24:06 +02:00
Bram Matthys 507061af46 Add tls-options::signature-algorithms for those who want to override the default.
We don't set it in UnrealIRCd at the moment, so this is just to override
the OpenSSL defaults at the moment. It is good to have this exposed, in
case some vulnerability is discovered or you need some flexibility in
tweaking this.
2025-09-21 13:55:24 +02:00
Bram Matthys b0b6cc81e2 This belongs to the autoconf upgrade too (see previous) 2025-09-21 13:39:12 +02:00
Bram Matthys 4c6e259681 You can now use "password" multiple times in the conf (eg in allow::password).
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; };
...
}
2025-09-21 11:42:59 +02:00
Bram Matthys 877d151da4 Support multiple TLS certificates/keys, e.g. ECDSA + ML-DSA (PQC).
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).
2025-09-21 10:32:29 +02:00