X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=src%2Fnetwork%2Fnetworkd-dhcp4.c;h=7907988a9bb9937c41f9c4411bee2f4df6c52987;hb=933c70a0a4e4fac47d18e0348ae97ee3d48dc139;hp=d8ac4552f4ca43a1a46b569c561e93788b3ec4c8;hpb=4a2c3dc318fab4e3cbe33e9835372f67e5114d54;p=thirdparty%2Fsystemd.git diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index d8ac4552f4c..7907988a9bb 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -1,12 +1,11 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -#include +#include #include #include "alloc-util.h" #include "hostname-util.h" #include "parse-util.h" -#include "netdev/vrf.h" #include "network-internal.h" #include "networkd-link.h" #include "networkd-manager.h" @@ -52,7 +51,8 @@ static int route_scope_from_address(const Route *route, const struct in_addr *se static int link_set_dhcp_routes(Link *link) { _cleanup_free_ sd_dhcp_route **static_routes = NULL; bool classless_route = false, static_route = false; - struct in_addr gateway, address; + const struct in_addr *router; + struct in_addr address; int r, n, i; uint32_t table; @@ -67,11 +67,7 @@ static int link_set_dhcp_routes(Link *link) { if (!link->network->dhcp_use_routes) return 0; - /* When the interface is part of an VRF use the VRFs routing table, unless - * there is a another table specified. */ - table = link->network->dhcp_route_table; - if (!link->network->dhcp_route_table_set && link->network->vrf != NULL) - table = VRF(link->network->vrf)->table; + table = link_get_dhcp_route_table(link); r = sd_dhcp_lease_get_address(link->dhcp_lease, &address); if (r < 0) @@ -123,26 +119,21 @@ static int link_set_dhcp_routes(Link *link) { link->dhcp4_messages++; } - r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway); - if (r == -ENODATA) - log_link_info_errno(link, r, "DHCP: No gateway received from DHCP server: %m"); + r = sd_dhcp_lease_get_router(link->dhcp_lease, &router); + if (IN_SET(r, 0, -ENODATA)) + log_link_info(link, "DHCP: No gateway received from DHCP server."); else if (r < 0) log_link_warning_errno(link, r, "DHCP error: could not get gateway: %m"); + else if (in4_addr_is_null(&router[0])) + log_link_info(link, "DHCP: Received gateway is null."); /* 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 (classless_route && static_route) log_link_warning(link, "Classless static routes received from DHCP server: ignoring static-route option and router option"); - if (r >= 0 && !classless_route) { - _cleanup_(route_freep) Route *route = NULL; - _cleanup_(route_freep) Route *route_gw = NULL; - - r = route_new(&route); - if (r < 0) - return log_link_error_errno(link, r, "Could not allocate route: %m"); - - route->protocol = RTPROT_DHCP; + if (r > 0 && !classless_route && !in4_addr_is_null(&router[0])) { + _cleanup_(route_freep) Route *route = NULL, *route_gw = NULL; r = route_new(&route_gw); if (r < 0) @@ -152,7 +143,7 @@ static int link_set_dhcp_routes(Link *link) { * route for the gw host so that we can route no matter the * netmask or existing kernel route tables. */ route_gw->family = AF_INET; - route_gw->dst.in = gateway; + route_gw->dst.in = router[0]; route_gw->dst_prefixlen = 32; route_gw->prefsrc.in = address; route_gw->scope = RT_SCOPE_LINK; @@ -166,9 +157,14 @@ static int link_set_dhcp_routes(Link *link) { link->dhcp4_messages++; + r = route_new(&route); + if (r < 0) + return log_link_error_errno(link, r, "Could not allocate route: %m"); + route->family = AF_INET; - route->gw.in = gateway; + route->gw.in = router[0]; route->prefsrc.in = address; + route->protocol = RTPROT_DHCP; route->priority = link->network->dhcp_route_metric; route->table = table; @@ -187,9 +183,9 @@ static int link_set_dhcp_routes(Link *link) { static int dhcp_lease_lost(Link *link) { _cleanup_(address_freep) Address *address = NULL; + const struct in_addr *router; struct in_addr addr; struct in_addr netmask; - struct in_addr gateway; unsigned prefixlen = 0; int r; @@ -218,19 +214,16 @@ static int dhcp_lease_lost(Link *link) { } } } - } - r = address_new(&address); - if (r >= 0) { - r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway); - if (r >= 0) { + r = sd_dhcp_lease_get_router(link->dhcp_lease, &router); + if (r > 0 && !in4_addr_is_null(&router[0])) { _cleanup_(route_freep) Route *route_gw = NULL; _cleanup_(route_freep) Route *route = NULL; r = route_new(&route_gw); if (r >= 0) { route_gw->family = AF_INET; - route_gw->dst.in = gateway; + route_gw->dst.in = router[0]; route_gw->dst_prefixlen = 32; route_gw->scope = RT_SCOPE_LINK; @@ -240,12 +233,15 @@ static int dhcp_lease_lost(Link *link) { r = route_new(&route); if (r >= 0) { route->family = AF_INET; - route->gw.in = gateway; + route->gw.in = router[0]; route_remove(route, link, NULL); } } + } + r = address_new(&address); + if (r >= 0) { r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr); if (r >= 0) { r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask); @@ -312,6 +308,9 @@ static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link * link_set_dhcp_routes(link); + /* Add back static routes since kernel removes while DHCPv4 address is removed from when lease expires */ + link_request_set_routes(link); + if (link->dhcp4_messages == 0) { link->dhcp4_configured = true; link_check_ready(link); @@ -399,10 +398,10 @@ static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) { } static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { + const struct in_addr *router; sd_dhcp_lease *lease; struct in_addr address; struct in_addr netmask; - struct in_addr gateway; unsigned prefixlen; uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME; int r; @@ -424,20 +423,20 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { prefixlen = in4_addr_netmask_to_prefixlen(&netmask); - r = sd_dhcp_lease_get_router(lease, &gateway); + r = sd_dhcp_lease_get_router(lease, &router); if (r < 0 && r != -ENODATA) return log_link_error_errno(link, r, "DHCP error: Could not get gateway: %m"); - if (r >= 0) + if (r > 0 && !in4_addr_is_null(&router[0])) log_struct(LOG_INFO, LOG_LINK_INTERFACE(link), LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u", ADDRESS_FMT_VAL(address), prefixlen, - ADDRESS_FMT_VAL(gateway)), + ADDRESS_FMT_VAL(router[0])), "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address), "PREFIXLEN=%u", prefixlen, - "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(gateway)); + "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(router[0])); else log_struct(LOG_INFO, LOG_LINK_INTERFACE(link), @@ -475,7 +474,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { if (r < 0) log_link_warning_errno(link, r, "Unable to shorten overlong DHCP hostname '%s', ignoring: %m", dhcpname); if (r == 1) - log_link_notice(link, "Overlong DCHP hostname received, shortened from '%s' to '%s'", dhcpname, hostname); + log_link_notice(link, "Overlong DHCP hostname received, shortened from '%s' to '%s'", dhcpname, hostname); } if (hostname) { @@ -512,31 +511,76 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { return 0; } -static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) { + +static int dhcp_server_is_black_listed(Link *link, sd_dhcp_client *client) { + sd_dhcp_lease *lease; + struct in_addr addr; + int r; + + assert(link); + assert(link->network); + assert(client); + + r = sd_dhcp_client_get_lease(client, &lease); + if (r < 0) + return log_link_error_errno(link, r, "Failed to get DHCP lease: %m"); + + r = sd_dhcp_lease_get_server_identifier(lease, &addr); + if (r < 0) + return log_link_debug_errno(link, r, "Failed to get DHCP server ip address: %m"); + + if (set_contains(link->network->dhcp_black_listed_ip, UINT32_TO_PTR(addr.s_addr))) { + log_struct(LOG_DEBUG, + LOG_LINK_INTERFACE(link), + LOG_LINK_MESSAGE(link, "DHCPv4 ip '%u.%u.%u.%u' found in black listed ip addresses, ignoring offer", + ADDRESS_FMT_VAL(addr))); + return true; + } + + return false; +} + +static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) { Link *link = userdata; - int r = 0; + int r; assert(link); assert(link->network); assert(link->manager); if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - return; + return 0; switch (event) { - case SD_DHCP_CLIENT_EVENT_EXPIRED: case SD_DHCP_CLIENT_EVENT_STOP: + + if (link_ipv4ll_fallback_enabled(link)) { + assert(link->ipv4ll); + + log_link_debug(link, "DHCP client is stopped. Acquiring IPv4 link-local address"); + + r = sd_ipv4ll_start(link->ipv4ll); + if (r < 0) + return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m"); + } + + if (link->network->dhcp_send_release) + (void) sd_dhcp_client_send_release(client); + + _fallthrough_; + case SD_DHCP_CLIENT_EVENT_EXPIRED: case SD_DHCP_CLIENT_EVENT_IP_CHANGE: + if (link->network->dhcp_critical) { log_link_error(link, "DHCPv4 connection considered system critical, ignoring request to reconfigure it."); - return; + return 0; } if (link->dhcp_lease) { r = dhcp_lease_lost(link); if (r < 0) { link_enter_failed(link); - return; + return r; } } @@ -544,7 +588,7 @@ static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) { r = dhcp_lease_acquired(client, link); if (r < 0) { link_enter_failed(link); - return; + return r; } } @@ -553,16 +597,23 @@ static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) { r = dhcp_lease_renew(client, link); if (r < 0) { link_enter_failed(link); - return; + return r; } break; case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE: r = dhcp_lease_acquired(client, link); if (r < 0) { link_enter_failed(link); - return; + return r; } break; + case SD_DHCP_CLIENT_EVENT_SELECTING: + r = dhcp_server_is_black_listed(link, client); + if (r < 0) + return r; + if (r != 0) + return -ENOMSG; + break; default: if (event < 0) log_link_warning_errno(link, event, "DHCP error: Client failed: %m"); @@ -571,7 +622,7 @@ static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) { break; } - return; + return 0; } static int dhcp4_set_hostname(Link *link) { @@ -818,5 +869,11 @@ int dhcp4_configure(Link *link) { return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set listen port: %m"); } + if (link->network->dhcp_max_attempts > 0) { + r = sd_dhcp_client_set_max_attempts(link->dhcp_client, link->network->dhcp_max_attempts); + if (r < 0) + return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set max attempts: %m"); + } + return dhcp4_set_client_identifier(link); }