1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-06-12 17:34:46 +02:00

New snomask 'x' (set by default): maxperip/connthrottle connect rejections

When a client is rejected by maxperip (not new) or connthrottle
ipv6-unknown-users-limit (that one is new), a notice to +s +x will be sent.

maxperip ipv4 example:
*** Client testuser4 with IP 1.2.3.4 rejected: maxperip limit exceeded (4 global, max 3)

maxperip ipv6 with /64 example:
*** Client testuser4 with IP 2001:dbe:0:0:0:0:0:4 rejected: maxperip limit exceeded for 2001:dbe::/64 (4 local, max 3)

connthrottle example where /56 limit is exceeded:
*** Client testuser5 with IP 2001:db8:cafe:abcd:0:0:0:5 rejected:
    connthrottle ipv6-unknown-users-limit (cidr-56, max 4) exceeded for
    2001:db8:cafe::/56 (5 unknown / 0 excepted / 0 known)

Oh and this commit also fixes a typo in existing CONNTHROTTLE events,
which previously were CONNTHROTLE (a missing T).
This commit is contained in:
Bram Matthys
2026-05-05 16:30:11 +02:00
parent 0940ed5d13
commit f765905b15
6 changed files with 70 additions and 6 deletions
+11
View File
@@ -201,6 +201,17 @@ log {
}
}
/* Connection-limit rejections (maxperip / connthrottle) - 'x' */
log {
source {
connthrottle.CONNTHROTTLE_IPV6_LIMIT;
maxperip.MAXPERIP_LIMIT;
}
destination {
snomask x;
}
}
/* Snomask s (server notices) - the "catch all" snomask for all other things */
log {
source {
+1
View File
@@ -530,6 +530,7 @@ extern const char *inetntop(int af, const void *in, char *local_dummy, size_t th
extern void mask_ipv6_rawip(const char *src, int prefix, char *dst);
extern const char *get_clone_mask_ipstr(Client *client, char *buf, size_t buflen);
extern const char *format_ipv6_prefix_reject_message(const char *template, const char *masked_rawip, int prefix);
extern const char *format_ipv6_addr(const char *rawip);
extern void delletterfromstring(char *s, char letter);
extern void addlettertodynamicstringsorted(char **str, char letter);
+1 -1
View File
@@ -448,7 +448,7 @@ typedef enum ClientStatus {
#define CLIENT_FLAG_IPV6 0x800000000 /**< client is using IPv6 */
/** @} */
#define OPER_SNOMASKS "+bBcdfkqsSoO"
#define OPER_SNOMASKS "+bBcdfxkqsSoO"
#define SEND_UMODES (SendUmodes)
#define ALL_UMODES (AllUmodes)
+16
View File
@@ -976,3 +976,19 @@ const char *format_ipv6_prefix_reject_message(const char *template,
buildvarstring(template, buf, sizeof(buf), vars, values);
return buf;
}
/** Format an IPv6 raw address as a compressed string (e.g. "2001:db8::").
*
* Returns a pointer to internal static storage, overwritten on each call.
*
* @param rawip 16-byte raw IPv6 address.
* @return inet_ntop result, or "?" on failure.
*/
const char *format_ipv6_addr(const char *rawip)
{
static char buf[128]; /* generously oversized; longest IPv6 string form is ~46 chars */
if (!inet_ntop(AF_INET6, rawip, buf, sizeof(buf)))
strlcpy(buf, "?", sizeof(buf));
return buf;
}
+15 -5
View File
@@ -559,7 +559,7 @@ EVENT(connthrottle_evt)
if (ucounter->rejected_clients)
{
unreal_log(ULOG_INFO, "connthrottle", "CONNTHROTLE_REPORT", NULL,
unreal_log(ULOG_INFO, "connthrottle", "CONNTHROTTLE_REPORT", NULL,
"ConnThrottle] Stats for this server past 60 secs: "
"Connections rejected: $num_rejected. "
"Accepted: $num_accepted_except except user(s) and "
@@ -615,7 +615,7 @@ int ct_pre_lconnect(Client *client)
/* We send the LARGE banner if throttling was activated */
if (!ucounter->throttling_previous_minute && !ucounter->throttling_banner_displayed)
{
unreal_log(ULOG_WARNING, "connthrottle", "CONNTHROTLE_ACTIVATED", NULL,
unreal_log(ULOG_WARNING, "connthrottle", "CONNTHROTTLE_ACTIVATED", NULL,
"[ConnThrottle] Connection throttling has been ACTIVATED due to a HIGH CONNECTION RATE.\n"
"Users with IP addresses that have not been seen before will be rejected above the set connection rate. Known users can still get in.\n"
"or more information see https://www.unrealircd.org/docs/ConnThrottle");
@@ -745,7 +745,7 @@ void ct_off(Client *client)
return; /* Already off */
ucounter->disabled = 1;
unreal_log(ULOG_WARNING, "connthrottle", "CONNTHROTLE_MODULE_DISABLED", client,
unreal_log(ULOG_WARNING, "connthrottle", "CONNTHROTTLE_MODULE_DISABLED", client,
"[ConnThrottle] $client.details DISABLED the connthrottle module.");
}
@@ -754,7 +754,7 @@ void ct_on(Client *client)
if (!ucounter->disabled)
return; /* Already on */
unreal_log(ULOG_WARNING, "connthrottle", "CONNTHROTLE_MODULE_ENABLED", client,
unreal_log(ULOG_WARNING, "connthrottle", "CONNTHROTTLE_MODULE_ENABLED", client,
"[ConnThrottle] $client.details ENABLED the connthrottle module.");
ucounter->disabled = 0;
}
@@ -762,7 +762,7 @@ void ct_on(Client *client)
void ct_reset(Client *client)
{
memset(ucounter, 0, sizeof(UCounter));
unreal_log(ULOG_WARNING, "connthrottle", "CONNTHROTLE_RESET", client,
unreal_log(ULOG_WARNING, "connthrottle", "CONNTHROTTLE_RESET", client,
"[ConnThrottle] $client.details did a RESET on the statistics/counters.");
}
@@ -1245,9 +1245,19 @@ const char *ct_allow_client(Client *client, ConfigItem_allow *aconf)
ct_make_rawip(client, tier, masked);
b = ct_find_bucket(tier, masked);
if (b && (b->unknown_users > effective_limit))
{
unreal_log(ULOG_INFO, "connthrottle", "CONNTHROTTLE_IPV6_LIMIT", client,
"Client $client.name with IP $client.ip rejected: connthrottle ipv6-unknown-users-limit (cidr-$prefix_len, max $max) exceeded for $prefix_addr/$prefix_len ($unknown_users unknown / $excepted_users excepted / $known_users known)",
log_data_string("prefix_addr", format_ipv6_addr(masked)),
log_data_integer("prefix_len", ct_tier_prefix[tier]),
log_data_integer("max", effective_limit),
log_data_integer("unknown_users", b->unknown_users),
log_data_integer("excepted_users", b->excepted_unknowns),
log_data_integer("known_users", b->known_users));
return format_ipv6_prefix_reject_message(
iConf.reject_message_too_many_new_connections_ipv6_range,
masked, ct_tier_prefix[tier]);
}
}
return NULL;
+26
View File
@@ -459,14 +459,40 @@ const char *maxperip_allow_client(Client *client, ConfigItem_allow *aconf)
{
if (exceeds_maxperip(client, aconf))
{
IpUsersBucket *bucket = find_ipusers_bucket(client);
if (IsIPV6(client) && iConf.default_ipv6_clone_mask < 128)
{
char masked[16];
mask_ipv6_rawip(client->rawip, iConf.default_ipv6_clone_mask, masked);
if (bucket && bucket->local_clients > aconf->maxperip)
unreal_log(ULOG_INFO, "maxperip", "MAXPERIP_LIMIT", client,
"Client $client.name with IP $client.ip rejected: maxperip limit exceeded for $prefix_addr/$prefix_len ($count local, max $max)",
log_data_string("prefix_addr", format_ipv6_addr(masked)),
log_data_integer("prefix_len", iConf.default_ipv6_clone_mask),
log_data_integer("count", bucket->local_clients),
log_data_integer("max", aconf->maxperip));
else
unreal_log(ULOG_INFO, "maxperip", "MAXPERIP_LIMIT", client,
"Client $client.name with IP $client.ip rejected: maxperip limit exceeded for $prefix_addr/$prefix_len ($count global, max $max)",
log_data_string("prefix_addr", format_ipv6_addr(masked)),
log_data_integer("prefix_len", iConf.default_ipv6_clone_mask),
log_data_integer("count", bucket ? bucket->global_clients : 0),
log_data_integer("max", aconf->global_maxperip));
return format_ipv6_prefix_reject_message(
iConf.reject_message_too_many_connections_ipv6_range,
masked, iConf.default_ipv6_clone_mask);
}
if (bucket && bucket->local_clients > aconf->maxperip)
unreal_log(ULOG_INFO, "maxperip", "MAXPERIP_LIMIT", client,
"Client $client.name with IP $client.ip rejected: maxperip limit exceeded ($count local, max $max)",
log_data_integer("count", bucket->local_clients),
log_data_integer("max", aconf->maxperip));
else
unreal_log(ULOG_INFO, "maxperip", "MAXPERIP_LIMIT", client,
"Client $client.name with IP $client.ip rejected: maxperip limit exceeded ($count global, max $max)",
log_data_integer("count", bucket ? bucket->global_clients : 0),
log_data_integer("max", aconf->global_maxperip));
return iConf.reject_message_too_many_connections;
}
return NULL;