This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Undernet IRC Server Source Code.".
The branch, u2_10_12_branch has been updated
via 9122e6f50e7f672a3c034be9f8f205a8b610ded8 (commit)
from d3a0f0a3ae30b815c460002f127e57ed2fa5ad70 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 9122e6f50e7f672a3c034be9f8f205a8b610ded8
Author: Michael Poole <[email protected]>
Date: Tue Nov 22 23:25:19 2016 -0500
IPcheck: Rate-limit connections per IPv6 /48.
diff --git a/doc/readme.features b/doc/readme.features
index caed7ed..60cd3bf 100644
--- a/doc/readme.features
+++ b/doc/readme.features
@@ -839,6 +839,22 @@ to 10, then a user is only allowed to connect once in 10s,
if they connect
again within 10s, then they are considered to be connecting too fast and
they are throttled.
+IPCHECK_48_CLONE_LIMIT
+ * Type: integer
+ * Default: 50
+
+This is a limit that works like IPCHECK_CLONE_LIMIT, but for all
+clients connecting from a given IPv6 /48 block.
+
+IPCHECK_48_CLONE_PERIOD
+ * Type: integer
+ * Default: 10
+
+This is a timer that works like IPCHECK_CLONE_PERIOD, but for all
+clients connecting from a given IPv6 /48 block. The number of
+connection attempts allowed in this period is given by the
+IPCHECK_48_CLONE_LIMIT feature.
+
IPCHECK_CLONE_DELAY
* Type: integer
* Default: 600
diff --git a/include/ircd_features.h b/include/ircd_features.h
index 8c772a2..1c9da29 100644
--- a/include/ircd_features.h
+++ b/include/ircd_features.h
@@ -80,6 +80,8 @@ enum Feature {
FEAT_SOCKRECVBUF,
FEAT_IPCHECK_CLONE_LIMIT,
FEAT_IPCHECK_CLONE_PERIOD,
+ FEAT_IPCHECK_48_CLONE_LIMIT,
+ FEAT_IPCHECK_48_CLONE_PERIOD,
FEAT_IPCHECK_CLONE_DELAY,
FEAT_CHANNELLEN,
diff --git a/ircd/IPcheck.c b/ircd/IPcheck.c
index ec4d15c..d5f8307 100644
--- a/ircd/IPcheck.c
+++ b/ircd/IPcheck.c
@@ -55,6 +55,14 @@ struct IPRegistryEntry {
unsigned char attempts; /**< Number of recent connection
attempts. */
};
+/** Stores information about an IPv6/48 block's recent connections. */
+struct IPRegistry48 {
+ struct IPRegistry48* next; /**< Next entry in the hash chain. */
+ int last_connect; /**< Last connection attempt timestamp. */
+ uint16_t addr[3]; /**< 48 MSBs of IP address. */
+ unsigned short attempts; /**< Number of recent connection attempts. */
+};
+
/** Size of hash table (must be a power of two). */
#define IP_REGISTRY_TABLE_SIZE 0x10000
/** Report current time for tracking in IPRegistryEntry::last_connect. */
@@ -66,13 +74,21 @@ struct IPRegistryEntry {
#define IPCHECK_CLONE_LIMIT feature_int(FEAT_IPCHECK_CLONE_LIMIT)
/** Macro for easy access to configured IPcheck clone period. */
#define IPCHECK_CLONE_PERIOD feature_int(FEAT_IPCHECK_CLONE_PERIOD)
+/** Macro for easy access to configured /48 clone limit. */
+#define IPCHECK_48_CLONE_LIMIT feature_int(FEAT_IPCHECK_48_CLONE_LIMIT)
+/** Macro for easy access to configured 48 clone period. */
+#define IPCHECK_48_CLONE_PERIOD feature_int(FEAT_IPCHECK_48_CLONE_PERIOD)
/** Macro for easy access to configured IPcheck clone delay. */
#define IPCHECK_CLONE_DELAY feature_int(FEAT_IPCHECK_CLONE_DELAY)
/** Hash table for storing IPRegistryEntry entries. */
static struct IPRegistryEntry* hashTable[IP_REGISTRY_TABLE_SIZE];
+/** Hash table for storing IPRegistry48 entries. */
+static struct IPRegistry48* hashTable48[IP_REGISTRY_TABLE_SIZE];
/** List of allocated but unused IPRegistryEntry structs. */
static struct IPRegistryEntry* freeList;
+/** List of allocated but unused IPRegistry48 structs. */
+static struct IPRegistry48* freeList48;
/** Periodic timer to look for too-old registry entries. */
static struct Timer expireTimer;
@@ -239,6 +255,57 @@ static void ip_registry_expire_entry(struct
IPRegistryEntry* entry)
}
}
+/** Calculate hash value for an IP address's /48 block.
+ * @param[in] ip Address to hash; must be an IPv6 address.
+ * @return Hash value for address.
+ */
+static unsigned int ip_48_hash(const struct irc_in_addr *ip)
+{
+ unsigned int res;
+ res = ip->in6_16[0] ^ ip->in6_16[1] ^ ip->in6_16[2];
+ return res & (IP_REGISTRY_TABLE_SIZE - 1);
+}
+
+/** Find or create an IPv6 /48 entry for the IP address.
+ * @param[in] ip IPv6 address to search for.
+ * @return Matching registry entry (possibly newly created).
+ */
+static struct IPRegistry48* ip_48_find(const struct irc_in_addr *ip)
+{
+ struct IPRegistry48* entry;
+ unsigned int idx;
+
+ /* Does it exist in the chain? */
+ idx = ip_48_hash(ip);
+ for (entry = hashTable48[idx]; entry; entry = entry->next) {
+ if ((ip->in6_16[0] == entry->addr[0])
+ && (ip->in6_16[1] == entry->addr[1])
+ && (ip->in6_16[2] == entry->addr[2]))
+ goto done;
+ }
+
+ /* Where do we get the next entry? */
+ entry = freeList48;
+ if (entry)
+ freeList48 = entry->next;
+ else
+ entry = MyMalloc(sizeof(*entry));
+
+ /* Initialize this entry. */
+ entry->last_connect = NOW;
+ entry->addr[0] = ip->in6_16[0];
+ entry->addr[1] = ip->in6_16[1];
+ entry->addr[2] = ip->in6_16[2];
+ entry->attempts = 0;
+
+ /* Link it into the hash table. */
+ entry->next = hashTable48[idx];
+ hashTable48[idx] = entry;
+
+done:
+ return entry;
+}
+
/** Periodic timer callback to check for expired registry entries.
* @param[in] ev Timer event (ignored).
*/
@@ -258,6 +325,20 @@ static void ip_registry_expire(struct Event* ev)
ip_registry_expire_entry(entry);
}
}
+
+ for (i = 0; i < IP_REGISTRY_TABLE_SIZE; ++i) {
+ struct IPRegistry48** prev_p;
+ struct IPRegistry48* entry;
+
+ for (prev_p = &hashTable48[i]; (entry = *prev_p); ) {
+ if (CONNECTED_SINCE(entry->last_connect) > 600) {
+ *prev_p = entry->next;
+ entry->next = freeList48;
+ freeList48 = entry;
+ } else
+ prev_p = &entry->next;
+ }
+ }
}
/** Initialize the IPcheck subsystem. */
@@ -279,6 +360,23 @@ int ip_registry_check_local(const struct irc_in_addr
*addr, time_t* next_target_
struct IPRegistryEntry* entry = ip_registry_find(addr);
unsigned int free_targets = STARTTARGETS;
+ if (!irc_in_addr_is_ipv4(addr)) {
+ struct IPRegistry48* entry_48 = ip_48_find(addr);
+
+ if (CONNECTED_SINCE(entry_48->last_connect) > IPCHECK_48_CLONE_PERIOD)
+ entry_48->attempts = 0;
+
+ entry_48->last_connect = NOW;
+ if (0 == ++entry_48->attempts)
+ --entry_48->attempts;
+
+#ifndef NOTHROTTLE
+ if ((entry_48->attempts >= IPCHECK_48_CLONE_LIMIT)
+ && ((CurrentTime - cli_since(&me) > IPCHECK_CLONE_DELAY)))
+ goto reject;
+#endif
+ }
+
if (0 == entry) {
entry = ip_registry_new_entry();
ip_registry_canonicalize(&entry->addr, addr);
@@ -310,17 +408,18 @@ int ip_registry_check_local(const struct irc_in_addr
*addr, time_t* next_target_
if (next_target_out)
*next_target_out = CurrentTime - (TARGET_DELAY * free_targets - 1);
}
+#ifndef NOTHROTTLE
else if ((CurrentTime - cli_since(&me)) > IPCHECK_CLONE_DELAY) {
/*
* Don't refuse connection when we just rebooted the server
*/
-#ifndef NOTHROTTLE
+reject:
assert(entry->connected > 0);
--entry->connected;
Debug((DEBUG_DNS, "IPcheck refusing local connection from %s: too fast.",
ircd_ntoa(&entry->addr)));
return 0;
-#endif
}
+#endif
Debug((DEBUG_DNS, "IPcheck accepting local connection from %s.",
ircd_ntoa(&entry->addr)));
return 1;
}
@@ -345,6 +444,16 @@ int ip_registry_check_remote(struct Client* cptr, int
is_burst)
Debug((DEBUG_DNS, "IPcheck accepting remote connection from invalid %s.",
ircd_ntoa(&cli_ip(cptr))));
return 1;
}
+
+ if (!irc_in_addr_is_ipv4(&cli_ip(cptr))) {
+ struct IPRegistry48* entry_48 = ip_48_find(&cli_ip(cptr));
+ if (CONNECTED_SINCE(entry_48->last_connect) > IPCHECK_48_CLONE_PERIOD)
+ entry_48->attempts = 0;
+ if (0 == ++entry_48->attempts)
+ --entry_48->attempts;
+ entry_48->last_connect = NOW;
+ }
+
entry = ip_registry_find(&cli_ip(cptr));
if (0 == entry) {
entry = ip_registry_new_entry();
@@ -385,6 +494,13 @@ int ip_registry_check_remote(struct Client* cptr, int
is_burst)
void ip_registry_connect_fail(const struct irc_in_addr *addr, int disconnect)
{
struct IPRegistryEntry* entry = ip_registry_find(addr);
+
+ if (!irc_in_addr_is_ipv4(addr)) {
+ struct IPRegistry48* entry_48 = ip_48_find(addr);
+ if (0 == --entry_48->attempts)
+ ++entry_48->attempts;
+ }
+
if (entry) {
if (0 == --entry->attempts) {
Debug((DEBUG_DNS, "IPcheck noting local connection failure for %s.",
ircd_ntoa(&entry->addr)));
diff --git a/ircd/ircd_features.c b/ircd/ircd_features.c
index 6941b58..b63347d 100644
--- a/ircd/ircd_features.c
+++ b/ircd/ircd_features.c
@@ -345,6 +345,8 @@ static struct FeatureDesc {
F_I(SOCKRECVBUF, 0, SERVER_TCP_WINDOW, 0),
F_I(IPCHECK_CLONE_LIMIT, 0, 4, 0),
F_I(IPCHECK_CLONE_PERIOD, 0, 40, 0),
+ F_I(IPCHECK_48_CLONE_LIMIT, 0, 50, 0),
+ F_I(IPCHECK_48_CLONE_PERIOD, 0, 10, 0),
F_I(IPCHECK_CLONE_DELAY, 0, 600, 0),
F_I(CHANNELLEN, 0, 200, 0),
-----------------------------------------------------------------------
Summary of changes:
doc/readme.features | 16 ++++++
include/ircd_features.h | 2 +
ircd/IPcheck.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++-
ircd/ircd_features.c | 2 +
4 files changed, 138 insertions(+), 2 deletions(-)
hooks/post-receive
--
Undernet IRC Server Source Code.
_______________________________________________
Patches mailing list
[email protected]
http://undernet.sbg.org/mailman/listinfo/patches