aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2015-03-12 14:17:14 +0000
committerVsevolod Stakhov <vsevolod@highsecure.ru>2015-03-12 14:17:14 +0000
commita943f89d45c1ee9073d894aee7d28077187120b7 (patch)
tree534b1f25b8dec5b93237792352dd0628d4f76b63
parente80283ac81f3677ed70f084275f157781d0ebba1 (diff)
downloadrspamd-a943f89d45c1ee9073d894aee7d28077187120b7.tar.gz
rspamd-a943f89d45c1ee9073d894aee7d28077187120b7.zip
Rework inet_address structure.
- Now addresses are opaque. - Save memory by splitting unix and inet sockaddrs. - Rework all functions related to inet addrs. - Use ptr arrays instead of home-made static arrays.
-rw-r--r--src/libutil/addr.c471
-rw-r--r--src/libutil/addr.h100
2 files changed, 444 insertions, 127 deletions
diff --git a/src/libutil/addr.c b/src/libutil/addr.c
index 3c4db3c8f..6877ce87c 100644
--- a/src/libutil/addr.c
+++ b/src/libutil/addr.c
@@ -32,25 +32,100 @@ enum {
RSPAMD_IPV6_UNSUPPORTED
} ipv6_status = RSPAMD_IPV6_UNDEFINED;
+/**
+ * Union that is used for storing sockaddrs
+ */
+union sa_union {
+ struct sockaddr sa;
+ struct sockaddr_in s4;
+ struct sockaddr_in6 s6;
+ struct sockaddr_un su;
+ struct sockaddr_storage ss;
+};
+
+union sa_inet {
+ struct sockaddr sa;
+ struct sockaddr_in s4;
+ struct sockaddr_in6 s6;
+};
+
+struct rspamd_addr_unix {
+ struct sockaddr_un addr;
+ gint mode;
+ uid_t owner;
+ gid_t group;
+};
+
+struct rspamd_addr_inet {
+ union sa_inet addr;
+};
+
+struct rspamd_inet_addr_s {
+ union {
+ struct rspamd_addr_inet in;
+ struct rspamd_addr_unix *un;
+ } u;
+ gint af;
+ socklen_t slen;
+};
static void
rspamd_ip_validate_af (rspamd_inet_addr_t *addr)
{
- if (addr->addr.sa.sa_family != addr->af) {
- addr->addr.sa.sa_family = addr->af;
+ if (addr->af != AF_UNIX) {
+ if (addr->u.in.addr.sa.sa_family != addr->af) {
+ addr->u.in.addr.sa.sa_family = addr->af;
+ }
}
+
if (addr->af == AF_INET) {
- addr->slen = sizeof (addr->addr.s4);
+ addr->slen = sizeof (struct sockaddr_in);
}
else if (addr->af == AF_INET6) {
- addr->slen = sizeof (addr->addr.s6);
+ addr->slen = sizeof (struct sockaddr_in6);
}
else if (addr->af == AF_UNIX) {
#ifdef SUN_LEN
- addr->slen = SUN_LEN (&addr->addr.su);
+ addr->slen = SUN_LEN (&addr->u.un->addr);
#else
- addr->slen = sizeof (addr->addr.su);
+ addr->slen = sizeof (addr->u.un->addr);
#endif
+#if defined(FREEBSD) || defined(__APPLE__)
+ addr->u.un->addr.sun_len = addr->slen;
+#endif
+ }
+}
+
+
+static rspamd_inet_addr_t *
+rspamd_inet_addr_create (gint af)
+{
+ rspamd_inet_addr_t *addr;
+
+ addr = g_slice_alloc (sizeof (rspamd_inet_addr_t));
+
+ if (af == AF_UNIX) {
+ addr->u.un = g_slice_alloc (sizeof (*addr->u.un));
+ addr->slen = sizeof (addr->u.un->addr);
+ }
+
+ addr->af = af;
+
+ rspamd_ip_validate_af (addr);
+
+ return addr;
+}
+
+void
+rspamd_inet_address_destroy (rspamd_inet_addr_t *addr)
+{
+ if (addr) {
+ if (addr->af == AF_UNIX) {
+ if (addr->u.un) {
+ g_slice_free1 (sizeof (*addr->u.un), addr->u.un);
+ }
+ }
+ g_slice_free1 (sizeof (rspamd_inet_addr_t), addr);
}
}
@@ -90,22 +165,22 @@ rspamd_ip_check_ipv6 (void)
}
gboolean
-rspamd_ip_is_valid (rspamd_inet_addr_t *addr)
+rspamd_ip_is_valid (const rspamd_inet_addr_t *addr)
{
const struct in_addr ip4_any = { INADDR_ANY }, ip4_none = { INADDR_NONE };
const struct in6_addr ip6_any = IN6ADDR_ANY_INIT;
gboolean ret = FALSE;
if (G_LIKELY (addr->af == AF_INET)) {
- if (memcmp (&addr->addr.s4.sin_addr, &ip4_any,
+ if (memcmp (&addr->u.in.addr.s4.sin_addr, &ip4_any,
sizeof (struct in_addr)) != 0 &&
- memcmp (&addr->addr.s4.sin_addr, &ip4_none,
+ memcmp (&addr->u.in.addr.s4.sin_addr, &ip4_none,
sizeof (struct in_addr)) != 0) {
ret = TRUE;
}
}
else if (G_UNLIKELY (addr->af == AF_INET6)) {
- if (memcmp (&addr->addr.s6.sin6_addr, &ip6_any,
+ if (memcmp (&addr->u.in.addr.s6.sin6_addr, &ip6_any,
sizeof (struct in6_addr)) != 0) {
ret = TRUE;
}
@@ -115,20 +190,34 @@ rspamd_ip_is_valid (rspamd_inet_addr_t *addr)
}
gint
-rspamd_accept_from_socket (gint sock, rspamd_inet_addr_t *addr)
+rspamd_accept_from_socket (gint sock, rspamd_inet_addr_t **target)
{
gint nfd, serrno;
- socklen_t len = sizeof (addr->addr.ss);
+ union sa_union su;
+ socklen_t len = sizeof (su);
+ rspamd_inet_addr_t *addr = NULL;
+
+ if ((nfd = accept (sock, &su.sa, &len)) == -1) {
+ if (target) {
+ *target = NULL;
+ }
- if ((nfd = accept (sock, &addr->addr.sa, &len)) == -1) {
if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK) {
return 0;
}
return -1;
}
+ addr = rspamd_inet_addr_create (su.sa.sa_family);
addr->slen = len;
- addr->af = addr->addr.sa.sa_family;
+
+ if (addr->af == AF_UNIX) {
+ addr->u.un = g_slice_alloc (sizeof (*addr->u.un));
+ memcpy (&addr->u.un->addr, &su.su, sizeof (struct sockaddr_un));
+ }
+ else {
+ memcpy (&addr->u.in.addr, &su, MIN (len, sizeof (addr->u.in.addr)));
+ }
if (rspamd_socket_nonblocking (nfd) < 0) {
goto out;
@@ -140,37 +229,48 @@ rspamd_accept_from_socket (gint sock, rspamd_inet_addr_t *addr)
goto out;
}
+ if (target) {
+ *target = addr;
+ }
+ else {
+ /* Avoid leak */
+ rspamd_inet_address_destroy (addr);
+ }
+
return (nfd);
out:
serrno = errno;
close (nfd);
errno = serrno;
+ rspamd_inet_address_destroy (addr);
+
return (-1);
}
static gboolean
-rspamd_parse_unix_path (rspamd_inet_addr_t *target, const char *src)
+rspamd_parse_unix_path (rspamd_inet_addr_t **target, const char *src)
{
gchar **tokens, **cur_tok, *p, *pwbuf;
gint pwlen;
struct passwd pw, *ppw;
struct group gr, *pgr;
+ rspamd_inet_addr_t *addr;
tokens = g_strsplit_set (src, " ", -1);
- target->af = AF_UNIX;
- target->slen = sizeof (target->addr.su);
- rspamd_strlcpy (target->addr.su.sun_path, tokens[0],
- sizeof (target->addr.su.sun_path));
- #ifdef FREEBSD
- target->addr.su.sun_len = SUN_LEN (&target->addr.su);
+ addr = rspamd_inet_addr_create (AF_UNIX);
+
+ rspamd_strlcpy (addr->u.un->addr.sun_path, tokens[0],
+ sizeof (addr->u.un->addr.sun_path));
+ #if defined(FREEBSD) || defined(__APPLE__)
+ addr->u.un->addr.sun_len = SUN_LEN (&addr->u.un->addr);
#endif
- target->mode = 00644;
- target->owner = 0;
- target->group = 0;
+ addr->u.un->mode = 00644;
+ addr->u.un->mode = 0;
+ addr->u.un->group = 0;
cur_tok = &tokens[1];
pwlen = sysconf (_SC_GETPW_R_SIZE_MAX);
@@ -181,12 +281,12 @@ rspamd_parse_unix_path (rspamd_inet_addr_t *target, const char *src)
if (g_ascii_strncasecmp (*cur_tok, "mode=", sizeof ("mode=") - 1) == 0) {
p = strchr (*cur_tok, '=');
/* XXX: add error check */
- target->mode = strtoul (p + 1, NULL, 0);
+ addr->u.un->mode = strtoul (p + 1, NULL, 0);
- if (target->mode == 0) {
+ if (addr->u.un->mode == 0) {
msg_err ("bad mode: %s", p + 1);
errno = EINVAL;
- return FALSE;
+ goto err;
}
}
else if (g_ascii_strncasecmp (*cur_tok, "owner=",
@@ -198,10 +298,10 @@ rspamd_parse_unix_path (rspamd_inet_addr_t *target, const char *src)
if (ppw == NULL) {
errno = ENOENT;
}
- return FALSE;
+ goto err;
}
- target->owner = pw.pw_uid;
- target->group = pw.pw_gid;
+ addr->u.un->owner = pw.pw_uid;
+ addr->u.un->group = pw.pw_gid;
}
else if (g_ascii_strncasecmp (*cur_tok, "group=",
sizeof ("group=") - 1) == 0) {
@@ -212,20 +312,37 @@ rspamd_parse_unix_path (rspamd_inet_addr_t *target, const char *src)
if (pgr == NULL) {
errno = ENOENT;
}
- return FALSE;
+ goto err;
}
- target->group = gr.gr_gid;
+ addr->u.un->group = gr.gr_gid;
}
cur_tok ++;
}
+ if (target) {
+ *target = addr;
+ }
+ else {
+ rspamd_inet_address_destroy (addr);
+ }
+
return TRUE;
+
+err:
+
+ rspamd_inet_address_destroy (addr);
+ return FALSE;
}
gboolean
-rspamd_parse_inet_address (rspamd_inet_addr_t *target, const char *src)
+rspamd_parse_inet_address (rspamd_inet_addr_t **target, const char *src)
{
gboolean ret = FALSE;
+ rspamd_inet_addr_t *addr;
+ union sa_inet su;
+
+ g_assert (src != NULL);
+ g_assert (target != NULL);
rspamd_ip_check_ipv6 ();
@@ -233,49 +350,49 @@ rspamd_parse_inet_address (rspamd_inet_addr_t *target, const char *src)
return rspamd_parse_unix_path (target, src);
}
else if (ipv6_status == RSPAMD_IPV6_SUPPORTED &&
- inet_pton (AF_INET6, src, &target->addr.s6.sin6_addr) == 1) {
- target->af = AF_INET6;
- target->slen = sizeof (target->addr.s6);
+ inet_pton (AF_INET6, src, &su.s6.sin6_addr) == 1) {
+ addr = rspamd_inet_addr_create (AF_INET6);
+ memcpy (&addr->u.in.addr.s6.sin6_addr, &su.s6.sin6_addr,
+ sizeof (struct in6_addr));
ret = TRUE;
}
- else if (inet_pton (AF_INET, src, &target->addr.s4.sin_addr) == 1) {
- target->af = AF_INET;
- target->slen = sizeof (target->addr.s4);
+ else if (inet_pton (AF_INET, src, &su.s4.sin_addr) == 1) {
+ addr = rspamd_inet_addr_create (AF_INET6);
+ memcpy (&addr->u.in.addr.s4.sin_addr, &su.s4.sin_addr,
+ sizeof (struct in_addr));
ret = TRUE;
}
- target->addr.sa.sa_family = target->af;
-
return ret;
}
const char *
-rspamd_inet_address_to_string (rspamd_inet_addr_t *addr)
+rspamd_inet_address_to_string (const rspamd_inet_addr_t *addr)
{
static char addr_str[INET6_ADDRSTRLEN + 1];
switch (addr->af) {
case AF_INET:
- return inet_ntop (addr->af, &addr->addr.s4.sin_addr, addr_str,
+ return inet_ntop (addr->af, &addr->u.in.addr.s4.sin_addr, addr_str,
sizeof (addr_str));
case AF_INET6:
- return inet_ntop (addr->af, &addr->addr.s6.sin6_addr, addr_str,
+ return inet_ntop (addr->af, &addr->u.in.addr.s6.sin6_addr, addr_str,
sizeof (addr_str));
case AF_UNIX:
- return addr->addr.su.sun_path;
+ return addr->u.un->addr.sun_path;
}
return "undefined";
}
uint16_t
-rspamd_inet_address_get_port (rspamd_inet_addr_t *addr)
+rspamd_inet_address_get_port (const rspamd_inet_addr_t *addr)
{
switch (addr->af) {
case AF_INET:
- return ntohs (addr->addr.s4.sin_port);
+ return ntohs (addr->u.in.addr.s4.sin_port);
case AF_INET6:
- return ntohs (addr->addr.s6.sin6_port);
+ return ntohs (addr->u.in.addr.s6.sin6_port);
}
return 0;
@@ -286,32 +403,38 @@ rspamd_inet_address_set_port (rspamd_inet_addr_t *addr, uint16_t port)
{
switch (addr->af) {
case AF_INET:
- addr->addr.s4.sin_port = htons (port);
+ addr->u.in.addr.s4.sin_port = htons (port);
break;
case AF_INET6:
- addr->addr.s6.sin6_port = htons (port);
+ addr->u.in.addr.s6.sin6_port = htons (port);
break;
}
}
int
-rspamd_inet_address_connect (rspamd_inet_addr_t *addr, gint type,
+rspamd_inet_address_connect (const rspamd_inet_addr_t *addr, gint type,
gboolean async)
{
int fd, r;
+ const struct sockaddr *sa;
if (addr == NULL) {
return -1;
}
- rspamd_ip_validate_af (addr);
-
fd = rspamd_socket_create (addr->af, type, 0, async);
if (fd == -1) {
return -1;
}
- r = connect (fd, &addr->addr.sa, addr->slen);
+ if (addr->af == AF_UNIX) {
+ sa = (const struct sockaddr *)&addr->u.un->addr;
+ }
+ else {
+ sa = &addr->u.in.addr.sa;
+ }
+
+ r = connect (fd, sa, addr->slen);
if (r == -1) {
if (!async || errno != EINPROGRESS) {
@@ -326,29 +449,37 @@ rspamd_inet_address_connect (rspamd_inet_addr_t *addr, gint type,
}
int
-rspamd_inet_address_listen (rspamd_inet_addr_t *addr, gint type,
+rspamd_inet_address_listen (const rspamd_inet_addr_t *addr, gint type,
gboolean async)
{
gint fd, r;
gint on = 1;
+ const struct sockaddr *sa;
+ const char *path;
if (addr == NULL) {
return -1;
}
- rspamd_ip_validate_af (addr);
fd = rspamd_socket_create (addr->af, type, 0, async);
if (fd == -1) {
return -1;
}
- if (addr->af == AF_UNIX && access (addr->addr.su.sun_path, W_OK) != -1) {
+ if (addr->af == AF_UNIX && access (addr->u.un->addr.sun_path, W_OK) != -1) {
/* Unlink old socket */
- (void)unlink (addr->addr.su.sun_path);
+ (void)unlink (addr->u.un->addr.sun_path);
+ }
+
+ if (addr->af == AF_UNIX) {
+ sa = (const struct sockaddr *)&addr->u.un->addr;
+ }
+ else {
+ sa = &addr->u.in.addr.sa;
}
setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof (gint));
- r = bind (fd, &addr->addr.sa, addr->slen);
+ r = bind (fd, sa, addr->slen);
if (r == -1) {
if (!async || errno != EINPROGRESS) {
close (fd);
@@ -361,15 +492,16 @@ rspamd_inet_address_listen (rspamd_inet_addr_t *addr, gint type,
if (type != SOCK_DGRAM) {
if (addr->af == AF_UNIX) {
+ path = addr->u.un->addr.sun_path;
/* Try to set mode and owner */
- if (chown (addr->addr.su.sun_path, addr->owner, addr->group) == -1) {
+ if (chown (path, addr->u.un->owner, addr->u.un->group) == -1) {
msg_info ("cannot change owner for %s to %d:%d: %s",
- addr->addr.su.sun_path, addr->owner, addr->group,
+ path, addr->u.un->owner, addr->u.un->group,
strerror (errno));
}
- if (chmod (addr->addr.su.sun_path, addr->mode) == -1) {
+ if (chmod (path, addr->u.un->mode) == -1) {
msg_info ("cannot change mode for %s to %od %s",
- addr->addr.su.sun_path, addr->mode, strerror (errno));
+ path, addr->u.un->mode, strerror (errno));
}
}
r = listen (fd, -1);
@@ -384,10 +516,67 @@ rspamd_inet_address_listen (rspamd_inet_addr_t *addr, gint type,
return fd;
}
+gssize
+rspamd_inet_address_recvfrom (gint fd, void *buf, gsize len, gint fl,
+ rspamd_inet_addr_t **target)
+{
+ gssize ret;
+ union sa_union su;
+ socklen_t slen = sizeof (su);
+ rspamd_inet_addr_t *addr = NULL;
+
+ if ((ret = recvfrom (fd, buf, len, fl, &su.sa, &slen)) == -1) {
+ if (target) {
+ *target = NULL;
+ }
+
+ return -1;
+ }
+
+ if (target) {
+ addr = rspamd_inet_addr_create (su.sa.sa_family);
+ addr->slen = len;
+
+ if (addr->af == AF_UNIX) {
+ addr->u.un = g_slice_alloc (sizeof (*addr->u.un));
+ memcpy (&addr->u.un->addr, &su.su, sizeof (struct sockaddr_un));
+ }
+ else {
+ memcpy (&addr->u.in.addr, &su, MIN (len, sizeof (addr->u.in.addr)));
+ }
+
+ *target = addr;
+ }
+
+ return (ret);
+}
+
+gssize
+rspamd_inet_address_sendto (gint fd, const void *buf, gsize len, gint fl,
+ const rspamd_inet_addr_t *addr)
+{
+ gssize r;
+ const struct sockaddr *sa;
+
+ if (addr == NULL) {
+ return -1;
+ }
+
+ if (addr->af == AF_UNIX) {
+ sa = (struct sockaddr *)&addr->u.un->addr;
+ }
+ else {
+ sa = &addr->u.in.addr.sa;
+ }
+
+ r = sendto (fd, buf, len, fl, sa, addr->slen);
+
+ return r;
+}
+
gboolean
rspamd_parse_host_port_priority_strv (gchar **tokens,
- rspamd_inet_addr_t **addr,
- guint *max_addrs,
+ GPtrArray **addrs,
guint *priority,
gchar **name,
guint default_port,
@@ -476,34 +665,30 @@ rspamd_parse_host_port_priority_strv (gchar **tokens,
/* Now copy up to max_addrs of addresses */
addr_cnt = 0;
cur = res;
- while (cur && addr_cnt < *max_addrs) {
+ while (cur) {
cur = cur->ai_next;
addr_cnt ++;
}
- if (pool == NULL) {
- *addr = g_new (rspamd_inet_addr_t, addr_cnt);
- }
- else {
- *addr = rspamd_mempool_alloc (pool, addr_cnt *
- sizeof (rspamd_inet_addr_t));
+ *addrs = g_ptr_array_new_full (addr_cnt,
+ (GDestroyNotify)rspamd_inet_address_destroy);
+
+ if (pool != NULL) {
+ rspamd_mempool_add_destructor (pool,
+ rspamd_ptr_array_free_hard, *addrs);
}
cur = res;
- addr_cnt = 0;
- while (cur && addr_cnt < *max_addrs) {
- cur_addr = &(*addr)[addr_cnt];
- memcpy (&cur_addr->addr, cur->ai_addr,
- MIN (sizeof (cur_addr->addr), cur->ai_addrlen));
- cur_addr->af = cur->ai_family;
- rspamd_ip_validate_af (cur_addr);
- cur_addr->slen = cur->ai_addrlen;
+ while (cur) {
+ cur_addr = rspamd_inet_address_from_sa (cur->ai_addr,
+ cur->ai_addrlen);
+
+ if (cur_addr != NULL) {
+ g_ptr_array_add (*addrs, cur_addr);
+ }
cur = cur->ai_next;
- addr_cnt ++;
}
- *max_addrs = addr_cnt;
-
freeaddrinfo (res);
}
else {
@@ -515,21 +700,22 @@ rspamd_parse_host_port_priority_strv (gchar **tokens,
}
else {
/* Special case of unix socket, as getaddrinfo cannot deal with them */
- if (pool == NULL) {
- *addr = g_new0 (rspamd_inet_addr_t, 1);
- }
- else {
- *addr = rspamd_mempool_alloc0 (pool, sizeof (rspamd_inet_addr_t));
+ *addrs = g_ptr_array_new_full (1,
+ (GDestroyNotify)rspamd_inet_address_destroy);
+
+ if (pool != NULL) {
+ rspamd_mempool_add_destructor (pool,
+ rspamd_ptr_array_free_hard, *addrs);
}
- cur_addr = *addr;
- if (!rspamd_parse_inet_address (cur_addr, tokens[0])) {
+ if (!rspamd_parse_inet_address (&cur_addr, tokens[0])) {
msg_err ("cannot parse unix socket definition %s: %s",
tokens[0],
strerror (errno));
goto err;
}
- *max_addrs = 1;
+
+ g_ptr_array_add (*addrs, cur_addr);
}
/* Restore errno */
@@ -552,8 +738,7 @@ err:
gboolean
rspamd_parse_host_port_priority (
const gchar *str,
- rspamd_inet_addr_t **addr,
- guint *max_addrs,
+ GPtrArray **addrs,
guint *priority,
gchar **name,
guint default_port,
@@ -567,7 +752,7 @@ rspamd_parse_host_port_priority (
return FALSE;
}
- ret = rspamd_parse_host_port_priority_strv (tokens, addr, max_addrs,
+ ret = rspamd_parse_host_port_priority_strv (tokens, addrs,
priority, name, default_port, pool);
g_strfreev (tokens);
@@ -577,12 +762,104 @@ rspamd_parse_host_port_priority (
gboolean
rspamd_parse_host_port (const gchar *str,
- rspamd_inet_addr_t **addr,
- guint *max_addrs,
+ GPtrArray **addrs,
gchar **name,
guint default_port,
rspamd_mempool_t *pool)
{
- return rspamd_parse_host_port_priority (str, addr, max_addrs, NULL,
+ return rspamd_parse_host_port_priority (str, addrs, NULL,
name, default_port, pool);
}
+
+
+guchar*
+rspamd_inet_address_get_radix_key (const rspamd_inet_addr_t *addr, guint *klen)
+{
+ guchar *res = NULL;
+ static struct in_addr local = {INADDR_LOOPBACK};
+
+ g_assert (addr != NULL);
+ g_assert (klen != NULL);
+
+ if (addr->af == AF_INET) {
+ *klen = sizeof (struct in_addr);
+ res = (guchar *)&addr->u.in.addr.s4.sin_addr;
+ }
+ else if (addr->af == AF_INET6) {
+ *klen = sizeof (struct in6_addr);
+ res = (guchar *)&addr->u.in.addr.s6.sin6_addr;
+ }
+ else if (addr->af == AF_UNIX) {
+ *klen = sizeof (struct in_addr);
+ res = (guchar *)&local;
+ }
+
+ return res;
+}
+
+
+rspamd_inet_addr_t *
+rspamd_inet_address_new (int af, const void *init)
+{
+ rspamd_inet_addr_t *addr;
+
+ addr = rspamd_inet_addr_create (af);
+
+ if (init != NULL) {
+ if (af == AF_UNIX) {
+ /* Init is a path */
+ rspamd_strlcpy (addr->u.un->addr.sun_path, init,
+ sizeof (addr->u.un->addr.sun_path));
+#if defined(FREEBSD) || defined(__APPLE__)
+ addr->u.un->addr.sun_len = SUN_LEN (&addr->u.un->addr);
+#endif
+ }
+ else if (af == AF_INET) {
+ memcpy (&addr->u.in.addr.s4.sin_addr, init, sizeof (struct in_addr));
+ }
+ else if (af == AF_INET6) {
+ memcpy (&addr->u.in.addr.s6.sin6_addr, init, sizeof (struct in6_addr));
+ }
+ }
+
+ return addr;
+}
+
+rspamd_inet_addr_t *
+rspamd_inet_address_from_sa (const struct sockaddr *sa, socklen_t slen)
+{
+ rspamd_inet_addr_t *addr;
+
+ g_assert (sa != NULL);
+ g_assert (slen >= sizeof (struct sockaddr));
+
+ addr = rspamd_inet_addr_create (sa->sa_family);
+
+ if (sa->sa_family == AF_UNIX) {
+ /* Init is a path */
+ const struct sockaddr_un *un = (const struct sockaddr_un *)sa;
+
+ g_assert (slen >= SUN_LEN (un));
+
+ rspamd_strlcpy (addr->u.un->addr.sun_path, un->sun_path,
+ sizeof (addr->u.un->addr.sun_path));
+#if defined(FREEBSD) || defined(__APPLE__)
+ addr->u.un->addr.sun_len = un->sun_len;
+#endif
+ }
+ else if (sa->sa_family == AF_INET) {
+ g_assert (slen >= sizeof (struct sockaddr_in));
+ memcpy (&addr->u.in.addr.s4, sa, sizeof (struct sockaddr_in));
+ }
+ else if (sa->sa_family == AF_INET6) {
+ g_assert (slen >= sizeof (struct sockaddr_in6));
+ memcpy (&addr->u.in.addr.s6, sa, sizeof (struct sockaddr_in6));
+ }
+ else {
+ /* XXX: currently we cannot deal with other AF */
+ g_assert (0);
+ }
+
+ return addr;
+}
+
diff --git a/src/libutil/addr.h b/src/libutil/addr.h
index b5282e34c..d3778f6a7 100644
--- a/src/libutil/addr.h
+++ b/src/libutil/addr.h
@@ -27,25 +27,26 @@
#include "mem_pool.h"
/**
- * Union that is used for storing sockaddrs
- */
-union sa_union {
- struct sockaddr_storage ss;
- struct sockaddr sa;
- struct sockaddr_in s4;
- struct sockaddr_in6 s6;
- struct sockaddr_un su;
-};
-
-typedef struct _rspamd_inet_addr_s {
- union sa_union addr;
- socklen_t slen;
- gint af;
- /* Unix socket specific */
- gint mode;
- uid_t owner;
- gid_t group;
-} rspamd_inet_addr_t;
+ * Opaque structure
+ */
+typedef struct rspamd_inet_addr_s rspamd_inet_addr_t;
+
+/**
+ * Create new inet address structure based on the address familiy and opaque init pointer
+ * @param af
+ * @param init
+ * @return new inet addr
+ */
+rspamd_inet_addr_t * rspamd_inet_address_new (int af, const void *init);
+
+/**
+ * Create new inet address structure from struct sockaddr
+ * @param sa
+ * @param slen
+ * @return
+ */
+rspamd_inet_addr_t * rspamd_inet_address_from_sa (const struct sockaddr *sa,
+ socklen_t slen);
/**
* Try to parse address from string
@@ -53,7 +54,7 @@ typedef struct _rspamd_inet_addr_s {
* @param src IP string representation
* @return TRUE if addr has been parsed
*/
-gboolean rspamd_parse_inet_address (rspamd_inet_addr_t *target,
+gboolean rspamd_parse_inet_address (rspamd_inet_addr_t **target,
const char *src);
/**
@@ -61,14 +62,52 @@ gboolean rspamd_parse_inet_address (rspamd_inet_addr_t *target,
* @param addr
* @return statically allocated string pointer (not thread safe)
*/
-const char * rspamd_inet_address_to_string (rspamd_inet_addr_t *addr);
+const char * rspamd_inet_address_to_string (const rspamd_inet_addr_t *addr);
/**
* Returns port number for the specified inet address in host byte order
* @param addr
* @return
*/
-uint16_t rspamd_inet_address_get_port (rspamd_inet_addr_t *addr);
+uint16_t rspamd_inet_address_get_port (const rspamd_inet_addr_t *addr);
+
+/**
+ * Returns address family of inet address
+ * @param addr
+ * @return
+ */
+gint rspamd_inet_address_get_af (const rspamd_inet_addr_t *addr);
+
+
+/**
+ * Makes a radix key from inet address
+ * @param addr
+ * @param klen
+ * @return
+ */
+guchar * rspamd_inet_address_get_radix_key (const rspamd_inet_addr_t *addr, guint *klen);
+
+/**
+ * Receive data from an unconnected socket and fill the inet_addr structure if needed
+ * @param fd
+ * @param buf
+ * @param len
+ * @param target
+ * @return same as recvfrom(2)
+ */
+gssize rspamd_inet_address_recvfrom (gint fd, void *buf, gsize len, gint fl,
+ rspamd_inet_addr_t **target);
+
+/**
+ * Send data via unconnected socket using the specified inet_addr structure
+ * @param fd
+ * @param buf
+ * @param len
+ * @param target
+ * @return
+ */
+gssize rspamd_inet_address_sendto (gint fd, const void *buf, gsize len, gint fl,
+ const rspamd_inet_addr_t *addr);
/**
* Set port for inet address
@@ -81,7 +120,7 @@ void rspamd_inet_address_set_port (rspamd_inet_addr_t *addr, uint16_t port);
* @param async perform operations asynchronously
* @return newly created and connected socket
*/
-int rspamd_inet_address_connect (rspamd_inet_addr_t *addr, gint type,
+int rspamd_inet_address_connect (const rspamd_inet_addr_t *addr, gint type,
gboolean async);
/**
@@ -91,7 +130,7 @@ int rspamd_inet_address_connect (rspamd_inet_addr_t *addr, gint type,
* @param async
* @return
*/
-int rspamd_inet_address_listen (rspamd_inet_addr_t *addr, gint type,
+int rspamd_inet_address_listen (const rspamd_inet_addr_t *addr, gint type,
gboolean async);
/**
* Check whether specified ip is valid (not INADDR_ANY or INADDR_NONE) for ipv4 or ipv6
@@ -99,18 +138,18 @@ int rspamd_inet_address_listen (rspamd_inet_addr_t *addr, gint type,
* @param af address family (AF_INET or AF_INET6)
* @return TRUE if the address is valid
*/
-gboolean rspamd_ip_is_valid (rspamd_inet_addr_t *addr);
+gboolean rspamd_ip_is_valid (const rspamd_inet_addr_t *addr);
/**
* Accept from listening socket filling addr structure
* @param sock listening socket
- * @param addr
+ * @param addr allocated inet addr structur
* @return
*/
-gint rspamd_accept_from_socket (gint sock, rspamd_inet_addr_t *addr);
+gint rspamd_accept_from_socket (gint sock, rspamd_inet_addr_t **addr);
gboolean rspamd_parse_host_port_priority_strv (gchar **tokens,
- rspamd_inet_addr_t **addr, guint *max_addrs, guint *priority,
+ GPtrArray **addrs, guint *priority,
gchar **name, guint default_port, rspamd_mempool_t *pool);
/**
@@ -121,7 +160,7 @@ gboolean rspamd_parse_host_port_priority_strv (gchar **tokens,
* @return TRUE if string was parsed
*/
gboolean rspamd_parse_host_port_priority (const gchar *str,
- rspamd_inet_addr_t **addr, guint *max_addrs,
+ GPtrArray **addrs,
guint *priority, gchar **name, guint default_port,
rspamd_mempool_t *pool);
@@ -132,8 +171,9 @@ gboolean rspamd_parse_host_port_priority (const gchar *str,
* @return TRUE if string was parsed
*/
gboolean rspamd_parse_host_port (const gchar *str,
- rspamd_inet_addr_t **addr, guint *max_addrs,
+ GPtrArray **addrs,
gchar **name, guint default_port, rspamd_mempool_t *pool);
+void rspamd_inet_address_destroy (rspamd_inet_addr_t *addr);
#endif /* ADDR_H_ */