commit fe1c8f8: [Fix] Make spf digest stable

Vsevolod Stakhov vsevolod at highsecure.ru
Fri Apr 12 15:35:03 UTC 2019


Author: Vsevolod Stakhov
Date: 2019-04-12 16:00:41 +0100
URL: https://github.com/rspamd/rspamd/commit/fe1c8f88b7253ab746958b7b5200b22d7f9ca901

[Fix] Make spf digest stable

---
 src/libserver/spf.c | 110 ++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 76 insertions(+), 34 deletions(-)

diff --git a/src/libserver/spf.c b/src/libserver/spf.c
index 2451f73db..70db4adbd 100644
--- a/src/libserver/spf.c
+++ b/src/libserver/spf.c
@@ -371,34 +371,6 @@ rspamd_spf_process_reference (struct spf_resolved *target,
 			DL_FOREACH (cur, cur_addr) {
 				memcpy (&taddr, cur_addr, sizeof (taddr));
 				taddr.spf_string = g_strdup (cur_addr->spf_string);
-
-				if (cur_addr->flags & RSPAMD_SPF_FLAG_IPV6) {
-					guint64 t[3];
-
-					memcpy (t, cur_addr->addr6, sizeof (guint64) * 2);
-					t[2] = ((guint64)(cur_addr->mech)) << 48;
-					t[2] |= cur_addr->m.dual.mask_v6;
-
-					for (guint j = 0; j < G_N_ELEMENTS (t); j ++) {
-						target->digest = mum_hash_step (target->digest, t[j]);
-					}
-				}
-				else if (cur_addr->flags & RSPAMD_SPF_FLAG_IPV4) {
-					guint64 t;
-
-					memcpy (&t, cur_addr->addr4, sizeof (guint32));
-					t |= ((guint64)(cur_addr->mech)) << 48;
-					t |= ((guint64)cur_addr->m.dual.mask_v4) << 32;
-
-					target->digest = mum_hash_step (target->digest, t);
-				}
-				else {
-					guint64 t = 0;
-
-					t |= ((guint64)(cur_addr->mech)) << 48;
-					target->digest = mum_hash_step (target->digest, t);
-				}
-
 				g_array_append_val (target->elts, taddr);
 			}
 		}
@@ -427,8 +399,6 @@ rspamd_spf_record_flatten (struct spf_record *rec)
 		if (rec->resolved->len > 0) {
 			rspamd_spf_process_reference (res, NULL, rec, TRUE);
 		}
-
-		res->digest = mum_hash_finish (res->digest);
 	}
 	else {
 		res = g_malloc0 (sizeof (*res));
@@ -442,6 +412,77 @@ rspamd_spf_record_flatten (struct spf_record *rec)
 	return res;
 }
 
+static gint
+rspamd_spf_elts_cmp (gconstpointer a, gconstpointer b)
+{
+	struct spf_addr *addr_a, *addr_b;
+
+	addr_a = (struct spf_addr *)a;
+	addr_b = (struct spf_addr *)b;
+
+	if (addr_a->flags == addr_b->flags) {
+		if (addr_a->flags & RSPAMD_SPF_FLAG_ANY) {
+			return 0;
+		}
+		else if (addr_a->flags & RSPAMD_SPF_FLAG_IPV4) {
+			return (addr_a->m.dual.mask_v4 - addr_b->m.dual.mask_v4) ||
+				memcmp (addr_a->addr4, addr_b->addr4, sizeof (addr_a->addr4));
+		}
+		else if (addr_a->flags & RSPAMD_SPF_FLAG_IPV6) {
+			return (addr_a->m.dual.mask_v6 - addr_b->m.dual.mask_v6) ||
+			 memcmp (addr_a->addr6, addr_b->addr6, sizeof (addr_a->addr6));
+		}
+		else {
+			return 0;
+		}
+	}
+	else {
+		if (addr_a->flags & RSPAMD_SPF_FLAG_ANY) {
+			return 1;
+		}
+		else if (addr_b->flags & RSPAMD_SPF_FLAG_ANY) {
+			return -1;
+		}
+		else if (addr_a->flags & RSPAMD_SPF_FLAG_IPV4) {
+			return -1;
+		}
+
+		return 1;
+	}
+}
+
+static void
+rspamd_spf_record_postprocess (struct spf_resolved *rec)
+{
+	g_array_sort (rec->elts, rspamd_spf_elts_cmp);
+
+	for (guint i = 0; i < rec->elts->len; i ++) {
+		struct spf_addr *cur_addr = &g_array_index (rec->elts, struct spf_addr, i);
+
+		if (cur_addr->flags & RSPAMD_SPF_FLAG_IPV6) {
+			guint64 t[3];
+
+			memcpy (t, cur_addr->addr6, sizeof (guint64) * 2);
+			t[2] = 0;
+			t[2] = ((guint64) (cur_addr->mech)) << 48u;
+			t[2] |= cur_addr->m.dual.mask_v6;
+
+			for (guint j = 0; j < G_N_ELEMENTS (t); j++) {
+				rec->digest = mum_hash_step (rec->digest, t[j]);
+			}
+		}
+		else if (cur_addr->flags & RSPAMD_SPF_FLAG_IPV4) {
+			guint64 t = 0;
+
+			memcpy (&t, cur_addr->addr4, sizeof (guint32));
+			t |= ((guint64) (cur_addr->mech)) << 48u;
+			t |= ((guint64) cur_addr->m.dual.mask_v4) << 32u;
+
+			rec->digest = mum_hash_step (rec->digest, t);
+		}
+	}
+}
+
 static void
 rspamd_spf_maybe_return (struct spf_record *rec)
 {
@@ -449,6 +490,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);
 		rec->callback (flat, rec->task, rec->cbdata);
 		REF_RELEASE (flat);
 		rec->done = TRUE;
@@ -688,6 +730,7 @@ spf_record_dns_callback (struct rdns_reply *reply, gpointer arg)
 					else {
 						cb->addr->flags |= RSPAMD_SPF_FLAG_RESOLVED;
 						cb->addr->flags &= ~RSPAMD_SPF_FLAG_PERMFAIL;
+						msg_debug_spf ("resolved MX addr");
 						spf_record_process_addr (rec, addr, elt_data);
 					}
 					break;
@@ -2107,7 +2150,6 @@ spf_dns_callback (struct rdns_reply *reply, gpointer arg)
 			&& rec->dns_requests == 0) {
 		resolved = rspamd_spf_new_addr_list (rec, rec->sender_domain);
 		addr = g_malloc0 (sizeof(*addr));
-		addr->flags = 0;
 		addr->flags |= RSPAMD_SPF_FLAG_NA;
 		g_ptr_array_insert (resolved->elts, 0, addr);
 	}
@@ -2115,7 +2157,6 @@ spf_dns_callback (struct rdns_reply *reply, gpointer arg)
 			&& rec->dns_requests == 0) {
 		resolved = rspamd_spf_new_addr_list (rec, rec->sender_domain);
 		addr = g_malloc0 (sizeof(*addr));
-		addr->flags = 0;
 		addr->flags |= RSPAMD_SPF_FLAG_TEMPFAIL;
 		g_ptr_array_insert (resolved->elts, 0, addr);
 	}
@@ -2135,7 +2176,7 @@ spf_dns_callback (struct rdns_reply *reply, gpointer arg)
 			}
 			else {
 				addr = g_malloc0 (sizeof(*addr));
-				addr->flags = 0;
+
 				if (reply->code == RDNS_RC_NOREC || reply->code == RDNS_RC_NXDOMAIN
 						|| reply->code == RDNS_RC_NOERROR) {
 					addr->flags |= RSPAMD_SPF_FLAG_NA;
@@ -2300,7 +2341,8 @@ spf_addr_mask_to_string (struct spf_addr *addr)
 		rspamd_printf_gstring (res, "%s/%d", ipstr, addr->m.dual.mask_v6);
 	}
 	else {
-		res = g_string_new ("unknown");
+		res = g_string_new (NULL);
+		rspamd_printf_gstring (res, "unknown, flags = %d", addr->flags);
 	}
 
 	s = res->str;


More information about the Commits mailing list