Browse Source

* Fix spf plugin that was broken in 0.4.7

* Add partial ipv6 support for some rspamd modules.
tags/0.5.0
Vsevolod Stakhov 12 years ago
parent
commit
4d4668a0d4
15 changed files with 432 additions and 46 deletions
  1. 1
    0
      CMakeLists.txt
  2. 2
    0
      config.h.in
  3. 48
    2
      src/dns.c
  4. 7
    1
      src/dns.h
  5. 5
    2
      src/logger.h
  6. 23
    0
      src/lua/lua_task.c
  7. 11
    0
      src/main.h
  8. 10
    1
      src/plugins/fuzzy_check.c
  9. 68
    4
      src/plugins/spf.c
  10. 17
    0
      src/protocol.c
  11. 198
    31
      src/spf.c
  12. 11
    1
      src/spf.h
  13. 12
    3
      src/symbols_cache.c
  14. 19
    0
      src/view.c
  15. 0
    1
      src/worker.c

+ 1
- 0
CMakeLists.txt View File

@@ -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)

#

+ 2
- 0
config.h.in View File

@@ -153,6 +153,8 @@

#cmakedefine HAVE_SETITIMER 1

#cmakedefine HAVE_INET_PTON 1

#define WITHOUT_PERL 1

#cmakedefine WITH_LUA 1

+ 48
- 2
src/dns.c View File

@@ -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 *

+ 7
- 1
src/dns.h View File

@@ -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;

+ 5
- 2
src/logger.h View File

@@ -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__)

+ 23
- 0
src/lua/lua_task.c View File

@@ -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);

+ 11
- 0
src/main.h View File

@@ -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 */

+ 10
- 1
src/plugins/fuzzy_check.c View File

@@ -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) {

+ 68
- 4
src/plugins/spf.c View File

@@ -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
}
}


+ 17
- 0
src/protocol.c View File

@@ -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 {

+ 198
- 31
src/spf.c View File

@@ -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;
}
}

+ 11
- 1
src/spf.h View File

@@ -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;

+ 12
- 3
src/symbols_cache.c View File

@@ -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

+ 19
- 0
src/view.c View File

@@ -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 *

+ 0
- 1
src/worker.c View File

@@ -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

Loading…
Cancel
Save