From: Yu Watanabe Date: Mon, 9 Mar 2026 06:18:24 +0000 (+0900) Subject: sd-dhcp-client: several fixlets for sending RELEASE or DECLINE X-Git-Tag: v260-rc3~24^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6eaa5ba32231290971823d0ddf73bc712c384bcc;p=thirdparty%2Fsystemd.git sd-dhcp-client: several fixlets for sending RELEASE or DECLINE - Extract common logic to client_send_release_or_decline(). - Do not send DECLINE message on BOOTP protocol. - Drop redundant assignment of chaddr, as it is already set by client_message_init() -> dhcp_message_init(). - Do not assign acquired address in ciaddr field of DECLINE message, but use Requested IP Address option. - Broadcast DECLINE message, rather than unicast. - Set server identifier in both cases. Fixes #39299. --- diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 8c373146f61..4b1cdd0b863 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -876,7 +876,7 @@ static int client_message_init( MAY contain the Parameter Request List option. */ /* NOTE: in case that there would be an option to do not send * any PRL at all, the size should be checked before sending */ - if (!set_isempty(client->req_opts) && type != DHCP_RELEASE) { + if (!set_isempty(client->req_opts) && IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST)) { _cleanup_free_ uint8_t *opts = NULL; size_t n_opts, i = 0; void *val; @@ -2356,70 +2356,93 @@ int sd_dhcp_client_start(sd_dhcp_client *client) { return r; } -static int client_send_release(sd_dhcp_client *client) { - _cleanup_free_ DHCPPacket *release = NULL; - size_t optoffset, optlen; +static int client_send_release_or_decline(sd_dhcp_client *client, uint8_t type) { int r; - assert(client); + assert(IN_SET(type, DHCP_RELEASE, DHCP_DECLINE)); - if (!client->send_release) - return 0; /* disabled */ + if (!sd_dhcp_client_is_running(client) || !client->lease || client->bootp) + return 0; /* there is nothing to release or decline */ - if (!client->lease || client->bootp) - return 0; /* there is nothing to be released */ + const char *name = type == DHCP_RELEASE ? "RELEASE" : "DECLINE"; - r = client_message_init(client, DHCP_RELEASE, &release, &optlen, &optoffset); + _cleanup_free_ DHCPPacket *packet = NULL; + size_t optoffset, optlen; + r = client_message_init(client, type, &packet, &optlen, &optoffset); if (r < 0) - return r; + return log_dhcp_client_errno(client, r, "Failed to initialize DHCP %s message: %m", name); - /* Fill up release IP and MAC */ - release->dhcp.ciaddr = client->lease->address; - memcpy(&release->dhcp.chaddr, client->hw_addr.bytes, client->hw_addr.length); + /* See RFC 2131, Table 5 */ + switch (type) { + case DHCP_RELEASE: + /* On release, the acquired address must be set in ciaddr. */ + packet->dhcp.ciaddr = client->lease->address; + break; - r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0, - SD_DHCP_OPTION_END, 0, NULL); + case DHCP_DECLINE: + /* On decline, the acquired address must be set in Requested IP Address option. */ + r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, /* overload= */ 0, + SD_DHCP_OPTION_REQUESTED_IP_ADDRESS, + 4, &client->lease->address); + if (r < 0) + return log_dhcp_client_errno( + client, r, + "Failed to append Requested IP Address option to DHCP %s message: %m", + name); + break; + + default: + assert_not_reached(); + } + + /* In both cases, the server identifier must be set. */ + r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, /* overload= */ 0, + SD_DHCP_OPTION_SERVER_IDENTIFIER, + 4, &client->lease->server_address); if (r < 0) - return r; + return log_dhcp_client_errno( + client, r, + "Failed to append Server Identifier option to DHCP %s message: %m", + name); - r = dhcp_network_send_udp_socket(client->fd, - client->lease->server_address, - client->server_port, - &release->dhcp, - sizeof(DHCPMessage) + optoffset); + r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, /* overload= */ 0, + SD_DHCP_OPTION_END, /* optlen= */ 0, /* optval= */ NULL); if (r < 0) - return r; + return log_dhcp_client_errno( + client, r, + "Failed to finalize DHCP %s message: %m", + name); + + switch (type) { + case DHCP_RELEASE: + r = dhcp_network_send_udp_socket( + client->fd, + client->lease->server_address, + client->server_port, + &packet->dhcp, + sizeof(DHCPMessage) + optoffset); + break; + case DHCP_DECLINE: + r = dhcp_client_send_raw(client, packet, sizeof(DHCPPacket) + optoffset); + break; + default: + assert_not_reached(); + } + if (r < 0) + return log_dhcp_client_errno( + client, r, + "Failed to send DHCP %s message: %m", + name); - log_dhcp_client(client, "RELEASE"); - return 0; + log_dhcp_client(client, "%s", name); + return 1; /* sent */ } int sd_dhcp_client_send_decline(sd_dhcp_client *client) { - _cleanup_free_ DHCPPacket *release = NULL; - size_t optoffset, optlen; int r; - if (!sd_dhcp_client_is_running(client) || !client->lease) - return 0; /* do nothing */ - - r = client_message_init(client, DHCP_DECLINE, &release, &optlen, &optoffset); - if (r < 0) - return r; - - release->dhcp.ciaddr = client->lease->address; - memcpy(&release->dhcp.chaddr, client->hw_addr.bytes, client->hw_addr.length); - - r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0, - SD_DHCP_OPTION_END, 0, NULL); - if (r < 0) - return r; - - r = dhcp_network_send_udp_socket(client->fd, - client->lease->server_address, - client->server_port, - &release->dhcp, - sizeof(DHCPMessage) + optoffset); - if (r < 0) + r = client_send_release_or_decline(client, DHCP_DECLINE); + if (r <= 0) return r; log_dhcp_client(client, "DECLINE"); @@ -2434,20 +2457,15 @@ int sd_dhcp_client_send_decline(sd_dhcp_client *client) { } int sd_dhcp_client_stop(sd_dhcp_client *client) { - int r; - if (!client) return 0; DHCP_CLIENT_DONT_DESTROY(client); - r = client_send_release(client); - if (r < 0) - log_dhcp_client_errno(client, r, - "Failed to send DHCP release message, ignoring: %m"); + if (client->send_release) + (void) client_send_release_or_decline(client, DHCP_RELEASE); client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); - return 0; }