aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--config.h.in2
-rw-r--r--src/dns.c50
-rw-r--r--src/dns.h8
-rw-r--r--src/logger.h7
-rw-r--r--src/lua/lua_task.c23
-rw-r--r--src/main.h11
-rw-r--r--src/plugins/fuzzy_check.c11
-rw-r--r--src/plugins/spf.c72
-rw-r--r--src/protocol.c17
-rw-r--r--src/spf.c229
-rw-r--r--src/spf.h12
-rw-r--r--src/symbols_cache.c15
-rw-r--r--src/view.c19
-rw-r--r--src/worker.c1
15 files changed, 432 insertions, 46 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 565cabe04..fc15f86c8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -745,6 +745,7 @@ CHECK_FUNCTION_EXISTS(tanhl HAVE_TANHL)
CHECK_FUNCTION_EXISTS(sendfile HAVE_SENDFILE)
CHECK_FUNCTION_EXISTS(mkstemp HAVE_MKSTEMP)
CHECK_FUNCTION_EXISTS(setitimer HAVE_SETITIMER)
+CHECK_FUNCTION_EXISTS(inet_pton HAVE_INET_PTON)
CHECK_FUNCTION_EXISTS(clock_gettime HAVE_CLOCK_GETTIME)
#
diff --git a/config.h.in b/config.h.in
index 8ad00557d..186021446 100644
--- a/config.h.in
+++ b/config.h.in
@@ -153,6 +153,8 @@
#cmakedefine HAVE_SETITIMER 1
+#cmakedefine HAVE_INET_PTON 1
+
#define WITHOUT_PERL 1
#cmakedefine WITH_LUA 1
diff --git a/src/dns.c b/src/dns.c
index fe087da08..f39d47843 100644
--- a/src/dns.c
+++ b/src/dns.c
@@ -663,6 +663,24 @@ make_a_req (struct rspamd_dns_request *req, const gchar *name)
req->requested_name = name;
}
+#ifdef HAVE_INET_PTON
+static void
+make_aaa_req (struct rspamd_dns_request *req, const gchar *name)
+{
+ guint16 *p;
+
+ allocate_packet (req, strlen (name));
+ make_dns_header (req);
+ format_dns_name (req, name, 0);
+ p = (guint16 *)(req->packet + req->pos);
+ *p++ = htons (DNS_T_AAAA);
+ *p = htons (DNS_C_IN);
+ req->pos += sizeof (guint16) * 2;
+ req->type = DNS_REQUEST_AAA;
+ req->requested_name = name;
+}
+#endif
+
static void
make_txt_req (struct rspamd_dns_request *req, const gchar *name)
{
@@ -1001,6 +1019,24 @@ dns_parse_rr (guint8 *in, union rspamd_reply_element *elt, guint8 **pos, struct
}
}
break;
+#ifdef HAVE_INET_PTON
+ case DNS_T_AAAA:
+ if (rep->request->type != DNS_REQUEST_AAA) {
+ p += datalen;
+ }
+ else {
+ if (datalen == sizeof (struct in6_addr) && datalen <= *remain) {
+ memcpy (&elt->aaa.addr, p, sizeof (struct in6_addr));
+ p += datalen;
+ parsed = TRUE;
+ }
+ else {
+ msg_info ("corrupted AAAA record");
+ return -1;
+ }
+ }
+ break;
+#endif
case DNS_T_PTR:
if (rep->request->type != DNS_REQUEST_PTR) {
p += datalen;
@@ -1387,6 +1423,15 @@ make_dns_request (struct rspamd_dns_resolver *resolver,
name = va_arg (args, const gchar *);
make_a_req (req, name);
break;
+ case DNS_REQUEST_AAA:
+#ifdef HAVE_INET_PTON
+ name = va_arg (args, const gchar *);
+ make_aaa_req (req, name);
+ break;
+#else
+ msg_err ("your system has no ipv6 support, cannot make aaa request");
+ break;
+#endif
case DNS_REQUEST_TXT:
name = va_arg (args, const gchar *);
make_txt_req (req, name);
@@ -1649,13 +1694,14 @@ dns_strerror (enum dns_rcode rcode)
return dns_rcodes[rcode];
}
-static gchar dns_types[6][16] = {
+static gchar dns_types[7][16] = {
[DNS_REQUEST_A] = "A request",
[DNS_REQUEST_PTR] = "PTR request",
[DNS_REQUEST_MX] = "MX request",
[DNS_REQUEST_TXT] = "TXT request",
[DNS_REQUEST_SRV] = "SRV request",
- [DNS_REQUEST_SPF] = "SPF request"
+ [DNS_REQUEST_SPF] = "SPF request",
+ [DNS_REQUEST_AAA] = "AAA request"
};
const gchar *
diff --git a/src/dns.h b/src/dns.h
index f174f5026..8914ae5b1 100644
--- a/src/dns.h
+++ b/src/dns.h
@@ -68,7 +68,8 @@ enum rspamd_request_type {
DNS_REQUEST_MX,
DNS_REQUEST_TXT,
DNS_REQUEST_SRV,
- DNS_REQUEST_SPF
+ DNS_REQUEST_SPF,
+ DNS_REQUEST_AAA
};
struct rspamd_dns_request {
@@ -100,6 +101,11 @@ union rspamd_reply_element {
struct in_addr addr[MAX_ADDRS];
guint16 addrcount;
} a;
+#ifdef HAVE_INET_PTON
+ struct {
+ struct in6_addr addr;
+ } aaa;
+#endif
struct {
gchar *name;
} ptr;
diff --git a/src/logger.h b/src/logger.h
index 6d0cac4b8..ec7a23af5 100644
--- a/src/logger.h
+++ b/src/logger.h
@@ -84,8 +84,11 @@ void rspamd_log_nodebug (rspamd_logger_t *logger);
#define msg_warn(...) rspamd_common_log_function(rspamd_main->logger, G_LOG_LEVEL_WARNING, __FUNCTION__, __VA_ARGS__)
#define msg_info(...) rspamd_common_log_function(rspamd_main->logger, G_LOG_LEVEL_INFO, __FUNCTION__, __VA_ARGS__)
#define msg_debug(...) rspamd_conditional_debug(rspamd_main->logger, -1, __FUNCTION__, __VA_ARGS__)
-#define debug_task(...) rspamd_conditional_debug(rspamd_main->logger, task->from_addr.s_addr, __FUNCTION__, __VA_ARGS__)
-
+#ifdef HAVE_INET_PTON
+# define debug_task(...) rspamd_conditional_debug(rspamd_main->logger, task->from_addr.d.in4.s_addr, __FUNCTION__, __VA_ARGS__)
+#else
+# define debug_task(...) rspamd_conditional_debug(rspamd_main->logger, task->from_addr.s_addr, __FUNCTION__, __VA_ARGS__)
+#endif
#else
#define msg_err(...) rspamd_fprintf(stderr, __VA_ARGS__)
#define msg_warn(...) rspamd_fprintf(stderr, __VA_ARGS__)
diff --git a/src/lua/lua_task.c b/src/lua/lua_task.c
index 7ca1c58df..5695b6f42 100644
--- a/src/lua/lua_task.c
+++ b/src/lua/lua_task.c
@@ -981,12 +981,26 @@ static gint
lua_task_get_from_ip (lua_State *L)
{
struct worker_task *task = lua_check_task (L);
+#ifdef HAVE_INET_PTON
+ gchar ipbuf[INET6_ADDRSTRLEN];
+#endif
if (task) {
+#ifdef HAVE_INET_PTON
+ if (task->from_addr.ipv6) {
+ inet_ntop (AF_INET6, &task->from_addr.d.in6, ipbuf, sizeof (ipbuf));
+ }
+ else {
+ inet_ntop (AF_INET, &task->from_addr.d.in4, ipbuf, sizeof (ipbuf));
+ }
+ lua_pushstring (L, ipbuf);
+ return 1;
+#else
if (task->from_addr.s_addr != INADDR_NONE && task->from_addr.s_addr != INADDR_ANY) {
lua_pushstring (L, inet_ntoa (task->from_addr));
return 1;
}
+#endif
}
lua_pushnil (L);
@@ -999,10 +1013,19 @@ lua_task_get_from_ip_num (lua_State *L)
struct worker_task *task = lua_check_task (L);
if (task) {
+#ifdef HAVE_INET_PTON
+ if (!task->from_addr.ipv6 && task->from_addr.d.in4.s_addr != INADDR_NONE) {
+ lua_pushinteger (L, ntohl (task->from_addr.d.in4.s_addr));
+ return 1;
+ }
+ /* TODO: do something with ipv6 numeric representation */
+#else
if (task->from_addr.s_addr != INADDR_NONE && task->from_addr.s_addr != INADDR_ANY) {
lua_pushinteger (L, ntohl (task->from_addr.s_addr));
return 1;
}
+
+#endif
}
lua_pushnil (L);
diff --git a/src/main.h b/src/main.h
index 22b2f7584..1d8fab134 100644
--- a/src/main.h
+++ b/src/main.h
@@ -203,7 +203,18 @@ struct worker_task {
const gchar *message_id; /**< message id */
GList *rcpt; /**< recipients list */
guint nrcpt; /**< number of recipients */
+#ifdef HAVE_INET_PTON
+ struct {
+ union {
+ struct in_addr in4;
+ struct in6_addr in6;
+ } d;
+ gboolean ipv6;
+ gboolean has_addr;
+ } from_addr;
+#else
struct in_addr from_addr; /**< client addr in numeric form */
+#endif
struct in_addr client_addr; /**< client addr in numeric form */
gchar *deliver_to; /**< address to deliver */
gchar *user; /**< user to deliver */
diff --git a/src/plugins/fuzzy_check.c b/src/plugins/fuzzy_check.c
index 4f66a5731..7d400a0c4 100644
--- a/src/plugins/fuzzy_check.c
+++ b/src/plugins/fuzzy_check.c
@@ -658,6 +658,15 @@ fuzzy_symbol_callback (struct worker_task *task, void *unused)
/* Check whitelist */
+#ifdef HAVE_INET_PTON
+ if (fuzzy_module_ctx->whitelist && !task->from_addr.ipv6 && task->from_addr.d.in4.s_addr != INADDR_NONE) {
+ if (radix32tree_find (fuzzy_module_ctx->whitelist, ntohl ((guint32) task->from_addr.d.in4.s_addr)) != RADIX_NO_VALUE) {
+ msg_info ("<%s>, address %s is whitelisted, skip fuzzy check",
+ task->message_id, inet_ntoa (task->from_addr.d.in4));
+ return;
+ }
+ }
+#else
if (fuzzy_module_ctx->whitelist && task->from_addr.s_addr != 0) {
if (radix32tree_find (fuzzy_module_ctx->whitelist, ntohl ((guint32) task->from_addr.s_addr)) != RADIX_NO_VALUE) {
msg_info ("<%s>, address %s is whitelisted, skip fuzzy check",
@@ -665,7 +674,7 @@ fuzzy_symbol_callback (struct worker_task *task, void *unused)
return;
}
}
-
+#endif
cur = task->text_parts;
while (cur) {
diff --git a/src/plugins/spf.c b/src/plugins/spf.c
index 093c57703..26b3c1903 100644
--- a/src/plugins/spf.c
+++ b/src/plugins/spf.c
@@ -166,17 +166,75 @@ spf_module_reconfig (struct config_file *cfg)
static gboolean
spf_check_element (struct spf_addr *addr, struct worker_task *task)
{
+ gboolean res = FALSE;
+#ifdef HAVE_INET_PTON
+ guint8 *s, *d, t;
+ guint nbits, addrlen;
+ struct in_addr in4s, in4d;
+ struct in6_addr in6s, in6d;
+
+ /* Basic comparing algorithm */
+ if (addr->data.normal.ipv6 == task->from_addr.ipv6) {
+ if (addr->data.normal.ipv6) {
+ addrlen = sizeof (struct in6_addr);
+ memcpy (&in6s, &addr->data.normal.d.in6, sizeof (struct in6_addr));
+ memcpy (&in6d, &task->from_addr.d.in6, sizeof (struct in6_addr));
+ s = (guint8 *)&in6s;
+ d = (guint8 *)&in6d;
+ }
+ else {
+ addrlen = sizeof (struct in_addr);
+ memcpy (&in4s, &addr->data.normal.d.in4, sizeof (struct in_addr));
+ memcpy (&in4d, &task->from_addr.d.in4, sizeof (struct in_addr));
+ s = (guint8 *)&in4s;
+ d = (guint8 *)&in4d;
+ }
+ /* Move pointers to the less significant byte */
+ t = 0x1;
+ s += addrlen - 1;
+ d += addrlen - 1;
+ /* TODO: improve this cycle by masking by words */
+ for (nbits = 0; nbits < addrlen * CHAR_BIT - addr->data.normal.mask; nbits ++) {
+ /* Skip bits from the beginning as we know that data is in network byte order */
+ if (nbits != 0 && nbits % 8 == 0) {
+ /* Move pointer to the next byte */
+ s --;
+ d --;
+ t = 0x1;
+ }
+ *s |= t;
+ *d |= t;
+ t <<= 1;
+ }
+ if (addr->data.normal.ipv6) {
+ res = memcmp (&in6d, &in6s, sizeof (struct in6_addr)) == 0;
+ }
+ else {
+ res = memcmp (&in4d, &in4s, sizeof (struct in_addr)) == 0;
+ }
+ }
+ else {
+ if (addr->data.normal.addr_any) {
+ res = TRUE;
+ }
+ else {
+ res = FALSE;
+ }
+ }
+#else
guint32 s, m;
if (addr->data.normal.mask == 0) {
m = 0;
}
else {
- m = G_MAXUINT32 << (32 - addr->data.normal.mask);
+ m = htonl (G_MAXUINT32 << (32 - addr->data.normal.mask));
}
- s = ntohl (task->from_addr.s_addr);
+ s = task->from_addr.s_addr;
+ res = (s & m) == (addr->data.normal.d.in4.s_addr & m);
+#endif
- if ((s & m) == (addr->data.normal.addr & m)) {
+ if (res) {
switch (addr->mech) {
case SPF_FAIL:
insert_result (task, spf_module_ctx->symbol_fail, 1, g_list_prepend (NULL, addr->spf_string));
@@ -248,9 +306,13 @@ spf_symbol_callback (struct worker_task *task, void *unused)
gchar *domain;
GList *l;
+#ifdef HAVE_INET_PTON
+ if (task->from_addr.has_addr) {
+ if (TRUE) {
+#else
if (task->from_addr.s_addr != INADDR_NONE && task->from_addr.s_addr != INADDR_ANY) {
if (radix32tree_find (spf_module_ctx->whitelist_ip, ntohl (task->from_addr.s_addr)) == RADIX_NO_VALUE) {
-
+#endif
domain = get_spf_domain (task);
if (domain) {
if ((l = rspamd_lru_hash_lookup (spf_module_ctx->spf_hash, domain, task->tv.tv_sec)) != NULL) {
@@ -261,9 +323,11 @@ spf_symbol_callback (struct worker_task *task, void *unused)
}
}
}
+#ifndef HAVE_INET_PTON
else {
msg_info ("ip %s is whitelisted for spf checks", inet_ntoa (task->from_addr));
}
+#endif
}
}
diff --git a/src/protocol.c b/src/protocol.c
index 40bd01e0c..fc03acacb 100644
--- a/src/protocol.c
+++ b/src/protocol.c
@@ -537,10 +537,27 @@ parse_header (struct worker_task *task, f_str_t * line)
/* ip_addr */
if (g_ascii_strncasecmp (headern, IP_ADDR_HEADER, sizeof (IP_ADDR_HEADER) - 1) == 0) {
tmp = memory_pool_fstrdup (task->task_pool, line);
+#ifdef HAVE_INET_PTON
+ if (inet_pton (AF_INET, tmp, &task->from_addr.d.in4) != 1) {
+ /* Try ipv6 */
+ if (inet_pton (AF_INET6, tmp, &task->from_addr.d.in6) == 1) {
+ task->from_addr.ipv6 = TRUE;
+ }
+ else {
+ msg_info ("bad ip header: '%s'", tmp);
+ return FALSE;
+ }
+ }
+ else {
+ task->from_addr.ipv6 = FALSE;
+ }
+ task->from_addr.has_addr = TRUE;
+#else
if (!inet_aton (tmp, &task->from_addr)) {
msg_info ("bad ip header: '%s'", tmp);
return FALSE;
}
+#endif
debug_task ("read IP header, value: %s", tmp);
}
else {
diff --git a/src/spf.c b/src/spf.c
index 137ca0f5e..738b56ee8 100644
--- a/src/spf.c
+++ b/src/spf.c
@@ -120,7 +120,11 @@ dump_spf_record (GList *addrs)
GList *cur;
gint r = 0;
gchar logbuf[BUFSIZ], c;
+#ifdef HAVE_INET_PTON
+ gchar ipbuf[INET6_ADDRSTRLEN];
+#else
struct in_addr ina;
+#endif
cur = addrs;
@@ -139,8 +143,19 @@ dump_spf_record (GList *addrs)
c = '+';
break;
}
- ina.s_addr = htonl (addr->data.normal.addr);
+#ifdef HAVE_INET_PTON
+ if (addr->data.normal.ipv6) {
+ inet_ntop (AF_INET6, &addr->data.normal.d.in6, ipbuf, sizeof (ipbuf));
+
+ }
+ else {
+ inet_ntop (AF_INET, &addr->data.normal.d.in4, ipbuf, sizeof (ipbuf));
+ }
+ r += snprintf (logbuf + r, sizeof (logbuf) - r, "%c%s/%d; ", c, ipbuf, addr->data.normal.mask);
+#else
+ ina.s_addr = addr->data.normal.d.in4.s_addr;
r += snprintf (logbuf + r, sizeof (logbuf) - r, "%c%s/%d; ", c, inet_ntoa (ina), addr->data.normal.mask);
+#endif
}
else {
r += snprintf (logbuf + r, sizeof (logbuf) - r, "%s; ", addr->spf_string);
@@ -204,9 +219,13 @@ static gboolean
parse_spf_ipmask (const gchar *begin, struct spf_addr *addr)
{
const gchar *pos;
- gchar ip_buf[sizeof ("255.255.255.255")], mask_buf[3], *p;
+ gchar mask_buf[5] = {'\0'}, *p;
gint state = 0, dots = 0;
- struct in_addr in;
+#ifdef HAVE_INET_PTON
+ gchar ip_buf[INET6_ADDRSTRLEN];
+#else
+ gchar ip_buf[INET_ADDRSTRLEN];
+#endif
bzero (ip_buf, sizeof (ip_buf));
bzero (mask_buf, sizeof (mask_buf));
@@ -226,6 +245,18 @@ parse_spf_ipmask (const gchar *begin, struct spf_addr *addr)
dots = 0;
break;
case 1:
+#ifdef HAVE_INET_PTON
+ if (p - ip_buf >= (gint)sizeof (ip_buf)) {
+ return FALSE;
+ }
+ if (g_ascii_isxdigit (*pos)) {
+ *p ++ = *pos ++;
+ }
+ else if (*pos == '.' || *pos == ':') {
+ *p ++ = *pos ++;
+ dots ++;
+ }
+#else
/* Begin parse ip */
if (p - ip_buf >= (gint)sizeof (ip_buf) || dots > 3) {
return FALSE;
@@ -237,6 +268,7 @@ parse_spf_ipmask (const gchar *begin, struct spf_addr *addr)
*p ++ = *pos ++;
dots ++;
}
+#endif
else if (*pos == '/') {
pos ++;
p = mask_buf;
@@ -249,7 +281,7 @@ parse_spf_ipmask (const gchar *begin, struct spf_addr *addr)
break;
case 2:
/* Parse mask */
- if (p - mask_buf > 2) {
+ if (p - mask_buf >= (gint)sizeof (mask_buf)) {
return FALSE;
}
if (g_ascii_isdigit (*pos)) {
@@ -262,22 +294,44 @@ parse_spf_ipmask (const gchar *begin, struct spf_addr *addr)
}
}
- if (!inet_aton (ip_buf, &in)) {
+#ifdef HAVE_INET_PTON
+ if (inet_pton (AF_INET, ip_buf, &addr->data.normal.d.in4) != 1) {
+ if (inet_pton (AF_INET6, ip_buf, &addr->data.normal.d.in6) == 1) {
+ addr->data.normal.ipv6 = TRUE;
+ }
+ else {
+ return FALSE;
+ }
+ }
+ else {
+ addr->data.normal.ipv6 = FALSE;
+ }
+#else
+ if (!inet_aton (ip_buf, &addr->data.normal.d.in4)) {
return FALSE;
}
- addr->data.normal.addr = ntohl (in.s_addr);
+#endif
if (state == 2) {
/* Also parse mask */
- addr->data.normal.mask = (mask_buf[0] - '0') * 10 + mask_buf[1] - '0';
- if (addr->data.normal.mask > 32) {
- msg_info ("bad ipmask value: '%s'", begin);
- return FALSE;
+ if (!addr->data.normal.ipv6) {
+ addr->data.normal.mask = (mask_buf[0] - '0') * 10 + mask_buf[1] - '0';
+ if (addr->data.normal.mask > 32) {
+ msg_info ("bad ipmask value: '%s'", begin);
+ return FALSE;
+ }
+ }
+ else {
+ addr->data.normal.mask = strtoul (mask_buf, NULL, 10);
+ if (addr->data.normal.mask > 128) {
+ msg_info ("bad ipmask value: '%s'", begin);
+ return FALSE;
+ }
}
}
else {
- addr->data.normal.mask = 32;
+ addr->data.normal.mask = addr->data.normal.ipv6 ? 128 : 32;
}
-
+ addr->data.normal.parsed = TRUE;
return TRUE;
}
@@ -329,6 +383,8 @@ spf_record_dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
task = cb->rec->task;
+ cb->rec->requests_inflight --;
+
if (reply->code == DNS_RC_NOERROR) {
if (reply->elements != NULL) {
/* Add all logic for all DNS states here */
@@ -341,12 +397,38 @@ spf_record_dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
/* Now resolve A record for this MX */
if (make_dns_request (task->resolver, task->s, task->task_pool, spf_record_dns_callback, (void *)cb, DNS_REQUEST_A, elt_data->mx.name)) {
task->dns_requests ++;
+ cb->rec->requests_inflight ++;
}
}
else if (reply->type == DNS_REQUEST_A) {
- if (cb->addr->data.normal.addr == 0) {
- cb->addr->data.normal.addr = ntohl (elt_data->a.addr[0].s_addr);
+ if (!cb->addr->data.normal.parsed) {
+ cb->addr->data.normal.d.in4.s_addr = elt_data->a.addr[0].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 = memory_pool_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->a.addr[0].s_addr;
+ new_addr->data.normal.parsed = TRUE;
+ cb->rec->addrs = g_list_insert_before (cb->rec->addrs, tmp, new_addr);
+ }
+ else {
+ msg_info ("wrong address list");
+ }
+ }
+
+ }
+#ifdef HAVE_INET_PTON
+ else if (reply->type == DNS_REQUEST_AAA) {
+ if (!cb->addr->data.normal.parsed) {
+ memcpy (&cb->addr->data.normal.d.in6, &elt_data->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 */
@@ -354,7 +436,9 @@ spf_record_dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
if (tmp) {
new_addr = memory_pool_alloc (task->task_pool, sizeof (struct spf_addr));
memcpy (new_addr, cb->addr, sizeof (struct spf_addr));
- new_addr->data.normal.addr = ntohl (elt_data->a.addr[0].s_addr);
+ memcpy (&new_addr->data.normal.d.in6, &elt_data->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 {
@@ -363,13 +447,39 @@ spf_record_dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
}
}
+#endif
break;
case SPF_RESOLVE_A:
if (reply->type == DNS_REQUEST_A) {
/* XXX: process only one record */
- cb->addr->data.normal.addr = ntohl (elt_data->a.addr[0].s_addr);
+ cb->addr->data.normal.d.in4.s_addr = elt_data->a.addr[0].s_addr;
+ cb->addr->data.normal.mask = 32;
+ cb->addr->data.normal.parsed = TRUE;
+ }
+#ifdef HAVE_INET_PTON
+ else if (reply->type == DNS_REQUEST_AAA) {
+ memcpy (&cb->addr->data.normal.d.in6, &elt_data->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 (reply->type == DNS_REQUEST_A) {
+ /* XXX: process only one record */
+ cb->addr->data.normal.d.in4.s_addr = elt_data->a.addr[0].s_addr;
+ cb->addr->data.normal.mask = 32;
+ cb->addr->data.normal.parsed = TRUE;
+ }
+ else if (reply->type == DNS_REQUEST_AAA) {
+ memcpy (&cb->addr->data.normal.d.in6, &elt_data->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;
case SPF_RESOLVE_PTR:
break;
@@ -413,7 +523,7 @@ spf_record_dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
case SPF_RESOLVE_EXISTS:
if (reply->type == DNS_REQUEST_A) {
/* If specified address resolves, we can accept connection from every IP */
- cb->addr->data.normal.addr = ntohl (INADDR_ANY);
+ cb->addr->data.normal.d.in4.s_addr = INADDR_NONE;
cb->addr->data.normal.mask = 0;
}
break;
@@ -427,22 +537,31 @@ spf_record_dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
case SPF_RESOLVE_MX:
if (reply->type == DNS_REQUEST_MX) {
msg_info ("cannot find MX record for %s", cb->rec->cur_domain);
- cb->addr->data.normal.addr = ntohl (INADDR_NONE);
+ cb->addr->data.normal.d.in4.s_addr = INADDR_NONE;
cb->addr->data.normal.mask = 32;
}
else if (reply->type != DNS_REQUEST_MX) {
msg_info ("cannot resolve MX record for %s", cb->rec->cur_domain);
- cb->addr->data.normal.addr = ntohl (INADDR_NONE);
+ cb->addr->data.normal.d.in4.s_addr = INADDR_NONE;
cb->addr->data.normal.mask = 32;
}
break;
case SPF_RESOLVE_A:
if (reply->type == DNS_REQUEST_A) {
/* XXX: process only one record */
- cb->addr->data.normal.addr = ntohl (INADDR_NONE);
+ cb->addr->data.normal.d.in4.s_addr = INADDR_NONE;
cb->addr->data.normal.mask = 32;
}
break;
+#ifdef HAVE_INET_PTON
+ case SPF_RESOLVE_AAA:
+ if (reply->type == DNS_REQUEST_AAA) {
+ /* XXX: process only one record */
+ memset (&cb->addr->data.normal.d.in6, 0xff, sizeof (struct in6_addr));
+ cb->addr->data.normal.mask = 32;
+ }
+ break;
+#endif
case SPF_RESOLVE_PTR:
break;
case SPF_RESOLVE_REDIRECT:
@@ -454,11 +573,15 @@ spf_record_dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
case SPF_RESOLVE_EXP:
break;
case SPF_RESOLVE_EXISTS:
- cb->addr->data.normal.addr = ntohl (INADDR_NONE);
+ cb->addr->data.normal.d.in4.s_addr = INADDR_NONE;
cb->addr->data.normal.mask = 32;
break;
}
}
+
+ if (cb->rec->requests_inflight == 0) {
+ cb->rec->callback (cb->rec, cb->rec->task);
+ }
}
static gboolean
@@ -479,7 +602,6 @@ parse_spf_a (struct worker_task *task, const gchar *begin, struct spf_record *re
if (!host) {
return FALSE;
}
-
rec->dns_requests ++;
cb = memory_pool_alloc (task->task_pool, sizeof (struct spf_dns_cb));
cb->rec = rec;
@@ -488,7 +610,7 @@ parse_spf_a (struct worker_task *task, const gchar *begin, struct spf_record *re
cb->in_include = rec->in_include;
if (make_dns_request (task->resolver, task->s, task->task_pool, spf_record_dns_callback, (void *)cb, DNS_REQUEST_A, host)) {
task->dns_requests ++;
-
+ rec->requests_inflight ++;
return TRUE;
}
@@ -525,16 +647,16 @@ parse_spf_mx (struct worker_task *task, const gchar *begin, struct spf_record *r
if (!host) {
return FALSE;
}
-
rec->dns_requests ++;
cb = memory_pool_alloc (task->task_pool, sizeof (struct spf_dns_cb));
cb->rec = rec;
cb->addr = addr;
- addr->data.normal.addr = 0;
+ memset (&addr->data.normal, 0, sizeof (addr->data.normal));
cb->cur_action = SPF_RESOLVE_MX;
cb->in_include = rec->in_include;
if (make_dns_request (task->resolver, task->s, task->task_pool, spf_record_dns_callback, (void *)cb, DNS_REQUEST_MX, host)) {
task->dns_requests ++;
+ rec->requests_inflight ++;
return TRUE;
}
@@ -546,14 +668,14 @@ static gboolean
parse_spf_all (struct worker_task *task, const gchar *begin, 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.addr = 0;
addr->data.normal.mask = 32;
}
else {
- addr->data.normal.addr = 0;
addr->data.normal.mask = 0;
+ addr->data.normal.addr_any = TRUE;
}
return TRUE;
@@ -568,6 +690,17 @@ parse_spf_ip4 (struct worker_task *task, const gchar *begin, struct spf_record *
return parse_spf_ipmask (begin, addr);
}
+#ifdef HAVE_INET_PTON
+static gboolean
+parse_spf_ip6 (struct worker_task *task, const gchar *begin, struct spf_record *rec, struct spf_addr *addr)
+{
+ /* ip6:addr[/mask] */
+
+ CHECK_REC (rec);
+ return parse_spf_ipmask (begin, addr);
+}
+#endif
+
static gboolean
parse_spf_include (struct worker_task *task, const gchar *begin, struct spf_record *rec, struct spf_addr *addr)
{
@@ -592,6 +725,7 @@ parse_spf_include (struct worker_task *task, const gchar *begin, struct spf_reco
domain = memory_pool_strdup (task->task_pool, begin);
if (make_dns_request (task->resolver, task->s, task->task_pool, spf_record_dns_callback, (void *)cb, DNS_REQUEST_TXT, domain)) {
task->dns_requests ++;
+ rec->requests_inflight ++;
return TRUE;
}
@@ -631,6 +765,7 @@ parse_spf_redirect (struct worker_task *task, const gchar *begin, struct spf_rec
domain = memory_pool_strdup (task->task_pool, begin);
if (make_dns_request (task->resolver, task->s, task->task_pool, spf_record_dns_callback, (void *)cb, DNS_REQUEST_TXT, domain)) {
task->dns_requests ++;
+ rec->requests_inflight ++;
return TRUE;
}
@@ -662,6 +797,7 @@ parse_spf_exists (struct worker_task *task, const gchar *begin, struct spf_recor
if (make_dns_request (task->resolver, task->s, task->task_pool, spf_record_dns_callback, (void *)cb, DNS_REQUEST_A, host)) {
task->dns_requests ++;
+ rec->requests_inflight ++;
return TRUE;
}
@@ -706,7 +842,10 @@ expand_spf_macro (struct worker_task *task, struct spf_record *rec, gchar *begin
{
gchar *p, *c, *new, *tmp;
gint len = 0, slen = 0, state = 0;
- gboolean need_expand = FALSE;
+#ifdef HAVE_INET_PTON
+ gchar ip_buf[INET6_ADDRSTRLEN];
+#endif
+ gboolean need_expand = FALSE;
p = begin;
/* Calculate length */
@@ -749,7 +888,11 @@ expand_spf_macro (struct worker_task *task, struct spf_record *rec, gchar *begin
/* Read macro name */
switch (g_ascii_tolower (*p)) {
case 'i':
- len += sizeof ("255.255.255.255") - 1;
+#ifdef HAVE_INET_PTON
+ len += sizeof (INET6_ADDRSTRLEN) - 1;
+#else
+ len += sizeof (INET_ADDRSTRLEN) - 1;
+#endif
break;
case 's':
len += strlen (rec->sender);
@@ -850,9 +993,20 @@ expand_spf_macro (struct worker_task *task, struct spf_record *rec, gchar *begin
/* Read macro name */
switch (g_ascii_tolower (*p)) {
case 'i':
+#ifdef HAVE_INET_PTON
+ if (task->from_addr.ipv6) {
+ inet_ntop (AF_INET6, &task->from_addr.d.in6, ip_buf, sizeof (ip_buf));
+ }
+ else {
+ inet_ntop (AF_INET, &task->from_addr.d.in4, ip_buf, sizeof (ip_buf));
+ }
+ len = strlen (ip_buf);
+ memcpy (c, ip_buf, len);
+#else
tmp = inet_ntoa (task->from_addr);
len = strlen (tmp);
memcpy (c, tmp, len);
+#endif
c += len;
break;
case 's':
@@ -928,7 +1082,7 @@ expand_spf_macro (struct worker_task *task, struct spf_record *rec, gchar *begin
(x) = memory_pool_alloc (task->task_pool, sizeof (struct spf_addr)); \
(x)->mech = check_spf_mech (rec->cur_elt, &need_shift); \
(x)->spf_string = memory_pool_strdup (task->task_pool, begin); \
- (x)->data.normal.addr = 0; \
+ memset (&(x)->data.normal, 0, sizeof ((x)->data.normal)); \
(x)->data.normal.mask = 32; \
(x)->is_list = FALSE; \
} while (0);
@@ -987,11 +1141,17 @@ parse_spf_record (struct worker_task *task, struct spf_record *rec)
begin += sizeof (SPF_INCLUDE) - 1;
res = parse_spf_include (task, begin, rec, new);
}
- else if (g_ascii_strncasecmp (begin, SPF_IP6, sizeof (SPF_IP4) - 1) == 0) {
+ 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 ("bad spf command: %s", begin);
@@ -1145,6 +1305,7 @@ spf_dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
union rspamd_reply_element *elt;
GList *cur;
+ rec->requests_inflight --;
if (reply->code == DNS_RC_NOERROR) {
cur = reply->elements;
while (cur) {
@@ -1153,6 +1314,10 @@ spf_dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
cur = g_list_next (cur);
}
}
+
+ if (rec->requests_inflight == 0) {
+ rec->callback (rec, rec->task);
+ }
}
gchar *
@@ -1220,6 +1385,7 @@ resolve_spf (struct worker_task *task, spf_cb_t callback)
if (make_dns_request (task->resolver, task->s, task->task_pool, spf_dns_callback, (void *)rec, DNS_REQUEST_TXT, rec->cur_domain)) {
task->dns_requests ++;
+ rec->requests_inflight ++;
return TRUE;
}
}
@@ -1249,6 +1415,7 @@ resolve_spf (struct worker_task *task, spf_cb_t callback)
rec->sender_domain = rec->cur_domain;
if (make_dns_request (task->resolver, task->s, task->task_pool, spf_dns_callback, (void *)rec, DNS_REQUEST_TXT, rec->cur_domain)) {
task->dns_requests ++;
+ rec->requests_inflight ++;
return TRUE;
}
}
diff --git a/src/spf.h b/src/spf.h
index 90a21c0b3..a9631e733 100644
--- a/src/spf.h
+++ b/src/spf.h
@@ -19,6 +19,7 @@ typedef enum spf_action_e {
SPF_RESOLVE_MX,
SPF_RESOLVE_A,
SPF_RESOLVE_PTR,
+ SPF_RESOLVE_AAA,
SPF_RESOLVE_REDIRECT,
SPF_RESOLVE_INCLUDE,
SPF_RESOLVE_EXISTS,
@@ -28,8 +29,16 @@ typedef enum spf_action_e {
struct spf_addr {
union {
struct {
- guint32 addr;
+ union {
+ struct in_addr in4;
+#ifdef HAVE_INET_PTON
+ struct in6_addr in6;
+#endif
+ } d;
guint32 mask;
+ gboolean ipv6;
+ gboolean parsed;
+ gboolean addr_any;
} normal;
GList *list;
} data;
@@ -45,6 +54,7 @@ struct spf_record {
gint elt_num;
gint nested;
gint dns_requests;
+ gint requests_inflight;
GList *addrs;
gchar *cur_domain;
diff --git a/src/symbols_cache.c b/src/symbols_cache.c
index 49934b6d2..ed8fa73f6 100644
--- a/src/symbols_cache.c
+++ b/src/symbols_cache.c
@@ -634,9 +634,12 @@ init_symbols_cache (memory_pool_t * pool, struct symbols_cache *cache, struct co
static GList *
check_dynamic_item (struct worker_task *task, struct symbols_cache *cache)
{
+#ifdef HAVE_INET_PTON
+ /* TODO: radix doesn't support ipv6 addrs */
+ return NULL;
+#else
GList *res = NULL;
uintptr_t r;
-
if (cache->dynamic_map != NULL && task->from_addr.s_addr != INADDR_NONE) {
if ((r = radix32tree_find (cache->dynamic_map, ntohl (task->from_addr.s_addr))) != RADIX_NO_VALUE) {
res = (GList *)((gpointer)r);
@@ -646,13 +649,18 @@ check_dynamic_item (struct worker_task *task, struct symbols_cache *cache)
return NULL;
}
}
-
return res;
+#endif
}
static gboolean
check_negative_dynamic_item (struct worker_task *task, struct symbols_cache *cache, struct cache_item *item)
{
+
+#ifdef HAVE_INET_PTON
+ /* TODO: radix doesn't support ipv6 addrs */
+ return FALSE;
+#else
GList *res = NULL;
uintptr_t r;
@@ -667,8 +675,9 @@ check_negative_dynamic_item (struct worker_task *task, struct symbols_cache *cac
}
}
}
-
return FALSE;
+#endif
+
}
static gboolean
diff --git a/src/view.c b/src/view.c
index 7b70a07ca..6c67fce95 100644
--- a/src/view.c
+++ b/src/view.c
@@ -135,6 +135,24 @@ find_view_by_ip (GList * views, struct worker_task *task)
GList *cur;
struct rspamd_view *v;
+#ifdef HAVE_INET_PTON
+
+ if (task->from_addr.ipv6 || task->from_addr.d.in4.s_addr == INADDR_NONE) {
+ return NULL;
+ }
+
+ cur = views;
+ while (cur) {
+ v = cur->data;
+ if (radix32tree_find (v->ip_tree, ntohl (task->from_addr.d.in4.s_addr)) != RADIX_NO_VALUE) {
+ return v;
+ }
+ cur = g_list_next (cur);
+ }
+
+ return NULL;
+#else
+
if (task->from_addr.s_addr == INADDR_NONE) {
return NULL;
}
@@ -149,6 +167,7 @@ find_view_by_ip (GList * views, struct worker_task *task)
}
return NULL;
+#endif
}
static struct rspamd_view *
diff --git a/src/worker.c b/src/worker.c
index eecaf45dc..250bf7d31 100644
--- a/src/worker.c
+++ b/src/worker.c
@@ -205,7 +205,6 @@ construct_task (struct rspamd_worker *worker)
new_task->worker = worker;
new_task->state = READ_COMMAND;
new_task->cfg = worker->srv->cfg;
- new_task->from_addr.s_addr = INADDR_NONE;
new_task->view_checked = FALSE;
#ifdef HAVE_CLOCK_GETTIME
# ifdef HAVE_CLOCK_PROCESS_CPUTIME_ID