diff options
author | Vsevolod Stakhov <vsevolod@rambler-co.ru> | 2011-03-03 17:08:37 +0300 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@rambler-co.ru> | 2011-03-03 17:08:37 +0300 |
commit | 2a2bc886c1b43a9c43a812959d7193cc03d7bc8d (patch) | |
tree | 99c0a23984497e9637a22e446d33b66c632788f1 /src/spf.c | |
parent | 0f2f88a6157250fecb9ce5d8d28b02b99739a2d2 (diff) | |
download | rspamd-2a2bc886c1b43a9c43a812959d7193cc03d7bc8d.tar.gz rspamd-2a2bc886c1b43a9c43a812959d7193cc03d7bc8d.zip |
* Fix parsing of include records in spf parser
Diffstat (limited to 'src/spf.c')
-rw-r--r-- | src/spf.c | 176 |
1 files changed, 100 insertions, 76 deletions
@@ -126,25 +126,57 @@ dump_spf_record (GList *addrs) while (cur) { addr = cur->data; - switch (addr->mech) { - case SPF_FAIL: - c = '-'; - break; - case SPF_SOFT_FAIL: - case SPF_NEUTRAL: - c = '~'; - break; - case SPF_PASS: - c = '+'; - break; + if (!addr->is_list) { + switch (addr->mech) { + case SPF_FAIL: + c = '-'; + break; + case SPF_SOFT_FAIL: + case SPF_NEUTRAL: + c = '~'; + break; + case SPF_PASS: + c = '+'; + break; + } + ina.s_addr = htonl (addr->data.normal.addr); + r += snprintf (logbuf + r, sizeof (logbuf) - r, "%c%s/%d; ", c, inet_ntoa (ina), addr->data.normal.mask); + } + else { + r += snprintf (logbuf + r, sizeof (logbuf) - r, "%s; ", addr->spf_string); + dump_spf_record (addr->data.list); } - ina.s_addr = htonl (addr->addr); - r += snprintf (logbuf + r, sizeof (logbuf) - r, "%c%s/%d; ", c, inet_ntoa (ina), addr->mask); cur = g_list_next (cur); } msg_info ("spf record: %s", logbuf); } +/* Find position of address inside addrs list */ +static GList * +spf_addr_find (GList *addrs, gpointer to_find) +{ + struct spf_addr *addr; + GList *cur, *res = NULL; + + cur = addrs; + while (cur) { + addr = cur->data; + if (addr->is_list) { + if ((res = spf_addr_find (addr->data.list, to_find)) != NULL) { + return res; + } + } + else { + if (cur->data == to_find) { + return cur; + } + } + cur = g_list_next (cur); + } + + return res; +} + /* * Destructor for spf record */ @@ -152,8 +184,18 @@ static void spf_record_destructor (gpointer r) { struct spf_record *rec = r; + GList *cur; + struct spf_addr *addr; 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); } } @@ -223,17 +265,17 @@ parse_spf_ipmask (const gchar *begin, struct spf_addr *addr) if (!inet_aton (ip_buf, &in)) { return FALSE; } - addr->addr = ntohl (in.s_addr); + addr->data.normal.addr = ntohl (in.s_addr); if (state == 2) { /* Also parse mask */ - addr->mask = (mask_buf[0] - '0') * 10 + mask_buf[1] - '0'; - if (addr->mask > 32) { + addr->data.normal.mask = (mask_buf[0] - '0') * 10 + mask_buf[1] - '0'; + if (addr->data.normal.mask > 32) { msg_info ("bad ipmask value: '%s'", begin); return FALSE; } } else { - addr->mask = 32; + addr->data.normal.mask = 32; } return TRUE; @@ -255,8 +297,8 @@ parse_spf_hostmask (struct worker_task *task, const gchar *begin, struct spf_add if (p != NULL) { /* Extract mask */ rspamd_strlcpy (mask_buf, p + 1, sizeof (mask_buf)); - addr->mask = mask_buf[0] * 10 + mask_buf[1]; - if (addr->mask > 32) { + addr->data.normal.mask = mask_buf[0] * 10 + mask_buf[1]; + if (addr->data.normal.mask > 32) { return FALSE; } if (host == NULL) { @@ -266,7 +308,7 @@ parse_spf_hostmask (struct worker_task *task, const gchar *begin, struct spf_add } } else { - addr->mask = 32; + addr->data.normal.mask = 32; if (host == NULL) { host = memory_pool_strdup (task->task_pool, begin); } @@ -281,8 +323,7 @@ spf_record_dns_callback (struct rspamd_dns_reply *reply, gpointer arg) struct spf_dns_cb *cb = arg; gchar *begin; union rspamd_reply_element *elt_data; - GList *tmp = NULL, *tmp1, - *elt, *last; + GList *tmp = NULL, *elt; struct worker_task *task; struct spf_addr *new_addr; @@ -303,17 +344,17 @@ spf_record_dns_callback (struct rspamd_dns_reply *reply, gpointer arg) } } else if (reply->type == DNS_REQUEST_A) { - if (cb->addr->addr == 0) { - cb->addr->addr = ntohl (elt_data->a.addr[0].s_addr); - cb->addr->mask = 32; + if (cb->addr->data.normal.addr == 0) { + cb->addr->data.normal.addr = ntohl (elt_data->a.addr[0].s_addr); + cb->addr->data.normal.mask = 32; } else { /* Insert one more address */ - tmp = g_list_find (cb->rec->addrs, cb->addr); + tmp = spf_addr_find (cb->rec->addrs, cb->addr); if (tmp) { new_addr = memory_pool_alloc (task->task_pool, sizeof (struct spf_addr)); memcpy (new_addr, cb->addr, sizeof (struct spf_addr)); - new_addr->addr = ntohl (elt_data->a.addr[0].s_addr); + new_addr->data.normal.addr = ntohl (elt_data->a.addr[0].s_addr); cb->rec->addrs = g_list_insert_before (cb->rec->addrs, tmp, new_addr); } else { @@ -326,8 +367,8 @@ spf_record_dns_callback (struct rspamd_dns_reply *reply, gpointer arg) case SPF_RESOLVE_A: if (reply->type == DNS_REQUEST_A) { /* XXX: process only one record */ - cb->addr->addr = ntohl (elt_data->a.addr[0].s_addr); - cb->addr->mask = 32; + cb->addr->data.normal.addr = ntohl (elt_data->a.addr[0].s_addr); + cb->addr->data.normal.mask = 32; } break; case SPF_RESOLVE_PTR: @@ -351,40 +392,20 @@ spf_record_dns_callback (struct rspamd_dns_reply *reply, gpointer arg) msg_info ("before include"); dump_spf_record (cb->rec->addrs); #endif - if (cb->rec->addrs) { - tmp = cb->rec->addrs; - cb->rec->addrs = NULL; - } + tmp = cb->rec->addrs; + cb->rec->addrs = NULL; cb->rec->in_include = TRUE; start_spf_parse (cb->rec, begin); cb->rec->in_include = FALSE; - if (tmp && cb->rec->addrs) { - tmp1 = g_list_find (tmp, cb->addr); - if (tmp1) { - /* Insert new list in place of include element */ - cb->rec->addrs->prev = tmp1->prev; - last = g_list_last (cb->rec->addrs); - last->next = tmp1; - tmp1->prev = last; - /* If tmp1 is at the beginning of the list, shift list */ - if (tmp == tmp1) { - tmp = cb->rec->addrs; - } - else { - tmp1->prev->next = cb->rec->addrs; - } - /* Remove self element */ - tmp = g_list_delete_link (tmp, tmp1); #ifdef SPF_DEBUG - msg_info ("after include"); - dump_spf_record (cb->rec->addrs); + msg_info ("after include"); + dump_spf_record (cb->rec->addrs); #endif - } - } - if (tmp) { - cb->rec->addrs = tmp; - } + /* Insert new list */ + cb->addr->is_list = TRUE; + cb->addr->data.list = cb->rec->addrs; + cb->rec->addrs = tmp; } break; case SPF_RESOLVE_EXP: @@ -392,8 +413,8 @@ spf_record_dns_callback (struct rspamd_dns_reply *reply, gpointer arg) case SPF_RESOLVE_EXISTS: if (reply->type == DNS_REQUEST_A) { /* If specified address resolves, we can accept connection from every IP */ - cb->addr->addr = ntohl (INADDR_ANY); - cb->addr->mask = 0; + cb->addr->data.normal.addr = ntohl (INADDR_ANY); + cb->addr->data.normal.mask = 0; } break; } @@ -406,20 +427,20 @@ spf_record_dns_callback (struct rspamd_dns_reply *reply, gpointer arg) case SPF_RESOLVE_MX: if (reply->type == DNS_REQUEST_MX) { msg_info ("cannot find MX record for %s", cb->rec->cur_domain); - cb->addr->addr = ntohl (INADDR_NONE); - cb->addr->mask = 32; + cb->addr->data.normal.addr = ntohl (INADDR_NONE); + cb->addr->data.normal.mask = 32; } else if (reply->type != DNS_REQUEST_MX) { msg_info ("cannot resolve MX record for %s", cb->rec->cur_domain); - cb->addr->addr = ntohl (INADDR_NONE); - cb->addr->mask = 32; + cb->addr->data.normal.addr = ntohl (INADDR_NONE); + cb->addr->data.normal.mask = 32; } break; case SPF_RESOLVE_A: if (reply->type == DNS_REQUEST_A) { /* XXX: process only one record */ - cb->addr->addr = ntohl (INADDR_NONE); - cb->addr->mask = 32; + cb->addr->data.normal.addr = ntohl (INADDR_NONE); + cb->addr->data.normal.mask = 32; } break; case SPF_RESOLVE_PTR: @@ -433,8 +454,8 @@ spf_record_dns_callback (struct rspamd_dns_reply *reply, gpointer arg) case SPF_RESOLVE_EXP: break; case SPF_RESOLVE_EXISTS: - cb->addr->addr = ntohl (INADDR_NONE); - cb->addr->mask = 32; + cb->addr->data.normal.addr = ntohl (INADDR_NONE); + cb->addr->data.normal.mask = 32; break; } } @@ -514,7 +535,7 @@ parse_spf_mx (struct worker_task *task, const gchar *begin, struct spf_record *r cb = memory_pool_alloc (task->task_pool, sizeof (struct spf_dns_cb)); cb->rec = rec; cb->addr = addr; - addr->addr = 0; + addr->data.normal.addr = 0; cb->cur_action = SPF_RESOLVE_MX; cb->in_include = rec->in_include; if (make_dns_request (task->resolver, task->s, task->task_pool, spf_record_dns_callback, (void *)cb, DNS_REQUEST_MX, host)) { @@ -532,12 +553,12 @@ parse_spf_all (struct worker_task *task, const gchar *begin, struct spf_record * /* All is 0/0 */ if (rec->in_include) { /* Ignore all record in include */ - addr->addr = 0; - addr->mask = 32; + addr->data.normal.addr = 0; + addr->data.normal.mask = 32; } else { - addr->addr = 0; - addr->mask = 0; + addr->data.normal.addr = 0; + addr->data.normal.mask = 0; } return TRUE; @@ -571,6 +592,8 @@ parse_spf_include (struct worker_task *task, const gchar *begin, struct spf_reco cb->addr = addr; cb->cur_action = SPF_RESOLVE_INCLUDE; cb->in_include = rec->in_include; + addr->is_list = TRUE; + addr->data.list = NULL; domain = memory_pool_strdup (task->task_pool, begin); if (make_dns_request (task->resolver, task->s, task->task_pool, spf_record_dns_callback, (void *)cb, DNS_REQUEST_TXT, domain)) { task->save.saved++; @@ -634,7 +657,7 @@ parse_spf_exists (struct worker_task *task, const gchar *begin, struct spf_recor begin ++; rec->dns_requests ++; - addr->mask = 32; + addr->data.normal.mask = 32; cb = memory_pool_alloc (task->task_pool, sizeof (struct spf_dns_cb)); cb->rec = rec; cb->addr = addr; @@ -910,8 +933,9 @@ expand_spf_macro (struct worker_task *task, struct spf_record *rec, gchar *begin (x) = memory_pool_alloc (task->task_pool, sizeof (struct spf_addr)); \ (x)->mech = check_spf_mech (rec->cur_elt, &need_shift); \ (x)->spf_string = memory_pool_strdup (task->task_pool, begin); \ - (x)->addr = 0; \ - (x)->mask = 32; \ + (x)->data.normal.addr = 0; \ + (x)->data.normal.mask = 32; \ + (x)->is_list = FALSE; \ } while (0); /* Read current element and try to parse record */ @@ -1183,7 +1207,7 @@ resolve_spf (struct worker_task *task, spf_cb_t callback) rec->cur_domain = memory_pool_strdup (task->task_pool, domains->data); g_list_free (domains); - if ((domain = strchr (rec->cur_domain, '@')) == NULL) { + if ((domain = strrchr (rec->cur_domain, '@')) == NULL) { return FALSE; } rec->sender = memory_pool_strdup (task->task_pool, rec->cur_domain); |