LCOV - code coverage report
Current view: top level - network - networkd-ndisc.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 5 497 1.0 %
Date: 2019-08-23 13:36:53 Functions: 1 20 5.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 1 548 0.2 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : /***
       3                 :            :   Copyright © 2014 Intel Corporation. All rights reserved.
       4                 :            : ***/
       5                 :            : 
       6                 :            : #include <netinet/icmp6.h>
       7                 :            : #include <arpa/inet.h>
       8                 :            : 
       9                 :            : #include "sd-ndisc.h"
      10                 :            : 
      11                 :            : #include "missing_network.h"
      12                 :            : #include "networkd-dhcp6.h"
      13                 :            : #include "networkd-manager.h"
      14                 :            : #include "networkd-ndisc.h"
      15                 :            : #include "networkd-route.h"
      16                 :            : #include "strv.h"
      17                 :            : 
      18                 :            : #define NDISC_DNSSL_MAX 64U
      19                 :            : #define NDISC_RDNSS_MAX 64U
      20                 :            : #define NDISC_PREFIX_LFT_MIN 7200U
      21                 :            : 
      22                 :          0 : static int ndisc_netlink_route_message_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
      23                 :            :         int r;
      24                 :            : 
      25         [ #  # ]:          0 :         assert(link);
      26         [ #  # ]:          0 :         assert(link->ndisc_messages > 0);
      27                 :            : 
      28                 :          0 :         link->ndisc_messages--;
      29                 :            : 
      30   [ #  #  #  # ]:          0 :         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
      31                 :          0 :                 return 1;
      32                 :            : 
      33                 :          0 :         r = sd_netlink_message_get_errno(m);
      34   [ #  #  #  # ]:          0 :         if (r < 0 && r != -EEXIST) {
      35   [ #  #  #  # ]:          0 :                 log_link_error_errno(link, r, "Could not set NDisc route or address: %m");
      36                 :          0 :                 link_enter_failed(link);
      37                 :          0 :                 return 1;
      38                 :            :         }
      39                 :            : 
      40         [ #  # ]:          0 :         if (link->ndisc_messages == 0) {
      41                 :          0 :                 link->ndisc_configured = true;
      42                 :          0 :                 r = link_request_set_routes(link);
      43         [ #  # ]:          0 :                 if (r < 0) {
      44                 :          0 :                         link_enter_failed(link);
      45                 :          0 :                         return 1;
      46                 :            :                 }
      47                 :          0 :                 link_check_ready(link);
      48                 :            :         }
      49                 :            : 
      50                 :          0 :         return 1;
      51                 :            : }
      52                 :            : 
      53                 :          0 : static int ndisc_netlink_address_message_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
      54                 :            :         int r;
      55                 :            : 
      56         [ #  # ]:          0 :         assert(link);
      57         [ #  # ]:          0 :         assert(link->ndisc_messages > 0);
      58                 :            : 
      59                 :          0 :         link->ndisc_messages--;
      60                 :            : 
      61   [ #  #  #  # ]:          0 :         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
      62                 :          0 :                 return 1;
      63                 :            : 
      64                 :          0 :         r = sd_netlink_message_get_errno(m);
      65   [ #  #  #  # ]:          0 :         if (r < 0 && r != -EEXIST) {
      66   [ #  #  #  # ]:          0 :                 log_link_error_errno(link, r, "Could not set NDisc route or address: %m");
      67                 :          0 :                 link_enter_failed(link);
      68                 :          0 :                 return 1;
      69         [ #  # ]:          0 :         } else if (r >= 0)
      70                 :          0 :                 (void) manager_rtnl_process_address(rtnl, m, link->manager);
      71                 :            : 
      72         [ #  # ]:          0 :         if (link->ndisc_messages == 0) {
      73                 :          0 :                 link->ndisc_configured = true;
      74                 :          0 :                 r = link_request_set_routes(link);
      75         [ #  # ]:          0 :                 if (r < 0) {
      76                 :          0 :                         link_enter_failed(link);
      77                 :          0 :                         return 1;
      78                 :            :                 }
      79                 :          0 :                 link_check_ready(link);
      80                 :            :         }
      81                 :            : 
      82                 :          0 :         return 1;
      83                 :            : }
      84                 :            : 
      85                 :          0 : static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
      86                 :          0 :         _cleanup_(route_freep) Route *route = NULL;
      87                 :            :         union in_addr_union gateway;
      88                 :            :         uint16_t lifetime;
      89                 :            :         unsigned preference;
      90                 :            :         uint32_t mtu;
      91                 :            :         usec_t time_now;
      92                 :            :         int r;
      93                 :            :         Address *address;
      94                 :            :         Iterator i;
      95                 :            : 
      96         [ #  # ]:          0 :         assert(link);
      97         [ #  # ]:          0 :         assert(rt);
      98                 :            : 
      99                 :          0 :         r = sd_ndisc_router_get_lifetime(rt, &lifetime);
     100         [ #  # ]:          0 :         if (r < 0)
     101   [ #  #  #  # ]:          0 :                 return log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
     102                 :            : 
     103         [ #  # ]:          0 :         if (lifetime == 0) /* not a default router */
     104                 :          0 :                 return 0;
     105                 :            : 
     106                 :          0 :         r = sd_ndisc_router_get_address(rt, &gateway.in6);
     107         [ #  # ]:          0 :         if (r < 0)
     108   [ #  #  #  # ]:          0 :                 return log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
     109                 :            : 
     110         [ #  # ]:          0 :         SET_FOREACH(address, link->addresses, i) {
     111         [ #  # ]:          0 :                 if (address->family != AF_INET6)
     112                 :          0 :                         continue;
     113         [ #  # ]:          0 :                 if (in_addr_equal(AF_INET6, &gateway, &address->in_addr)) {
     114                 :          0 :                         _cleanup_free_ char *buffer = NULL;
     115                 :            : 
     116                 :          0 :                         (void) in_addr_to_string(AF_INET6, &address->in_addr, &buffer);
     117   [ #  #  #  # ]:          0 :                         log_link_debug(link, "No NDisc route added, gateway %s matches local address",
     118                 :            :                                        strnull(buffer));
     119                 :          0 :                         return 0;
     120                 :            :                 }
     121                 :            :         }
     122                 :            : 
     123         [ #  # ]:          0 :         SET_FOREACH(address, link->addresses_foreign, i) {
     124         [ #  # ]:          0 :                 if (address->family != AF_INET6)
     125                 :          0 :                         continue;
     126         [ #  # ]:          0 :                 if (in_addr_equal(AF_INET6, &gateway, &address->in_addr)) {
     127                 :          0 :                         _cleanup_free_ char *buffer = NULL;
     128                 :            : 
     129                 :          0 :                         (void) in_addr_to_string(AF_INET6, &address->in_addr, &buffer);
     130   [ #  #  #  # ]:          0 :                         log_link_debug(link, "No NDisc route added, gateway %s matches local address",
     131                 :            :                                        strnull(buffer));
     132                 :          0 :                         return 0;
     133                 :            :                 }
     134                 :            :         }
     135                 :            : 
     136                 :          0 :         r = sd_ndisc_router_get_preference(rt, &preference);
     137         [ #  # ]:          0 :         if (r < 0)
     138   [ #  #  #  # ]:          0 :                 return log_link_warning_errno(link, r, "Failed to get default router preference from RA: %m");
     139                 :            : 
     140                 :          0 :         r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
     141         [ #  # ]:          0 :         if (r < 0)
     142   [ #  #  #  # ]:          0 :                 return log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
     143                 :            : 
     144                 :          0 :         r = sd_ndisc_router_get_mtu(rt, &mtu);
     145         [ #  # ]:          0 :         if (r == -ENODATA)
     146                 :          0 :                 mtu = 0;
     147         [ #  # ]:          0 :         else if (r < 0)
     148   [ #  #  #  # ]:          0 :                 return log_link_warning_errno(link, r, "Failed to get default router MTU from RA: %m");
     149                 :            : 
     150                 :          0 :         r = route_new(&route);
     151         [ #  # ]:          0 :         if (r < 0)
     152   [ #  #  #  # ]:          0 :                 return log_link_error_errno(link, r, "Could not allocate route: %m");
     153                 :            : 
     154                 :          0 :         route->family = AF_INET6;
     155                 :          0 :         route->table = link_get_ipv6_accept_ra_route_table(link);
     156                 :          0 :         route->priority = link->network->dhcp_route_metric;
     157                 :          0 :         route->protocol = RTPROT_RA;
     158                 :          0 :         route->pref = preference;
     159                 :          0 :         route->gw = gateway;
     160                 :          0 :         route->lifetime = time_now + lifetime * USEC_PER_SEC;
     161                 :          0 :         route->mtu = mtu;
     162                 :            : 
     163                 :          0 :         r = route_configure(route, link, ndisc_netlink_route_message_handler);
     164         [ #  # ]:          0 :         if (r < 0) {
     165   [ #  #  #  # ]:          0 :                 log_link_warning_errno(link, r, "Could not set default route: %m");
     166                 :          0 :                 link_enter_failed(link);
     167                 :          0 :                 return r;
     168                 :            :         }
     169         [ #  # ]:          0 :         if (r > 0)
     170                 :          0 :                 link->ndisc_messages++;
     171                 :            : 
     172                 :          0 :         return 0;
     173                 :            : }
     174                 :            : 
     175                 :          0 : static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) {
     176                 :          0 :         _cleanup_(address_freep) Address *address = NULL;
     177                 :            :         Address *existing_address;
     178                 :            :         uint32_t lifetime_valid, lifetime_preferred, lifetime_remaining;
     179                 :            :         usec_t time_now;
     180                 :            :         unsigned prefixlen;
     181                 :            :         int r;
     182                 :            : 
     183         [ #  # ]:          0 :         assert(link);
     184         [ #  # ]:          0 :         assert(rt);
     185                 :            : 
     186                 :          0 :         r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
     187         [ #  # ]:          0 :         if (r < 0)
     188   [ #  #  #  # ]:          0 :                 return log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
     189                 :            : 
     190                 :          0 :         r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
     191         [ #  # ]:          0 :         if (r < 0)
     192   [ #  #  #  # ]:          0 :                 return log_link_error_errno(link, r, "Failed to get prefix length: %m");
     193                 :            : 
     194                 :          0 :         r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_valid);
     195         [ #  # ]:          0 :         if (r < 0)
     196   [ #  #  #  # ]:          0 :                 return log_link_error_errno(link, r, "Failed to get prefix valid lifetime: %m");
     197                 :            : 
     198                 :          0 :         r = sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred);
     199         [ #  # ]:          0 :         if (r < 0)
     200   [ #  #  #  # ]:          0 :                 return log_link_error_errno(link, r, "Failed to get prefix preferred lifetime: %m");
     201                 :            : 
     202                 :            :         /* The preferred lifetime is never greater than the valid lifetime */
     203         [ #  # ]:          0 :         if (lifetime_preferred > lifetime_valid)
     204                 :          0 :                 return 0;
     205                 :            : 
     206                 :          0 :         r = address_new(&address);
     207         [ #  # ]:          0 :         if (r < 0)
     208   [ #  #  #  # ]:          0 :                 return log_link_error_errno(link, r, "Could not allocate address: %m");
     209                 :            : 
     210                 :          0 :         address->family = AF_INET6;
     211                 :          0 :         r = sd_ndisc_router_prefix_get_address(rt, &address->in_addr.in6);
     212         [ #  # ]:          0 :         if (r < 0)
     213   [ #  #  #  # ]:          0 :                 return log_link_error_errno(link, r, "Failed to get prefix address: %m");
     214                 :            : 
     215         [ #  # ]:          0 :         if (in_addr_is_null(AF_INET6, (const union in_addr_union *) &link->network->ipv6_token) == 0)
     216                 :          0 :                 memcpy(((char *)&address->in_addr.in6) + 8, ((char *)&link->network->ipv6_token) + 8, 8);
     217                 :            :         else {
     218                 :            :                 /* see RFC4291 section 2.5.1 */
     219                 :          0 :                 address->in_addr.in6.s6_addr[8]  = link->mac.ether_addr_octet[0];
     220                 :          0 :                 address->in_addr.in6.s6_addr[8] ^= 1 << 1;
     221                 :          0 :                 address->in_addr.in6.s6_addr[9]  = link->mac.ether_addr_octet[1];
     222                 :          0 :                 address->in_addr.in6.s6_addr[10] = link->mac.ether_addr_octet[2];
     223                 :          0 :                 address->in_addr.in6.s6_addr[11] = 0xff;
     224                 :          0 :                 address->in_addr.in6.s6_addr[12] = 0xfe;
     225                 :          0 :                 address->in_addr.in6.s6_addr[13] = link->mac.ether_addr_octet[3];
     226                 :          0 :                 address->in_addr.in6.s6_addr[14] = link->mac.ether_addr_octet[4];
     227                 :          0 :                 address->in_addr.in6.s6_addr[15] = link->mac.ether_addr_octet[5];
     228                 :            :         }
     229                 :          0 :         address->prefixlen = prefixlen;
     230                 :          0 :         address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
     231                 :          0 :         address->cinfo.ifa_prefered = lifetime_preferred;
     232                 :            : 
     233                 :            :         /* see RFC4862 section 5.5.3.e */
     234                 :          0 :         r = address_get(link, address->family, &address->in_addr, address->prefixlen, &existing_address);
     235         [ #  # ]:          0 :         if (r > 0) {
     236                 :          0 :                 lifetime_remaining = existing_address->cinfo.tstamp / 100 + existing_address->cinfo.ifa_valid - time_now / USEC_PER_SEC;
     237   [ #  #  #  # ]:          0 :                 if (lifetime_valid > NDISC_PREFIX_LFT_MIN || lifetime_valid > lifetime_remaining)
     238                 :          0 :                         address->cinfo.ifa_valid = lifetime_valid;
     239         [ #  # ]:          0 :                 else if (lifetime_remaining <= NDISC_PREFIX_LFT_MIN)
     240                 :          0 :                         address->cinfo.ifa_valid = lifetime_remaining;
     241                 :            :                 else
     242                 :          0 :                         address->cinfo.ifa_valid = NDISC_PREFIX_LFT_MIN;
     243         [ #  # ]:          0 :         } else if (lifetime_valid > 0)
     244                 :          0 :                 address->cinfo.ifa_valid = lifetime_valid;
     245                 :            :         else
     246                 :          0 :                 return 0; /* see RFC4862 section 5.5.3.d */
     247                 :            : 
     248         [ #  # ]:          0 :         if (address->cinfo.ifa_valid == 0)
     249                 :          0 :                 return 0;
     250                 :            : 
     251                 :          0 :         r = address_configure(address, link, ndisc_netlink_address_message_handler, true);
     252         [ #  # ]:          0 :         if (r < 0) {
     253   [ #  #  #  # ]:          0 :                 log_link_warning_errno(link, r, "Could not set SLAAC address: %m");
     254                 :          0 :                 link_enter_failed(link);
     255                 :          0 :                 return r;
     256                 :            :         }
     257         [ #  # ]:          0 :         if (r > 0)
     258                 :          0 :                 link->ndisc_messages++;
     259                 :            : 
     260                 :          0 :         return 0;
     261                 :            : }
     262                 :            : 
     263                 :          0 : static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
     264                 :          0 :         _cleanup_(route_freep) Route *route = NULL;
     265                 :            :         usec_t time_now;
     266                 :            :         uint32_t lifetime;
     267                 :            :         unsigned prefixlen;
     268                 :            :         int r;
     269                 :            : 
     270         [ #  # ]:          0 :         assert(link);
     271         [ #  # ]:          0 :         assert(rt);
     272                 :            : 
     273                 :          0 :         r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
     274         [ #  # ]:          0 :         if (r < 0)
     275   [ #  #  #  # ]:          0 :                 return log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
     276                 :            : 
     277                 :          0 :         r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
     278         [ #  # ]:          0 :         if (r < 0)
     279   [ #  #  #  # ]:          0 :                 return log_link_error_errno(link, r, "Failed to get prefix length: %m");
     280                 :            : 
     281                 :          0 :         r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime);
     282         [ #  # ]:          0 :         if (r < 0)
     283   [ #  #  #  # ]:          0 :                 return log_link_error_errno(link, r, "Failed to get prefix lifetime: %m");
     284                 :            : 
     285                 :          0 :         r = route_new(&route);
     286         [ #  # ]:          0 :         if (r < 0)
     287   [ #  #  #  # ]:          0 :                 return log_link_error_errno(link, r, "Could not allocate route: %m");
     288                 :            : 
     289                 :          0 :         route->family = AF_INET6;
     290                 :          0 :         route->table = link_get_ipv6_accept_ra_route_table(link);
     291                 :          0 :         route->priority = link->network->dhcp_route_metric;
     292                 :          0 :         route->protocol = RTPROT_RA;
     293                 :          0 :         route->flags = RTM_F_PREFIX;
     294                 :          0 :         route->dst_prefixlen = prefixlen;
     295                 :          0 :         route->lifetime = time_now + lifetime * USEC_PER_SEC;
     296                 :            : 
     297                 :          0 :         r = sd_ndisc_router_prefix_get_address(rt, &route->dst.in6);
     298         [ #  # ]:          0 :         if (r < 0)
     299   [ #  #  #  # ]:          0 :                 return log_link_error_errno(link, r, "Failed to get prefix address: %m");
     300                 :            : 
     301                 :          0 :         r = route_configure(route, link, ndisc_netlink_route_message_handler);
     302         [ #  # ]:          0 :         if (r < 0) {
     303   [ #  #  #  # ]:          0 :                 log_link_warning_errno(link, r, "Could not set prefix route: %m");
     304                 :          0 :                 link_enter_failed(link);
     305                 :          0 :                 return r;
     306                 :            :         }
     307         [ #  # ]:          0 :         if (r > 0)
     308                 :          0 :                 link->ndisc_messages++;
     309                 :            : 
     310                 :          0 :         return 0;
     311                 :            : }
     312                 :            : 
     313                 :          0 : static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
     314                 :          0 :         _cleanup_(route_freep) Route *route = NULL;
     315                 :            :         struct in6_addr gateway;
     316                 :            :         uint32_t lifetime;
     317                 :            :         unsigned preference, prefixlen;
     318                 :            :         usec_t time_now;
     319                 :            :         int r;
     320                 :            : 
     321         [ #  # ]:          0 :         assert(link);
     322                 :            : 
     323                 :          0 :         r = sd_ndisc_router_route_get_lifetime(rt, &lifetime);
     324         [ #  # ]:          0 :         if (r < 0)
     325   [ #  #  #  # ]:          0 :                 return log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
     326                 :            : 
     327         [ #  # ]:          0 :         if (lifetime == 0)
     328                 :          0 :                 return 0;
     329                 :            : 
     330                 :          0 :         r = sd_ndisc_router_get_address(rt, &gateway);
     331         [ #  # ]:          0 :         if (r < 0)
     332   [ #  #  #  # ]:          0 :                 return log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
     333                 :            : 
     334                 :          0 :         r = sd_ndisc_router_route_get_prefixlen(rt, &prefixlen);
     335         [ #  # ]:          0 :         if (r < 0)
     336   [ #  #  #  # ]:          0 :                 return log_link_warning_errno(link, r, "Failed to get route prefix length: %m");
     337                 :            : 
     338                 :          0 :         r = sd_ndisc_router_route_get_preference(rt, &preference);
     339         [ #  # ]:          0 :         if (r < 0)
     340   [ #  #  #  # ]:          0 :                 return log_link_warning_errno(link, r, "Failed to get default router preference from RA: %m");
     341                 :            : 
     342                 :          0 :         r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
     343         [ #  # ]:          0 :         if (r < 0)
     344   [ #  #  #  # ]:          0 :                 return log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
     345                 :            : 
     346                 :          0 :         r = route_new(&route);
     347         [ #  # ]:          0 :         if (r < 0)
     348   [ #  #  #  # ]:          0 :                 return log_link_error_errno(link, r, "Could not allocate route: %m");
     349                 :            : 
     350                 :          0 :         route->family = AF_INET6;
     351                 :          0 :         route->table = link_get_ipv6_accept_ra_route_table(link);
     352                 :          0 :         route->protocol = RTPROT_RA;
     353                 :          0 :         route->pref = preference;
     354                 :          0 :         route->gw.in6 = gateway;
     355                 :          0 :         route->dst_prefixlen = prefixlen;
     356                 :          0 :         route->lifetime = time_now + lifetime * USEC_PER_SEC;
     357                 :            : 
     358                 :          0 :         r = sd_ndisc_router_route_get_address(rt, &route->dst.in6);
     359         [ #  # ]:          0 :         if (r < 0)
     360   [ #  #  #  # ]:          0 :                 return log_link_error_errno(link, r, "Failed to get route address: %m");
     361                 :            : 
     362                 :          0 :         r = route_configure(route, link, ndisc_netlink_route_message_handler);
     363         [ #  # ]:          0 :         if (r < 0) {
     364   [ #  #  #  # ]:          0 :                 log_link_warning_errno(link, r, "Could not set additional route: %m");
     365                 :          0 :                 link_enter_failed(link);
     366                 :          0 :                 return r;
     367                 :            :         }
     368         [ #  # ]:          0 :         if (r > 0)
     369                 :          0 :                 link->ndisc_messages++;
     370                 :            : 
     371                 :          0 :         return 0;
     372                 :            : }
     373                 :            : 
     374                 :          0 : static void ndisc_rdnss_hash_func(const NDiscRDNSS *x, struct siphash *state) {
     375                 :          0 :         siphash24_compress(&x->address, sizeof(x->address), state);
     376                 :          0 : }
     377                 :            : 
     378                 :          0 : static int ndisc_rdnss_compare_func(const NDiscRDNSS *a, const NDiscRDNSS *b) {
     379                 :          0 :         return memcmp(&a->address, &b->address, sizeof(a->address));
     380                 :            : }
     381                 :            : 
     382                 :            : DEFINE_PRIVATE_HASH_OPS(ndisc_rdnss_hash_ops, NDiscRDNSS, ndisc_rdnss_hash_func, ndisc_rdnss_compare_func);
     383                 :            : 
     384                 :          0 : static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
     385                 :            :         uint32_t lifetime;
     386                 :            :         const struct in6_addr *a;
     387                 :            :         usec_t time_now;
     388                 :            :         int i, n, r;
     389                 :            : 
     390         [ #  # ]:          0 :         assert(link);
     391         [ #  # ]:          0 :         assert(rt);
     392                 :            : 
     393                 :          0 :         r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
     394         [ #  # ]:          0 :         if (r < 0)
     395   [ #  #  #  # ]:          0 :                 return log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
     396                 :            : 
     397                 :          0 :         r = sd_ndisc_router_rdnss_get_lifetime(rt, &lifetime);
     398         [ #  # ]:          0 :         if (r < 0)
     399   [ #  #  #  # ]:          0 :                 return log_link_warning_errno(link, r, "Failed to get RDNSS lifetime: %m");
     400                 :            : 
     401                 :          0 :         n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
     402         [ #  # ]:          0 :         if (n < 0)
     403   [ #  #  #  # ]:          0 :                 return log_link_warning_errno(link, n, "Failed to get RDNSS addresses: %m");
     404                 :            : 
     405         [ #  # ]:          0 :         for (i = 0; i < n; i++) {
     406      [ #  #  # ]:          0 :                 _cleanup_free_ NDiscRDNSS *x = NULL;
     407                 :          0 :                 NDiscRDNSS d = {
     408                 :          0 :                         .address = a[i],
     409                 :            :                 }, *y;
     410                 :            : 
     411         [ #  # ]:          0 :                 if (lifetime == 0) {
     412                 :          0 :                         (void) set_remove(link->ndisc_rdnss, &d);
     413                 :          0 :                         link_dirty(link);
     414                 :          0 :                         continue;
     415                 :            :                 }
     416                 :            : 
     417                 :          0 :                 y = set_get(link->ndisc_rdnss, &d);
     418         [ #  # ]:          0 :                 if (y) {
     419                 :          0 :                         y->valid_until = time_now + lifetime * USEC_PER_SEC;
     420                 :          0 :                         continue;
     421                 :            :                 }
     422                 :            : 
     423                 :          0 :                 ndisc_vacuum(link);
     424                 :            : 
     425         [ #  # ]:          0 :                 if (set_size(link->ndisc_rdnss) >= NDISC_RDNSS_MAX) {
     426   [ #  #  #  # ]:          0 :                         log_link_warning(link, "Too many RDNSS records per link, ignoring.");
     427                 :          0 :                         continue;
     428                 :            :                 }
     429                 :            : 
     430                 :          0 :                 r = set_ensure_allocated(&link->ndisc_rdnss, &ndisc_rdnss_hash_ops);
     431         [ #  # ]:          0 :                 if (r < 0)
     432                 :          0 :                         return log_oom();
     433                 :            : 
     434                 :          0 :                 x = new(NDiscRDNSS, 1);
     435         [ #  # ]:          0 :                 if (!x)
     436                 :          0 :                         return log_oom();
     437                 :            : 
     438                 :          0 :                 *x = (NDiscRDNSS) {
     439                 :          0 :                         .address = a[i],
     440                 :          0 :                         .valid_until = time_now + lifetime * USEC_PER_SEC,
     441                 :            :                 };
     442                 :            : 
     443                 :          0 :                 r = set_put(link->ndisc_rdnss, x);
     444         [ #  # ]:          0 :                 if (r < 0)
     445                 :          0 :                         return log_oom();
     446                 :            : 
     447                 :          0 :                 TAKE_PTR(x);
     448                 :            : 
     449         [ #  # ]:          0 :                 assert(r > 0);
     450                 :          0 :                 link_dirty(link);
     451                 :            :         }
     452                 :            : 
     453                 :          0 :         return 0;
     454                 :            : }
     455                 :            : 
     456                 :          0 : static void ndisc_dnssl_hash_func(const NDiscDNSSL *x, struct siphash *state) {
     457                 :          0 :         siphash24_compress(NDISC_DNSSL_DOMAIN(x), strlen(NDISC_DNSSL_DOMAIN(x)), state);
     458                 :          0 : }
     459                 :            : 
     460                 :          0 : static int ndisc_dnssl_compare_func(const NDiscDNSSL *a, const NDiscDNSSL *b) {
     461                 :          0 :         return strcmp(NDISC_DNSSL_DOMAIN(a), NDISC_DNSSL_DOMAIN(b));
     462                 :            : }
     463                 :            : 
     464                 :            : DEFINE_PRIVATE_HASH_OPS(ndisc_dnssl_hash_ops, NDiscDNSSL, ndisc_dnssl_hash_func, ndisc_dnssl_compare_func);
     465                 :            : 
     466                 :          0 : static void ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
     467         [ #  # ]:          0 :         _cleanup_strv_free_ char **l = NULL;
     468                 :            :         uint32_t lifetime;
     469                 :            :         usec_t time_now;
     470                 :            :         char **i;
     471                 :            :         int r;
     472                 :            : 
     473         [ #  # ]:          0 :         assert(link);
     474         [ #  # ]:          0 :         assert(rt);
     475                 :            : 
     476                 :          0 :         r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
     477         [ #  # ]:          0 :         if (r < 0) {
     478   [ #  #  #  # ]:          0 :                 log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
     479                 :          0 :                 return;
     480                 :            :         }
     481                 :            : 
     482                 :          0 :         r = sd_ndisc_router_dnssl_get_lifetime(rt, &lifetime);
     483         [ #  # ]:          0 :         if (r < 0) {
     484   [ #  #  #  # ]:          0 :                 log_link_warning_errno(link, r, "Failed to get RDNSS lifetime: %m");
     485                 :          0 :                 return;
     486                 :            :         }
     487                 :            : 
     488                 :          0 :         r = sd_ndisc_router_dnssl_get_domains(rt, &l);
     489         [ #  # ]:          0 :         if (r < 0) {
     490   [ #  #  #  # ]:          0 :                 log_link_warning_errno(link, r, "Failed to get RDNSS addresses: %m");
     491                 :          0 :                 return;
     492                 :            :         }
     493                 :            : 
     494   [ #  #  #  # ]:          0 :         STRV_FOREACH(i, l) {
     495      [ #  #  # ]:          0 :                 _cleanup_free_ NDiscDNSSL *s;
     496                 :            :                 NDiscDNSSL *x;
     497                 :            : 
     498                 :          0 :                 s = malloc0(ALIGN(sizeof(NDiscDNSSL)) + strlen(*i) + 1);
     499         [ #  # ]:          0 :                 if (!s) {
     500                 :          0 :                         log_oom();
     501                 :          0 :                         return;
     502                 :            :                 }
     503                 :            : 
     504                 :          0 :                 strcpy(NDISC_DNSSL_DOMAIN(s), *i);
     505                 :            : 
     506         [ #  # ]:          0 :                 if (lifetime == 0) {
     507                 :          0 :                         (void) set_remove(link->ndisc_dnssl, s);
     508                 :          0 :                         link_dirty(link);
     509                 :          0 :                         continue;
     510                 :            :                 }
     511                 :            : 
     512                 :          0 :                 x = set_get(link->ndisc_dnssl, s);
     513         [ #  # ]:          0 :                 if (x) {
     514                 :          0 :                         x->valid_until = time_now + lifetime * USEC_PER_SEC;
     515                 :          0 :                         continue;
     516                 :            :                 }
     517                 :            : 
     518                 :          0 :                 ndisc_vacuum(link);
     519                 :            : 
     520         [ #  # ]:          0 :                 if (set_size(link->ndisc_dnssl) >= NDISC_DNSSL_MAX) {
     521   [ #  #  #  # ]:          0 :                         log_link_warning(link, "Too many DNSSL records per link, ignoring.");
     522                 :          0 :                         continue;
     523                 :            :                 }
     524                 :            : 
     525                 :          0 :                 r = set_ensure_allocated(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops);
     526         [ #  # ]:          0 :                 if (r < 0) {
     527                 :          0 :                         log_oom();
     528                 :          0 :                         return;
     529                 :            :                 }
     530                 :            : 
     531                 :          0 :                 s->valid_until = time_now + lifetime * USEC_PER_SEC;
     532                 :            : 
     533                 :          0 :                 r = set_put(link->ndisc_dnssl, s);
     534         [ #  # ]:          0 :                 if (r < 0) {
     535                 :          0 :                         log_oom();
     536                 :          0 :                         return;
     537                 :            :                 }
     538                 :            : 
     539                 :          0 :                 s = NULL;
     540         [ #  # ]:          0 :                 assert(r > 0);
     541                 :          0 :                 link_dirty(link);
     542                 :            :         }
     543                 :            : }
     544                 :            : 
     545                 :          0 : static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
     546                 :            :         int r;
     547                 :            : 
     548         [ #  # ]:          0 :         assert(link);
     549         [ #  # ]:          0 :         assert(rt);
     550                 :            : 
     551                 :          0 :         r = sd_ndisc_router_option_rewind(rt);
     552                 :          0 :         for (;;) {
     553                 :            :                 uint8_t type;
     554                 :            : 
     555         [ #  # ]:          0 :                 if (r < 0)
     556   [ #  #  #  # ]:          0 :                         return log_link_warning_errno(link, r, "Failed to iterate through options: %m");
     557         [ #  # ]:          0 :                 if (r == 0) /* EOF */
     558                 :          0 :                         break;
     559                 :            : 
     560                 :          0 :                 r = sd_ndisc_router_option_get_type(rt, &type);
     561         [ #  # ]:          0 :                 if (r < 0)
     562   [ #  #  #  # ]:          0 :                         return log_link_warning_errno(link, r, "Failed to get RA option type: %m");
     563                 :            : 
     564   [ #  #  #  #  :          0 :                 switch (type) {
                      # ]
     565                 :            : 
     566                 :          0 :                 case SD_NDISC_OPTION_PREFIX_INFORMATION: {
     567                 :            :                         uint8_t flags;
     568                 :            : 
     569                 :          0 :                         r = sd_ndisc_router_prefix_get_flags(rt, &flags);
     570         [ #  # ]:          0 :                         if (r < 0)
     571   [ #  #  #  # ]:          0 :                                 return log_link_warning_errno(link, r, "Failed to get RA prefix flags: %m");
     572                 :            : 
     573         [ #  # ]:          0 :                         if (link->network->ipv6_accept_ra_use_onlink_prefix &&
     574         [ #  # ]:          0 :                             FLAGS_SET(flags, ND_OPT_PI_FLAG_ONLINK))
     575                 :          0 :                                 (void) ndisc_router_process_onlink_prefix(link, rt);
     576                 :            : 
     577         [ #  # ]:          0 :                         if (link->network->ipv6_accept_ra_use_autonomous_prefix &&
     578         [ #  # ]:          0 :                             FLAGS_SET(flags, ND_OPT_PI_FLAG_AUTO))
     579                 :          0 :                                 (void) ndisc_router_process_autonomous_prefix(link, rt);
     580                 :            : 
     581                 :          0 :                         break;
     582                 :            :                 }
     583                 :            : 
     584                 :          0 :                 case SD_NDISC_OPTION_ROUTE_INFORMATION:
     585                 :          0 :                         (void) ndisc_router_process_route(link, rt);
     586                 :          0 :                         break;
     587                 :            : 
     588                 :          0 :                 case SD_NDISC_OPTION_RDNSS:
     589         [ #  # ]:          0 :                         if (link->network->ipv6_accept_ra_use_dns)
     590                 :          0 :                                 (void) ndisc_router_process_rdnss(link, rt);
     591                 :          0 :                         break;
     592                 :            : 
     593                 :          0 :                 case SD_NDISC_OPTION_DNSSL:
     594         [ #  # ]:          0 :                         if (link->network->ipv6_accept_ra_use_dns)
     595                 :          0 :                                 (void) ndisc_router_process_dnssl(link, rt);
     596                 :          0 :                         break;
     597                 :            :                 }
     598                 :            : 
     599                 :          0 :                 r = sd_ndisc_router_option_next(rt);
     600                 :            :         }
     601                 :            : 
     602                 :          0 :         return 0;
     603                 :            : }
     604                 :            : 
     605                 :          0 : static int ndisc_prefix_is_black_listed(Link *link, sd_ndisc_router *rt) {
     606                 :            :         int r;
     607                 :            : 
     608         [ #  # ]:          0 :         assert(link);
     609         [ #  # ]:          0 :         assert(link->network);
     610         [ #  # ]:          0 :         assert(rt);
     611                 :            : 
     612                 :          0 :         for (r = sd_ndisc_router_option_rewind(rt); ; r = sd_ndisc_router_option_next(rt)) {
     613                 :            :                 union in_addr_union a;
     614                 :            :                 uint8_t type;
     615                 :            : 
     616         [ #  # ]:          0 :                 if (r < 0)
     617   [ #  #  #  # ]:          0 :                         return log_link_warning_errno(link, r, "Failed to iterate through options: %m");
     618         [ #  # ]:          0 :                 if (r == 0) /* EOF */
     619                 :          0 :                         return false;
     620                 :            : 
     621                 :          0 :                 r = sd_ndisc_router_option_get_type(rt, &type);
     622         [ #  # ]:          0 :                 if (r < 0)
     623   [ #  #  #  # ]:          0 :                         return log_link_warning_errno(link, r, "Failed to get RA option type: %m");
     624                 :            : 
     625         [ #  # ]:          0 :                 if (type != SD_NDISC_OPTION_PREFIX_INFORMATION)
     626                 :          0 :                         continue;
     627                 :            : 
     628                 :          0 :                 r = sd_ndisc_router_prefix_get_address(rt, &a.in6);
     629         [ #  # ]:          0 :                 if (r < 0)
     630   [ #  #  #  # ]:          0 :                         return log_link_error_errno(link, r, "Failed to get prefix address: %m");
     631                 :            : 
     632         [ #  # ]:          0 :                 if (set_contains(link->network->ndisc_black_listed_prefix, &a.in6)) {
     633         [ #  # ]:          0 :                         if (DEBUG_LOGGING) {
     634                 :          0 :                                 _cleanup_free_ char *b = NULL;
     635                 :            : 
     636                 :          0 :                                 (void) in_addr_to_string(AF_INET6, &a, &b);
     637   [ #  #  #  # ]:          0 :                                 log_link_debug(link, "Prefix '%s' is black listed, ignoring", strna(b));
     638                 :            :                         }
     639                 :            : 
     640                 :          0 :                         return true;
     641                 :            :                 }
     642                 :            :         }
     643                 :            : }
     644                 :            : 
     645                 :          0 : static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
     646                 :            :         uint64_t flags;
     647                 :            :         int r;
     648                 :            : 
     649         [ #  # ]:          0 :         assert(link);
     650         [ #  # ]:          0 :         assert(link->network);
     651         [ #  # ]:          0 :         assert(link->manager);
     652         [ #  # ]:          0 :         assert(rt);
     653                 :            : 
     654                 :          0 :         r = sd_ndisc_router_get_flags(rt, &flags);
     655         [ #  # ]:          0 :         if (r < 0)
     656   [ #  #  #  # ]:          0 :                 return log_link_warning_errno(link, r, "Failed to get RA flags: %m");
     657                 :            : 
     658         [ #  # ]:          0 :         if (flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)) {
     659                 :            :                 /* (re)start DHCPv6 client in stateful or stateless mode according to RA flags */
     660                 :          0 :                 r = dhcp6_request_address(link, !(flags & ND_RA_FLAG_MANAGED));
     661   [ #  #  #  # ]:          0 :                 if (r < 0 && r != -EBUSY)
     662   [ #  #  #  # ]:          0 :                         log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease on NDisc request: %m");
     663                 :            :                 else {
     664   [ #  #  #  # ]:          0 :                         log_link_debug(link, "Acquiring DHCPv6 lease on NDisc request");
     665                 :          0 :                         r = 0;
     666                 :            :                 }
     667                 :            :         }
     668                 :            : 
     669         [ #  # ]:          0 :         if (ndisc_prefix_is_black_listed(link, rt) == 0) {
     670                 :          0 :                 (void) ndisc_router_process_default(link, rt);
     671                 :          0 :                 (void) ndisc_router_process_options(link, rt);
     672                 :            :         }
     673                 :            : 
     674                 :          0 :         return r;
     675                 :            : }
     676                 :            : 
     677                 :          0 : static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata) {
     678                 :          0 :         Link *link = userdata;
     679                 :            : 
     680         [ #  # ]:          0 :         assert(link);
     681                 :            : 
     682   [ #  #  #  # ]:          0 :         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
     683                 :          0 :                 return;
     684                 :            : 
     685      [ #  #  # ]:          0 :         switch (event) {
     686                 :            : 
     687                 :          0 :         case SD_NDISC_EVENT_ROUTER:
     688                 :          0 :                 (void) ndisc_router_handler(link, rt);
     689                 :          0 :                 break;
     690                 :            : 
     691                 :          0 :         case SD_NDISC_EVENT_TIMEOUT:
     692                 :          0 :                 link->ndisc_configured = true;
     693                 :          0 :                 link_check_ready(link);
     694                 :            : 
     695                 :          0 :                 break;
     696                 :          0 :         default:
     697   [ #  #  #  # ]:          0 :                 log_link_warning(link, "IPv6 Neighbor Discovery unknown event: %d", event);
     698                 :            :         }
     699                 :            : }
     700                 :            : 
     701                 :          0 : int ndisc_configure(Link *link) {
     702                 :            :         int r;
     703                 :            : 
     704         [ #  # ]:          0 :         assert(link);
     705                 :            : 
     706                 :          0 :         r = sd_ndisc_new(&link->ndisc);
     707         [ #  # ]:          0 :         if (r < 0)
     708                 :          0 :                 return r;
     709                 :            : 
     710                 :          0 :         r = sd_ndisc_attach_event(link->ndisc, NULL, 0);
     711         [ #  # ]:          0 :         if (r < 0)
     712                 :          0 :                 return r;
     713                 :            : 
     714                 :          0 :         r = sd_ndisc_set_mac(link->ndisc, &link->mac);
     715         [ #  # ]:          0 :         if (r < 0)
     716                 :          0 :                 return r;
     717                 :            : 
     718                 :          0 :         r = sd_ndisc_set_ifindex(link->ndisc, link->ifindex);
     719         [ #  # ]:          0 :         if (r < 0)
     720                 :          0 :                 return r;
     721                 :            : 
     722                 :          0 :         r = sd_ndisc_set_callback(link->ndisc, ndisc_handler, link);
     723         [ #  # ]:          0 :         if (r < 0)
     724                 :          0 :                 return r;
     725                 :            : 
     726                 :          0 :         return 0;
     727                 :            : }
     728                 :            : 
     729                 :          0 : void ndisc_vacuum(Link *link) {
     730                 :            :         NDiscRDNSS *r;
     731                 :            :         NDiscDNSSL *d;
     732                 :            :         Iterator i;
     733                 :            :         usec_t time_now;
     734                 :            : 
     735         [ #  # ]:          0 :         assert(link);
     736                 :            : 
     737                 :            :         /* Removes all RDNSS and DNSSL entries whose validity time has passed */
     738                 :            : 
     739                 :          0 :         time_now = now(clock_boottime_or_monotonic());
     740                 :            : 
     741         [ #  # ]:          0 :         SET_FOREACH(r, link->ndisc_rdnss, i)
     742         [ #  # ]:          0 :                 if (r->valid_until < time_now) {
     743                 :          0 :                         free(set_remove(link->ndisc_rdnss, r));
     744                 :          0 :                         link_dirty(link);
     745                 :            :                 }
     746                 :            : 
     747         [ #  # ]:          0 :         SET_FOREACH(d, link->ndisc_dnssl, i)
     748         [ #  # ]:          0 :                 if (d->valid_until < time_now) {
     749                 :          0 :                         free(set_remove(link->ndisc_dnssl, d));
     750                 :          0 :                         link_dirty(link);
     751                 :            :                 }
     752                 :          0 : }
     753                 :            : 
     754                 :         28 : void ndisc_flush(Link *link) {
     755         [ -  + ]:         28 :         assert(link);
     756                 :            : 
     757                 :            :         /* Removes all RDNSS and DNSSL entries, without exception */
     758                 :            : 
     759                 :         28 :         link->ndisc_rdnss = set_free_free(link->ndisc_rdnss);
     760                 :         28 :         link->ndisc_dnssl = set_free_free(link->ndisc_dnssl);
     761                 :         28 : }
     762                 :            : 
     763                 :          0 : int config_parse_ndisc_black_listed_prefix(
     764                 :            :                 const char *unit,
     765                 :            :                 const char *filename,
     766                 :            :                 unsigned line,
     767                 :            :                 const char *section,
     768                 :            :                 unsigned section_line,
     769                 :            :                 const char *lvalue,
     770                 :            :                 int ltype,
     771                 :            :                 const char *rvalue,
     772                 :            :                 void *data,
     773                 :            :                 void *userdata) {
     774                 :            : 
     775                 :          0 :         Network *network = data;
     776                 :            :         const char *p;
     777                 :            :         int r;
     778                 :            : 
     779         [ #  # ]:          0 :         assert(filename);
     780         [ #  # ]:          0 :         assert(lvalue);
     781         [ #  # ]:          0 :         assert(rvalue);
     782         [ #  # ]:          0 :         assert(data);
     783                 :            : 
     784         [ #  # ]:          0 :         if (isempty(rvalue)) {
     785                 :          0 :                 network->ndisc_black_listed_prefix = set_free_free(network->ndisc_black_listed_prefix);
     786                 :          0 :                 return 0;
     787                 :            :         }
     788                 :            : 
     789                 :          0 :         for (p = rvalue;;) {
     790      [ #  #  # ]:          0 :                 _cleanup_free_ char *n = NULL;
     791      [ #  #  # ]:          0 :                 _cleanup_free_ struct in6_addr *a = NULL;
     792                 :            :                 union in_addr_union ip;
     793                 :            : 
     794                 :          0 :                 r = extract_first_word(&p, &n, NULL, 0);
     795         [ #  # ]:          0 :                 if (r < 0) {
     796         [ #  # ]:          0 :                         log_syntax(unit, LOG_ERR, filename, line, r,
     797                 :            :                                    "Failed to parse NDISC black listed prefix, ignoring assignment: %s",
     798                 :            :                                    rvalue);
     799                 :          0 :                         return 0;
     800                 :            :                 }
     801         [ #  # ]:          0 :                 if (r == 0)
     802                 :          0 :                         return 0;
     803                 :            : 
     804                 :          0 :                 r = in_addr_from_string(AF_INET6, n, &ip);
     805         [ #  # ]:          0 :                 if (r < 0) {
     806         [ #  # ]:          0 :                         log_syntax(unit, LOG_ERR, filename, line, r,
     807                 :            :                                    "NDISC black listed prefix is invalid, ignoring assignment: %s", n);
     808                 :          0 :                         continue;
     809                 :            :                 }
     810                 :            : 
     811         [ #  # ]:          0 :                 if (set_contains(network->ndisc_black_listed_prefix, &ip.in6))
     812                 :          0 :                         continue;
     813                 :            : 
     814                 :          0 :                 r = set_ensure_allocated(&network->ndisc_black_listed_prefix, &in6_addr_hash_ops);
     815         [ #  # ]:          0 :                 if (r < 0)
     816                 :          0 :                         return log_oom();
     817                 :            : 
     818                 :          0 :                 a = newdup(struct in6_addr, &ip.in6, 1);
     819         [ #  # ]:          0 :                 if (!a)
     820                 :          0 :                         return log_oom();
     821                 :            : 
     822                 :          0 :                 r = set_put(network->ndisc_black_listed_prefix, a);
     823         [ #  # ]:          0 :                 if (r < 0) {
     824         [ #  # ]:          0 :                         log_syntax(unit, LOG_ERR, filename, line, r,
     825                 :            :                                    "Failed to store NDISC black listed prefix '%s', ignoring assignment: %m", n);
     826                 :          0 :                         continue;
     827                 :            :                 }
     828                 :            : 
     829                 :          0 :                 TAKE_PTR(a);
     830                 :            :         }
     831                 :            : 
     832                 :            :         return 0;
     833                 :            : }

Generated by: LCOV version 1.14