]> source.dussan.org Git - rspamd.git/commitdiff
Fix parsing of fixed length IP addresses.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Tue, 13 Oct 2015 14:17:45 +0000 (15:17 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Tue, 13 Oct 2015 14:17:45 +0000 (15:17 +0100)
src/libmime/message.c
src/libserver/cfg_rcl.c
src/libserver/protocol.c
src/libutil/addr.c
src/libutil/addr.h
src/lua/lua_http.c
src/lua/lua_ip.c
src/lua/lua_tcp.c
src/rspamd.c
test/rspamd_http_test.c
test/rspamd_upstream_test.c

index 183b9bcee1843dbfad63cc492730c008bbf3a334..8b257aab3ff57b5357db8b484c40825df97e6172 100644 (file)
@@ -1566,7 +1566,9 @@ rspamd_message_parse (struct rspamd_task *task)
                if (task->received->len > 0 && (task->flags & RSPAMD_TASK_FLAG_NO_IP)) {
                        recv = g_ptr_array_index (task->received, 0);
                        if (recv->real_ip) {
-                               if (!rspamd_parse_inet_address (&task->from_addr, recv->real_ip)) {
+                               if (!rspamd_parse_inet_address (&task->from_addr,
+                                               recv->real_ip,
+                                               0)) {
                                        msg_warn_task ("cannot get IP from received header: '%s'",
                                                        recv->real_ip);
                                        task->from_addr = NULL;
index 2e348c780f31898f7be7be977a532874153ac07c..fcfbb716b3b232ced9be5f1608fcb0c2a1d5ebd8 100644 (file)
@@ -2343,7 +2343,7 @@ rspamd_rcl_parse_struct_addr (rspamd_mempool_t *pool,
        if (ucl_object_type (obj) == UCL_STRING) {
                val = ucl_object_tostring (obj);
 
-               if (!rspamd_parse_inet_address (target, val)) {
+               if (!rspamd_parse_inet_address (target, val, 0)) {
                        g_set_error (err,
                                CFG_RCL_ERROR,
                                EINVAL,
index ba2599f5ff7e78ca5640b2c8e09680f71d8341e4..b721c3d62489b5854fb5e2d4a1b71d4af3a9e265 100644 (file)
@@ -389,7 +389,7 @@ rspamd_protocol_handle_headers (struct rspamd_task *task,
                case 'i':
                case 'I':
                        if (g_ascii_strncasecmp (headern, IP_ADDR_HEADER, hlen) == 0) {
-                               if (!rspamd_parse_inet_address (&task->from_addr, hv->str)) {
+                               if (!rspamd_parse_inet_address (&task->from_addr, hv->str, 0)) {
                                        msg_err_task ("bad ip header: '%V'", hv);
                                        return FALSE;
                                }
index 0423310088e00d741f9de16bac6517990fd3fbe9..3ddd1028915eff8543b5401ee0f8966ecbb6777b 100644 (file)
@@ -352,7 +352,175 @@ err:
 }
 
 gboolean
-rspamd_parse_inet_address (rspamd_inet_addr_t **target, const char *src)
+rspamd_parse_inet_address_ip4 (const guchar *text, gsize len, gpointer target)
+{
+       const guchar *p;
+       guchar c;
+       guint32 addr = 0, *addrptr = target;
+       guint octet = 0, n = 0;
+
+       g_assert (text != NULL);
+       g_assert (target != NULL);
+
+       if (len == 0) {
+               len = strlen (text);
+       }
+
+       for (p = text; p < text + len; p++) {
+               c = *p;
+
+               if (c >= '0' && c <= '9') {
+                       octet = octet * 10 + (c - '0');
+
+                       if (octet > 255) {
+                               return FALSE;
+                       }
+
+                       continue;
+               }
+
+               if (c == '.') {
+                       addr = (addr << 8) + octet;
+                       octet = 0;
+                       n++;
+                       continue;
+               }
+
+               return FALSE;
+       }
+
+       if (n == 3) {
+               addr = (addr << 8) + octet;
+               *addrptr = ntohl (addr);
+
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+gboolean
+rspamd_parse_inet_address_ip6 (const guchar *text, gsize len, gpointer target)
+{
+       guchar t, *zero = NULL, *s, *d,  *addr = target;
+       const guchar *p, *digit = NULL;
+       gsize len4 = 0;
+       guint n = 8, nibbles = 0, word = 0;
+
+       g_assert (text != NULL);
+       g_assert (target != NULL);
+
+       if (len == 0) {
+               len = strlen (text);
+       }
+
+       /* Ignore trailing semicolon */
+       if (text[0] == ':') {
+               p = text + 1;
+               len--;
+       }
+       else {
+               p = text;
+       }
+
+       for (/* void */; len; len--) {
+               t = *p++;
+
+               if (t == ':') {
+                       if (nibbles) {
+                               digit = p;
+                               len4 = len;
+                               *addr++ = (u_char) (word >> 8);
+                               *addr++ = (u_char) (word & 0xff);
+
+                               if (--n) {
+                                       nibbles = 0;
+                                       word = 0;
+                                       continue;
+                               }
+                       } else {
+                               if (zero == NULL) {
+                                       digit = p;
+                                       len4 = len;
+                                       zero = addr;
+                                       continue;
+                               }
+                       }
+
+                       return FALSE;
+               }
+
+               if (t == '.' && nibbles) {
+                       if (n < 2 || digit == NULL) {
+                               return FALSE;
+                       }
+
+                       /* IPv4 encoded in IPv6 */
+                       if (!rspamd_parse_inet_address_ip4 (digit, len4 - 1, &word)) {
+                               return FALSE;
+                       }
+
+                       word = ntohl (word);
+                       *addr++ = (guchar) ((word >> 24) & 0xff);
+                       *addr++ = (guchar) ((word >> 16) & 0xff);
+                       n--;
+                       break;
+               }
+
+               if (++nibbles > 4) {
+                       /* Too many dots */
+                       return FALSE;
+               }
+
+               /* Restore from hex */
+               if (t >= '0' && t <= '9') {
+                       word = word * 16 + (t - '0');
+                       continue;
+               }
+
+               t |= 0x20;
+
+               if (t >= 'a' && t <= 'f') {
+                       word = word * 16 + (t - 'a') + 10;
+                       continue;
+               }
+
+               return FALSE;
+       }
+
+       if (nibbles == 0 && zero == NULL) {
+               return FALSE;
+       }
+
+       *addr++ = (guchar) (word >> 8);
+       *addr++ = (guchar) (word & 0xff);
+
+       if (--n) {
+               if (zero) {
+                       n *= 2;
+                       s = addr - 1;
+                       d = s + n;
+                       while (s >= zero) {
+                               *d-- = *s--;
+                       }
+                       memset (zero, 0, n);
+
+                       return TRUE;
+               }
+
+       } else {
+               if (zero == NULL) {
+                       return TRUE;
+               }
+       }
+
+       return FALSE;
+}
+
+gboolean
+rspamd_parse_inet_address (rspamd_inet_addr_t **target,
+               const char *src,
+               gsize srclen)
 {
        gboolean ret = FALSE;
        rspamd_inet_addr_t *addr = NULL;
@@ -360,11 +528,15 @@ rspamd_parse_inet_address (rspamd_inet_addr_t **target, const char *src)
        const char *end;
        char ipbuf[INET6_ADDRSTRLEN + 1];
        guint iplen;
-       guint portnum;
+       gulong portnum;
 
        g_assert (src != NULL);
        g_assert (target != NULL);
 
+       if (srclen == 0) {
+               srclen = strlen (src);
+       }
+
        rspamd_ip_check_ipv6 ();
 
        if (src[0] == '/' || src[0] == '.') {
@@ -388,7 +560,8 @@ rspamd_parse_inet_address (rspamd_inet_addr_t **target, const char *src)
                rspamd_strlcpy (ipbuf, src + 1, iplen);
 
                if (ipv6_status == RSPAMD_IPV6_SUPPORTED &&
-                               inet_pton (AF_INET6, ipbuf, &su.s6.sin6_addr) == 1) {
+                               rspamd_parse_inet_address_ip6 (ipbuf, iplen - 1,
+                                               &su.s6.sin6_addr)) {
                        addr = rspamd_inet_addr_create (AF_INET6);
                        memcpy (&addr->u.in.addr.s6.sin6_addr, &su.s6.sin6_addr,
                                        sizeof (struct in6_addr));
@@ -397,7 +570,7 @@ rspamd_parse_inet_address (rspamd_inet_addr_t **target, const char *src)
 
                if (ret && end[1] == ':') {
                        /* Port part */
-                       portnum = strtoul (end + 1, NULL, 10);
+                       rspamd_strtoul (end + 1, srclen - iplen - 1, &portnum);
                        rspamd_inet_address_set_port (addr, portnum);
                }
        }
@@ -406,7 +579,7 @@ rspamd_parse_inet_address (rspamd_inet_addr_t **target, const char *src)
                if ((end = strchr (src, ':')) != NULL) {
                        /* This is either port number and ipv4 addr or ipv6 addr */
                        if (ipv6_status == RSPAMD_IPV6_SUPPORTED &&
-                                       inet_pton (AF_INET6, src, &su.s6.sin6_addr) == 1) {
+                                       rspamd_parse_inet_address_ip6 (src, srclen, &su.s6.sin6_addr)) {
                                addr = rspamd_inet_addr_create (AF_INET6);
                                memcpy (&addr->u.in.addr.s6.sin6_addr, &su.s6.sin6_addr,
                                                sizeof (struct in6_addr));
@@ -423,25 +596,26 @@ rspamd_parse_inet_address (rspamd_inet_addr_t **target, const char *src)
                                        rspamd_strlcpy (ipbuf, src, iplen);
                                }
 
-                               if (inet_pton (AF_INET, ipbuf, &su.s4.sin_addr) == 1) {
+                               if (rspamd_parse_inet_address_ip4 (ipbuf, iplen - 1,
+                                               &su.s4.sin_addr)) {
                                        addr = rspamd_inet_addr_create (AF_INET);
                                        memcpy (&addr->u.in.addr.s4.sin_addr, &su.s4.sin_addr,
                                                        sizeof (struct in_addr));
-                                       portnum = strtoul (end + 1, NULL, 10);
+                                       rspamd_strtoul (end + 1, srclen - iplen - 1, &portnum);
                                        rspamd_inet_address_set_port (addr, portnum);
                                        ret = TRUE;
                                }
                        }
                }
                else {
-                       if (inet_pton (AF_INET, src, &su.s4.sin_addr) == 1) {
+                       if (rspamd_parse_inet_address_ip4 (src, srclen, &su.s4.sin_addr)) {
                                addr = rspamd_inet_addr_create (AF_INET);
                                memcpy (&addr->u.in.addr.s4.sin_addr, &su.s4.sin_addr,
                                                sizeof (struct in_addr));
                                ret = TRUE;
                        }
                        else if (ipv6_status == RSPAMD_IPV6_SUPPORTED &&
-                                       inet_pton (AF_INET6, src, &su.s6.sin6_addr) == 1) {
+                                       rspamd_parse_inet_address_ip6 (src, srclen, &su.s6.sin6_addr)) {
                                addr = rspamd_inet_addr_create (AF_INET6);
                                memcpy (&addr->u.in.addr.s6.sin6_addr, &su.s6.sin6_addr,
                                                sizeof (struct in6_addr));
@@ -820,7 +994,7 @@ rspamd_parse_host_port_priority_strv (gchar **tokens,
                                        rspamd_ptr_array_free_hard, *addrs);
                }
 
-               if (!rspamd_parse_inet_address (&cur_addr, tokens[0])) {
+               if (!rspamd_parse_inet_address (&cur_addr, tokens[0], 0)) {
                        msg_err ("cannot parse unix socket definition %s: %s",
                                        tokens[0],
                                        strerror (errno));
index affd871583052a578f6fa3413c03481329663c77..d686fa52a8f76ace72c6b4b4a9655a98ad49aba3 100644 (file)
@@ -63,6 +63,28 @@ rspamd_inet_addr_t * rspamd_inet_address_new (int af, const void *init);
 rspamd_inet_addr_t * rspamd_inet_address_from_sa (const struct sockaddr *sa,
                socklen_t slen);
 
+/**
+ * Parse string with ipv6 address of length `len` to `target` which should be
+ * at least sizeof (in6_addr_t)
+ * @param text input string
+ * @param len lenth of `text` (if 0, then `text` must be zero terminated)
+ * @param target target structure
+ * @return TRUE if the address has been parsed, otherwise `target` content is undefined
+ */
+gboolean rspamd_parse_inet_address_ip6 (const guchar *text, gsize len,
+               gpointer target);
+
+/**
+ * Parse string with ipv4 address of length `len` to `target` which should be
+ * at least sizeof (in4_addr_t)
+ * @param text input string
+ * @param len lenth of `text` (if 0, then `text` must be zero terminated)
+ * @param target target structure
+ * @return TRUE if the address has been parsed, otherwise `target` content is undefined
+ */
+gboolean rspamd_parse_inet_address_ip4 (const guchar *text, gsize len,
+               gpointer target);
+
 /**
  * Try to parse address from string
  * @param target target to fill
@@ -70,7 +92,8 @@ rspamd_inet_addr_t * rspamd_inet_address_from_sa (const struct sockaddr *sa,
  * @return TRUE if addr has been parsed
  */
 gboolean rspamd_parse_inet_address (rspamd_inet_addr_t **target,
-       const char *src);
+               const char *src,
+               gsize srclen);
 
 /**
  * Returns string representation of inet address
index 6e0417a82586092125e859de68d919bb09cb5bb6..23adb69148f432984123d39d7fc7fc22ad309721 100644 (file)
@@ -449,7 +449,7 @@ lua_http_request (lua_State *L)
                rspamd_session_watcher_push (session);
        }
 
-       if (rspamd_parse_inet_address (&cbd->addr, msg->host->str)) {
+       if (rspamd_parse_inet_address (&cbd->addr, msg->host->str, 0)) {
                /* Host is numeric IP, no need to resolve */
                if (!lua_http_make_connection (cbd)) {
                        lua_http_maybe_free (cbd);
index 43f9892d9a015a5dbfe3053f8eca29387ee50133..1f4ae03f61672ed63037b6ac2facb2e9b9c6a3da 100644 (file)
@@ -359,7 +359,7 @@ lua_ip_from_string (lua_State *L)
        ip_str = luaL_checkstring (L, 1);
        if (ip_str) {
                ip = lua_ip_new (L, NULL);
-               rspamd_parse_inet_address (&ip->addr, ip_str);
+               rspamd_parse_inet_address (&ip->addr, ip_str, 0);
        }
        else {
                lua_pushnil (L);
@@ -511,7 +511,7 @@ rspamd_lua_ip_push_fromstring (lua_State *L, const gchar *ip_str)
        }
        else {
                ip = g_slice_alloc0 (sizeof (struct rspamd_lua_ip));
-               rspamd_parse_inet_address (&ip->addr, ip_str);
+               rspamd_parse_inet_address (&ip->addr, ip_str, 0);
 
                pip = lua_newuserdata (L, sizeof (struct rspamd_lua_ip *));
                rspamd_lua_setclass (L, "rspamd{ip}", -1);
index afc1fd5d908af65010a4353271ba1304017888f7..e7d22c6c554f2912504ae91b0e5bd01e4e1655d2 100644 (file)
@@ -600,7 +600,7 @@ lua_tcp_request (lua_State *L)
                                g_quark_from_static_string ("lua tcp"));
        }
 
-       if (rspamd_parse_inet_address (&cbd->addr, host)) {
+       if (rspamd_parse_inet_address (&cbd->addr, host, 0)) {
                rspamd_inet_address_set_port (cbd->addr, port);
                /* Host is numeric IP, no need to resolve */
                if (!lua_tcp_make_connection (cbd)) {
index dccd3b6c5959e16b17a7b6123db6c43520e729b9..38d99828958656643437075334643a9e54ded0b8 100644 (file)
@@ -979,7 +979,8 @@ main (gint argc, gchar **argv, gchar **env)
        control_fd = -1;
        if (rspamd_main->cfg->control_socket_path) {
                if (!rspamd_parse_inet_address (&control_addr,
-                               rspamd_main->cfg->control_socket_path)) {
+                               rspamd_main->cfg->control_socket_path,
+                               0)) {
                        msg_err_main ("cannot parse inet address %s",
                                        rspamd_main->cfg->control_socket_path);
                }
index 81b598a45213c1b6028f6a85b346a3bdaf9c49cf..f05d828b5c2e42e2272adb036d3fc2ab6e4cc549 100644 (file)
@@ -244,7 +244,7 @@ rspamd_http_test_func (void)
 
        mtx = rspamd_mempool_get_mutex (pool);
 
-       rspamd_parse_inet_address (&addr, "127.0.0.1");
+       rspamd_parse_inet_address (&addr, "127.0.0.1", 0);
        rspamd_inet_address_set_port (addr, ottery_rand_range (30000) + 32768);
        serv_key = rspamd_http_connection_gen_key ();
        client_key = rspamd_http_connection_gen_key ();
index e2f2c17eef17f8f33473ba0e672e73b3e9ce320c..528b0a9dcd66647a5382b087605e7062d5a1add4 100644 (file)
@@ -138,9 +138,9 @@ rspamd_upstream_test_func (void)
        nls = rspamd_upstreams_create ();
        g_assert (rspamd_upstreams_add_upstream (nls, "127.0.0.1", 0, NULL));
        up = rspamd_upstream_get (nls, RSPAMD_UPSTREAM_RANDOM);
-       rspamd_parse_inet_address(&paddr, "127.0.0.2");
+       rspamd_parse_inet_address (&paddr, "127.0.0.2", 0);
        g_assert (rspamd_upstream_add_addr (up, paddr));
-       rspamd_parse_inet_address(&paddr, "::1");
+       rspamd_parse_inet_address (&paddr, "::1", 0);
        g_assert (rspamd_upstream_add_addr (up, paddr));
        addr = rspamd_upstream_addr (up);
        for (i = 0; i < 256; i ++) {