aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libmime/message.c4
-rw-r--r--src/libserver/cfg_rcl.c2
-rw-r--r--src/libserver/protocol.c2
-rw-r--r--src/libutil/addr.c194
-rw-r--r--src/libutil/addr.h25
-rw-r--r--src/lua/lua_http.c2
-rw-r--r--src/lua/lua_ip.c4
-rw-r--r--src/lua/lua_tcp.c2
-rw-r--r--src/rspamd.c3
9 files changed, 219 insertions, 19 deletions
diff --git a/src/libmime/message.c b/src/libmime/message.c
index 183b9bcee..8b257aab3 100644
--- a/src/libmime/message.c
+++ b/src/libmime/message.c
@@ -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;
diff --git a/src/libserver/cfg_rcl.c b/src/libserver/cfg_rcl.c
index 2e348c780..fcfbb716b 100644
--- a/src/libserver/cfg_rcl.c
+++ b/src/libserver/cfg_rcl.c
@@ -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,
diff --git a/src/libserver/protocol.c b/src/libserver/protocol.c
index ba2599f5f..b721c3d62 100644
--- a/src/libserver/protocol.c
+++ b/src/libserver/protocol.c
@@ -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;
}
diff --git a/src/libutil/addr.c b/src/libutil/addr.c
index 042331008..3ddd10289 100644
--- a/src/libutil/addr.c
+++ b/src/libutil/addr.c
@@ -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));
diff --git a/src/libutil/addr.h b/src/libutil/addr.h
index affd87158..d686fa52a 100644
--- a/src/libutil/addr.h
+++ b/src/libutil/addr.h
@@ -64,13 +64,36 @@ 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
* @param src IP string representation
* @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
diff --git a/src/lua/lua_http.c b/src/lua/lua_http.c
index 6e0417a82..23adb6914 100644
--- a/src/lua/lua_http.c
+++ b/src/lua/lua_http.c
@@ -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);
diff --git a/src/lua/lua_ip.c b/src/lua/lua_ip.c
index 43f9892d9..1f4ae03f6 100644
--- a/src/lua/lua_ip.c
+++ b/src/lua/lua_ip.c
@@ -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);
diff --git a/src/lua/lua_tcp.c b/src/lua/lua_tcp.c
index afc1fd5d9..e7d22c6c5 100644
--- a/src/lua/lua_tcp.c
+++ b/src/lua/lua_tcp.c
@@ -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)) {
diff --git a/src/rspamd.c b/src/rspamd.c
index dccd3b6c5..38d998289 100644
--- a/src/rspamd.c
+++ b/src/rspamd.c
@@ -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);
}