LCOV - code coverage report
Current view: top level - basic - in-addr-util.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 304 406 74.9 %
Date: 2019-08-23 13:36:53 Functions: 24 32 75.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 187 324 57.7 %

           Branch data     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                 :        344 : bool in4_addr_is_null(const struct in_addr *a) {
      21         [ -  + ]:        344 :         assert(a);
      22                 :            : 
      23                 :        344 :         return a->s_addr == 0;
      24                 :            : }
      25                 :            : 
      26                 :        472 : int in_addr_is_null(int family, const union in_addr_union *u) {
      27         [ -  + ]:        472 :         assert(u);
      28                 :            : 
      29         [ +  + ]:        472 :         if (family == AF_INET)
      30                 :        344 :                 return in4_addr_is_null(&u->in);
      31                 :            : 
      32         [ +  + ]:        128 :         if (family == AF_INET6)
      33   [ +  +  +  -  :        124 :                 return IN6_IS_ADDR_UNSPECIFIED(&u->in6);
             +  -  +  + ]
      34                 :            : 
      35                 :          4 :         return -EAFNOSUPPORT;
      36                 :            : }
      37                 :            : 
      38                 :         32 : bool in4_addr_is_link_local(const struct in_addr *a) {
      39         [ -  + ]:         32 :         assert(a);
      40                 :            : 
      41                 :         32 :         return (be32toh(a->s_addr) & UINT32_C(0xFFFF0000)) == (UINT32_C(169) << 24 | UINT32_C(254) << 16);
      42                 :            : }
      43                 :            : 
      44                 :         68 : int in_addr_is_link_local(int family, const union in_addr_union *u) {
      45         [ -  + ]:         68 :         assert(u);
      46                 :            : 
      47         [ +  + ]:         68 :         if (family == AF_INET)
      48                 :         32 :                 return in4_addr_is_link_local(&u->in);
      49                 :            : 
      50         [ +  - ]:         36 :         if (family == AF_INET6)
      51                 :         36 :                 return IN6_IS_ADDR_LINKLOCAL(&u->in6);
      52                 :            : 
      53                 :          0 :         return -EAFNOSUPPORT;
      54                 :            : }
      55                 :            : 
      56                 :         16 : int in_addr_is_multicast(int family, const union in_addr_union *u) {
      57         [ -  + ]:         16 :         assert(u);
      58                 :            : 
      59         [ +  + ]:         16 :         if (family == AF_INET)
      60                 :          8 :                 return IN_MULTICAST(be32toh(u->in.s_addr));
      61                 :            : 
      62         [ +  - ]:          8 :         if (family == AF_INET6)
      63                 :          8 :                 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                 :        148 : bool in4_addr_equal(const struct in_addr *a, const struct in_addr *b) {
      96         [ -  + ]:        148 :         assert(a);
      97         [ -  + ]:        148 :         assert(b);
      98                 :            : 
      99                 :        148 :         return a->s_addr == b->s_addr;
     100                 :            : }
     101                 :            : 
     102                 :        384 : int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b) {
     103         [ -  + ]:        384 :         assert(a);
     104         [ -  + ]:        384 :         assert(b);
     105                 :            : 
     106         [ +  + ]:        384 :         if (family == AF_INET)
     107                 :        148 :                 return in4_addr_equal(&a->in, &b->in);
     108                 :            : 
     109         [ +  - ]:        236 :         if (family == AF_INET6)
     110                 :            :                 return
     111                 :        472 :                         a->in6.s6_addr32[0] == b->in6.s6_addr32[0] &&
     112         [ +  - ]:        236 :                         a->in6.s6_addr32[1] == b->in6.s6_addr32[1] &&
     113   [ +  -  +  - ]:        708 :                         a->in6.s6_addr32[2] == b->in6.s6_addr32[2] &&
     114         [ +  - ]:        236 :                         a->in6.s6_addr32[3] == b->in6.s6_addr32[3];
     115                 :            : 
     116                 :          0 :         return -EAFNOSUPPORT;
     117                 :            : }
     118                 :            : 
     119                 :        172 : 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         [ -  + ]:        172 :         assert(a);
     129         [ -  + ]:        172 :         assert(b);
     130                 :            : 
     131                 :            :         /* Checks whether there are any addresses that are in both
     132                 :            :          * networks */
     133                 :            : 
     134                 :        172 :         m = MIN(aprefixlen, bprefixlen);
     135                 :            : 
     136         [ +  + ]:        172 :         if (family == AF_INET) {
     137                 :            :                 uint32_t x, nm;
     138                 :            : 
     139                 :         36 :                 x = be32toh(a->in.s_addr ^ b->in.s_addr);
     140         [ +  + ]:         36 :                 nm = (m == 0) ? 0 : 0xFFFFFFFFUL << (32 - m);
     141                 :            : 
     142                 :         36 :                 return (x & nm) == 0;
     143                 :            :         }
     144                 :            : 
     145         [ +  - ]:        136 :         if (family == AF_INET6) {
     146                 :            :                 unsigned i;
     147                 :            : 
     148         [ -  + ]:        136 :                 if (m > 128)
     149                 :          0 :                         m = 128;
     150                 :            : 
     151         [ +  + ]:       1572 :                 for (i = 0; i < 16; i++) {
     152                 :            :                         uint8_t x, nm;
     153                 :            : 
     154                 :       1504 :                         x = a->in6.s6_addr[i] ^ b->in6.s6_addr[i];
     155                 :            : 
     156         [ +  + ]:       1504 :                         if (m < 8)
     157                 :        616 :                                 nm = 0xFF << (8 - m);
     158                 :            :                         else
     159                 :        888 :                                 nm = 0xFF;
     160                 :            : 
     161         [ +  + ]:       1504 :                         if ((x & nm) != 0)
     162                 :         68 :                                 return 0;
     163                 :            : 
     164         [ +  + ]:       1436 :                         if (m > 8)
     165                 :        784 :                                 m -= 8;
     166                 :            :                         else
     167                 :        652 :                                 m = 0;
     168                 :            :                 }
     169                 :            : 
     170                 :         68 :                 return 1;
     171                 :            :         }
     172                 :            : 
     173                 :          0 :         return -EAFNOSUPPORT;
     174                 :            : }
     175                 :            : 
     176                 :         56 : int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen) {
     177         [ -  + ]:         56 :         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         [ -  + ]:         56 :         if (prefixlen <= 0)
     183                 :          0 :                 return 0;
     184                 :            : 
     185         [ +  + ]:         56 :         if (family == AF_INET) {
     186                 :            :                 uint32_t c, n;
     187                 :            : 
     188         [ -  + ]:         24 :                 if (prefixlen > 32)
     189                 :          0 :                         prefixlen = 32;
     190                 :            : 
     191                 :         24 :                 c = be32toh(u->in.s_addr);
     192                 :         24 :                 n = c + (1UL << (32 - prefixlen));
     193         [ +  + ]:         24 :                 if (n < c)
     194                 :          8 :                         return 0;
     195                 :         16 :                 n &= 0xFFFFFFFFUL << (32 - prefixlen);
     196                 :            : 
     197                 :         16 :                 u->in.s_addr = htobe32(n);
     198                 :         16 :                 return 1;
     199                 :            :         }
     200                 :            : 
     201         [ +  - ]:         32 :         if (family == AF_INET6) {
     202                 :         32 :                 struct in6_addr add = {}, result;
     203                 :         32 :                 uint8_t overflow = 0;
     204                 :            :                 unsigned i;
     205                 :            : 
     206         [ -  + ]:         32 :                 if (prefixlen > 128)
     207                 :          0 :                         prefixlen = 128;
     208                 :            : 
     209                 :            :                 /* First calculate what we have to add */
     210                 :         32 :                 add.s6_addr[(prefixlen-1) / 8] = 1 << (7 - (prefixlen-1) % 8);
     211                 :            : 
     212         [ +  + ]:        544 :                 for (i = 16; i > 0; i--) {
     213                 :        512 :                         unsigned j = i - 1;
     214                 :            : 
     215                 :        512 :                         result.s6_addr[j] = u->in6.s6_addr[j] + add.s6_addr[j] + overflow;
     216                 :        512 :                         overflow = (result.s6_addr[j] < u->in6.s6_addr[j]);
     217                 :            :                 }
     218                 :            : 
     219         [ +  + ]:         32 :                 if (overflow)
     220                 :          8 :                         return 0;
     221                 :            : 
     222                 :         24 :                 u->in6 = result;
     223                 :         24 :                 return 1;
     224                 :            :         }
     225                 :            : 
     226                 :          0 :         return -EAFNOSUPPORT;
     227                 :            : }
     228                 :            : 
     229                 :         28 : int in_addr_random_prefix(
     230                 :            :                 int family,
     231                 :            :                 union in_addr_union *u,
     232                 :            :                 unsigned prefixlen_fixed_part,
     233                 :            :                 unsigned prefixlen) {
     234                 :            : 
     235         [ -  + ]:         28 :         assert(u);
     236                 :            : 
     237                 :            :         /* Random network part of an address by one. */
     238                 :            : 
     239         [ -  + ]:         28 :         if (prefixlen <= 0)
     240                 :          0 :                 return 0;
     241                 :            : 
     242         [ +  + ]:         28 :         if (family == AF_INET) {
     243                 :            :                 uint32_t c, n;
     244                 :            : 
     245         [ -  + ]:         20 :                 if (prefixlen_fixed_part > 32)
     246                 :          0 :                         prefixlen_fixed_part = 32;
     247         [ -  + ]:         20 :                 if (prefixlen > 32)
     248                 :          0 :                         prefixlen = 32;
     249         [ -  + ]:         20 :                 if (prefixlen_fixed_part >= prefixlen)
     250                 :          0 :                         return -EINVAL;
     251                 :            : 
     252                 :         20 :                 c = be32toh(u->in.s_addr);
     253                 :         20 :                 c &= ((UINT32_C(1) << prefixlen_fixed_part) - 1) << (32 - prefixlen_fixed_part);
     254                 :            : 
     255                 :         20 :                 random_bytes(&n, sizeof(n));
     256                 :         20 :                 n &= ((UINT32_C(1) << (prefixlen - prefixlen_fixed_part)) - 1) << (32 - prefixlen);
     257                 :            : 
     258                 :         20 :                 u->in.s_addr = htobe32(n | c);
     259                 :         20 :                 return 1;
     260                 :            :         }
     261                 :            : 
     262         [ +  - ]:          8 :         if (family == AF_INET6) {
     263                 :            :                 struct in6_addr n;
     264                 :            :                 unsigned i, j;
     265                 :            : 
     266         [ -  + ]:          8 :                 if (prefixlen_fixed_part > 128)
     267                 :          0 :                         prefixlen_fixed_part = 128;
     268         [ -  + ]:          8 :                 if (prefixlen > 128)
     269                 :          0 :                         prefixlen = 128;
     270         [ -  + ]:          8 :                 if (prefixlen_fixed_part >= prefixlen)
     271                 :          0 :                         return -EINVAL;
     272                 :            : 
     273                 :          8 :                 random_bytes(&n, sizeof(n));
     274                 :            : 
     275         [ +  + ]:        136 :                 for (i = 0; i < 16; i++) {
     276                 :        128 :                         uint8_t mask_fixed_part = 0, mask = 0;
     277                 :            : 
     278         [ +  + ]:        128 :                         if (i < (prefixlen_fixed_part + 7) / 8) {
     279         [ +  - ]:         12 :                                 if (i < prefixlen_fixed_part / 8)
     280                 :         12 :                                         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         [ +  + ]:        128 :                         if (i < (prefixlen + 7) / 8) {
     288         [ +  - ]:         40 :                                 if (i < prefixlen / 8)
     289                 :         40 :                                         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                 :        128 :                         u->in6.s6_addr[i] &= mask_fixed_part;
     297                 :        128 :                         u->in6.s6_addr[i] |= n.s6_addr[i] & mask;
     298                 :            :                 }
     299                 :            : 
     300                 :          8 :                 return 1;
     301                 :            :         }
     302                 :            : 
     303                 :          0 :         return -EAFNOSUPPORT;
     304                 :            : }
     305                 :            : 
     306                 :        892 : int in_addr_to_string(int family, const union in_addr_union *u, char **ret) {
     307                 :        892 :         _cleanup_free_ char *x = NULL;
     308                 :            :         size_t l;
     309                 :            : 
     310         [ -  + ]:        892 :         assert(u);
     311         [ -  + ]:        892 :         assert(ret);
     312                 :            : 
     313         [ +  + ]:        892 :         if (family == AF_INET)
     314                 :        524 :                 l = INET_ADDRSTRLEN;
     315         [ +  - ]:        368 :         else if (family == AF_INET6)
     316                 :        368 :                 l = INET6_ADDRSTRLEN;
     317                 :            :         else
     318                 :          0 :                 return -EAFNOSUPPORT;
     319                 :            : 
     320                 :        892 :         x = new(char, l);
     321         [ -  + ]:        892 :         if (!x)
     322                 :          0 :                 return -ENOMEM;
     323                 :            : 
     324                 :        892 :         errno = 0;
     325         [ -  + ]:        892 :         if (!inet_ntop(family, u, x, l))
     326                 :          0 :                 return errno_or_else(EINVAL);
     327                 :            : 
     328                 :        892 :         *ret = TAKE_PTR(x);
     329                 :        892 :         return 0;
     330                 :            : }
     331                 :            : 
     332                 :        132 : int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret) {
     333                 :        132 :         _cleanup_free_ char *x = NULL;
     334                 :            :         char *p;
     335                 :            :         size_t l;
     336                 :            : 
     337         [ -  + ]:        132 :         assert(u);
     338         [ -  + ]:        132 :         assert(ret);
     339                 :            : 
     340         [ +  + ]:        132 :         if (family == AF_INET)
     341                 :         92 :                 l = INET_ADDRSTRLEN + 3;
     342         [ +  - ]:         40 :         else if (family == AF_INET6)
     343                 :         40 :                 l = INET6_ADDRSTRLEN + 4;
     344                 :            :         else
     345                 :          0 :                 return -EAFNOSUPPORT;
     346                 :            : 
     347         [ -  + ]:        132 :         if (prefixlen > FAMILY_ADDRESS_SIZE(family) * 8)
     348                 :          0 :                 return -EINVAL;
     349                 :            : 
     350                 :        132 :         x = new(char, l);
     351         [ -  + ]:        132 :         if (!x)
     352                 :          0 :                 return -ENOMEM;
     353                 :            : 
     354                 :        132 :         errno = 0;
     355         [ -  + ]:        132 :         if (!inet_ntop(family, u, x, l))
     356                 :          0 :                 return errno_or_else(EINVAL);
     357                 :            : 
     358                 :        132 :         p = x + strlen(x);
     359                 :        132 :         l -= strlen(x);
     360                 :        132 :         (void) strpcpyf(&p, l, "/%u", prefixlen);
     361                 :            : 
     362                 :        132 :         *ret = TAKE_PTR(x);
     363                 :        132 :         return 0;
     364                 :            : }
     365                 :            : 
     366                 :         36 : int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret) {
     367                 :         36 :         _cleanup_free_ char *x = NULL;
     368                 :            :         size_t l;
     369                 :            :         int r;
     370                 :            : 
     371         [ -  + ]:         36 :         assert(u);
     372         [ -  + ]:         36 :         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         [ +  + ]:         36 :         if (family != AF_INET6)
     378                 :          8 :                 goto fallback;
     379         [ +  + ]:         28 :         if (ifindex <= 0)
     380                 :          8 :                 goto fallback;
     381                 :            : 
     382                 :         20 :         r = in_addr_is_link_local(family, u);
     383         [ -  + ]:         20 :         if (r < 0)
     384                 :          0 :                 return r;
     385         [ +  + ]:         20 :         if (r == 0)
     386                 :          8 :                 goto fallback;
     387                 :            : 
     388                 :         12 :         l = INET6_ADDRSTRLEN + 1 + DECIMAL_STR_MAX(ifindex) + 1;
     389                 :         12 :         x = new(char, l);
     390         [ -  + ]:         12 :         if (!x)
     391                 :          0 :                 return -ENOMEM;
     392                 :            : 
     393                 :         12 :         errno = 0;
     394         [ -  + ]:         12 :         if (!inet_ntop(family, u, x, l))
     395                 :          0 :                 return errno_or_else(EINVAL);
     396                 :            : 
     397                 :         12 :         sprintf(strchr(x, 0), "%%%i", ifindex);
     398                 :            : 
     399                 :         12 :         *ret = TAKE_PTR(x);
     400                 :         12 :         return 0;
     401                 :            : 
     402                 :         24 : fallback:
     403                 :         24 :         return in_addr_to_string(family, u, ret);
     404                 :            : }
     405                 :            : 
     406                 :       1816 : int in_addr_from_string(int family, const char *s, union in_addr_union *ret) {
     407                 :            :         union in_addr_union buffer;
     408         [ -  + ]:       1816 :         assert(s);
     409                 :            : 
     410   [ +  -  -  + ]:       1816 :         if (!IN_SET(family, AF_INET, AF_INET6))
     411                 :          0 :                 return -EAFNOSUPPORT;
     412                 :            : 
     413                 :       1816 :         errno = 0;
     414   [ +  +  +  + ]:       1816 :         if (inet_pton(family, s, ret ?: &buffer) <= 0)
     415                 :        536 :                 return errno_or_else(EINVAL);
     416                 :            : 
     417                 :       1280 :         return 0;
     418                 :            : }
     419                 :            : 
     420                 :        672 : int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret) {
     421                 :            :         int r;
     422                 :            : 
     423         [ -  + ]:        672 :         assert(s);
     424                 :            : 
     425                 :        672 :         r = in_addr_from_string(AF_INET, s, ret);
     426         [ +  + ]:        672 :         if (r >= 0) {
     427         [ +  + ]:        300 :                 if (ret_family)
     428                 :        296 :                         *ret_family = AF_INET;
     429                 :        300 :                 return 0;
     430                 :            :         }
     431                 :            : 
     432                 :        372 :         r = in_addr_from_string(AF_INET6, s, ret);
     433         [ +  + ]:        372 :         if (r >= 0) {
     434         [ +  + ]:        256 :                 if (ret_family)
     435                 :        248 :                         *ret_family = AF_INET6;
     436                 :        256 :                 return 0;
     437                 :            :         }
     438                 :            : 
     439                 :        116 :         return -EINVAL;
     440                 :            : }
     441                 :            : 
     442                 :        168 : int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex) {
     443                 :        168 :         _cleanup_free_ char *buf = NULL;
     444                 :            :         const char *suffix;
     445                 :        168 :         int r, ifi = 0;
     446                 :            : 
     447         [ -  + ]:        168 :         assert(s);
     448         [ -  + ]:        168 :         assert(family);
     449         [ -  + ]:        168 :         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                 :        168 :         suffix = strchr(s, '%');
     455         [ +  + ]:        168 :         if (suffix) {
     456                 :            : 
     457         [ +  - ]:         24 :                 if (ifindex) {
     458                 :            :                         /* If we shall return the interface index, try to parse it */
     459                 :         24 :                         r = parse_ifindex(suffix + 1, &ifi);
     460         [ +  + ]:         24 :                         if (r < 0) {
     461                 :            :                                 unsigned u;
     462                 :            : 
     463                 :          8 :                                 u = if_nametoindex(suffix + 1);
     464         [ +  + ]:          8 :                                 if (u <= 0)
     465                 :          4 :                                         return -errno;
     466                 :            : 
     467                 :          4 :                                 ifi = (int) u;
     468                 :            :                         }
     469                 :            :                 }
     470                 :            : 
     471                 :         20 :                 buf = strndup(s, suffix - s);
     472         [ -  + ]:         20 :                 if (!buf)
     473                 :          0 :                         return -ENOMEM;
     474                 :            : 
     475                 :         20 :                 s = buf;
     476                 :            :         }
     477                 :            : 
     478                 :        164 :         r = in_addr_from_string_auto(s, family, ret);
     479         [ +  + ]:        164 :         if (r < 0)
     480                 :         12 :                 return r;
     481                 :            : 
     482         [ +  + ]:        152 :         if (ifindex)
     483                 :         48 :                 *ifindex = ifi;
     484                 :            : 
     485                 :        152 :         return r;
     486                 :            : }
     487                 :            : 
     488                 :         44 : unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr) {
     489         [ -  + ]:         44 :         assert(addr);
     490                 :            : 
     491                 :         44 :         return 32U - u32ctz(be32toh(addr->s_addr));
     492                 :            : }
     493                 :            : 
     494                 :         12 : struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) {
     495         [ -  + ]:         12 :         assert(addr);
     496         [ -  + ]:         12 :         assert(prefixlen <= 32);
     497                 :            : 
     498                 :            :         /* Shifting beyond 32 is not defined, handle this specially. */
     499         [ -  + ]:         12 :         if (prefixlen == 0)
     500                 :          0 :                 addr->s_addr = 0;
     501                 :            :         else
     502                 :         12 :                 addr->s_addr = htobe32((0xffffffff << (32 - prefixlen)) & 0xffffffff);
     503                 :            : 
     504                 :         12 :         return addr;
     505                 :            : }
     506                 :            : 
     507                 :          8 : int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) {
     508                 :          8 :         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         [ -  + ]:          8 :         assert(addr);
     513         [ -  + ]:          8 :         assert(prefixlen);
     514                 :            : 
     515         [ +  - ]:          8 :         if (msb_octet < 128)
     516                 :            :                 /* class A, leading bits: 0 */
     517                 :          8 :                 *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                 :          8 :         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                 :        396 : int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret) {
     607                 :            :         uint8_t u;
     608                 :            :         int r;
     609                 :            : 
     610   [ +  -  -  + ]:        396 :         if (!IN_SET(family, AF_INET, AF_INET6))
     611                 :          0 :                 return -EAFNOSUPPORT;
     612                 :            : 
     613                 :        396 :         r = safe_atou8(p, &u);
     614         [ +  + ]:        396 :         if (r < 0)
     615                 :         16 :                 return r;
     616                 :            : 
     617         [ +  + ]:        380 :         if (u > FAMILY_ADDRESS_SIZE(family) * 8)
     618                 :         16 :                 return -ERANGE;
     619                 :            : 
     620                 :        364 :         *ret = u;
     621                 :        364 :         return 0;
     622                 :            : }
     623                 :            : 
     624                 :        176 : 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                 :        176 :         _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         [ -  + ]:        176 :         assert(p);
     637                 :            : 
     638   [ +  -  -  + ]:        176 :         if (!IN_SET(family, AF_INET, AF_INET6))
     639                 :          0 :                 return -EAFNOSUPPORT;
     640                 :            : 
     641                 :        176 :         e = strchr(p, '/');
     642         [ +  + ]:        176 :         if (e) {
     643                 :        148 :                 str = strndup(p, e - p);
     644         [ -  + ]:        148 :                 if (!str)
     645                 :          0 :                         return -ENOMEM;
     646                 :            : 
     647                 :        148 :                 l = str;
     648                 :            :         } else
     649                 :         28 :                 l = p;
     650                 :            : 
     651                 :        176 :         r = in_addr_from_string(family, l, &buffer);
     652         [ +  + ]:        176 :         if (r < 0)
     653                 :         28 :                 return r;
     654                 :            : 
     655         [ +  + ]:        148 :         if (e) {
     656                 :        132 :                 r = in_addr_parse_prefixlen(family, e+1, &k);
     657         [ +  + ]:        132 :                 if (r < 0)
     658                 :         16 :                         return r;
     659                 :            :         } else
     660                 :         16 :                 k = FAMILY_ADDRESS_SIZE(family) * 8;
     661                 :            : 
     662         [ +  - ]:        132 :         if (ret_prefix)
     663                 :        132 :                 *ret_prefix = buffer;
     664         [ +  - ]:        132 :         if (ret_prefixlen)
     665                 :        132 :                 *ret_prefixlen = k;
     666                 :            : 
     667                 :        132 :         return 0;
     668                 :            : }
     669                 :            : 
     670                 :        328 : 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                 :        328 :         _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         [ -  + ]:        328 :         assert(p);
     684                 :            : 
     685                 :        328 :         e = strchr(p, '/');
     686         [ +  + ]:        328 :         if (e) {
     687                 :        280 :                 str = strndup(p, e - p);
     688         [ -  + ]:        280 :                 if (!str)
     689                 :          0 :                         return -ENOMEM;
     690                 :            : 
     691                 :        280 :                 l = str;
     692                 :            :         } else
     693                 :         48 :                 l = p;
     694                 :            : 
     695                 :        328 :         r = in_addr_from_string_auto(l, &family, &buffer);
     696         [ +  + ]:        328 :         if (r < 0)
     697                 :         24 :                 return r;
     698                 :            : 
     699         [ +  + ]:        304 :         if (e) {
     700                 :        264 :                 r = in_addr_parse_prefixlen(family, e+1, &k);
     701         [ +  + ]:        264 :                 if (r < 0)
     702                 :         16 :                         return r;
     703                 :            :         } else
     704   [ +  +  +  - ]:         40 :                 switch (mode) {
     705                 :          8 :                 case PREFIXLEN_FULL:
     706                 :          8 :                         k = FAMILY_ADDRESS_SIZE(family) * 8;
     707                 :          8 :                         break;
     708                 :         16 :                 case PREFIXLEN_REFUSE:
     709                 :         16 :                         return -ENOANO; /* To distinguish this error from others. */
     710                 :         16 :                 case PREFIXLEN_LEGACY:
     711         [ +  + ]:         16 :                         if (family == AF_INET) {
     712                 :          8 :                                 r = in4_addr_default_prefixlen(&buffer.in, &k);
     713         [ -  + ]:          8 :                                 if (r < 0)
     714                 :          0 :                                         return r;
     715                 :            :                         } else
     716                 :          8 :                                 k = 0;
     717                 :         16 :                         break;
     718                 :          0 :                 default:
     719                 :          0 :                         assert_not_reached("Invalid prefixlen mode");
     720                 :            :                 }
     721                 :            : 
     722         [ +  - ]:        272 :         if (ret_family)
     723                 :        272 :                 *ret_family = family;
     724         [ +  - ]:        272 :         if (ret_prefix)
     725                 :        272 :                 *ret_prefix = buffer;
     726         [ +  - ]:        272 :         if (ret_prefixlen)
     727                 :        272 :                 *ret_prefixlen = k;
     728                 :            : 
     729                 :        272 :         return 0;
     730                 :            : 
     731                 :            : }
     732                 :            : 
     733                 :        316 : static void in_addr_data_hash_func(const struct in_addr_data *a, struct siphash *state) {
     734                 :        316 :         siphash24_compress(&a->family, sizeof(a->family), state);
     735                 :        316 :         siphash24_compress(&a->address, FAMILY_ADDRESS_SIZE(a->family), state);
     736                 :        316 : }
     737                 :            : 
     738                 :        128 : static int in_addr_data_compare_func(const struct in_addr_data *x, const struct in_addr_data *y) {
     739                 :            :         int r;
     740                 :            : 
     741         [ +  + ]:        128 :         r = CMP(x->family, y->family);
     742         [ +  + ]:        128 :         if (r != 0)
     743                 :         20 :                 return r;
     744                 :            : 
     745                 :        108 :         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