From c19df00f6def1ee74ae0812b529f2a1b589c256f Mon Sep 17 00:00:00 2001
From: Daniel Wang <wonderfly@users.noreply.github.com>
Date: Sat, 20 May 2017 04:05:18 -0700
Subject: [PATCH] DHCP: when adding static routes set scopes properly (#5982)
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.
(cherry picked from commit d6eac9bd06066c8d041449538a9cdee0fd928835)
---
man/systemd.network.xml | 8 +++++---
src/network/networkd-dhcp4.c | 17 +++++++++++++++--
2 files changed, 20 insertions(+), 5 deletions(-)
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index b807ebf29b..aaa7b0968d 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -937,9 +937,11 @@
<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>
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index c5c5b95c8f..ae0f78daab 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -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)