commit 9e61dce: [Feature] Implement configurable limits for SPF lookups

Vsevolod Stakhov vsevolod at highsecure.ru
Fri Oct 25 08:35:06 UTC 2019


Author: Vsevolod Stakhov
Date: 2019-10-25 09:22:43 +0100
URL: https://github.com/rspamd/rspamd/commit/9e61dce1b503b21f85ee24378aa4a3383680e792

[Feature] Implement configurable limits for SPF lookups

---
 src/libserver/spf.c | 67 +++++++++++++++++++++++++++++++++++++++++++++--------
 src/libserver/spf.h |  8 +++++++
 2 files changed, 65 insertions(+), 10 deletions(-)

diff --git a/src/libserver/spf.c b/src/libserver/spf.c
index 631594808..d362a7293 100644
--- a/src/libserver/spf.c
+++ b/src/libserver/spf.c
@@ -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;
@@ -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;
diff --git a/src/libserver/spf.h b/src/libserver/spf.h
index 725d84fe4..cd8eaffac 100644
--- a/src/libserver/spf.h
+++ b/src/libserver/spf.h
@@ -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


More information about the Commits mailing list