]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
Improve SPF parser.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 1 May 2014 14:02:11 +0000 (15:02 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 1 May 2014 14:02:11 +0000 (15:02 +0100)
- Simplify logic of parsing.
- Allow AAAA records for MX and PTR
- Implement PTR parsing
- Implement multiple addrs for A and AAAA records

src/libserver/spf.c
src/rdns

index 0800ad95b11bc7425dc1bd01718b97fdfe52cf37..50a4e09a9f251485ed9a0547051caa1a421a128d 100644 (file)
@@ -74,6 +74,7 @@
 struct spf_dns_cb {
        struct spf_record *rec;
        struct spf_addr *addr;
+       gchar *ptr_host;
        spf_action_t cur_action;
        gboolean in_include;
 };
@@ -386,6 +387,65 @@ parse_spf_hostmask (struct rspamd_task *task, const gchar *begin, struct spf_add
        return host;
 }
 
+static void
+spf_record_process_addr (struct rdns_reply_entry *elt,
+               struct spf_dns_cb *cb, struct rspamd_task *task)
+{
+       struct spf_addr *addr = cb->addr, *new_addr;
+       GList *tmp = NULL;
+
+       if (elt->type == RDNS_REQUEST_A) {
+               if (!addr->data.normal.parsed) {
+                       addr->data.normal.d.in4.s_addr = elt->content.a.addr.s_addr;
+                       addr->data.normal.mask = 32;
+                       addr->data.normal.parsed = TRUE;
+               }
+               else {
+                       /* Insert one more address */
+                       tmp = spf_addr_find (cb->rec->addrs, addr);
+                       if (tmp) {
+                               new_addr = rspamd_mempool_alloc (task->task_pool,
+                                               sizeof (struct spf_addr));
+                               memcpy (new_addr, addr, sizeof (struct spf_addr));
+                               new_addr->data.normal.d.in4.s_addr = elt->content.a.addr.s_addr;
+                               new_addr->data.normal.parsed = TRUE;
+                               cb->rec->addrs = g_list_insert_before (cb->rec->addrs, tmp, new_addr);
+                       }
+                       else {
+                               msg_info ("<%s>: spf error for domain %s: addresses mismatch",
+                                               task->message_id, cb->rec->sender_domain);
+                       }
+               }
+
+       }
+       else if (elt->type == RDNS_REQUEST_AAAA) {
+               if (!addr->data.normal.parsed) {
+                       memcpy (&addr->data.normal.d.in6,
+                                       &elt->content.aaa.addr, sizeof (struct in6_addr));
+                       addr->data.normal.mask = 32;
+                       addr->data.normal.parsed = TRUE;
+                       addr->data.normal.ipv6 = TRUE;
+               }
+               else {
+                       /* Insert one more address */
+                       tmp = spf_addr_find (cb->rec->addrs, addr);
+                       if (tmp) {
+                               new_addr = rspamd_mempool_alloc (task->task_pool, sizeof (struct spf_addr));
+                               memcpy (new_addr, addr, sizeof (struct spf_addr));
+                               memcpy (&new_addr->data.normal.d.in6,
+                                               &elt->content.aaa.addr, sizeof (struct in6_addr));
+                               new_addr->data.normal.parsed = TRUE;
+                               new_addr->data.normal.ipv6 = TRUE;
+                               cb->rec->addrs = g_list_insert_before (cb->rec->addrs, tmp, new_addr);
+                       }
+                       else {
+                               msg_info ("<%s>: spf error for domain %s: addresses mismatch",
+                                               task->message_id, cb->rec->sender_domain);
+                       }
+               }
+       }
+}
+
 static void
 spf_record_dns_callback (struct rdns_reply *reply, gpointer arg)
 {
@@ -408,95 +468,44 @@ spf_record_dns_callback (struct rdns_reply *reply, gpointer arg)
                                if (elt_data->type == RDNS_REQUEST_MX) {
                                        /* Now resolve A record for this MX */
                                        if (make_dns_request (task->resolver, task->s, task->task_pool,
-                                                       spf_record_dns_callback, (void *)cb, RDNS_REQUEST_A, elt_data->content.mx.name)) {
+                                                       spf_record_dns_callback, (void *)cb, RDNS_REQUEST_A,
+                                                       elt_data->content.mx.name)) {
                                                task->dns_requests ++;
                                                cb->rec->requests_inflight ++;
                                        }
-                               }
-                               else if (elt_data->type == RDNS_REQUEST_A) {
-                                       if (!cb->addr->data.normal.parsed) {
-                                               cb->addr->data.normal.d.in4.s_addr = elt_data->content.a.addr.s_addr;
-                                               cb->addr->data.normal.mask = 32;
-                                               cb->addr->data.normal.parsed = TRUE;
-                                       }
-                                       else {
-                                               /* Insert one more address */
-                                               tmp = spf_addr_find (cb->rec->addrs, cb->addr);
-                                               if (tmp) {
-                                                       new_addr = rspamd_mempool_alloc (task->task_pool, sizeof (struct spf_addr));
-                                                       memcpy (new_addr, cb->addr, sizeof (struct spf_addr));
-                                                       new_addr->data.normal.d.in4.s_addr = elt_data->content.a.addr.s_addr;
-                                                       new_addr->data.normal.parsed = TRUE;
-                                                       cb->rec->addrs = g_list_insert_before (cb->rec->addrs, tmp, new_addr);
-                                               }
-                                               else {
-                                                       msg_info ("<%s>: spf error for domain %s: addresses mismatch",
-                                                                       task->message_id, cb->rec->sender_domain);
-                                               }
+                                       if (make_dns_request (task->resolver, task->s, task->task_pool,
+                                                       spf_record_dns_callback, (void *)cb, RDNS_REQUEST_AAAA,
+                                                       elt_data->content.mx.name)) {
+                                               task->dns_requests ++;
+                                               cb->rec->requests_inflight ++;
                                        }
-
                                }
-#ifdef HAVE_INET_PTON
-                               else if (elt_data->type == RDNS_REQUEST_AAAA) {
-                                       if (!cb->addr->data.normal.parsed) {
-                                               memcpy (&cb->addr->data.normal.d.in6, &elt_data->content.aaa.addr, sizeof (struct in6_addr));
-                                               cb->addr->data.normal.mask = 32;
-                                               cb->addr->data.normal.parsed = TRUE;
-                                               cb->addr->data.normal.ipv6 = TRUE;
-                                       }
-                                       else {
-                                               /* Insert one more address */
-                                               tmp = spf_addr_find (cb->rec->addrs, cb->addr);
-                                               if (tmp) {
-                                                       new_addr = rspamd_mempool_alloc (task->task_pool, sizeof (struct spf_addr));
-                                                       memcpy (new_addr, cb->addr, sizeof (struct spf_addr));
-                                                       memcpy (&new_addr->data.normal.d.in6, &elt_data->content.aaa.addr, sizeof (struct in6_addr));
-                                                       new_addr->data.normal.parsed = TRUE;
-                                                       new_addr->data.normal.ipv6 = TRUE;
-                                                       cb->rec->addrs = g_list_insert_before (cb->rec->addrs, tmp, new_addr);
-                                               }
-                                               else {
-                                                       msg_info ("<%s>: spf error for domain %s: addresses mismatch",
-                                                                       task->message_id, cb->rec->sender_domain);
-                                               }
-                                       }
-
+                               else {
+                                       spf_record_process_addr (elt_data, cb, task);
                                }
-#endif
                                break;
                        case SPF_RESOLVE_A:
-                               if (elt_data->type == RDNS_REQUEST_A) {
-                                       /* XXX: process only one record */
-                                       cb->addr->data.normal.d.in4.s_addr = elt_data->content.a.addr.s_addr;
-                                       cb->addr->data.normal.mask = 32;
-                                       cb->addr->data.normal.parsed = TRUE;
-                               }
-#ifdef HAVE_INET_PTON
-                               else if (elt_data->type == RDNS_REQUEST_AAAA) {
-                                       memcpy (&cb->addr->data.normal.d.in6, &elt_data->content.aaa.addr, sizeof (struct in6_addr));
-                                       cb->addr->data.normal.mask = 32;
-                                       cb->addr->data.normal.parsed = TRUE;
-                                       cb->addr->data.normal.ipv6 = TRUE;
-                               }
-#endif
-                               break;
-#ifdef HAVE_INET_PTON
                        case SPF_RESOLVE_AAA:
-                               if (elt_data->type == RDNS_REQUEST_A) {
-                                       /* XXX: process only one record */
-                                       cb->addr->data.normal.d.in4.s_addr = elt_data->content.a.addr.s_addr;
-                                       cb->addr->data.normal.mask = 32;
-                                       cb->addr->data.normal.parsed = TRUE;
-                               }
-                               else if (elt_data->type == RDNS_REQUEST_AAAA) {
-                                       memcpy (&cb->addr->data.normal.d.in6, &elt_data->content.aaa.addr, sizeof (struct in6_addr));
-                                       cb->addr->data.normal.mask = 32;
-                                       cb->addr->data.normal.parsed = TRUE;
-                                       cb->addr->data.normal.ipv6 = TRUE;
-                               }
-#endif
+                               spf_record_process_addr (elt_data, cb, task);
                                break;
                        case SPF_RESOLVE_PTR:
+                               if (elt_data->type == RDNS_REQUEST_PTR) {
+                                       if (make_dns_request (task->resolver, task->s, task->task_pool,
+                                                       spf_record_dns_callback, (void *)cb, RDNS_REQUEST_A,
+                                                       elt_data->content.ptr.name)) {
+                                               task->dns_requests ++;
+                                               cb->rec->requests_inflight ++;
+                                       }
+                                       if (make_dns_request (task->resolver, task->s, task->task_pool,
+                                                       spf_record_dns_callback, (void *)cb, RDNS_REQUEST_AAAA,
+                                                       elt_data->content.ptr.name)) {
+                                               task->dns_requests ++;
+                                               cb->rec->requests_inflight ++;
+                                       }
+                               }
+                               else {
+                                       spf_record_process_addr (elt_data, cb, task);
+                               }
                                break;
                        case SPF_RESOLVE_REDIRECT:
                                if (elt_data->type == RDNS_REQUEST_TXT) {
@@ -536,7 +545,7 @@ spf_record_dns_callback (struct rdns_reply *reply, gpointer arg)
                        case SPF_RESOLVE_EXP:
                                break;
                        case SPF_RESOLVE_EXISTS:
-                               if (elt_data->type == RDNS_REQUEST_A) {
+                               if (elt_data->type == RDNS_REQUEST_A || elt_data->type == RDNS_REQUEST_AAAA) {
                                        /* If specified address resolves, we can accept connection from every IP */
                                        cb->addr->data.normal.d.in4.s_addr = INADDR_NONE;
                                        cb->addr->data.normal.mask = 0;
@@ -657,10 +666,47 @@ parse_spf_a (struct rspamd_task *task, const gchar *begin, struct spf_record *re
 static gboolean
 parse_spf_ptr (struct rspamd_task *task, const gchar *begin, struct spf_record *rec, struct spf_addr *addr)
 {
+       struct spf_dns_cb *cb;
+       gchar                           *host, *ptr;
+
        CHECK_REC (rec);
-       
-       msg_info ("<%s>: spf error for domain %s: ptr elements are not implemented",
-                       rec->task->message_id, rec->sender_domain);
+
+       if (begin == NULL) {
+               return FALSE;
+       }
+       if (*begin == ':') {
+               begin ++;
+               host = rspamd_mempool_strdup (task->task_pool, begin);
+       }
+       else if (*begin == '\0') {
+               host = rec->cur_domain;
+       }
+       else {
+               return FALSE;
+       }
+
+       rec->dns_requests ++;
+       cb = rspamd_mempool_alloc (task->task_pool, sizeof (struct spf_dns_cb));
+       cb->rec = rec;
+       cb->addr = addr;
+       memset (&addr->data.normal, 0, sizeof (addr->data.normal));
+       cb->cur_action = SPF_RESOLVE_PTR;
+       cb->in_include = rec->in_include;
+       cb->ptr_host = host;
+       ptr = rdns_generate_ptr_from_str (rspamd_inet_address_to_string (&task->from_addr));
+       if (ptr == NULL) {
+               return FALSE;
+       }
+       rspamd_mempool_add_destructor (task->task_pool, free, ptr);
+       if (make_dns_request (task->resolver, task->s, task->task_pool,
+                       spf_record_dns_callback, (void *)cb, RDNS_REQUEST_PTR, ptr)) {
+               task->dns_requests ++;
+               rec->requests_inflight ++;
+
+               return TRUE;
+       }
+
+       return FALSE;
        return TRUE;
 }
 
index 2838695f608ed5bb4ef3ed9dfd4d0a095bca2059..27f4808313ecfe37fbfffca91b7269e23e78d2d1 160000 (submodule)
--- a/src/rdns
+++ b/src/rdns
@@ -1 +1 @@
-Subproject commit 2838695f608ed5bb4ef3ed9dfd4d0a095bca2059
+Subproject commit 27f4808313ecfe37fbfffca91b7269e23e78d2d1