"Fossies" - the Fresh Open Source Software Archive

Member "rspamd-1.7.3/src/libutil/addr.c" (10 Apr 2018, 37671 Bytes) of package /linux/misc/rspamd-1.7.3.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.6.6_vs_1.7.0.

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