aboutsummaryrefslogtreecommitdiffstats
path: root/src/spf.c
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@rambler-co.ru>2011-03-03 17:08:37 +0300
committerVsevolod Stakhov <vsevolod@rambler-co.ru>2011-03-03 17:08:37 +0300
commit2a2bc886c1b43a9c43a812959d7193cc03d7bc8d (patch)
tree99c0a23984497e9637a22e446d33b66c632788f1 /src/spf.c
parent0f2f88a6157250fecb9ce5d8d28b02b99739a2d2 (diff)
downloadrspamd-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.c176
1 files changed, 100 insertions, 76 deletions
diff --git a/src/spf.c b/src/spf.c
index f19665e79..233025ca3 100644
--- a/src/spf.c
+++ b/src/spf.c
@@ -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);