From: Vsevolod Stakhov Date: Wed, 18 Mar 2015 15:12:39 +0000 (+0000) Subject: Start rework for spf structures. X-Git-Tag: 0.9.0~477^2~8 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=c83993180110061c097d19033c6a46cba79c3758;p=rspamd.git Start rework for spf structures. --- diff --git a/src/libserver/spf.c b/src/libserver/spf.c index 13eff0c27..6e4e55a86 100644 --- a/src/libserver/spf.c +++ b/src/libserver/spf.c @@ -49,8 +49,28 @@ #define SPF_MAX_NESTING 10 #define SPF_MAX_DNS_REQUESTS 30 +struct spf_resolved_element { + GPtrArray *elts; + gchar *cur_domain; + gboolean redirected; /* Ingnore level, it's redirected */ +}; + +struct spf_record { + gint nested; + gint dns_requests; + gint requests_inflight; + + guint ttl; + GArray *resolved; /* Array of struct spf_resolved_element */ + const gchar *sender; + const gchar *sender_domain; + gchar *local_part; + struct rspamd_task *task; + spf_cb_t callback; +}; + /** - * State machine for SPF record: + * BNF for SPF record: * * spf_mech ::= +|-|~|? * @@ -91,8 +111,7 @@ struct spf_dns_cb { } \ } while (0) \ -static gboolean parse_spf_record (struct rspamd_task *task, - struct spf_record *rec); +static gboolean parse_spf_record (struct spf_record *rec, const gchar *elt); static gboolean start_spf_parse (struct spf_record *rec, gchar *begin, guint ttl); @@ -119,6 +138,54 @@ check_spf_mech (const gchar *elt, gboolean *need_shift) } } +static struct spf_addr * +rspamd_spf_new_addr (struct spf_record *rec, const gchar *elt) +{ + struct spf_resolved_element *resolved; + gboolean need_shift = FALSE; + struct spf_addr *naddr; + + /* Peek the top element */ + resolved = &g_array_index (rec->resolved, struct spf_resolved_element, + rec->resolved->len - 1); + naddr = g_slice_alloc0 (sizeof (*naddr)); + naddr->mech = check_spf_mech (elt, &need_shift); + + if (need_shift) { + naddr->spf_string = g_strdup (elt + 1); + } + else { + naddr->spf_string = g_strdup (elt); + } + + g_ptr_array_add (resolved->elts, naddr); + + return naddr; +} + +static void +rspamd_spf_free_addr (gpointer a) +{ + struct spf_addr *addr = a; + + if (addr) { + g_free (addr->spf_string); + g_slice_free1 (sizeof (*addr), addr); + } +} + +static void +rspamd_spf_new_addr_list (struct spf_record *rec, const gchar *domain) +{ + struct spf_resolved_element resolved; + + resolved.redirected = FALSE; + resolved.cur_domain = g_strdup (domain); + resolved.elts = g_ptr_array_new_full (8, rspamd_spf_free_addr); + + g_array_append_val (rec->resolved, resolved); +} + /* Debugging function that dumps spf record in log */ static void dump_spf_record (GList *addrs) @@ -1538,31 +1605,21 @@ parse_spf_scopes (struct spf_record *rec, gchar **begin) } static gboolean -start_spf_parse (struct spf_record *rec, gchar *begin, guint ttl) +start_spf_parse (struct spf_record *rec, gchar *begin) { + gchar **elts, **cur_elt; + /* Skip spaces */ while (g_ascii_isspace (*begin)) { begin++; } - if (g_ascii_strncasecmp (begin, SPF_VER1_STR, - sizeof (SPF_VER1_STR) - 1) == 0) { + if (g_ascii_strncasecmp (begin, SPF_VER1_STR, sizeof (SPF_VER1_STR) - 1) == 0) { begin += sizeof (SPF_VER1_STR) - 1; + while (g_ascii_isspace (*begin) && *begin) { begin++; } - rec->elts = g_strsplit_set (begin, " ", 0); - rec->elt_num = 0; - if (rec->elts) { - rspamd_mempool_add_destructor (rec->task->task_pool, - (rspamd_mempool_destruct_t)g_strfreev, rec->elts); - rec->cur_elt = rec->elts[0]; - while (parse_spf_record (rec->task, rec)) ; - if (ttl != 0) { - rec->ttl = ttl; - } - return TRUE; - } } else if (g_ascii_strncasecmp (begin, SPF_VER2_STR, sizeof (SPF_VER2_STR) - 1) == 0) { @@ -1577,21 +1634,6 @@ start_spf_parse (struct spf_record *rec, gchar *begin, guint ttl) parse_spf_scopes (rec, &begin); } /* Now common spf record */ - while (g_ascii_isspace (*begin) && *begin) { - begin++; - } - rec->elts = g_strsplit_set (begin, " ", 0); - rec->elt_num = 0; - if (rec->elts) { - rspamd_mempool_add_destructor (rec->task->task_pool, - (rspamd_mempool_destruct_t)g_strfreev, rec->elts); - rec->cur_elt = rec->elts[0]; - while (parse_spf_record (rec->task, rec)) ; - if (ttl != 0) { - rec->ttl = ttl; - } - } - return TRUE; } else { msg_debug ("<%s>: spf error for domain %s: bad spf record version: %*s", @@ -1599,8 +1641,26 @@ start_spf_parse (struct spf_record *rec, gchar *begin, guint ttl) rec->sender_domain, sizeof (SPF_VER1_STR) - 1, begin); + return FALSE; } - return FALSE; + + while (g_ascii_isspace (*begin) && *begin) { + begin++; + } + + elts = g_strsplit_set (begin, " ", 0); + + if (elts) { + cur_elt = elts; + + while (*cur_elt) { + parse_spf_record (rec, *cur_elt); + cur_elt ++; + } + + g_strfreev (elts); + } + return TRUE; } static void @@ -1611,9 +1671,13 @@ spf_dns_callback (struct rdns_reply *reply, gpointer arg) rec->requests_inflight--; if (reply->code == RDNS_RC_NOERROR) { - LL_FOREACH (reply->entries, elt) - { - if (start_spf_parse (rec, elt->content.txt.data, elt->ttl)) { + if (rec->resolved->len == 1) { + /* Top level resolved element */ + rec->ttl = reply->entries->ttl; + } + + LL_FOREACH (reply->entries, elt) { + if (start_spf_parse (rec, elt->content.txt.data)) { break; } } @@ -1624,10 +1688,10 @@ spf_dns_callback (struct rdns_reply *reply, gpointer arg) } } -gchar * +const gchar * get_spf_domain (struct rspamd_task *task) { - gchar *domain, *res = NULL; + const gchar *domain, *res = NULL; const gchar *sender; sender = rspamd_task_get_sender (task); @@ -1635,7 +1699,7 @@ get_spf_domain (struct rspamd_task *task) if (sender != NULL) { domain = strchr (sender, '@'); if (domain) { - res = rspamd_mempool_strdup (task->task_pool, domain + 1); + res = domain + 1; } } @@ -1667,34 +1731,27 @@ resolve_spf (struct rspamd_task *task, spf_cb_t callback) rec->local_part = rspamd_mempool_alloc (task->task_pool, domain - sender); rspamd_strlcpy (rec->local_part, sender, domain - sender); - rec->cur_domain = rspamd_mempool_strdup (task->task_pool, domain + 1); - rec->sender_domain = rec->cur_domain; - - if (make_dns_request (task->resolver, task->s, task->task_pool, - spf_dns_callback, - (void *)rec, RDNS_REQUEST_TXT, rec->cur_domain)) { - task->dns_requests++; - rec->requests_inflight++; - return TRUE; - } + rec->sender_domain = domain + 1; } else if (task->helo != NULL && strchr (task->helo, '.') != NULL) { - /* For notifies we can check HELO identity and check SPF accrodingly */ + /* For notifies we can check HELO identity and check SPF accordingly */ /* XXX: very poor check */ rec->local_part = rspamd_mempool_strdup (task->task_pool, "postmaster"); - rec->cur_domain = task->helo; rec->sender_domain = task->helo; - - if (make_dns_request (task->resolver, task->s, task->task_pool, - spf_dns_callback, - (void *)rec, RDNS_REQUEST_TXT, rec->cur_domain)) { - task->dns_requests++; - rec->requests_inflight++; - return TRUE; - } + } + else { + return FALSE; } - return FALSE; + rspamd_spf_new_addr_list (rec, rec->sender_domain); + + if (make_dns_request (task->resolver, task->s, task->task_pool, + spf_dns_callback, + (void *)rec, RDNS_REQUEST_TXT, rec->sender_domain)) { + task->dns_requests++; + rec->requests_inflight++; + return TRUE; + } } /* diff --git a/src/libserver/spf.h b/src/libserver/spf.h index 616595c35..c491cd8b4 100644 --- a/src/libserver/spf.h +++ b/src/libserver/spf.h @@ -2,11 +2,12 @@ #define RSPAMD_SPF_H #include "config.h" +#include "ref.h" struct rspamd_task; -struct spf_record; +struct spf_resolved; -typedef void (*spf_cb_t)(struct spf_record *record, struct rspamd_task *task); +typedef void (*spf_cb_t)(struct spf_resolved *record, struct rspamd_task *task); typedef enum spf_mech_e { SPF_FAIL, @@ -26,47 +27,29 @@ typedef enum spf_action_e { SPF_RESOLVE_EXP } spf_action_t; +#define RSPAMD_SPF_FLAG_IPV6 (1 << 0) +#define RSPAMD_SPF_FLAG_ANY (1 << 1) +#define RSPAMD_SPF_FLAG_PARSED (1 << 2) +#define RSPAMD_SPF_FLAG_VALID (1 << 3) +#define RSPAMD_SPF_FLAG_REFRENCE (1 << 4) + struct spf_addr { + guchar addr[sizeof (struct in6_addr)]; union { struct { - union { - struct in_addr in4; -#ifdef HAVE_INET_PTON - struct in6_addr in6; -#endif - } d; - guint32 mask; - gboolean ipv6; - gboolean parsed; - gboolean addr_any; - } normal; - GList *list; - } data; - gboolean is_list; + guint16 mask_v4; + guint16 mask_v6; + } dual; + guint32 mask; + } m; + guint flags; spf_mech_t mech; gchar *spf_string; }; -struct spf_record { - gchar **elts; - - gchar *cur_elt; - gint elt_num; - gint nested; - gint dns_requests; - gint requests_inflight; - - guint ttl; - - GList *addrs; - gchar *cur_domain; - const gchar *sender; - gchar *sender_domain; - gchar *local_part; - struct rspamd_task *task; - spf_cb_t callback; - - gboolean in_include; +struct spf_resolved { + GArray *elts; /* Flat list of struct spf_addr */ + ref_entry_t ref; /* Refcounting */ }; @@ -78,7 +61,17 @@ gboolean resolve_spf (struct rspamd_task *task, spf_cb_t callback); /* * Get a domain for spf for specified task */ -gchar * get_spf_domain (struct rspamd_task *task); +const gchar * get_spf_domain (struct rspamd_task *task); +/* + * Increase refcount + */ +struct spf_resolved * spf_record_ref (struct spf_resolved *rec); + +/* + * Decrease refcount + */ +void spf_record_unref (struct spf_resolved *rec); + #endif