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

Reply via email to