]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: dhcp4: also support semi-static routes with Gateway=_dhcp4 when UseGateway...
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 12 Jul 2021 16:06:08 +0000 (01:06 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 14 Jul 2021 19:17:09 +0000 (04:17 +0900)
This makes the default gateway is read from classless static routes or
router option even if UseGateway=no or UseRoutes=no, and will be used
when configuring semi-static routes such that specified with Gateway=_dhcp4.

This also changes the behavior of RoutesToDNS= or RoutesToNTP=.
Previously, the DNS or NTP servers are not in the same network, then the
routes to the servers were not configured when UseGateway=no or
UseRoutes=no. With this commit, the default gateway in classless static
routes or router option will used to connecting the servers even if
UseGateway=no or UseRoutes=no.

Fixes #20208.

src/network/networkd-dhcp4.c

index 511e4b1bdfde099c8325d871657c04b5382fcecc..8936e68a33f7c4322d1dabb73995e663e5e66240 100644 (file)
@@ -379,9 +379,6 @@ static int dhcp4_request_static_routes(Link *link, struct in_addr *ret_default_g
         assert(link->dhcp_lease);
         assert(ret_default_gw);
 
-        if (!link->network->dhcp_use_routes)
-                return 0;
-
         n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes);
         if (IN_SET(n, 0, -ENODATA)) {
                 log_link_debug(link, "DHCP: No static routes received from DHCP server.");
@@ -406,6 +403,45 @@ static int dhcp4_request_static_routes(Link *link, struct in_addr *ret_default_g
         if (classless_route && static_route)
                 log_link_debug(link, "Classless static routes received from DHCP server: ignoring static-route option");
 
+        if (!link->network->dhcp_use_routes) {
+                if (!classless_route)
+                        return 0;
+
+                /* Even if UseRoutes=no, try to find default gateway to make semi-static routes and
+                 * routes to DNS or NTP servers can be configured in later steps. */
+                for (int i = 0; i < n; i++) {
+                        struct in_addr dst;
+                        uint8_t prefixlen;
+
+                        if (sd_dhcp_route_get_option(static_routes[i]) != SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE)
+                                continue;
+
+                        r = sd_dhcp_route_get_destination(static_routes[i], &dst);
+                        if (r < 0)
+                                return r;
+
+                        if (in4_addr_is_set(&dst))
+                                continue;
+
+                        r = sd_dhcp_route_get_destination_prefix_length(static_routes[i], &prefixlen);
+                        if (r < 0)
+                                return r;
+
+                        if (prefixlen != 0)
+                                continue;
+
+                        r = sd_dhcp_route_get_gateway(static_routes[i], ret_default_gw);
+                        if (r < 0)
+                                return r;
+
+                        break;
+                }
+
+                /* Do not return 1 here, to ensure the router option can override the default gateway
+                 * that was found. */
+                return 0;
+        }
+
         for (int i = 0; i < n; i++) {
                 _cleanup_(route_freep) Route *route = NULL;
                 struct in_addr gw;
@@ -454,19 +490,15 @@ static int dhcp4_request_static_routes(Link *link, struct in_addr *ret_default_g
         return classless_route;
 }
 
-static int dhcp4_request_gateway(Link *link, struct in_addr *ret_gw) {
+static int dhcp4_request_gateway(Link *link, struct in_addr *gw) {
         _cleanup_(route_freep) Route *route = NULL;
         const struct in_addr *router;
         struct in_addr address;
-        Route *rt;
         int r;
 
         assert(link);
         assert(link->dhcp_lease);
-        assert(ret_gw);
-
-        if (!link->network->dhcp_use_gateway)
-                return 0;
+        assert(gw);
 
         r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
         if (r < 0)
@@ -484,6 +516,16 @@ static int dhcp4_request_gateway(Link *link, struct in_addr *ret_gw) {
                 return 0;
         }
 
+        if (!link->network->dhcp_use_gateway) {
+                /* When no classless static route is provided, even if UseGateway=no, use the gateway
+                 * address to configure semi-static routes or routes to DNS or NTP servers. Note, if
+                 * neither UseRoutes= nor UseGateway= is disabled, use the default gateway in classless
+                 * static routes if provided (in that case, in4_addr_is_null(gw) below is true). */
+                if (in4_addr_is_null(gw))
+                        *gw = router[0];
+                return 0;
+        }
+
         /* The dhcp netmask may mask out the gateway. First, add an explicit route for the gateway host
          * so that we can route no matter the netmask or existing kernel route tables. */
         r = dhcp4_request_route_to_gateway(link, &router[0]);
@@ -508,18 +550,42 @@ static int dhcp4_request_gateway(Link *link, struct in_addr *ret_gw) {
         if (r < 0)
                 return r;
 
+        /* When no classless static route is provided, or UseRoutes=no, then use the router address to
+         * configure semi-static routes and routes to DNS or NTP servers in later steps. */
+        *gw = router[0];
+        return 0;
+}
+
+static int dhcp4_request_semi_static_routes(Link *link, const struct in_addr *gw) {
+        Route *rt;
+        int r;
+
+        assert(link);
+        assert(link->dhcp_lease);
+        assert(link->network);
+        assert(gw);
+
+        if (in4_addr_is_null(gw))
+                return 0;
+
         HASHMAP_FOREACH(rt, link->network->routes_by_section) {
+                _cleanup_(route_freep) Route *route = NULL;
+
                 if (!rt->gateway_from_dhcp_or_ra)
                         continue;
 
                 if (rt->gw_family != AF_INET)
                         continue;
 
+                r = dhcp4_request_route_to_gateway(link, gw);
+                if (r < 0)
+                        return r;
+
                 r = route_dup(rt, &route);
                 if (r < 0)
                         return r;
 
-                route->gw.in = router[0];
+                route->gw.in = *gw;
                 if (!route->protocol_set)
                         route->protocol = RTPROT_DHCP;
                 if (!route->priority_set)
@@ -534,7 +600,6 @@ static int dhcp4_request_gateway(Link *link, struct in_addr *ret_gw) {
                         return r;
         }
 
-        *ret_gw = router[0];
         return 0;
 }
 
@@ -653,6 +718,10 @@ static int dhcp4_request_routes(Link *link) {
                         return log_link_error_errno(link, r, "DHCP error: Could not request gateway: %m");
         }
 
+        r = dhcp4_request_semi_static_routes(link, &gw);
+        if (r < 0)
+                return log_link_error_errno(link, r, "DHCP error: Could not request routes with Gateway=_dhcp4 setting: %m");
+
         r = dhcp4_request_routes_to_dns(link, &gw);
         if (r < 0)
                 return log_link_error_errno(link, r, "DHCP error: Could not request routes to DNS servers: %m");