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

477 Commits

Author SHA1 Message Date
Bram Matthys b785d69309 Fixes after clang-format, as planned. These are whitespace only.
These were not a surprise, but deliberate: we let the previous
clang-format commit be 100% clang-format job (so reproducable)
and after that we planend and did this commit, because we chose
to leave some stuff alone and do it manually.

This commit will (also) be added to .git-blame-ignore-revs
2026-07-05 12:28:37 +02:00
Bram Matthys 548d66d26c Reformat all source code, using 'make format' (clang-format 21.1.8)
This reformats entire UnrealIRCd source code, according to
.clang-format which was previously commited.

This is reproducable using clang-format version 21.1.8.

These are only visual changes, they have no effect on code.

This commit will be added to .git-blame-ignore-revs so 'git blame'
and the similar blame view on GitHub will ignore this commit.
2026-07-05 12:11:51 +02:00
Bram Matthys 3c6b552df5 More preparations for clang-format: a few long and multi-line comments
were changed so when we run 'make format' in the future it looks better.
2026-07-05 09:13:56 +02:00
Bram Matthys 27f6eaf474 More preparations for clang-format: move some #define outside of a group
Because otherwise they all line up.. even though they are completely
unrelated (clang-format doesn't know that :D, it needs a empty line)
2026-07-04 21:17:56 +02:00
Bram Matthys 684f6515d4 "CAP LS" may only respond 1 line, we now advertise less. "CAP LS 302" unaffected.
When not using version 302, such as with "CAP LS", the specification does not
allow us to use continuation lines. This means all advertised caps must fit
into one line. That is no longer always the case, especially if you load 3rd
party capabilities. So we need to scratch advertising some capabilities to
<302 clients.

"CAP LS 302" is unaffected. Note that version 302 in the specification exists
since at least November 2017, so most clients use that one.

According to https://ircv3.net/software/clients the following clients are
affected by this change:

Desktop Clients
* KVIrc
* Circe
* catgirl
* BitchX
* Pidgin
* LimeChat

Mobile Clients
* IRC for Android
* LimeChat

And various older versions of other clients (obviously).

NOTE: The source is only that IRCv3 page. I did not check manually.

For this particular commit. We filter out various unrealircd.org informative
CAPs and the vendor specific json-log. So that isn't much of a problem.
However, in the future we may be forced to filter out more capabilities to
make room. It would be much better if all clients are on >=302. Also, I
should mention we are not the only IRCd out there, so I can't vouch on what
other IRCds (will) do when hitting this non-302-limit.

Reported by ProgVal in https://bugs.unrealircd.org/view.php?id=6630
2026-06-22 09:19:38 +02:00
Bram Matthys 09a732e2c1 Redo draft/chathistory-end from yesterday in a different way.
The previous mechanism (from yesterday) was a bit too simple at the
chathistory.c where returned_lines < limit would set the end tag but
it would not deal with the situation where returned_lines == limit
which is ambigious. So we had to move up a layer (or is it down?),
don't handle this in chathistory.c but in the backend. A new struct
field r->reached_end was added for this (set by backend).
2026-06-20 08:32:28 +02:00
Bram Matthys 1162da4a9e * Server linking and certificates: we now treat listener blocks that are
`serversonly` (such as port 6900 in the example.conf) and link { } blocks
  in a different way than regular listen { } blocks:
  * If there are different certificates used in the serversonly listen block
    vs link blocks, then this is almost always means server linking is broken,
    so we now print a warning on boot and rehash.
  * We also print an 'advice' if any of these are not using (long-lived)
    self-signed certificate. This is because CA issued certificates are
    typically not suitable because they typically rotate keys and thus change
    the `spkifp`. Changing spkifp breaks server linking. We will now print
    an advice along with command and config block instructions to fix it.
  * We now use `set::server-linking::tls-options` for link { } blocks
    and listen { } blocks that are `serversonly`. All the rest uses the
    `set::tls` settings by default (eg the regular listen { } block on 6697).
    * This means our guide on
      [Using Let's Encrypt with UnrealIRCd](https://www.unrealircd.org/docs/Using_Let's_Encrypt_with_UnrealIRCd)
      and generic usage is more intuitive. You just set both set settings
      and then no longer need to use any tls-options in listen blocks or link
      blocks. The example conf has also been updated with this.
    * If `set::server-linking::tls-options` is not configured, it defaults
      to `set::tls`, so there is no unexpected behavior change for anyone.
  * In a future release we will make server linking with `spkifp` mandatory,
    so all of this helps with getting people ready for that, making such
    a future transition smooth.

TODO: Update wiki, better wording in release notes, etc.

This also changes the default example conf:

/* RECOMMENDED:
 * Everyone should be using IRC over SSL/TLS on port 6697. However, to use
 * it properly, you have to get a "real" certificate instead of the
 * self-signed default certificate that was generated by the installer.
 * The Let's Encrypt initiative allows you to get a free certificate that is
 * issued by a trusted Certificate Authority. Instructions are at:
 * https://www.unrealircd.org/docs/Using_Let's_Encrypt_with_UnrealIRCd
 *
 * When you follow that guide you will have a "dual certificate" setup:
 * set::tls:
 *   Your trusted CA certificate, served to clients on port 6697.
 *   (key and certificate change and renew every xx days automatically)
 * set::server-linking::tls-options
 *   A long-lived self-signed certificate for server linking, with
 *   a stable 'spkifp' signature that you use in link blocks.
 *   This certificate is used automatically in "serversonly" listen blocks
 *   (port 6900 in this configuration file) and automatically used for all
 *   link { } blocks.
 *
 */
//set {
//      tls {
//              certificate "/etc/letsencrypt/live/irc.example.org/fullchain.pem";
//              key "/etc/letsencrypt/live/irc.example.org/privkey.pem";
//      }
//      server-linking {
//              tls-options {
//                      certificate "tls/server.cert.pem";
//                      key "tls/server.key.pem";
//              }
//      }
//}
2026-06-16 20:50:56 +02:00
Bram Matthys 65f918e8e9 Add json_expand_flood_counts() and make available in Central Spamreport
and JSON-RPC.

This exposes the newly added flood counters from
4384f1127b and
029675f867 in JSON.

I didn't want to put it in every JSON log message. So right now it
is only in:
* JSON-RPC with object_detail_level >= 5.
* Central Spamreport

I may expand it later to one or a few other areas.
2026-06-13 12:09:09 +02:00
Bram Matthys 029675f867 Similar to previous, add total_channel_flood_count() for +f/+F limits exceeded
* `total_channel_flood_count('..setting..')` returns the number of
  times `+f`/`+F` limits were exceeded by that user in all channels
  the user is or was in. Available are: `nick`, `join`, `knock`, `msg`,
  `ctcp`, `text`, `repeat` and `paste` (and `all` for the sum).
2026-06-13 07:46:51 +02:00
Bram Matthys 4384f1127b Crule: new server_flood_count() for nick, away, join etc floods.
Suggested by westid in https://bugs.unrealircd.org/view.php?id=6477

* New [crule function](https://www.unrealircd.org/docs/Crule) that return
  the number of times a flood was blocked for that user. For example,
  `server_flood_count('away')` returns the number of time away-flood
  was exceeded. Aslo available: `nick`, `join`, `invite`, `knock`,
  `vhost` and `conversations`. Plus, there is `all` for a total of all.
  * This can be used in a security-group::rule or spamfilter::rule.
    Eg: `spamfilter { rule "server_flood_count('nick')>4"; action gline; }`

This also - internally - adds a mechanism to run spamfilter rule-only-
filters after the command handler, whenever a tag value or other thing
changed. That's part of this commit.
2026-06-12 17:43:51 +02:00
Bram Matthys faecdd66cd Config-file based *LINES/Spamfilter: preserve hit counters between rehashes.
Unlike non-config-based TKLs - which go through tkldb - they are still not
preserved through restarts. But at least they are not lost due to REHASH.
This is done via a save+restore, a bit complicated, but we have little
choice (other than not doing this at all).

This also moves remove_config_tkls() from conf.c to tkl.c
2026-06-10 14:30:39 +02:00
Bram Matthys d5b799d3de Server bans and Spamfilters now track how often they are hit and the time
of the last hit, eg in `STATS gline` for GLINEs. These counts happen on
each individual server and are not network-wide. This allows IRCOps to see
which entries never get any hits and can potentially be removed.
* Important exception: config-based spamfilters/bans lose their counters
  on `REHASH` and restart atm.
* For non-config TKLs, the hit count and last hit timestamp are preserved
  across reboots (via tkldb).
* Again, see *Developers and protocol* for the exact STATS field.

The spamfilter hits already existed but all the rest is new.

Suggested by BlackBishop in https://bugs.unrealircd.org/view.php?id=6304
(in particular, time of the last hit)
2026-06-08 13:44:00 +02:00
Bram Matthys bc086e3ffe Add and update doxygen docs for module API 2026-04-04 19:40:03 +02:00
Bram Matthys 36baf946a3 Guard against multiline+history amplification attacks in CHATHISTORY.
Add a little fake lag based on history result: 400ms for 50 lines
under normal conditions where 50 lines = 50 lines. But this can go
up to 5000ms for worst-case amplification attacks where requesting
50 lines actually returns 50*15=750 lines when each line is a multiline
with max-lines, which gets you close to 350k+. This would only happen
if someone on the channel is doing evil stuff (with presumably consent
of the ops).

Also guard against hiting max sendq. If we are too close, then we
reject the CHATHISTORY request rather than quiting with "Max SendQ
exceeded". This protects against an attack where someone would be
tricked into joining a channel with amplified history (as explained
in previous paragraph), their client would do an automatic CHATHISTORY
request and then the victim would exceed max sendq and thus be killed.

And yes, this and maaaaany other multiline + history interactions
and many "buts" and security/flood concerns are why this implemtnation
took (and still takes) a lot of hours to get right :D.
2026-04-03 07:59:11 +02:00
Bram Matthys a1dc459a33 Update +H limit and write release notes regarding draft/multiline support.
For +H we now temporarily allow overshooting. This only matters for low limits.
Multiline batches are atomic so we have to choose to keep them as a whole
or remove the complete batch. So if +H 5:1h and the last message was a 15-line
multiline event, what do we do? We allow temporary overshooting to store the
15 lines. As said, the alternative would be to store 0 lines which would be
worse in terms of functionality, and the small overshoot is defensible.

For higher limits (where the +H line limit is bigger than multiline max-lines),
we always stay under the +H limit. Eg if all history in a channel consists
of 15 line multiline events and we have +H 100 then we will store 90, not 105.
It's only for +H linelimit < max-lines that this matters, because there the
zero-lines consequence sucks too much ;)
2026-04-02 20:24:21 +02:00
Bram Matthys 8c0590cda2 Add multiline support in history. 2026-03-30 19:09:20 +02:00
Bram Matthys 1df465a6a5 Add +f subtype 'p' (for 'paste'). So [2p]:15 means max 2 pastes per 15s.
This way you can limit the number of pastes going on in a channel, as
this is from everyone in that channel (like 'm') not individual (like 't').
If it is exceeded then we will simply reject the BATCH, similar to
how action d(rop) works for some other subtypes. You won't see the paste
on the channel, only the sending user receives an error (MULTILINE_PASTE_LIMIT).

Small note: a multiline BATCH of just 2 lines is not considered a paste.
We consider a multiline of 3+ lines as a paste. I think that is reasonable,
since a two-line-multiline is not that much of a paste ;).

In the default anti-flood profile (+F normal) we also set 2p per 15s,
so this means channels are by default limited to 2 pastes per 15s max.
Of course, you can override this with +f [4p]:15 or whatever you like.
In terms of +F profiles, the defaults are (maximum x pastes per 15 seconds):
very-strict: 1p
strict: 1p
normal: 2p
relaxed: 2p
very-relaxed: 3p
2026-03-30 14:55:03 +02:00
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 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 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 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 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
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 c1dff43c8d Make the "ModDataAdd: out of space" error message more helpful 2025-10-15 08:31:27 +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 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 dbb2d1a5c8 Move isupport_check_for_changes() to the 'isupport' module.
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.
2025-09-20 15:44:56 +02:00
Bram Matthys e78a6a6dbf isupport & extended-isupport module, work in progress.
This is mostly from Valware PR https://github.com/unrealircd/unrealircd/pull/310
Will do more changes in later commits..
2025-09-20 14:34:28 +02:00
Bram Matthys 96a2ea5c02 Add HOOKTYPE_BANNED_CLIENT 2025-07-12 18:06:52 +02:00
Val Lorentz 5aec83b444 Fix mismatched closing parenthesis (#314) 2025-07-06 14:53:00 +00:00
Bram Matthys cb17d58db0 Some small changes to previous commit:
* 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
2025-07-06 09:19:04 +02:00
Valerie Liu 6a6dd66c84 Add HOOKTYPE_CAN_USE_NICK to allow modules to reject certain nicks (#313)
* Add `HOOKTYPE_CAN_USE_NICK` for modules to disallow certain "internal-use" nicks
* Run the hook on local NICK commands
2025-07-06 07:10:58 +00:00
Valerie Liu 5d7feff725 Fix HOOKTYPE_PRE_CHANMSG refering to hooktype_can_send_to_user()
as an alternative. It should mention hooktype_can_send_to_channel() instead.
2025-04-14 15:30:51 +00:00
Bram Matthys 74e17b7a26 Make SPAMINFO show the UTF8 block names a text uses.
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
2025-03-23 13:03:58 +01:00
Bram Matthys 9691a6d819 Create TextAnalysis framework (hook), this counts the unicode block
switches like antimixedutf8 did, and counts the number of characters
used per unicode block. Potentially more can be added later, this is
flexible and modules can add stuff (..well not yet.. the struct is
missing some members..).

Use it from antimixedutf8 so that it now uses the new code, which is
similar to what I made and then reverted in July 2023:
https://github.com/unrealircd/unrealircd/commit/3e2f668f10fccedfd035526d7b20d7ca6819a8ae
..except that it now calculated in src/modules/utf8functions.c.
But yeah, this needs more testing and possibly (default) score
adjustments to deal with false positives !! And a warning in release notes :D

Put the text analysis in ClientContext member textanalysis,
so typically accessed through clictx->textanalysis.
Note that this struct can (and often is) NULL, for example if it is
a remote client, if it is not a PRIVMSG/NOTICE (will improve later)
or if the utf8functions module is not loaded (to keep things optional).

BREAKING CHANGE is that ClientContext is now passed in the
HOOKTYPE_CAN_SEND_TO_CHANNEL and HOOKTYPE_CAN_SEND_TO_USER hooks.

So HOOKTYPE_CAN_SEND_TO_USER prototype changed from:
int hooktype_can_send_to_user(Client *client, Client *target, const char **text, const char **errmsg, SendType sendtype);
To:
int hooktype_can_send_to_user(Client *client, Client *target, const char **text, const char **errmsg, SendType sendtype, ClientContext *clictx);

And HOOKTYPE_CAN_SEND_TO_CHANNEL prototype changes from:
int hooktype_can_send_to_channel(Client *client, Channel *channel, Membership *member, const char **text, const char **errmsg, SendType sendtype);
To:
int hooktype_can_send_to_channel(Client *client, Channel *channel, Membership *member, const char **text, const char **errmsg, SendType sendtype, ClientContext *clictx);

A side-affect of this change for antimixedutf8 purposes is that,
while the analysis is only done once per line, the 'actions' are
performed for each target, so the action will run 4 times for
"PRIVMSG a,b,c,d :text" although that may not be important in
practice. Just mentioning.
2025-03-23 11:44:24 +01:00
Bram Matthys 9b3d219743 Add utf8functions with utf8_convert_confusables() from July 16 2023.
I started work on this back then but didn't finalize it. Now I
have to figure out what was left to be done :D. Other than the
obvious case of seeing some debugging code that prints out for
every converted character. Not yet visible / usable by end-users!
2025-03-22 07:56:11 +01:00
Bram Matthys 8c21472d03 Move allow::maxperip to its own module (maxperip), add HOOKTYPE_ALLOW_CLIENT.
Also fix documentation for ~10 hooks to mention the hook name.

Obviously, the maxperip module is loaded by default (in modules.default.conf)
but it is nice to have the 400+ lines contained in a separate module
rather than being in the nick module that does NICK/UID handling.
Will look at moving more later..
2025-03-22 07:42:00 +01:00
Bram Matthys b95c1570a9 Add CONFIG_ALLOW_BLOCK & CONFIG_CLASS in HOOKTYPE_CONFIGTEST and
HOOKTYPE_CONFIGRUN_EX. Allowing to modularize things (for us and
third party modules)
2025-03-22 06:39:44 +01:00
Bram Matthys d15c82346e Pass ClientContext in CMD_FUNC() and friends. So extra arg. Breaking change.
It now passes 'clictx' which at the moment only has clictx->cmd which
points to the command handler. So only useful in very few cases where
you have like a generic command handler and thus have no idea for which
command you are being called. In the future, with this new ClientContext
struct, we can simply add new fields to the struct without breaking
things in the core and in (third party) modules.

If you use the magic functions in your modules CMD_FUNC(cmd_mycmd),
OVERRIDE_FUNC(myoverride), CALL_NEXT_COMMAND_OVERRIDE() and such then
you shouldn't have any compile errors as these will use the correct
prototypes and variable names automatically. In a few cases you can't
use these, in which case you will need to update your modules.
2025-03-21 15:40:42 +01:00
Bram Matthys 6c98f7224a Always try to maintain chronological order in chat history, and optimize stuff.
Previously if a new history item was added (because someone sent a message)
we would always append at the end of chat history buffer of the channel.
Now we put the message at the position decided by the "time" message tag,
which could be at the end but also slightly before that.
* Upside: should result in a consistent chat history on all servers
* Downside: if your server time is off for several seconds then it
  could look a little weird. Then again, it would already have looked weird
  in real live chat with timestamps and when replaying chat history probably.

Also add some simple optimizations: in the log line object we now have direct
pointers to the msgid and time strings, so the code doesn't need to do a
find_mtag() all the time. This should lower CPU usage during log playback
and also makes things more simple in the source code.

I did some testing with various history injection variants but this needs
more extensive testing.
2024-11-27 10:34:07 +01:00
Bram Matthys 4557036cd6 Move unreal_expand_string() to an efunc so all code can access it
and use it not only from vhost { } block code but also for like
blacklist::reason.

This so the same variables with the same names are available at
those places.

Supported are:
$nick, $username, $realname, $ip, $hostname, $server, $account,
$operlogin, $operclass, $country_code (xx for unknown),
$asn (0 for unknown).
2024-09-20 17:13:23 +02:00
Bram Matthys c39d763e00 Move 416 lines from src/misc.c to src/modules/quit.c: exit_client() etc.
This so if there is ever an issue, we can hot-patch it. This affects
exit_client(), exit_client_fmt(), exit_client_ex(), banned_client(),
and various (internal) help functions.

This also means you cannot call these functions during TEST/INIT (eg
during REHASH) since the 'quit' module which provides these modules
may not be loaded yet. I don't think that's a situation/problem but
this needs some more testing.
2024-09-15 17:45:25 +02:00
Bram Matthys 4f3e524602 Add function set_client_ip() and call HOOKTYPE_IP_CHANGE there if needed.
This to replace the scattered IP setting. It is very important to always
use set_client_ip() from this point. Everywhere!

Also, in addition to client->ip, this adds client->rawip that contains
the IP in network byte order. In older UnrealIRCd versions we always had
the raw IP but not the IP as a string, so we moved to IP as a string,
but it can be useful to have both in terms of optimizations.
Of course, then the client->ip and client->rawip always need to 100% match,
hence the set_client_ip().

This also changes IsIPV6() to do A BUGFIX, it changes it from:
* if local user is the user connected over IPv6? Otherwise, does it have ':' in the IP?
To:
* check if the IPv6 flag is set (which is set if IP contains ':')
This may seem insignificant but it means that for spoofed IP addresses,
such as WEBIRC or transparant proxy, we use the correct transport.
Previously, if the proxy was IPv6 then even if the spoofed user was using
IPv4, the ident check would still be tried over IPv6. That sort of fun.
From now in, in such a situation client->local->socket_type will be
SOCKET_TYPE_IPV6 but since client->ip (and rawip) will contain IPv4
the IsIPV6() will actually return false, as it should be.

Also, in the HOOKTYPE_IP_CHANGE, enforce that if HOOK_DENY is returned,
the the user is killed by dead_link(). The user must be killed because
that is what we expect, and you cannot use exit_client() because from
some code paths that would be too much freed structures / hassle,
as a comment in src/modules/connect-flood.c correctly states:
/* There are two reasons why we can't use exit_client() here:
 * 1) Because the HOOKTYPE_IP_CHANGE call may be too deep.
 *    Eg: read_packet -> webserver_packet_in ->
 *    webserver_handle_request_header -> webserver_handle_request ->
 *    RunHook().... and then returning without touching anything
 *    after an exit_client() would not be feasible.
 * 2) Because in HOOKTYPE_ACCEPT we always need to use dead_socket
 *    if we want to print a friendly message to TLS users.
 */
2024-07-20 12:22:26 +02:00
Bram Matthys e12559ad78 Allow modules to provide SASL locally, by hooking into AUTHENTICATE.
Note that this is still a dumb interface and not a real proper
authentication framework.

This adds HOOKTYPE_SASL_AUTHENTICATE and HOOKTYPE_SASL_MECHS and
also provides 3 functions: sasl_succeeded(), sasl_failed() and
a helper function decode_authenticate_plain() for AUTHENTICATE PLAIN.
2024-05-13 13:23:59 +02:00
Bram Matthys 4da58dde41 Update central spamreport, https://www.unrealircd.org/docs/Central_spamreport
set::central-blocklist::spamreport and ::spamreport-enabled are now GONE.
We now require a normal spamreport block, just like for other spamreport
functionality. So, if you want to enable this feature, use:
spamreport unrealircd { type central-spamreport; }

See https://www.unrealircd.org/docs/Central_spamreport for all info.

You can use CBL with central spamreport or central spamreport without CBL.
All explained at that URL.
2023-11-25 11:50:25 +01:00
Bram Matthys bdfc3c97dd Add RegisterApiCallbackResolverHost() and make blacklist module non-PERM.
Hopefully this works OK... still need to test w/REHASH to see.
2023-11-25 09:39:50 +01:00
Bram Matthys 6ce1958e1c Add URL API and use it at one place from central-blocklist. Docs at:
https://www.unrealircd.org/docs/Dev:URL_API
2023-11-25 08:31:12 +01:00
Bram Matthys be586531bc Make get_central_api_key() an efunction rather than doing things by hooks.
An efunction with a default that returns NULL, so you don't need to
load the module if you don't want the functionality.
2023-11-24 09:24:10 +01:00
k4be fb6711c671 Improve MONITOR/WATCH extensibility.
The `watch-check` function now has a new argument which can be used to pass data to watch_notify callbacks.
New `watch_add` and `watch_del` hooks are called whenever new entries are created or removed.
New `monitor_notification` hook is called whenever a RPL_MONONLINE or RPL_MONOFFLINE is being sent, so a module can add its own notification besides it.
2023-11-19 14:01:16 +01:00