]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network/dhcp4: do not set gateway if DNS server or friends is in the acquired prefix 32741/head
authorYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 10 May 2024 03:49:50 +0000 (12:49 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 10 May 2024 04:46:39 +0000 (13:46 +0900)
Previously, even if a DNS server is in the acquired prefix, the route to the
server might have gateway address.
This makes the prefix route, which is always configured, is also handled
as same as static routes, and do not use any gateway if the prefix route
is the most suitable route to access the destination.
The same change is also applied to route to NTP servers and semi-static
routes.

Fixes a regression introduced by 0ce86f5eeb0921b44a9782260a8c88aafb15ffde.

Fixes #32715.

src/network/networkd-dhcp4.c

index cb470ec4e11ed6a9d3142955b2de41bc0f3ffea1..4dd6044b1897278969d69302f347a1ca7bda9a8c 100644 (file)
@@ -147,12 +147,11 @@ static int dhcp4_find_gateway_for_destination(
                 Link *link,
                 const struct in_addr *destination,
                 uint8_t prefixlength,
-                bool allow_null,
                 struct in_addr *ret) {
 
         _cleanup_free_ sd_dhcp_route **routes = NULL;
         size_t n_routes = 0;
-        bool is_classless, reachable;
+        bool is_classless;
         uint8_t max_prefixlen = UINT8_MAX;
         struct in_addr gw;
         int r;
@@ -165,14 +164,21 @@ static int dhcp4_find_gateway_for_destination(
         /* This tries to find the most suitable gateway for an address or address range.
          * E.g. if the server provides the default gateway 192.168.0.1 and a classless static route for
          * 8.0.0.0/8 with gateway 192.168.0.2, then this returns 192.168.0.2 for 8.8.8.8/32, and 192.168.0.1
-         * for 9.9.9.9/32. If 'allow_null' flag is set, and the input address or address range is in the
-         * assigned network, then the default gateway will be ignored and the null address will be returned
-         * unless a matching non-default gateway found. */
+         * for 9.9.9.9/32. If the input address or address range is in the assigned network, then the null
+         * address will be returned. */
 
+        /* First, check with the assigned prefix, and if the destination is in the prefix, set the null
+         * address for the gateway, and return it unless more suitable static route is found. */
         r = dhcp4_prefix_covers(link, destination, prefixlength);
         if (r < 0)
                 return r;
-        reachable = r > 0;
+        if (r > 0) {
+                r = sd_dhcp_lease_get_prefix(link->dhcp_lease, NULL, &max_prefixlen);
+                if (r < 0)
+                        return r;
+
+                gw = (struct in_addr) {};
+        }
 
         r = dhcp4_get_classless_static_or_static_routes(link, &routes, &n_routes);
         if (r < 0 && r != -ENODATA)
@@ -208,25 +214,17 @@ static int dhcp4_find_gateway_for_destination(
                 max_prefixlen = len;
         }
 
-        /* Found a suitable gateway in classless static routes or static routes. */
+        /* The destination is reachable. Note, the gateway address returned here may be NULL. */
         if (max_prefixlen != UINT8_MAX) {
-                if (max_prefixlen == 0 && reachable && allow_null)
-                        /* Do not return the default gateway, if the destination is in the assigned network. */
-                        *ret = (struct in_addr) {};
-                else
-                        *ret = gw;
-                return 0;
-        }
-
-        /* When the destination is in the assigned network, return the null address if allowed. */
-        if (reachable && allow_null) {
-                *ret = (struct in_addr) {};
+                *ret = gw;
                 return 0;
         }
 
         /* According to RFC 3442: If the DHCP server returns both a Classless Static Routes option and
          * a Router option, the DHCP client MUST ignore the Router option. */
         if (!is_classless) {
+                /* No matching static route is found, and the destination is not in the acquired network,
+                 * falling back to the Router option. */
                 r = dhcp4_get_router(link, ret);
                 if (r >= 0)
                         return 0;
@@ -234,11 +232,7 @@ static int dhcp4_find_gateway_for_destination(
                         return r;
         }
 
-        if (!reachable)
-                return -EHOSTUNREACH; /* Not in the same network, cannot reach the destination. */
-
-        assert(!allow_null);
-        return -ENODATA; /* No matching gateway found. */
+        return -EHOSTUNREACH; /* Cannot reach the destination. */
 }
 
 static int dhcp4_remove_address_and_routes(Link *link, bool only_marked) {
@@ -651,8 +645,8 @@ static int dhcp4_request_semi_static_routes(Link *link) {
 
                 assert(rt->family == AF_INET);
 
-                r = dhcp4_find_gateway_for_destination(link, &rt->dst.in, rt->dst_prefixlen, /* allow_null = */ false, &gw);
-                if (IN_SET(r, -EHOSTUNREACH, -ENODATA)) {
+                r = dhcp4_find_gateway_for_destination(link, &rt->dst.in, rt->dst_prefixlen, &gw);
+                if (r == -EHOSTUNREACH) {
                         log_link_debug_errno(link, r, "DHCP: Cannot find suitable gateway for destination %s of semi-static route, ignoring: %m",
                                              IN4_ADDR_PREFIX_TO_STRING(&rt->dst.in, rt->dst_prefixlen));
                         continue;
@@ -660,6 +654,12 @@ static int dhcp4_request_semi_static_routes(Link *link) {
                 if (r < 0)
                         return r;
 
+                if (in4_addr_is_null(&gw)) {
+                        log_link_debug(link, "DHCP: Destination %s of semi-static route is in the acquired network, skipping configuration.",
+                                       IN4_ADDR_PREFIX_TO_STRING(&rt->dst.in, rt->dst_prefixlen));
+                        continue;
+                }
+
                 r = dhcp4_request_route_to_gateway(link, &gw);
                 if (r < 0)
                         return r;
@@ -697,7 +697,7 @@ static int dhcp4_request_routes_to_servers(
                 if (in4_addr_is_null(dst))
                         continue;
 
-                r = dhcp4_find_gateway_for_destination(link, dst, 32, /* allow_null = */ true, &gw);
+                r = dhcp4_find_gateway_for_destination(link, dst, 32, &gw);
                 if (r == -EHOSTUNREACH) {
                         log_link_debug_errno(link, r, "DHCP: Cannot find suitable gateway for destination %s, ignoring: %m",
                                              IN4_ADDR_PREFIX_TO_STRING(dst, 32));