summaryrefslogtreecommitdiffstats
path: root/src/libserver/spf.c
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2015-03-18 16:43:46 +0000
committerVsevolod Stakhov <vsevolod@highsecure.ru>2015-03-18 16:43:46 +0000
commited1d6587a088d4a64c4ca47604da5b79280ef85a (patch)
tree3d0f524f18ced74d2f7c9f64a2f26a8a94585343 /src/libserver/spf.c
parentcd603ad1e87f01b8872b5b44b48ce3de51da9120 (diff)
downloadrspamd-ed1d6587a088d4a64c4ca47604da5b79280ef85a.tar.gz
rspamd-ed1d6587a088d4a64c4ca47604da5b79280ef85a.zip
Add records flattening logic.
Diffstat (limited to 'src/libserver/spf.c')
-rw-r--r--src/libserver/spf.c112
1 files changed, 95 insertions, 17 deletions
diff --git a/src/libserver/spf.c b/src/libserver/spf.c
index 163ebf5c2..69693db6f 100644
--- a/src/libserver/spf.c
+++ b/src/libserver/spf.c
@@ -101,7 +101,7 @@ struct spf_dns_cb {
gboolean in_include;
};
-#define CHECK_REC(rec) \
+#define CHECK_REC(rec) \
do { \
if ((rec)->nested > SPF_MAX_NESTING || \
(rec)->dns_requests > SPF_MAX_DNS_REQUESTS) { \
@@ -113,8 +113,7 @@ struct spf_dns_cb {
} while (0) \
static gboolean parse_spf_record (struct spf_record *rec, const gchar *elt);
-static gboolean start_spf_parse (struct spf_record *rec, gchar *begin,
- guint ttl);
+static gboolean start_spf_parse (struct spf_record *rec, gchar *begin);
/* Determine spf mech */
static spf_mech_t
@@ -327,6 +326,97 @@ parse_spf_ipmask (const gchar *begin,
}
+static void
+rspamd_flatten_record_dtor (struct spf_resolved *r)
+{
+ struct spf_addr *addr;
+ guint i;
+
+ for (i = 0; i < r->elts; i ++) {
+ addr = &g_array_index (r->elts, struct spf_addr, i);
+ g_free (addr->spf_string);
+ }
+
+ g_array_free (r->elts, TRUE);
+ g_slice_free1 (sizeof (*r), r);
+}
+
+static void
+rspamd_spf_process_reference (struct spf_resolved *target,
+ struct spf_addr *addr, struct spf_record *rec, gboolean top)
+{
+ struct spf_resolved_element *elt;
+ struct spf_addr *cur, taddr;
+ guint i;
+
+ if (addr) {
+ g_assert (addr->m.idx < rec->resolved->len);
+
+ elt = &g_array_index (rec->resolved, struct spf_resolved_element,
+ addr->m.idx);
+ }
+ else {
+ elt = &g_array_index (rec->resolved, struct spf_resolved_element, 0);
+ }
+
+ while (elt->redirected) {
+ cur = g_ptr_array_index (elt->elts, 0);
+ g_assert (cur->flags & RSPAMD_SPF_FLAG_REFRENCE);
+ g_assert (cur->m.idx < rec->resolved->len);
+ elt = &g_array_index (rec->resolved, struct spf_resolved_element,
+ cur->m.idx);
+ }
+
+ for (i = 0; i < elt->elts->len; i ++) {
+ cur = g_ptr_array_index (elt->elts, i);
+
+ if (!(cur->flags & RSPAMD_SPF_FLAG_PARSED)) {
+ /* Ignore unparsed addrs */
+ continue;
+ }
+ else if (cur->flags & RSPAMD_SPF_FLAG_REFRENCE) {
+ /* Process reference */
+ rspamd_spf_process_reference (target, cur, rec, FALSE);
+ }
+ else {
+ if ((cur->flags & RSPAMD_SPF_FLAG_ANY) && !top) {
+ /* Ignore wide policies in includes */
+ continue;
+ }
+
+ memcpy (&taddr, cur, sizeof (taddr));
+ /* Steal element */
+ cur->spf_string = NULL;
+ g_array_append_val (target->elts, taddr);
+ }
+ }
+}
+
+/*
+ * Parse record and flatten it to a simple structure
+ */
+static struct spf_resolved *
+rspamd_spf_record_flatten (struct spf_record *rec)
+{
+ struct spf_resolved *res;
+
+ struct spf_resolved_element *top;
+ guint i;
+
+ g_assert (rec != NULL);
+
+ res = g_slice_alloc (sizeof (*res));
+ res->elts = g_array_sized_new (FALSE, FALSE, sizeof (struct spf_addr),
+ rec->resolved->len);
+ REF_INIT_RETAIN (res, rspamd_flatten_record_dtor);
+
+ top = &g_array_index (rec->resolved, struct spf_resolved_element, 0);
+
+ rspamd_spf_process_reference (res->elts, NULL, rec, TRUE);
+
+ return res;
+}
+
static gboolean
spf_check_ptr_host (struct spf_dns_cb *cb, const char *name)
{
@@ -549,13 +639,11 @@ spf_record_dns_callback (struct rdns_reply *reply, gpointer arg)
spf_record_addr_set (addr, FALSE);
}
break;
-#ifdef HAVE_INET_PTON
case SPF_RESOLVE_AAA:
if (rdns_request_has_type (reply->request, RDNS_REQUEST_AAAA)) {
spf_record_addr_set (addr, FALSE);
}
break;
-#endif
case SPF_RESOLVE_PTR:
spf_record_addr_set (addr, FALSE);
break;
@@ -858,7 +946,6 @@ parse_spf_ip4 (struct spf_record *rec, struct spf_addr *addr)
return parse_spf_ipmask (addr->spf_string, addr, rec);
}
-#ifdef HAVE_INET_PTON
static gboolean
parse_spf_ip6 (struct spf_record *rec, struct spf_addr *addr)
{
@@ -867,7 +954,7 @@ parse_spf_ip6 (struct spf_record *rec, struct spf_addr *addr)
CHECK_REC (rec);
return parse_spf_ipmask (addr->spf_string, addr, rec);
}
-#endif
+
static gboolean
parse_spf_include (struct spf_record *rec, struct spf_addr *addr)
@@ -1052,9 +1139,7 @@ expand_spf_macro (struct spf_record *rec,
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;
@@ -1109,11 +1194,7 @@ expand_spf_macro (struct spf_record *rec,
/* Read macro name */
switch (g_ascii_tolower (*p)) {
case 'i':
-#ifdef HAVE_INET_PTON
len += INET6_ADDRSTRLEN - 1;
-#else
- len += INET_ADDRSTRLEN - 1;
-#endif
break;
case 's':
len += strlen (rec->sender);
@@ -1526,6 +1607,7 @@ start_spf_parse (struct spf_record *rec, gchar *begin)
g_strfreev (elts);
}
+
return TRUE;
}
@@ -1619,7 +1701,3 @@ resolve_spf (struct rspamd_task *task, spf_cb_t callback)
return TRUE;
}
}
-
-/*
- * vi:ts=4
- */