#include "message.h"
#include "filter.h"
-#define SPF_VER_STR "v=spf1"
+#define SPF_VER1_STR "v=spf1"
+#define SPF_VER2_STR "spf2."
+#define SPF_SCOPE_PRA "pra"
+#define SPF_SCOPE_MFROM "mfrom"
#define SPF_ALL "all"
#define SPF_A "a"
#define SPF_IP4 "ip4"
struct spf_record *rec;
struct spf_addr *addr;
spf_action_t cur_action;
+ gboolean in_include;
};
#define CHECK_REC(rec) \
if (type == DNS_TXT) {
if (addresses != NULL) {
begin = *(char **)addresses;
- if (cb->rec->addrs) {
+
+ if (!cb->in_include && cb->rec->addrs) {
g_list_free (cb->rec->addrs);
cb->rec->addrs = NULL;
}
if (elt->prev == NULL && elt->next == NULL) {
g_list_free1 (elt);
}
-
else {
if (elt->prev) {
else {
/* Elt is the first element, so we need to shift temporary list */
tmp = elt->next;
+ tmp->prev = NULL;
}
if (elt->next) {
elt->next->prev = last;
- last->next = elt->next;
+ if (last != NULL) {
+ last->next = elt->next;
+ }
+ }
+
+ if (cb->rec->addrs != NULL) {
+ cb->rec->addrs->prev = elt->prev;
}
-
- cb->rec->addrs->prev = elt->prev;
cb->rec->addrs = tmp;
g_list_free1 (elt);
cb->rec = rec;
cb->addr = addr;
cb->cur_action = SPF_RESOLVE_A;
+ cb->in_include = rec->in_include;
if (evdns_resolve_ipv4 (host, DNS_QUERY_NO_SEARCH, spf_record_dns_callback, (void *)cb) == 0) {
task->save.saved++;
cb->rec = rec;
cb->addr = addr;
cb->cur_action = SPF_RESOLVE_MX;
+ cb->in_include = rec->in_include;
if (evdns_resolve_mx (host, DNS_QUERY_NO_SEARCH, spf_record_dns_callback, (void *)cb) == 0) {
task->save.saved++;
cb->rec = rec;
cb->addr = addr;
cb->cur_action = SPF_RESOLVE_INCLUDE;
+ cb->in_include = rec->in_include;
domain = memory_pool_strdup (task->task_pool, begin);
if (evdns_resolve_txt (domain, DNS_QUERY_NO_SEARCH, spf_record_dns_callback, (void *)cb) == 0) {
cb = memory_pool_alloc (task->task_pool, sizeof (struct spf_dns_cb));
cb->rec = rec;
cb->addr = addr;
- cb->cur_action = SPF_RESOLVE_INCLUDE;
+ cb->cur_action = SPF_RESOLVE_REDIRECT;
+ cb->in_include = rec->in_include;
domain = memory_pool_strdup (task->task_pool, begin);
if (evdns_resolve_txt (domain, DNS_QUERY_NO_SEARCH, spf_record_dns_callback, (void *)cb) == 0) {
cb->rec = rec;
cb->addr = addr;
cb->cur_action = SPF_RESOLVE_EXISTS;
+ cb->in_include = rec->in_include;
host = memory_pool_strdup (task->task_pool, begin);
if (evdns_resolve_ipv4 (host, DNS_QUERY_NO_SEARCH, spf_record_dns_callback, (void *)cb) == 0) {
if (rec->cur_elt == NULL) {
return FALSE;
}
+ else if (*rec->cur_elt == '\0') {
+ /* Silently skip empty elements */
+ rec->elt_num ++;
+ return TRUE;
+ }
else {
begin = expand_spf_macro (task, rec, rec->cur_elt);
if (*begin == '?' || *begin == '+' || *begin == '-' || *begin == '~') {
}
#undef NEW_ADDR
+static void
+parse_spf_scopes (struct spf_record *rec, char **begin)
+{
+ for (;;) {
+ if (g_ascii_strncasecmp (*begin, SPF_SCOPE_PRA, sizeof (SPF_SCOPE_PRA) - 1) == 0) {
+ *begin += sizeof (SPF_SCOPE_PRA) - 1;
+ /* XXX: Implement actual PRA check */
+ /* extract_pra_info (rec); */
+ continue;
+ }
+ else if (g_ascii_strncasecmp (*begin, SPF_SCOPE_MFROM, sizeof (SPF_SCOPE_MFROM) - 1) == 0) {
+ /* mfrom is standart spf1 check */
+ *begin += sizeof (SPF_SCOPE_MFROM) - 1;
+ continue;
+ }
+ else if (**begin != ',') {
+ break;
+ }
+ (*begin) ++;
+ }
+}
+
static void
start_spf_parse (struct spf_record *rec, char *begin)
{
- if (strncmp (begin, SPF_VER_STR, sizeof (SPF_VER_STR) - 1) == 0) {
- begin += sizeof (SPF_VER_STR) - 1;
+ /* Skip spaces */
+ while (g_ascii_isspace (*begin)) {
+ begin ++;
+ }
+
+ if (g_ascii_strncasecmp (begin, SPF_VER1_STR, sizeof (SPF_VER1_STR) - 1) == 0) {
+ begin += sizeof (SPF_VER1_STR) - 1;
+ while (g_ascii_isspace (*begin) && *begin) {
+ begin ++;
+ }
+ rec->elts = g_strsplit_set (begin, " ", 0);
+ rec->elt_num = 0;
+ if (rec->elts) {
+ memory_pool_add_destructor (rec->task->task_pool, (pool_destruct_func)g_strfreev, rec->elts);
+ rec->cur_elt = rec->elts[0];
+ while (parse_spf_record (rec->task, rec));
+ if (rec->addrs) {
+ rec->addrs = g_list_reverse (rec->addrs);
+ }
+ }
+ }
+ else if (g_ascii_strncasecmp (begin, SPF_VER2_STR, sizeof (SPF_VER2_STR) - 1) == 0) {
+ /* Skip one number of record, so no we are here spf2.0/ */
+ begin += sizeof (SPF_VER2_STR);
+ if (*begin != '/') {
+ msg_info ("sender id string has not valid skope");
+ }
+ else {
+ begin ++;
+ parse_spf_scopes (rec, &begin);
+ }
+ /* Now common spf record */
while (g_ascii_isspace (*begin) && *begin) {
begin ++;
}
- rec->elts = g_strsplit (begin, " ", 0);
+ rec->elts = g_strsplit_set (begin, " ", 0);
rec->elt_num = 0;
if (rec->elts) {
memory_pool_add_destructor (rec->task->task_pool, (pool_destruct_func)g_strfreev, rec->elts);
}
}
else {
- msg_info ("bad spf record version: %*s", sizeof (SPF_VER_STR) - 1, begin);
+ msg_info ("bad spf record version: %*s", sizeof (SPF_VER1_STR) - 1, begin);
}
}