Browse Source

Fix parsing routines.

tags/0.9.0
Vsevolod Stakhov 9 years ago
parent
commit
d6cbb11077
1 changed files with 182 additions and 205 deletions
  1. 182
    205
      src/libserver/spf.c

+ 182
- 205
src/libserver/spf.c View File

@@ -911,10 +911,7 @@ parse_spf_ptr (struct rspamd_task *task,
}

static gboolean
parse_spf_mx (struct rspamd_task *task,
const gchar *begin,
struct spf_record *rec,
struct spf_addr *addr)
parse_spf_mx (struct spf_record *rec, struct spf_addr *addr)
{
struct spf_dns_cb *cb;
gchar *host;
@@ -952,76 +949,66 @@ parse_spf_mx (struct rspamd_task *task,
}

static gboolean
parse_spf_all (struct rspamd_task *task,
const gchar *begin,
struct spf_record *rec,
struct spf_addr *addr)
parse_spf_all (struct spf_record *rec, struct spf_addr *addr)
{
/* All is 0/0 */
memset (&addr->data.normal.d, 0, sizeof (addr->data.normal.d));
if (rec->in_include) {
/* Ignore all record in include */
addr->data.normal.mask = 32;
}
else {
addr->data.normal.mask = 0;
addr->data.normal.addr_any = TRUE;
}
memset (&addr->addr, 0, sizeof (addr->addr));
addr->m.mask = 0;
addr->flags |= RSPAMD_SPF_FLAG_ANY;

return TRUE;
}

static gboolean
parse_spf_ip4 (struct rspamd_task *task,
const gchar *begin,
struct spf_record *rec,
struct spf_addr *addr)
parse_spf_ip4 (struct spf_record *rec, struct spf_addr *addr)
{
/* ip4:addr[/mask] */

CHECK_REC (rec);
return parse_spf_ipmask (begin, addr, rec);
return parse_spf_ipmask (addr->spf_string, addr, rec);
}

#ifdef HAVE_INET_PTON
static gboolean
parse_spf_ip6 (struct rspamd_task *task,
const gchar *begin,
struct spf_record *rec,
struct spf_addr *addr)
parse_spf_ip6 (struct spf_record *rec, struct spf_addr *addr)
{
/* ip6:addr[/mask] */

CHECK_REC (rec);
return parse_spf_ipmask (begin, addr, rec);
return parse_spf_ipmask (addr->spf_string, addr, rec);
}
#endif

static gboolean
parse_spf_include (struct rspamd_task *task,
const gchar *begin,
struct spf_record *rec,
struct spf_addr *addr)
parse_spf_include (struct spf_record *rec, struct spf_addr *addr)
{
struct spf_dns_cb *cb;
gchar *domain;
struct spf_resolved_element *resolved;
struct rspamd_task *task = rec->task;

resolved = &g_array_index (rec->resolved, struct spf_resolved_element,
rec->resolved->len - 1);

CHECK_REC (rec);
domain = strchr (addr->spf_string, '=');

if (begin == NULL || *begin != ':') {
if (domain == NULL) {
return FALSE;
}
begin++;

domain++;

rec->dns_requests++;

cb = rspamd_mempool_alloc (task->task_pool, sizeof (struct spf_dns_cb));
cb->rec = rec;
cb->addr = addr;
cb->cur_action = SPF_RESOLVE_INCLUDE;
cb->in_include = rec->in_include;
addr->is_list = TRUE;
addr->data.list = NULL;
domain = rspamd_mempool_strdup (task->task_pool, begin);
/* Set reference */
addr->flags |= RSPAMD_SPF_FLAG_REFRENCE;
addr->m.mask = rec->resolved->len;
rspamd_spf_new_addr_list (rec, domain);
msg_debug ("resolve include %s", domain);

if (make_dns_request (task->resolver, task->s, task->task_pool,
@@ -1037,10 +1024,7 @@ parse_spf_include (struct rspamd_task *task,
}

static gboolean
parse_spf_exp (struct rspamd_task *task,
const gchar *begin,
struct spf_record *rec,
struct spf_addr *addr)
parse_spf_exp (struct spf_record *rec, struct spf_addr *addr)
{
CHECK_REC (rec);

@@ -1049,29 +1033,51 @@ parse_spf_exp (struct rspamd_task *task,
}

static gboolean
parse_spf_redirect (struct rspamd_task *task,
const gchar *begin,
struct spf_record *rec,
struct spf_addr *addr)
parse_spf_redirect (struct spf_record *rec, struct spf_addr *addr)
{
struct spf_dns_cb *cb;
gchar *domain;
const gchar *domain;
struct spf_resolved_element *resolved;
struct spf_addr *cur;
struct rspamd_task *task = rec->task;
guint i;

resolved = &g_array_index (rec->resolved, struct spf_resolved_element,
rec->resolved->len - 1);

CHECK_REC (rec);

if (begin == NULL || *begin != '=') {
domain = strchr (addr->spf_string, '=');

if (domain == NULL) {
return FALSE;
}
begin++;

domain++;

rec->dns_requests++;
resolved->redirected = TRUE;

/* Now clear all elements but this one */
for (i = 0; i < resolved->elts->len; i ++) {
cur = g_ptr_array_index (resolved->elts, i);

if (cur != addr) {
g_ptr_array_remove_index_fast (resolved->elts, i);
}
}

cb = rspamd_mempool_alloc (task->task_pool, sizeof (struct spf_dns_cb));
/* Set reference */
addr->flags |= RSPAMD_SPF_FLAG_REFRENCE;
addr->m.mask = rec->resolved->len;
rspamd_spf_new_addr_list (rec, domain);

cb->rec = rec;
cb->addr = addr;
cb->cur_action = SPF_RESOLVE_REDIRECT;
cb->in_include = rec->in_include;
domain = rspamd_mempool_strdup (task->task_pool, begin);
msg_debug ("resolve redirect %s", domain);

if (make_dns_request (task->resolver, task->s, task->task_pool,
spf_record_dns_callback, (void *)cb, RDNS_REQUEST_TXT, domain)) {
task->dns_requests++;
@@ -1084,29 +1090,27 @@ parse_spf_redirect (struct rspamd_task *task,
}

static gboolean
parse_spf_exists (struct rspamd_task *task,
const gchar *begin,
struct spf_record *rec,
struct spf_addr *addr)
parse_spf_exists (struct spf_record *rec, struct spf_addr *addr)
{
struct spf_dns_cb *cb;
gchar *host;
const gchar *host;
struct rspamd_task *task = rec->task;

CHECK_REC (rec);

if (begin == NULL || *begin != ':') {
host = strchr (addr->spf_string, ':');
if (host == NULL) {
msg_info ("bad SPF exist record: %s", addr->spf_string);
return FALSE;
}
begin++;

host ++;
rec->dns_requests++;

addr->data.normal.mask = 32;
cb = rspamd_mempool_alloc (task->task_pool, sizeof (struct spf_dns_cb));
cb->rec = rec;
cb->addr = addr;
cb->cur_action = SPF_RESOLVE_EXISTS;
cb->in_include = rec->in_include;
host = rspamd_mempool_strdup (task->task_pool, begin);

msg_debug ("resolve exists %s", host);
if (make_dns_request (task->resolver, task->s, task->task_pool,
@@ -1152,17 +1156,26 @@ reverse_spf_ip (gchar *ip, gint len)
memcpy (ip, ipbuf, len);
}

static gchar *
expand_spf_macro (struct rspamd_task *task, struct spf_record *rec,
gchar *begin)
static const gchar *
expand_spf_macro (struct spf_record *rec,
const gchar *begin)
{
gchar *p, *c, *new, *tmp;
const gchar *p, *c;
gchar *new, *tmp;
gint len = 0, slen = 0, state = 0;
#ifdef HAVE_INET_PTON
gchar ip_buf[INET6_ADDRSTRLEN];
#endif
gboolean need_expand = FALSE;
struct rspamd_task *task;
struct spf_resolved_element *resolved;

g_assert (rec != NULL);
g_assert (begin != NULL);

task = rec->task;
resolved = &g_array_index (rec->resolved, struct spf_resolved_element,
rec->resolved->len - 1);
p = begin;
/* Calculate length */
while (*p) {
@@ -1223,7 +1236,7 @@ expand_spf_macro (struct rspamd_task *task, struct spf_record *rec,
len += strlen (rec->sender_domain);
break;
case 'd':
len += strlen (rec->cur_domain);
len += strlen (resolved->cur_domain);
break;
case 'v':
len += sizeof ("in-addr") - 1;
@@ -1348,8 +1361,8 @@ expand_spf_macro (struct rspamd_task *task, struct spf_record *rec,
c += len;
break;
case 'd':
len = strlen (rec->cur_domain);
memcpy (c, rec->cur_domain, len);
len = strlen (resolved->cur_domain);
memcpy (c, resolved->cur_domain, len);
c += len;
break;
case 'v':
@@ -1411,174 +1424,138 @@ expand_spf_macro (struct rspamd_task *task, struct spf_record *rec,

}

#define NEW_ADDR(x) do { \
(x) = rspamd_mempool_alloc (task->task_pool, sizeof (struct spf_addr)); \
(x)->mech = check_spf_mech (rec->cur_elt, &need_shift); \
(x)->spf_string = rspamd_mempool_strdup (task->task_pool, begin); \
memset (&(x)->data.normal, 0, sizeof ((x)->data.normal)); \
(x)->data.normal.mask = 32; \
(x)->is_list = FALSE; \
} while (0);

/* Read current element and try to parse record */
static gboolean
parse_spf_record (struct rspamd_task *task, struct spf_record *rec)
parse_spf_record (struct spf_record *rec, const gchar *elt)
{
struct spf_addr *new = NULL;
gboolean need_shift, res = FALSE;
gchar *begin;
struct spf_addr *addr = NULL;
gboolean res = FALSE;
const gchar *begin;
struct rspamd_task *task;
struct spf_resolved_element *resolved;
gchar t;

rec->cur_elt = rec->elts[rec->elt_num];
if (rec->cur_elt == NULL) {
return FALSE;
}
else if (*rec->cur_elt == '\0') {
/* Silently skip empty elements */
rec->elt_num++;
resolved = &g_array_index (rec->resolved, struct spf_resolved_element,
rec->resolved->len - 1);
g_assert (elt != NULL);
g_assert (rec != NULL);
if (*elt == '\0' || resolved->redirected) {
return TRUE;
}
else {
begin = expand_spf_macro (task, rec, rec->cur_elt);
if (*begin == '?' || *begin == '+' || *begin == '-' || *begin == '~') {
begin++;
}

task = rec->task;
begin = expand_spf_macro (rec, elt);
addr = rspamd_spf_new_addr (rec, begin);
g_assert (addr != NULL);
t = g_ascii_tolower (addr->spf_string[0]);
begin = addr->spf_string;

/* Now check what we have */
switch (g_ascii_tolower (*begin)) {
case 'a':
/* all or a */
if (g_ascii_strncasecmp (begin, SPF_ALL,
/* Now check what we have */
switch (t) {
case 'a':
/* all or a */
if (g_ascii_strncasecmp (begin, SPF_ALL,
sizeof (SPF_ALL) - 1) == 0) {
NEW_ADDR (new);
begin += sizeof (SPF_ALL) - 1;
res = parse_spf_all (task, begin, rec, new);
}
else if (g_ascii_strncasecmp (begin, SPF_A,
res = parse_spf_all (rec, addr);
}
else if (g_ascii_strncasecmp (begin, SPF_A,
sizeof (SPF_A) - 1) == 0) {
NEW_ADDR (new);
begin += sizeof (SPF_A) - 1;
res = parse_spf_a (task, begin, rec, new);
}
else {
msg_info ("<%s>: spf error for domain %s: bad spf command %s",
res = parse_spf_a (rec, addr);
}
else {
msg_info ("<%s>: spf error for domain %s: bad spf command %s",
task->message_id, rec->sender_domain, begin);
}
break;
case 'i':
/* include or ip4 */
if (g_ascii_strncasecmp (begin, SPF_IP4,
}
break;
case 'i':
/* include or ip4 */
if (g_ascii_strncasecmp (begin, SPF_IP4,
sizeof (SPF_IP4) - 1) == 0) {
NEW_ADDR (new);
begin += sizeof (SPF_IP4) - 1;
res = parse_spf_ip4 (task, begin, rec, new);
}
else if (g_ascii_strncasecmp (begin, SPF_INCLUDE,
res = parse_spf_ip4 (rec, addr);
}
else if (g_ascii_strncasecmp (begin, SPF_INCLUDE,
sizeof (SPF_INCLUDE) - 1) == 0) {
NEW_ADDR (new);
begin += sizeof (SPF_INCLUDE) - 1;
res = parse_spf_include (task, begin, rec, new);
}
else if (g_ascii_strncasecmp (begin, SPF_IP6, sizeof (SPF_IP6) -
res = parse_spf_include (rec, addr);
}
else if (g_ascii_strncasecmp (begin, SPF_IP6, sizeof (SPF_IP6) -
1) == 0) {
#ifdef HAVE_INET_PTON
NEW_ADDR (new);
begin += sizeof (SPF_IP6) - 1;
res = parse_spf_ip6 (task, begin, rec, new);
#else
msg_info (
"ignoring ip6 spf command as IPv6 is not supported: %s",
begin);
new = NULL;
res = TRUE;
begin += sizeof (SPF_IP6) - 1;
#endif
}
else {
msg_info ("<%s>: spf error for domain %s: bad spf command %s",
res = parse_spf_ip6 (rec, addr);
}
else {
msg_info ("<%s>: spf error for domain %s: bad spf command %s",
task->message_id, rec->sender_domain, begin);
}
break;
case 'm':
/* mx */
if (g_ascii_strncasecmp (begin, SPF_MX, sizeof (SPF_MX) - 1) == 0) {
NEW_ADDR (new);
begin += sizeof (SPF_MX) - 1;
res = parse_spf_mx (task, begin, rec, new);
}
else {
msg_info ("<%s>: spf error for domain %s: bad spf command %s",
}
break;
case 'm':
/* mx */
if (g_ascii_strncasecmp (begin, SPF_MX, sizeof (SPF_MX) - 1) == 0) {
res = parse_spf_mx (rec, addr);
}
else {
msg_info ("<%s>: spf error for domain %s: bad spf command %s",
task->message_id, rec->sender_domain, begin);
}
break;
case 'p':
/* ptr */
if (g_ascii_strncasecmp (begin, SPF_PTR,
}
break;
case 'p':
/* ptr */
if (g_ascii_strncasecmp (begin, SPF_PTR,
sizeof (SPF_PTR) - 1) == 0) {
NEW_ADDR (new);
begin += sizeof (SPF_PTR) - 1;
res = parse_spf_ptr (task, begin, rec, new);
}
else {
msg_info ("<%s>: spf error for domain %s: bad spf command %s",
res = parse_spf_ptr (rec, addr);
}
else {
msg_info ("<%s>: spf error for domain %s: bad spf command %s",
task->message_id, rec->sender_domain, begin);
}
break;
case 'e':
/* exp or exists */
if (g_ascii_strncasecmp (begin, SPF_EXP,
}
break;
case 'e':
/* exp or exists */
if (g_ascii_strncasecmp (begin, SPF_EXP,
sizeof (SPF_EXP) - 1) == 0) {
begin += sizeof (SPF_EXP) - 1;
res = parse_spf_exp (task, begin, rec, NULL);
}
else if (g_ascii_strncasecmp (begin, SPF_EXISTS,
res = parse_spf_exp (rec, addr);
}
else if (g_ascii_strncasecmp (begin, SPF_EXISTS,
sizeof (SPF_EXISTS) - 1) == 0) {
NEW_ADDR (new);
begin += sizeof (SPF_EXISTS) - 1;
res = parse_spf_exists (task, begin, rec, new);
}
else {
msg_info ("<%s>: spf error for domain %s: bad spf command %s",
res = parse_spf_exists (rec, addr);
}
else {
msg_info ("<%s>: spf error for domain %s: bad spf command %s",
task->message_id, rec->sender_domain, begin);
}
break;
case 'r':
/* redirect */
if (g_ascii_strncasecmp (begin, SPF_REDIRECT,
}
break;
case 'r':
/* redirect */
if (g_ascii_strncasecmp (begin, SPF_REDIRECT,
sizeof (SPF_REDIRECT) - 1) == 0) {
begin += sizeof (SPF_REDIRECT) - 1;
res = parse_spf_redirect (task, begin, rec, NULL);
}
else {
msg_info ("<%s>: spf error for domain %s: bad spf command %s",
task->message_id, rec->sender_domain, begin);
}
break;
case 'v':
if (g_ascii_strncasecmp (begin, "v=spf",
sizeof ("v=spf") - 1) == 0) {
/* Skip this element till the end of record */
while (*begin && !g_ascii_isspace (*begin)) {
begin++;
}
}
break;
default:
res = parse_spf_redirect (rec, addr);
}
else {
msg_info ("<%s>: spf error for domain %s: bad spf command %s",
task->message_id, rec->sender_domain, begin);
break;
task->message_id, rec->sender_domain, begin);
}
if (res) {
if (new != NULL) {
rec->addrs = g_list_prepend (rec->addrs, new);
break;
case 'v':
if (g_ascii_strncasecmp (begin, "v=spf",
sizeof ("v=spf") - 1) == 0) {
/* Skip this element till the end of record */
while (*begin && !g_ascii_isspace (*begin)) {
begin++;
}
rec->elt_num++;
}
break;
default:
msg_info ("<%s>: spf error for domain %s: bad spf command %s",
task->message_id, rec->sender_domain, begin);
break;
}

if (res) {
addr->flags |= RSPAMD_SPF_FLAG_VALID;
}

return res;
}
#undef NEW_ADDR

static void
parse_spf_scopes (struct spf_record *rec, gchar **begin)

Loading…
Cancel
Save