commit 2219a8e: [Minor] Add method to get matching SPF record

Vsevolod Stakhov vsevolod at highsecure.ru
Thu Apr 11 17:21:13 UTC 2019


Author: Vsevolod Stakhov
Date: 2019-04-11 17:26:42 +0100
URL: https://github.com/rspamd/rspamd/commit/2219a8e09fba415759e06279ebe4f044c42ae4ba (HEAD -> master)

[Minor] Add method to get matching SPF record

---
 src/libserver/spf.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/libserver/spf.h |  9 +++++++
 2 files changed, 79 insertions(+)

diff --git a/src/libserver/spf.c b/src/libserver/spf.c
index ee2c06923..2451f73db 100644
--- a/src/libserver/spf.c
+++ b/src/libserver/spf.c
@@ -2308,4 +2308,74 @@ spf_addr_mask_to_string (struct spf_addr *addr)
 
 
 	return s;
+}
+
+struct spf_addr*
+spf_addr_match_task (struct rspamd_task *task, struct spf_resolved *rec)
+{
+	const guint8 *s, *d;
+	guint af, mask, bmask, addrlen;
+	struct spf_addr *selected = NULL, *addr, *any_addr = NULL;
+	guint i;
+
+	if (task->from_addr == NULL) {
+		return FALSE;
+	}
+
+	for (i = 0; i < rec->elts->len; i ++) {
+		addr = &g_array_index (rec->elts, struct spf_addr, i);
+		if (addr->flags & RSPAMD_SPF_FLAG_TEMPFAIL) {
+			continue;
+		}
+
+		af = rspamd_inet_address_get_af (task->from_addr);
+		/* Basic comparing algorithm */
+		if (((addr->flags & RSPAMD_SPF_FLAG_IPV6) && af == AF_INET6) ||
+			((addr->flags & RSPAMD_SPF_FLAG_IPV4) && af == AF_INET)) {
+			d = rspamd_inet_address_get_hash_key (task->from_addr, &addrlen);
+
+			if (af == AF_INET6) {
+				s = (const guint8 *) addr->addr6;
+				mask = addr->m.dual.mask_v6;
+			}
+			else {
+				s = (const guint8 *) addr->addr4;
+				mask = addr->m.dual.mask_v4;
+			}
+
+			/* Compare the first bytes */
+			bmask = mask / CHAR_BIT;
+			if (mask > addrlen * CHAR_BIT) {
+				msg_info_task ("bad mask length: %d", mask);
+			}
+			else if (memcmp (s, d, bmask) == 0) {
+				if (bmask * CHAR_BIT < mask) {
+					/* Compare the remaining bits */
+					s += bmask;
+					d += bmask;
+					mask = (0xffu << (CHAR_BIT - (mask - bmask * 8u))) & 0xffu;
+
+					if ((*s & mask) == (*d & mask)) {
+						selected = addr;
+						break;
+					}
+				}
+				else {
+					selected = addr;
+					break;
+				}
+			}
+		}
+		else {
+			if (addr->flags & RSPAMD_SPF_FLAG_ANY) {
+				any_addr = addr;
+			}
+		}
+	}
+
+	if (selected) {
+		return selected;
+	}
+
+	return any_addr;
 }
\ No newline at end of file
diff --git a/src/libserver/spf.h b/src/libserver/spf.h
index 5df52d0e0..722e98c03 100644
--- a/src/libserver/spf.h
+++ b/src/libserver/spf.h
@@ -98,4 +98,13 @@ void spf_record_unref (struct spf_resolved *rec);
  * @return
  */
 gchar *spf_addr_mask_to_string (struct spf_addr *addr);
+
+/**
+ * Returns spf address that matches the specific task (or nil if not matched)
+ * @param task
+ * @param rec
+ * @return
+ */
+struct spf_addr * spf_addr_match_task (struct rspamd_task *task,
+									   struct spf_resolved *rec);
 #endif


More information about the Commits mailing list