LCOV - code coverage report
Current view: top level - basic - in-addr-util.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 304 406 74.9 %
Date: 2019-08-22 15:41:25 Functions: 24 32 75.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <arpa/inet.h>
       4             : #include <endian.h>
       5             : #include <errno.h>
       6             : #include <net/if.h>
       7             : #include <stdint.h>
       8             : #include <stdio.h>
       9             : #include <stdlib.h>
      10             : 
      11             : #include "alloc-util.h"
      12             : #include "errno-util.h"
      13             : #include "in-addr-util.h"
      14             : #include "macro.h"
      15             : #include "parse-util.h"
      16             : #include "random-util.h"
      17             : #include "strxcpyx.h"
      18             : #include "util.h"
      19             : 
      20          86 : bool in4_addr_is_null(const struct in_addr *a) {
      21          86 :         assert(a);
      22             : 
      23          86 :         return a->s_addr == 0;
      24             : }
      25             : 
      26         118 : int in_addr_is_null(int family, const union in_addr_union *u) {
      27         118 :         assert(u);
      28             : 
      29         118 :         if (family == AF_INET)
      30          86 :                 return in4_addr_is_null(&u->in);
      31             : 
      32          32 :         if (family == AF_INET6)
      33          31 :                 return IN6_IS_ADDR_UNSPECIFIED(&u->in6);
      34             : 
      35           1 :         return -EAFNOSUPPORT;
      36             : }
      37             : 
      38           8 : bool in4_addr_is_link_local(const struct in_addr *a) {
      39           8 :         assert(a);
      40             : 
      41           8 :         return (be32toh(a->s_addr) & UINT32_C(0xFFFF0000)) == (UINT32_C(169) << 24 | UINT32_C(254) << 16);
      42             : }
      43             : 
      44          17 : int in_addr_is_link_local(int family, const union in_addr_union *u) {
      45          17 :         assert(u);
      46             : 
      47          17 :         if (family == AF_INET)
      48           8 :                 return in4_addr_is_link_local(&u->in);
      49             : 
      50           9 :         if (family == AF_INET6)
      51           9 :                 return IN6_IS_ADDR_LINKLOCAL(&u->in6);
      52             : 
      53           0 :         return -EAFNOSUPPORT;
      54             : }
      55             : 
      56           4 : int in_addr_is_multicast(int family, const union in_addr_union *u) {
      57           4 :         assert(u);
      58             : 
      59           4 :         if (family == AF_INET)
      60           2 :                 return IN_MULTICAST(be32toh(u->in.s_addr));
      61             : 
      62           2 :         if (family == AF_INET6)
      63           2 :                 return IN6_IS_ADDR_MULTICAST(&u->in6);
      64             : 
      65           0 :         return -EAFNOSUPPORT;
      66             : }
      67             : 
      68           0 : bool in4_addr_is_localhost(const struct in_addr *a) {
      69           0 :         assert(a);
      70             : 
      71             :         /* All of 127.x.x.x is localhost. */
      72           0 :         return (be32toh(a->s_addr) & UINT32_C(0xFF000000)) == UINT32_C(127) << 24;
      73             : }
      74             : 
      75           0 : bool in4_addr_is_non_local(const struct in_addr *a) {
      76             :         /* Whether the address is not null and not localhost.
      77             :          *
      78             :          * As such, it is suitable to configure as DNS/NTP server from DHCP. */
      79           0 :         return !in4_addr_is_null(a) &&
      80           0 :                !in4_addr_is_localhost(a);
      81             : }
      82             : 
      83           0 : int in_addr_is_localhost(int family, const union in_addr_union *u) {
      84           0 :         assert(u);
      85             : 
      86           0 :         if (family == AF_INET)
      87           0 :                 return in4_addr_is_localhost(&u->in);
      88             : 
      89           0 :         if (family == AF_INET6)
      90           0 :                 return IN6_IS_ADDR_LOOPBACK(&u->in6);
      91             : 
      92           0 :         return -EAFNOSUPPORT;
      93             : }
      94             : 
      95          37 : bool in4_addr_equal(const struct in_addr *a, const struct in_addr *b) {
      96          37 :         assert(a);
      97          37 :         assert(b);
      98             : 
      99          37 :         return a->s_addr == b->s_addr;
     100             : }
     101             : 
     102          96 : int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b) {
     103          96 :         assert(a);
     104          96 :         assert(b);
     105             : 
     106          96 :         if (family == AF_INET)
     107          37 :                 return in4_addr_equal(&a->in, &b->in);
     108             : 
     109          59 :         if (family == AF_INET6)
     110             :                 return
     111         118 :                         a->in6.s6_addr32[0] == b->in6.s6_addr32[0] &&
     112          59 :                         a->in6.s6_addr32[1] == b->in6.s6_addr32[1] &&
     113         177 :                         a->in6.s6_addr32[2] == b->in6.s6_addr32[2] &&
     114          59 :                         a->in6.s6_addr32[3] == b->in6.s6_addr32[3];
     115             : 
     116           0 :         return -EAFNOSUPPORT;
     117             : }
     118             : 
     119          43 : int in_addr_prefix_intersect(
     120             :                 int family,
     121             :                 const union in_addr_union *a,
     122             :                 unsigned aprefixlen,
     123             :                 const union in_addr_union *b,
     124             :                 unsigned bprefixlen) {
     125             : 
     126             :         unsigned m;
     127             : 
     128          43 :         assert(a);
     129          43 :         assert(b);
     130             : 
     131             :         /* Checks whether there are any addresses that are in both
     132             :          * networks */
     133             : 
     134          43 :         m = MIN(aprefixlen, bprefixlen);
     135             : 
     136          43 :         if (family == AF_INET) {
     137             :                 uint32_t x, nm;
     138             : 
     139           9 :                 x = be32toh(a->in.s_addr ^ b->in.s_addr);
     140           9 :                 nm = (m == 0) ? 0 : 0xFFFFFFFFUL << (32 - m);
     141             : 
     142           9 :                 return (x & nm) == 0;
     143             :         }
     144             : 
     145          34 :         if (family == AF_INET6) {
     146             :                 unsigned i;
     147             : 
     148          34 :                 if (m > 128)
     149           0 :                         m = 128;
     150             : 
     151         393 :                 for (i = 0; i < 16; i++) {
     152             :                         uint8_t x, nm;
     153             : 
     154         376 :                         x = a->in6.s6_addr[i] ^ b->in6.s6_addr[i];
     155             : 
     156         376 :                         if (m < 8)
     157         154 :                                 nm = 0xFF << (8 - m);
     158             :                         else
     159         222 :                                 nm = 0xFF;
     160             : 
     161         376 :                         if ((x & nm) != 0)
     162          17 :                                 return 0;
     163             : 
     164         359 :                         if (m > 8)
     165         196 :                                 m -= 8;
     166             :                         else
     167         163 :                                 m = 0;
     168             :                 }
     169             : 
     170          17 :                 return 1;
     171             :         }
     172             : 
     173           0 :         return -EAFNOSUPPORT;
     174             : }
     175             : 
     176          14 : int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen) {
     177          14 :         assert(u);
     178             : 
     179             :         /* Increases the network part of an address by one. Returns
     180             :          * positive it that succeeds, or 0 if this overflows. */
     181             : 
     182          14 :         if (prefixlen <= 0)
     183           0 :                 return 0;
     184             : 
     185          14 :         if (family == AF_INET) {
     186             :                 uint32_t c, n;
     187             : 
     188           6 :                 if (prefixlen > 32)
     189           0 :                         prefixlen = 32;
     190             : 
     191           6 :                 c = be32toh(u->in.s_addr);
     192           6 :                 n = c + (1UL << (32 - prefixlen));
     193           6 :                 if (n < c)
     194           2 :                         return 0;
     195           4 :                 n &= 0xFFFFFFFFUL << (32 - prefixlen);
     196             : 
     197           4 :                 u->in.s_addr = htobe32(n);
     198           4 :                 return 1;
     199             :         }
     200             : 
     201           8 :         if (family == AF_INET6) {
     202           8 :                 struct in6_addr add = {}, result;
     203           8 :                 uint8_t overflow = 0;
     204             :                 unsigned i;
     205             : 
     206           8 :                 if (prefixlen > 128)
     207           0 :                         prefixlen = 128;
     208             : 
     209             :                 /* First calculate what we have to add */
     210           8 :                 add.s6_addr[(prefixlen-1) / 8] = 1 << (7 - (prefixlen-1) % 8);
     211             : 
     212         136 :                 for (i = 16; i > 0; i--) {
     213         128 :                         unsigned j = i - 1;
     214             : 
     215         128 :                         result.s6_addr[j] = u->in6.s6_addr[j] + add.s6_addr[j] + overflow;
     216         128 :                         overflow = (result.s6_addr[j] < u->in6.s6_addr[j]);
     217             :                 }
     218             : 
     219           8 :                 if (overflow)
     220           2 :                         return 0;
     221             : 
     222           6 :                 u->in6 = result;
     223           6 :                 return 1;
     224             :         }
     225             : 
     226           0 :         return -EAFNOSUPPORT;
     227             : }
     228             : 
     229           7 : int in_addr_random_prefix(
     230             :                 int family,
     231             :                 union in_addr_union *u,
     232             :                 unsigned prefixlen_fixed_part,
     233             :                 unsigned prefixlen) {
     234             : 
     235           7 :         assert(u);
     236             : 
     237             :         /* Random network part of an address by one. */
     238             : 
     239           7 :         if (prefixlen <= 0)
     240           0 :                 return 0;
     241             : 
     242           7 :         if (family == AF_INET) {
     243             :                 uint32_t c, n;
     244             : 
     245           5 :                 if (prefixlen_fixed_part > 32)
     246           0 :                         prefixlen_fixed_part = 32;
     247           5 :                 if (prefixlen > 32)
     248           0 :                         prefixlen = 32;
     249           5 :                 if (prefixlen_fixed_part >= prefixlen)
     250           0 :                         return -EINVAL;
     251             : 
     252           5 :                 c = be32toh(u->in.s_addr);
     253           5 :                 c &= ((UINT32_C(1) << prefixlen_fixed_part) - 1) << (32 - prefixlen_fixed_part);
     254             : 
     255           5 :                 random_bytes(&n, sizeof(n));
     256           5 :                 n &= ((UINT32_C(1) << (prefixlen - prefixlen_fixed_part)) - 1) << (32 - prefixlen);
     257             : 
     258           5 :                 u->in.s_addr = htobe32(n | c);
     259           5 :                 return 1;
     260             :         }
     261             : 
     262           2 :         if (family == AF_INET6) {
     263             :                 struct in6_addr n;
     264             :                 unsigned i, j;
     265             : 
     266           2 :                 if (prefixlen_fixed_part > 128)
     267           0 :                         prefixlen_fixed_part = 128;
     268           2 :                 if (prefixlen > 128)
     269           0 :                         prefixlen = 128;
     270           2 :                 if (prefixlen_fixed_part >= prefixlen)
     271           0 :                         return -EINVAL;
     272             : 
     273           2 :                 random_bytes(&n, sizeof(n));
     274             : 
     275          34 :                 for (i = 0; i < 16; i++) {
     276          32 :                         uint8_t mask_fixed_part = 0, mask = 0;
     277             : 
     278          32 :                         if (i < (prefixlen_fixed_part + 7) / 8) {
     279           3 :                                 if (i < prefixlen_fixed_part / 8)
     280           3 :                                         mask_fixed_part = 0xffu;
     281             :                                 else {
     282           0 :                                         j = prefixlen_fixed_part % 8;
     283           0 :                                         mask_fixed_part = ((UINT8_C(1) << (j + 1)) - 1) << (8 - j);
     284             :                                 }
     285             :                         }
     286             : 
     287          32 :                         if (i < (prefixlen + 7) / 8) {
     288          10 :                                 if (i < prefixlen / 8)
     289          10 :                                         mask = 0xffu ^ mask_fixed_part;
     290             :                                 else {
     291           0 :                                         j = prefixlen % 8;
     292           0 :                                         mask = (((UINT8_C(1) << (j + 1)) - 1) << (8 - j)) ^ mask_fixed_part;
     293             :                                 }
     294             :                         }
     295             : 
     296          32 :                         u->in6.s6_addr[i] &= mask_fixed_part;
     297          32 :                         u->in6.s6_addr[i] |= n.s6_addr[i] & mask;
     298             :                 }
     299             : 
     300           2 :                 return 1;
     301             :         }
     302             : 
     303           0 :         return -EAFNOSUPPORT;
     304             : }
     305             : 
     306         223 : int in_addr_to_string(int family, const union in_addr_union *u, char **ret) {
     307         223 :         _cleanup_free_ char *x = NULL;
     308             :         size_t l;
     309             : 
     310         223 :         assert(u);
     311         223 :         assert(ret);
     312             : 
     313         223 :         if (family == AF_INET)
     314         130 :                 l = INET_ADDRSTRLEN;
     315          93 :         else if (family == AF_INET6)
     316          93 :                 l = INET6_ADDRSTRLEN;
     317             :         else
     318           0 :                 return -EAFNOSUPPORT;
     319             : 
     320         223 :         x = new(char, l);
     321         223 :         if (!x)
     322           0 :                 return -ENOMEM;
     323             : 
     324         223 :         errno = 0;
     325         223 :         if (!inet_ntop(family, u, x, l))
     326           0 :                 return errno_or_else(EINVAL);
     327             : 
     328         223 :         *ret = TAKE_PTR(x);
     329         223 :         return 0;
     330             : }
     331             : 
     332          33 : int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret) {
     333          33 :         _cleanup_free_ char *x = NULL;
     334             :         char *p;
     335             :         size_t l;
     336             : 
     337          33 :         assert(u);
     338          33 :         assert(ret);
     339             : 
     340          33 :         if (family == AF_INET)
     341          23 :                 l = INET_ADDRSTRLEN + 3;
     342          10 :         else if (family == AF_INET6)
     343          10 :                 l = INET6_ADDRSTRLEN + 4;
     344             :         else
     345           0 :                 return -EAFNOSUPPORT;
     346             : 
     347          33 :         if (prefixlen > FAMILY_ADDRESS_SIZE(family) * 8)
     348           0 :                 return -EINVAL;
     349             : 
     350          33 :         x = new(char, l);
     351          33 :         if (!x)
     352           0 :                 return -ENOMEM;
     353             : 
     354          33 :         errno = 0;
     355          33 :         if (!inet_ntop(family, u, x, l))
     356           0 :                 return errno_or_else(EINVAL);
     357             : 
     358          33 :         p = x + strlen(x);
     359          33 :         l -= strlen(x);
     360          33 :         (void) strpcpyf(&p, l, "/%u", prefixlen);
     361             : 
     362          33 :         *ret = TAKE_PTR(x);
     363          33 :         return 0;
     364             : }
     365             : 
     366           9 : int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret) {
     367           9 :         _cleanup_free_ char *x = NULL;
     368             :         size_t l;
     369             :         int r;
     370             : 
     371           9 :         assert(u);
     372           9 :         assert(ret);
     373             : 
     374             :         /* Much like in_addr_to_string(), but optionally appends the zone interface index to the address, to properly
     375             :          * handle IPv6 link-local addresses. */
     376             : 
     377           9 :         if (family != AF_INET6)
     378           2 :                 goto fallback;
     379           7 :         if (ifindex <= 0)
     380           2 :                 goto fallback;
     381             : 
     382           5 :         r = in_addr_is_link_local(family, u);
     383           5 :         if (r < 0)
     384           0 :                 return r;
     385           5 :         if (r == 0)
     386           2 :                 goto fallback;
     387             : 
     388           3 :         l = INET6_ADDRSTRLEN + 1 + DECIMAL_STR_MAX(ifindex) + 1;
     389           3 :         x = new(char, l);
     390           3 :         if (!x)
     391           0 :                 return -ENOMEM;
     392             : 
     393           3 :         errno = 0;
     394           3 :         if (!inet_ntop(family, u, x, l))
     395           0 :                 return errno_or_else(EINVAL);
     396             : 
     397           3 :         sprintf(strchr(x, 0), "%%%i", ifindex);
     398             : 
     399           3 :         *ret = TAKE_PTR(x);
     400           3 :         return 0;
     401             : 
     402           6 : fallback:
     403           6 :         return in_addr_to_string(family, u, ret);
     404             : }
     405             : 
     406         454 : int in_addr_from_string(int family, const char *s, union in_addr_union *ret) {
     407             :         union in_addr_union buffer;
     408         454 :         assert(s);
     409             : 
     410         454 :         if (!IN_SET(family, AF_INET, AF_INET6))
     411           0 :                 return -EAFNOSUPPORT;
     412             : 
     413         454 :         errno = 0;
     414         454 :         if (inet_pton(family, s, ret ?: &buffer) <= 0)
     415         134 :                 return errno_or_else(EINVAL);
     416             : 
     417         320 :         return 0;
     418             : }
     419             : 
     420         168 : int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret) {
     421             :         int r;
     422             : 
     423         168 :         assert(s);
     424             : 
     425         168 :         r = in_addr_from_string(AF_INET, s, ret);
     426         168 :         if (r >= 0) {
     427          75 :                 if (ret_family)
     428          74 :                         *ret_family = AF_INET;
     429          75 :                 return 0;
     430             :         }
     431             : 
     432          93 :         r = in_addr_from_string(AF_INET6, s, ret);
     433          93 :         if (r >= 0) {
     434          64 :                 if (ret_family)
     435          62 :                         *ret_family = AF_INET6;
     436          64 :                 return 0;
     437             :         }
     438             : 
     439          29 :         return -EINVAL;
     440             : }
     441             : 
     442          42 : int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex) {
     443          42 :         _cleanup_free_ char *buf = NULL;
     444             :         const char *suffix;
     445          42 :         int r, ifi = 0;
     446             : 
     447          42 :         assert(s);
     448          42 :         assert(family);
     449          42 :         assert(ret);
     450             : 
     451             :         /* Similar to in_addr_from_string_auto() but also parses an optionally appended IPv6 zone suffix ("scope id")
     452             :          * if one is found. */
     453             : 
     454          42 :         suffix = strchr(s, '%');
     455          42 :         if (suffix) {
     456             : 
     457           6 :                 if (ifindex) {
     458             :                         /* If we shall return the interface index, try to parse it */
     459           6 :                         r = parse_ifindex(suffix + 1, &ifi);
     460           6 :                         if (r < 0) {
     461             :                                 unsigned u;
     462             : 
     463           2 :                                 u = if_nametoindex(suffix + 1);
     464           2 :                                 if (u <= 0)
     465           1 :                                         return -errno;
     466             : 
     467           1 :                                 ifi = (int) u;
     468             :                         }
     469             :                 }
     470             : 
     471           5 :                 buf = strndup(s, suffix - s);
     472           5 :                 if (!buf)
     473           0 :                         return -ENOMEM;
     474             : 
     475           5 :                 s = buf;
     476             :         }
     477             : 
     478          41 :         r = in_addr_from_string_auto(s, family, ret);
     479          41 :         if (r < 0)
     480           3 :                 return r;
     481             : 
     482          38 :         if (ifindex)
     483          12 :                 *ifindex = ifi;
     484             : 
     485          38 :         return r;
     486             : }
     487             : 
     488          11 : unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr) {
     489          11 :         assert(addr);
     490             : 
     491          11 :         return 32U - u32ctz(be32toh(addr->s_addr));
     492             : }
     493             : 
     494           3 : struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) {
     495           3 :         assert(addr);
     496           3 :         assert(prefixlen <= 32);
     497             : 
     498             :         /* Shifting beyond 32 is not defined, handle this specially. */
     499           3 :         if (prefixlen == 0)
     500           0 :                 addr->s_addr = 0;
     501             :         else
     502           3 :                 addr->s_addr = htobe32((0xffffffff << (32 - prefixlen)) & 0xffffffff);
     503             : 
     504           3 :         return addr;
     505             : }
     506             : 
     507           2 : int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) {
     508           2 :         uint8_t msb_octet = *(uint8_t*) addr;
     509             : 
     510             :         /* addr may not be aligned, so make sure we only access it byte-wise */
     511             : 
     512           2 :         assert(addr);
     513           2 :         assert(prefixlen);
     514             : 
     515           2 :         if (msb_octet < 128)
     516             :                 /* class A, leading bits: 0 */
     517           2 :                 *prefixlen = 8;
     518           0 :         else if (msb_octet < 192)
     519             :                 /* class B, leading bits 10 */
     520           0 :                 *prefixlen = 16;
     521           0 :         else if (msb_octet < 224)
     522             :                 /* class C, leading bits 110 */
     523           0 :                 *prefixlen = 24;
     524             :         else
     525             :                 /* class D or E, no default prefixlen */
     526           0 :                 return -ERANGE;
     527             : 
     528           2 :         return 0;
     529             : }
     530             : 
     531           0 : int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask) {
     532             :         unsigned char prefixlen;
     533             :         int r;
     534             : 
     535           0 :         assert(addr);
     536           0 :         assert(mask);
     537             : 
     538           0 :         r = in4_addr_default_prefixlen(addr, &prefixlen);
     539           0 :         if (r < 0)
     540           0 :                 return r;
     541             : 
     542           0 :         in4_addr_prefixlen_to_netmask(mask, prefixlen);
     543           0 :         return 0;
     544             : }
     545             : 
     546           0 : int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen) {
     547           0 :         assert(addr);
     548             : 
     549           0 :         if (family == AF_INET) {
     550             :                 struct in_addr mask;
     551             : 
     552           0 :                 if (!in4_addr_prefixlen_to_netmask(&mask, prefixlen))
     553           0 :                         return -EINVAL;
     554             : 
     555           0 :                 addr->in.s_addr &= mask.s_addr;
     556           0 :                 return 0;
     557             :         }
     558             : 
     559           0 :         if (family == AF_INET6) {
     560             :                 unsigned i;
     561             : 
     562           0 :                 for (i = 0; i < 16; i++) {
     563             :                         uint8_t mask;
     564             : 
     565           0 :                         if (prefixlen >= 8) {
     566           0 :                                 mask = 0xFF;
     567           0 :                                 prefixlen -= 8;
     568             :                         } else {
     569           0 :                                 mask = 0xFF << (8 - prefixlen);
     570           0 :                                 prefixlen = 0;
     571             :                         }
     572             : 
     573           0 :                         addr->in6.s6_addr[i] &= mask;
     574             :                 }
     575             : 
     576           0 :                 return 0;
     577             :         }
     578             : 
     579           0 :         return -EAFNOSUPPORT;
     580             : }
     581             : 
     582           0 : int in_addr_prefix_covers(int family,
     583             :                           const union in_addr_union *prefix,
     584             :                           unsigned char prefixlen,
     585             :                           const union in_addr_union *address) {
     586             : 
     587             :         union in_addr_union masked_prefix, masked_address;
     588             :         int r;
     589             : 
     590           0 :         assert(prefix);
     591           0 :         assert(address);
     592             : 
     593           0 :         masked_prefix = *prefix;
     594           0 :         r = in_addr_mask(family, &masked_prefix, prefixlen);
     595           0 :         if (r < 0)
     596           0 :                 return r;
     597             : 
     598           0 :         masked_address = *address;
     599           0 :         r = in_addr_mask(family, &masked_address, prefixlen);
     600           0 :         if (r < 0)
     601           0 :                 return r;
     602             : 
     603           0 :         return in_addr_equal(family, &masked_prefix, &masked_address);
     604             : }
     605             : 
     606          99 : int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret) {
     607             :         uint8_t u;
     608             :         int r;
     609             : 
     610          99 :         if (!IN_SET(family, AF_INET, AF_INET6))
     611           0 :                 return -EAFNOSUPPORT;
     612             : 
     613          99 :         r = safe_atou8(p, &u);
     614          99 :         if (r < 0)
     615           4 :                 return r;
     616             : 
     617          95 :         if (u > FAMILY_ADDRESS_SIZE(family) * 8)
     618           4 :                 return -ERANGE;
     619             : 
     620          91 :         *ret = u;
     621          91 :         return 0;
     622             : }
     623             : 
     624          44 : int in_addr_prefix_from_string(
     625             :                 const char *p,
     626             :                 int family,
     627             :                 union in_addr_union *ret_prefix,
     628             :                 unsigned char *ret_prefixlen) {
     629             : 
     630          44 :         _cleanup_free_ char *str = NULL;
     631             :         union in_addr_union buffer;
     632             :         const char *e, *l;
     633             :         unsigned char k;
     634             :         int r;
     635             : 
     636          44 :         assert(p);
     637             : 
     638          44 :         if (!IN_SET(family, AF_INET, AF_INET6))
     639           0 :                 return -EAFNOSUPPORT;
     640             : 
     641          44 :         e = strchr(p, '/');
     642          44 :         if (e) {
     643          37 :                 str = strndup(p, e - p);
     644          37 :                 if (!str)
     645           0 :                         return -ENOMEM;
     646             : 
     647          37 :                 l = str;
     648             :         } else
     649           7 :                 l = p;
     650             : 
     651          44 :         r = in_addr_from_string(family, l, &buffer);
     652          44 :         if (r < 0)
     653           7 :                 return r;
     654             : 
     655          37 :         if (e) {
     656          33 :                 r = in_addr_parse_prefixlen(family, e+1, &k);
     657          33 :                 if (r < 0)
     658           4 :                         return r;
     659             :         } else
     660           4 :                 k = FAMILY_ADDRESS_SIZE(family) * 8;
     661             : 
     662          33 :         if (ret_prefix)
     663          33 :                 *ret_prefix = buffer;
     664          33 :         if (ret_prefixlen)
     665          33 :                 *ret_prefixlen = k;
     666             : 
     667          33 :         return 0;
     668             : }
     669             : 
     670          82 : int in_addr_prefix_from_string_auto_internal(
     671             :                 const char *p,
     672             :                 InAddrPrefixLenMode mode,
     673             :                 int *ret_family,
     674             :                 union in_addr_union *ret_prefix,
     675             :                 unsigned char *ret_prefixlen) {
     676             : 
     677          82 :         _cleanup_free_ char *str = NULL;
     678             :         union in_addr_union buffer;
     679             :         const char *e, *l;
     680             :         unsigned char k;
     681             :         int family, r;
     682             : 
     683          82 :         assert(p);
     684             : 
     685          82 :         e = strchr(p, '/');
     686          82 :         if (e) {
     687          70 :                 str = strndup(p, e - p);
     688          70 :                 if (!str)
     689           0 :                         return -ENOMEM;
     690             : 
     691          70 :                 l = str;
     692             :         } else
     693          12 :                 l = p;
     694             : 
     695          82 :         r = in_addr_from_string_auto(l, &family, &buffer);
     696          82 :         if (r < 0)
     697           6 :                 return r;
     698             : 
     699          76 :         if (e) {
     700          66 :                 r = in_addr_parse_prefixlen(family, e+1, &k);
     701          66 :                 if (r < 0)
     702           4 :                         return r;
     703             :         } else
     704          10 :                 switch (mode) {
     705           2 :                 case PREFIXLEN_FULL:
     706           2 :                         k = FAMILY_ADDRESS_SIZE(family) * 8;
     707           2 :                         break;
     708           4 :                 case PREFIXLEN_REFUSE:
     709           4 :                         return -ENOANO; /* To distinguish this error from others. */
     710           4 :                 case PREFIXLEN_LEGACY:
     711           4 :                         if (family == AF_INET) {
     712           2 :                                 r = in4_addr_default_prefixlen(&buffer.in, &k);
     713           2 :                                 if (r < 0)
     714           0 :                                         return r;
     715             :                         } else
     716           2 :                                 k = 0;
     717           4 :                         break;
     718           0 :                 default:
     719           0 :                         assert_not_reached("Invalid prefixlen mode");
     720             :                 }
     721             : 
     722          68 :         if (ret_family)
     723          68 :                 *ret_family = family;
     724          68 :         if (ret_prefix)
     725          68 :                 *ret_prefix = buffer;
     726          68 :         if (ret_prefixlen)
     727          68 :                 *ret_prefixlen = k;
     728             : 
     729          68 :         return 0;
     730             : 
     731             : }
     732             : 
     733          79 : static void in_addr_data_hash_func(const struct in_addr_data *a, struct siphash *state) {
     734          79 :         siphash24_compress(&a->family, sizeof(a->family), state);
     735          79 :         siphash24_compress(&a->address, FAMILY_ADDRESS_SIZE(a->family), state);
     736          79 : }
     737             : 
     738          26 : static int in_addr_data_compare_func(const struct in_addr_data *x, const struct in_addr_data *y) {
     739             :         int r;
     740             : 
     741          26 :         r = CMP(x->family, y->family);
     742          26 :         if (r != 0)
     743           2 :                 return r;
     744             : 
     745          24 :         return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family));
     746             : }
     747             : 
     748             : DEFINE_HASH_OPS(in_addr_data_hash_ops, struct in_addr_data, in_addr_data_hash_func, in_addr_data_compare_func);
     749             : 
     750           0 : static void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state) {
     751           0 :         assert(addr);
     752             : 
     753           0 :         siphash24_compress(addr, sizeof(*addr), state);
     754           0 : }
     755             : 
     756           0 : static int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b) {
     757           0 :         return memcmp(a, b, sizeof(*a));
     758             : }
     759             : 
     760             : DEFINE_HASH_OPS(in6_addr_hash_ops, struct in6_addr, in6_addr_hash_func, in6_addr_compare_func);

Generated by: LCOV version 1.14