Browse Source

Improve SPF parser.

- Simplify logic of parsing.
- Allow AAAA records for MX and PTR
- Implement PTR parsing
- Implement multiple addrs for A and AAAA records
tags/0.7.0
Vsevolod Stakhov 10 years ago
parent
commit
b8566c7685
2 changed files with 129 additions and 83 deletions
  1. 128
    82
      src/libserver/spf.c
  2. 1
    1
      src/rdns

+ 128
- 82
src/libserver/spf.c View 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;
}


+ 1
- 1
src/rdns

@@ -1 +1 @@
Subproject commit 2838695f608ed5bb4ef3ed9dfd4d0a095bca2059
Subproject commit 27f4808313ecfe37fbfffca91b7269e23e78d2d1

Loading…
Cancel
Save