LCOV - code coverage report
Current view: top level - network - networkd-dhcp4.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 5 794 0.6 %
Date: 2019-08-22 15:41:25 Functions: 1 30 3.3 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <netinet/in.h>
       4             : #include <linux/if.h>
       5             : #include <linux/if_arp.h>
       6             : 
       7             : #include "alloc-util.h"
       8             : #include "hostname-util.h"
       9             : #include "parse-util.h"
      10             : #include "network-internal.h"
      11             : #include "networkd-dhcp4.h"
      12             : #include "networkd-link.h"
      13             : #include "networkd-manager.h"
      14             : #include "networkd-network.h"
      15             : #include "string-table.h"
      16             : #include "string-util.h"
      17             : #include "sysctl-util.h"
      18             : 
      19             : static int dhcp_remove_routes(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all);
      20             : static int dhcp_remove_router(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all);
      21             : static int dhcp_remove_dns_routes(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all);
      22             : static int dhcp_remove_address(Link *link, sd_dhcp_lease *lease, const struct in_addr *address);
      23             : 
      24           6 : void dhcp4_release_old_lease(Link *link) {
      25           6 :         struct in_addr address = {}, address_old = {};
      26             : 
      27           6 :         assert(link);
      28             : 
      29           6 :         if (!link->dhcp_lease_old)
      30           6 :                 return;
      31             : 
      32           0 :         assert(link->dhcp_lease);
      33             : 
      34           0 :         (void) sd_dhcp_lease_get_address(link->dhcp_lease_old, &address_old);
      35           0 :         (void) sd_dhcp_lease_get_address(link->dhcp_lease, &address);
      36             : 
      37           0 :         (void) dhcp_remove_routes(link, link->dhcp_lease_old, &address_old, false);
      38           0 :         (void) dhcp_remove_router(link, link->dhcp_lease_old, &address_old, false);
      39           0 :         (void) dhcp_remove_dns_routes(link, link->dhcp_lease_old, &address_old, false);
      40             : 
      41           0 :         if (!in4_addr_equal(&address_old, &address))
      42           0 :                 (void) dhcp_remove_address(link, link->dhcp_lease_old, &address_old);
      43             : 
      44           0 :         link->dhcp_lease_old = sd_dhcp_lease_unref(link->dhcp_lease_old);
      45           0 :         link_dirty(link);
      46             : }
      47             : 
      48           0 : static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
      49             :         int r;
      50             : 
      51           0 :         assert(link);
      52           0 :         assert(link->dhcp4_messages > 0);
      53             : 
      54           0 :         link->dhcp4_messages--;
      55             : 
      56           0 :         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
      57           0 :                 return 1;
      58             : 
      59           0 :         r = sd_netlink_message_get_errno(m);
      60           0 :         if (r < 0 && r != -EEXIST) {
      61           0 :                 log_link_error_errno(link, r, "Could not set DHCPv4 route: %m");
      62           0 :                 link_enter_failed(link);
      63           0 :                 return 1;
      64             :         }
      65             : 
      66           0 :         if (link->dhcp4_messages == 0) {
      67           0 :                 link->dhcp4_configured = true;
      68             :                 /* New address and routes are configured now. Let's release old lease. */
      69           0 :                 dhcp4_release_old_lease(link);
      70           0 :                 link_check_ready(link);
      71             :         }
      72             : 
      73           0 :         return 1;
      74             : }
      75             : 
      76           0 : static int route_scope_from_address(const Route *route, const struct in_addr *self_addr) {
      77           0 :         assert(route);
      78           0 :         assert(self_addr);
      79             : 
      80           0 :         if (in4_addr_is_localhost(&route->dst.in) ||
      81           0 :             (!in4_addr_is_null(self_addr) && in4_addr_equal(&route->dst.in, self_addr)))
      82           0 :                 return RT_SCOPE_HOST;
      83           0 :         else if (in4_addr_is_null(&route->gw.in))
      84           0 :                 return RT_SCOPE_LINK;
      85             :         else
      86           0 :                 return RT_SCOPE_UNIVERSE;
      87             : }
      88             : 
      89           0 : static int dhcp_route_configure(Route **route, Link *link) {
      90             :         int r;
      91             : 
      92           0 :         assert(route);
      93           0 :         assert(*route);
      94           0 :         assert(link);
      95             : 
      96           0 :         if (set_contains(link->dhcp_routes, *route))
      97           0 :                 return 0;
      98             : 
      99           0 :         r = route_configure(*route, link, dhcp4_route_handler);
     100           0 :         if (r <= 0)
     101           0 :                 return r;
     102             : 
     103           0 :         link->dhcp4_messages++;
     104             : 
     105           0 :         r = set_put(link->dhcp_routes, *route);
     106           0 :         if (r < 0)
     107           0 :                 return r;
     108             : 
     109           0 :         TAKE_PTR(*route);
     110           0 :         return 0;
     111             : }
     112             : 
     113           0 : static int link_set_dns_routes(Link *link, const struct in_addr *address) {
     114             :         const struct in_addr *dns;
     115             :         uint32_t table;
     116             :         int i, n, r;
     117             : 
     118           0 :         assert(link);
     119           0 :         assert(link->dhcp_lease);
     120           0 :         assert(link->network);
     121             : 
     122           0 :         if (!link->network->dhcp_use_dns ||
     123           0 :             !link->network->dhcp_routes_to_dns)
     124           0 :                 return 0;
     125             : 
     126           0 :         n = sd_dhcp_lease_get_dns(link->dhcp_lease, &dns);
     127           0 :         if (IN_SET(n, 0, -ENODATA))
     128           0 :                 return 0;
     129           0 :         if (n < 0)
     130           0 :                 return log_link_warning_errno(link, n, "DHCP error: could not get DNS servers: %m");
     131             : 
     132           0 :         table = link_get_dhcp_route_table(link);
     133             : 
     134           0 :         for (i = 0; i < n; i ++) {
     135           0 :                 _cleanup_(route_freep) Route *route = NULL;
     136             : 
     137           0 :                 r = route_new(&route);
     138           0 :                 if (r < 0)
     139           0 :                         return log_link_error_errno(link, r,  "Could not allocate route: %m");
     140             : 
     141             :                 /* Set routes to DNS servers. */
     142             : 
     143           0 :                 route->family = AF_INET;
     144           0 :                 route->dst.in = dns[i];
     145           0 :                 route->dst_prefixlen = 32;
     146           0 :                 route->prefsrc.in = *address;
     147           0 :                 route->scope = RT_SCOPE_LINK;
     148           0 :                 route->protocol = RTPROT_DHCP;
     149           0 :                 route->priority = link->network->dhcp_route_metric;
     150           0 :                 route->table = table;
     151             : 
     152           0 :                 r = dhcp_route_configure(&route, link);
     153           0 :                 if (r < 0)
     154           0 :                         return log_link_error_errno(link, r, "Could not set route to DNS server: %m");
     155             :         }
     156             : 
     157           0 :         return 0;
     158             : }
     159             : 
     160           0 : static int link_set_dhcp_routes(Link *link) {
     161           0 :         _cleanup_free_ sd_dhcp_route **static_routes = NULL;
     162           0 :         bool classless_route = false, static_route = false;
     163             :         const struct in_addr *router;
     164             :         struct in_addr address;
     165             :         int r, n, i;
     166             :         uint32_t table;
     167             : 
     168           0 :         assert(link);
     169             : 
     170           0 :         if (!link->dhcp_lease) /* link went down while we configured the IP addresses? */
     171           0 :                 return 0;
     172             : 
     173           0 :         if (!link->network) /* link went down while we configured the IP addresses? */
     174           0 :                 return 0;
     175             : 
     176           0 :         if (!link->network->dhcp_use_routes)
     177           0 :                 return 0;
     178             : 
     179           0 :         if (!link_has_carrier(link) && !link->network->configure_without_carrier)
     180             :                 /* During configuring addresses, the link lost its carrier. As networkd is dropping
     181             :                  * the addresses now, let's not configure the routes either. */
     182           0 :                 return 0;
     183             : 
     184           0 :         r = set_ensure_allocated(&link->dhcp_routes, &route_full_hash_ops);
     185           0 :         if (r < 0)
     186           0 :                 return log_oom();
     187             : 
     188             :         /* Clear old entries in case the set was already allocated */
     189           0 :         set_clear(link->dhcp_routes);
     190             : 
     191           0 :         table = link_get_dhcp_route_table(link);
     192             : 
     193           0 :         r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
     194           0 :         if (r < 0)
     195           0 :                 return log_link_warning_errno(link, r, "DHCP error: could not get address: %m");
     196             : 
     197           0 :         n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes);
     198           0 :         if (n == -ENODATA)
     199           0 :                 log_link_debug_errno(link, n, "DHCP: No routes received from DHCP server: %m");
     200           0 :         else if (n < 0)
     201           0 :                 log_link_debug_errno(link, n, "DHCP error: could not get routes: %m");
     202             : 
     203           0 :         for (i = 0; i < n; i++) {
     204           0 :                 switch (sd_dhcp_route_get_option(static_routes[i])) {
     205           0 :                 case SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
     206           0 :                         classless_route = true;
     207           0 :                         break;
     208           0 :                 case SD_DHCP_OPTION_STATIC_ROUTE:
     209           0 :                         static_route = true;
     210           0 :                         break;
     211             :                 }
     212           0 :         }
     213             : 
     214           0 :         for (i = 0; i < n; i++) {
     215           0 :                 _cleanup_(route_freep) Route *route = NULL;
     216             : 
     217             :                 /* if the DHCP server returns both a Classless Static Routes option and a Static Routes option,
     218             :                    the DHCP client MUST ignore the Static Routes option. */
     219           0 :                 if (classless_route &&
     220           0 :                     sd_dhcp_route_get_option(static_routes[i]) != SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE)
     221           0 :                         continue;
     222             : 
     223           0 :                 r = route_new(&route);
     224           0 :                 if (r < 0)
     225           0 :                         return log_link_error_errno(link, r, "Could not allocate route: %m");
     226             : 
     227           0 :                 route->family = AF_INET;
     228           0 :                 route->protocol = RTPROT_DHCP;
     229           0 :                 assert_se(sd_dhcp_route_get_gateway(static_routes[i], &route->gw.in) >= 0);
     230           0 :                 assert_se(sd_dhcp_route_get_destination(static_routes[i], &route->dst.in) >= 0);
     231           0 :                 assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes[i], &route->dst_prefixlen) >= 0);
     232           0 :                 route->priority = link->network->dhcp_route_metric;
     233           0 :                 route->table = table;
     234           0 :                 route->scope = route_scope_from_address(route, &address);
     235           0 :                 if (IN_SET(route->scope, RT_SCOPE_LINK, RT_SCOPE_UNIVERSE))
     236           0 :                         route->prefsrc.in = address;
     237             : 
     238           0 :                 if (set_contains(link->dhcp_routes, route))
     239           0 :                         continue;
     240             : 
     241           0 :                 r = dhcp_route_configure(&route, link);
     242           0 :                 if (r < 0)
     243           0 :                         return log_link_error_errno(link, r, "Could not set route: %m");
     244             :         }
     245             : 
     246           0 :         r = sd_dhcp_lease_get_router(link->dhcp_lease, &router);
     247           0 :         if (IN_SET(r, 0, -ENODATA))
     248           0 :                 log_link_info(link, "DHCP: No gateway received from DHCP server.");
     249           0 :         else if (r < 0)
     250           0 :                 log_link_warning_errno(link, r, "DHCP error: could not get gateway: %m");
     251           0 :         else if (in4_addr_is_null(&router[0]))
     252           0 :                 log_link_info(link, "DHCP: Received gateway is null.");
     253             : 
     254             :         /* According to RFC 3442: If the DHCP server returns both a Classless Static Routes option and
     255             :            a Router option, the DHCP client MUST ignore the Router option. */
     256           0 :         if (classless_route && static_route)
     257           0 :                 log_link_warning(link, "Classless static routes received from DHCP server: ignoring static-route option and router option");
     258             : 
     259           0 :         if (r > 0 && !classless_route && !in4_addr_is_null(&router[0])) {
     260           0 :                 _cleanup_(route_freep) Route *route = NULL, *route_gw = NULL;
     261             : 
     262           0 :                 r = route_new(&route_gw);
     263           0 :                 if (r < 0)
     264           0 :                         return log_link_error_errno(link, r,  "Could not allocate route: %m");
     265             : 
     266             :                 /* The dhcp netmask may mask out the gateway. Add an explicit
     267             :                  * route for the gw host so that we can route no matter the
     268             :                  * netmask or existing kernel route tables. */
     269           0 :                 route_gw->family = AF_INET;
     270           0 :                 route_gw->dst.in = router[0];
     271           0 :                 route_gw->dst_prefixlen = 32;
     272           0 :                 route_gw->prefsrc.in = address;
     273           0 :                 route_gw->scope = RT_SCOPE_LINK;
     274           0 :                 route_gw->protocol = RTPROT_DHCP;
     275           0 :                 route_gw->priority = link->network->dhcp_route_metric;
     276           0 :                 route_gw->table = table;
     277             : 
     278           0 :                 r = dhcp_route_configure(&route_gw, link);
     279           0 :                 if (r < 0)
     280           0 :                         return log_link_error_errno(link, r, "Could not set host route: %m");
     281             : 
     282           0 :                 r = route_new(&route);
     283           0 :                 if (r < 0)
     284           0 :                         return log_link_error_errno(link, r, "Could not allocate route: %m");
     285             : 
     286           0 :                 route->family = AF_INET;
     287           0 :                 route->gw.in = router[0];
     288           0 :                 route->prefsrc.in = address;
     289           0 :                 route->protocol = RTPROT_DHCP;
     290           0 :                 route->priority = link->network->dhcp_route_metric;
     291           0 :                 route->table = table;
     292             : 
     293           0 :                 r = dhcp_route_configure(&route, link);
     294           0 :                 if (r < 0)
     295           0 :                         return log_link_error_errno(link, r, "Could not set router: %m");
     296             :         }
     297             : 
     298           0 :         return link_set_dns_routes(link, &address);
     299             : }
     300             : 
     301           0 : static int dhcp_remove_routes(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all) {
     302           0 :         _cleanup_free_ sd_dhcp_route **routes = NULL;
     303             :         uint32_t table;
     304             :         int n, i, r;
     305             : 
     306           0 :         assert(link);
     307           0 :         assert(address);
     308             : 
     309           0 :         if (!link->network->dhcp_use_routes)
     310           0 :                 return 0;
     311             : 
     312           0 :         n = sd_dhcp_lease_get_routes(lease, &routes);
     313           0 :         if (IN_SET(n, 0, -ENODATA))
     314           0 :                 return 0;
     315           0 :         else if (n < 0)
     316           0 :                 return log_link_error_errno(link, n, "DHCP error: Failed to get routes: %m");
     317             : 
     318           0 :         table = link_get_dhcp_route_table(link);
     319             : 
     320           0 :         for (i = 0; i < n; i++) {
     321           0 :                 _cleanup_(route_freep) Route *route = NULL;
     322             : 
     323           0 :                 r = route_new(&route);
     324           0 :                 if (r < 0)
     325           0 :                         return log_oom();
     326             : 
     327           0 :                 route->family = AF_INET;
     328           0 :                 assert_se(sd_dhcp_route_get_gateway(routes[i], &route->gw.in) >= 0);
     329           0 :                 assert_se(sd_dhcp_route_get_destination(routes[i], &route->dst.in) >= 0);
     330           0 :                 assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &route->dst_prefixlen) >= 0);
     331           0 :                 route->priority = link->network->dhcp_route_metric;
     332           0 :                 route->table = table;
     333           0 :                 route->scope = route_scope_from_address(route, address);
     334           0 :                 if (IN_SET(route->scope, RT_SCOPE_LINK, RT_SCOPE_UNIVERSE))
     335           0 :                         route->prefsrc.in = *address;
     336             : 
     337           0 :                 if (!remove_all && set_contains(link->dhcp_routes, route))
     338           0 :                         continue;
     339             : 
     340           0 :                 (void) route_remove(route, link, NULL);
     341             :         }
     342             : 
     343           0 :         return n;
     344             : }
     345             : 
     346           0 : static int dhcp_remove_router(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all) {
     347           0 :         _cleanup_(route_freep) Route *route_gw = NULL, *route = NULL;
     348             :         const struct in_addr *router;
     349             :         uint32_t table;
     350             :         int r;
     351             : 
     352           0 :         assert(link);
     353           0 :         assert(address);
     354             : 
     355           0 :         if (!link->network->dhcp_use_routes)
     356           0 :                 return 0;
     357             : 
     358           0 :         r = sd_dhcp_lease_get_router(lease, &router);
     359           0 :         if (IN_SET(r, 0, -ENODATA)) {
     360           0 :                 log_link_debug(link, "DHCP: No gateway received from DHCP server.");
     361           0 :                 return 0;
     362           0 :         } else if (r < 0)
     363           0 :                 return log_link_error_errno(link, r, "DHCP error: could not get gateway: %m");
     364           0 :         else if (in4_addr_is_null(&router[0])) {
     365           0 :                 log_link_info(link, "DHCP: Received gateway is null, ignoring.");
     366           0 :                 return 0;
     367             :         }
     368             : 
     369           0 :         table = link_get_dhcp_route_table(link);
     370             : 
     371           0 :         r = route_new(&route_gw);
     372           0 :         if (r < 0)
     373           0 :                 return log_oom();
     374             : 
     375           0 :         route_gw->family = AF_INET;
     376           0 :         route_gw->dst.in = router[0];
     377           0 :         route_gw->dst_prefixlen = 32;
     378           0 :         route_gw->prefsrc.in = *address;
     379           0 :         route_gw->scope = RT_SCOPE_LINK;
     380           0 :         route_gw->protocol = RTPROT_DHCP;
     381           0 :         route_gw->priority = link->network->dhcp_route_metric;
     382           0 :         route_gw->table = table;
     383             : 
     384           0 :         if (remove_all || !set_contains(link->dhcp_routes, route_gw))
     385           0 :                 (void) route_remove(route_gw, link, NULL);
     386             : 
     387           0 :         r = route_new(&route);
     388           0 :         if (r < 0)
     389           0 :                 return log_oom();
     390             : 
     391           0 :         route->family = AF_INET;
     392           0 :         route->gw.in = router[0];
     393           0 :         route->prefsrc.in = *address;
     394           0 :         route->protocol = RTPROT_DHCP;
     395           0 :         route->priority = link->network->dhcp_route_metric;
     396           0 :         route->table = table;
     397             : 
     398           0 :         if (remove_all || !set_contains(link->dhcp_routes, route))
     399           0 :                 (void) route_remove(route, link, NULL);
     400             : 
     401           0 :         return 0;
     402             : }
     403             : 
     404           0 : static int dhcp_remove_dns_routes(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all) {
     405             :         const struct in_addr *dns;
     406             :         uint32_t table;
     407             :         int i, n, r;
     408             : 
     409           0 :         assert(link);
     410           0 :         assert(lease);
     411           0 :         assert(link->network);
     412             : 
     413           0 :         if (!link->network->dhcp_use_dns ||
     414           0 :             !link->network->dhcp_routes_to_dns)
     415           0 :                 return 0;
     416             : 
     417           0 :         n = sd_dhcp_lease_get_dns(lease, &dns);
     418           0 :         if (IN_SET(n, 0, -ENODATA))
     419           0 :                 return 0;
     420           0 :         if (n < 0)
     421           0 :                 return log_link_warning_errno(link, n, "DHCP error: could not get DNS servers: %m");
     422             : 
     423           0 :         table = link_get_dhcp_route_table(link);
     424             : 
     425           0 :         for (i = 0; i < n; i ++) {
     426           0 :                 _cleanup_(route_freep) Route *route = NULL;
     427             : 
     428           0 :                 r = route_new(&route);
     429           0 :                 if (r < 0)
     430           0 :                         return log_link_error_errno(link, r,  "Could not allocate route: %m");
     431             : 
     432           0 :                 route->family = AF_INET;
     433           0 :                 route->dst.in = dns[i];
     434           0 :                 route->dst_prefixlen = 32;
     435           0 :                 route->prefsrc.in = *address;
     436           0 :                 route->scope = RT_SCOPE_LINK;
     437           0 :                 route->protocol = RTPROT_DHCP;
     438           0 :                 route->priority = link->network->dhcp_route_metric;
     439           0 :                 route->table = table;
     440             : 
     441           0 :                 if (!remove_all && set_contains(link->dhcp_routes, route))
     442           0 :                         continue;
     443             : 
     444           0 :                 (void) route_remove(route, link, NULL);
     445             :         }
     446             : 
     447           0 :         return 0;
     448             : }
     449             : 
     450           0 : static int dhcp_remove_address(Link *link, sd_dhcp_lease *lease, const struct in_addr *address) {
     451           0 :         _cleanup_(address_freep) Address *a = NULL;
     452             :         struct in_addr netmask;
     453             :         int r;
     454             : 
     455           0 :         assert(link);
     456           0 :         assert(address);
     457             : 
     458           0 :         if (in4_addr_is_null(address))
     459           0 :                 return 0;
     460             : 
     461           0 :         r = address_new(&a);
     462           0 :         if (r < 0)
     463           0 :                 return log_oom();
     464             : 
     465           0 :         a->family = AF_INET;
     466           0 :         a->in_addr.in = *address;
     467             : 
     468           0 :         if (sd_dhcp_lease_get_netmask(lease, &netmask) >= 0)
     469           0 :                 a->prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
     470             : 
     471           0 :         (void) address_remove(a, link, NULL);
     472             : 
     473           0 :         return 0;
     474             : }
     475             : 
     476           0 : static int dhcp_reset_mtu(Link *link) {
     477             :         uint16_t mtu;
     478             :         int r;
     479             : 
     480           0 :         assert(link);
     481             : 
     482           0 :         if (!link->network->dhcp_use_mtu)
     483           0 :                 return 0;
     484             : 
     485           0 :         r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
     486           0 :         if (r < 0)
     487           0 :                 return r;
     488             : 
     489           0 :         if (link->original_mtu == mtu)
     490           0 :                 return 0;
     491             : 
     492           0 :         r = link_set_mtu(link, link->original_mtu);
     493           0 :         if (r < 0) {
     494           0 :                 log_link_error_errno(link, r, "DHCP error: could not reset MTU: %m");
     495           0 :                 link_enter_failed(link);
     496           0 :                 return r;
     497             :         }
     498             : 
     499           0 :         return 0;
     500             : }
     501             : 
     502           0 : static int dhcp_reset_hostname(Link *link) {
     503             :         const char *hostname;
     504             :         int r;
     505             : 
     506           0 :         assert(link);
     507             : 
     508           0 :         if (!link->network->dhcp_use_hostname)
     509           0 :                 return 0;
     510             : 
     511           0 :         hostname = link->network->dhcp_hostname;
     512           0 :         if (!hostname)
     513           0 :                 (void) sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
     514             : 
     515           0 :         if (!hostname)
     516           0 :                 return 0;
     517             : 
     518             :         /* If a hostname was set due to the lease, then unset it now. */
     519           0 :         r = manager_set_hostname(link->manager, NULL);
     520           0 :         if (r < 0)
     521           0 :                 return log_link_error_errno(link, r, "DHCP error: Failed to reset transient hostname: %m");
     522             : 
     523           0 :         return 0;
     524             : }
     525             : 
     526           0 : static int dhcp_lease_lost(Link *link) {
     527           0 :         struct in_addr address = {};
     528             : 
     529           0 :         assert(link);
     530           0 :         assert(link->dhcp_lease);
     531             : 
     532           0 :         log_link_warning(link, "DHCP lease lost");
     533             : 
     534           0 :         link->dhcp4_configured = false;
     535             : 
     536           0 :         (void) sd_dhcp_lease_get_address(link->dhcp_lease, &address);
     537           0 :         (void) dhcp_remove_routes(link, link->dhcp_lease, &address, true);
     538           0 :         (void) dhcp_remove_router(link, link->dhcp_lease, &address, true);
     539           0 :         (void) dhcp_remove_dns_routes(link, link->dhcp_lease, &address, true);
     540           0 :         (void) dhcp_remove_address(link, link->dhcp_lease, &address);
     541           0 :         (void) dhcp_reset_mtu(link);
     542           0 :         (void) dhcp_reset_hostname(link);
     543             : 
     544           0 :         link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
     545           0 :         link_dirty(link);
     546             : 
     547           0 :         return 0;
     548             : }
     549             : 
     550           0 : static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
     551             :         int r;
     552             : 
     553           0 :         assert(link);
     554             : 
     555           0 :         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
     556           0 :                 return 1;
     557             : 
     558           0 :         r = sd_netlink_message_get_errno(m);
     559           0 :         if (r < 0 && r != -EEXIST) {
     560           0 :                 log_link_error_errno(link, r, "Could not set DHCPv4 address: %m");
     561           0 :                 link_enter_failed(link);
     562           0 :                 return 1;
     563           0 :         } else if (r >= 0)
     564           0 :                 (void) manager_rtnl_process_address(rtnl, m, link->manager);
     565             : 
     566           0 :         r = link_set_dhcp_routes(link);
     567           0 :         if (r < 0) {
     568           0 :                 link_enter_failed(link);
     569           0 :                 return 1;
     570             :         }
     571             : 
     572             :         /* Add back static routes since kernel removes while DHCPv4 address is removed from when lease expires */
     573           0 :         r = link_request_set_routes(link);
     574           0 :         if (r < 0) {
     575           0 :                 link_enter_failed(link);
     576           0 :                 return 1;
     577             :         }
     578             : 
     579           0 :         if (link->dhcp4_messages == 0) {
     580           0 :                 link->dhcp4_configured = true;
     581             :                 /* The new address is configured, and no route is requested.
     582             :                  * Let's drop the old lease. */
     583           0 :                 dhcp4_release_old_lease(link);
     584           0 :                 link_check_ready(link);
     585             :         }
     586             : 
     587           0 :         return 1;
     588             : }
     589             : 
     590           0 : static int dhcp4_update_address(Link *link,
     591             :                                 struct in_addr *address,
     592             :                                 struct in_addr *netmask,
     593             :                                 uint32_t lifetime) {
     594           0 :         _cleanup_(address_freep) Address *addr = NULL;
     595             :         unsigned prefixlen;
     596             :         int r;
     597             : 
     598           0 :         assert(address);
     599           0 :         assert(netmask);
     600           0 :         assert(lifetime);
     601             : 
     602           0 :         prefixlen = in4_addr_netmask_to_prefixlen(netmask);
     603             : 
     604           0 :         r = address_new(&addr);
     605           0 :         if (r < 0)
     606           0 :                 return r;
     607             : 
     608           0 :         addr->family = AF_INET;
     609           0 :         addr->in_addr.in.s_addr = address->s_addr;
     610           0 :         addr->cinfo.ifa_prefered = lifetime;
     611           0 :         addr->cinfo.ifa_valid = lifetime;
     612           0 :         addr->prefixlen = prefixlen;
     613           0 :         addr->broadcast.s_addr = address->s_addr | ~netmask->s_addr;
     614             : 
     615             :         /* allow reusing an existing address and simply update its lifetime
     616             :          * in case it already exists */
     617           0 :         r = address_configure(addr, link, dhcp4_address_handler, true);
     618           0 :         if (r < 0)
     619           0 :                 return r;
     620             : 
     621           0 :         return 0;
     622             : }
     623             : 
     624           0 : static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
     625             :         sd_dhcp_lease *lease;
     626             :         struct in_addr address;
     627             :         struct in_addr netmask;
     628           0 :         uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
     629             :         int r;
     630             : 
     631           0 :         assert(link);
     632           0 :         assert(client);
     633           0 :         assert(link->network);
     634             : 
     635           0 :         r = sd_dhcp_client_get_lease(client, &lease);
     636           0 :         if (r < 0)
     637           0 :                 return log_link_warning_errno(link, r, "DHCP error: no lease: %m");
     638             : 
     639           0 :         sd_dhcp_lease_unref(link->dhcp_lease);
     640           0 :         link->dhcp4_configured = false;
     641           0 :         link->dhcp_lease = sd_dhcp_lease_ref(lease);
     642           0 :         link_dirty(link);
     643             : 
     644           0 :         r = sd_dhcp_lease_get_address(lease, &address);
     645           0 :         if (r < 0)
     646           0 :                 return log_link_warning_errno(link, r, "DHCP error: no address: %m");
     647             : 
     648           0 :         r = sd_dhcp_lease_get_netmask(lease, &netmask);
     649           0 :         if (r < 0)
     650           0 :                 return log_link_warning_errno(link, r, "DHCP error: no netmask: %m");
     651             : 
     652           0 :         if (!FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
     653           0 :                 r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime);
     654           0 :                 if (r < 0)
     655           0 :                         return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
     656             :         }
     657             : 
     658           0 :         r = dhcp4_update_address(link, &address, &netmask, lifetime);
     659           0 :         if (r < 0)
     660           0 :                 return log_link_warning_errno(link, r, "Could not update IP address: %m");
     661             : 
     662           0 :         return 0;
     663             : }
     664             : 
     665           0 : static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
     666             :         const struct in_addr *router;
     667             :         sd_dhcp_lease *lease;
     668             :         struct in_addr address;
     669             :         struct in_addr netmask;
     670             :         unsigned prefixlen;
     671           0 :         uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
     672             :         int r;
     673             : 
     674           0 :         assert(client);
     675           0 :         assert(link);
     676             : 
     677           0 :         link->dhcp4_configured = false;
     678             : 
     679           0 :         r = sd_dhcp_client_get_lease(client, &lease);
     680           0 :         if (r < 0)
     681           0 :                 return log_link_error_errno(link, r, "DHCP error: No lease: %m");
     682             : 
     683           0 :         r = sd_dhcp_lease_get_address(lease, &address);
     684           0 :         if (r < 0)
     685           0 :                 return log_link_error_errno(link, r, "DHCP error: No address: %m");
     686             : 
     687           0 :         r = sd_dhcp_lease_get_netmask(lease, &netmask);
     688           0 :         if (r < 0)
     689           0 :                 return log_link_error_errno(link, r, "DHCP error: No netmask: %m");
     690             : 
     691           0 :         prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
     692             : 
     693           0 :         if (!FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
     694           0 :                 r = sd_dhcp_lease_get_lifetime(lease, &lifetime);
     695           0 :                 if (r < 0)
     696           0 :                         return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
     697             :         }
     698             : 
     699           0 :         r = sd_dhcp_lease_get_router(lease, &router);
     700           0 :         if (r < 0 && r != -ENODATA)
     701           0 :                 return log_link_error_errno(link, r, "DHCP error: Could not get gateway: %m");
     702             : 
     703           0 :         if (r > 0 && !in4_addr_is_null(&router[0]))
     704           0 :                 log_struct(LOG_INFO,
     705             :                            LOG_LINK_INTERFACE(link),
     706             :                            LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
     707             :                                             ADDRESS_FMT_VAL(address),
     708             :                                             prefixlen,
     709             :                                             ADDRESS_FMT_VAL(router[0])),
     710             :                            "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
     711             :                            "PREFIXLEN=%u", prefixlen,
     712             :                            "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(router[0]));
     713             :         else
     714           0 :                 log_struct(LOG_INFO,
     715             :                            LOG_LINK_INTERFACE(link),
     716             :                            LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u",
     717             :                                             ADDRESS_FMT_VAL(address),
     718             :                                             prefixlen),
     719             :                            "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
     720             :                            "PREFIXLEN=%u", prefixlen);
     721             : 
     722           0 :         link->dhcp_lease = sd_dhcp_lease_ref(lease);
     723           0 :         link_dirty(link);
     724             : 
     725           0 :         if (link->network->dhcp_use_mtu) {
     726             :                 uint16_t mtu;
     727             : 
     728           0 :                 r = sd_dhcp_lease_get_mtu(lease, &mtu);
     729           0 :                 if (r >= 0) {
     730           0 :                         r = link_set_mtu(link, mtu);
     731           0 :                         if (r < 0)
     732           0 :                                 log_link_error_errno(link, r, "Failed to set MTU to %" PRIu16 ": %m", mtu);
     733             :                 }
     734             :         }
     735             : 
     736           0 :         if (link->network->dhcp_use_hostname) {
     737           0 :                 const char *dhcpname = NULL;
     738           0 :                 _cleanup_free_ char *hostname = NULL;
     739             : 
     740           0 :                 if (link->network->dhcp_hostname)
     741           0 :                         dhcpname = link->network->dhcp_hostname;
     742             :                 else
     743           0 :                         (void) sd_dhcp_lease_get_hostname(lease, &dhcpname);
     744             : 
     745           0 :                 if (dhcpname) {
     746           0 :                         r = shorten_overlong(dhcpname, &hostname);
     747           0 :                         if (r < 0)
     748           0 :                                 log_link_warning_errno(link, r, "Unable to shorten overlong DHCP hostname '%s', ignoring: %m", dhcpname);
     749           0 :                         if (r == 1)
     750           0 :                                 log_link_notice(link, "Overlong DHCP hostname received, shortened from '%s' to '%s'", dhcpname, hostname);
     751             :                 }
     752             : 
     753           0 :                 if (hostname) {
     754           0 :                         r = manager_set_hostname(link->manager, hostname);
     755           0 :                         if (r < 0)
     756           0 :                                 log_link_error_errno(link, r, "Failed to set transient hostname to '%s': %m", hostname);
     757             :                 }
     758             :         }
     759             : 
     760           0 :         if (link->network->dhcp_use_timezone) {
     761           0 :                 const char *tz = NULL;
     762             : 
     763           0 :                 (void) sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz);
     764             : 
     765           0 :                 if (tz) {
     766           0 :                         r = manager_set_timezone(link->manager, tz);
     767           0 :                         if (r < 0)
     768           0 :                                 log_link_error_errno(link, r, "Failed to set timezone to '%s': %m", tz);
     769             :                 }
     770             :         }
     771             : 
     772           0 :         r = dhcp4_update_address(link, &address, &netmask, lifetime);
     773           0 :         if (r < 0)
     774           0 :                 return log_link_warning_errno(link, r, "Could not update IP address: %m");
     775             : 
     776           0 :         return 0;
     777             : }
     778             : 
     779           0 : static int dhcp_lease_ip_change(sd_dhcp_client *client, Link *link) {
     780             :         int r;
     781             : 
     782           0 :         link->dhcp_lease_old = TAKE_PTR(link->dhcp_lease);
     783             : 
     784             :         /* On ip address change, to keep the connectability, we would like to assign new address and
     785             :          * routes, and then release old lease. There are two possible success paths:
     786             :          *
     787             :          * 1. new address and routes are configured.
     788             :          *    -> handled by dhcp_release_old_lease() in dhcp4_route_handler().
     789             :          * 2. new address is configured and no route is requested.
     790             :          *    -> handled by dhcp_release_old_lease() in dhcp4_address_handler().
     791             :          *
     792             :          * On error in assigning new address and routes, then the link always enters to the failed
     793             :          * state. And link_enter_failed() leads to the DHCP client to be stopped. So,
     794             :          * dhcp_release_old_lease() will be also called by link_stop_clients().
     795             :          */
     796             : 
     797           0 :         r = dhcp_lease_acquired(client, link);
     798           0 :         if (r < 0) {
     799             :                 /* If it fails, then the new address is not configured yet.
     800             :                  * So, let's simply drop the old lease. */
     801           0 :                 sd_dhcp_lease_unref(link->dhcp_lease);
     802           0 :                 link->dhcp_lease = TAKE_PTR(link->dhcp_lease_old);
     803           0 :                 (void) dhcp_lease_lost(link);
     804           0 :                 return r;
     805             :         }
     806             : 
     807           0 :         return 0;
     808             : }
     809             : 
     810           0 : static int dhcp_server_is_black_listed(Link *link, sd_dhcp_client *client) {
     811             :         sd_dhcp_lease *lease;
     812             :         struct in_addr addr;
     813             :         int r;
     814             : 
     815           0 :         assert(link);
     816           0 :         assert(link->network);
     817           0 :         assert(client);
     818             : 
     819           0 :         r = sd_dhcp_client_get_lease(client, &lease);
     820           0 :         if (r < 0)
     821           0 :                 return log_link_error_errno(link, r, "Failed to get DHCP lease: %m");
     822             : 
     823           0 :         r = sd_dhcp_lease_get_server_identifier(lease, &addr);
     824           0 :         if (r < 0)
     825           0 :                 return log_link_debug_errno(link, r, "Failed to get DHCP server ip address: %m");
     826             : 
     827           0 :         if (set_contains(link->network->dhcp_black_listed_ip, UINT32_TO_PTR(addr.s_addr))) {
     828           0 :                 log_struct(LOG_DEBUG,
     829             :                            LOG_LINK_INTERFACE(link),
     830             :                            LOG_LINK_MESSAGE(link, "DHCPv4 ip '%u.%u.%u.%u' found in black listed ip addresses, ignoring offer",
     831             :                                             ADDRESS_FMT_VAL(addr)));
     832           0 :                 return true;
     833             :         }
     834             : 
     835           0 :         return false;
     836             : }
     837             : 
     838           0 : static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
     839           0 :         Link *link = userdata;
     840             :         int r;
     841             : 
     842           0 :         assert(link);
     843           0 :         assert(link->network);
     844           0 :         assert(link->manager);
     845             : 
     846           0 :         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
     847           0 :                 return 0;
     848             : 
     849           0 :         switch (event) {
     850           0 :                 case SD_DHCP_CLIENT_EVENT_STOP:
     851             : 
     852           0 :                         if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4)) {
     853           0 :                                 assert(link->ipv4ll);
     854             : 
     855           0 :                                 log_link_debug(link, "DHCP client is stopped. Acquiring IPv4 link-local address");
     856             : 
     857           0 :                                 r = sd_ipv4ll_start(link->ipv4ll);
     858           0 :                                 if (r < 0)
     859           0 :                                         return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
     860             :                         }
     861             : 
     862           0 :                         if (FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
     863           0 :                                 log_link_notice(link, "DHCPv4 connection considered critical, ignoring request to reconfigure it.");
     864           0 :                                 return 0;
     865             :                         }
     866             : 
     867           0 :                         if (link->network->dhcp_send_release)
     868           0 :                                 (void) sd_dhcp_client_send_release(client);
     869             : 
     870           0 :                         if (link->dhcp_lease) {
     871           0 :                                 r = dhcp_lease_lost(link);
     872           0 :                                 if (r < 0) {
     873           0 :                                         link_enter_failed(link);
     874           0 :                                         return r;
     875             :                                 }
     876             :                         }
     877             : 
     878           0 :                         break;
     879           0 :                 case SD_DHCP_CLIENT_EVENT_EXPIRED:
     880           0 :                         if (FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
     881           0 :                                 log_link_notice(link, "DHCPv4 connection considered critical, ignoring request to reconfigure it.");
     882           0 :                                 return 0;
     883             :                         }
     884             : 
     885           0 :                         if (link->dhcp_lease) {
     886           0 :                                 r = dhcp_lease_lost(link);
     887           0 :                                 if (r < 0) {
     888           0 :                                         link_enter_failed(link);
     889           0 :                                         return r;
     890             :                                 }
     891             :                         }
     892             : 
     893           0 :                         break;
     894           0 :                 case SD_DHCP_CLIENT_EVENT_IP_CHANGE:
     895           0 :                         if (FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
     896           0 :                                 log_link_notice(link, "DHCPv4 connection considered critical, ignoring request to reconfigure it.");
     897           0 :                                 return 0;
     898             :                         }
     899             : 
     900           0 :                         r = dhcp_lease_ip_change(client, link);
     901           0 :                         if (r < 0) {
     902           0 :                                 link_enter_failed(link);
     903           0 :                                 return r;
     904             :                         }
     905             : 
     906           0 :                         break;
     907           0 :                 case SD_DHCP_CLIENT_EVENT_RENEW:
     908           0 :                         r = dhcp_lease_renew(client, link);
     909           0 :                         if (r < 0) {
     910           0 :                                 link_enter_failed(link);
     911           0 :                                 return r;
     912             :                         }
     913           0 :                         break;
     914           0 :                 case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE:
     915           0 :                         r = dhcp_lease_acquired(client, link);
     916           0 :                         if (r < 0) {
     917           0 :                                 link_enter_failed(link);
     918           0 :                                 return r;
     919             :                         }
     920           0 :                         break;
     921           0 :                 case SD_DHCP_CLIENT_EVENT_SELECTING:
     922           0 :                         r = dhcp_server_is_black_listed(link, client);
     923           0 :                         if (r < 0)
     924           0 :                                 return r;
     925           0 :                         if (r != 0)
     926           0 :                                 return -ENOMSG;
     927           0 :                         break;
     928           0 :                 default:
     929           0 :                         if (event < 0)
     930           0 :                                 log_link_warning_errno(link, event, "DHCP error: Client failed: %m");
     931             :                         else
     932           0 :                                 log_link_warning(link, "DHCP unknown event: %i", event);
     933           0 :                         break;
     934             :         }
     935             : 
     936           0 :         return 0;
     937             : }
     938             : 
     939           0 : static int dhcp4_set_hostname(Link *link) {
     940           0 :         _cleanup_free_ char *hostname = NULL;
     941             :         const char *hn;
     942             :         int r;
     943             : 
     944           0 :         assert(link);
     945             : 
     946           0 :         if (!link->network->dhcp_send_hostname)
     947           0 :                 hn = NULL;
     948           0 :         else if (link->network->dhcp_hostname)
     949           0 :                 hn = link->network->dhcp_hostname;
     950             :         else {
     951           0 :                 r = gethostname_strict(&hostname);
     952           0 :                 if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */
     953           0 :                         return r;
     954             : 
     955           0 :                 hn = hostname;
     956             :         }
     957             : 
     958           0 :         r = sd_dhcp_client_set_hostname(link->dhcp_client, hn);
     959           0 :         if (r == -EINVAL && hostname)
     960             :                 /* Ignore error when the machine's hostname is not suitable to send in DHCP packet. */
     961           0 :                 log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
     962           0 :         else if (r < 0)
     963           0 :                 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set hostname: %m");
     964             : 
     965           0 :         return 0;
     966             : }
     967             : 
     968           0 : static bool promote_secondaries_enabled(const char *ifname) {
     969           0 :         _cleanup_free_ char *promote_secondaries_sysctl = NULL;
     970             :         char *promote_secondaries_path;
     971             :         int r;
     972             : 
     973           0 :         promote_secondaries_path = strjoina("net/ipv4/conf/", ifname, "/promote_secondaries");
     974           0 :         r = sysctl_read(promote_secondaries_path, &promote_secondaries_sysctl);
     975           0 :         if (r < 0) {
     976           0 :                 log_debug_errno(r, "Cannot read sysctl %s", promote_secondaries_path);
     977           0 :                 return false;
     978             :         }
     979             : 
     980           0 :         truncate_nl(promote_secondaries_sysctl);
     981           0 :         r = parse_boolean(promote_secondaries_sysctl);
     982           0 :         if (r < 0)
     983           0 :                 log_warning_errno(r, "Cannot parse sysctl %s with content %s as boolean", promote_secondaries_path, promote_secondaries_sysctl);
     984           0 :         return r > 0;
     985             : }
     986             : 
     987             : /* dhcp4_set_promote_secondaries will ensure this interface has
     988             :  * the "promote_secondaries" option in the kernel set. If this sysctl
     989             :  * is not set DHCP will work only as long as the IP address does not
     990             :  * changes between leases. The kernel will remove all secondary IP
     991             :  * addresses of an interface otherwise. The way systemd-network works
     992             :  * is that the new IP of a lease is added as a secondary IP and when
     993             :  * the primary one expires it relies on the kernel to promote the
     994             :  * secondary IP. See also https://github.com/systemd/systemd/issues/7163
     995             :  */
     996           0 : int dhcp4_set_promote_secondaries(Link *link) {
     997             :         int r;
     998             : 
     999           0 :         assert(link);
    1000           0 :         assert(link->network);
    1001           0 :         assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);
    1002             : 
    1003             :         /* check if the kernel has promote_secondaries enabled for our
    1004             :          * interface. If it is not globally enabled or enabled for the
    1005             :          * specific interface we must either enable it.
    1006             :          */
    1007           0 :         if (!(promote_secondaries_enabled("all") || promote_secondaries_enabled(link->ifname))) {
    1008           0 :                 char *promote_secondaries_path = NULL;
    1009             : 
    1010           0 :                 log_link_debug(link, "promote_secondaries is unset, setting it");
    1011           0 :                 promote_secondaries_path = strjoina("net/ipv4/conf/", link->ifname, "/promote_secondaries");
    1012           0 :                 r = sysctl_write(promote_secondaries_path, "1");
    1013           0 :                 if (r < 0)
    1014           0 :                         log_link_warning_errno(link, r, "cannot set sysctl %s to 1", promote_secondaries_path);
    1015           0 :                 return r > 0;
    1016             :         }
    1017             : 
    1018           0 :         return 0;
    1019             : }
    1020             : 
    1021           0 : int dhcp4_set_client_identifier(Link *link) {
    1022             :         int r;
    1023             : 
    1024           0 :         assert(link);
    1025           0 :         assert(link->network);
    1026           0 :         assert(link->dhcp_client);
    1027             : 
    1028           0 :         switch (link->network->dhcp_client_identifier) {
    1029           0 :         case DHCP_CLIENT_ID_DUID: {
    1030             :                 /* If configured, apply user specified DUID and IAID */
    1031           0 :                 const DUID *duid = link_get_duid(link);
    1032             : 
    1033           0 :                 if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0)
    1034           0 :                         r = sd_dhcp_client_set_iaid_duid_llt(link->dhcp_client,
    1035           0 :                                                              link->network->iaid_set,
    1036           0 :                                                              link->network->iaid,
    1037             :                                                              duid->llt_time);
    1038             :                 else
    1039           0 :                         r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
    1040           0 :                                                          link->network->iaid_set,
    1041           0 :                                                          link->network->iaid,
    1042           0 :                                                          duid->type,
    1043           0 :                                                          duid->raw_data_len > 0 ? duid->raw_data : NULL,
    1044           0 :                                                          duid->raw_data_len);
    1045           0 :                 if (r < 0)
    1046           0 :                         return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set IAID+DUID: %m");
    1047           0 :                 break;
    1048             :         }
    1049           0 :         case DHCP_CLIENT_ID_DUID_ONLY: {
    1050             :                 /* If configured, apply user specified DUID */
    1051           0 :                 const DUID *duid = link_get_duid(link);
    1052             : 
    1053           0 :                 if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0)
    1054           0 :                         r = sd_dhcp_client_set_duid_llt(link->dhcp_client,
    1055             :                                                         duid->llt_time);
    1056             :                 else
    1057           0 :                         r = sd_dhcp_client_set_duid(link->dhcp_client,
    1058           0 :                                                     duid->type,
    1059           0 :                                                     duid->raw_data_len > 0 ? duid->raw_data : NULL,
    1060           0 :                                                     duid->raw_data_len);
    1061           0 :                 if (r < 0)
    1062           0 :                         return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set DUID: %m");
    1063           0 :                 break;
    1064             :         }
    1065           0 :         case DHCP_CLIENT_ID_MAC:
    1066           0 :                 r = sd_dhcp_client_set_client_id(link->dhcp_client,
    1067             :                                                  ARPHRD_ETHER,
    1068           0 :                                                  (const uint8_t *) &link->mac,
    1069             :                                                  sizeof(link->mac));
    1070           0 :                 if (r < 0)
    1071           0 :                         return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set client ID: %m");
    1072           0 :                 break;
    1073           0 :         default:
    1074           0 :                 assert_not_reached("Unknown client identifier type.");
    1075             :         }
    1076             : 
    1077           0 :         return 0;
    1078             : }
    1079             : 
    1080           0 : int dhcp4_configure(Link *link) {
    1081             :         int r;
    1082             : 
    1083           0 :         assert(link);
    1084           0 :         assert(link->network);
    1085           0 :         assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);
    1086             : 
    1087           0 :         if (!link->dhcp_client) {
    1088           0 :                 r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize);
    1089           0 :                 if (r == -ENOMEM)
    1090           0 :                         return log_oom();
    1091           0 :                 if (r < 0)
    1092           0 :                         return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to create DHCP4 client: %m");
    1093             :         }
    1094             : 
    1095           0 :         r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
    1096           0 :         if (r < 0)
    1097           0 :                 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to attach event: %m");
    1098             : 
    1099           0 :         r = sd_dhcp_client_set_mac(link->dhcp_client,
    1100           0 :                                    (const uint8_t *) &link->mac,
    1101             :                                    sizeof (link->mac), ARPHRD_ETHER);
    1102           0 :         if (r < 0)
    1103           0 :                 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set MAC address: %m");
    1104             : 
    1105           0 :         r = sd_dhcp_client_set_ifindex(link->dhcp_client, link->ifindex);
    1106           0 :         if (r < 0)
    1107           0 :                 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set ifindex: %m");
    1108             : 
    1109           0 :         r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp4_handler, link);
    1110           0 :         if (r < 0)
    1111           0 :                 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set callback: %m");
    1112             : 
    1113           0 :         r = sd_dhcp_client_set_request_broadcast(link->dhcp_client,
    1114           0 :                                                  link->network->dhcp_broadcast);
    1115           0 :         if (r < 0)
    1116           0 :                 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for broadcast: %m");
    1117             : 
    1118           0 :         if (link->mtu) {
    1119           0 :                 r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu);
    1120           0 :                 if (r < 0)
    1121           0 :                         return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set MTU: %m");
    1122             :         }
    1123             : 
    1124           0 :         if (link->network->dhcp_use_mtu) {
    1125           0 :                 r = sd_dhcp_client_set_request_option(link->dhcp_client,
    1126             :                                                       SD_DHCP_OPTION_INTERFACE_MTU);
    1127           0 :                 if (r < 0)
    1128           0 :                         return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for MTU: %m");
    1129             :         }
    1130             : 
    1131             :         /* NOTE: even if this variable is called "use", it also "sends" PRL
    1132             :          * options, maybe there should be a different configuration variable
    1133             :          * to send or not route options?. */
    1134             :         /* NOTE: when using Anonymize=yes, routes PRL options are sent
    1135             :          * by default, so they don't need to be added here. */
    1136           0 :         if (link->network->dhcp_use_routes && !link->network->dhcp_anonymize) {
    1137           0 :                 r = sd_dhcp_client_set_request_option(link->dhcp_client,
    1138             :                                                       SD_DHCP_OPTION_STATIC_ROUTE);
    1139           0 :                 if (r < 0)
    1140           0 :                         return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for static route: %m");
    1141             : 
    1142           0 :                 r = sd_dhcp_client_set_request_option(link->dhcp_client,
    1143             :                                                       SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE);
    1144           0 :                 if (r < 0)
    1145           0 :                         return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for classless static route: %m");
    1146             :         }
    1147             : 
    1148           0 :         if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO && !link->network->dhcp_anonymize) {
    1149           0 :                 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_DOMAIN_SEARCH_LIST);
    1150           0 :                 if (r < 0)
    1151           0 :                         return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for domain search list: %m");
    1152             :         }
    1153             : 
    1154           0 :         if (link->network->dhcp_use_ntp) {
    1155           0 :                 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NTP_SERVER);
    1156           0 :                 if (r < 0)
    1157           0 :                         return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for NTP server: %m");
    1158             :         }
    1159             : 
    1160           0 :         if (link->network->dhcp_use_timezone) {
    1161           0 :                 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE);
    1162           0 :                 if (r < 0)
    1163           0 :                         return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for timezone: %m");
    1164             :         }
    1165             : 
    1166           0 :         r = dhcp4_set_hostname(link);
    1167           0 :         if (r < 0)
    1168           0 :                 return r;
    1169             : 
    1170           0 :         if (link->network->dhcp_vendor_class_identifier) {
    1171           0 :                 r = sd_dhcp_client_set_vendor_class_identifier(link->dhcp_client,
    1172           0 :                                                                link->network->dhcp_vendor_class_identifier);
    1173           0 :                 if (r < 0)
    1174           0 :                         return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set vendor class identifier: %m");
    1175             :         }
    1176             : 
    1177           0 :         if (link->network->dhcp_user_class) {
    1178           0 :                 r = sd_dhcp_client_set_user_class(link->dhcp_client, (const char **) link->network->dhcp_user_class);
    1179           0 :                 if (r < 0)
    1180           0 :                         return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set user class: %m");
    1181             :         }
    1182             : 
    1183           0 :         if (link->network->dhcp_client_port) {
    1184           0 :                 r = sd_dhcp_client_set_client_port(link->dhcp_client, link->network->dhcp_client_port);
    1185           0 :                 if (r < 0)
    1186           0 :                         return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set listen port: %m");
    1187             :         }
    1188             : 
    1189           0 :         if (link->network->dhcp_max_attempts > 0) {
    1190           0 :                 r = sd_dhcp_client_set_max_attempts(link->dhcp_client, link->network->dhcp_max_attempts);
    1191           0 :                 if (r < 0)
    1192           0 :                         return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set max attempts: %m");
    1193             :         }
    1194             : 
    1195           0 :         return dhcp4_set_client_identifier(link);
    1196             : }
    1197             : 
    1198           0 : int config_parse_dhcp_max_attempts(
    1199             :                 const char *unit,
    1200             :                 const char *filename,
    1201             :                 unsigned line,
    1202             :                 const char *section,
    1203             :                 unsigned section_line,
    1204             :                 const char *lvalue,
    1205             :                 int ltype,
    1206             :                 const char *rvalue,
    1207             :                 void *data,
    1208             :                 void *userdata) {
    1209             : 
    1210           0 :         Network *network = data;
    1211             :         uint64_t a;
    1212             :         int r;
    1213             : 
    1214           0 :         assert(network);
    1215           0 :         assert(lvalue);
    1216           0 :         assert(rvalue);
    1217             : 
    1218           0 :         if (isempty(rvalue)) {
    1219           0 :                 network->dhcp_max_attempts = 0;
    1220           0 :                 return 0;
    1221             :         }
    1222             : 
    1223           0 :         if (streq(rvalue, "infinity")) {
    1224           0 :                 network->dhcp_max_attempts = (uint64_t) -1;
    1225           0 :                 return 0;
    1226             :         }
    1227             : 
    1228           0 :         r = safe_atou64(rvalue, &a);
    1229           0 :         if (r < 0) {
    1230           0 :                 log_syntax(unit, LOG_ERR, filename, line, r,
    1231             :                            "Failed to parse DHCP maximum attempts, ignoring: %s", rvalue);
    1232           0 :                 return 0;
    1233             :         }
    1234             : 
    1235           0 :         if (a == 0) {
    1236           0 :                 log_syntax(unit, LOG_ERR, filename, line, 0,
    1237             :                            "%s= must be positive integer or 'infinity', ignoring: %s", lvalue, rvalue);
    1238           0 :                 return 0;
    1239             :         }
    1240             : 
    1241           0 :         network->dhcp_max_attempts = a;
    1242             : 
    1243           0 :         return 0;
    1244             : }
    1245             : 
    1246           0 : int config_parse_dhcp_black_listed_ip_address(
    1247             :                 const char *unit,
    1248             :                 const char *filename,
    1249             :                 unsigned line,
    1250             :                 const char *section,
    1251             :                 unsigned section_line,
    1252             :                 const char *lvalue,
    1253             :                 int ltype,
    1254             :                 const char *rvalue,
    1255             :                 void *data,
    1256             :                 void *userdata) {
    1257             : 
    1258           0 :         Network *network = data;
    1259             :         const char *p;
    1260             :         int r;
    1261             : 
    1262           0 :         assert(filename);
    1263           0 :         assert(lvalue);
    1264           0 :         assert(rvalue);
    1265           0 :         assert(data);
    1266             : 
    1267           0 :         if (isempty(rvalue)) {
    1268           0 :                 network->dhcp_black_listed_ip = set_free(network->dhcp_black_listed_ip);
    1269           0 :                 return 0;
    1270             :         }
    1271             : 
    1272           0 :         for (p = rvalue;;) {
    1273           0 :                 _cleanup_free_ char *n = NULL;
    1274             :                 union in_addr_union ip;
    1275             : 
    1276           0 :                 r = extract_first_word(&p, &n, NULL, 0);
    1277           0 :                 if (r < 0) {
    1278           0 :                         log_syntax(unit, LOG_ERR, filename, line, r,
    1279             :                                    "Failed to parse DHCP black listed ip address, ignoring assignment: %s",
    1280             :                                    rvalue);
    1281           0 :                         return 0;
    1282             :                 }
    1283           0 :                 if (r == 0)
    1284           0 :                         return 0;
    1285             : 
    1286           0 :                 r = in_addr_from_string(AF_INET, n, &ip);
    1287           0 :                 if (r < 0) {
    1288           0 :                         log_syntax(unit, LOG_ERR, filename, line, r,
    1289             :                                    "DHCP black listed ip address is invalid, ignoring assignment: %s", n);
    1290           0 :                         continue;
    1291             :                 }
    1292             : 
    1293           0 :                 r = set_ensure_allocated(&network->dhcp_black_listed_ip, NULL);
    1294           0 :                 if (r < 0)
    1295           0 :                         return log_oom();
    1296             : 
    1297           0 :                 r = set_put(network->dhcp_black_listed_ip, UINT32_TO_PTR(ip.in.s_addr));
    1298           0 :                 if (r < 0)
    1299           0 :                         log_syntax(unit, LOG_ERR, filename, line, r,
    1300             :                                    "Failed to store DHCP black listed ip address '%s', ignoring assignment: %m", n);
    1301             :         }
    1302             : 
    1303             :         return 0;
    1304             : }
    1305             : 
    1306           0 : int config_parse_dhcp_user_class(
    1307             :                 const char *unit,
    1308             :                 const char *filename,
    1309             :                 unsigned line,
    1310             :                 const char *section,
    1311             :                 unsigned section_line,
    1312             :                 const char *lvalue,
    1313             :                 int ltype,
    1314             :                 const char *rvalue,
    1315             :                 void *data,
    1316             :                 void *userdata) {
    1317             : 
    1318           0 :         char ***l = data;
    1319             :         int r;
    1320             : 
    1321           0 :         assert(l);
    1322           0 :         assert(lvalue);
    1323           0 :         assert(rvalue);
    1324             : 
    1325           0 :         if (isempty(rvalue)) {
    1326           0 :                 *l = strv_free(*l);
    1327           0 :                 return 0;
    1328             :         }
    1329             : 
    1330           0 :         for (;;) {
    1331           0 :                 _cleanup_free_ char *w = NULL;
    1332             : 
    1333           0 :                 r = extract_first_word(&rvalue, &w, NULL, 0);
    1334           0 :                 if (r == -ENOMEM)
    1335           0 :                         return log_oom();
    1336           0 :                 if (r < 0) {
    1337           0 :                         log_syntax(unit, LOG_ERR, filename, line, r,
    1338             :                                    "Failed to split user classes option, ignoring: %s", rvalue);
    1339           0 :                         break;
    1340             :                 }
    1341           0 :                 if (r == 0)
    1342           0 :                         break;
    1343             : 
    1344           0 :                 if (strlen(w) > 255) {
    1345           0 :                         log_syntax(unit, LOG_ERR, filename, line, 0,
    1346             :                                    "%s length is not in the range 1-255, ignoring.", w);
    1347           0 :                         continue;
    1348             :                 }
    1349             : 
    1350           0 :                 r = strv_push(l, w);
    1351           0 :                 if (r < 0)
    1352           0 :                         return log_oom();
    1353             : 
    1354           0 :                 w = NULL;
    1355             :         }
    1356             : 
    1357           0 :         return 0;
    1358             : }
    1359             : 
    1360             : static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
    1361             :         [DHCP_CLIENT_ID_MAC] = "mac",
    1362             :         [DHCP_CLIENT_ID_DUID] = "duid",
    1363             :         [DHCP_CLIENT_ID_DUID_ONLY] = "duid-only",
    1364             : };
    1365             : 
    1366           0 : DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DHCPClientIdentifier);
    1367           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DHCPClientIdentifier,
    1368             :                          "Failed to parse client identifier type");

Generated by: LCOV version 1.14