diff options
Diffstat (limited to 'src/libutil/addr.c')
-rw-r--r-- | src/libutil/addr.c | 600 |
1 files changed, 503 insertions, 97 deletions
diff --git a/src/libutil/addr.c b/src/libutil/addr.c index 3c4db3c8f..2db961574 100644 --- a/src/libutil/addr.c +++ b/src/libutil/addr.c @@ -32,28 +32,108 @@ 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; + } + } + else { + addr->u.un->addr.sun_family = AF_UNIX; } + 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_alloc0 (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); + /* Zero terminate to avoid issues with SUN_LEN */ + addr->u.un->addr.sun_path[0] = '\0'; + } + + 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); + } +} + static void rspamd_ip_check_ipv6 (void) { @@ -90,22 +170,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 +195,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 +234,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 +286,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 +303,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,70 +317,92 @@ 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) { + rspamd_ip_validate_af (addr); + *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 = NULL; + union sa_inet su; + + g_assert (src != NULL); + g_assert (target != NULL); rspamd_ip_check_ipv6 (); if (src[0] == '/' || src[0] == '.') { 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); + else if (inet_pton (AF_INET, src, &su.s4.sin_addr) == 1) { + 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 (inet_pton (AF_INET, src, &target->addr.s4.sin_addr) == 1) { - target->af = AF_INET; - target->slen = sizeof (target->addr.s4); + else if (ipv6_status == RSPAMD_IPV6_SUPPORTED && + 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; } - target->addr.sa.sa_family = target->af; + if (ret && target) { + *target = addr; + } 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 +413,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 +459,46 @@ 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); + +#ifdef HAVE_IPV6_V6ONLY + if (addr->af == AF_INET6) { + /* We need to set this flag to avoid errors */ + on = 1; + setsockopt (fd, SOL_IPV6, IPV6_V6ONLY, (const void *)&on, sizeof (gint)); + } +#endif + + r = bind (fd, sa, addr->slen); if (r == -1) { if (!async || errno != EINPROGRESS) { close (fd); @@ -361,15 +511,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 +535,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 +684,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 +719,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 +757,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 +771,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 +781,214 @@ 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; +} + +void +rspamd_inet_address_apply_mask (rspamd_inet_addr_t *addr, guint mask) +{ + guint32 umsk, *p; + + if (mask > 0 && addr != NULL) { + if (addr->af == AF_INET && mask <= 32) { + umsk = htonl (G_MAXUINT32 << (32 - mask)); + addr->u.in.addr.s4.sin_addr.s_addr &= umsk; + } + else if (addr->af == AF_INET && mask <= 128) { + p = (uint32_t *)&addr->u.in.addr.s6.sin6_addr; + p += 3; + while (mask > 0) { + umsk = htonl (G_MAXUINT32 << (32 - (mask > 32 ? 32 : mask))); + *p &= umsk; + p --; + mask -= 32; + } + } + } +} + +static gint +rspamd_inet_address_af_order (const rspamd_inet_addr_t *addr) +{ + int ret; + + switch (addr->af) { + case AF_UNIX: + ret = 2; + break; + case AF_INET: + ret = 1; + break; + default: + ret = 0; + break; + } + + return ret; +} + +gint +rspamd_inet_address_compare (const rspamd_inet_addr_t *a1, + const rspamd_inet_addr_t *a2) +{ + g_assert (a1 != NULL); + g_assert (a2 != NULL); + + if (a1->af != a2->af) { + return (rspamd_inet_address_af_order (a2) - + rspamd_inet_address_af_order (a1)); + } + else { + switch (a1->af) { + case AF_INET: + return memcmp (&a1->u.in.addr.s4.sin_addr, + &a2->u.in.addr.s4.sin_addr, sizeof (struct in_addr)); + case AF_INET6: + return memcmp (&a1->u.in.addr.s6.sin6_addr, + &a2->u.in.addr.s6.sin6_addr, sizeof (struct in6_addr)); + case AF_UNIX: + return strncmp (a1->u.un->addr.sun_path, + a2->u.un->addr.sun_path, sizeof (a1->u.un->addr.sun_path)); + default: + return memcmp (&a1->u.in, &a2->u.in, sizeof (a1->u.in)); + } + } + + return 0; +} + +gint +rspamd_inet_address_compare_ptr (const gpointer a1, + const gpointer a2) +{ + const rspamd_inet_addr_t **i1 = a1, **i2 = a2; + + return rspamd_inet_address_compare (*i1, *i2); +} + +rspamd_inet_addr_t * +rspamd_inet_address_copy (const rspamd_inet_addr_t *addr) +{ + rspamd_inet_addr_t *n; + + if (addr == NULL) { + return NULL; + } + + n = rspamd_inet_addr_create (addr->af); + + if (n->af == AF_UNIX) { + memcpy (n->u.un, addr->u.un, sizeof (*addr->u.un)); + } + else { + memcpy (&n->u.in, &addr->u.in, sizeof (addr->u.in)); + } + + return n; +} + +gint +rspamd_inet_address_get_af (const rspamd_inet_addr_t *addr) +{ + g_assert (addr != NULL); + + return addr->af; +} |