]> source.dussan.org Git - rspamd.git/commitdiff
Add records flattening logic.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Wed, 18 Mar 2015 16:43:46 +0000 (16:43 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Wed, 18 Mar 2015 16:43:46 +0000 (16:43 +0000)
src/libserver/spf.c

index 163ebf5c2cae93a2edb26b7ff8014ad48e4f4687..69693db6f75e2f49393c0ea504986202ee93f470 100644 (file)
@@ -101,7 +101,7 @@ struct spf_dns_cb {
        gboolean in_include;
 };
 
-#define CHECK_REC(rec)                                      \
+#define CHECK_REC(rec)                                          \
        do {                                                        \
                if ((rec)->nested > SPF_MAX_NESTING ||                  \
                        (rec)->dns_requests > SPF_MAX_DNS_REQUESTS) {       \
@@ -113,8 +113,7 @@ struct spf_dns_cb {
        } while (0)                                                 \
 
 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);
+static gboolean start_spf_parse (struct spf_record *rec, gchar *begin);
 
 /* Determine spf mech */
 static spf_mech_t
@@ -327,6 +326,97 @@ parse_spf_ipmask (const gchar *begin,
 
 }
 
+static void
+rspamd_flatten_record_dtor (struct spf_resolved *r)
+{
+       struct spf_addr *addr;
+       guint i;
+
+       for (i = 0; i < r->elts; i ++) {
+               addr = &g_array_index (r->elts, struct spf_addr, i);
+               g_free (addr->spf_string);
+       }
+
+       g_array_free (r->elts, TRUE);
+       g_slice_free1 (sizeof (*r), r);
+}
+
+static void
+rspamd_spf_process_reference (struct spf_resolved *target,
+               struct spf_addr *addr, struct spf_record *rec, gboolean top)
+{
+       struct spf_resolved_element *elt;
+       struct spf_addr *cur, taddr;
+       guint i;
+
+       if (addr) {
+               g_assert (addr->m.idx < rec->resolved->len);
+
+               elt = &g_array_index (rec->resolved, struct spf_resolved_element,
+                               addr->m.idx);
+       }
+       else {
+               elt = &g_array_index (rec->resolved, struct spf_resolved_element, 0);
+       }
+
+       while (elt->redirected) {
+               cur = g_ptr_array_index (elt->elts, 0);
+               g_assert (cur->flags & RSPAMD_SPF_FLAG_REFRENCE);
+               g_assert (cur->m.idx < rec->resolved->len);
+               elt = &g_array_index (rec->resolved, struct spf_resolved_element,
+                               cur->m.idx);
+       }
+
+       for (i = 0; i < elt->elts->len; i ++) {
+               cur = g_ptr_array_index (elt->elts, i);
+
+               if (!(cur->flags & RSPAMD_SPF_FLAG_PARSED)) {
+                       /* Ignore unparsed addrs */
+                       continue;
+               }
+               else if (cur->flags & RSPAMD_SPF_FLAG_REFRENCE) {
+                       /* Process reference */
+                       rspamd_spf_process_reference (target, cur, rec, FALSE);
+               }
+               else {
+                       if ((cur->flags & RSPAMD_SPF_FLAG_ANY) && !top) {
+                               /* Ignore wide policies in includes */
+                               continue;
+                       }
+
+                       memcpy (&taddr, cur, sizeof (taddr));
+                       /* Steal element */
+                       cur->spf_string = NULL;
+                       g_array_append_val (target->elts, taddr);
+               }
+       }
+}
+
+/*
+ * Parse record and flatten it to a simple structure
+ */
+static struct spf_resolved *
+rspamd_spf_record_flatten (struct spf_record *rec)
+{
+       struct spf_resolved *res;
+
+       struct spf_resolved_element *top;
+       guint i;
+
+       g_assert (rec != NULL);
+
+       res = g_slice_alloc (sizeof (*res));
+       res->elts = g_array_sized_new (FALSE, FALSE, sizeof (struct spf_addr),
+                       rec->resolved->len);
+       REF_INIT_RETAIN (res, rspamd_flatten_record_dtor);
+
+       top = &g_array_index (rec->resolved, struct spf_resolved_element, 0);
+
+       rspamd_spf_process_reference (res->elts, NULL, rec, TRUE);
+
+       return res;
+}
+
 static gboolean
 spf_check_ptr_host (struct spf_dns_cb *cb, const char *name)
 {
@@ -549,13 +639,11 @@ spf_record_dns_callback (struct rdns_reply *reply, gpointer arg)
                                spf_record_addr_set (addr, FALSE);
                        }
                        break;
-#ifdef HAVE_INET_PTON
                case SPF_RESOLVE_AAA:
                        if (rdns_request_has_type (reply->request, RDNS_REQUEST_AAAA)) {
                                spf_record_addr_set (addr, FALSE);
                        }
                        break;
-#endif
                case SPF_RESOLVE_PTR:
                        spf_record_addr_set (addr, FALSE);
                        break;
@@ -858,7 +946,6 @@ parse_spf_ip4 (struct spf_record *rec, struct spf_addr *addr)
        return parse_spf_ipmask (addr->spf_string, addr, rec);
 }
 
-#ifdef HAVE_INET_PTON
 static gboolean
 parse_spf_ip6 (struct spf_record *rec, struct spf_addr *addr)
 {
@@ -867,7 +954,7 @@ parse_spf_ip6 (struct spf_record *rec, struct spf_addr *addr)
        CHECK_REC (rec);
        return parse_spf_ipmask (addr->spf_string, addr, rec);
 }
-#endif
+
 
 static gboolean
 parse_spf_include (struct spf_record *rec, struct spf_addr *addr)
@@ -1052,9 +1139,7 @@ expand_spf_macro (struct spf_record *rec,
        const gchar *p, *c;
        gchar *new, *tmp;
        gint len = 0, slen = 0, state = 0;
-#ifdef HAVE_INET_PTON
        gchar ip_buf[INET6_ADDRSTRLEN];
-#endif
        gboolean need_expand = FALSE;
        struct rspamd_task *task;
        struct spf_resolved_element *resolved;
@@ -1109,11 +1194,7 @@ expand_spf_macro (struct spf_record *rec,
                        /* Read macro name */
                        switch (g_ascii_tolower (*p)) {
                        case 'i':
-#ifdef HAVE_INET_PTON
                                len += INET6_ADDRSTRLEN - 1;
-#else
-                               len += INET_ADDRSTRLEN - 1;
-#endif
                                break;
                        case 's':
                                len += strlen (rec->sender);
@@ -1526,6 +1607,7 @@ start_spf_parse (struct spf_record *rec, gchar *begin)
 
                g_strfreev (elts);
        }
+
        return TRUE;
 }
 
@@ -1619,7 +1701,3 @@ resolve_spf (struct rspamd_task *task, spf_cb_t callback)
                return TRUE;
        }
 }
-
-/*
- * vi:ts=4
- */