return 1;
}
-static int route_scope_from_address(const Route *route, const struct in_addr *self_addr) {
- assert(route);
- assert(self_addr);
-
- if (in4_addr_is_localhost(&route->dst.in) ||
- (in4_addr_is_set(self_addr) && in4_addr_equal(&route->dst.in, self_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 dhcp_route_configure(Route *route, Link *link) {
Route *ret;
int r;
return dhcp_route_configure(route, link);
}
+static int dhcp_route_configure_auto(
+ Route *route,
+ Link *link,
+ const struct in_addr *gw) {
+
+ struct in_addr address, netmask, prefix;
+ uint8_t prefixlen;
+ int r;
+
+ assert(route);
+ assert(link);
+ assert(link->dhcp_lease);
+ assert(gw);
+
+ /* The route object may be reused in an iteration. All elements must be set or cleared. */
+
+ r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
+ if (r < 0)
+ return r;
+
+ r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
+ if (r < 0)
+ return r;
+
+ prefix.s_addr = address.s_addr & netmask.s_addr;
+ prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
+
+ if (in4_addr_is_localhost(&route->dst.in)) {
+ if (in4_addr_is_set(gw))
+ log_link_debug(link, "DHCP: requested route destination "IPV4_ADDRESS_FMT_STR"/%u is localhost, "
+ "ignoring gateway address "IPV4_ADDRESS_FMT_STR,
+ IPV4_ADDRESS_FMT_VAL(route->dst.in), route->dst_prefixlen, IPV4_ADDRESS_FMT_VAL(*gw));
+
+ route->scope = RT_SCOPE_HOST;
+ route->gw_family = AF_UNSPEC;
+ route->gw = IN_ADDR_NULL;
+ route->prefsrc = IN_ADDR_NULL;
+
+ } else if (in4_addr_equal(&route->dst.in, &address)) {
+ if (in4_addr_is_set(gw))
+ log_link_debug(link, "DHCP: requested route destination "IPV4_ADDRESS_FMT_STR"/%u is equivalent to the acquired address, "
+ "ignoring gateway address "IPV4_ADDRESS_FMT_STR,
+ IPV4_ADDRESS_FMT_VAL(route->dst.in), route->dst_prefixlen, IPV4_ADDRESS_FMT_VAL(*gw));
+
+ route->scope = RT_SCOPE_HOST;
+ route->gw_family = AF_UNSPEC;
+ route->gw = IN_ADDR_NULL;
+ route->prefsrc.in = address;
+
+ } else if (route->dst_prefixlen >= prefixlen &&
+ (route->dst.in.s_addr & netmask.s_addr) == prefix.s_addr) {
+ if (in4_addr_is_set(gw))
+ log_link_debug(link, "DHCP: requested route destination "IPV4_ADDRESS_FMT_STR"/%u is in the assigned network "
+ IPV4_ADDRESS_FMT_STR"/%u, ignoring gateway address "IPV4_ADDRESS_FMT_STR,
+ IPV4_ADDRESS_FMT_VAL(route->dst.in), route->dst_prefixlen,
+ IPV4_ADDRESS_FMT_VAL(prefix), prefixlen,
+ IPV4_ADDRESS_FMT_VAL(*gw));
+
+ route->scope = RT_SCOPE_LINK;
+ route->gw_family = AF_UNSPEC;
+ route->gw = IN_ADDR_NULL;
+ route->prefsrc.in = address;
+
+ } else {
+ if (in4_addr_is_null(gw)) {
+ log_link_debug(link, "DHCP: requested route destination "IPV4_ADDRESS_FMT_STR"/%u is not in the assigned network "
+ IPV4_ADDRESS_FMT_STR"/%u, but no gateway is specified, ignoring.",
+ IPV4_ADDRESS_FMT_VAL(route->dst.in), route->dst_prefixlen,
+ IPV4_ADDRESS_FMT_VAL(prefix), prefixlen);
+ return 0;
+ }
+
+ r = link_set_dhcp_route_to_gateway(link, gw);
+ if (r < 0)
+ return r;
+
+ route->scope = RT_SCOPE_UNIVERSE;
+ route->gw_family = AF_INET;
+ route->gw.in = *gw;
+ route->prefsrc.in = address;
+ }
+
+ return dhcp_route_configure(route, link);
+}
+
static int link_set_dhcp_static_routes(Link *link) {
_cleanup_free_ sd_dhcp_route **static_routes = NULL;
bool classless_route = false, static_route = false;
_cleanup_(route_freep) Route *route = NULL;
- struct in_addr address;
int n, r;
assert(link);
if (!link->network->dhcp_use_routes)
return 0;
- r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
- if (r < 0)
- return r;
-
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.");
route->mtu = link->network->dhcp_route_mtu;
for (int i = 0; i < n; i++) {
+ struct in_addr gw;
+
if (sd_dhcp_route_get_option(static_routes[i]) !=
(classless_route ? SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE : SD_DHCP_OPTION_STATIC_ROUTE))
continue;
- r = sd_dhcp_route_get_gateway(static_routes[i], &route->gw.in);
+ r = sd_dhcp_route_get_gateway(static_routes[i], &gw);
if (r < 0)
return r;
if (r < 0)
return r;
- route->scope = route_scope_from_address(route, &address);
- if (IN_SET(route->scope, RT_SCOPE_LINK, RT_SCOPE_UNIVERSE))
- route->prefsrc.in = address;
- else
- route->prefsrc = IN_ADDR_NULL;
-
- r = dhcp_route_configure(route, link);
+ r = dhcp_route_configure_auto(route, link, &gw);
if (r < 0)
return r;
}