]> source.dussan.org Git - rspamd.git/commitdiff
[Feature] Implement configurable limits for SPF lookups
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Fri, 25 Oct 2019 08:22:43 +0000 (09:22 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Fri, 25 Oct 2019 08:30:36 +0000 (09:30 +0100)
src/libserver/spf.c
src/libserver/spf.h

index 6315948086b1d986cdb3ffac8c01322cede5ebbf..d362a72938a6a5c1a42afbb4538ab9b4a7682087 100644 (file)
 #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;
@@ -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:
  *
@@ -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);
@@ -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);
 
@@ -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
@@ -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;
index 725d84fe4df0db72b0a9b20b38c4e8ec38ae4fc1..cd8eaffac75abca31de8b458839a9eff07bd5158 100644 (file)
@@ -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)];
@@ -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