Add specification for channel flood limits#589
Add specification for channel flood limits#589ValwareIRC wants to merge 2 commits intoircv3:masterfrom
Conversation
This document outlines the specification proposed for channel flood limits, detailing how servers can advertise flood protection limits to clients and how privileged clients can set additional limits
Added metadata for title, layout, and copyright information.
There was a problem hiding this comment.
Pull request overview
Adds a new IRCv3 extension specification describing how servers can advertise per-channel flood protection limits to clients and how privileged clients can set additional channel flood limits, enabling clients to rate-limit user actions proactively.
Changes:
- Introduces the
draft/channel-flood-limitscapability and theCHANLIMITSmessage (server-to-client and client-to-server semantics). - Specifies multi-source merging rules, per-user personalization behavior, and a batch-based delivery mechanism for long limit sets.
- Adds examples, ABNF grammar, and security considerations for parsing and validating advertised limits.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| --- | ||
| title: "Channel Flood Limits" | ||
| layout: spec | ||
| work-in-progress: true | ||
| copyrights: | ||
| - | ||
| name: "Valware" | ||
| period: "2026" | ||
| email: "v.a.pond@outlook.com" |
There was a problem hiding this comment.
This new spec file doesn't include the YAML front matter used by the rest of the extensions/*.md specs (---, title:, layout: spec, work-in-progress: true, copyrights:, etc.). Without it, the site generator will likely not apply the standard spec layout/metadata and may render incorrectly. Please convert the top-of-file header/copyright block into front matter matching the established pattern in other extension specs.
| The `draft/channel-flood-limits` capability does not depend on any other | ||
| capability, but works well alongside: | ||
|
|
||
| - [batch](https://ircv3.net/specs/extensions/batch): Required for delivering | ||
| limits that exceed a single IRC line. Servers MUST support batch if they | ||
| advertise `draft/channel-flood-limits`. |
There was a problem hiding this comment.
The spec says draft/channel-flood-limits "does not depend on any other capability", but later requires batch to deliver limits that exceed one IRC line. Since BATCH messages are only legal after negotiating the batch capability, this needs to be specified as an explicit dependency (e.g., clients MUST negotiate batch when requesting draft/channel-flood-limits, and servers MUST NOT ACK the capability unless batch is also enabled).
| The `draft/channel-flood-limits` capability does not depend on any other | |
| capability, but works well alongside: | |
| - [batch](https://ircv3.net/specs/extensions/batch): Required for delivering | |
| limits that exceed a single IRC line. Servers MUST support batch if they | |
| advertise `draft/channel-flood-limits`. | |
| The `draft/channel-flood-limits` capability depends on the | |
| [`batch`](https://ircv3.net/specs/extensions/batch) capability. Clients MUST | |
| negotiate `batch` when requesting `draft/channel-flood-limits`, and servers | |
| MUST NOT ACK `draft/channel-flood-limits` unless `batch` is also enabled. | |
| This capability also works well alongside: |
|
|
||
| ### Batch type | ||
|
|
||
| This specification adds the `chanlimits` batch type for use with the | ||
| [batch](https://ircv3.net/specs/extensions/batch) extension. | ||
|
|
||
| When the effective limits for a channel have many limit types and would exceed | ||
| the 512-byte IRC message limit, the server MUST use a batch to deliver them: | ||
|
|
||
| ``` | ||
| :irc.example.com BATCH +ref chanlimits #channel | ||
| @batch=ref :irc.example.com CHANLIMITS #channel channel:message=40/15,join=30/15,nick=8/15,ctcp=7/15,knock=10/15 | ||
| @batch=ref :irc.example.com CHANLIMITS #channel user:message=5/15,repeat=3/15 | ||
| :irc.example.com BATCH -ref |
There was a problem hiding this comment.
Because this is a work-in-progress spec, the newly-defined batch type name should follow the same draft-prefixing approach used elsewhere (e.g. draft/multiline uses draft/multiline as the batch type name). Consider renaming chanlimits to draft/chanlimits for the draft, and reserving the unprefixed chanlimits name for the final/ratified version.
| ##### Client-to-server scopes (conditional) | ||
|
|
||
| Privileged clients (bots, services) use these scopes when *setting* limits via | ||
| client-to-server `CHANLIMITS`. They tell the server which users a limit should | ||
| target. The server resolves them per-user and folds the result into the `user` | ||
| scope it sends to each client. | ||
|
|
||
| | Scope | Description | | ||
| |----------------------|-------------| | ||
| | `user` | Applies to all users. | |
There was a problem hiding this comment.
The "Client-to-server scopes" section only lists conditional user-* scopes, but the rest of the spec (merge rules, limit types, and ABNF) implies privileged clients can also set channel-scoped limits. Please clarify whether channel is allowed client-to-server; if it is, document it in this table, and if it isn't, update the ABNF and earlier text to exclude it.
| ##### Client-to-server scopes (conditional) | |
| Privileged clients (bots, services) use these scopes when *setting* limits via | |
| client-to-server `CHANLIMITS`. They tell the server which users a limit should | |
| target. The server resolves them per-user and folds the result into the `user` | |
| scope it sends to each client. | |
| | Scope | Description | | |
| |----------------------|-------------| | |
| | `user` | Applies to all users. | | |
| ##### Client-to-server scopes | |
| Privileged clients (bots, services) use these scopes when *setting* limits via | |
| client-to-server `CHANLIMITS`. They tell the server which users or channels a | |
| limit should target. Conditional `user-*` scopes are resolved per-user and | |
| folded into the `user` scope the server sends to each client; the `channel` | |
| scope applies directly to the channel as a whole. | |
| | Scope | Description | | |
| |----------------------|-------------| | |
| | `user` | Applies to all users. | | |
| | `channel` | Applies to the channel as a whole. Privileged clients MAY set channel-scoped limits where permitted by server policy. | |
| scope = base-scope [ scope-param ] | ||
| / vendor-scope [ scope-param ] | ||
| base-scope = "channel" / "user" / "user-unvoiced" | ||
| / "user-unidentified" / "user-new" |
There was a problem hiding this comment.
The ABNF for scope allows an optional =... parameter for any base-scope, which would permit undefined forms like user=123, and also allows user-new without the required =<seconds> parameter. Tighten the grammar so only the intended scopes can carry parameters (at least user-new=<seconds>, and optionally vendor scopes if desired).
| scope = base-scope [ scope-param ] | |
| / vendor-scope [ scope-param ] | |
| base-scope = "channel" / "user" / "user-unvoiced" | |
| / "user-unidentified" / "user-new" | |
| scope = base-scope / param-scope | |
| base-scope = "channel" / "user" / "user-unvoiced" | |
| / "user-unidentified" | |
| param-scope = "user-new" scope-param | |
| / vendor-scope [ scope-param ] |
| count = 1*DIGIT ; positive integer | ||
| duration = 1*DIGIT ; positive integer, seconds | ||
|
|
There was a problem hiding this comment.
In the ABNF, count and duration are defined as 1*DIGIT, which permits 0, but the surrounding text calls these "positive integers" and the security section treats 0 as a special-case invalid value. Consider updating the grammar to require non-zero values (e.g. NZDIGIT *DIGIT) to match the semantics.
| count = 1*DIGIT ; positive integer | |
| duration = 1*DIGIT ; positive integer, seconds | |
| NZDIGIT = %x31-39 ; 1-9 | |
| count = NZDIGIT *DIGIT ; positive integer > 0 | |
| duration = NZDIGIT *DIGIT ; positive integer > 0, seconds |
|
I don't think this is a workable idea. Half of it is just reinventing channel modes to fix a deficiency with UnrealIRCd not telling users about default channel flood limits and the method for communicating flood methods isn't workable in practice because how flood methods work is vendor-specific meaning clients have to fall back to per-IRCd guesswork like they do currently. |
|
On Libera we explicitly do not publish our server configurations regarding flood limits/fakelag/etc., because it would otherwise provide an easy guideline for spambots to stay behind so they are more likely to evade network-wide detection and prevention measures for longer. These configurations are also subject to change without notice to respond to threats. We would not implement any form of this specification as written. I can potentially see a value for a specified channel metadata key for channel bots to publish their own limits in a consumable form, for channels who do wish to expose such limits publicly. This really wouldn't need any sort of client capability or additional commands though. |
|
Looks like a fairly complex spec for just communicating the flood limits and not enforcing them despite the server having to know and manipulate them all. I'm wondering if the extbans wouldn't be a better framework for both communicating and enforcing flood limits. All it would need is a new matching criterion on the number of message per unit of time. |
This document outlines the specification proposed for channel flood limits, detailing how servers can advertise flood protection limits to clients and how privileged clients can set additional limits