aboutsummaryrefslogtreecommitdiff
path: root/kike.c
diff options
context:
space:
mode:
authorPřemysl Janouch <p.janouch@gmail.com>2014-08-10 02:22:52 +0200
committerPřemysl Janouch <p.janouch@gmail.com>2014-08-10 02:22:52 +0200
commitb8f002eaf51a9358fedc591b552856f1014674c4 (patch)
tree1e89b105f0c7ee2fa82abbe37e16f848d0597e55 /kike.c
parent126c07b70a7f3217845ffbdf2a001af355755d7c (diff)
downloadxK-b8f002eaf51a9358fedc591b552856f1014674c4.tar.gz
xK-b8f002eaf51a9358fedc591b552856f1014674c4.tar.xz
xK-b8f002eaf51a9358fedc591b552856f1014674c4.zip
kike: add a trivial flood detector
Diffstat (limited to 'kike.c')
-rw-r--r--kike.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/kike.c b/kike.c
index c390715..32be85c 100644
--- a/kike.c
+++ b/kike.c
@@ -92,6 +92,49 @@ setup_signal_handlers (void)
exit_fatal ("%s: %s", "sigaction", strerror (errno));
}
+// --- Rate limiter ------------------------------------------------------------
+
+struct flood_detector
+{
+ unsigned interval; ///< Interval for the limit
+ unsigned limit; ///< Maximum number of events allowed
+
+ time_t *timestamps; ///< Timestamps of last events
+ unsigned pos; ///< Index of the oldest event
+};
+
+static void
+flood_detector_init (struct flood_detector *self,
+ unsigned interval, unsigned limit)
+{
+ self->interval = interval;
+ self->limit = limit;
+ self->timestamps = xcalloc (limit + 1, sizeof *self->timestamps);
+ self->pos = 0;
+}
+
+static void
+flood_detector_free (struct flood_detector *self)
+{
+ free (self->timestamps);
+}
+
+static bool
+flood_detector_check (struct flood_detector *self)
+{
+ time_t now = time (NULL);
+ self->timestamps[self->pos++] = now;
+ if (self->pos > self->limit)
+ self->pos = 0;
+
+ time_t begin = now - self->interval;
+ size_t count = 0;
+ for (size_t i = 0; i <= self->limit; i++)
+ if (self->timestamps[i] >= begin)
+ count++;
+ return count <= self->limit;
+}
+
// --- IRC token validation ----------------------------------------------------
// Use the enum only if applicable and a simple boolean isn't sufficient.
@@ -277,6 +320,7 @@ struct client
unsigned mode; ///< User's mode
char *away_message; ///< Away message
time_t last_active; ///< Last PRIVMSG, to get idle time
+ struct flood_detector antiflood; ///< Flood detector
};
static void
@@ -287,6 +331,8 @@ client_init (struct client *self)
self->socket_fd = -1;
str_init (&self->read_buffer);
str_init (&self->write_buffer);
+ // TODO: make this configurable and more fine-grained
+ flood_detector_init (&self->antiflood, 10, 20);
}
static void
@@ -306,6 +352,7 @@ client_free (struct client *self)
free (self->hostname);
free (self->away_message);
+ flood_detector_free (&self->antiflood);
}
static void client_close_link (struct client *, const char *);
@@ -2299,6 +2346,12 @@ irc_process_message (const struct irc_message *msg,
if (c->closing_link)
return;
+ if (!flood_detector_check (&c->antiflood))
+ {
+ client_close_link (c, "Excess flood");
+ return;
+ }
+
struct irc_command *cmd = str_map_find (&c->ctx->handlers, msg->command);
if (!cmd)
irc_send_reply (c, IRC_ERR_UNKNOWNCOMMAND, msg->command);