mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-22 22:03:43 +03:00
send dhcpv6 release when stopping
This commit is contained in:
parent
1200777b21
commit
b895aa5ff5
5
NEWS
5
NEWS
@ -131,6 +131,11 @@ CHANGES WITH 253 in spe:
|
||||
|
||||
* systemd-networkd-wait-online now supports alternative interface names.
|
||||
|
||||
* The [DHCPv6] section in .network file gained new SendRelease=
|
||||
setting which enables the DHCPv6 client to send release when
|
||||
it stops. This is the analog of the [DHCPv4] SendRelease= setting.
|
||||
It is enabled by default.
|
||||
|
||||
Changes in systemd-dissect:
|
||||
|
||||
* systemd-dissect gained a new option --list, to print the paths fo the
|
||||
|
@ -2292,6 +2292,7 @@ allow my_server_t localnet_peer_t:peer recv;</programlisting>
|
||||
<term><varname>UseHostname=</varname></term>
|
||||
<term><varname>UseDomains=</varname></term>
|
||||
<term><varname>NetLabel=</varname></term>
|
||||
<term><varname>SendRelease=</varname></term>
|
||||
<listitem>
|
||||
<para>As in the [DHCPv4] section.</para>
|
||||
</listitem>
|
||||
|
@ -79,6 +79,7 @@ struct sd_dhcp6_client {
|
||||
|
||||
sd_dhcp6_client_callback_t callback;
|
||||
void *userdata;
|
||||
bool send_release;
|
||||
|
||||
/* Ignore machine-ID when generating DUID. See dhcp_identifier_set_duid_en(). */
|
||||
bool test_mode;
|
||||
|
@ -11,6 +11,7 @@ static const char * const dhcp6_state_table[_DHCP6_STATE_MAX] = {
|
||||
[DHCP6_STATE_BOUND] = "bound",
|
||||
[DHCP6_STATE_RENEW] = "renew",
|
||||
[DHCP6_STATE_REBIND] = "rebind",
|
||||
[DHCP6_STATE_STOPPING] = "stopping",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(dhcp6_state, DHCP6State);
|
||||
|
@ -58,6 +58,7 @@ typedef enum DHCP6State {
|
||||
DHCP6_STATE_BOUND,
|
||||
DHCP6_STATE_RENEW,
|
||||
DHCP6_STATE_REBIND,
|
||||
DHCP6_STATE_STOPPING,
|
||||
_DHCP6_STATE_MAX,
|
||||
_DHCP6_STATE_INVALID = -EINVAL,
|
||||
} DHCP6State;
|
||||
|
@ -498,6 +498,14 @@ int sd_dhcp6_client_set_rapid_commit(sd_dhcp6_client *client, int enable) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_send_release(sd_dhcp6_client *client, int enable) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
|
||||
|
||||
client->send_release = enable;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) {
|
||||
assert_return(client, -EINVAL);
|
||||
|
||||
@ -586,7 +594,8 @@ static int client_append_common_options_in_managed_mode(
|
||||
DHCP6_STATE_SOLICITATION,
|
||||
DHCP6_STATE_REQUEST,
|
||||
DHCP6_STATE_RENEW,
|
||||
DHCP6_STATE_REBIND));
|
||||
DHCP6_STATE_REBIND,
|
||||
DHCP6_STATE_STOPPING));
|
||||
assert(buf);
|
||||
assert(*buf);
|
||||
assert(offset);
|
||||
@ -603,9 +612,11 @@ static int client_append_common_options_in_managed_mode(
|
||||
return r;
|
||||
}
|
||||
|
||||
r = dhcp6_option_append_fqdn(buf, offset, client->fqdn);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (client->state != DHCP6_STATE_STOPPING) {
|
||||
r = dhcp6_option_append_fqdn(buf, offset, client->fqdn);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = dhcp6_option_append_user_class(buf, offset, client->user_class);
|
||||
if (r < 0)
|
||||
@ -636,6 +647,8 @@ static DHCP6MessageType client_message_type_from_state(sd_dhcp6_client *client)
|
||||
return DHCP6_MESSAGE_RENEW;
|
||||
case DHCP6_STATE_REBIND:
|
||||
return DHCP6_MESSAGE_REBIND;
|
||||
case DHCP6_STATE_STOPPING:
|
||||
return DHCP6_MESSAGE_RELEASE;
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
@ -679,6 +692,9 @@ static int client_append_oro(sd_dhcp6_client *client, uint8_t **buf, size_t *off
|
||||
req_opts = p;
|
||||
break;
|
||||
|
||||
case DHCP6_STATE_STOPPING:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
n = client->n_req_opts;
|
||||
req_opts = client->req_opts;
|
||||
@ -690,6 +706,22 @@ static int client_append_oro(sd_dhcp6_client *client, uint8_t **buf, size_t *off
|
||||
return dhcp6_option_append(buf, offset, SD_DHCP6_OPTION_ORO, n * sizeof(be16_t), req_opts);
|
||||
}
|
||||
|
||||
static int client_append_mudurl(sd_dhcp6_client *client, uint8_t **buf, size_t *offset) {
|
||||
assert(client);
|
||||
assert(buf);
|
||||
assert(*buf);
|
||||
assert(offset);
|
||||
|
||||
if (!client->mudurl)
|
||||
return 0;
|
||||
|
||||
if (client->state == DHCP6_STATE_STOPPING)
|
||||
return 0;
|
||||
|
||||
return dhcp6_option_append(buf, offset, SD_DHCP6_OPTION_MUD_URL_V6,
|
||||
strlen(client->mudurl), client->mudurl);
|
||||
}
|
||||
|
||||
int dhcp6_client_send_message(sd_dhcp6_client *client) {
|
||||
_cleanup_free_ uint8_t *buf = NULL;
|
||||
struct in6_addr all_servers =
|
||||
@ -735,7 +767,7 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) {
|
||||
|
||||
case DHCP6_STATE_REQUEST:
|
||||
case DHCP6_STATE_RENEW:
|
||||
|
||||
case DHCP6_STATE_STOPPING:
|
||||
r = dhcp6_option_append(&buf, &offset, SD_DHCP6_OPTION_SERVERID,
|
||||
client->lease->serverid_len,
|
||||
client->lease->serverid);
|
||||
@ -753,18 +785,15 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) {
|
||||
return r;
|
||||
break;
|
||||
|
||||
case DHCP6_STATE_STOPPED:
|
||||
case DHCP6_STATE_BOUND:
|
||||
case DHCP6_STATE_STOPPED:
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
if (client->mudurl) {
|
||||
r = dhcp6_option_append(&buf, &offset, SD_DHCP6_OPTION_MUD_URL_V6,
|
||||
strlen(client->mudurl), client->mudurl);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
r = client_append_mudurl(client, &buf, &offset);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = client_append_oro(client, &buf, &offset);
|
||||
if (r < 0)
|
||||
@ -856,6 +885,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
|
||||
break;
|
||||
|
||||
case DHCP6_STATE_STOPPED:
|
||||
case DHCP6_STATE_STOPPING:
|
||||
case DHCP6_STATE_BOUND:
|
||||
default:
|
||||
assert_not_reached();
|
||||
@ -911,6 +941,7 @@ static int client_start_transaction(sd_dhcp6_client *client, DHCP6State state) {
|
||||
assert(IN_SET(client->state, DHCP6_STATE_BOUND, DHCP6_STATE_RENEW));
|
||||
break;
|
||||
case DHCP6_STATE_STOPPED:
|
||||
case DHCP6_STATE_STOPPING:
|
||||
case DHCP6_STATE_BOUND:
|
||||
default:
|
||||
assert_not_reached();
|
||||
@ -1319,6 +1350,7 @@ static int client_receive_message(
|
||||
|
||||
case DHCP6_STATE_BOUND:
|
||||
case DHCP6_STATE_STOPPED:
|
||||
case DHCP6_STATE_STOPPING:
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
@ -1326,10 +1358,37 @@ static int client_receive_message(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int client_send_release(sd_dhcp6_client *client) {
|
||||
sd_dhcp6_lease *lease;
|
||||
|
||||
assert(client);
|
||||
|
||||
if (!client->send_release)
|
||||
return 0;
|
||||
|
||||
if (sd_dhcp6_client_get_lease(client, &lease) < 0)
|
||||
return 0;
|
||||
|
||||
if (!lease->ia_na && !lease->ia_pd)
|
||||
return 0;
|
||||
|
||||
client_set_state(client, DHCP6_STATE_STOPPING);
|
||||
return dhcp6_client_send_message(client);
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_stop(sd_dhcp6_client *client) {
|
||||
int r;
|
||||
|
||||
if (!client)
|
||||
return 0;
|
||||
|
||||
/* Intentionally ignoring failure to send DHCP6 release. The DHCPv6 client
|
||||
engine is about to release its UDP socket inconditionally. */
|
||||
r = client_send_release(client);
|
||||
if (r < 0)
|
||||
log_dhcp6_client_errno(client, r,
|
||||
"Failed to send DHCP6 release message, ignoring: %m");
|
||||
|
||||
client_stop(client, SD_DHCP6_CLIENT_EVENT_STOP);
|
||||
|
||||
client->receive_message = sd_event_source_unref(client->receive_message);
|
||||
|
@ -602,6 +602,62 @@ static const uint8_t msg_request[] = {
|
||||
0x00, 0x00,
|
||||
};
|
||||
|
||||
/* RFC 3315 section 18.1.6. The DHCP6 Release message must include:
|
||||
- transaction id
|
||||
- server identifier
|
||||
- client identifier
|
||||
- all released IA with addresses included
|
||||
- elapsed time (required for all messages).
|
||||
All other options aren't required. */
|
||||
static const uint8_t msg_release[] = {
|
||||
/* Message type */
|
||||
DHCP6_MESSAGE_RELEASE,
|
||||
/* Transaction ID */
|
||||
0x00, 0x00, 0x00,
|
||||
/* Server ID */
|
||||
0x00, SD_DHCP6_OPTION_SERVERID, 0x00, 0x0e,
|
||||
SERVER_ID_BYTES,
|
||||
/* IA_NA */
|
||||
0x00, SD_DHCP6_OPTION_IA_NA, 0x00, 0x44,
|
||||
IA_ID_BYTES,
|
||||
0x00, 0x00, 0x00, 0x00, /* lifetime T1 */
|
||||
0x00, 0x00, 0x00, 0x00, /* lifetime T2 */
|
||||
/* IA_NA (IAADDR suboption) */
|
||||
0x00, SD_DHCP6_OPTION_IAADDR, 0x00, 0x18,
|
||||
IA_NA_ADDRESS1_BYTES,
|
||||
0x00, 0x00, 0x00, 0x00, /* preferred lifetime */
|
||||
0x00, 0x00, 0x00, 0x00, /* valid lifetime */
|
||||
/* IA_NA (IAADDR suboption) */
|
||||
0x00, SD_DHCP6_OPTION_IAADDR, 0x00, 0x18,
|
||||
IA_NA_ADDRESS2_BYTES,
|
||||
0x00, 0x00, 0x00, 0x00, /* preferred lifetime */
|
||||
0x00, 0x00, 0x00, 0x00, /* valid lifetime */
|
||||
/* IA_PD */
|
||||
0x00, SD_DHCP6_OPTION_IA_PD, 0x00, 0x46,
|
||||
IA_ID_BYTES,
|
||||
0x00, 0x00, 0x00, 0x00, /* lifetime T1 */
|
||||
0x00, 0x00, 0x00, 0x00, /* lifetime T2 */
|
||||
/* IA_PD (IA_PD_PREFIX suboption) */
|
||||
0x00, SD_DHCP6_OPTION_IA_PD_PREFIX, 0x00, 0x19,
|
||||
0x00, 0x00, 0x00, 0x00, /* preferred lifetime */
|
||||
0x00, 0x00, 0x00, 0x00, /* valid lifetime */
|
||||
0x40, /* prefixlen */
|
||||
IA_PD_PREFIX1_BYTES,
|
||||
/* IA_PD (IA_PD_PREFIX suboption) */
|
||||
0x00, SD_DHCP6_OPTION_IA_PD_PREFIX, 0x00, 0x19,
|
||||
0x00, 0x00, 0x00, 0x00, /* preferred lifetime */
|
||||
0x00, 0x00, 0x00, 0x00, /* valid lifetime */
|
||||
0x40, /* prefixlen */
|
||||
IA_PD_PREFIX2_BYTES,
|
||||
/* Client ID */
|
||||
0x00, SD_DHCP6_OPTION_CLIENTID, 0x00, 0x0e,
|
||||
CLIENT_ID_BYTES,
|
||||
/* Extra options */
|
||||
/* Elapsed time */
|
||||
0x00, SD_DHCP6_OPTION_ELAPSED_TIME, 0x00, 0x02,
|
||||
0x00, 0x00,
|
||||
};
|
||||
|
||||
static const uint8_t msg_reply[] = {
|
||||
/* Message type */
|
||||
DHCP6_MESSAGE_REPLY,
|
||||
@ -775,13 +831,24 @@ static void test_client_verify_solicit(const DHCP6Message *msg, size_t len) {
|
||||
assert_se(memcmp(msg, msg_solicit, len - sizeof(be16_t)) == 0);
|
||||
}
|
||||
|
||||
static void test_client_verify_release(const DHCP6Message *msg, size_t len) {
|
||||
log_debug("/* %s */", __func__);
|
||||
|
||||
assert_se(len == sizeof(msg_release));
|
||||
assert_se(msg->type == DHCP6_MESSAGE_RELEASE);
|
||||
/* The transaction ID and elapsed time value are not deterministic. Skip them. */
|
||||
assert_se(memcmp(msg->options, msg_release + offsetof(DHCP6Message, options),
|
||||
len - offsetof(DHCP6Message, options) - sizeof(be16_t)) == 0);
|
||||
}
|
||||
|
||||
static void test_client_verify_request(const DHCP6Message *msg, size_t len) {
|
||||
log_debug("/* %s */", __func__);
|
||||
|
||||
assert_se(len == sizeof(msg_request));
|
||||
assert_se(msg->type == DHCP6_MESSAGE_REQUEST);
|
||||
/* The transaction ID and elapsed time value are not deterministic. Skip them. */
|
||||
assert_se(memcmp(msg->options, msg_request + offsetof(DHCP6Message, options), len - offsetof(DHCP6Message, options) - sizeof(be16_t)) == 0);
|
||||
assert_se(memcmp(msg->options, msg_request + offsetof(DHCP6Message, options),
|
||||
len - offsetof(DHCP6Message, options) - sizeof(be16_t)) == 0);
|
||||
}
|
||||
|
||||
static void test_lease_common(sd_dhcp6_client *client) {
|
||||
@ -905,7 +972,7 @@ static void test_client_callback(sd_dhcp6_client *client, int event, void *userd
|
||||
case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE:
|
||||
log_debug("/* %s (event=ip-acquire) */", __func__);
|
||||
|
||||
assert_se(IN_SET(test_client_sent_message_count, 3, 4));
|
||||
assert_se(IN_SET(test_client_sent_message_count, 3, 5));
|
||||
|
||||
test_lease_managed(client);
|
||||
|
||||
@ -916,7 +983,7 @@ static void test_client_callback(sd_dhcp6_client *client, int event, void *userd
|
||||
assert_se(dhcp6_client_set_transaction_id(client, ((const DHCP6Message*) msg_reply)->transaction_id) >= 0);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
case 5:
|
||||
assert_se(sd_event_exit(sd_dhcp6_client_get_event(client), 0) >= 0);
|
||||
break;
|
||||
|
||||
@ -974,6 +1041,12 @@ int dhcp6_network_send_udp_socket(int s, struct in6_addr *a, const void *packet,
|
||||
break;
|
||||
|
||||
case 3:
|
||||
test_client_verify_release(packet, len);
|
||||
/* when stopping, dhcp6 client doesn't wait for release server reply */
|
||||
assert_se(write(test_fd[1], msg_reply, sizeof(msg_reply)) == sizeof(msg_reply));
|
||||
break;
|
||||
|
||||
case 4:
|
||||
test_client_verify_solicit(packet, len);
|
||||
assert_se(write(test_fd[1], msg_reply, sizeof(msg_reply)) == sizeof(msg_reply));
|
||||
break;
|
||||
@ -1010,6 +1083,7 @@ TEST(dhcp6_client) {
|
||||
assert_se(sd_dhcp6_client_set_local_address(client, &local_address) >= 0);
|
||||
assert_se(sd_dhcp6_client_set_fqdn(client, "host.lab.intra") >= 0);
|
||||
assert_se(sd_dhcp6_client_set_iaid(client, unaligned_read_be32((uint8_t[]) { IA_ID_BYTES })) >= 0);
|
||||
assert_se(sd_dhcp6_client_set_send_release(client, true) >= 0);
|
||||
dhcp6_client_set_test_mode(client, true);
|
||||
|
||||
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DNS_SERVER) >= 0);
|
||||
@ -1028,7 +1102,7 @@ TEST(dhcp6_client) {
|
||||
|
||||
assert_se(sd_event_loop(e) >= 0);
|
||||
|
||||
assert_se(test_client_sent_message_count == 4);
|
||||
assert_se(test_client_sent_message_count == 5);
|
||||
|
||||
assert_se(!sd_dhcp6_client_unref(client_ref));
|
||||
test_fd[1] = safe_close(test_fd[1]);
|
||||
|
@ -707,6 +707,12 @@ static int dhcp6_configure(Link *link) {
|
||||
"DHCPv6 CLIENT: Failed to %s rapid commit: %m",
|
||||
enable_disable(link->network->dhcp6_use_rapid_commit));
|
||||
|
||||
r = sd_dhcp6_client_set_send_release(client, link->network->dhcp6_send_release);
|
||||
if (r < 0)
|
||||
return log_link_debug_errno(link, r,
|
||||
"DHCPv6 CLIENT: Failed to %s sending release message on stop: %m",
|
||||
enable_disable(link->network->dhcp6_send_release));
|
||||
|
||||
link->dhcp6_client = TAKE_PTR(client);
|
||||
|
||||
return 0;
|
||||
|
@ -270,6 +270,7 @@ DHCPv6.DUIDType, config_parse_duid_type,
|
||||
DHCPv6.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, dhcp6_duid)
|
||||
DHCPv6.RapidCommit, config_parse_bool, 0, offsetof(Network, dhcp6_use_rapid_commit)
|
||||
DHCPv6.NetLabel, config_parse_string, CONFIG_PARSE_STRING_SAFE, offsetof(Network, dhcp6_netlabel)
|
||||
DHCPv6.SendRelease, config_parse_bool, 0, offsetof(Network, dhcp6_send_release)
|
||||
IPv6AcceptRA.UseGateway, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_gateway)
|
||||
IPv6AcceptRA.UseRoutePrefix, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_route_prefix)
|
||||
IPv6AcceptRA.UseAutonomousPrefix, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_autonomous_prefix)
|
||||
|
@ -416,6 +416,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
|
||||
.dhcp6_use_rapid_commit = true,
|
||||
.dhcp6_duid.type = _DUID_TYPE_INVALID,
|
||||
.dhcp6_client_start_mode = _DHCP6_CLIENT_START_MODE_INVALID,
|
||||
.dhcp6_send_release = true,
|
||||
|
||||
.dhcp_pd = -1,
|
||||
.dhcp_pd_announce = true,
|
||||
|
@ -186,6 +186,7 @@ struct Network {
|
||||
OrderedHashmap *dhcp6_client_send_vendor_options;
|
||||
Set *dhcp6_request_options;
|
||||
char *dhcp6_netlabel;
|
||||
bool dhcp6_send_release;
|
||||
|
||||
/* DHCP Server Support */
|
||||
bool dhcp_server;
|
||||
|
@ -264,6 +264,7 @@ int sd_dhcp6_client_set_address_request(sd_dhcp6_client *client,
|
||||
int sd_dhcp6_client_add_vendor_option(sd_dhcp6_client *client,
|
||||
sd_dhcp6_option *v);
|
||||
int sd_dhcp6_client_set_rapid_commit(sd_dhcp6_client *client, int enable);
|
||||
int sd_dhcp6_client_set_send_release(sd_dhcp6_client *client, int enable);
|
||||
|
||||
int sd_dhcp6_client_get_lease(
|
||||
sd_dhcp6_client *client,
|
||||
|
Loading…
x
Reference in New Issue
Block a user