]> source.dussan.org Git - rspamd.git/commitdiff
Rework flattening and callback logic.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Wed, 18 Mar 2015 17:10:16 +0000 (17:10 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Wed, 18 Mar 2015 17:10:16 +0000 (17:10 +0000)
src/libserver/spf.c
src/libserver/spf.h

index 51c4a67ac364477f2c190117fa133cdbe9e790e6..e9c0ebc7177aed5a4b832d1510f9800072f992c7 100644 (file)
@@ -67,6 +67,7 @@ struct spf_record {
        gchar *local_part;
        struct rspamd_task *task;
        spf_cb_t callback;
+       gboolean done;
 };
 
 /**
@@ -200,130 +201,20 @@ static void
 spf_record_destructor (gpointer r)
 {
        struct spf_record *rec = r;
-       GList *cur;
        struct spf_addr *addr;
+       struct spf_resolved_element *elt;
+       guint i, j;
 
-       if (rec->addrs) {
-               cur = rec->addrs;
-               while (cur) {
-                       addr = cur->data;
-                       if (addr->is_list && addr->data.list != NULL) {
-                               g_list_free (addr->data.list);
-                       }
-                       cur = g_list_next (cur);
-               }
-               g_list_free (rec->addrs);
-       }
-}
-
-static gboolean
-parse_spf_ipmask (const gchar *begin,
-       struct spf_addr *addr,
-       struct spf_record *rec)
-{
-       const gchar *pos;
-       gchar mask_buf[5] = {'\0'}, *p;
-       gint state = 0, dots = 0;
-       guint mask;
-       gchar ip_buf[INET6_ADDRSTRLEN];
-
-       bzero (ip_buf,   sizeof (ip_buf));
-       bzero (mask_buf, sizeof (mask_buf));
-       pos = begin;
-       p = ip_buf;
-
-       while (*pos) {
-               switch (state) {
-               case 0:
-                       /* Require ':' */
-                       if (*pos != ':') {
-                               msg_info ("<%s>: spf error for domain %s: semicolon missing",
-                                       rec->task->message_id, rec->sender_domain);
-                               return FALSE;
-                       }
-                       state = 1;
-                       pos++;
-                       p = ip_buf;
-                       dots = 0;
-                       break;
-               case 1:
-                       if (p - ip_buf >= (gint)sizeof (ip_buf)) {
-                               return FALSE;
-                       }
-                       if (g_ascii_isxdigit (*pos)) {
-                               *p++ = *pos++;
-                       }
-                       else if (*pos == '.' || *pos == ':') {
-                               *p++ = *pos++;
-                               dots++;
-                       }
-                       else if (*pos == '/') {
-                               pos++;
-                               p = mask_buf;
-                               state = 2;
-                       }
-                       else {
-                               /* Invalid character */
-                               msg_info ("<%s>: spf error for domain %s: invalid ip address",
-                                       rec->task->message_id, rec->sender_domain);
-                               return FALSE;
-                       }
-                       break;
-               case 2:
-                       /* Parse mask */
-                       if (p - mask_buf >= (gint)sizeof (mask_buf)) {
-                               msg_info ("<%s>: spf error for domain %s: too long mask",
-                                       rec->task->message_id, rec->sender_domain);
-                               return FALSE;
-                       }
-                       if (g_ascii_isdigit (*pos)) {
-                               *p++ = *pos++;
-                       }
-                       else {
-                               return FALSE;
-                       }
-                       break;
-               }
-       }
-
-       if (inet_pton (AF_INET, ip_buf, &addr->addr) != 1) {
-               if (inet_pton (AF_INET6, ip_buf, &addr->addr) == 1) {
-                       addr->flags |= RSPAMD_SPF_FLAG_IPV6;
-               }
-               else {
-                       msg_info ("<%s>: spf error for domain %s: invalid ip address",
-                               rec->task->message_id, rec->sender_domain);
-                       return FALSE;
-               }
-       }
-
-       if (state == 2) {
-               /* Also parse mask */
-               mask = strtoul (mask_buf, NULL, 10);
-               if (mask > (addr->flags & RSPAMD_SPF_FLAG_IPV6) ? 128 : 32) {
-                       msg_info (
-                                       "<%s>: spf error for domain %s: bad ipmask value: '%s'",
-                                       rec->task->message_id,
-                                       rec->sender_domain,
-                                       begin);
-                       return FALSE;
-               }
+       if (rec) {
+               for (i = 0; i < rec->resolved->len; i ++) {
+                       elt = &g_array_index (rec->resolved, struct spf_resolved_element, i);
 
-               if (addr->flags & RSPAMD_SPF_FLAG_IPV6) {
-                       addr->m.dual.mask_v6 = mask;
+                       /* Elts are destructed automatically here */
+                       g_ptr_array_free (elt->elts, TRUE);
+                       g_free (elt->cur_domain);
                }
-               else {
-                       addr->m.dual.mask_v4 = mask;
-               }
-
-       }
-       else {
-               addr->m.dual.mask_v6 = 128;
-               addr->m.dual.mask_v4 = 32;
+               g_array_free (rec->resolved, TRUE);
        }
-
-       return TRUE;
-
 }
 
 static void
@@ -337,6 +228,7 @@ rspamd_flatten_record_dtor (struct spf_resolved *r)
                g_free (addr->spf_string);
        }
 
+       g_free (r->domain);
        g_array_free (r->elts, TRUE);
        g_slice_free1 (sizeof (*r), r);
 }
@@ -408,6 +300,7 @@ rspamd_spf_record_flatten (struct spf_record *rec)
        res = g_slice_alloc (sizeof (*res));
        res->elts = g_array_sized_new (FALSE, FALSE, sizeof (struct spf_addr),
                        rec->resolved->len);
+       res->domain = g_strdup (rec->sender_domain);
        REF_INIT_RETAIN (res, rspamd_flatten_record_dtor);
 
        top = &g_array_index (rec->resolved, struct spf_resolved_element, 0);
@@ -417,6 +310,19 @@ rspamd_spf_record_flatten (struct spf_record *rec)
        return res;
 }
 
+static void
+rspamd_spf_maybe_return (struct spf_record *rec)
+{
+       struct spf_resolved *flat;
+
+       if (rec->requests_inflight == 0 && !rec->done) {
+               flat = rspamd_spf_record_flatten (rec);
+               rec->callback (flat, rec->task);
+               REF_RELEASE (flat);
+               rec->done = TRUE;
+       }
+}
+
 static gboolean
 spf_check_ptr_host (struct spf_dns_cb *cb, const char *name)
 {
@@ -480,9 +386,11 @@ spf_record_process_addr (struct spf_addr *addr, struct 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;
        }
        else {
                msg_err ("internal error, bad DNS reply is treated as address: %s",
@@ -511,6 +419,9 @@ spf_record_addr_set (struct spf_addr *addr, gboolean allow_any)
        memset (addr->addr6, fill, sizeof (addr->addr6));
        addr->m.dual.mask_v4 = maskv4;
        addr->m.dual.mask_v6 = maskv6;
+
+       addr->flags |= RSPAMD_SPF_FLAG_IPV4;
+       addr->flags |= RSPAMD_SPF_FLAG_IPV6;
 }
 
 static void
@@ -669,9 +580,7 @@ spf_record_dns_callback (struct rdns_reply *reply, gpointer arg)
                }
        }
 
-       if (cb->rec->requests_inflight == 0) {
-               cb->rec->callback (cb->rec, cb->rec->task);
-       }
+       rspamd_spf_maybe_return (cb->rec);
 }
 
 /*
@@ -1682,6 +1591,8 @@ start_spf_parse (struct spf_record *rec, gchar *begin)
                g_strfreev (elts);
        }
 
+       rspamd_spf_maybe_return (rec);
+
        return TRUE;
 }
 
@@ -1705,9 +1616,7 @@ spf_dns_callback (struct rdns_reply *reply, gpointer arg)
                }
        }
 
-       if (rec->requests_inflight == 0) {
-               rec->callback (rec, rec->task);
-       }
+       rspamd_spf_maybe_return (rec);
 }
 
 const gchar *
@@ -1741,6 +1650,8 @@ resolve_spf (struct rspamd_task *task, spf_cb_t callback)
        rec->task = task;
        rec->callback = callback;
 
+       rspamd_spf_new_addr_list (rec, rec->sender_domain);
+
        /* Add destructor */
        rspamd_mempool_add_destructor (task->task_pool,
                (rspamd_mempool_destruct_t)spf_record_destructor,
@@ -1765,8 +1676,6 @@ resolve_spf (struct rspamd_task *task, spf_cb_t callback)
                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)) {
@@ -1774,4 +1683,6 @@ resolve_spf (struct rspamd_task *task, spf_cb_t callback)
                rec->requests_inflight++;
                return TRUE;
        }
+
+       return FALSE;
 }
index 395e4ef0291c2c3e9a314d1742941b636c0d5b03..db220e03af81342fd9cc7657427d09b6b318fb7b 100644 (file)
@@ -50,6 +50,7 @@ struct spf_addr {
 };
 
 struct spf_resolved {
+       gchar *domain;
        GArray *elts; /* Flat list of struct spf_addr */
        ref_entry_t ref; /* Refcounting */
 };