aboutsummaryrefslogtreecommitdiffstats
path: root/src/libutil
diff options
context:
space:
mode:
Diffstat (limited to 'src/libutil')
-rw-r--r--src/libutil/addr.c135
-rw-r--r--src/libutil/addr.h16
-rw-r--r--src/libutil/radix.c1
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 ++;