kike: add a trivial flood detector
This commit is contained in:
parent
126c07b70a
commit
b8f002eaf5
53
kike.c
53
kike.c
|
@ -92,6 +92,49 @@ setup_signal_handlers (void)
|
||||||
exit_fatal ("%s: %s", "sigaction", strerror (errno));
|
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 ----------------------------------------------------
|
// --- IRC token validation ----------------------------------------------------
|
||||||
|
|
||||||
// Use the enum only if applicable and a simple boolean isn't sufficient.
|
// Use the enum only if applicable and a simple boolean isn't sufficient.
|
||||||
|
@ -277,6 +320,7 @@ struct client
|
||||||
unsigned mode; ///< User's mode
|
unsigned mode; ///< User's mode
|
||||||
char *away_message; ///< Away message
|
char *away_message; ///< Away message
|
||||||
time_t last_active; ///< Last PRIVMSG, to get idle time
|
time_t last_active; ///< Last PRIVMSG, to get idle time
|
||||||
|
struct flood_detector antiflood; ///< Flood detector
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -287,6 +331,8 @@ client_init (struct client *self)
|
||||||
self->socket_fd = -1;
|
self->socket_fd = -1;
|
||||||
str_init (&self->read_buffer);
|
str_init (&self->read_buffer);
|
||||||
str_init (&self->write_buffer);
|
str_init (&self->write_buffer);
|
||||||
|
// TODO: make this configurable and more fine-grained
|
||||||
|
flood_detector_init (&self->antiflood, 10, 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -306,6 +352,7 @@ client_free (struct client *self)
|
||||||
|
|
||||||
free (self->hostname);
|
free (self->hostname);
|
||||||
free (self->away_message);
|
free (self->away_message);
|
||||||
|
flood_detector_free (&self->antiflood);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void client_close_link (struct client *, const char *);
|
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)
|
if (c->closing_link)
|
||||||
return;
|
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);
|
struct irc_command *cmd = str_map_find (&c->ctx->handlers, msg->command);
|
||||||
if (!cmd)
|
if (!cmd)
|
||||||
irc_send_reply (c, IRC_ERR_UNKNOWNCOMMAND, msg->command);
|
irc_send_reply (c, IRC_ERR_UNKNOWNCOMMAND, msg->command);
|
||||||
|
|
Loading…
Reference in New Issue