RSPAMD_CL_FLAG_INT_32,
"Maximum count of heartbeats to be lost before trying to "
"terminate a worker (default: 0 - disabled)");
+ rspamd_rcl_add_default_handler (sub,
+ "max_lua_urls",
+ rspamd_rcl_parse_struct_integer,
+ G_STRUCT_OFFSET (struct rspamd_config, max_lua_urls),
+ RSPAMD_CL_FLAG_INT_32,
+ "Maximum count of URLs to pass to Lua to avoid DoS");
/* Neighbours configuration */
rspamd_rcl_add_section_doc (&sub->subsections, "neighbours", "name",
return (x << k) | (x >> (64 - k));
}
-
gdouble
rspamd_random_double_fast (void)
{
- const guint64 s0 = xorshifto_seed[0];
- guint64 s1 = xorshifto_seed[1];
+ return rspamd_random_double_fast_seed (xorshifto_seed);
+}
+
+gdouble
+rspamd_random_double_fast_seed (guint64 seed[2])
+{
+ const guint64 s0 = seed[0];
+ guint64 s1 = seed[1];
const guint64 result = s0 + s1;
s1 ^= s0;
- xorshifto_seed[0] = xoroshiro_rotl(s0, 55) ^ s1 ^ (s1 << 14);
- xorshifto_seed[1] = xoroshiro_rotl (s1, 36);
+ seed[0] = xoroshiro_rotl(s0, 55) ^ s1 ^ (s1 << 14);
+ seed[1] = xoroshiro_rotl (s1, 36);
return rspamd_double_from_int64 (result);
}
int i;
gint mask;
gint need_images;
+ gdouble skip_prob;
+ guint64 xoroshiro_state[2];
};
static void
return;
}
+ if (cb->skip_prob > 0) {
+ gdouble coin = rspamd_random_double_fast_seed (cb->xoroshiro_state);
+
+ if (coin < cb->skip_prob) {
+ return;
+ }
+ }
+
lua_url = lua_newuserdata (cb->L, sizeof (struct rspamd_lua_url));
rspamd_lua_setclass (cb->L, "rspamd{url}", -1);
lua_url->url = url;
}
}
+static inline gsize
+lua_task_urls_adjust_skip_prob (struct rspamd_task *task,
+ struct lua_tree_cb_data *cb, gsize sz, gsize max_urls)
+{
+ if (max_urls > 0 && sz > max_urls) {
+ cb->skip_prob = 1.0 - ((gdouble)max_urls) / (gdouble)sz;
+ /*
+ * Use task dependent probabilistic seed to ensure that
+ * consequent task:get_urls return the same list of urls
+ */
+ memcpy (&cb->xoroshiro_state[0], &task->task_timestamp,
+ MIN (sizeof (cb->xoroshiro_state[0]), sizeof (task->task_timestamp)));
+ memcpy (&cb->xoroshiro_state[1], MESSAGE_FIELD (task, digest),
+ sizeof (cb->xoroshiro_state[1]));
+ sz = max_urls;
+ }
+
+ return sz;
+}
+
static gint
lua_task_get_urls (lua_State * L)
{
PROTOCOL_FILE|PROTOCOL_FTP;
const gchar *cache_name = "emails+urls";
gboolean need_images = FALSE;
- gsize sz;
+ gsize sz, max_urls = 0;
if (task) {
+ if (task->cfg) {
+ max_urls = task->cfg->max_lua_urls;
+ }
+
if (task->message == NULL) {
lua_newtable (L);
sz = g_hash_table_size (MESSAGE_FIELD (task, urls)) +
g_hash_table_size (MESSAGE_FIELD (task, emails));
+ sz = lua_task_urls_adjust_skip_prob (task, &cb, sz, max_urls);
+
if (protocols_mask == (default_mask|PROTOCOL_MAILTO)) {
/* Can use cached version */
if (!lua_task_get_cached (L, task, cache_name)) {
}
sz = g_hash_table_size (MESSAGE_FIELD (task, urls));
+ sz = lua_task_urls_adjust_skip_prob (task, &cb, sz, max_urls);
if (protocols_mask == (default_mask)) {
if (!lua_task_get_cached (L, task, cache_name)) {
LUA_TRACE_POINT;
struct rspamd_task *task = lua_check_task (L, 1);
gboolean need_emails = FALSE, ret = FALSE;
+ gsize sz = 0;
if (task) {
if (task->message) {
}
if (g_hash_table_size (MESSAGE_FIELD (task, urls)) > 0) {
+ sz += g_hash_table_size (MESSAGE_FIELD (task, urls));
ret = TRUE;
}
if (need_emails && g_hash_table_size (MESSAGE_FIELD (task, emails)) > 0) {
+ sz += g_hash_table_size (MESSAGE_FIELD (task, emails));
ret = TRUE;
}
}
}
lua_pushboolean (L, ret);
+ lua_pushinteger (L, sz);
- return 1;
+ return 2;
}
static gint