]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
DHCP: when adding static routes set scopes properly (#5982)
authorDaniel Wang <wonderfly@users.noreply.github.com>
Sat, 20 May 2017 11:05:18 +0000 (04:05 -0700)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sat, 20 May 2017 11:05:18 +0000 (07:05 -0400)
DHCP responses could include static routes, but unfortunately not an
option to tell what scope to use. So it's important that the client sets
it properly.

This mimics what the `ip route add` command does when adding a static
route without an explicit scope:

* If the destination IP is on the local host, use scope `host`
* Otherwise if the gateway IP is null (direct route), use scope `link`
* If anything else, use the current default `global`.

Fixes #5979.

man/systemd.network.xml
src/network/networkd-dhcp4.c

index 08cbe9be0840e7325e173eade2d5e1122f55fcd7..6b83a5b8515062ff7a8b97ef71f8fe5c02d2cf4f 100644 (file)
         <varlistentry>
           <term><varname>UseRoutes=</varname></term>
           <listitem>
-            <para>When true (the default), the static routes will be
-            requested from the DHCP server and added to the routing
-            table with a metric of 1024.</para>
+            <para>When true (the default), the static routes will be requested from the DHCP server and added to the
+              routing table with a metric of 1024, and a scope of "global", "link" or "host", depending on the route's
+              destination and gateway. If the destination is on the local host, e.g., 127.x.x.x, or the same as the
+              link's own address, the scope will be set to "host". Otherwise if the gateway is null (a direct route), a
+              "link" scope will be used. For anything else, scope defaults to "global".</para>
           </listitem>
         </varlistentry>
 
index c5c5b95c8fef3115607acde635d8edc8175c8c45..ae0f78daaba89a6ef98a3f07bffbb11d92afaa30 100644 (file)
@@ -52,8 +52,21 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m,
         return 1;
 }
 
+static int route_scope_from_address(const Route *route, const struct in_addr *self_addr) {
+        assert(route);
+        assert(self_addr);
+
+        if (in_addr_is_localhost(AF_INET, &route->dst) ||
+            (self_addr->s_addr && route->dst.in.s_addr == self_addr->s_addr))
+                return RT_SCOPE_HOST;
+        else if (in4_addr_is_null(&route->gw.in))
+                return RT_SCOPE_LINK;
+        else
+                return RT_SCOPE_UNIVERSE;
+}
+
 static int link_set_dhcp_routes(Link *link) {
-        struct in_addr gateway;
+        struct in_addr gateway, address;
         _cleanup_free_ sd_dhcp_route **static_routes = NULL;
         int r, n, i;
 
@@ -69,7 +82,6 @@ static int link_set_dhcp_routes(Link *link) {
                 return log_link_warning_errno(link, r, "DHCP error: could not get gateway: %m");
 
         if (r >= 0) {
-                struct in_addr address;
                 _cleanup_route_free_ Route *route = NULL;
                 _cleanup_route_free_ Route *route_gw = NULL;
 
@@ -141,6 +153,7 @@ static int link_set_dhcp_routes(Link *link) {
                 assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes[i], &route->dst_prefixlen) >= 0);
                 route->priority = link->network->dhcp_route_metric;
                 route->table = link->network->dhcp_route_table;
+                route->scope = route_scope_from_address(route, &address);
 
                 r = route_configure(route, link, dhcp4_route_handler);
                 if (r < 0)