From 0fb2347cce41a52c93405cf35257eafb3efb2565 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Tue, 22 Dec 2015 14:30:08 +0000 Subject: [PATCH] Fix issues with multiple addresses in SPF records Issue: #455 Reported by: @moisseev --- src/libserver/spf.c | 73 ++++++++++++++++++++++++++++++++++----------- src/libserver/spf.h | 12 ++++---- 2 files changed, 62 insertions(+), 23 deletions(-) diff --git a/src/libserver/spf.c b/src/libserver/spf.c index a421d7a07..e8394ec74 100644 --- a/src/libserver/spf.c +++ b/src/libserver/spf.c @@ -177,6 +177,8 @@ rspamd_spf_new_addr (struct spf_record *rec, } g_ptr_array_add (resolved->elts, naddr); + naddr->prev = naddr; + naddr->next = NULL; return naddr; } @@ -184,11 +186,13 @@ rspamd_spf_new_addr (struct spf_record *rec, static void rspamd_spf_free_addr (gpointer a) { - struct spf_addr *addr = a; + struct spf_addr *addr = a, *tmp, *cur; if (addr) { g_free (addr->spf_string); - g_slice_free1 (sizeof (*addr), addr); + DL_FOREACH_SAFE (addr, cur, tmp) { + g_slice_free1 (sizeof (*cur), cur); + } } } @@ -250,7 +254,7 @@ rspamd_spf_process_reference (struct spf_resolved *target, struct spf_addr *addr, struct spf_record *rec, gboolean top) { struct spf_resolved_element *elt, *relt; - struct spf_addr *cur = NULL, taddr; + struct spf_addr *cur = NULL, taddr, *cur_addr; guint i; if (addr) { @@ -314,10 +318,11 @@ rspamd_spf_process_reference (struct spf_resolved *target, continue; } - memcpy (&taddr, cur, sizeof (taddr)); - /* Steal element */ - cur->spf_string = NULL; - g_array_append_val (target->elts, taddr); + DL_FOREACH (cur, cur_addr) { + memcpy (&taddr, cur_addr, sizeof (taddr)); + taddr.spf_string = g_strdup (cur_addr->spf_string); + g_array_append_val (target->elts, taddr); + } } } } @@ -420,20 +425,52 @@ spf_check_ptr_host (struct spf_dns_cb *cb, const char *name) static void spf_record_process_addr (struct spf_record *rec, struct spf_addr *addr, struct - rdns_reply_entry - *reply) + rdns_reply_entry *reply) { - if (reply->type == RDNS_REQUEST_AAAA) { - memcpy (addr->addr6, &reply->content.aaa.addr, sizeof (addr->addr6)); - addr->flags |= RSPAMD_SPF_FLAG_IPV6; - } - else if (reply->type == RDNS_REQUEST_A) { - memcpy (addr->addr4, &reply->content.a.addr, sizeof (addr->addr4)); - addr->flags |= RSPAMD_SPF_FLAG_IPV4; + struct spf_addr *naddr; + + if (!addr->flags & RSPAMD_SPF_FLAG_PROCESSED) { + /* That's the first address */ + if (reply->type == RDNS_REQUEST_AAAA) { + memcpy (addr->addr6, + &reply->content.aaa.addr, + sizeof (addr->addr6)); + addr->flags |= RSPAMD_SPF_FLAG_IPV6; + } + else if (reply->type == RDNS_REQUEST_A) { + memcpy (addr->addr4, &reply->content.a.addr, sizeof (addr->addr4)); + addr->flags |= RSPAMD_SPF_FLAG_IPV4; + } + else { + msg_err_spf ( + "internal error, bad DNS reply is treated as address: %s", + rdns_strtype (reply->type)); + } } else { - msg_err_spf ("internal error, bad DNS reply is treated as address: %s", - rdns_strtype (reply->type)); + /* We need to create a new address */ + naddr = g_slice_alloc0 (sizeof (*naddr)); + memcpy (naddr, addr, sizeof (*naddr)); + naddr->next = NULL; + naddr->prev = NULL; + + if (reply->type == RDNS_REQUEST_AAAA) { + memcpy (naddr->addr6, + &reply->content.aaa.addr, + sizeof (addr->addr6)); + naddr->flags |= RSPAMD_SPF_FLAG_IPV6; + } + else if (reply->type == RDNS_REQUEST_A) { + memcpy (naddr->addr4, &reply->content.a.addr, sizeof (addr->addr4)); + naddr->flags |= RSPAMD_SPF_FLAG_IPV4; + } + else { + msg_err_spf ( + "internal error, bad DNS reply is treated as address: %s", + rdns_strtype (reply->type)); + } + + DL_APPEND (addr, naddr); } } diff --git a/src/libserver/spf.h b/src/libserver/spf.h index 9aa439905..9e875b515 100644 --- a/src/libserver/spf.h +++ b/src/libserver/spf.h @@ -30,11 +30,12 @@ typedef enum spf_action_e { #define RSPAMD_SPF_FLAG_IPV6 (1 << 0) #define RSPAMD_SPF_FLAG_IPV4 (1 << 1) -#define RSPAMD_SPF_FLAG_ANY (1 << 2) -#define RSPAMD_SPF_FLAG_PARSED (1 << 3) -#define RSPAMD_SPF_FLAG_VALID (1 << 4) -#define RSPAMD_SPF_FLAG_REFRENCE (1 << 5) -#define RSPAMD_SPF_FLAG_REDIRECT (1 << 6) +#define RSPAMD_SPF_FLAG_PROCESSED (1 << 2) +#define RSPAMD_SPF_FLAG_ANY (1 << 3) +#define RSPAMD_SPF_FLAG_PARSED (1 << 4) +#define RSPAMD_SPF_FLAG_VALID (1 << 5) +#define RSPAMD_SPF_FLAG_REFRENCE (1 << 6) +#define RSPAMD_SPF_FLAG_REDIRECT (1 << 7) struct spf_addr { guchar addr6[sizeof (struct in6_addr)]; @@ -49,6 +50,7 @@ struct spf_addr { guint flags; spf_mech_t mech; gchar *spf_string; + struct spf_addr *prev, *next; }; struct spf_resolved { -- 2.39.5