summaryrefslogtreecommitdiffstats
path: root/src/network/networkd-dhcp4.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/network/networkd-dhcp4.c206
1 files changed, 102 insertions, 104 deletions
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index 49c452d..4dd6044 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -20,6 +20,7 @@
#include "networkd-manager.h"
#include "networkd-network.h"
#include "networkd-nexthop.h"
+#include "networkd-ntp.h"
#include "networkd-queue.h"
#include "networkd-route.h"
#include "networkd-setlink.h"
@@ -146,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;
@@ -164,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)
@@ -207,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;
@@ -233,31 +232,26 @@ 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) {
Address *address;
Route *route;
- int k, r = 0;
+ int ret = 0;
assert(link);
+ assert(link->manager);
- SET_FOREACH(route, link->routes) {
+ SET_FOREACH(route, link->manager->routes) {
if (route->source != NETWORK_CONFIG_SOURCE_DHCP4)
continue;
+ if (route->nexthop.ifindex != 0 && route->nexthop.ifindex != link->ifindex)
+ continue;
if (only_marked && !route_is_marked(route))
continue;
- k = route_remove(route);
- if (k < 0)
- r = k;
-
- route_cancel_request(route, link);
+ RET_GATHER(ret, route_remove_and_cancel(route, link->manager));
}
SET_FOREACH(address, link->addresses) {
@@ -266,12 +260,10 @@ static int dhcp4_remove_address_and_routes(Link *link, bool only_marked) {
if (only_marked && !address_is_marked(address))
continue;
- k = address_remove_and_drop(address);
- if (k < 0)
- r = k;
+ RET_GATHER(ret, address_remove_and_cancel(address, link));
}
- return r;
+ return ret;
}
static int dhcp4_address_get(Link *link, Address **ret) {
@@ -347,12 +339,9 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request
assert(m);
assert(link);
- r = sd_netlink_message_get_errno(m);
- if (r < 0 && r != -EEXIST) {
- log_link_message_warning_errno(link, m, r, "Could not set DHCPv4 route");
- link_enter_failed(link);
- return 1;
- }
+ r = route_configure_handler_internal(rtnl, m, link, route, "Could not set DHCPv4 route");
+ if (r <= 0)
+ return r;
r = dhcp4_check_ready(link);
if (r < 0)
@@ -361,14 +350,14 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request
return 1;
}
-static int dhcp4_request_route(Route *in, Link *link) {
- _cleanup_(route_freep) Route *route = in;
+static int dhcp4_request_route(Route *route, Link *link) {
struct in_addr server;
Route *existing;
int r;
assert(route);
assert(link);
+ assert(link->manager);
assert(link->network);
assert(link->dhcp_lease);
@@ -385,22 +374,29 @@ static int dhcp4_request_route(Route *in, Link *link) {
route->priority = link->network->dhcp_route_metric;
if (!route->table_set)
route->table = link_get_dhcp4_route_table(link);
- if (route->mtu == 0)
- route->mtu = link->network->dhcp_route_mtu;
- if (route->quickack < 0)
- route->quickack = link->network->dhcp_quickack;
- if (route->initcwnd == 0)
- route->initcwnd = link->network->dhcp_initial_congestion_window;
- if (route->initrwnd == 0)
- route->initrwnd = link->network->dhcp_advertised_receive_window;
-
- if (route_get(NULL, link, route, &existing) < 0) /* This is a new route. */
+ r = route_metric_set(&route->metric, RTAX_MTU, link->network->dhcp_route_mtu);
+ if (r < 0)
+ return r;
+ r = route_metric_set(&route->metric, RTAX_INITCWND, link->network->dhcp_initial_congestion_window);
+ if (r < 0)
+ return r;
+ r = route_metric_set(&route->metric, RTAX_INITRWND, link->network->dhcp_advertised_receive_window);
+ if (r < 0)
+ return r;
+ r = route_metric_set(&route->metric, RTAX_QUICKACK, link->network->dhcp_quickack);
+ if (r < 0)
+ return r;
+
+ r = route_adjust_nexthops(route, link);
+ if (r < 0)
+ return r;
+
+ if (route_get(link->manager, route, &existing) < 0) /* This is a new route. */
link->dhcp4_configured = false;
else
route_unmark(existing);
- return link_request_route(link, TAKE_PTR(route), true, &link->dhcp4_messages,
- dhcp4_route_handler, NULL);
+ return link_request_route(link, route, &link->dhcp4_messages, dhcp4_route_handler);
}
static bool link_prefixroute(Link *link) {
@@ -409,7 +405,7 @@ static bool link_prefixroute(Link *link) {
}
static int dhcp4_request_prefix_route(Link *link) {
- _cleanup_(route_freep) Route *route = NULL;
+ _cleanup_(route_unrefp) Route *route = NULL;
int r;
assert(link);
@@ -433,11 +429,11 @@ static int dhcp4_request_prefix_route(Link *link) {
if (r < 0)
return r;
- return dhcp4_request_route(TAKE_PTR(route), link);
+ return dhcp4_request_route(route, link);
}
static int dhcp4_request_route_to_gateway(Link *link, const struct in_addr *gw) {
- _cleanup_(route_freep) Route *route = NULL;
+ _cleanup_(route_unrefp) Route *route = NULL;
struct in_addr address;
int r;
@@ -458,15 +454,14 @@ static int dhcp4_request_route_to_gateway(Link *link, const struct in_addr *gw)
route->prefsrc.in = address;
route->scope = RT_SCOPE_LINK;
- return dhcp4_request_route(TAKE_PTR(route), link);
+ return dhcp4_request_route(route, link);
}
static int dhcp4_request_route_auto(
- Route *in,
+ Route *route,
Link *link,
const struct in_addr *gw) {
- _cleanup_(route_freep) Route *route = in;
struct in_addr address;
int r;
@@ -486,8 +481,8 @@ static int dhcp4_request_route_auto(
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->nexthop.family = AF_UNSPEC;
+ route->nexthop.gw = IN_ADDR_NULL;
route->prefsrc = IN_ADDR_NULL;
} else if (in4_addr_equal(&route->dst.in, &address)) {
@@ -497,8 +492,8 @@ static int dhcp4_request_route_auto(
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->nexthop.family = AF_UNSPEC;
+ route->nexthop.gw = IN_ADDR_NULL;
route->prefsrc.in = address;
} else if (in4_addr_is_null(gw)) {
@@ -520,8 +515,8 @@ static int dhcp4_request_route_auto(
}
route->scope = RT_SCOPE_LINK;
- route->gw_family = AF_UNSPEC;
- route->gw = IN_ADDR_NULL;
+ route->nexthop.family = AF_UNSPEC;
+ route->nexthop.gw = IN_ADDR_NULL;
route->prefsrc.in = address;
} else {
@@ -530,12 +525,12 @@ static int dhcp4_request_route_auto(
return r;
route->scope = RT_SCOPE_UNIVERSE;
- route->gw_family = AF_INET;
- route->gw.in = *gw;
+ route->nexthop.family = AF_INET;
+ route->nexthop.gw.in = *gw;
route->prefsrc.in = address;
}
- return dhcp4_request_route(TAKE_PTR(route), link);
+ return dhcp4_request_route(route, link);
}
static int dhcp4_request_classless_static_or_static_routes(Link *link) {
@@ -556,7 +551,7 @@ static int dhcp4_request_classless_static_or_static_routes(Link *link) {
return r;
FOREACH_ARRAY(e, routes, n_routes) {
- _cleanup_(route_freep) Route *route = NULL;
+ _cleanup_(route_unrefp) Route *route = NULL;
struct in_addr gw;
r = route_new(&route);
@@ -575,7 +570,7 @@ static int dhcp4_request_classless_static_or_static_routes(Link *link) {
if (r < 0)
return r;
- r = dhcp4_request_route_auto(TAKE_PTR(route), link, &gw);
+ r = dhcp4_request_route_auto(route, link, &gw);
if (r < 0)
return r;
}
@@ -584,7 +579,7 @@ static int dhcp4_request_classless_static_or_static_routes(Link *link) {
}
static int dhcp4_request_default_gateway(Link *link) {
- _cleanup_(route_freep) Route *route = NULL;
+ _cleanup_(route_unrefp) Route *route = NULL;
struct in_addr address, router;
int r;
@@ -623,11 +618,11 @@ static int dhcp4_request_default_gateway(Link *link) {
return r;
/* Next, add a default gateway. */
- route->gw_family = AF_INET;
- route->gw.in = router;
+ route->nexthop.family = AF_INET;
+ route->nexthop.gw.in = router;
route->prefsrc.in = address;
- return dhcp4_request_route(TAKE_PTR(route), link);
+ return dhcp4_request_route(route, link);
}
static int dhcp4_request_semi_static_routes(Link *link) {
@@ -639,19 +634,19 @@ static int dhcp4_request_semi_static_routes(Link *link) {
assert(link->network);
HASHMAP_FOREACH(rt, link->network->routes_by_section) {
- _cleanup_(route_freep) Route *route = NULL;
+ _cleanup_(route_unrefp) Route *route = NULL;
struct in_addr gw;
if (!rt->gateway_from_dhcp_or_ra)
continue;
- if (rt->gw_family != AF_INET)
+ if (rt->nexthop.family != AF_INET)
continue;
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;
@@ -659,17 +654,23 @@ 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;
- r = route_dup(rt, &route);
+ r = route_dup(rt, NULL, &route);
if (r < 0)
return r;
- route->gw.in = gw;
+ route->nexthop.gw.in = gw;
- r = dhcp4_request_route(TAKE_PTR(route), link);
+ r = dhcp4_request_route(route, link);
if (r < 0)
return r;
}
@@ -690,13 +691,13 @@ static int dhcp4_request_routes_to_servers(
assert(servers || n_servers == 0);
FOREACH_ARRAY(dst, servers, n_servers) {
- _cleanup_(route_freep) Route *route = NULL;
+ _cleanup_(route_unrefp) Route *route = NULL;
struct in_addr gw;
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));
@@ -712,7 +713,7 @@ static int dhcp4_request_routes_to_servers(
route->dst.in = *dst;
route->dst_prefixlen = 32;
- r = dhcp4_request_route_auto(TAKE_PTR(route), link, &gw);
+ r = dhcp4_request_route_auto(route, link, &gw);
if (r < 0)
return r;
}
@@ -728,7 +729,7 @@ static int dhcp4_request_routes_to_dns(Link *link) {
assert(link->dhcp_lease);
assert(link->network);
- if (!link->network->dhcp_use_dns ||
+ if (!link_get_use_dns(link, NETWORK_CONFIG_SOURCE_DHCP4) ||
!link->network->dhcp_routes_to_dns)
return 0;
@@ -749,7 +750,7 @@ static int dhcp4_request_routes_to_ntp(Link *link) {
assert(link->dhcp_lease);
assert(link->network);
- if (!link->network->dhcp_use_ntp ||
+ if (!link_get_use_ntp(link, NETWORK_CONFIG_SOURCE_DHCP4) ||
!link->network->dhcp_routes_to_ntp)
return 0;
@@ -835,7 +836,7 @@ static int dhcp_reset_hostname(Link *link) {
}
int dhcp4_lease_lost(Link *link) {
- int k, r = 0;
+ int r = 0;
assert(link);
assert(link->dhcp_lease);
@@ -849,17 +850,9 @@ int dhcp4_lease_lost(Link *link) {
sd_dhcp_lease_has_6rd(link->dhcp_lease))
dhcp4_pd_prefix_lost(link);
- k = dhcp4_remove_address_and_routes(link, /* only_marked = */ false);
- if (k < 0)
- r = k;
-
- k = dhcp_reset_mtu(link);
- if (k < 0)
- r = k;
-
- k = dhcp_reset_hostname(link);
- if (k < 0)
- r = k;
+ RET_GATHER(r, dhcp4_remove_address_and_routes(link, /* only_marked = */ false));
+ RET_GATHER(r, dhcp_reset_mtu(link));
+ RET_GATHER(r, dhcp_reset_hostname(link));
link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
link_dirty(link);
@@ -892,7 +885,7 @@ static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Reques
}
static int dhcp4_request_address(Link *link, bool announce) {
- _cleanup_(address_freep) Address *addr = NULL;
+ _cleanup_(address_unrefp) Address *addr = NULL;
struct in_addr address, server;
uint8_t prefixlen;
Address *existing;
@@ -997,7 +990,7 @@ static int dhcp4_request_address_and_routes(Link *link, bool announce) {
assert(link);
link_mark_addresses(link, NETWORK_CONFIG_SOURCE_DHCP4);
- link_mark_routes(link, NETWORK_CONFIG_SOURCE_DHCP4);
+ manager_mark_routes(link->manager, link, NETWORK_CONFIG_SOURCE_DHCP4);
r = dhcp4_request_address(link, announce);
if (r < 0)
@@ -1181,7 +1174,7 @@ static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
}
r = sd_ipv4ll_start(link->ipv4ll);
- if (r < 0)
+ if (r < 0 && r != -ESTALE) /* On exit, we cannot and should not start sd-ipv4ll. */
return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
}
@@ -1548,13 +1541,13 @@ static int dhcp4_configure(Link *link) {
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for classless static route: %m");
}
- if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
+ if (link_get_use_domains(link, NETWORK_CONFIG_SOURCE_DHCP4) > 0) {
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_DOMAIN_SEARCH);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for domain search list: %m");
}
- if (link->network->dhcp_use_ntp) {
+ if (link_get_use_ntp(link, NETWORK_CONFIG_SOURCE_DHCP4)) {
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NTP_SERVER);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for NTP server: %m");
@@ -1642,6 +1635,11 @@ static int dhcp4_configure(Link *link) {
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set listen port: %m");
}
+ if (link->network->dhcp_port > 0) {
+ r = sd_dhcp_client_set_port(link->dhcp_client, link->network->dhcp_port);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set server port: %m");
+ }
if (link->network->dhcp_max_attempts > 0) {
r = sd_dhcp_client_set_max_attempts(link->dhcp_client, link->network->dhcp_max_attempts);