LCOV - code coverage report
Current view: top level - shared - local-addresses.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 122 167 73.1 %
Date: 2019-08-22 15:41:25 Functions: 3 3 100.0 %

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

Generated by: LCOV version 1.14