LCOV - code coverage report
Current view: top level - network - networkd-ndisc.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 5 497 1.0 %
Date: 2019-08-22 15:41:25 Functions: 1 20 5.0 %

          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           6 : void ndisc_flush(Link *link) {
     755           6 :         assert(link);
     756             : 
     757             :         /* Removes all RDNSS and DNSSL entries, without exception */
     758             : 
     759           6 :         link->ndisc_rdnss = set_free_free(link->ndisc_rdnss);
     760           6 :         link->ndisc_dnssl = set_free_free(link->ndisc_dnssl);
     761           6 : }
     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