LCOV - code coverage report
Current view: top level - libsystemd/sd-netlink - local-addresses.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 119 162 73.5 %
Date: 2015-07-29 18:47:03 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2008-2011 Lennart Poettering
       7             :   Copyright 2014 Tom Gundersen
       8             : 
       9             :   systemd is free software; you can redistribute it and/or modify it
      10             :   under the terms of the GNU Lesser General Public License as published by
      11             :   the Free Software Foundation; either version 2.1 of the License, or
      12             :   (at your option) any later version.
      13             : 
      14             :   systemd is distributed in the hope that it will be useful, but
      15             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      17             :   Lesser General Public License for more details.
      18             : 
      19             :   You should have received a copy of the GNU Lesser General Public License
      20             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      21             : ***/
      22             : 
      23             : #include "sd-netlink.h"
      24             : #include "netlink-util.h"
      25             : #include "macro.h"
      26             : #include "local-addresses.h"
      27             : 
      28           4 : static int address_compare(const void *_a, const void *_b) {
      29           4 :         const struct local_address *a = _a, *b = _b;
      30             : 
      31             :         /* Order lowest scope first, IPv4 before IPv6, lowest interface index first */
      32             : 
      33           4 :         if (a->family == AF_INET && b->family == AF_INET6)
      34           0 :                 return -1;
      35           4 :         if (a->family == AF_INET6 && b->family == AF_INET)
      36           2 :                 return 1;
      37             : 
      38           2 :         if (a->scope < b->scope)
      39           0 :                 return -1;
      40           2 :         if (a->scope > b->scope)
      41           1 :                 return 1;
      42             : 
      43           1 :         if (a->metric < b->metric)
      44           0 :                 return -1;
      45           1 :         if (a->metric > b->metric)
      46           0 :                 return 1;
      47             : 
      48           1 :         if (a->ifindex < b->ifindex)
      49           0 :                 return -1;
      50           1 :         if (a->ifindex > b->ifindex)
      51           1 :                 return 1;
      52             : 
      53           0 :         return memcmp(&a->address, &b->address, FAMILY_ADDRESS_SIZE(a->family));
      54             : }
      55             : 
      56           1 : int local_addresses(sd_netlink *context, int ifindex, int af, struct local_address **ret) {
      57           2 :         _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
      58           2 :         _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
      59           2 :         _cleanup_free_ struct local_address *list = NULL;
      60           1 :         size_t n_list = 0, n_allocated = 0;
      61             :         sd_netlink_message *m;
      62             :         int r;
      63             : 
      64           1 :         assert(ret);
      65             : 
      66           1 :         if (context)
      67           0 :                 rtnl = sd_netlink_ref(context);
      68             :         else {
      69           1 :                 r = sd_netlink_open(&rtnl);
      70           1 :                 if (r < 0)
      71           0 :                         return r;
      72             :         }
      73             : 
      74           1 :         r = sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, af);
      75           1 :         if (r < 0)
      76           0 :                 return r;
      77             : 
      78           1 :         r = sd_netlink_call(rtnl, req, 0, &reply);
      79           1 :         if (r < 0)
      80           0 :                 return r;
      81             : 
      82           7 :         for (m = reply; m; m = sd_netlink_message_next(m)) {
      83             :                 struct local_address *a;
      84             :                 unsigned char flags;
      85             :                 uint16_t type;
      86             :                 int ifi, family;
      87             : 
      88           6 :                 r = sd_netlink_message_get_errno(m);
      89           6 :                 if (r < 0)
      90           0 :                         return r;
      91             : 
      92           6 :                 r = sd_netlink_message_get_type(m, &type);
      93           6 :                 if (r < 0)
      94           0 :                         return r;
      95           6 :                 if (type != RTM_NEWADDR)
      96           2 :                         continue;
      97             : 
      98           6 :                 r = sd_rtnl_message_addr_get_ifindex(m, &ifi);
      99           6 :                 if (r < 0)
     100           0 :                         return r;
     101           6 :                 if (ifindex > 0 && ifi != ifindex)
     102           0 :                         continue;
     103             : 
     104           6 :                 r = sd_rtnl_message_addr_get_family(m, &family);
     105           6 :                 if (r < 0)
     106           0 :                         return r;
     107           6 :                 if (af != AF_UNSPEC && af != family)
     108           0 :                         continue;
     109             : 
     110           6 :                 r = sd_rtnl_message_addr_get_flags(m, &flags);
     111           6 :                 if (r < 0)
     112           0 :                         return r;
     113           6 :                 if (flags & IFA_F_DEPRECATED)
     114           0 :                         continue;
     115             : 
     116           6 :                 if (!GREEDY_REALLOC0(list, n_allocated, n_list+1))
     117           0 :                         return -ENOMEM;
     118             : 
     119           6 :                 a = list + n_list;
     120             : 
     121           6 :                 r = sd_rtnl_message_addr_get_scope(m, &a->scope);
     122           6 :                 if (r < 0)
     123           0 :                         return r;
     124             : 
     125           6 :                 if (ifindex == 0 && (a->scope == RT_SCOPE_HOST || a->scope == RT_SCOPE_NOWHERE))
     126           2 :                         continue;
     127             : 
     128           4 :                 switch (family) {
     129             : 
     130             :                 case AF_INET:
     131           2 :                         r = sd_netlink_message_read_in_addr(m, IFA_LOCAL, &a->address.in);
     132           2 :                         if (r < 0) {
     133           0 :                                 r = sd_netlink_message_read_in_addr(m, IFA_ADDRESS, &a->address.in);
     134           0 :                                 if (r < 0)
     135           0 :                                         continue;
     136             :                         }
     137           2 :                         break;
     138             : 
     139             :                 case AF_INET6:
     140           2 :                         r = sd_netlink_message_read_in6_addr(m, IFA_LOCAL, &a->address.in6);
     141           2 :                         if (r < 0) {
     142           2 :                                 r = sd_netlink_message_read_in6_addr(m, IFA_ADDRESS, &a->address.in6);
     143           2 :                                 if (r < 0)
     144           0 :                                         continue;
     145             :                         }
     146           2 :                         break;
     147             : 
     148             :                 default:
     149           0 :                         continue;
     150             :                 }
     151             : 
     152           4 :                 a->ifindex = ifi;
     153           4 :                 a->family = family;
     154             : 
     155           4 :                 n_list++;
     156             :         };
     157             : 
     158           1 :         if (n_list > 0)
     159           1 :                 qsort(list, n_list, sizeof(struct local_address), address_compare);
     160             : 
     161           1 :         *ret = list;
     162           1 :         list = NULL;
     163             : 
     164           1 :         return (int) n_list;
     165             : }
     166             : 
     167           1 : int local_gateways(sd_netlink *context, int ifindex, int af, struct local_address **ret) {
     168           2 :         _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
     169           2 :         _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
     170           2 :         _cleanup_free_ struct local_address *list = NULL;
     171           1 :         sd_netlink_message *m = NULL;
     172           1 :         size_t n_list = 0, n_allocated = 0;
     173             :         int r;
     174             : 
     175           1 :         assert(ret);
     176             : 
     177           1 :         if (context)
     178           0 :                 rtnl = sd_netlink_ref(context);
     179             :         else {
     180           1 :                 r = sd_netlink_open(&rtnl);
     181           1 :                 if (r < 0)
     182           0 :                         return r;
     183             :         }
     184             : 
     185           1 :         r = sd_rtnl_message_new_route(rtnl, &req, RTM_GETROUTE, af, RTPROT_UNSPEC);
     186           1 :         if (r < 0)
     187           0 :                 return r;
     188             : 
     189           1 :         r = sd_netlink_message_request_dump(req, true);
     190           1 :         if (r < 0)
     191           0 :                 return r;
     192             : 
     193           1 :         r = sd_netlink_call(rtnl, req, 0, &reply);
     194           1 :         if (r < 0)
     195           0 :                 return r;
     196             : 
     197          23 :         for (m = reply; m; m = sd_netlink_message_next(m)) {
     198             :                 struct local_address *a;
     199             :                 uint16_t type;
     200             :                 unsigned char dst_len, src_len;
     201             :                 uint32_t ifi;
     202             :                 int family;
     203             : 
     204          22 :                 r = sd_netlink_message_get_errno(m);
     205          22 :                 if (r < 0)
     206           0 :                         return r;
     207             : 
     208          22 :                 r = sd_netlink_message_get_type(m, &type);
     209          22 :                 if (r < 0)
     210           0 :                         return r;
     211          22 :                 if (type != RTM_NEWROUTE)
     212          21 :                         continue;
     213             : 
     214             :                 /* We only care for default routes */
     215          22 :                 r = sd_rtnl_message_route_get_dst_prefixlen(m, &dst_len);
     216          22 :                 if (r < 0)
     217           0 :                         return r;
     218          22 :                 if (dst_len != 0)
     219          19 :                         continue;
     220             : 
     221           3 :                 r = sd_rtnl_message_route_get_src_prefixlen(m, &src_len);
     222           3 :                 if (r < 0)
     223           0 :                         return r;
     224           3 :                 if (src_len != 0)
     225           0 :                         continue;
     226             : 
     227           3 :                 r = sd_netlink_message_read_u32(m, RTA_OIF, &ifi);
     228           3 :                 if (r < 0)
     229           0 :                         return r;
     230           3 :                 if (ifindex > 0 && (int) ifi != ifindex)
     231           0 :                         continue;
     232             : 
     233           3 :                 r = sd_rtnl_message_route_get_family(m, &family);
     234           3 :                 if (r < 0)
     235           0 :                         return r;
     236           3 :                 if (af != AF_UNSPEC && af != family)
     237           0 :                         continue;
     238             : 
     239           3 :                 if (!GREEDY_REALLOC0(list, n_allocated, n_list + 1))
     240           0 :                         return -ENOMEM;
     241             : 
     242           3 :                 a = list + n_list;
     243             : 
     244           3 :                 switch (family) {
     245             :                 case AF_INET:
     246           1 :                         r = sd_netlink_message_read_in_addr(m, RTA_GATEWAY, &a->address.in);
     247           1 :                         if (r < 0)
     248           0 :                                 continue;
     249             : 
     250           1 :                         break;
     251             :                 case AF_INET6:
     252           2 :                         r = sd_netlink_message_read_in6_addr(m, RTA_GATEWAY, &a->address.in6);
     253           2 :                         if (r < 0)
     254           2 :                                 continue;
     255             : 
     256           0 :                         break;
     257             :                 default:
     258           0 :                         continue;
     259             :                 }
     260             : 
     261           1 :                 sd_netlink_message_read_u32(m, RTA_PRIORITY, &a->metric);
     262             : 
     263           1 :                 a->ifindex = ifi;
     264           1 :                 a->family = family;
     265             : 
     266           1 :                 n_list++;
     267             :         }
     268             : 
     269           1 :         if (n_list > 0)
     270           1 :                 qsort(list, n_list, sizeof(struct local_address), address_compare);
     271             : 
     272           1 :         *ret = list;
     273           1 :         list = NULL;
     274             : 
     275           1 :         return (int) n_list;
     276             : }

Generated by: LCOV version 1.11