LCOV - code coverage report
Current view: top level - shared - local-addresses.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 117 167 70.1 %
Date: 2019-08-23 13:36:53 Functions: 3 3 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 67 130 51.5 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include "sd-netlink.h"
       4                 :            : 
       5                 :            : #include "alloc-util.h"
       6                 :            : #include "local-addresses.h"
       7                 :            : #include "macro.h"
       8                 :            : #include "netlink-util.h"
       9                 :            : #include "sort-util.h"
      10                 :            : 
      11                 :         44 : static int address_compare(const struct local_address *a, const struct local_address *b) {
      12                 :            :         int r;
      13                 :            : 
      14                 :            :         /* Order lowest scope first, IPv4 before IPv6, lowest interface index first */
      15                 :            : 
      16   [ +  +  -  + ]:         44 :         if (a->family == AF_INET && b->family == AF_INET6)
      17                 :          0 :                 return -1;
      18   [ +  +  +  + ]:         44 :         if (a->family == AF_INET6 && b->family == AF_INET)
      19                 :         16 :                 return 1;
      20                 :            : 
      21         [ +  - ]:         28 :         r = CMP(a->scope, b->scope);
      22         [ -  + ]:         28 :         if (r != 0)
      23                 :          0 :                 return r;
      24                 :            : 
      25         [ +  - ]:         28 :         r = CMP(a->metric, b->metric);
      26         [ -  + ]:         28 :         if (r != 0)
      27                 :          0 :                 return r;
      28                 :            : 
      29         [ +  - ]:         28 :         r = CMP(a->ifindex, b->ifindex);
      30         [ +  - ]:         28 :         if (r != 0)
      31                 :         28 :                 return r;
      32                 :            : 
      33                 :          0 :         return memcmp(&a->address, &b->address, FAMILY_ADDRESS_SIZE(a->family));
      34                 :            : }
      35                 :            : 
      36                 :          4 : int local_addresses(sd_netlink *context, int ifindex, int af, struct local_address **ret) {
      37                 :          4 :         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
      38                 :          4 :         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
      39                 :          4 :         _cleanup_free_ struct local_address *list = NULL;
      40                 :          4 :         size_t n_list = 0, n_allocated = 0;
      41                 :            :         sd_netlink_message *m;
      42                 :            :         int r;
      43                 :            : 
      44         [ -  + ]:          4 :         assert(ret);
      45                 :            : 
      46         [ -  + ]:          4 :         if (context)
      47                 :          0 :                 rtnl = sd_netlink_ref(context);
      48                 :            :         else {
      49                 :          4 :                 r = sd_netlink_open(&rtnl);
      50         [ -  + ]:          4 :                 if (r < 0)
      51                 :          0 :                         return r;
      52                 :            :         }
      53                 :            : 
      54                 :          4 :         r = sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, af);
      55         [ -  + ]:          4 :         if (r < 0)
      56                 :          0 :                 return r;
      57                 :            : 
      58                 :          4 :         r = sd_netlink_call(rtnl, req, 0, &reply);
      59         [ -  + ]:          4 :         if (r < 0)
      60                 :          0 :                 return r;
      61                 :            : 
      62         [ +  + ]:         40 :         for (m = reply; m; m = sd_netlink_message_next(m)) {
      63                 :            :                 struct local_address *a;
      64                 :            :                 unsigned char flags;
      65                 :            :                 uint16_t type;
      66                 :            :                 int ifi, family;
      67                 :            : 
      68                 :         36 :                 r = sd_netlink_message_get_errno(m);
      69         [ -  + ]:         36 :                 if (r < 0)
      70                 :          0 :                         return r;
      71                 :            : 
      72                 :         36 :                 r = sd_netlink_message_get_type(m, &type);
      73         [ -  + ]:         36 :                 if (r < 0)
      74                 :          0 :                         return r;
      75         [ -  + ]:         36 :                 if (type != RTM_NEWADDR)
      76                 :          8 :                         continue;
      77                 :            : 
      78                 :         36 :                 r = sd_rtnl_message_addr_get_ifindex(m, &ifi);
      79         [ -  + ]:         36 :                 if (r < 0)
      80                 :          0 :                         return r;
      81   [ -  +  #  # ]:         36 :                 if (ifindex > 0 && ifi != ifindex)
      82                 :          0 :                         continue;
      83                 :            : 
      84                 :         36 :                 r = sd_rtnl_message_addr_get_family(m, &family);
      85         [ -  + ]:         36 :                 if (r < 0)
      86                 :          0 :                         return r;
      87   [ -  +  #  # ]:         36 :                 if (af != AF_UNSPEC && af != family)
      88                 :          0 :                         continue;
      89                 :            : 
      90                 :         36 :                 r = sd_rtnl_message_addr_get_flags(m, &flags);
      91         [ -  + ]:         36 :                 if (r < 0)
      92                 :          0 :                         return r;
      93         [ -  + ]:         36 :                 if (flags & IFA_F_DEPRECATED)
      94                 :          0 :                         continue;
      95                 :            : 
      96         [ -  + ]:         36 :                 if (!GREEDY_REALLOC0(list, n_allocated, n_list+1))
      97                 :          0 :                         return -ENOMEM;
      98                 :            : 
      99                 :         36 :                 a = list + n_list;
     100                 :            : 
     101                 :         36 :                 r = sd_rtnl_message_addr_get_scope(m, &a->scope);
     102         [ -  + ]:         36 :                 if (r < 0)
     103                 :          0 :                         return r;
     104                 :            : 
     105   [ +  -  +  +  :         36 :                 if (ifindex == 0 && IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))
                   +  + ]
     106                 :          8 :                         continue;
     107                 :            : 
     108      [ +  +  - ]:         28 :                 switch (family) {
     109                 :            : 
     110                 :         16 :                 case AF_INET:
     111                 :         16 :                         r = sd_netlink_message_read_in_addr(m, IFA_LOCAL, &a->address.in);
     112         [ -  + ]:         16 :                         if (r < 0) {
     113                 :          0 :                                 r = sd_netlink_message_read_in_addr(m, IFA_ADDRESS, &a->address.in);
     114         [ #  # ]:          0 :                                 if (r < 0)
     115                 :          0 :                                         continue;
     116                 :            :                         }
     117                 :         16 :                         break;
     118                 :            : 
     119                 :         12 :                 case AF_INET6:
     120                 :         12 :                         r = sd_netlink_message_read_in6_addr(m, IFA_LOCAL, &a->address.in6);
     121         [ +  - ]:         12 :                         if (r < 0) {
     122                 :         12 :                                 r = sd_netlink_message_read_in6_addr(m, IFA_ADDRESS, &a->address.in6);
     123         [ -  + ]:         12 :                                 if (r < 0)
     124                 :          0 :                                         continue;
     125                 :            :                         }
     126                 :         12 :                         break;
     127                 :            : 
     128                 :          0 :                 default:
     129                 :          0 :                         continue;
     130                 :            :                 }
     131                 :            : 
     132                 :         28 :                 a->ifindex = ifi;
     133                 :         28 :                 a->family = family;
     134                 :            : 
     135                 :         28 :                 n_list++;
     136                 :            :         };
     137                 :            : 
     138                 :          4 :         typesafe_qsort(list, n_list, address_compare);
     139                 :            : 
     140                 :          4 :         *ret = TAKE_PTR(list);
     141                 :            : 
     142                 :          4 :         return (int) n_list;
     143                 :            : }
     144                 :            : 
     145                 :          4 : int local_gateways(sd_netlink *context, int ifindex, int af, struct local_address **ret) {
     146                 :          4 :         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
     147                 :          4 :         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
     148                 :          4 :         _cleanup_free_ struct local_address *list = NULL;
     149                 :          4 :         sd_netlink_message *m = NULL;
     150                 :          4 :         size_t n_list = 0, n_allocated = 0;
     151                 :            :         int r;
     152                 :            : 
     153         [ -  + ]:          4 :         assert(ret);
     154                 :            : 
     155         [ -  + ]:          4 :         if (context)
     156                 :          0 :                 rtnl = sd_netlink_ref(context);
     157                 :            :         else {
     158                 :          4 :                 r = sd_netlink_open(&rtnl);
     159         [ -  + ]:          4 :                 if (r < 0)
     160                 :          0 :                         return r;
     161                 :            :         }
     162                 :            : 
     163                 :          4 :         r = sd_rtnl_message_new_route(rtnl, &req, RTM_GETROUTE, af, RTPROT_UNSPEC);
     164         [ -  + ]:          4 :         if (r < 0)
     165                 :          0 :                 return r;
     166                 :            : 
     167                 :          4 :         r = sd_netlink_message_request_dump(req, true);
     168         [ -  + ]:          4 :         if (r < 0)
     169                 :          0 :                 return r;
     170                 :            : 
     171                 :          4 :         r = sd_netlink_call(rtnl, req, 0, &reply);
     172         [ -  + ]:          4 :         if (r < 0)
     173                 :          0 :                 return r;
     174                 :            : 
     175         [ +  + ]:        140 :         for (m = reply; m; m = sd_netlink_message_next(m)) {
     176                 :            :                 struct local_address *a;
     177                 :            :                 uint16_t type;
     178                 :            :                 unsigned char dst_len, src_len, table;
     179                 :            :                 uint32_t ifi;
     180                 :            :                 int family;
     181                 :            : 
     182                 :        136 :                 r = sd_netlink_message_get_errno(m);
     183         [ -  + ]:        136 :                 if (r < 0)
     184                 :          0 :                         return r;
     185                 :            : 
     186                 :        136 :                 r = sd_netlink_message_get_type(m, &type);
     187         [ -  + ]:        136 :                 if (r < 0)
     188                 :          0 :                         return r;
     189         [ -  + ]:        136 :                 if (type != RTM_NEWROUTE)
     190                 :        132 :                         continue;
     191                 :            : 
     192                 :            :                 /* We only care for default routes */
     193                 :        136 :                 r = sd_rtnl_message_route_get_dst_prefixlen(m, &dst_len);
     194         [ -  + ]:        136 :                 if (r < 0)
     195                 :          0 :                         return r;
     196         [ +  + ]:        136 :                 if (dst_len != 0)
     197                 :        132 :                         continue;
     198                 :            : 
     199                 :          4 :                 r = sd_rtnl_message_route_get_src_prefixlen(m, &src_len);
     200         [ -  + ]:          4 :                 if (r < 0)
     201                 :          0 :                         return r;
     202         [ -  + ]:          4 :                 if (src_len != 0)
     203                 :          0 :                         continue;
     204                 :            : 
     205                 :          4 :                 r = sd_rtnl_message_route_get_table(m, &table);
     206         [ -  + ]:          4 :                 if (r < 0)
     207                 :          0 :                         return r;
     208         [ -  + ]:          4 :                 if (table != RT_TABLE_MAIN)
     209                 :          0 :                         continue;
     210                 :            : 
     211                 :          4 :                 r = sd_netlink_message_read_u32(m, RTA_OIF, &ifi);
     212         [ -  + ]:          4 :                 if (r == -ENODATA) /* Not all routes have an RTA_OIF attribute (for example nexthop ones) */
     213                 :          0 :                         continue;
     214         [ -  + ]:          4 :                 if (r < 0)
     215                 :          0 :                         return r;
     216   [ -  +  #  # ]:          4 :                 if (ifindex > 0 && (int) ifi != ifindex)
     217                 :          0 :                         continue;
     218                 :            : 
     219                 :          4 :                 r = sd_rtnl_message_route_get_family(m, &family);
     220         [ -  + ]:          4 :                 if (r < 0)
     221                 :          0 :                         return r;
     222   [ -  +  #  # ]:          4 :                 if (af != AF_UNSPEC && af != family)
     223                 :          0 :                         continue;
     224                 :            : 
     225         [ -  + ]:          4 :                 if (!GREEDY_REALLOC0(list, n_allocated, n_list + 1))
     226                 :          0 :                         return -ENOMEM;
     227                 :            : 
     228                 :          4 :                 a = list + n_list;
     229                 :            : 
     230      [ +  -  - ]:          4 :                 switch (family) {
     231                 :          4 :                 case AF_INET:
     232                 :          4 :                         r = sd_netlink_message_read_in_addr(m, RTA_GATEWAY, &a->address.in);
     233         [ -  + ]:          4 :                         if (r < 0)
     234                 :          0 :                                 continue;
     235                 :            : 
     236                 :          4 :                         break;
     237                 :          0 :                 case AF_INET6:
     238                 :          0 :                         r = sd_netlink_message_read_in6_addr(m, RTA_GATEWAY, &a->address.in6);
     239         [ #  # ]:          0 :                         if (r < 0)
     240                 :          0 :                                 continue;
     241                 :            : 
     242                 :          0 :                         break;
     243                 :          0 :                 default:
     244                 :          0 :                         continue;
     245                 :            :                 }
     246                 :            : 
     247                 :          4 :                 sd_netlink_message_read_u32(m, RTA_PRIORITY, &a->metric);
     248                 :            : 
     249                 :          4 :                 a->ifindex = ifi;
     250                 :          4 :                 a->family = family;
     251                 :            : 
     252                 :          4 :                 n_list++;
     253                 :            :         }
     254                 :            : 
     255                 :          4 :         typesafe_qsort(list, n_list, address_compare);
     256                 :            : 
     257                 :          4 :         *ret = TAKE_PTR(list);
     258                 :            : 
     259                 :          4 :         return (int) n_list;
     260                 :            : }

Generated by: LCOV version 1.14