]> source.dussan.org Git - rspamd.git/commitdiff
* Fix spf plugin that was broken in 0.4.7
authorVsevolod Stakhov <vsevolod@rambler-co.ru>
Fri, 20 Apr 2012 16:02:28 +0000 (20:02 +0400)
committerVsevolod Stakhov <vsevolod@rambler-co.ru>
Fri, 20 Apr 2012 16:02:28 +0000 (20:02 +0400)
* Add partial ipv6 support for some rspamd modules.

15 files changed:
CMakeLists.txt
config.h.in
src/dns.c
src/dns.h
src/logger.h
src/lua/lua_task.c
src/main.h
src/plugins/fuzzy_check.c
src/plugins/spf.c
src/protocol.c
src/spf.c
src/spf.h
src/symbols_cache.c
src/view.c
src/worker.c

index 565cabe0497ea8c3aa9139bb6c2fac3d482477d8..fc15f86c8b7ca4605cae52f438b1c98b5c13ba58 100644 (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)
 
 # 
index 8ad00557dc40f1ba8cbd90202493958abd1c6ca9..186021446809e977ec47d9629c40bbcb5b277c8a 100644 (file)
 
 #cmakedefine HAVE_SETITIMER      1
 
+#cmakedefine HAVE_INET_PTON      1
+
 #define      WITHOUT_PERL        1
 
 #cmakedefine WITH_LUA            1
index fe087da08bed7f091fbb53998d87f5a986089c2d..f39d47843daa687e605d41226587dbac2dc9a51e 100644 (file)
--- 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 *
index f174f5026703968c3040c678bb1c303a5f85291a..8914ae5b1d30504ab273d7cb969cf21ab2028762 100644 (file)
--- 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;
index 6d0cac4b81c5b74183956b58012521c17006391e..ec7a23af5fc9f13501cee2fc88e58c665f2eda5c 100644 (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__)
index 7ca1c58df01d49c6a17da8505fe2a639d18b25dd..5695b6f42e563d3c4a172b754a5734f065208cb4 100644 (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);
index 22b2f75848b584a3e0b1aebe59660a54768a625b..1d8fab134a3749653d03f5d23b0258472d356f5d 100644 (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                                                            */
index 4f66a5731c3feb816fcb21927283eba5d251a643..7d400a0c42504a3e609663ea3c63ff916fb5c582 100644 (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) {
index 093c57703c84f96c4b9ebacbd549e34cda7ded4c..26b3c190350bbf153a3678729049a533d0207b15 100644 (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
        }
 }
 
index 40bd01e0cc9ff22a599e11f02ee615201f315923..fc03acacbe1f352c7c04b3e6449980acbd452f9c 100644 (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 {
index 137ca0f5e3153836c1655e05430b67aecfe60d12..738b56ee81c3b456712582c804c23e9445714af4 100644 (file)
--- 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;
                        }
                }
index 90a21c0b36a1faac0baef74fc37d3d83d6562a7e..a9631e733b922dab7e810389a85a2c4602989734 100644 (file)
--- 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;
index 49934b6d2e530226e4c6f425de9bccc636c0e29c..ed8fa73f6fbd1cfb07307cab41e9165886e516c6 100644 (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
index 7b70a07cadc295a8bbff1d8a28fd8ae876c68055..6c67fce9580f012eb050728a014fab0208910577 100644 (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             *
index eecaf45dc6c9ec751be17059e9c83c8798bb7f41..250bf7d3156bae99d8911a9971530657a2546268 100644 (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