From c19df00f6def1ee74ae0812b529f2a1b589c256f Mon Sep 17 00:00:00 2001 From: Daniel Wang 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 @@ UseRoutes= - 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. + 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". 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)