|
|
@@ -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; |
|
|
|
} |
|
|
|
|