From cb274a2fd8b3b6c1f4cd6842e1cf79bb0c63d8a4 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Wed, 22 Oct 2014 16:21:18 +0100 Subject: [PATCH] Verify spf PTR records. Reported by: @citrin --- src/libserver/spf.c | 87 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 73 insertions(+), 14 deletions(-) diff --git a/src/libserver/spf.c b/src/libserver/spf.c index 98a95bdf3..67b119e12 100644 --- a/src/libserver/spf.c +++ b/src/libserver/spf.c @@ -480,6 +480,60 @@ spf_record_process_addr (struct rdns_reply_entry *elt, } } +static gboolean +spf_check_ptr_host (struct spf_dns_cb *cb, const char *name) +{ + const char *dend, *nend, *dstart, *nstart; + + if (name == NULL) { + return FALSE; + } + if (cb->ptr_host == NULL) { + /* We need to check whether `cur_domain` is a subdomain for `name` */ + dstart = cb->rec->cur_domain; + dend = dstart + strlen (dstart) - 1; + nstart = name; + nend = nstart + strlen (nstart) - 1; + + if (nend == nstart || dend == dstart) { + return FALSE; + } + /* Strip last '.' from names */ + if (*nend == '.') { + nend --; + } + if (*dend == '.') { + dend --; + } + + /* Now compare from end to start */ + for (;;) { + if (g_ascii_tolower (*dend) != g_ascii_tolower (*nend)) { + return FALSE; + } + if (dend == dstart) { + break; + } + if (nend == nstart) { + /* Name is shorter than cur_domain */ + return FALSE; + } + nend --; + dend --; + } + if (nend != nstart && *(nend - 1) != '.') { + /* Not a subdomain */ + return FALSE; + } + } + else { + dstart = cb->rec->cur_domain; + return rspamd_strcase_equal (dstart, name); + } + + return TRUE; +} + static void spf_record_dns_callback (struct rdns_reply *reply, gpointer arg) { @@ -526,19 +580,24 @@ spf_record_dns_callback (struct rdns_reply *reply, gpointer arg) 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++; + /* Validate returned records prior to making A requests */ + if (spf_check_ptr_host (cb, elt_data->content.ptr.name)) { + 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 { @@ -737,7 +796,7 @@ parse_spf_ptr (struct rspamd_task *task, host = rspamd_mempool_strdup (task->task_pool, begin); } else if (*begin == '\0') { - host = rec->cur_domain; + host = NULL; } else { return FALSE; -- 2.39.5