"Fossies" - the Fresh Open Source Software Archive

Member "rspamd-1.7.9/src/libutil/addr.c" (1 Aug 2018, 37899 Bytes) of package /linux/misc/rspamd-1.7.9.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 latest Fossies "Diffs" side-by-side code changes report: 1.7.8_vs_1.7.9.

    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, *percent;
  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     /* Check IPv6 scope */
  517     if ((percent = memchr (p, '%', len)) != NULL && percent > p) {
  518         len = percent - p; /* Ignore scope */
  519     }
  520 
  521     for (/* void */; len; len--) {
  522         t = *p++;
  523 
  524         if (t == ':') {
  525             if (nibbles) {
  526                 digit = p;
  527                 len4 = len;
  528                 *addr++ = (u_char) (word >> 8);
  529                 *addr++ = (u_char) (word & 0xff);
  530 
  531                 if (--n) {
  532                     nibbles = 0;
  533                     word = 0;
  534                     continue;
  535                 }
  536             } else {
  537                 if (zero == NULL) {
  538                     digit = p;
  539                     len4 = len;
  540                     zero = addr;
  541                     continue;
  542                 }
  543             }
  544 
  545             return FALSE;
  546         }
  547 
  548         if (t == '.' && nibbles) {
  549             if (n < 2 || digit == NULL) {
  550                 return FALSE;
  551             }
  552 
  553             /* IPv4 encoded in IPv6 */
  554             if (!rspamd_parse_inet_address_ip4 (digit, len4 - 1, &word)) {
  555                 return FALSE;
  556             }
  557 
  558             word = ntohl (word);
  559             *addr++ = (guchar) ((word >> 24) & 0xff);
  560             *addr++ = (guchar) ((word >> 16) & 0xff);
  561             n--;
  562             break;
  563         }
  564 
  565         if (++nibbles > 4) {
  566             /* Too many dots */
  567             return FALSE;
  568         }
  569 
  570         /* Restore from hex */
  571         if (t >= '0' && t <= '9') {
  572             word = word * 16 + (t - '0');
  573             continue;
  574         }
  575 
  576         t |= 0x20;
  577 
  578         if (t >= 'a' && t <= 'f') {
  579             word = word * 16 + (t - 'a') + 10;
  580             continue;
  581         }
  582 
  583         return FALSE;
  584     }
  585 
  586     if (nibbles == 0 && zero == NULL) {
  587         return FALSE;
  588     }
  589 
  590     *addr++ = (guchar) (word >> 8);
  591     *addr++ = (guchar) (word & 0xff);
  592 
  593     if (--n) {
  594         if (zero) {
  595             n *= 2;
  596             s = addr - 1;
  597             d = s + n;
  598             while (s >= zero) {
  599                 *d-- = *s--;
  600             }
  601             memset (zero, 0, n);
  602 
  603             return TRUE;
  604         }
  605 
  606     } else {
  607         if (zero == NULL) {
  608             return TRUE;
  609         }
  610     }
  611 
  612     return FALSE;
  613 }
  614 
  615 /* Checks for ipv6 mapped address */
  616 static rspamd_inet_addr_t *
  617 rspamd_inet_address_v6_maybe_map (const struct sockaddr_in6 *sin6)
  618 {
  619     rspamd_inet_addr_t *addr = NULL;
  620     /* 10 zero bytes or 80 bits */
  621     static const guint8 mask[] = {
  622         0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  623     };
  624     const guint8 *p;
  625 
  626     if (memcmp ((const guint8 *)&sin6->sin6_addr, mask, sizeof (mask)) == 0) {
  627         p = (const guint8 *)&sin6->sin6_addr;
  628 
  629         if ((p[10] == 0xff && p[11] == 0xff)) {
  630             addr = rspamd_inet_addr_create (AF_INET);
  631             memcpy (&addr->u.in.addr.s4.sin_addr, &p[12],
  632                     sizeof (struct in_addr));
  633         }
  634         else {
  635             /* Something strange but not mapped v4 address */
  636             addr = rspamd_inet_addr_create (AF_INET6);
  637             memcpy (&addr->u.in.addr.s6.sin6_addr, &sin6->sin6_addr,
  638                     sizeof (struct in6_addr));
  639         }
  640     }
  641     else {
  642         addr = rspamd_inet_addr_create (AF_INET6);
  643         memcpy (&addr->u.in.addr.s6.sin6_addr, &sin6->sin6_addr,
  644                 sizeof (struct in6_addr));
  645     }
  646 
  647     return addr;
  648 }
  649 
  650 static void
  651 rspamd_inet_address_v6_maybe_map_static (const struct sockaddr_in6 *sin6,
  652         rspamd_inet_addr_t *addr)
  653 {
  654     /* 10 zero bytes or 80 bits */
  655     static const guint8 mask[] = {
  656         0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  657     };
  658     const guint8 *p;
  659 
  660     if (memcmp ((const guint8 *)&sin6->sin6_addr, mask, sizeof (mask)) == 0) {
  661         p = (const guint8 *)&sin6->sin6_addr;
  662 
  663         if ((p[10] == 0xff && p[11] == 0xff)) {
  664             memcpy (&addr->u.in.addr.s4.sin_addr, &p[12],
  665                     sizeof (struct in_addr));
  666             addr->af = AF_INET;
  667             addr->slen = sizeof (addr->u.in.addr.s4);
  668         }
  669         else {
  670             /* Something strange but not mapped v4 address */
  671             memcpy (&addr->u.in.addr.s6.sin6_addr, &sin6->sin6_addr,
  672                     sizeof (struct in6_addr));
  673             addr->af = AF_INET6;
  674             addr->slen = sizeof (addr->u.in.addr.s6);
  675         }
  676     }
  677     else {
  678         memcpy (&addr->u.in.addr.s6.sin6_addr, &sin6->sin6_addr,
  679                 sizeof (struct in6_addr));
  680         addr->af = AF_INET6;
  681         addr->slen = sizeof (addr->u.in.addr.s6);
  682     }
  683 }
  684 
  685 gboolean
  686 rspamd_parse_inet_address (rspamd_inet_addr_t **target,
  687         const char *src,
  688         gsize srclen)
  689 {
  690     gboolean ret = FALSE;
  691     rspamd_inet_addr_t *addr = NULL;
  692     union sa_inet su;
  693     const char *end;
  694     char ipbuf[INET6_ADDRSTRLEN + 1];
  695     guint iplen;
  696     gulong portnum;
  697 
  698     g_assert (src != NULL);
  699     g_assert (target != NULL);
  700 
  701     if (srclen == 0) {
  702         srclen = strlen (src);
  703     }
  704 
  705     rspamd_ip_check_ipv6 ();
  706 
  707     if (src[0] == '/' || src[0] == '.') {
  708         return rspamd_parse_unix_path (target, src);
  709     }
  710 
  711     if (src[0] == '[') {
  712         /* Ipv6 address in format [::1]:port or just [::1] */
  713         end = memchr (src + 1, ']', srclen - 1);
  714 
  715         if (end == NULL) {
  716             return FALSE;
  717         }
  718 
  719         iplen = end - src - 1;
  720 
  721         if (iplen == 0 || iplen >= sizeof (ipbuf)) {
  722             return FALSE;
  723         }
  724 
  725         rspamd_strlcpy (ipbuf, src + 1, iplen + 1);
  726 
  727         if (rspamd_parse_inet_address_ip6 (ipbuf, iplen,
  728                         &su.s6.sin6_addr)) {
  729             addr = rspamd_inet_address_v6_maybe_map (&su.s6);
  730             ret = TRUE;
  731         }
  732 
  733         if (ret && end[1] == ':') {
  734             /* Port part */
  735             rspamd_strtoul (end + 1, srclen - iplen - 3, &portnum);
  736             rspamd_inet_address_set_port (addr, portnum);
  737         }
  738     }
  739     else {
  740 
  741         if ((end = memchr (src, ':', srclen)) != NULL) {
  742             /* This is either port number and ipv4 addr or ipv6 addr */
  743             /* Search for another semicolon */
  744             if (memchr (end + 1, ':', srclen - (end - src + 1)) &&
  745                     rspamd_parse_inet_address_ip6 (src, srclen, &su.s6.sin6_addr)) {
  746                 addr = rspamd_inet_address_v6_maybe_map (&su.s6);
  747                 ret = TRUE;
  748             }
  749             else {
  750                 /* Not ipv6, so try ip:port */
  751                 iplen = end - src;
  752 
  753                 if (iplen >= sizeof (ipbuf) || iplen <= 1) {
  754                     return FALSE;
  755                 }
  756                 else {
  757                     rspamd_strlcpy (ipbuf, src, iplen + 1);
  758                 }
  759 
  760                 if (rspamd_parse_inet_address_ip4 (ipbuf, iplen,
  761                         &su.s4.sin_addr)) {
  762                     addr = rspamd_inet_addr_create (AF_INET);
  763                     memcpy (&addr->u.in.addr.s4.sin_addr, &su.s4.sin_addr,
  764                             sizeof (struct in_addr));
  765                     rspamd_strtoul (end + 1, srclen - iplen - 1, &portnum);
  766                     rspamd_inet_address_set_port (addr, portnum);
  767                     ret = TRUE;
  768                 }
  769             }
  770         }
  771         else {
  772             if (rspamd_parse_inet_address_ip4 (src, srclen, &su.s4.sin_addr)) {
  773                 addr = rspamd_inet_addr_create (AF_INET);
  774                 memcpy (&addr->u.in.addr.s4.sin_addr, &su.s4.sin_addr,
  775                         sizeof (struct in_addr));
  776                 ret = TRUE;
  777             }
  778             else if (rspamd_parse_inet_address_ip6 (src, srclen, &su.s6.sin6_addr)) {
  779                 addr = rspamd_inet_address_v6_maybe_map (&su.s6);
  780                 ret = TRUE;
  781             }
  782         }
  783     }
  784 
  785     if (ret && target) {
  786         *target = addr;
  787     }
  788 
  789     return ret;
  790 }
  791 
  792 gboolean
  793 rspamd_parse_inet_address_ip (const char *src, gsize srclen,
  794         rspamd_inet_addr_t *target)
  795 {
  796     const char *end;
  797     char ipbuf[INET6_ADDRSTRLEN + 1];
  798     guint iplen;
  799     gulong portnum;
  800     gboolean ret = FALSE;
  801     union sa_inet su;
  802 
  803     g_assert (target != NULL);
  804     g_assert (src != NULL);
  805 
  806     if (src[0] == '[') {
  807         /* Ipv6 address in format [::1]:port or just [::1] */
  808         end = memchr (src + 1, ']', srclen - 1);
  809 
  810         if (end == NULL) {
  811             return FALSE;
  812         }
  813 
  814         iplen = end - src - 1;
  815 
  816         if (iplen == 0 || iplen >= sizeof (ipbuf)) {
  817             return FALSE;
  818         }
  819 
  820         rspamd_strlcpy (ipbuf, src + 1, iplen + 1);
  821 
  822         if (rspamd_parse_inet_address_ip6 (ipbuf, iplen,
  823                         &su.s6.sin6_addr)) {
  824             rspamd_inet_address_v6_maybe_map_static (&su.s6, target);
  825             ret = TRUE;
  826         }
  827 
  828         if (ret && end[1] == ':') {
  829             /* Port part */
  830             rspamd_strtoul (end + 1, srclen - iplen - 3, &portnum);
  831             rspamd_inet_address_set_port (target, portnum);
  832         }
  833     }
  834     else {
  835 
  836         if ((end = memchr (src, ':', srclen)) != NULL) {
  837             /* This is either port number and ipv4 addr or ipv6 addr */
  838             /* Search for another semicolon */
  839             if (memchr (end + 1, ':', srclen - (end - src + 1)) &&
  840                     rspamd_parse_inet_address_ip6 (src, srclen, &su.s6.sin6_addr)) {
  841                 rspamd_inet_address_v6_maybe_map_static (&su.s6, target);
  842                 ret = TRUE;
  843             }
  844             else {
  845                 /* Not ipv6, so try ip:port */
  846                 iplen = end - src;
  847 
  848                 if (iplen >= sizeof (ipbuf) || iplen <= 1) {
  849                     return FALSE;
  850                 }
  851                 else {
  852                     rspamd_strlcpy (ipbuf, src, iplen + 1);
  853                 }
  854 
  855                 if (rspamd_parse_inet_address_ip4 (ipbuf, iplen,
  856                         &su.s4.sin_addr)) {
  857                     memcpy (&target->u.in.addr.s4.sin_addr, &su.s4.sin_addr,
  858                             sizeof (struct in_addr));
  859                     target->af = AF_INET;
  860                     target->slen = sizeof (target->u.in.addr.s4);
  861                     rspamd_strtoul (end + 1, srclen - iplen - 1, &portnum);
  862                     rspamd_inet_address_set_port (target, portnum);
  863                     ret = TRUE;
  864                 }
  865             }
  866         }
  867         else {
  868             if (rspamd_parse_inet_address_ip4 (src, srclen, &su.s4.sin_addr)) {
  869                 memcpy (&target->u.in.addr.s4.sin_addr, &su.s4.sin_addr,
  870                         sizeof (struct in_addr));
  871                 target->af = AF_INET;
  872                 target->slen = sizeof (target->u.in.addr.s4);
  873                 ret = TRUE;
  874             }
  875             else if (rspamd_parse_inet_address_ip6 (src, srclen,
  876                     &su.s6.sin6_addr)) {
  877                 rspamd_inet_address_v6_maybe_map_static (&su.s6, target);
  878                 ret = TRUE;
  879             }
  880         }
  881     }
  882 
  883     return ret;
  884 }
  885 
  886 const char *
  887 rspamd_inet_address_to_string (const rspamd_inet_addr_t *addr)
  888 {
  889     static char addr_str[INET6_ADDRSTRLEN + 1];
  890 
  891     if (addr == NULL) {
  892         return "<empty inet address>";
  893     }
  894 
  895     switch (addr->af) {
  896     case AF_INET:
  897         return inet_ntop (addr->af, &addr->u.in.addr.s4.sin_addr, addr_str,
  898                    sizeof (addr_str));
  899     case AF_INET6:
  900         return inet_ntop (addr->af, &addr->u.in.addr.s6.sin6_addr, addr_str,
  901                    sizeof (addr_str));
  902     case AF_UNIX:
  903         return addr->u.un->addr.sun_path;
  904     }
  905 
  906     return "undefined";
  907 }
  908 
  909 const char *
  910 rspamd_inet_address_to_string_pretty (const rspamd_inet_addr_t *addr)
  911 {
  912     static char addr_str[PATH_MAX + 5];
  913 
  914     if (addr == NULL) {
  915         return "<empty inet address>";
  916     }
  917 
  918     switch (addr->af) {
  919     case AF_INET:
  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_INET6:
  925         rspamd_snprintf (addr_str, sizeof (addr_str), "[%s]:%d",
  926                 rspamd_inet_address_to_string (addr),
  927                 rspamd_inet_address_get_port (addr));
  928         break;
  929     case AF_UNIX:
  930         rspamd_snprintf (addr_str, sizeof (addr_str), "unix:%s",
  931                 rspamd_inet_address_to_string (addr));
  932         break;
  933     }
  934 
  935     return addr_str;
  936 }
  937 
  938 uint16_t
  939 rspamd_inet_address_get_port (const rspamd_inet_addr_t *addr)
  940 {
  941     switch (addr->af) {
  942     case AF_INET:
  943         return ntohs (addr->u.in.addr.s4.sin_port);
  944     case AF_INET6:
  945         return ntohs (addr->u.in.addr.s6.sin6_port);
  946     }
  947 
  948     return 0;
  949 }
  950 
  951 void
  952 rspamd_inet_address_set_port (rspamd_inet_addr_t *addr, uint16_t port)
  953 {
  954     switch (addr->af) {
  955     case AF_INET:
  956         addr->u.in.addr.s4.sin_port = htons (port);
  957         break;
  958     case AF_INET6:
  959         addr->u.in.addr.s6.sin6_port = htons (port);
  960         break;
  961     }
  962 }
  963 
  964 int
  965 rspamd_inet_address_connect (const rspamd_inet_addr_t *addr, gint type,
  966         gboolean async)
  967 {
  968     int fd, r;
  969     const struct sockaddr *sa;
  970 
  971     if (addr == NULL) {
  972         return -1;
  973     }
  974 
  975     fd = rspamd_socket_create (addr->af, type, 0, async);
  976     if (fd == -1) {
  977         return -1;
  978     }
  979 
  980     if (addr->af == AF_UNIX) {
  981         sa = (const struct sockaddr *)&addr->u.un->addr;
  982     }
  983     else {
  984         sa = &addr->u.in.addr.sa;
  985     }
  986 
  987     r = connect (fd, sa, addr->slen);
  988 
  989     if (r == -1) {
  990         if (!async || errno != EINPROGRESS) {
  991             close (fd);
  992             msg_warn ("connect %s failed: %d, '%s'",
  993                     rspamd_inet_address_to_string_pretty (addr),
  994                     errno, strerror (errno));
  995             return -1;
  996         }
  997     }
  998 
  999     return fd;
 1000 }
 1001 
 1002 int
 1003 rspamd_inet_address_listen (const rspamd_inet_addr_t *addr, gint type,
 1004         gboolean async)
 1005 {
 1006     gint fd, r;
 1007     gint on = 1;
 1008     const struct sockaddr *sa;
 1009     const char *path;
 1010 
 1011     if (addr == NULL) {
 1012         return -1;
 1013     }
 1014 
 1015     fd = rspamd_socket_create (addr->af, type, 0, async);
 1016     if (fd == -1) {
 1017         return -1;
 1018     }
 1019 
 1020     if (addr->af == AF_UNIX && access (addr->u.un->addr.sun_path, W_OK) != -1) {
 1021         /* Unlink old socket */
 1022         (void)unlink (addr->u.un->addr.sun_path);
 1023     }
 1024 
 1025     if (addr->af == AF_UNIX) {
 1026         sa = (const struct sockaddr *)&addr->u.un->addr;
 1027     }
 1028     else {
 1029         sa = &addr->u.in.addr.sa;
 1030     }
 1031 
 1032     (void)setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof (gint));
 1033 
 1034 #ifdef HAVE_IPV6_V6ONLY
 1035     if (addr->af == AF_INET6) {
 1036         /* We need to set this flag to avoid errors */
 1037         on = 1;
 1038 #ifdef SOL_IPV6
 1039         (void)setsockopt (fd, SOL_IPV6, IPV6_V6ONLY, (const void *)&on, sizeof (gint));
 1040 #elif defined(IPPROTO_IPV6)
 1041         (void)setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, (const void *)&on, sizeof (gint));
 1042 #endif
 1043     }
 1044 #endif
 1045 
 1046     r = bind (fd, sa, addr->slen);
 1047     if (r == -1) {
 1048         if (!async || errno != EINPROGRESS) {
 1049             close (fd);
 1050             msg_warn ("bind %s failed: %d, '%s'",
 1051                     rspamd_inet_address_to_string_pretty (addr),
 1052                     errno,
 1053                     strerror (errno));
 1054             return -1;
 1055         }
 1056     }
 1057 
 1058     if (type != SOCK_DGRAM) {
 1059 
 1060         if (addr->af == AF_UNIX) {
 1061             path = addr->u.un->addr.sun_path;
 1062             /* Try to set mode and owner */
 1063 
 1064             if (addr->u.un->owner != (uid_t)-1 || addr->u.un->group != (gid_t)-1) {
 1065                 if (chown (path, addr->u.un->owner, addr->u.un->group) == -1) {
 1066                     msg_info ("cannot change owner for %s to %d:%d: %s",
 1067                             path, addr->u.un->owner, addr->u.un->group,
 1068                             strerror (errno));
 1069                 }
 1070             }
 1071 
 1072             if (chmod (path, addr->u.un->mode) == -1) {
 1073                 msg_info ("cannot change mode for %s to %od %s",
 1074                         path, addr->u.un->mode, strerror (errno));
 1075             }
 1076         }
 1077         r = listen (fd, -1);
 1078 
 1079         if (r == -1) {
 1080             msg_warn ("listen %s failed: %d, '%s'",
 1081                     rspamd_inet_address_to_string_pretty (addr),
 1082                     errno, strerror (errno));
 1083             close (fd);
 1084             return -1;
 1085         }
 1086     }
 1087 
 1088     return fd;
 1089 }
 1090 
 1091 gssize
 1092 rspamd_inet_address_recvfrom (gint fd, void *buf, gsize len, gint fl,
 1093         rspamd_inet_addr_t **target)
 1094 {
 1095     gssize ret;
 1096     union sa_union su;
 1097     socklen_t slen = sizeof (su);
 1098     rspamd_inet_addr_t *addr = NULL;
 1099 
 1100     if ((ret = recvfrom (fd, buf, len, fl, &su.sa, &slen)) == -1) {
 1101         if (target) {
 1102             *target = NULL;
 1103         }
 1104 
 1105         return -1;
 1106     }
 1107 
 1108     if (target) {
 1109         addr = rspamd_inet_addr_create (su.sa.sa_family);
 1110         addr->slen = slen;
 1111 
 1112         if (addr->af == AF_UNIX) {
 1113             addr->u.un = g_malloc (sizeof (*addr->u.un));
 1114             memcpy (&addr->u.un->addr, &su.su, sizeof (struct sockaddr_un));
 1115         }
 1116         else {
 1117             memcpy (&addr->u.in.addr, &su.sa, MIN (slen, sizeof (addr->u.in.addr)));
 1118         }
 1119 
 1120         *target = addr;
 1121     }
 1122 
 1123     return (ret);
 1124 }
 1125 
 1126 gssize
 1127 rspamd_inet_address_sendto (gint fd, const void *buf, gsize len, gint fl,
 1128         const rspamd_inet_addr_t *addr)
 1129 {
 1130     gssize r;
 1131     const struct sockaddr *sa;
 1132 
 1133     if (addr == NULL) {
 1134         return -1;
 1135     }
 1136 
 1137     if (addr->af == AF_UNIX) {
 1138         sa = (struct sockaddr *)&addr->u.un->addr;
 1139     }
 1140     else {
 1141         sa = &addr->u.in.addr.sa;
 1142     }
 1143 
 1144     r = sendto (fd, buf, len, fl, sa, addr->slen);
 1145 
 1146     return r;
 1147 }
 1148 
 1149 static gboolean
 1150 rspamd_check_port_priority (const char *line, guint default_port,
 1151         guint *priority, gchar *out,
 1152         gsize outlen, rspamd_mempool_t *pool)
 1153 {
 1154     guint real_port = default_port, real_priority = 0;
 1155     gchar *err_str, *err_str_prio;
 1156 
 1157     if (line && line[0] == ':') {
 1158         errno = 0;
 1159         real_port = strtoul (line + 1, &err_str, 10);
 1160 
 1161         if (err_str && *err_str == ':') {
 1162             /* We have priority */
 1163             real_priority = strtoul (err_str + 1, &err_str_prio, 10);
 1164 
 1165             if (err_str_prio && *err_str_prio != '\0') {
 1166                 msg_err_pool_check (
 1167                         "cannot parse priority: %s, at symbol %c, error: %s",
 1168                         line,
 1169                         *err_str_prio,
 1170                         strerror (errno));
 1171 
 1172                 return FALSE;
 1173             }
 1174         }
 1175         else if (err_str && *err_str != '\0') {
 1176             msg_err_pool_check (
 1177                     "cannot parse port: %s, at symbol %c, error: %s",
 1178                     line,
 1179                     *err_str,
 1180                     strerror (errno));
 1181 
 1182             return FALSE;
 1183         }
 1184     }
 1185 
 1186     if (priority) {
 1187         *priority = real_priority;
 1188     }
 1189 
 1190     rspamd_snprintf (out, outlen, "%ud", real_port);
 1191 
 1192     return TRUE;
 1193 }
 1194 
 1195 static gboolean
 1196 rspamd_resolve_addrs (const char *begin, size_t len, GPtrArray **addrs,
 1197         const gchar *portbuf, gint flags,
 1198         rspamd_mempool_t *pool)
 1199 {
 1200     struct addrinfo hints, *res, *cur;
 1201     rspamd_inet_addr_t *cur_addr = NULL;
 1202     gint r, addr_cnt;
 1203     gchar *addr_cpy = NULL;
 1204 
 1205     rspamd_ip_check_ipv6 ();
 1206 
 1207     if (rspamd_parse_inet_address (&cur_addr, begin, len)) {
 1208         if (*addrs == NULL) {
 1209             *addrs = g_ptr_array_new_full (1,
 1210                     (GDestroyNotify) rspamd_inet_address_free);
 1211 
 1212             if (pool != NULL) {
 1213                 rspamd_mempool_add_destructor (pool,
 1214                         rspamd_ptr_array_free_hard, *addrs);
 1215             }
 1216         }
 1217 
 1218         rspamd_inet_address_set_port (cur_addr, strtoul (portbuf, NULL, 10));
 1219         g_ptr_array_add (*addrs, cur_addr);
 1220     }
 1221     else {
 1222         memset (&hints, 0, sizeof (hints));
 1223         hints.ai_socktype = SOCK_STREAM; /* Type of the socket */
 1224         hints.ai_flags = AI_NUMERICSERV|flags;
 1225 
 1226         if (len > 0) {
 1227             if (pool) {
 1228                 addr_cpy = rspamd_mempool_alloc (pool, len + 1);
 1229             }
 1230             else {
 1231                 addr_cpy = g_malloc (len + 1);
 1232             }
 1233 
 1234             rspamd_strlcpy (addr_cpy, begin, len + 1);
 1235         }
 1236         /* Otherwise it will be NULL */
 1237 
 1238         if (ipv6_status == RSPAMD_IPV6_SUPPORTED) {
 1239             hints.ai_family = AF_UNSPEC;
 1240         }
 1241         else {
 1242             hints.ai_family = AF_INET;
 1243         }
 1244 
 1245         if ((r = getaddrinfo (addr_cpy, portbuf, &hints, &res)) == 0) {
 1246             /* Now copy up to max_addrs of addresses */
 1247             addr_cnt = 0;
 1248             cur = res;
 1249             while (cur) {
 1250                 cur = cur->ai_next;
 1251                 addr_cnt ++;
 1252             }
 1253 
 1254             if (*addrs == NULL) {
 1255                 *addrs = g_ptr_array_new_full (addr_cnt,
 1256                         (GDestroyNotify) rspamd_inet_address_free);
 1257 
 1258                 if (pool != NULL) {
 1259                     rspamd_mempool_add_destructor (pool,
 1260                             rspamd_ptr_array_free_hard, *addrs);
 1261                 }
 1262             }
 1263 
 1264             cur = res;
 1265             while (cur) {
 1266                 cur_addr = rspamd_inet_address_from_sa (cur->ai_addr,
 1267                         cur->ai_addrlen);
 1268 
 1269                 if (cur_addr != NULL) {
 1270                     g_ptr_array_add (*addrs, cur_addr);
 1271                 }
 1272                 cur = cur->ai_next;
 1273             }
 1274 
 1275             freeaddrinfo (res);
 1276         }
 1277         else if (addr_cpy) {
 1278             msg_err_pool_check ("address resolution for %s failed: %s",
 1279                     addr_cpy,
 1280                     gai_strerror (r));
 1281 
 1282             if (pool == NULL) {
 1283                 g_free (addr_cpy);
 1284             }
 1285 
 1286             return FALSE;
 1287         }
 1288         else {
 1289             /* Should never ever happen */
 1290             g_assert (0);
 1291         }
 1292     }
 1293 
 1294     return TRUE;
 1295 }
 1296 
 1297 gboolean
 1298 rspamd_parse_host_port_priority (const gchar *str,
 1299     GPtrArray **addrs,
 1300     guint *priority,
 1301     gchar **name_ptr,
 1302     guint default_port,
 1303     rspamd_mempool_t *pool)
 1304 {
 1305     gchar portbuf[8];
 1306     const gchar *p, *name = NULL;
 1307     gsize namelen;
 1308     rspamd_inet_addr_t *cur_addr = NULL;
 1309 
 1310     /*
 1311      * In this function, we can have several possibilities:
 1312      * 1) Unix socket: check for '.' or '/' at the begin of string
 1313      * 2) \[ipv6\]: check for '[' at the beginning
 1314      * 3) '*': means listening on any address
 1315      * 4) ip|host[:port[:priority]]
 1316      */
 1317 
 1318     if (str[0] == '*') {
 1319         if (!rspamd_check_port_priority (str + 1, default_port, priority,
 1320                 portbuf, sizeof (portbuf), pool)) {
 1321             return FALSE;
 1322         }
 1323 
 1324         if (!rspamd_resolve_addrs (str, 0, addrs, portbuf, AI_PASSIVE, pool)) {
 1325             return FALSE;
 1326         }
 1327 
 1328         name = "*";
 1329         namelen = 1;
 1330     }
 1331     else if (str[0] == '[') {
 1332         /* This is braced IPv6 address */
 1333         p = strchr (str, ']');
 1334 
 1335         if (p == NULL) {
 1336             msg_err_pool_check ("cannot parse address definition %s: %s",
 1337                     str,
 1338                     strerror (EINVAL));
 1339 
 1340             return FALSE;
 1341         }
 1342 
 1343         name = str + 1;
 1344         namelen = p - str - 1;
 1345 
 1346         if (!rspamd_check_port_priority (p + 1, default_port, priority, portbuf,
 1347                 sizeof (portbuf), pool)) {
 1348             return FALSE;
 1349         }
 1350 
 1351         if (!rspamd_resolve_addrs (name, namelen, addrs,
 1352                 portbuf, 0, pool)) {
 1353             return FALSE;
 1354         }
 1355     }
 1356     else if (str[0] == '/' || str[0] == '.') {
 1357         /* Special case of unix socket, as getaddrinfo cannot deal with them */
 1358         if (*addrs == NULL) {
 1359             *addrs = g_ptr_array_new_full (1,
 1360                     (GDestroyNotify) rspamd_inet_address_free);
 1361 
 1362             if (pool != NULL) {
 1363                 rspamd_mempool_add_destructor (pool,
 1364                         rspamd_ptr_array_free_hard, *addrs);
 1365             }
 1366         }
 1367 
 1368         if (!rspamd_parse_inet_address (&cur_addr, str, 0)) {
 1369             msg_err_pool_check ("cannot parse unix socket definition %s: %s",
 1370                     str,
 1371                     strerror (errno));
 1372 
 1373             return FALSE;
 1374         }
 1375 
 1376         g_ptr_array_add (*addrs, cur_addr);
 1377         name = str;
 1378         namelen = strlen (str);
 1379     }
 1380     else {
 1381         p = strchr (str, ':');
 1382 
 1383         if (p == NULL) {
 1384             /* Just address or IP */
 1385             name = str;
 1386             namelen = strlen (str);
 1387             rspamd_check_port_priority ("", default_port, priority, portbuf,
 1388                     sizeof (portbuf), pool);
 1389 
 1390             if (!rspamd_resolve_addrs (name, namelen, addrs,
 1391                     portbuf, 0, pool)) {
 1392                 return FALSE;
 1393             }
 1394         }
 1395         else {
 1396             name = str;
 1397             namelen = p - str;
 1398 
 1399             if (!rspamd_check_port_priority (p, default_port, priority, portbuf,
 1400                     sizeof (portbuf), pool)) {
 1401                 return FALSE;
 1402             }
 1403 
 1404             if (!rspamd_resolve_addrs (str, p - str, addrs,
 1405                     portbuf, 0, pool)) {
 1406                 return FALSE;
 1407             }
 1408         }
 1409     }
 1410 
 1411     if (name_ptr != NULL) {
 1412         if (pool) {
 1413             *name_ptr = rspamd_mempool_alloc (pool, namelen + 1);
 1414         }
 1415         else {
 1416             *name_ptr = g_malloc (namelen + 1);
 1417         }
 1418 
 1419         rspamd_strlcpy (*name_ptr, name, namelen + 1);
 1420     }
 1421 
 1422     return TRUE;
 1423 }
 1424 
 1425 guchar*
 1426 rspamd_inet_address_get_hash_key (const rspamd_inet_addr_t *addr, guint *klen)
 1427 {
 1428     guchar *res = NULL;
 1429     static struct in_addr local = {INADDR_LOOPBACK};
 1430 
 1431     g_assert (addr != NULL);
 1432     g_assert (klen != NULL);
 1433 
 1434     if (addr->af == AF_INET) {
 1435         *klen = sizeof (struct in_addr);
 1436         res = (guchar *)&addr->u.in.addr.s4.sin_addr;
 1437     }
 1438     else if (addr->af == AF_INET6) {
 1439         *klen = sizeof (struct in6_addr);
 1440         res = (guchar *)&addr->u.in.addr.s6.sin6_addr;
 1441     }
 1442     else if (addr->af == AF_UNIX) {
 1443         *klen = sizeof (struct in_addr);
 1444         res = (guchar *)&local;
 1445     }
 1446     else {
 1447         *klen = 0;
 1448         res = NULL;
 1449     }
 1450 
 1451     return res;
 1452 }
 1453 
 1454 
 1455 rspamd_inet_addr_t *
 1456 rspamd_inet_address_new (int af, const void *init)
 1457 {
 1458     rspamd_inet_addr_t *addr;
 1459 
 1460     addr = rspamd_inet_addr_create (af);
 1461 
 1462     if (init != NULL) {
 1463         if (af == AF_UNIX) {
 1464             /* Init is a path */
 1465             rspamd_strlcpy (addr->u.un->addr.sun_path, init,
 1466                     sizeof (addr->u.un->addr.sun_path));
 1467 #if defined(FREEBSD) || defined(__APPLE__)
 1468             addr->u.un->addr.sun_len = SUN_LEN (&addr->u.un->addr);
 1469 #endif
 1470         }
 1471         else if (af == AF_INET) {
 1472             memcpy (&addr->u.in.addr.s4.sin_addr, init, sizeof (struct in_addr));
 1473         }
 1474         else if (af == AF_INET6) {
 1475             memcpy (&addr->u.in.addr.s6.sin6_addr, init, sizeof (struct in6_addr));
 1476         }
 1477     }
 1478 
 1479     return addr;
 1480 }
 1481 
 1482 rspamd_inet_addr_t *
 1483 rspamd_inet_address_from_sa (const struct sockaddr *sa, socklen_t slen)
 1484 {
 1485     rspamd_inet_addr_t *addr;
 1486 
 1487     g_assert (sa != NULL);
 1488     g_assert (slen >= sizeof (struct sockaddr));
 1489 
 1490     addr = rspamd_inet_addr_create (sa->sa_family);
 1491 
 1492     if (sa->sa_family == AF_UNIX) {
 1493         /* Init is a path */
 1494         const struct sockaddr_un *un = (const struct sockaddr_un *)sa;
 1495 
 1496         g_assert (slen >= SUN_LEN (un));
 1497 
 1498         rspamd_strlcpy (addr->u.un->addr.sun_path, un->sun_path,
 1499                 sizeof (addr->u.un->addr.sun_path));
 1500 #if defined(FREEBSD) || defined(__APPLE__)
 1501         addr->u.un->addr.sun_len = un->sun_len;
 1502 #endif
 1503     }
 1504     else if (sa->sa_family == AF_INET) {
 1505         g_assert (slen >= sizeof (struct sockaddr_in));
 1506         memcpy (&addr->u.in.addr.s4, sa, sizeof (struct sockaddr_in));
 1507     }
 1508     else if (sa->sa_family == AF_INET6) {
 1509         g_assert (slen >= sizeof (struct sockaddr_in6));
 1510         memcpy (&addr->u.in.addr.s6, sa, sizeof (struct sockaddr_in6));
 1511     }
 1512     else {
 1513         /* XXX: currently we cannot deal with other AF */
 1514         g_assert (0);
 1515     }
 1516 
 1517     return addr;
 1518 }
 1519 
 1520 rspamd_inet_addr_t *
 1521 rspamd_inet_address_from_rnds (const struct rdns_reply_entry *rep)
 1522 {
 1523     rspamd_inet_addr_t *addr = NULL;
 1524 
 1525     g_assert (rep != NULL);
 1526 
 1527     if (rep->type == RDNS_REQUEST_A) {
 1528         addr = rspamd_inet_addr_create (AF_INET);
 1529         memcpy (&addr->u.in.addr.s4.sin_addr, &rep->content.a.addr,
 1530                 sizeof (struct in_addr));
 1531     }
 1532     else if (rep->type == RDNS_REQUEST_AAAA) {
 1533         addr = rspamd_inet_addr_create (AF_INET6);
 1534         memcpy (&addr->u.in.addr.s6.sin6_addr, &rep->content.aaa.addr,
 1535                         sizeof (struct in6_addr));
 1536     }
 1537 
 1538     return addr;
 1539 }
 1540 
 1541 void
 1542 rspamd_inet_address_apply_mask (rspamd_inet_addr_t *addr, guint mask)
 1543 {
 1544     guint32 umsk, *p;
 1545 
 1546     if (mask > 0 && addr != NULL) {
 1547         if (addr->af == AF_INET && mask <= 32) {
 1548             umsk = htonl (G_MAXUINT32 << (32 - mask));
 1549             addr->u.in.addr.s4.sin_addr.s_addr &= umsk;
 1550         }
 1551         else if (addr->af == AF_INET6 && mask <= 128) {
 1552             p = (uint32_t *)&addr->u.in.addr.s6.sin6_addr;
 1553             mask = 128 - mask;
 1554             p += 3;
 1555 
 1556             for (;;) {
 1557                 if (mask >= 32) {
 1558                     mask -= 32;
 1559                     *p = 0;
 1560                 }
 1561                 else {
 1562                     umsk = htonl (G_MAXUINT32 << mask);
 1563                     *p &= umsk;
 1564                     break;
 1565                 }
 1566 
 1567                 p --;
 1568             }
 1569         }
 1570     }
 1571 }
 1572 
 1573 static gint
 1574 rspamd_inet_address_af_order (const rspamd_inet_addr_t *addr)
 1575 {
 1576     int ret;
 1577 
 1578     switch (addr->af) {
 1579     case AF_UNIX:
 1580         ret = 2;
 1581         break;
 1582     case AF_INET:
 1583         ret = 1;
 1584         break;
 1585     default:
 1586         ret = 0;
 1587         break;
 1588     }
 1589 
 1590     return ret;
 1591 }
 1592 
 1593 gint
 1594 rspamd_inet_address_compare (const rspamd_inet_addr_t *a1,
 1595         const rspamd_inet_addr_t *a2)
 1596 {
 1597     g_assert (a1 != NULL);
 1598     g_assert (a2 != NULL);
 1599 
 1600     if (a1->af != a2->af) {
 1601         return (rspamd_inet_address_af_order (a2) -
 1602                 rspamd_inet_address_af_order (a1));
 1603     }
 1604     else {
 1605         switch (a1->af) {
 1606         case AF_INET:
 1607             return memcmp (&a1->u.in.addr.s4.sin_addr,
 1608                     &a2->u.in.addr.s4.sin_addr, sizeof (struct in_addr));
 1609         case AF_INET6:
 1610             return memcmp (&a1->u.in.addr.s6.sin6_addr,
 1611                 &a2->u.in.addr.s6.sin6_addr, sizeof (struct in6_addr));
 1612         case AF_UNIX:
 1613             return strncmp (a1->u.un->addr.sun_path,
 1614                 a2->u.un->addr.sun_path, sizeof (a1->u.un->addr.sun_path));
 1615         default:
 1616             return memcmp (&a1->u.in, &a2->u.in, sizeof (a1->u.in));
 1617         }
 1618     }
 1619 
 1620     return 0;
 1621 }
 1622 
 1623 gint
 1624 rspamd_inet_address_compare_ptr (gconstpointer a1,
 1625         gconstpointer a2)
 1626 {
 1627     const rspamd_inet_addr_t **i1 = (const rspamd_inet_addr_t **)a1,
 1628             **i2 = (const rspamd_inet_addr_t **)a2;
 1629 
 1630     return rspamd_inet_address_compare (*i1, *i2);
 1631 }
 1632 
 1633 rspamd_inet_addr_t *
 1634 rspamd_inet_address_copy (const rspamd_inet_addr_t *addr)
 1635 {
 1636     rspamd_inet_addr_t *n;
 1637 
 1638     if (addr == NULL) {
 1639         return NULL;
 1640     }
 1641 
 1642     n = rspamd_inet_addr_create (addr->af);
 1643 
 1644     if (n->af == AF_UNIX) {
 1645         memcpy (n->u.un, addr->u.un, sizeof (*addr->u.un));
 1646     }
 1647     else {
 1648         memcpy (&n->u.in, &addr->u.in, sizeof (addr->u.in));
 1649     }
 1650 
 1651     return n;
 1652 }
 1653 
 1654 gint
 1655 rspamd_inet_address_get_af (const rspamd_inet_addr_t *addr)
 1656 {
 1657     g_assert (addr != NULL);
 1658 
 1659     return addr->af;
 1660 }
 1661 
 1662 
 1663 guint
 1664 rspamd_inet_address_hash (gconstpointer a)
 1665 {
 1666     const rspamd_inet_addr_t *addr = a;
 1667     rspamd_cryptobox_fast_hash_state_t st;
 1668 
 1669     rspamd_cryptobox_fast_hash_init (&st, rspamd_hash_seed ());
 1670     rspamd_cryptobox_fast_hash_update (&st, &addr->af, sizeof (addr->af));
 1671 
 1672 
 1673     if (addr->af == AF_UNIX && addr->u.un) {
 1674         rspamd_cryptobox_fast_hash_update (&st, addr->u.un, sizeof (*addr->u.un));
 1675     }
 1676     else {
 1677         /* We ignore port part here */
 1678         if (addr->af == AF_INET) {
 1679             rspamd_cryptobox_fast_hash_update (&st, &addr->u.in.addr.s4.sin_addr,
 1680                     sizeof (addr->u.in.addr.s4.sin_addr));
 1681         }
 1682         else {
 1683             rspamd_cryptobox_fast_hash_update (&st, &addr->u.in.addr.s6.sin6_addr,
 1684                     sizeof (addr->u.in.addr.s6.sin6_addr));
 1685         }
 1686     }
 1687 
 1688     return rspamd_cryptobox_fast_hash_final (&st);
 1689 }
 1690 
 1691 gboolean
 1692 rspamd_inet_address_equal (gconstpointer a, gconstpointer b)
 1693 {
 1694     const rspamd_inet_addr_t *a1 = a, *a2 = b;
 1695 
 1696     return rspamd_inet_address_compare (a1, a2) == 0;
 1697 }
 1698 
 1699 #ifndef IN6_IS_ADDR_LOOPBACK
 1700 #define IN6_IS_ADDR_LOOPBACK(a)     \
 1701     ((*(const __uint32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \
 1702     (*(const __uint32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \
 1703     (*(const __uint32_t *)(const void *)(&(a)->s6_addr[8]) == 0) && \
 1704     (*(const __uint32_t *)(const void *)(&(a)->s6_addr[12]) == ntohl(1)))
 1705 #endif
 1706 #ifndef IN6_IS_ADDR_LINKLOCAL
 1707 #define IN6_IS_ADDR_LINKLOCAL(a)    \
 1708     (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0x80))
 1709 #endif
 1710 #ifndef IN6_IS_ADDR_SITELOCAL
 1711 #define IN6_IS_ADDR_SITELOCAL(a)    \
 1712     (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0xc0))
 1713 #endif
 1714 
 1715 gboolean
 1716 rspamd_inet_address_is_local (const rspamd_inet_addr_t *addr,
 1717         gboolean check_laddrs)
 1718 {
 1719     if (addr == NULL) {
 1720         return FALSE;
 1721     }
 1722 
 1723     if (addr->af == AF_UNIX) {
 1724         /* Always true for unix sockets */
 1725         return TRUE;
 1726     }
 1727     else {
 1728         if (addr->af == AF_INET) {
 1729             if ((ntohl (addr->u.in.addr.s4.sin_addr.s_addr) & 0xff000000)
 1730                     == 0x7f000000) {
 1731                 return TRUE;
 1732             }
 1733         }
 1734         else if (addr->af == AF_INET6) {
 1735             if (IN6_IS_ADDR_LOOPBACK (&addr->u.in.addr.s6.sin6_addr) ||
 1736                         IN6_IS_ADDR_LINKLOCAL (&addr->u.in.addr.s6.sin6_addr) ||
 1737                         IN6_IS_ADDR_SITELOCAL (&addr->u.in.addr.s6.sin6_addr)) {
 1738                 return TRUE;
 1739             }
 1740         }
 1741 
 1742         if (check_laddrs && local_addrs) {
 1743             if (rspamd_match_radix_map_addr (local_addrs, addr) != NULL) {
 1744                 return TRUE;
 1745             }
 1746         }
 1747     }
 1748 
 1749     return FALSE;
 1750 }
 1751 
 1752 struct rspamd_radix_map_helper **
 1753 rspamd_inet_library_init (void)
 1754 {
 1755     return &local_addrs;
 1756 }
 1757 
 1758 void
 1759 rspamd_inet_library_destroy (void)
 1760 {
 1761     /* Ugly: local_addrs will actually be freed by config object */
 1762 }
 1763 
 1764 gsize
 1765 rspamd_inet_address_storage_size (void)
 1766 {
 1767     return sizeof (rspamd_inet_addr_t);
 1768 }