"Fossies" - the Fresh Open Source Software Archive

Member "rspamd-1.7.8/src/libutil/addr.c" (12 Jul 2018, 37757 Bytes) of package /linux/misc/rspamd-1.7.8.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "addr.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.7.5_vs_1.7.6.

    1 /*-
    2  * Copyright 2016 Vsevolod Stakhov
    3  *
    4  * Licensed under the Apache License, Version 2.0 (the "License");
    5  * you may not use this file except in compliance with the License.
    6  * You may obtain a copy of the License at
    7  *
    8  *   http://www.apache.org/licenses/LICENSE-2.0
    9  *
   10  * Unless required by applicable law or agreed to in writing, software
   11  * distributed under the License is distributed on an "AS IS" BASIS,
   12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13  * See the License for the specific language governing permissions and
   14  * limitations under the License.
   15  */
   16 #include "config.h"
   17 #include "addr.h"
   18 #include "util.h"
   19 #include "map_helpers.h"
   20 #include "logger.h"
   21 #include "cryptobox.h"
   22 #include "unix-std.h"
   23 /* pwd and grp */
   24 #ifdef HAVE_PWD_H
   25 #include <pwd.h>
   26 #endif
   27 
   28 #ifdef HAVE_GRP_H
   29 #include <grp.h>
   30 #endif
   31 
   32 static struct rspamd_radix_map_helper *local_addrs;
   33 
   34 enum {
   35     RSPAMD_IPV6_UNDEFINED = 0,
   36     RSPAMD_IPV6_SUPPORTED,
   37     RSPAMD_IPV6_UNSUPPORTED
   38 } ipv6_status = RSPAMD_IPV6_UNDEFINED;
   39 
   40 /**
   41  * Union that is used for storing sockaddrs
   42  */
   43 union sa_union {
   44     struct sockaddr sa;
   45     struct sockaddr_in s4;
   46     struct sockaddr_in6 s6;
   47     struct sockaddr_un su;
   48     struct sockaddr_storage ss;
   49 };
   50 
   51 union sa_inet {
   52     struct sockaddr sa;
   53     struct sockaddr_in s4;
   54     struct sockaddr_in6 s6;
   55 };
   56 
   57 struct rspamd_addr_unix {
   58     struct sockaddr_un addr;
   59     gint mode;
   60     uid_t owner;
   61     gid_t group;
   62 };
   63 
   64 struct rspamd_addr_inet {
   65     union sa_inet addr;
   66 };
   67 
   68 struct rspamd_inet_addr_s {
   69     union {
   70         struct rspamd_addr_inet in;
   71         struct rspamd_addr_unix *un;
   72     } u;
   73     gint af;
   74     socklen_t slen;
   75 };
   76 
   77 static void
   78 rspamd_ip_validate_af (rspamd_inet_addr_t *addr)
   79 {
   80     if (addr->af != AF_UNIX) {
   81         if (addr->u.in.addr.sa.sa_family != addr->af) {
   82             addr->u.in.addr.sa.sa_family = addr->af;
   83         }
   84     }
   85     else {
   86         addr->u.un->addr.sun_family = AF_UNIX;
   87     }
   88 
   89     if (addr->af == AF_INET) {
   90         addr->slen = sizeof (struct sockaddr_in);
   91     }
   92     else if (addr->af == AF_INET6) {
   93         addr->slen = sizeof (struct sockaddr_in6);
   94     }
   95     else if (addr->af == AF_UNIX) {
   96 #ifdef SUN_LEN
   97         addr->slen = SUN_LEN (&addr->u.un->addr);
   98 #else
   99         addr->slen = sizeof (addr->u.un->addr);
  100 #endif
  101 #if defined(FREEBSD) || defined(__APPLE__)
  102         addr->u.un->addr.sun_len = addr->slen;
  103 #endif
  104     }
  105 }
  106 
  107 
  108 static rspamd_inet_addr_t *
  109 rspamd_inet_addr_create (gint af)
  110 {
  111     rspamd_inet_addr_t *addr;
  112 
  113     addr = g_malloc0 (sizeof (rspamd_inet_addr_t));
  114 
  115     addr->af = af;
  116 
  117     if (af == AF_UNIX) {
  118         addr->u.un = g_malloc0 (sizeof (*addr->u.un));
  119         addr->slen = sizeof (addr->u.un->addr);
  120     }
  121     else {
  122         rspamd_ip_validate_af (addr);
  123     }
  124 
  125     return addr;
  126 }
  127 
  128 void
  129 rspamd_inet_address_free (rspamd_inet_addr_t *addr)
  130 {
  131     if (addr) {
  132         if (addr->af == AF_UNIX) {
  133             if (addr->u.un) {
  134                 g_free (addr->u.un);
  135             }
  136         }
  137         g_free (addr);
  138     }
  139 }
  140 
  141 static void
  142 rspamd_ip_check_ipv6 (void)
  143 {
  144     if (ipv6_status == RSPAMD_IPV6_UNDEFINED) {
  145         gint s, r;
  146         struct sockaddr_in6 sin6;
  147         const struct in6_addr ip6_local = IN6ADDR_LOOPBACK_INIT;
  148 
  149         s = socket (AF_INET6, SOCK_STREAM, 0);
  150         if (s == -1) {
  151             ipv6_status = RSPAMD_IPV6_UNSUPPORTED;
  152         }
  153         else {
  154             /*
  155              * Some systems allow ipv6 sockets creating but not binding,
  156              * so here we try to bind to some local address and check, whether it
  157              * is possible
  158              */
  159             memset (&sin6, 0, sizeof (sin6));
  160             sin6.sin6_family = AF_INET6;
  161             sin6.sin6_port = rspamd_random_uint64_fast () % 40000 + 20000;
  162             sin6.sin6_addr = ip6_local;
  163 
  164             r = bind (s, (struct sockaddr *)&sin6, sizeof (sin6));
  165             if (r == -1 && errno != EADDRINUSE) {
  166                 ipv6_status = RSPAMD_IPV6_UNSUPPORTED;
  167             }
  168             else {
  169                 ipv6_status = RSPAMD_IPV6_SUPPORTED;
  170             }
  171             close (s);
  172         }
  173     }
  174 }
  175 
  176 gboolean
  177 rspamd_ip_is_valid (const rspamd_inet_addr_t *addr)
  178 {
  179     const struct in_addr ip4_any = { INADDR_ANY }, ip4_none = { INADDR_NONE };
  180     const struct in6_addr ip6_any = IN6ADDR_ANY_INIT;
  181     gboolean ret = FALSE;
  182 
  183     if (G_LIKELY (addr->af == AF_INET)) {
  184         if (memcmp (&addr->u.in.addr.s4.sin_addr, &ip4_any,
  185             sizeof (struct in_addr)) != 0 &&
  186             memcmp (&addr->u.in.addr.s4.sin_addr, &ip4_none,
  187             sizeof (struct in_addr)) != 0) {
  188             ret = TRUE;
  189         }
  190     }
  191     else if (G_UNLIKELY (addr->af == AF_INET6)) {
  192         if (memcmp (&addr->u.in.addr.s6.sin6_addr, &ip6_any,
  193             sizeof (struct in6_addr)) != 0) {
  194             ret = TRUE;
  195         }
  196     }
  197 
  198     return ret;
  199 }
  200 
  201 static void
  202 rspamd_enable_accept_event (gint fd, short what, gpointer d)
  203 {
  204     struct event *events = d;
  205 
  206     event_del (&events[1]);
  207     event_add (&events[0], NULL);
  208 }
  209 
  210 static void
  211 rspamd_disable_accept_events (gint sock, GList *accept_events)
  212 {
  213     GList *cur;
  214     struct event *events;
  215     const gdouble throttling = 0.5;
  216     struct timeval tv;
  217     struct event_base *ev_base;
  218 
  219     double_to_tv (throttling, &tv);
  220 
  221     for (cur = accept_events; cur != NULL; cur = g_list_next (cur)) {
  222         events = cur->data;
  223 
  224         ev_base = event_get_base (&events[0]);
  225         event_del (&events[0]);
  226         event_set (&events[1], sock, EV_TIMEOUT, rspamd_enable_accept_event,
  227                 events);
  228         event_base_set (ev_base, &events[1]);
  229         event_add (&events[1], &tv);
  230     }
  231 }
  232 
  233 gint
  234 rspamd_accept_from_socket (gint sock, rspamd_inet_addr_t **target,
  235         GList *accept_events)
  236 {
  237     gint nfd, serrno;
  238     union sa_union su;
  239     socklen_t len = sizeof (su);
  240     rspamd_inet_addr_t *addr = NULL;
  241 
  242     if ((nfd = accept (sock, &su.sa, &len)) == -1) {
  243         if (target) {
  244             *target = NULL;
  245         }
  246 
  247         if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK) {
  248             return 0;
  249         }
  250         else if (errno == EMFILE || errno == ENFILE) {
  251             /* Temporary disable accept event */
  252             rspamd_disable_accept_events (sock, accept_events);
  253 
  254             return 0;
  255         }
  256 
  257         return -1;
  258     }
  259 
  260     if (su.sa.sa_family == AF_INET6) {
  261         /* Deal with bloody v4 mapped to v6 addresses */
  262 
  263         static const guint8 mask[] = {
  264                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  265         };
  266         const guint8 *p;
  267 
  268         if (memcmp ((const guint8 *)&su.s6.sin6_addr, mask, sizeof (mask)) == 0) {
  269             p = (const guint8 *)&su.s6.sin6_addr;
  270 
  271             if ((p[10] == 0xff && p[11] == 0xff)) {
  272                 addr = rspamd_inet_addr_create (AF_INET);
  273                 memcpy (&addr->u.in.addr.s4.sin_addr, &p[12],
  274                         sizeof (struct in_addr));
  275             }
  276             else {
  277                 /* Something strange but not mapped v4 address */
  278                 addr = rspamd_inet_addr_create (AF_INET6);
  279                 memcpy (&addr->u.in.addr.s6.sin6_addr, &su.s6.sin6_addr,
  280                         sizeof (struct in6_addr));
  281             }
  282         }
  283         else {
  284             addr = rspamd_inet_addr_create (AF_INET6);
  285             memcpy (&addr->u.in.addr.s6.sin6_addr, &su.s6.sin6_addr,
  286                     sizeof (struct in6_addr));
  287         }
  288 
  289     }
  290     else {
  291         addr = rspamd_inet_addr_create (su.sa.sa_family);
  292         addr->slen = len;
  293 
  294         if (addr->af == AF_UNIX) {
  295             len = sizeof (su);
  296 
  297             if (getsockname (sock, &su.sa, &len) != -1) {
  298                 memcpy (&addr->u.un->addr, &su.su, MIN (len,
  299                         sizeof (struct sockaddr_un)));
  300             }
  301             else {
  302                 /* Just copy socket address */
  303                 memcpy (&addr->u.un->addr, &su.sa, sizeof (struct sockaddr));
  304             }
  305         }
  306         else {
  307             memcpy (&addr->u.in.addr, &su, MIN (len, sizeof (addr->u.in.addr)));
  308         }
  309     }
  310 
  311     if (rspamd_socket_nonblocking (nfd) < 0) {
  312         goto out;
  313     }
  314 
  315     /* Set close on exec */
  316     if (fcntl (nfd, F_SETFD, FD_CLOEXEC) == -1) {
  317         msg_warn ("fcntl failed: %d, '%s'", errno, strerror (errno));
  318         goto out;
  319     }
  320 
  321     if (target) {
  322         *target = addr;
  323     }
  324     else {
  325         /* Avoid leak */
  326         rspamd_inet_address_free (addr);
  327     }
  328 
  329     return (nfd);
  330 
  331 out:
  332     serrno = errno;
  333     close (nfd);
  334     errno = serrno;
  335     rspamd_inet_address_free (addr);
  336 
  337     return (-1);
  338 
  339 }
  340 
  341 static gboolean
  342 rspamd_parse_unix_path (rspamd_inet_addr_t **target, const char *src)
  343 {
  344     gchar **tokens, **cur_tok, *p, *pwbuf;
  345     glong pwlen;
  346     struct passwd pw, *ppw;
  347     struct group gr, *pgr;
  348     rspamd_inet_addr_t *addr;
  349     bool has_group = false;
  350 
  351     tokens = g_strsplit_set (src, " ,", -1);
  352     addr = rspamd_inet_addr_create (AF_UNIX);
  353 
  354     rspamd_strlcpy (addr->u.un->addr.sun_path, tokens[0],
  355             sizeof (addr->u.un->addr.sun_path));
  356     #if defined(FREEBSD) || defined(__APPLE__)
  357     addr->u.un->addr.sun_len = SUN_LEN (&addr->u.un->addr);
  358     #endif
  359 
  360     addr->u.un->mode = 00644;
  361     addr->u.un->owner = (uid_t)-1;
  362     addr->u.un->group = (gid_t)-1;
  363 
  364     cur_tok = &tokens[1];
  365 #ifdef _SC_GETPW_R_SIZE_MAX
  366     pwlen = sysconf (_SC_GETPW_R_SIZE_MAX);
  367     if (pwlen <= 0) {
  368         pwlen = 8192;
  369     }
  370 #else
  371     pwlen = 8192;
  372 #endif
  373 
  374     pwbuf = g_malloc0 (pwlen);
  375 
  376     while (*cur_tok) {
  377         if (g_ascii_strncasecmp (*cur_tok, "mode=", sizeof ("mode=") - 1) == 0) {
  378             p = strchr (*cur_tok, '=');
  379             /* XXX: add error check */
  380             addr->u.un->mode = strtoul (p + 1, NULL, 0);
  381 
  382             if (addr->u.un->mode == 0) {
  383                 msg_err ("bad mode: %s", p + 1);
  384                 errno = EINVAL;
  385                 goto err;
  386             }
  387         }
  388         else if (g_ascii_strncasecmp (*cur_tok, "owner=",
  389                 sizeof ("owner=") - 1) == 0) {
  390             p = strchr (*cur_tok, '=');
  391 
  392             if (getpwnam_r (p + 1, &pw, pwbuf, pwlen, &ppw) != 0 || ppw == NULL) {
  393                 msg_err ("bad user: %s", p + 1);
  394                 if (ppw == NULL) {
  395                     errno = ENOENT;
  396                 }
  397                 goto err;
  398             }
  399             addr->u.un->owner = pw.pw_uid;
  400 
  401             if (!has_group) {
  402                 addr->u.un->group = pw.pw_gid;
  403             }
  404         }
  405         else if (g_ascii_strncasecmp (*cur_tok, "group=",
  406                 sizeof ("group=") - 1) == 0) {
  407             p = strchr (*cur_tok, '=');
  408 
  409             if (getgrnam_r (p + 1, &gr, pwbuf, pwlen, &pgr) != 0 || pgr == NULL) {
  410                 msg_err ("bad group: %s", p + 1);
  411                 if (pgr == NULL) {
  412                     errno = ENOENT;
  413                 }
  414                 goto err;
  415             }
  416 
  417             has_group = true;
  418             addr->u.un->group = gr.gr_gid;
  419         }
  420         cur_tok ++;
  421     }
  422 
  423     g_free (pwbuf);
  424     g_strfreev (tokens);
  425 
  426     if (target) {
  427         rspamd_ip_validate_af (addr);
  428         *target = addr;
  429     }
  430     else {
  431         rspamd_inet_address_free (addr);
  432     }
  433 
  434     return TRUE;
  435 
  436 err:
  437 
  438     g_strfreev (tokens);
  439     g_free (pwbuf);
  440     rspamd_inet_address_free (addr);
  441     return FALSE;
  442 }
  443 
  444 gboolean
  445 rspamd_parse_inet_address_ip4 (const guchar *text, gsize len, gpointer target)
  446 {
  447     const guchar *p;
  448     guchar c;
  449     guint32 addr = 0, *addrptr = target;
  450     guint octet = 0, n = 0;
  451 
  452     g_assert (text != NULL);
  453     g_assert (target != NULL);
  454 
  455     if (len == 0) {
  456         len = strlen (text);
  457     }
  458 
  459     for (p = text; p < text + len; p++) {
  460         c = *p;
  461 
  462         if (c >= '0' && c <= '9') {
  463             octet = octet * 10 + (c - '0');
  464 
  465             if (octet > 255) {
  466                 return FALSE;
  467             }
  468 
  469             continue;
  470         }
  471 
  472         if (c == '.') {
  473             addr = (addr << 8) + octet;
  474             octet = 0;
  475             n++;
  476             continue;
  477         }
  478 
  479         return FALSE;
  480     }
  481 
  482     if (n == 3) {
  483         addr = (addr << 8) + octet;
  484         *addrptr = ntohl (addr);
  485 
  486         return TRUE;
  487     }
  488 
  489     return FALSE;
  490 }
  491 
  492 gboolean
  493 rspamd_parse_inet_address_ip6 (const guchar *text, gsize len, gpointer target)
  494 {
  495     guchar t, *zero = NULL, *s, *d,  *addr = target;
  496     const guchar *p, *digit = NULL;
  497     gsize len4 = 0;
  498     guint n = 8, nibbles = 0, word = 0;
  499 
  500     g_assert (text != NULL);
  501     g_assert (target != NULL);
  502 
  503     if (len == 0) {
  504         len = strlen (text);
  505     }
  506 
  507     /* Ignore trailing semicolon */
  508     if (text[0] == ':') {
  509         p = text + 1;
  510         len--;
  511     }
  512     else {
  513         p = text;
  514     }
  515 
  516     for (/* void */; len; len--) {
  517         t = *p++;
  518 
  519         if (t == ':') {
  520             if (nibbles) {
  521                 digit = p;
  522                 len4 = len;
  523                 *addr++ = (u_char) (word >> 8);
  524                 *addr++ = (u_char) (word & 0xff);
  525 
  526                 if (--n) {
  527                     nibbles = 0;
  528                     word = 0;
  529                     continue;
  530                 }
  531             } else {
  532                 if (zero == NULL) {
  533                     digit = p;
  534                     len4 = len;
  535                     zero = addr;
  536                     continue;
  537                 }
  538             }
  539 
  540             return FALSE;
  541         }
  542 
  543         if (t == '.' && nibbles) {
  544             if (n < 2 || digit == NULL) {
  545                 return FALSE;
  546             }
  547 
  548             /* IPv4 encoded in IPv6 */
  549             if (!rspamd_parse_inet_address_ip4 (digit, len4 - 1, &word)) {
  550                 return FALSE;
  551             }
  552 
  553             word = ntohl (word);
  554             *addr++ = (guchar) ((word >> 24) & 0xff);
  555             *addr++ = (guchar) ((word >> 16) & 0xff);
  556             n--;
  557             break;
  558         }
  559 
  560         if (++nibbles > 4) {
  561             /* Too many dots */
  562             return FALSE;
  563         }
  564 
  565         /* Restore from hex */
  566         if (t >= '0' && t <= '9') {
  567             word = word * 16 + (t - '0');
  568             continue;
  569         }
  570 
  571         t |= 0x20;
  572 
  573         if (t >= 'a' && t <= 'f') {
  574             word = word * 16 + (t - 'a') + 10;
  575             continue;
  576         }
  577 
  578         return FALSE;
  579     }
  580 
  581     if (nibbles == 0 && zero == NULL) {
  582         return FALSE;
  583     }
  584 
  585     *addr++ = (guchar) (word >> 8);
  586     *addr++ = (guchar) (word & 0xff);
  587 
  588     if (--n) {
  589         if (zero) {
  590             n *= 2;
  591             s = addr - 1;
  592             d = s + n;
  593             while (s >= zero) {
  594                 *d-- = *s--;
  595             }
  596             memset (zero, 0, n);
  597 
  598             return TRUE;
  599         }
  600 
  601     } else {
  602         if (zero == NULL) {
  603             return TRUE;
  604         }
  605     }
  606 
  607     return FALSE;
  608 }
  609 
  610 /* Checks for ipv6 mapped address */
  611 static rspamd_inet_addr_t *
  612 rspamd_inet_address_v6_maybe_map (const struct sockaddr_in6 *sin6)
  613 {
  614     rspamd_inet_addr_t *addr = NULL;
  615     /* 10 zero bytes or 80 bits */
  616     static const guint8 mask[] = {
  617         0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  618     };
  619     const guint8 *p;
  620 
  621     if (memcmp ((const guint8 *)&sin6->sin6_addr, mask, sizeof (mask)) == 0) {
  622         p = (const guint8 *)&sin6->sin6_addr;
  623 
  624         if ((p[10] == 0xff && p[11] == 0xff)) {
  625             addr = rspamd_inet_addr_create (AF_INET);
  626             memcpy (&addr->u.in.addr.s4.sin_addr, &p[12],
  627                     sizeof (struct in_addr));
  628         }
  629         else {
  630             /* Something strange but not mapped v4 address */
  631             addr = rspamd_inet_addr_create (AF_INET6);
  632             memcpy (&addr->u.in.addr.s6.sin6_addr, &sin6->sin6_addr,
  633                     sizeof (struct in6_addr));
  634         }
  635     }
  636     else {
  637         addr = rspamd_inet_addr_create (AF_INET6);
  638         memcpy (&addr->u.in.addr.s6.sin6_addr, &sin6->sin6_addr,
  639                 sizeof (struct in6_addr));
  640     }
  641 
  642     return addr;
  643 }
  644 
  645 static void
  646 rspamd_inet_address_v6_maybe_map_static (const struct sockaddr_in6 *sin6,
  647         rspamd_inet_addr_t *addr)
  648 {
  649     /* 10 zero bytes or 80 bits */
  650     static const guint8 mask[] = {
  651         0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  652     };
  653     const guint8 *p;
  654 
  655     if (memcmp ((const guint8 *)&sin6->sin6_addr, mask, sizeof (mask)) == 0) {
  656         p = (const guint8 *)&sin6->sin6_addr;
  657 
  658         if ((p[10] == 0xff && p[11] == 0xff)) {
  659             memcpy (&addr->u.in.addr.s4.sin_addr, &p[12],
  660                     sizeof (struct in_addr));
  661             addr->af = AF_INET;
  662             addr->slen = sizeof (addr->u.in.addr.s4);
  663         }
  664         else {
  665             /* Something strange but not mapped v4 address */
  666             memcpy (&addr->u.in.addr.s6.sin6_addr, &sin6->sin6_addr,
  667                     sizeof (struct in6_addr));
  668             addr->af = AF_INET6;
  669             addr->slen = sizeof (addr->u.in.addr.s6);
  670         }
  671     }
  672     else {
  673         memcpy (&addr->u.in.addr.s6.sin6_addr, &sin6->sin6_addr,
  674                 sizeof (struct in6_addr));
  675         addr->af = AF_INET6;
  676         addr->slen = sizeof (addr->u.in.addr.s6);
  677     }
  678 }
  679 
  680 gboolean
  681 rspamd_parse_inet_address (rspamd_inet_addr_t **target,
  682         const char *src,
  683         gsize srclen)
  684 {
  685     gboolean ret = FALSE;
  686     rspamd_inet_addr_t *addr = NULL;
  687     union sa_inet su;
  688     const char *end;
  689     char ipbuf[INET6_ADDRSTRLEN + 1];
  690     guint iplen;
  691     gulong portnum;
  692 
  693     g_assert (src != NULL);
  694     g_assert (target != NULL);
  695 
  696     if (srclen == 0) {
  697         srclen = strlen (src);
  698     }
  699 
  700     rspamd_ip_check_ipv6 ();
  701 
  702     if (src[0] == '/' || src[0] == '.') {
  703         return rspamd_parse_unix_path (target, src);
  704     }
  705 
  706     if (src[0] == '[') {
  707         /* Ipv6 address in format [::1]:port or just [::1] */
  708         end = memchr (src + 1, ']', srclen - 1);
  709 
  710         if (end == NULL) {
  711             return FALSE;
  712         }
  713 
  714         iplen = end - src - 1;
  715 
  716         if (iplen == 0 || iplen >= sizeof (ipbuf)) {
  717             return FALSE;
  718         }
  719 
  720         rspamd_strlcpy (ipbuf, src + 1, iplen + 1);
  721 
  722         if (rspamd_parse_inet_address_ip6 (ipbuf, iplen,
  723                         &su.s6.sin6_addr)) {
  724             addr = rspamd_inet_address_v6_maybe_map (&su.s6);
  725             ret = TRUE;
  726         }
  727 
  728         if (ret && end[1] == ':') {
  729             /* Port part */
  730             rspamd_strtoul (end + 1, srclen - iplen - 3, &portnum);
  731             rspamd_inet_address_set_port (addr, portnum);
  732         }
  733     }
  734     else {
  735 
  736         if ((end = memchr (src, ':', srclen)) != NULL) {
  737             /* This is either port number and ipv4 addr or ipv6 addr */
  738             /* Search for another semicolon */
  739             if (memchr (end + 1, ':', srclen - (end - src + 1)) &&
  740                     rspamd_parse_inet_address_ip6 (src, srclen, &su.s6.sin6_addr)) {
  741                 addr = rspamd_inet_address_v6_maybe_map (&su.s6);
  742                 ret = TRUE;
  743             }
  744             else {
  745                 /* Not ipv6, so try ip:port */
  746                 iplen = end - src;
  747 
  748                 if (iplen >= sizeof (ipbuf) || iplen <= 1) {
  749                     return FALSE;
  750                 }
  751                 else {
  752                     rspamd_strlcpy (ipbuf, src, iplen + 1);
  753                 }
  754 
  755                 if (rspamd_parse_inet_address_ip4 (ipbuf, iplen,
  756                         &su.s4.sin_addr)) {
  757                     addr = rspamd_inet_addr_create (AF_INET);
  758                     memcpy (&addr->u.in.addr.s4.sin_addr, &su.s4.sin_addr,
  759                             sizeof (struct in_addr));
  760                     rspamd_strtoul (end + 1, srclen - iplen - 1, &portnum);
  761                     rspamd_inet_address_set_port (addr, portnum);
  762                     ret = TRUE;
  763                 }
  764             }
  765         }
  766         else {
  767             if (rspamd_parse_inet_address_ip4 (src, srclen, &su.s4.sin_addr)) {
  768                 addr = rspamd_inet_addr_create (AF_INET);
  769                 memcpy (&addr->u.in.addr.s4.sin_addr, &su.s4.sin_addr,
  770                         sizeof (struct in_addr));
  771                 ret = TRUE;
  772             }
  773             else if (rspamd_parse_inet_address_ip6 (src, srclen, &su.s6.sin6_addr)) {
  774                 addr = rspamd_inet_address_v6_maybe_map (&su.s6);
  775                 ret = TRUE;
  776             }
  777         }
  778     }
  779 
  780     if (ret && target) {
  781         *target = addr;
  782     }
  783 
  784     return ret;
  785 }
  786 
  787 gboolean
  788 rspamd_parse_inet_address_ip (const char *src, gsize srclen,
  789         rspamd_inet_addr_t *target)
  790 {
  791     const char *end;
  792     char ipbuf[INET6_ADDRSTRLEN + 1];
  793     guint iplen;
  794     gulong portnum;
  795     gboolean ret = FALSE;
  796     union sa_inet su;
  797 
  798     g_assert (target != NULL);
  799     g_assert (src != NULL);
  800 
  801     if (src[0] == '[') {
  802         /* Ipv6 address in format [::1]:port or just [::1] */
  803         end = memchr (src + 1, ']', srclen - 1);
  804 
  805         if (end == NULL) {
  806             return FALSE;
  807         }
  808 
  809         iplen = end - src - 1;
  810 
  811         if (iplen == 0 || iplen >= sizeof (ipbuf)) {
  812             return FALSE;
  813         }
  814 
  815         rspamd_strlcpy (ipbuf, src + 1, iplen + 1);
  816 
  817         if (rspamd_parse_inet_address_ip6 (ipbuf, iplen,
  818                         &su.s6.sin6_addr)) {
  819             rspamd_inet_address_v6_maybe_map_static (&su.s6, target);
  820             ret = TRUE;
  821         }
  822 
  823         if (ret && end[1] == ':') {
  824             /* Port part */
  825             rspamd_strtoul (end + 1, srclen - iplen - 3, &portnum);
  826             rspamd_inet_address_set_port (target, portnum);
  827         }
  828     }
  829     else {
  830 
  831         if ((end = memchr (src, ':', srclen)) != NULL) {
  832             /* This is either port number and ipv4 addr or ipv6 addr */
  833             /* Search for another semicolon */
  834             if (memchr (end + 1, ':', srclen - (end - src + 1)) &&
  835                     rspamd_parse_inet_address_ip6 (src, srclen, &su.s6.sin6_addr)) {
  836                 rspamd_inet_address_v6_maybe_map_static (&su.s6, target);
  837                 ret = TRUE;
  838             }
  839             else {
  840                 /* Not ipv6, so try ip:port */
  841                 iplen = end - src;
  842 
  843                 if (iplen >= sizeof (ipbuf) || iplen <= 1) {
  844                     return FALSE;
  845                 }
  846                 else {
  847                     rspamd_strlcpy (ipbuf, src, iplen + 1);
  848                 }
  849 
  850                 if (rspamd_parse_inet_address_ip4 (ipbuf, iplen,
  851                         &su.s4.sin_addr)) {
  852                     memcpy (&target->u.in.addr.s4.sin_addr, &su.s4.sin_addr,
  853                             sizeof (struct in_addr));
  854                     target->af = AF_INET;
  855                     target->slen = sizeof (target->u.in.addr.s4);
  856                     rspamd_strtoul (end + 1, srclen - iplen - 1, &portnum);
  857                     rspamd_inet_address_set_port (target, portnum);
  858                     ret = TRUE;
  859                 }
  860             }
  861         }
  862         else {
  863             if (rspamd_parse_inet_address_ip4 (src, srclen, &su.s4.sin_addr)) {
  864                 memcpy (&target->u.in.addr.s4.sin_addr, &su.s4.sin_addr,
  865                         sizeof (struct in_addr));
  866                 target->af = AF_INET;
  867                 target->slen = sizeof (target->u.in.addr.s4);
  868                 ret = TRUE;
  869             }
  870             else if (rspamd_parse_inet_address_ip6 (src, srclen,
  871                     &su.s6.sin6_addr)) {
  872                 rspamd_inet_address_v6_maybe_map_static (&su.s6, target);
  873                 ret = TRUE;
  874             }
  875         }
  876     }
  877 
  878     return ret;
  879 }
  880 
  881 const char *
  882 rspamd_inet_address_to_string (const rspamd_inet_addr_t *addr)
  883 {
  884     static char addr_str[INET6_ADDRSTRLEN + 1];
  885 
  886     if (addr == NULL) {
  887         return "<empty inet address>";
  888     }
  889 
  890     switch (addr->af) {
  891     case AF_INET:
  892         return inet_ntop (addr->af, &addr->u.in.addr.s4.sin_addr, addr_str,
  893                    sizeof (addr_str));
  894     case AF_INET6:
  895         return inet_ntop (addr->af, &addr->u.in.addr.s6.sin6_addr, addr_str,
  896                    sizeof (addr_str));
  897     case AF_UNIX:
  898         return addr->u.un->addr.sun_path;
  899     }
  900 
  901     return "undefined";
  902 }
  903 
  904 const char *
  905 rspamd_inet_address_to_string_pretty (const rspamd_inet_addr_t *addr)
  906 {
  907     static char addr_str[PATH_MAX + 5];
  908 
  909     if (addr == NULL) {
  910         return "<empty inet address>";
  911     }
  912 
  913     switch (addr->af) {
  914     case AF_INET:
  915         rspamd_snprintf (addr_str, sizeof (addr_str), "%s:%d",
  916                 rspamd_inet_address_to_string (addr),
  917                 rspamd_inet_address_get_port (addr));
  918         break;
  919     case AF_INET6:
  920         rspamd_snprintf (addr_str, sizeof (addr_str), "[%s]:%d",
  921                 rspamd_inet_address_to_string (addr),
  922                 rspamd_inet_address_get_port (addr));
  923         break;
  924     case AF_UNIX:
  925         rspamd_snprintf (addr_str, sizeof (addr_str), "unix:%s",
  926                 rspamd_inet_address_to_string (addr));
  927         break;
  928     }
  929 
  930     return addr_str;
  931 }
  932 
  933 uint16_t
  934 rspamd_inet_address_get_port (const rspamd_inet_addr_t *addr)
  935 {
  936     switch (addr->af) {
  937     case AF_INET:
  938         return ntohs (addr->u.in.addr.s4.sin_port);
  939     case AF_INET6:
  940         return ntohs (addr->u.in.addr.s6.sin6_port);
  941     }
  942 
  943     return 0;
  944 }
  945 
  946 void
  947 rspamd_inet_address_set_port (rspamd_inet_addr_t *addr, uint16_t port)
  948 {
  949     switch (addr->af) {
  950     case AF_INET:
  951         addr->u.in.addr.s4.sin_port = htons (port);
  952         break;
  953     case AF_INET6:
  954         addr->u.in.addr.s6.sin6_port = htons (port);
  955         break;
  956     }
  957 }
  958 
  959 int
  960 rspamd_inet_address_connect (const rspamd_inet_addr_t *addr, gint type,
  961         gboolean async)
  962 {
  963     int fd, r;
  964     const struct sockaddr *sa;
  965 
  966     if (addr == NULL) {
  967         return -1;
  968     }
  969 
  970     fd = rspamd_socket_create (addr->af, type, 0, async);
  971     if (fd == -1) {
  972         return -1;
  973     }
  974 
  975     if (addr->af == AF_UNIX) {
  976         sa = (const struct sockaddr *)&addr->u.un->addr;
  977     }
  978     else {
  979         sa = &addr->u.in.addr.sa;
  980     }
  981 
  982     r = connect (fd, sa, addr->slen);
  983 
  984     if (r == -1) {
  985         if (!async || errno != EINPROGRESS) {
  986             close (fd);
  987             msg_warn ("connect %s failed: %d, '%s'",
  988                     rspamd_inet_address_to_string_pretty (addr),
  989                     errno, strerror (errno));
  990             return -1;
  991         }
  992     }
  993 
  994     return fd;
  995 }
  996 
  997 int
  998 rspamd_inet_address_listen (const rspamd_inet_addr_t *addr, gint type,
  999         gboolean async)
 1000 {
 1001     gint fd, r;
 1002     gint on = 1;
 1003     const struct sockaddr *sa;
 1004     const char *path;
 1005 
 1006     if (addr == NULL) {
 1007         return -1;
 1008     }
 1009 
 1010     fd = rspamd_socket_create (addr->af, type, 0, async);
 1011     if (fd == -1) {
 1012         return -1;
 1013     }
 1014 
 1015     if (addr->af == AF_UNIX && access (addr->u.un->addr.sun_path, W_OK) != -1) {
 1016         /* Unlink old socket */
 1017         (void)unlink (addr->u.un->addr.sun_path);
 1018     }
 1019 
 1020     if (addr->af == AF_UNIX) {
 1021         sa = (const struct sockaddr *)&addr->u.un->addr;
 1022     }
 1023     else {
 1024         sa = &addr->u.in.addr.sa;
 1025     }
 1026 
 1027     (void)setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof (gint));
 1028 
 1029 #ifdef HAVE_IPV6_V6ONLY
 1030     if (addr->af == AF_INET6) {
 1031         /* We need to set this flag to avoid errors */
 1032         on = 1;
 1033 #ifdef SOL_IPV6
 1034         (void)setsockopt (fd, SOL_IPV6, IPV6_V6ONLY, (const void *)&on, sizeof (gint));
 1035 #elif defined(IPPROTO_IPV6)
 1036         (void)setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, (const void *)&on, sizeof (gint));
 1037 #endif
 1038     }
 1039 #endif
 1040 
 1041     r = bind (fd, sa, addr->slen);
 1042     if (r == -1) {
 1043         if (!async || errno != EINPROGRESS) {
 1044             close (fd);
 1045             msg_warn ("bind %s failed: %d, '%s'",
 1046                     rspamd_inet_address_to_string_pretty (addr),
 1047                     errno,
 1048                     strerror (errno));
 1049             return -1;
 1050         }
 1051     }
 1052 
 1053     if (type != SOCK_DGRAM) {
 1054 
 1055         if (addr->af == AF_UNIX) {
 1056             path = addr->u.un->addr.sun_path;
 1057             /* Try to set mode and owner */
 1058 
 1059             if (addr->u.un->owner != (uid_t)-1 || addr->u.un->group != (gid_t)-1) {
 1060                 if (chown (path, addr->u.un->owner, addr->u.un->group) == -1) {
 1061                     msg_info ("cannot change owner for %s to %d:%d: %s",
 1062                             path, addr->u.un->owner, addr->u.un->group,
 1063                             strerror (errno));
 1064                 }
 1065             }
 1066 
 1067             if (chmod (path, addr->u.un->mode) == -1) {
 1068                 msg_info ("cannot change mode for %s to %od %s",
 1069                         path, addr->u.un->mode, strerror (errno));
 1070             }
 1071         }
 1072         r = listen (fd, -1);
 1073 
 1074         if (r == -1) {
 1075             msg_warn ("listen %s failed: %d, '%s'",
 1076                     rspamd_inet_address_to_string_pretty (addr),
 1077                     errno, strerror (errno));
 1078             close (fd);
 1079             return -1;
 1080         }
 1081     }
 1082 
 1083     return fd;
 1084 }
 1085 
 1086 gssize
 1087 rspamd_inet_address_recvfrom (gint fd, void *buf, gsize len, gint fl,
 1088         rspamd_inet_addr_t **target)
 1089 {
 1090     gssize ret;
 1091     union sa_union su;
 1092     socklen_t slen = sizeof (su);
 1093     rspamd_inet_addr_t *addr = NULL;
 1094 
 1095     if ((ret = recvfrom (fd, buf, len, fl, &su.sa, &slen)) == -1) {
 1096         if (target) {
 1097             *target = NULL;
 1098         }
 1099 
 1100         return -1;
 1101     }
 1102 
 1103     if (target) {
 1104         addr = rspamd_inet_addr_create (su.sa.sa_family);
 1105         addr->slen = slen;
 1106 
 1107         if (addr->af == AF_UNIX) {
 1108             addr->u.un = g_malloc (sizeof (*addr->u.un));
 1109             memcpy (&addr->u.un->addr, &su.su, sizeof (struct sockaddr_un));
 1110         }
 1111         else {
 1112             memcpy (&addr->u.in.addr, &su.sa, MIN (slen, sizeof (addr->u.in.addr)));
 1113         }
 1114 
 1115         *target = addr;
 1116     }
 1117 
 1118     return (ret);
 1119 }
 1120 
 1121 gssize
 1122 rspamd_inet_address_sendto (gint fd, const void *buf, gsize len, gint fl,
 1123         const rspamd_inet_addr_t *addr)
 1124 {
 1125     gssize r;
 1126     const struct sockaddr *sa;
 1127 
 1128     if (addr == NULL) {
 1129         return -1;
 1130     }
 1131 
 1132     if (addr->af == AF_UNIX) {
 1133         sa = (struct sockaddr *)&addr->u.un->addr;
 1134     }
 1135     else {
 1136         sa = &addr->u.in.addr.sa;
 1137     }
 1138 
 1139     r = sendto (fd, buf, len, fl, sa, addr->slen);
 1140 
 1141     return r;
 1142 }
 1143 
 1144 static gboolean
 1145 rspamd_check_port_priority (const char *line, guint default_port,
 1146         guint *priority, gchar *out,
 1147         gsize outlen, rspamd_mempool_t *pool)
 1148 {
 1149     guint real_port = default_port, real_priority = 0;
 1150     gchar *err_str, *err_str_prio;
 1151 
 1152     if (line && line[0] == ':') {
 1153         errno = 0;
 1154         real_port = strtoul (line + 1, &err_str, 10);
 1155 
 1156         if (err_str && *err_str == ':') {
 1157             /* We have priority */
 1158             real_priority = strtoul (err_str + 1, &err_str_prio, 10);
 1159 
 1160             if (err_str_prio && *err_str_prio != '\0') {
 1161                 msg_err_pool_check (
 1162                         "cannot parse priority: %s, at symbol %c, error: %s",
 1163                         line,
 1164                         *err_str_prio,
 1165                         strerror (errno));
 1166 
 1167                 return FALSE;
 1168             }
 1169         }
 1170         else if (err_str && *err_str != '\0') {
 1171             msg_err_pool_check (
 1172                     "cannot parse port: %s, at symbol %c, error: %s",
 1173                     line,
 1174                     *err_str,
 1175                     strerror (errno));
 1176 
 1177             return FALSE;
 1178         }
 1179     }
 1180 
 1181     if (priority) {
 1182         *priority = real_priority;
 1183     }
 1184 
 1185     rspamd_snprintf (out, outlen, "%ud", real_port);
 1186 
 1187     return TRUE;
 1188 }
 1189 
 1190 static gboolean
 1191 rspamd_resolve_addrs (const char *begin, size_t len, GPtrArray **addrs,
 1192         const gchar *portbuf, gint flags,
 1193         rspamd_mempool_t *pool)
 1194 {
 1195     struct addrinfo hints, *res, *cur;
 1196     rspamd_inet_addr_t *cur_addr = NULL;
 1197     gint r, addr_cnt;
 1198     gchar *addr_cpy = NULL;
 1199 
 1200     rspamd_ip_check_ipv6 ();
 1201 
 1202     if (rspamd_parse_inet_address (&cur_addr, begin, len)) {
 1203         if (*addrs == NULL) {
 1204             *addrs = g_ptr_array_new_full (1,
 1205                     (GDestroyNotify) rspamd_inet_address_free);
 1206 
 1207             if (pool != NULL) {
 1208                 rspamd_mempool_add_destructor (pool,
 1209                         rspamd_ptr_array_free_hard, *addrs);
 1210             }
 1211         }
 1212 
 1213         rspamd_inet_address_set_port (cur_addr, strtoul (portbuf, NULL, 10));
 1214         g_ptr_array_add (*addrs, cur_addr);
 1215     }
 1216     else {
 1217         memset (&hints, 0, sizeof (hints));
 1218         hints.ai_socktype = SOCK_STREAM; /* Type of the socket */
 1219         hints.ai_flags = AI_NUMERICSERV|flags;
 1220 
 1221         if (len > 0) {
 1222             if (pool) {
 1223                 addr_cpy = rspamd_mempool_alloc (pool, len + 1);
 1224             }
 1225             else {
 1226                 addr_cpy = g_malloc (len + 1);
 1227             }
 1228 
 1229             rspamd_strlcpy (addr_cpy, begin, len + 1);
 1230         }
 1231         /* Otherwise it will be NULL */
 1232 
 1233         if (ipv6_status == RSPAMD_IPV6_SUPPORTED) {
 1234             hints.ai_family = AF_UNSPEC;
 1235         }
 1236         else {
 1237             hints.ai_family = AF_INET;
 1238         }
 1239 
 1240         if ((r = getaddrinfo (addr_cpy, portbuf, &hints, &res)) == 0) {
 1241             /* Now copy up to max_addrs of addresses */
 1242             addr_cnt = 0;
 1243             cur = res;
 1244             while (cur) {
 1245                 cur = cur->ai_next;
 1246                 addr_cnt ++;
 1247             }
 1248 
 1249             if (*addrs == NULL) {
 1250                 *addrs = g_ptr_array_new_full (addr_cnt,
 1251                         (GDestroyNotify) rspamd_inet_address_free);
 1252 
 1253                 if (pool != NULL) {
 1254                     rspamd_mempool_add_destructor (pool,
 1255                             rspamd_ptr_array_free_hard, *addrs);
 1256                 }
 1257             }
 1258 
 1259             cur = res;
 1260             while (cur) {
 1261                 cur_addr = rspamd_inet_address_from_sa (cur->ai_addr,
 1262                         cur->ai_addrlen);
 1263 
 1264                 if (cur_addr != NULL) {
 1265                     g_ptr_array_add (*addrs, cur_addr);
 1266                 }
 1267                 cur = cur->ai_next;
 1268             }
 1269 
 1270             freeaddrinfo (res);
 1271         }
 1272         else if (addr_cpy) {
 1273             msg_err_pool_check ("address resolution for %s failed: %s",
 1274                     addr_cpy,
 1275                     gai_strerror (r));
 1276 
 1277             if (pool == NULL) {
 1278                 g_free (addr_cpy);
 1279             }
 1280 
 1281             return FALSE;
 1282         }
 1283         else {
 1284             /* Should never ever happen */
 1285             g_assert (0);
 1286         }
 1287     }
 1288 
 1289     return TRUE;
 1290 }
 1291 
 1292 gboolean
 1293 rspamd_parse_host_port_priority (const gchar *str,
 1294     GPtrArray **addrs,
 1295     guint *priority,
 1296     gchar **name_ptr,
 1297     guint default_port,
 1298     rspamd_mempool_t *pool)
 1299 {
 1300     gchar portbuf[8];
 1301     const gchar *p, *name = NULL;
 1302     gsize namelen;
 1303     rspamd_inet_addr_t *cur_addr = NULL;
 1304 
 1305     /*
 1306      * In this function, we can have several possibilities:
 1307      * 1) Unix socket: check for '.' or '/' at the begin of string
 1308      * 2) \[ipv6\]: check for '[' at the beginning
 1309      * 3) '*': means listening on any address
 1310      * 4) ip|host[:port[:priority]]
 1311      */
 1312 
 1313     if (str[0] == '*') {
 1314         if (!rspamd_check_port_priority (str + 1, default_port, priority,
 1315                 portbuf, sizeof (portbuf), pool)) {
 1316             return FALSE;
 1317         }
 1318 
 1319         if (!rspamd_resolve_addrs (str, 0, addrs, portbuf, AI_PASSIVE, pool)) {
 1320             return FALSE;
 1321         }
 1322 
 1323         name = "*";
 1324         namelen = 1;
 1325     }
 1326     else if (str[0] == '[') {
 1327         /* This is braced IPv6 address */
 1328         p = strchr (str, ']');
 1329 
 1330         if (p == NULL) {
 1331             msg_err_pool_check ("cannot parse address definition %s: %s",
 1332                     str,
 1333                     strerror (EINVAL));
 1334 
 1335             return FALSE;
 1336         }
 1337 
 1338         name = str + 1;
 1339         namelen = p - str - 1;
 1340 
 1341         if (!rspamd_check_port_priority (p + 1, default_port, priority, portbuf,
 1342                 sizeof (portbuf), pool)) {
 1343             return FALSE;
 1344         }
 1345 
 1346         if (!rspamd_resolve_addrs (name, namelen, addrs,
 1347                 portbuf, 0, pool)) {
 1348             return FALSE;
 1349         }
 1350     }
 1351     else if (str[0] == '/' || str[0] == '.') {
 1352         /* Special case of unix socket, as getaddrinfo cannot deal with them */
 1353         if (*addrs == NULL) {
 1354             *addrs = g_ptr_array_new_full (1,
 1355                     (GDestroyNotify) rspamd_inet_address_free);
 1356 
 1357             if (pool != NULL) {
 1358                 rspamd_mempool_add_destructor (pool,
 1359                         rspamd_ptr_array_free_hard, *addrs);
 1360             }
 1361         }
 1362 
 1363         if (!rspamd_parse_inet_address (&cur_addr, str, 0)) {
 1364             msg_err_pool_check ("cannot parse unix socket definition %s: %s",
 1365                     str,
 1366                     strerror (errno));
 1367 
 1368             return FALSE;
 1369         }
 1370 
 1371         g_ptr_array_add (*addrs, cur_addr);
 1372         name = str;
 1373         namelen = strlen (str);
 1374     }
 1375     else {
 1376         p = strchr (str, ':');
 1377 
 1378         if (p == NULL) {
 1379             /* Just address or IP */
 1380             name = str;
 1381             namelen = strlen (str);
 1382             rspamd_check_port_priority ("", default_port, priority, portbuf,
 1383                     sizeof (portbuf), pool);
 1384 
 1385             if (!rspamd_resolve_addrs (name, namelen, addrs,
 1386                     portbuf, 0, pool)) {
 1387                 return FALSE;
 1388             }
 1389         }
 1390         else {
 1391             name = str;
 1392             namelen = p - str;
 1393 
 1394             if (!rspamd_check_port_priority (p, default_port, priority, portbuf,
 1395                     sizeof (portbuf), pool)) {
 1396                 return FALSE;
 1397             }
 1398 
 1399             if (!rspamd_resolve_addrs (str, p - str, addrs,
 1400                     portbuf, 0, pool)) {
 1401                 return FALSE;
 1402             }
 1403         }
 1404     }
 1405 
 1406     if (name_ptr != NULL) {
 1407         if (pool) {
 1408             *name_ptr = rspamd_mempool_alloc (pool, namelen + 1);
 1409         }
 1410         else {
 1411             *name_ptr = g_malloc (namelen + 1);
 1412         }
 1413 
 1414         rspamd_strlcpy (*name_ptr, name, namelen + 1);
 1415     }
 1416 
 1417     return TRUE;
 1418 }
 1419 
 1420 guchar*
 1421 rspamd_inet_address_get_hash_key (const rspamd_inet_addr_t *addr, guint *klen)
 1422 {
 1423     guchar *res = NULL;
 1424     static struct in_addr local = {INADDR_LOOPBACK};
 1425 
 1426     g_assert (addr != NULL);
 1427     g_assert (klen != NULL);
 1428 
 1429     if (addr->af == AF_INET) {
 1430         *klen = sizeof (struct in_addr);
 1431         res = (guchar *)&addr->u.in.addr.s4.sin_addr;
 1432     }
 1433     else if (addr->af == AF_INET6) {
 1434         *klen = sizeof (struct in6_addr);
 1435         res = (guchar *)&addr->u.in.addr.s6.sin6_addr;
 1436     }
 1437     else if (addr->af == AF_UNIX) {
 1438         *klen = sizeof (struct in_addr);
 1439         res = (guchar *)&local;
 1440     }
 1441     else {
 1442         *klen = 0;
 1443         res = NULL;
 1444     }
 1445 
 1446     return res;
 1447 }
 1448 
 1449 
 1450 rspamd_inet_addr_t *
 1451 rspamd_inet_address_new (int af, const void *init)
 1452 {
 1453     rspamd_inet_addr_t *addr;
 1454 
 1455     addr = rspamd_inet_addr_create (af);
 1456 
 1457     if (init != NULL) {
 1458         if (af == AF_UNIX) {
 1459             /* Init is a path */
 1460             rspamd_strlcpy (addr->u.un->addr.sun_path, init,
 1461                     sizeof (addr->u.un->addr.sun_path));
 1462 #if defined(FREEBSD) || defined(__APPLE__)
 1463             addr->u.un->addr.sun_len = SUN_LEN (&addr->u.un->addr);
 1464 #endif
 1465         }
 1466         else if (af == AF_INET) {
 1467             memcpy (&addr->u.in.addr.s4.sin_addr, init, sizeof (struct in_addr));
 1468         }
 1469         else if (af == AF_INET6) {
 1470             memcpy (&addr->u.in.addr.s6.sin6_addr, init, sizeof (struct in6_addr));
 1471         }
 1472     }
 1473 
 1474     return addr;
 1475 }
 1476 
 1477 rspamd_inet_addr_t *
 1478 rspamd_inet_address_from_sa (const struct sockaddr *sa, socklen_t slen)
 1479 {
 1480     rspamd_inet_addr_t *addr;
 1481 
 1482     g_assert (sa != NULL);
 1483     g_assert (slen >= sizeof (struct sockaddr));
 1484 
 1485     addr = rspamd_inet_addr_create (sa->sa_family);
 1486 
 1487     if (sa->sa_family == AF_UNIX) {
 1488         /* Init is a path */
 1489         const struct sockaddr_un *un = (const struct sockaddr_un *)sa;
 1490 
 1491         g_assert (slen >= SUN_LEN (un));
 1492 
 1493         rspamd_strlcpy (addr->u.un->addr.sun_path, un->sun_path,
 1494                 sizeof (addr->u.un->addr.sun_path));
 1495 #if defined(FREEBSD) || defined(__APPLE__)
 1496         addr->u.un->addr.sun_len = un->sun_len;
 1497 #endif
 1498     }
 1499     else if (sa->sa_family == AF_INET) {
 1500         g_assert (slen >= sizeof (struct sockaddr_in));
 1501         memcpy (&addr->u.in.addr.s4, sa, sizeof (struct sockaddr_in));
 1502     }
 1503     else if (sa->sa_family == AF_INET6) {
 1504         g_assert (slen >= sizeof (struct sockaddr_in6));
 1505         memcpy (&addr->u.in.addr.s6, sa, sizeof (struct sockaddr_in6));
 1506     }
 1507     else {
 1508         /* XXX: currently we cannot deal with other AF */
 1509         g_assert (0);
 1510     }
 1511 
 1512     return addr;
 1513 }
 1514 
 1515 rspamd_inet_addr_t *
 1516 rspamd_inet_address_from_rnds (const struct rdns_reply_entry *rep)
 1517 {
 1518     rspamd_inet_addr_t *addr = NULL;
 1519 
 1520     g_assert (rep != NULL);
 1521 
 1522     if (rep->type == RDNS_REQUEST_A) {
 1523         addr = rspamd_inet_addr_create (AF_INET);
 1524         memcpy (&addr->u.in.addr.s4.sin_addr, &rep->content.a.addr,
 1525                 sizeof (struct in_addr));
 1526     }
 1527     else if (rep->type == RDNS_REQUEST_AAAA) {
 1528         addr = rspamd_inet_addr_create (AF_INET6);
 1529         memcpy (&addr->u.in.addr.s6.sin6_addr, &rep->content.aaa.addr,
 1530                         sizeof (struct in6_addr));
 1531     }
 1532 
 1533     return addr;
 1534 }
 1535 
 1536 void
 1537 rspamd_inet_address_apply_mask (rspamd_inet_addr_t *addr, guint mask)
 1538 {
 1539     guint32 umsk, *p;
 1540 
 1541     if (mask > 0 && addr != NULL) {
 1542         if (addr->af == AF_INET && mask <= 32) {
 1543             umsk = htonl (G_MAXUINT32 << (32 - mask));
 1544             addr->u.in.addr.s4.sin_addr.s_addr &= umsk;
 1545         }
 1546         else if (addr->af == AF_INET6 && mask <= 128) {
 1547             p = (uint32_t *)&addr->u.in.addr.s6.sin6_addr;
 1548             mask = 128 - mask;
 1549             p += 3;
 1550 
 1551             for (;;) {
 1552                 if (mask >= 32) {
 1553                     mask -= 32;
 1554                     *p = 0;
 1555                 }
 1556                 else {
 1557                     umsk = htonl (G_MAXUINT32 << mask);
 1558                     *p &= umsk;
 1559                     break;
 1560                 }
 1561 
 1562                 p --;
 1563             }
 1564         }
 1565     }
 1566 }
 1567 
 1568 static gint
 1569 rspamd_inet_address_af_order (const rspamd_inet_addr_t *addr)
 1570 {
 1571     int ret;
 1572 
 1573     switch (addr->af) {
 1574     case AF_UNIX:
 1575         ret = 2;
 1576         break;
 1577     case AF_INET:
 1578         ret = 1;
 1579         break;
 1580     default:
 1581         ret = 0;
 1582         break;
 1583     }
 1584 
 1585     return ret;
 1586 }
 1587 
 1588 gint
 1589 rspamd_inet_address_compare (const rspamd_inet_addr_t *a1,
 1590         const rspamd_inet_addr_t *a2)
 1591 {
 1592     g_assert (a1 != NULL);
 1593     g_assert (a2 != NULL);
 1594 
 1595     if (a1->af != a2->af) {
 1596         return (rspamd_inet_address_af_order (a2) -
 1597                 rspamd_inet_address_af_order (a1));
 1598     }
 1599     else {
 1600         switch (a1->af) {
 1601         case AF_INET:
 1602             return memcmp (&a1->u.in.addr.s4.sin_addr,
 1603                     &a2->u.in.addr.s4.sin_addr, sizeof (struct in_addr));
 1604         case AF_INET6:
 1605             return memcmp (&a1->u.in.addr.s6.sin6_addr,
 1606                 &a2->u.in.addr.s6.sin6_addr, sizeof (struct in6_addr));
 1607         case AF_UNIX:
 1608             return strncmp (a1->u.un->addr.sun_path,
 1609                 a2->u.un->addr.sun_path, sizeof (a1->u.un->addr.sun_path));
 1610         default:
 1611             return memcmp (&a1->u.in, &a2->u.in, sizeof (a1->u.in));
 1612         }
 1613     }
 1614 
 1615     return 0;
 1616 }
 1617 
 1618 gint
 1619 rspamd_inet_address_compare_ptr (gconstpointer a1,
 1620         gconstpointer a2)
 1621 {
 1622     const rspamd_inet_addr_t **i1 = (const rspamd_inet_addr_t **)a1,
 1623             **i2 = (const rspamd_inet_addr_t **)a2;
 1624 
 1625     return rspamd_inet_address_compare (*i1, *i2);
 1626 }
 1627 
 1628 rspamd_inet_addr_t *
 1629 rspamd_inet_address_copy (const rspamd_inet_addr_t *addr)
 1630 {
 1631     rspamd_inet_addr_t *n;
 1632 
 1633     if (addr == NULL) {
 1634         return NULL;
 1635     }
 1636 
 1637     n = rspamd_inet_addr_create (addr->af);
 1638 
 1639     if (n->af == AF_UNIX) {
 1640         memcpy (n->u.un, addr->u.un, sizeof (*addr->u.un));
 1641     }
 1642     else {
 1643         memcpy (&n->u.in, &addr->u.in, sizeof (addr->u.in));
 1644     }
 1645 
 1646     return n;
 1647 }
 1648 
 1649 gint
 1650 rspamd_inet_address_get_af (const rspamd_inet_addr_t *addr)
 1651 {
 1652     g_assert (addr != NULL);
 1653 
 1654     return addr->af;
 1655 }
 1656 
 1657 
 1658 guint
 1659 rspamd_inet_address_hash (gconstpointer a)
 1660 {
 1661     const rspamd_inet_addr_t *addr = a;
 1662     rspamd_cryptobox_fast_hash_state_t st;
 1663 
 1664     rspamd_cryptobox_fast_hash_init (&st, rspamd_hash_seed ());
 1665     rspamd_cryptobox_fast_hash_update (&st, &addr->af, sizeof (addr->af));
 1666 
 1667 
 1668     if (addr->af == AF_UNIX && addr->u.un) {
 1669         rspamd_cryptobox_fast_hash_update (&st, addr->u.un, sizeof (*addr->u.un));
 1670     }
 1671     else {
 1672         /* We ignore port part here */
 1673         if (addr->af == AF_INET) {
 1674             rspamd_cryptobox_fast_hash_update (&st, &addr->u.in.addr.s4.sin_addr,
 1675                     sizeof (addr->u.in.addr.s4.sin_addr));
 1676         }
 1677         else {
 1678             rspamd_cryptobox_fast_hash_update (&st, &addr->u.in.addr.s6.sin6_addr,
 1679                     sizeof (addr->u.in.addr.s6.sin6_addr));
 1680         }
 1681     }
 1682 
 1683     return rspamd_cryptobox_fast_hash_final (&st);
 1684 }
 1685 
 1686 gboolean
 1687 rspamd_inet_address_equal (gconstpointer a, gconstpointer b)
 1688 {
 1689     const rspamd_inet_addr_t *a1 = a, *a2 = b;
 1690 
 1691     return rspamd_inet_address_compare (a1, a2) == 0;
 1692 }
 1693 
 1694 #ifndef IN6_IS_ADDR_LOOPBACK
 1695 #define IN6_IS_ADDR_LOOPBACK(a)     \
 1696     ((*(const __uint32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \
 1697     (*(const __uint32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \
 1698     (*(const __uint32_t *)(const void *)(&(a)->s6_addr[8]) == 0) && \
 1699     (*(const __uint32_t *)(const void *)(&(a)->s6_addr[12]) == ntohl(1)))
 1700 #endif
 1701 #ifndef IN6_IS_ADDR_LINKLOCAL
 1702 #define IN6_IS_ADDR_LINKLOCAL(a)    \
 1703     (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0x80))
 1704 #endif
 1705 #ifndef IN6_IS_ADDR_SITELOCAL
 1706 #define IN6_IS_ADDR_SITELOCAL(a)    \
 1707     (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0xc0))
 1708 #endif
 1709 
 1710 gboolean
 1711 rspamd_inet_address_is_local (const rspamd_inet_addr_t *addr,
 1712         gboolean check_laddrs)
 1713 {
 1714     if (addr == NULL) {
 1715         return FALSE;
 1716     }
 1717 
 1718     if (addr->af == AF_UNIX) {
 1719         /* Always true for unix sockets */
 1720         return TRUE;
 1721     }
 1722     else {
 1723         if (addr->af == AF_INET) {
 1724             if ((ntohl (addr->u.in.addr.s4.sin_addr.s_addr) & 0xff000000)
 1725                     == 0x7f000000) {
 1726                 return TRUE;
 1727             }
 1728         }
 1729         else if (addr->af == AF_INET6) {
 1730             if (IN6_IS_ADDR_LOOPBACK (&addr->u.in.addr.s6.sin6_addr) ||
 1731                         IN6_IS_ADDR_LINKLOCAL (&addr->u.in.addr.s6.sin6_addr) ||
 1732                         IN6_IS_ADDR_SITELOCAL (&addr->u.in.addr.s6.sin6_addr)) {
 1733                 return TRUE;
 1734             }
 1735         }
 1736 
 1737         if (check_laddrs && local_addrs) {
 1738             if (rspamd_match_radix_map_addr (local_addrs, addr) != NULL) {
 1739                 return TRUE;
 1740             }
 1741         }
 1742     }
 1743 
 1744     return FALSE;
 1745 }
 1746 
 1747 struct rspamd_radix_map_helper **
 1748 rspamd_inet_library_init (void)
 1749 {
 1750     return &local_addrs;
 1751 }
 1752 
 1753 void
 1754 rspamd_inet_library_destroy (void)
 1755 {
 1756     /* Ugly: local_addrs will actually be freed by config object */
 1757 }
 1758 
 1759 gsize
 1760 rspamd_inet_address_storage_size (void)
 1761 {
 1762     return sizeof (rspamd_inet_addr_t);
 1763 }