diff options
Diffstat (limited to 'src/libutil')
-rw-r--r-- | src/libutil/addr.c | 135 | ||||
-rw-r--r-- | src/libutil/addr.h | 16 | ||||
-rw-r--r-- | src/libutil/radix.c | 1 |
3 files changed, 152 insertions, 0 deletions
diff --git a/src/libutil/addr.c b/src/libutil/addr.c index fa20ff6fe..27ccbc4db 100644 --- a/src/libutil/addr.c +++ b/src/libutil/addr.c @@ -603,6 +603,41 @@ rspamd_inet_address_v6_maybe_map (const struct sockaddr_in6 *sin6) return addr; } +static void +rspamd_inet_address_v6_maybe_map_static (const struct sockaddr_in6 *sin6, + rspamd_inet_addr_t *addr) +{ + /* 10 zero bytes or 80 bits */ + static const guint8 mask[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + const guint8 *p; + + if (memcmp ((const guint8 *)&sin6->sin6_addr, mask, sizeof (mask)) == 0) { + p = (const guint8 *)&sin6->sin6_addr; + + if ((p[10] == 0xff && p[11] == 0xff)) { + memcpy (&addr->u.in.addr.s4.sin_addr, &p[12], + sizeof (struct in_addr)); + addr->af = AF_INET; + addr->slen = sizeof (addr->u.in.addr.s4); + } + else { + /* Something strange but not mapped v4 address */ + memcpy (&addr->u.in.addr.s6.sin6_addr, &sin6->sin6_addr, + sizeof (struct in6_addr)); + addr->af = AF_INET6; + addr->slen = sizeof (addr->u.in.addr.s6); + } + } + else { + memcpy (&addr->u.in.addr.s6.sin6_addr, &sin6->sin6_addr, + sizeof (struct in6_addr)); + addr->af = AF_INET6; + addr->slen = sizeof (addr->u.in.addr.s6); + } +} + gboolean rspamd_parse_inet_address (rspamd_inet_addr_t **target, const char *src, @@ -713,6 +748,100 @@ rspamd_parse_inet_address (rspamd_inet_addr_t **target, return ret; } +gboolean +rspamd_parse_inet_address_ip (const char *src, gsize srclen, + rspamd_inet_addr_t *target) +{ + const char *end; + char ipbuf[INET6_ADDRSTRLEN + 1]; + guint iplen; + gulong portnum; + gboolean ret = FALSE; + union sa_inet su; + + g_assert (target != NULL); + g_assert (src != NULL); + + if (src[0] == '[') { + /* Ipv6 address in format [::1]:port or just [::1] */ + end = memchr (src + 1, ']', srclen - 1); + + if (end == NULL) { + return FALSE; + } + + iplen = end - src - 1; + + if (iplen == 0 || iplen >= sizeof (ipbuf)) { + return FALSE; + } + + rspamd_strlcpy (ipbuf, src + 1, iplen + 1); + + if (rspamd_parse_inet_address_ip6 (ipbuf, iplen, + &su.s6.sin6_addr)) { + rspamd_inet_address_v6_maybe_map_static (&su.s6, target); + ret = TRUE; + } + + if (ret && end[1] == ':') { + /* Port part */ + rspamd_strtoul (end + 1, srclen - iplen - 3, &portnum); + rspamd_inet_address_set_port (target, portnum); + } + } + else { + + if ((end = memchr (src, ':', srclen)) != NULL) { + /* This is either port number and ipv4 addr or ipv6 addr */ + /* Search for another semicolon */ + if (memchr (end + 1, ':', srclen - (end - src + 1)) && + rspamd_parse_inet_address_ip6 (src, srclen, &su.s6.sin6_addr)) { + rspamd_inet_address_v6_maybe_map_static (&su.s6, target); + ret = TRUE; + } + else { + /* Not ipv6, so try ip:port */ + iplen = end - src; + + if (iplen >= sizeof (ipbuf) || iplen <= 1) { + return FALSE; + } + else { + rspamd_strlcpy (ipbuf, src, iplen + 1); + } + + if (rspamd_parse_inet_address_ip4 (ipbuf, iplen, + &su.s4.sin_addr)) { + memcpy (&target->u.in.addr.s4.sin_addr, &su.s4.sin_addr, + sizeof (struct in_addr)); + target->af = AF_INET; + target->slen = sizeof (target->u.in.addr.s4); + rspamd_strtoul (end + 1, srclen - iplen - 1, &portnum); + rspamd_inet_address_set_port (target, portnum); + ret = TRUE; + } + } + } + else { + if (rspamd_parse_inet_address_ip4 (src, srclen, &su.s4.sin_addr)) { + memcpy (&target->u.in.addr.s4.sin_addr, &su.s4.sin_addr, + sizeof (struct in_addr)); + target->af = AF_INET; + target->slen = sizeof (target->u.in.addr.s4); + ret = TRUE; + } + else if (rspamd_parse_inet_address_ip6 (src, srclen, + &su.s6.sin6_addr)) { + rspamd_inet_address_v6_maybe_map_static (&su.s6, target); + ret = TRUE; + } + } + } + + return ret; +} + const char * rspamd_inet_address_to_string (const rspamd_inet_addr_t *addr) { @@ -1583,3 +1712,9 @@ rspamd_inet_library_destroy (void) radix_destroy_compressed (local_addrs); } } + +gsize +rspamd_inet_address_storage_size (void) +{ + return sizeof (rspamd_inet_addr_t); +} diff --git a/src/libutil/addr.h b/src/libutil/addr.h index e648a2b07..2d31e4f23 100644 --- a/src/libutil/addr.h +++ b/src/libutil/addr.h @@ -92,6 +92,16 @@ gboolean rspamd_parse_inet_address_ip4 (const guchar *text, gsize len, gpointer target); /** + * Parse ipv4 or ipv6 address to a static buffer `target`. Does not support Unix sockets + * @param src + * @param srclen + * @param target + * @return + */ +gboolean rspamd_parse_inet_address_ip (const char *src, + gsize srclen, rspamd_inet_addr_t *target); + +/** * Try to parse address from string * @param target target to fill * @param src IP string representation @@ -266,4 +276,10 @@ gboolean rspamd_inet_address_equal (gconstpointer a, gconstpointer b); */ gboolean rspamd_inet_address_is_local (const rspamd_inet_addr_t *addr); +/** + * Returns size of storage required to store a complete IP address + * @return + */ +gsize rspamd_inet_address_storage_size (void); + #endif /* ADDR_H_ */ diff --git a/src/libutil/radix.c b/src/libutil/radix.c index ebfd03197..8b1ca01c9 100644 --- a/src/libutil/radix.c +++ b/src/libutil/radix.c @@ -291,6 +291,7 @@ rspamd_radix_add_iplist (const gchar *list, const gchar *separators, if (k > 32) { k = 32; } + radix_insert_compressed (tree, (guint8 *)&ina, sizeof (ina), 32 - k, (uintptr_t)value); res ++; |