Skip to content

Commit

Permalink
[Feature] Implement configurable limits for SPF lookups
Browse files Browse the repository at this point in the history
  • Loading branch information
vstakhov committed Oct 25, 2019
1 parent 1207a81 commit 9e61dce
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 10 deletions.
67 changes: 57 additions & 10 deletions src/libserver/spf.c
Expand Up @@ -39,10 +39,6 @@
#define SPF_REDIRECT "redirect"
#define SPF_EXP "exp"

/** SPF limits for avoiding abuse **/
#define SPF_MAX_NESTING 10
#define SPF_MAX_DNS_REQUESTS 30

struct spf_resolved_element {
GPtrArray *elts;
gchar *cur_domain;
Expand All @@ -66,6 +62,14 @@ struct spf_record {
gboolean done;
};

struct rspamd_spf_library_ctx {
guint max_dns_nesting;
guint max_dns_requests;
guint min_cache_ttl;
};

struct rspamd_spf_library_ctx *spf_lib_ctx = NULL;

/**
* BNF for SPF record:
*
Expand Down Expand Up @@ -119,15 +123,50 @@ struct spf_dns_cb {

#define CHECK_REC(rec) \
do { \
if ((rec)->nested > SPF_MAX_NESTING || \
(rec)->dns_requests > SPF_MAX_DNS_REQUESTS) { \
msg_info_spf ("spf recursion limit %d is reached, domain: %s", \
(rec)->dns_requests, \
if (spf_lib_ctx->max_dns_nesting > 0 && \
(rec)->nested > spf_lib_ctx->max_dns_nesting) { \
msg_warn_spf ("spf nesting limit: %d > %d is reached, domain: %s", \
(rec)->nested, spf_lib_ctx->max_dns_nesting, \
(rec)->sender_domain); \
return FALSE; \
} \
if (spf_lib_ctx->max_dns_requests > 0 && \
(rec)->dns_requests > spf_lib_ctx->max_dns_requests) { \
msg_warn_spf ("spf dns requests limit: %d > %d is reached, domain: %s", \
(rec)->dns_requests, spf_lib_ctx->max_dns_requests, \
(rec)->sender_domain); \
return FALSE; \
} \
} while (0) \

RSPAMD_CONSTRUCTOR(rspamd_spf_lib_ctx_ctor) {
spf_lib_ctx = g_malloc0 (sizeof (*spf_lib_ctx));
spf_lib_ctx->max_dns_nesting = SPF_MAX_NESTING;
spf_lib_ctx->max_dns_requests = SPF_MAX_DNS_REQUESTS;
spf_lib_ctx->min_cache_ttl = SPF_MIN_CACHE_TTL;
}

RSPAMD_DESTRUCTOR(rspamd_spf_lib_ctx_dtor) {
g_free (spf_lib_ctx);
spf_lib_ctx = NULL;
}

void
spf_library_config (gint max_dns_nesting, gint max_dns_requests,
gint min_cache_ttl)
{
if (max_dns_nesting >= 0) {
spf_lib_ctx->max_dns_nesting = max_dns_nesting;
}

if (max_dns_requests >= 0) {
spf_lib_ctx->max_dns_requests = max_dns_requests;
}

if (min_cache_ttl >= 0) {
spf_lib_ctx->min_cache_ttl = min_cache_ttl;
}
}

static gboolean start_spf_parse (struct spf_record *rec,
struct spf_resolved_element *resolved, gchar *begin);
Expand Down Expand Up @@ -452,7 +491,7 @@ rspamd_spf_elts_cmp (gconstpointer a, gconstpointer b)
}

static void
rspamd_spf_record_postprocess (struct spf_resolved *rec)
rspamd_spf_record_postprocess (struct spf_resolved *rec, struct rspamd_task *task)
{
g_array_sort (rec->elts, rspamd_spf_elts_cmp);

Expand Down Expand Up @@ -481,6 +520,14 @@ rspamd_spf_record_postprocess (struct spf_resolved *rec)
rec->digest = mum_hash_step (rec->digest, t);
}
}

if (spf_lib_ctx->min_cache_ttl > 0) {
if (rec->ttl != 0 && rec->ttl < spf_lib_ctx->min_cache_ttl) {
msg_info_task ("increasing ttl from %d to %d as it lower than a limit",
rec->ttl, spf_lib_ctx->min_cache_ttl);
rec->ttl = spf_lib_ctx->min_cache_ttl;
}
}
}

static void
Expand All @@ -490,7 +537,7 @@ rspamd_spf_maybe_return (struct spf_record *rec)

if (rec->requests_inflight == 0 && !rec->done) {
flat = rspamd_spf_record_flatten (rec);
rspamd_spf_record_postprocess (flat);
rspamd_spf_record_postprocess (flat, rec->task);
rec->callback (flat, rec->task, rec->cbdata);
REF_RELEASE (flat);
rec->done = TRUE;
Expand Down
8 changes: 8 additions & 0 deletions src/libserver/spf.h
Expand Up @@ -46,6 +46,11 @@ typedef enum spf_action_e {
#define RSPAMD_SPF_FLAG_PERMFAIL (1u << 10u)
#define RSPAMD_SPF_FLAG_RESOLVED (1u << 11u)

/** Default SPF limits for avoiding abuse **/
#define SPF_MAX_NESTING 10
#define SPF_MAX_DNS_REQUESTS 30
#define SPF_MIN_CACHE_TTL (60 * 5) /* 5 minutes */

struct spf_addr {
guchar addr6[sizeof (struct in6_addr)];
guchar addr4[sizeof (struct in_addr)];
Expand Down Expand Up @@ -112,6 +117,9 @@ gchar *spf_addr_mask_to_string (struct spf_addr *addr);
struct spf_addr *spf_addr_match_task (struct rspamd_task *task,
struct spf_resolved *rec);

void spf_library_config (gint max_dns_nesting, gint max_dns_requests,
gint min_cache_ttl);

#ifdef __cplusplus
}
#endif
Expand Down

0 comments on commit 9e61dce

Please sign in to comment.