mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-03 08:10:17 +01:00
dhcp: merge branch 'th/dhcp-client-id-in-lease'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1477
(cherry picked from commit 831b8f8e7e)
This commit is contained in:
commit
82d5f00961
12 changed files with 402 additions and 228 deletions
|
|
@ -237,30 +237,65 @@ nm_dhcp_client_create_l3cd(NMDhcpClient *self)
|
|||
NM_IP_CONFIG_SOURCE_DHCP);
|
||||
}
|
||||
|
||||
GHashTable *
|
||||
nm_dhcp_client_create_options_dict(NMDhcpClient *self, gboolean static_keys)
|
||||
{
|
||||
NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self);
|
||||
GHashTable *options;
|
||||
GBytes *effective_client_id;
|
||||
|
||||
options = nm_dhcp_option_create_options_dict(static_keys);
|
||||
|
||||
effective_client_id = nm_dhcp_client_get_effective_client_id(self);
|
||||
if (effective_client_id) {
|
||||
guint option = NM_IS_IPv4(priv->config.addr_family) ? NM_DHCP_OPTION_DHCP4_CLIENT_ID
|
||||
: NM_DHCP_OPTION_DHCP6_CLIENT_ID;
|
||||
gs_free char *str = nm_dhcp_utils_duid_to_string(effective_client_id);
|
||||
|
||||
/* Note that for the nm-dhcp-helper based plugins (dhclient), the plugin
|
||||
* may send the used client-id/DUID via the environment variables and
|
||||
* overwrite them yet again. */
|
||||
|
||||
if (static_keys) {
|
||||
nm_dhcp_option_add_option(options, priv->config.addr_family, option, str);
|
||||
} else {
|
||||
g_hash_table_insert(
|
||||
options,
|
||||
g_strdup(nm_dhcp_option_request_string(priv->config.addr_family, option)),
|
||||
g_steal_pointer(&str));
|
||||
}
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void
|
||||
gboolean
|
||||
nm_dhcp_client_set_effective_client_id(NMDhcpClient *self, GBytes *client_id)
|
||||
{
|
||||
NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self);
|
||||
gs_free char *tmp_str = NULL;
|
||||
NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self);
|
||||
gs_free char *tmp_str = NULL;
|
||||
gs_unref_bytes GBytes *client_id_to_free = NULL;
|
||||
|
||||
g_return_if_fail(NM_IS_DHCP_CLIENT(self));
|
||||
g_return_if_fail(!client_id || g_bytes_get_size(client_id) >= 2);
|
||||
g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE);
|
||||
g_return_val_if_fail(!client_id || g_bytes_get_size(client_id) >= 2, FALSE);
|
||||
|
||||
priv = NM_DHCP_CLIENT_GET_PRIVATE(self);
|
||||
|
||||
if (nm_g_bytes_equal0(priv->effective_client_id, client_id))
|
||||
return;
|
||||
return FALSE;
|
||||
|
||||
g_bytes_unref(priv->effective_client_id);
|
||||
client_id_to_free = g_steal_pointer(&priv->effective_client_id);
|
||||
priv->effective_client_id = nm_g_bytes_ref(client_id);
|
||||
|
||||
_LOGT("%s: set %s",
|
||||
_LOGT("%s: set effective %s",
|
||||
priv->config.addr_family == AF_INET6 ? "duid" : "client-id",
|
||||
priv->effective_client_id
|
||||
? (tmp_str = nm_dhcp_utils_duid_to_string(priv->effective_client_id))
|
||||
: "default");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -967,12 +1002,6 @@ _dhcp_client_decline(NMDhcpClient *self,
|
|||
return klass->decline(self, l3cd, error_message, error);
|
||||
}
|
||||
|
||||
static GBytes *
|
||||
get_duid(NMDhcpClient *self)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ipv6_lladdr_timeout(gpointer user_data)
|
||||
{
|
||||
|
|
@ -1317,11 +1346,6 @@ nm_dhcp_client_start(NMDhcpClient *self, GError **error)
|
|||
IS_IPv4 = NM_IS_IPv4(priv->config.addr_family);
|
||||
|
||||
if (!IS_IPv4) {
|
||||
if (!priv->config.v6.enforce_duid)
|
||||
own_client_id = NM_DHCP_CLIENT_GET_CLASS(self)->get_duid(self);
|
||||
|
||||
nm_dhcp_client_set_effective_client_id(self, own_client_id ?: priv->config.client_id);
|
||||
|
||||
addr = ipv6_lladdr_find(self);
|
||||
if (!addr) {
|
||||
_LOGD("waiting for IPv6LL address");
|
||||
|
|
@ -1449,7 +1473,7 @@ nm_dhcp_client_stop(NMDhcpClient *self, gboolean release)
|
|||
/*****************************************************************************/
|
||||
|
||||
static char *
|
||||
bytearray_variant_to_string(NMDhcpClient *self, GVariant *value, const char *key)
|
||||
bytearray_variant_to_string(GVariant *value)
|
||||
{
|
||||
const guint8 *array;
|
||||
char *str;
|
||||
|
|
@ -1499,8 +1523,9 @@ label_is_unknown_xyz(const char *label)
|
|||
static void
|
||||
maybe_add_option(NMDhcpClient *self, GHashTable *hash, const char *key, GVariant *value)
|
||||
{
|
||||
char *str_value;
|
||||
int priv_opt_num;
|
||||
const int IS_IPv4 = NM_IS_IPv4(NM_DHCP_CLIENT_GET_PRIVATE(self)->config.addr_family);
|
||||
char *str_value;
|
||||
int priv_opt_num;
|
||||
|
||||
if (!g_variant_is_of_type(value, G_VARIANT_TYPE_BYTESTRING))
|
||||
return;
|
||||
|
|
@ -1517,27 +1542,49 @@ maybe_add_option(NMDhcpClient *self, GHashTable *hash, const char *key, GVariant
|
|||
if (NM_STR_HAS_PREFIX(key, "private_") || !key[0])
|
||||
return;
|
||||
|
||||
str_value = bytearray_variant_to_string(self, value, key);
|
||||
str_value = bytearray_variant_to_string(value);
|
||||
if (!str_value)
|
||||
return;
|
||||
|
||||
if ((IS_IPv4 && nm_streq(key, "dhcp_client_identifier"))
|
||||
|| (!IS_IPv4 && nm_streq(key, "dhcp6_client_id"))) {
|
||||
gs_free char *str = g_steal_pointer(&str_value);
|
||||
gs_unref_bytes GBytes *bytes = NULL;
|
||||
|
||||
/* Validate and normalize the client-id/DUID. */
|
||||
|
||||
bytes = nm_utils_hexstr2bin(str);
|
||||
if (!bytes || g_bytes_get_size(bytes) < 2) {
|
||||
/* Seems invalid. Ignore */
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nm_dhcp_client_set_effective_client_id(self, bytes)) {
|
||||
/* the client-id is identical and we already set it. Nothing to do. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* The effective-client-id was (re)set. Update "hash" with the new value... */
|
||||
str_value = nm_dhcp_utils_duid_to_string(bytes);
|
||||
}
|
||||
|
||||
g_hash_table_insert(hash, g_strdup(key), str_value);
|
||||
|
||||
/* dhclient has no special labels for private dhcp options: it uses "unknown_xyz"
|
||||
* labels for that. We need to identify those to alias them to our "private_xyz"
|
||||
* format unused in the internal dchp plugins.
|
||||
*/
|
||||
* labels for that. We need to identify those to alias them to our "private_xyz"
|
||||
* format unused in the internal dchp plugins.
|
||||
*/
|
||||
if ((priv_opt_num = label_is_unknown_xyz(key)) > 0) {
|
||||
gs_free guint8 *check_val = NULL;
|
||||
char *hex_str = NULL;
|
||||
gsize len;
|
||||
|
||||
/* dhclient passes values from dhcp private options in its own "string" format:
|
||||
* if the raw values are printable as ascii strings, it will pass the string
|
||||
* representation; if the values are not printable as an ascii string, it will
|
||||
* pass a string displaying the hex values (hex string). Try to enforce passing
|
||||
* always an hex string, converting string representation if needed.
|
||||
*/
|
||||
* if the raw values are printable as ascii strings, it will pass the string
|
||||
* representation; if the values are not printable as an ascii string, it will
|
||||
* pass a string displaying the hex values (hex string). Try to enforce passing
|
||||
* always an hex string, converting string representation if needed.
|
||||
*/
|
||||
check_val = nm_utils_hexstr2bin_alloc(str_value, FALSE, TRUE, ":", 0, &len);
|
||||
hex_str = nm_utils_bin2hexstr_full(check_val ?: (guint8 *) str_value,
|
||||
check_val ? len : strlen(str_value),
|
||||
|
|
@ -1623,7 +1670,7 @@ nm_dhcp_client_handle_event(gpointer unused,
|
|||
GVariant *value;
|
||||
|
||||
/* Copy options */
|
||||
str_options = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_free);
|
||||
str_options = nm_dhcp_client_create_options_dict(self, FALSE);
|
||||
g_variant_iter_init(&iter, options);
|
||||
while (g_variant_iter_next(&iter, "{&sv}", &name, &value)) {
|
||||
maybe_add_option(self, str_options, name, value);
|
||||
|
|
@ -1914,8 +1961,7 @@ nm_dhcp_client_class_init(NMDhcpClientClass *client_class)
|
|||
client_class->accept = _accept;
|
||||
client_class->decline = decline;
|
||||
|
||||
client_class->stop = stop;
|
||||
client_class->get_duid = get_duid;
|
||||
client_class->stop = stop;
|
||||
|
||||
obj_properties[PROP_CONFIG] =
|
||||
g_param_spec_pointer(NM_DHCP_CLIENT_CONFIG,
|
||||
|
|
|
|||
|
|
@ -214,17 +214,6 @@ typedef struct {
|
|||
gboolean (*ip6_start)(NMDhcpClient *self, const struct in6_addr *ll_addr, GError **error);
|
||||
|
||||
void (*stop)(NMDhcpClient *self, gboolean release);
|
||||
|
||||
/**
|
||||
* get_duid:
|
||||
* @self: the #NMDhcpClient
|
||||
*
|
||||
* Attempts to find an existing DHCPv6 DUID for this client in the DHCP
|
||||
* client's persistent configuration. Returned DUID should be the binary
|
||||
* representation of the DUID. If no DUID is found, %NULL should be
|
||||
* returned.
|
||||
*/
|
||||
GBytes *(*get_duid)(NMDhcpClient *self);
|
||||
} NMDhcpClientClass;
|
||||
|
||||
GType nm_dhcp_client_get_type(void);
|
||||
|
|
@ -285,11 +274,13 @@ const char *nm_dhcp_client_get_iface(NMDhcpClient *self);
|
|||
NMDedupMultiIndex *nm_dhcp_client_get_multi_idx(NMDhcpClient *self);
|
||||
int nm_dhcp_client_get_ifindex(NMDhcpClient *self);
|
||||
|
||||
void nm_dhcp_client_set_effective_client_id(NMDhcpClient *self, GBytes *client_id);
|
||||
GBytes *nm_dhcp_client_get_effective_client_id(NMDhcpClient *self);
|
||||
gboolean nm_dhcp_client_set_effective_client_id(NMDhcpClient *self, GBytes *client_id);
|
||||
GBytes *nm_dhcp_client_get_effective_client_id(NMDhcpClient *self);
|
||||
|
||||
NML3ConfigData *nm_dhcp_client_create_l3cd(NMDhcpClient *self);
|
||||
|
||||
GHashTable *nm_dhcp_client_create_options_dict(NMDhcpClient *self, gboolean static_keys);
|
||||
|
||||
/*****************************************************************************
|
||||
* Client data
|
||||
*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -399,6 +399,7 @@ nm_dhcp_dhclient_create_config(const char *interface,
|
|||
if (out_new_client_id)
|
||||
nm_clear_pointer(out_new_client_id, g_bytes_unref);
|
||||
NM_SET_OUT(out_new_client_id, read_client_id(p));
|
||||
/* fall-through. We keep the line... */
|
||||
}
|
||||
|
||||
/* Override config file hostname and use one from the connection */
|
||||
|
|
@ -523,6 +524,20 @@ nm_dhcp_dhclient_create_config(const char *interface,
|
|||
return g_string_free(g_steal_pointer(&new_contents), FALSE);
|
||||
}
|
||||
|
||||
/* In the lease file, dhclient will write "option dhcp6.client-id $HEXSTR". This
|
||||
* function does the same. */
|
||||
static char *
|
||||
nm_dhcp_dhclient_escape_duid_as_hex(GBytes *duid)
|
||||
{
|
||||
const guint8 *s;
|
||||
gsize len;
|
||||
|
||||
nm_assert(duid);
|
||||
|
||||
s = g_bytes_get_data(duid, &len);
|
||||
return nm_utils_bin2hexstr_fuller(s, len, ':', FALSE, FALSE, NULL);
|
||||
}
|
||||
|
||||
/* Roughly follow what dhclient's quotify_buf() and pretty_escape() functions do */
|
||||
char *
|
||||
nm_dhcp_dhclient_escape_duid(GBytes *duid)
|
||||
|
|
@ -605,7 +620,7 @@ error:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#define DUID_PREFIX "default-duid \""
|
||||
#define DEFAULT_DUID_PREFIX "default-duid \""
|
||||
|
||||
/* Beware: @error may be unset even if the function returns %NULL. */
|
||||
GBytes *
|
||||
|
|
@ -626,10 +641,10 @@ nm_dhcp_dhclient_read_duid(const char *leasefile, GError **error)
|
|||
const char *p = nm_str_skip_leading_spaces(contents_v[i]);
|
||||
GBytes *duid;
|
||||
|
||||
if (!NM_STR_HAS_PREFIX(p, DUID_PREFIX))
|
||||
if (!NM_STR_HAS_PREFIX(p, DEFAULT_DUID_PREFIX))
|
||||
continue;
|
||||
|
||||
p += NM_STRLEN(DUID_PREFIX);
|
||||
p += NM_STRLEN(DEFAULT_DUID_PREFIX);
|
||||
|
||||
g_strchomp((char *) p);
|
||||
|
||||
|
|
@ -647,15 +662,21 @@ nm_dhcp_dhclient_read_duid(const char *leasefile, GError **error)
|
|||
}
|
||||
|
||||
gboolean
|
||||
nm_dhcp_dhclient_save_duid(const char *leasefile, GBytes *duid, GError **error)
|
||||
nm_dhcp_dhclient_save_duid(const char *leasefile,
|
||||
GBytes *duid,
|
||||
gboolean enforce_duid,
|
||||
GError **error)
|
||||
{
|
||||
gs_free char *escaped_duid = NULL;
|
||||
gs_free const char **lines = NULL;
|
||||
nm_auto_free_gstring GString *s = NULL;
|
||||
const char *const *iter;
|
||||
gsize len = 0;
|
||||
gs_free char *conflicting_duid_line = NULL;
|
||||
gs_free char *contents = NULL;
|
||||
gsize contents_len = 0;
|
||||
|
||||
g_return_val_if_fail(leasefile != NULL, FALSE);
|
||||
|
||||
if (!duid) {
|
||||
nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "missing duid");
|
||||
g_return_val_if_reached(FALSE);
|
||||
|
|
@ -665,48 +686,68 @@ nm_dhcp_dhclient_save_duid(const char *leasefile, GBytes *duid, GError **error)
|
|||
nm_assert(escaped_duid);
|
||||
|
||||
if (g_file_test(leasefile, G_FILE_TEST_EXISTS)) {
|
||||
gs_free char *contents = NULL;
|
||||
|
||||
if (!g_file_get_contents(leasefile, &contents, &len, error)) {
|
||||
if (!g_file_get_contents(leasefile, &contents, &contents_len, error)) {
|
||||
g_prefix_error(error, "failed to read lease file %s: ", leasefile);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
lines = nm_strsplit_set_with_empty(contents, "\n\r");
|
||||
lines = nm_strsplit_set_with_empty(contents, "\n");
|
||||
}
|
||||
|
||||
s = g_string_sized_new(len + 50);
|
||||
g_string_append_printf(s, DUID_PREFIX "%s\";\n", escaped_duid);
|
||||
s = g_string_sized_new(contents_len + 50);
|
||||
g_string_append_printf(s, DEFAULT_DUID_PREFIX "%s\";\n", escaped_duid);
|
||||
|
||||
/* Preserve existing leasefile contents */
|
||||
if (lines) {
|
||||
for (iter = lines; *iter; iter++) {
|
||||
const char *str = *iter;
|
||||
const char *l;
|
||||
gboolean ends_with_r;
|
||||
gsize l_len;
|
||||
gsize prefix_len;
|
||||
|
||||
/* If we find an uncommented DUID in the file, check if
|
||||
* equal to the one we are going to write: if so, no need
|
||||
* to update the lease file, otherwise skip the old DUID.
|
||||
*/
|
||||
l = nm_str_skip_leading_spaces(str);
|
||||
if (g_str_has_prefix(l, DUID_PREFIX)) {
|
||||
gs_strfreev char **split = NULL;
|
||||
l = nm_str_skip_leading_spaces(str);
|
||||
l_len = strlen(l);
|
||||
prefix_len = l - str;
|
||||
|
||||
split = g_strsplit(l, "\"", -1);
|
||||
if (split[0] && nm_streq0(split[1], escaped_duid))
|
||||
return TRUE;
|
||||
ends_with_r = l_len > 0 && l[l_len - 1u] == '\r';
|
||||
if (ends_with_r) {
|
||||
((char *) l)[--l_len] = '\0';
|
||||
}
|
||||
|
||||
if (NM_STR_HAS_PREFIX(l, DEFAULT_DUID_PREFIX)) {
|
||||
/* We always add our line on top. This line can be skipped. */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (str)
|
||||
g_string_append(s, str);
|
||||
/* avoid to add an extra '\n' at the end of file */
|
||||
if ((iter[1]) != NULL)
|
||||
if (enforce_duid & NM_STR_HAS_PREFIX(l, "option dhcp6.client-id ")) {
|
||||
/* we want to use our duid. Skip the per-lease client-id. */
|
||||
if (!conflicting_duid_line) {
|
||||
gs_free char *duid_hex = nm_dhcp_dhclient_escape_duid_as_hex(duid);
|
||||
|
||||
conflicting_duid_line = g_strdup_printf("option dhcp6.client-id %s;", duid_hex);
|
||||
}
|
||||
/* We adjust the duid line and set what we want. */
|
||||
l = conflicting_duid_line;
|
||||
}
|
||||
|
||||
g_string_append_len(s, str, prefix_len);
|
||||
g_string_append(s, l);
|
||||
if (ends_with_r) {
|
||||
g_string_append_c(s, '\r');
|
||||
g_string_append_c(s, '\n');
|
||||
} else if ((iter[1]) != NULL) {
|
||||
/* avoid to add an extra '\n' at the end of file */
|
||||
g_string_append_c(s, '\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (contents && strlen(contents) == contents_len && nm_streq(contents, s->str)) {
|
||||
/* The file is already as we want it. We are done. */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!g_file_set_contents(leasefile, s->str, -1, error)) {
|
||||
g_prefix_error(error, "failed to set DUID in lease file %s: ", leasefile);
|
||||
return FALSE;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ GBytes *nm_dhcp_dhclient_unescape_duid(const char *duid);
|
|||
|
||||
GBytes *nm_dhcp_dhclient_read_duid(const char *leasefile, GError **error);
|
||||
|
||||
gboolean nm_dhcp_dhclient_save_duid(const char *leasefile, GBytes *duid, GError **error);
|
||||
gboolean nm_dhcp_dhclient_save_duid(const char *leasefile,
|
||||
GBytes *duid,
|
||||
gboolean enforce_duid,
|
||||
GError **error);
|
||||
|
||||
#endif /* __NETWORKMANAGER_DHCP_DHCLIENT_UTILS_H__ */
|
||||
|
|
|
|||
|
|
@ -82,6 +82,10 @@ G_DEFINE_TYPE(NMDhcpDhclient, nm_dhcp_dhclient, NM_TYPE_DHCP_CLIENT)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static GBytes *read_duid_from_lease(NMDhcpDhclient *self);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static const char *
|
||||
nm_dhcp_dhclient_get_path(void)
|
||||
{
|
||||
|
|
@ -332,6 +336,7 @@ static gboolean
|
|||
dhclient_start(NMDhcpClient *client,
|
||||
gboolean set_mode,
|
||||
gboolean release,
|
||||
gboolean set_duid,
|
||||
pid_t *out_pid,
|
||||
GError **error)
|
||||
{
|
||||
|
|
@ -410,8 +415,11 @@ dhclient_start(NMDhcpClient *client,
|
|||
}
|
||||
|
||||
/* Save the DUID to the leasefile dhclient will actually use */
|
||||
if (addr_family == AF_INET6) {
|
||||
if (!nm_dhcp_dhclient_save_duid(priv->lease_file, client_config->client_id, &local)) {
|
||||
if (set_duid && addr_family == AF_INET6) {
|
||||
if (!nm_dhcp_dhclient_save_duid(priv->lease_file,
|
||||
nm_dhcp_client_get_effective_client_id(client),
|
||||
client_config->v6.enforce_duid,
|
||||
&local)) {
|
||||
nm_utils_error_set(error,
|
||||
NM_UTILS_ERROR_UNKNOWN,
|
||||
"failed to save DUID to '%s': %s",
|
||||
|
|
@ -547,11 +555,11 @@ ip4_start(NMDhcpClient *client, GError **error)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if (new_client_id) {
|
||||
nm_assert(!client_config->client_id);
|
||||
nm_dhcp_client_set_effective_client_id(client, new_client_id);
|
||||
}
|
||||
return dhclient_start(client, FALSE, FALSE, NULL, error);
|
||||
/* Note that the effective-client-id for IPv4 here might be unknown/NULL. */
|
||||
nm_assert(!new_client_id || !client_config->client_id);
|
||||
nm_dhcp_client_set_effective_client_id(client, client_config->client_id ?: new_client_id);
|
||||
|
||||
return dhclient_start(client, FALSE, FALSE, FALSE, NULL, error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
|
@ -560,6 +568,7 @@ ip6_start(NMDhcpClient *client, const struct in6_addr *ll_addr, GError **error)
|
|||
NMDhcpDhclient *self = NM_DHCP_DHCLIENT(client);
|
||||
NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE(self);
|
||||
const NMDhcpClientConfig *config;
|
||||
gs_unref_bytes GBytes *effective_client_id = NULL;
|
||||
|
||||
config = nm_dhcp_client_get_config(client);
|
||||
|
||||
|
|
@ -586,7 +595,12 @@ ip6_start(NMDhcpClient *client, const struct in6_addr *ll_addr, GError **error)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
return dhclient_start(client, TRUE, FALSE, NULL, error);
|
||||
nm_assert(config->client_id);
|
||||
if (!config->v6.enforce_duid)
|
||||
effective_client_id = read_duid_from_lease(self);
|
||||
nm_dhcp_client_set_effective_client_id(client, effective_client_id ?: config->client_id);
|
||||
|
||||
return dhclient_start(client, TRUE, FALSE, TRUE, NULL, error);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -620,7 +634,7 @@ stop(NMDhcpClient *client, gboolean release)
|
|||
if (release) {
|
||||
pid_t rpid = -1;
|
||||
|
||||
if (dhclient_start(client, FALSE, TRUE, &rpid, NULL)) {
|
||||
if (dhclient_start(client, FALSE, TRUE, FALSE, &rpid, NULL)) {
|
||||
/* Wait a few seconds for the release to happen */
|
||||
nm_dhcp_client_stop_pid(rpid, nm_dhcp_client_get_iface(client));
|
||||
}
|
||||
|
|
@ -628,10 +642,10 @@ stop(NMDhcpClient *client, gboolean release)
|
|||
}
|
||||
|
||||
static GBytes *
|
||||
get_duid(NMDhcpClient *client)
|
||||
read_duid_from_lease(NMDhcpDhclient *self)
|
||||
{
|
||||
NMDhcpDhclient *self = NM_DHCP_DHCLIENT(client);
|
||||
NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE(self);
|
||||
NMDhcpClient *client = NM_DHCP_CLIENT(self);
|
||||
NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE(self);
|
||||
const NMDhcpClientConfig *client_config;
|
||||
GBytes *duid = NULL;
|
||||
gs_free char *leasefile = NULL;
|
||||
|
|
@ -724,7 +738,6 @@ nm_dhcp_dhclient_class_init(NMDhcpDhclientClass *dhclient_class)
|
|||
client_class->ip4_start = ip4_start;
|
||||
client_class->ip6_start = ip6_start;
|
||||
client_class->stop = stop;
|
||||
client_class->get_duid = get_duid;
|
||||
}
|
||||
|
||||
const NMDhcpClientFactory _nm_dhcp_client_factory_dhclient = {
|
||||
|
|
|
|||
|
|
@ -624,7 +624,7 @@ lease_to_ip4_config(NMDhcpNettools *self, NDhcp4ClientLease *lease, GError **err
|
|||
|
||||
l3cd = nm_dhcp_client_create_l3cd(NM_DHCP_CLIENT(self));
|
||||
|
||||
options = nm_dhcp_option_create_options_dict();
|
||||
options = nm_dhcp_client_create_options_dict(NM_DHCP_CLIENT(self), TRUE);
|
||||
|
||||
if (!lease_parse_address(self, lease, l3cd, iface, options, &lease_address, error))
|
||||
return NULL;
|
||||
|
|
@ -1100,7 +1100,7 @@ dhcp4_event_cb(int fd, GIOCondition condition, gpointer user_data)
|
|||
}
|
||||
|
||||
static gboolean
|
||||
nettools_create(NMDhcpNettools *self, GError **error)
|
||||
nettools_create(NMDhcpNettools *self, GBytes **out_effective_client_id, GError **error)
|
||||
{
|
||||
NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self);
|
||||
nm_auto(n_dhcp4_client_config_freep) NDhcp4ClientConfig *config = NULL;
|
||||
|
|
@ -1197,6 +1197,9 @@ nettools_create(NMDhcpNettools *self, GError **error)
|
|||
|
||||
priv->event_source = nm_g_unix_fd_add_source(fd, G_IO_IN, dhcp4_event_cb, self);
|
||||
|
||||
*out_effective_client_id =
|
||||
(client_id == client_id_new) ? g_steal_pointer(&client_id_new) : g_bytes_ref(client_id);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -1287,8 +1290,9 @@ static gboolean
|
|||
ip4_start(NMDhcpClient *client, GError **error)
|
||||
{
|
||||
nm_auto(n_dhcp4_client_probe_config_freep) NDhcp4ClientProbeConfig *config = NULL;
|
||||
NMDhcpNettools *self = NM_DHCP_NETTOOLS(client);
|
||||
NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self);
|
||||
NMDhcpNettools *self = NM_DHCP_NETTOOLS(client);
|
||||
NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self);
|
||||
gs_unref_bytes GBytes *effective_client_id = NULL;
|
||||
const NMDhcpClientConfig *client_config;
|
||||
gs_free char *lease_file = NULL;
|
||||
struct in_addr last_addr = {0};
|
||||
|
|
@ -1299,7 +1303,7 @@ ip4_start(NMDhcpClient *client, GError **error)
|
|||
g_return_val_if_fail(!priv->probe, FALSE);
|
||||
g_return_val_if_fail(client_config, FALSE);
|
||||
|
||||
if (!nettools_create(self, error))
|
||||
if (!nettools_create(self, &effective_client_id, error))
|
||||
return FALSE;
|
||||
|
||||
r = n_dhcp4_client_probe_config_new(&config);
|
||||
|
|
@ -1445,6 +1449,9 @@ ip4_start(NMDhcpClient *client, GError **error)
|
|||
}
|
||||
|
||||
_LOGT("dhcp-client4: start " NM_HASH_OBFUSCATE_PTR_FMT, NM_HASH_OBFUSCATE_PTR(priv->client));
|
||||
|
||||
nm_dhcp_client_set_effective_client_id(client, effective_client_id);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -190,12 +190,12 @@ static const NMDhcpOption *const _sorted_options_4[G_N_ELEMENTS(_nm_dhcp_option_
|
|||
};
|
||||
|
||||
const NMDhcpOption _nm_dhcp_option_dhcp6_options[] = {
|
||||
REQ(NM_DHCP_OPTION_DHCP6_CLIENTID, "dhcp6_client_id", FALSE),
|
||||
REQ(NM_DHCP_OPTION_DHCP6_CLIENT_ID, "dhcp6_client_id", FALSE),
|
||||
|
||||
/* Don't request server ID by default; some servers don't reply to
|
||||
* Information Requests that request the Server ID.
|
||||
*/
|
||||
REQ(NM_DHCP_OPTION_DHCP6_SERVERID, "dhcp6_server_id", FALSE),
|
||||
REQ(NM_DHCP_OPTION_DHCP6_SERVER_ID, "dhcp6_server_id", FALSE),
|
||||
|
||||
REQ(NM_DHCP_OPTION_DHCP6_DNS_SERVERS, "dhcp6_name_servers", TRUE),
|
||||
REQ(NM_DHCP_OPTION_DHCP6_DOMAIN_LIST, "dhcp6_domain_search", TRUE),
|
||||
|
|
@ -460,7 +460,7 @@ nm_dhcp_option_add_requests_to_options(GHashTable *options, int addr_family)
|
|||
}
|
||||
|
||||
GHashTable *
|
||||
nm_dhcp_option_create_options_dict(void)
|
||||
nm_dhcp_option_create_options_dict(gboolean static_keys)
|
||||
{
|
||||
return g_hash_table_new_full(nm_str_hash, g_str_equal, NULL, g_free);
|
||||
return g_hash_table_new_full(nm_str_hash, g_str_equal, static_keys ? NULL : g_free, g_free);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,8 +157,8 @@ typedef enum {
|
|||
} NMDhcpOptionDhcp4Options;
|
||||
|
||||
typedef enum {
|
||||
NM_DHCP_OPTION_DHCP6_CLIENTID = 1,
|
||||
NM_DHCP_OPTION_DHCP6_SERVERID = 2,
|
||||
NM_DHCP_OPTION_DHCP6_CLIENT_ID = 1,
|
||||
NM_DHCP_OPTION_DHCP6_SERVER_ID = 2,
|
||||
NM_DHCP_OPTION_DHCP6_DNS_SERVERS = 23,
|
||||
NM_DHCP_OPTION_DHCP6_DOMAIN_LIST = 24,
|
||||
NM_DHCP_OPTION_DHCP6_SNTP_SERVERS = 31,
|
||||
|
|
@ -222,7 +222,8 @@ void nm_dhcp_option_add_option_in_addr(GHashTable *options,
|
|||
in_addr_t value);
|
||||
void
|
||||
nm_dhcp_option_add_option_u64(GHashTable *options, int addr_family, guint option, guint64 value);
|
||||
void nm_dhcp_option_add_requests_to_options(GHashTable *options, int addr_family);
|
||||
GHashTable *nm_dhcp_option_create_options_dict(void);
|
||||
void nm_dhcp_option_add_requests_to_options(GHashTable *options, int addr_family);
|
||||
|
||||
GHashTable *nm_dhcp_option_create_options_dict(gboolean static_keys);
|
||||
|
||||
#endif /* __NM_DHCP_OPTIONS_H__ */
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ lease_to_ip6_config(NMDhcpSystemd *self, sd_dhcp6_lease *lease, gint32 ts, GErro
|
|||
|
||||
l3cd = nm_dhcp_client_create_l3cd(NM_DHCP_CLIENT(self));
|
||||
|
||||
options = nm_dhcp_option_create_options_dict();
|
||||
options = nm_dhcp_client_create_options_dict(NM_DHCP_CLIENT(self), TRUE);
|
||||
|
||||
if (!nm_dhcp_client_get_config(NM_DHCP_CLIENT(self))->v6.info_only) {
|
||||
gboolean has_any_addresses = FALSE;
|
||||
|
|
@ -271,7 +271,7 @@ ip6_start(NMDhcpClient *client, const struct in6_addr *ll_addr, GError **error)
|
|||
|
||||
/* TODO: honor nm_dhcp_client_get_anycast_address() */
|
||||
|
||||
duid = nm_dhcp_client_get_effective_client_id(client);
|
||||
duid = client_config->client_id;
|
||||
if (!duid || !(duid_arr = g_bytes_get_data(duid, &duid_len)) || duid_len < 2) {
|
||||
nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "missing DUID");
|
||||
g_return_val_if_reached(FALSE);
|
||||
|
|
@ -379,6 +379,8 @@ ip6_start(NMDhcpClient *client, const struct in6_addr *ll_addr, GError **error)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
nm_dhcp_client_set_effective_client_id(client, duid);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -895,122 +895,175 @@ test_read_commented_duid_from_leasefile(void)
|
|||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
_save_duid(const char *path, const guint8 *duid_bin, gsize duid_len)
|
||||
_check_duid_impl(const guint8 *duid_bin,
|
||||
gsize duid_len,
|
||||
gboolean enforce_duid,
|
||||
const char *old_content,
|
||||
const char *new_content)
|
||||
{
|
||||
gs_unref_bytes GBytes *duid = NULL;
|
||||
GError *error = NULL;
|
||||
gs_free_error GError *error = NULL;
|
||||
gs_free char *contents = NULL;
|
||||
gboolean success;
|
||||
const char *path = NM_BUILD_SRCDIR "/src/core/dhcp/tests/check-duid.lease";
|
||||
gs_unref_bytes GBytes *duid = NULL;
|
||||
gsize contents_len;
|
||||
|
||||
g_assert(path);
|
||||
g_assert(duid_bin);
|
||||
g_assert(duid_len > 0);
|
||||
|
||||
duid = g_bytes_new(duid_bin, duid_len);
|
||||
success = nm_dhcp_dhclient_save_duid(path, duid, &error);
|
||||
if (!nm_str_is_empty(old_content) || nmtst_get_rand_bool()) {
|
||||
success = g_file_set_contents(path, old_content ?: "", -1, &error);
|
||||
nmtst_assert_success(success, error);
|
||||
} else
|
||||
nmtst_file_unlink_if_exists(path);
|
||||
|
||||
duid = g_bytes_new(duid_bin, duid_len);
|
||||
|
||||
success = nm_dhcp_dhclient_save_duid(path, duid, enforce_duid, &error);
|
||||
nmtst_assert_success(success, error);
|
||||
|
||||
success = g_file_get_contents(path, &contents, &contents_len, &error);
|
||||
nmtst_assert_success(success, error);
|
||||
g_assert(contents);
|
||||
|
||||
nmtst_file_unlink(path);
|
||||
|
||||
if (!nm_streq0(new_content, contents))
|
||||
g_error("FAILING:\n\nEXPECTED:\n%s\nACTUAL:\n%s\n\n", new_content, contents);
|
||||
|
||||
g_assert_cmpstr(new_content, ==, contents);
|
||||
g_assert_cmpint(contents_len, ==, strlen(contents));
|
||||
}
|
||||
|
||||
#define _DUID(...) ((const guint8[]){__VA_ARGS__})
|
||||
|
||||
#define _check_duid(duid, enforce_duid, old_content, new_content) \
|
||||
_check_duid_impl((duid), sizeof(duid), (enforce_duid), (old_content), (new_content))
|
||||
|
||||
static void
|
||||
test_write_duid(void)
|
||||
{
|
||||
const guint8 duid[] = {000, 001, 000, 001, 027, 'X', 0350, 'X', 0, '#', 025, 010, '~', 0254};
|
||||
const char *expected_contents =
|
||||
"default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n";
|
||||
GError *error = NULL;
|
||||
gs_free char *contents = NULL;
|
||||
gboolean success;
|
||||
const char *path = "test-dhclient-write-duid.leases";
|
||||
_check_duid(_DUID(000, 001, 000, 001, 027, 'X', 0350, 'X', 0, '#', 025, 010, '~', 0254),
|
||||
FALSE,
|
||||
NULL,
|
||||
"default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n");
|
||||
|
||||
_save_duid(path, duid, G_N_ELEMENTS(duid));
|
||||
_check_duid(
|
||||
_DUID(000, 001, 000, 001, 023, 'o', 023, 'n', 000, '"', 0372, 0214, 0326, 0302),
|
||||
FALSE,
|
||||
"default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n",
|
||||
"default-duid \"\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302\";\n");
|
||||
|
||||
success = g_file_get_contents(path, &contents, NULL, &error);
|
||||
nmtst_assert_success(success, error);
|
||||
_check_duid(_DUID(000, 001, 000, 001, 023, 'o', 023, 'n', 000, '"', 0372, 0214, 0326, 0302),
|
||||
FALSE,
|
||||
"#default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n",
|
||||
"default-duid "
|
||||
"\"\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302\";\n#default-duid "
|
||||
"\"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n");
|
||||
_check_duid(
|
||||
_DUID(000, 001, 000, 001, 023, 'o', 023, 'n', 000, '"', 0372, 0214, 0326, 0302),
|
||||
FALSE,
|
||||
"### Commented old DUID ###\n#default-duid "
|
||||
"\"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n",
|
||||
"default-duid \"\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302\";\n### "
|
||||
"Commented old DUID ###\n#default-duid "
|
||||
"\"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n");
|
||||
|
||||
unlink(path);
|
||||
_check_duid(
|
||||
_DUID(0xaa, 0xb, 0xcc, 0xd, 0xee, 0xf),
|
||||
FALSE,
|
||||
"default-duid \"\\252\\013\\314\\015\\356\\017\";\nlease6 {\n interface \"eth1\";\n "
|
||||
" ia-na f1:ce:00:01 {\n starts 1671015678;\n renew 60;\n rebind 105;\n "
|
||||
"iaaddr 192:168:121::1:112c {\n starts 1671015678;\n preferred-life 120;\n "
|
||||
" max-life 120;\n }\n }\n option fqdn.encoded true;\n option "
|
||||
"fqdn.server-update true;\n option fqdn.no-client-update false;\n option fqdn.fqdn "
|
||||
"\"dff6de4fcb0f\";\n option fqdn.hostname \"dff6de4fcb0f\";\n option dhcp6.client-id "
|
||||
"aa:b:cc:d:ee:f;\n option dhcp6.server-id 0:1:0:1:2b:2c:4d:1d:0:0:0:0:0:0;\n option "
|
||||
"dhcp6.name-servers 192:168:121:0:ce0f:f1ff:fece:1;\n option dhcp6.fqdn "
|
||||
"1:c:64:66:66:36:64:65:34:66:63:62:30:66;\n option dhcp6.status-code success "
|
||||
"\"success\";\n}\n",
|
||||
"default-duid \"\\252\\013\\314\\015\\356\\017\";\nlease6 {\n interface \"eth1\";\n "
|
||||
" ia-na f1:ce:00:01 {\n starts 1671015678;\n renew 60;\n rebind 105;\n "
|
||||
"iaaddr 192:168:121::1:112c {\n starts 1671015678;\n preferred-life 120;\n "
|
||||
" max-life 120;\n }\n }\n option fqdn.encoded true;\n option "
|
||||
"fqdn.server-update true;\n option fqdn.no-client-update false;\n option fqdn.fqdn "
|
||||
"\"dff6de4fcb0f\";\n option fqdn.hostname \"dff6de4fcb0f\";\n option dhcp6.client-id "
|
||||
"aa:b:cc:d:ee:f;\n option dhcp6.server-id 0:1:0:1:2b:2c:4d:1d:0:0:0:0:0:0;\n option "
|
||||
"dhcp6.name-servers 192:168:121:0:ce0f:f1ff:fece:1;\n option dhcp6.fqdn "
|
||||
"1:c:64:66:66:36:64:65:34:66:63:62:30:66;\n option dhcp6.status-code success "
|
||||
"\"success\";\n}\n");
|
||||
|
||||
g_assert_cmpstr(expected_contents, ==, contents);
|
||||
}
|
||||
_check_duid(
|
||||
_DUID(0xaa, 0xb, 0xcc, 0xd, 0xee, 0xf),
|
||||
FALSE,
|
||||
"default-duid \"\\252\\013\\314\\015\\356\\017\";\nlease6 {\n interface \"eth1\";\n "
|
||||
" ia-na f1:ce:00:01 {\n starts 1671015678;\n renew 60;\n rebind 105;\n "
|
||||
"iaaddr 192:168:121::1:112c {\n starts 1671015678;\n preferred-life 120;\n "
|
||||
" max-life 120;\n }\n }\n option fqdn.encoded true;\n option "
|
||||
"fqdn.server-update true;\n option fqdn.no-client-update false;\n option fqdn.fqdn "
|
||||
"\"dff6de4fcb0f\";\n option fqdn.hostname \"dff6de4fcb0f\";\n option dhcp6.client-id "
|
||||
"aa:b:cc:d:ee:f;\n option dhcp6.server-id 0:1:0:1:2b:2c:4d:1d:0:0:0:0:0:0;\n option "
|
||||
"dhcp6.name-servers 192:168:121:0:ce0f:f1ff:fece:1;\n option dhcp6.fqdn "
|
||||
"1:c:64:66:66:36:64:65:34:66:63:62:30:66;\n option dhcp6.status-code success "
|
||||
"\"success\";\r\n}\n",
|
||||
"default-duid \"\\252\\013\\314\\015\\356\\017\";\nlease6 {\n interface \"eth1\";\n "
|
||||
" ia-na f1:ce:00:01 {\n starts 1671015678;\n renew 60;\n rebind 105;\n "
|
||||
"iaaddr 192:168:121::1:112c {\n starts 1671015678;\n preferred-life 120;\n "
|
||||
" max-life 120;\n }\n }\n option fqdn.encoded true;\n option "
|
||||
"fqdn.server-update true;\n option fqdn.no-client-update false;\n option fqdn.fqdn "
|
||||
"\"dff6de4fcb0f\";\n option fqdn.hostname \"dff6de4fcb0f\";\n option dhcp6.client-id "
|
||||
"aa:b:cc:d:ee:f;\n option dhcp6.server-id 0:1:0:1:2b:2c:4d:1d:0:0:0:0:0:0;\n option "
|
||||
"dhcp6.name-servers 192:168:121:0:ce0f:f1ff:fece:1;\n option dhcp6.fqdn "
|
||||
"1:c:64:66:66:36:64:65:34:66:63:62:30:66;\n option dhcp6.status-code success "
|
||||
"\"success\";\r\n}\n");
|
||||
|
||||
static void
|
||||
test_write_existing_duid(void)
|
||||
{
|
||||
const guint8 duid[] =
|
||||
{000, 001, 000, 001, 023, 'o', 023, 'n', 000, '"', 0372, 0214, 0326, 0302};
|
||||
const char *original_contents =
|
||||
"default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n";
|
||||
const char *expected_contents =
|
||||
"default-duid \"\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302\";\n";
|
||||
GError *error = NULL;
|
||||
gs_free char *contents = NULL;
|
||||
gboolean success;
|
||||
const char *path = "test-dhclient-write-existing-duid.leases";
|
||||
_check_duid(
|
||||
_DUID(0xaa, 0xb, 0xcc, 0xd, 0xee, 0xe),
|
||||
FALSE,
|
||||
"default-duid \"\\252\\013\\314\\015\\356\\017\";\nlease6 {\n interface \"eth1\";\n "
|
||||
" ia-na f1:ce:00:01 {\n starts 1671015678;\n renew 60;\n rebind 105;\n "
|
||||
"iaaddr 192:168:121::1:112c {\n starts 1671015678;\n preferred-life 120;\n "
|
||||
" max-life 120;\n }\n }\n option fqdn.encoded true;\n option "
|
||||
"fqdn.server-update true;\n option fqdn.no-client-update false;\n option fqdn.fqdn "
|
||||
"\"dff6de4fcb0f\";\n option fqdn.hostname \"dff6de4fcb0f\";\n option dhcp6.client-id "
|
||||
"aa:b:cc:d:ee:f;\n option dhcp6.server-id 0:1:0:1:2b:2c:4d:1d:0:0:0:0:0:0;\n option "
|
||||
"dhcp6.name-servers 192:168:121:0:ce0f:f1ff:fece:1;\n option dhcp6.fqdn "
|
||||
"1:c:64:66:66:36:64:65:34:66:63:62:30:66;\n option dhcp6.status-code success "
|
||||
"\"success\";\r\n}\n",
|
||||
"default-duid \"\\252\\013\\314\\015\\356\\016\";\nlease6 {\n interface \"eth1\";\n "
|
||||
" ia-na f1:ce:00:01 {\n starts 1671015678;\n renew 60;\n rebind 105;\n "
|
||||
"iaaddr 192:168:121::1:112c {\n starts 1671015678;\n preferred-life 120;\n "
|
||||
" max-life 120;\n }\n }\n option fqdn.encoded true;\n option "
|
||||
"fqdn.server-update true;\n option fqdn.no-client-update false;\n option fqdn.fqdn "
|
||||
"\"dff6de4fcb0f\";\n option fqdn.hostname \"dff6de4fcb0f\";\n option dhcp6.client-id "
|
||||
"aa:b:cc:d:ee:f;\n option dhcp6.server-id 0:1:0:1:2b:2c:4d:1d:0:0:0:0:0:0;\n option "
|
||||
"dhcp6.name-servers 192:168:121:0:ce0f:f1ff:fece:1;\n option dhcp6.fqdn "
|
||||
"1:c:64:66:66:36:64:65:34:66:63:62:30:66;\n option dhcp6.status-code success "
|
||||
"\"success\";\r\n}\n");
|
||||
|
||||
success = g_file_set_contents(path, original_contents, -1, &error);
|
||||
nmtst_assert_success(success, error);
|
||||
|
||||
/* Save other DUID; should be overwritten */
|
||||
_save_duid(path, duid, G_N_ELEMENTS(duid));
|
||||
|
||||
/* reread original contents */
|
||||
success = g_file_get_contents(path, &contents, NULL, &error);
|
||||
nmtst_assert_success(success, error);
|
||||
|
||||
unlink(path);
|
||||
g_assert_cmpstr(expected_contents, ==, contents);
|
||||
}
|
||||
|
||||
static const guint8 DUID_BIN[] =
|
||||
{000, 001, 000, 001, 023, 'o', 023, 'n', 000, '"', 0372, 0214, 0326, 0302};
|
||||
#define DUID "\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302"
|
||||
|
||||
static void
|
||||
test_write_existing_commented_duid(void)
|
||||
{
|
||||
#define ORIG_CONTENTS "#default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n"
|
||||
const char *expected_contents = "default-duid \"" DUID "\";\n" ORIG_CONTENTS;
|
||||
GError *error = NULL;
|
||||
gs_free char *contents = NULL;
|
||||
gboolean success;
|
||||
const char *path = "test-dhclient-write-existing-commented-duid.leases";
|
||||
|
||||
success = g_file_set_contents(path, ORIG_CONTENTS, -1, &error);
|
||||
nmtst_assert_success(success, error);
|
||||
|
||||
/* Save other DUID; should be saved on top */
|
||||
_save_duid(path, DUID_BIN, G_N_ELEMENTS(DUID_BIN));
|
||||
|
||||
/* reread original contents */
|
||||
success = g_file_get_contents(path, &contents, NULL, &error);
|
||||
nmtst_assert_success(success, error);
|
||||
|
||||
unlink(path);
|
||||
g_assert_cmpstr(expected_contents, ==, contents);
|
||||
#undef ORIG_CONTENTS
|
||||
}
|
||||
|
||||
static void
|
||||
test_write_existing_multiline_duid(void)
|
||||
{
|
||||
#define ORIG_CONTENTS \
|
||||
"### Commented old DUID ###\n" \
|
||||
"#default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n"
|
||||
const char *expected_contents = "default-duid \"" DUID "\";\n" ORIG_CONTENTS;
|
||||
GError *error = NULL;
|
||||
gs_free char *contents = NULL;
|
||||
gboolean success;
|
||||
nmtst_auto_unlinkfile char *path =
|
||||
g_strdup("test-dhclient-write-existing-multiline-duid.leases");
|
||||
|
||||
success = g_file_set_contents(path, ORIG_CONTENTS, -1, &error);
|
||||
nmtst_assert_success(success, error);
|
||||
|
||||
_save_duid(path, DUID_BIN, G_N_ELEMENTS(DUID_BIN));
|
||||
|
||||
success = g_file_get_contents(path, &contents, NULL, &error);
|
||||
nmtst_assert_success(success, error);
|
||||
|
||||
g_assert_cmpstr(expected_contents, ==, contents);
|
||||
#undef ORIG_CONTENTS
|
||||
_check_duid(
|
||||
_DUID(0xaa, 0xb, 0xcc, 0xd, 0xee, 0xe),
|
||||
TRUE,
|
||||
"default-duid \"\\252\\013\\314\\015\\356\\017\";\nlease6 {\n interface \"eth1\";\n "
|
||||
" ia-na f1:ce:00:01 {\n starts 1671015678;\n renew 60;\n rebind 105;\n "
|
||||
"iaaddr 192:168:121::1:112c {\n starts 1671015678;\n preferred-life 120;\n "
|
||||
" max-life 120;\n }\n }\n option fqdn.encoded true;\n option "
|
||||
"fqdn.server-update true;\n option fqdn.no-client-update false;\n option fqdn.fqdn "
|
||||
"\"dff6de4fcb0f\";\n option fqdn.hostname \"dff6de4fcb0f\";\n option dhcp6.client-id "
|
||||
"aa:b:cc:d:ee:f;\n option dhcp6.server-id 0:1:0:1:2b:2c:4d:1d:0:0:0:0:0:0;\n option "
|
||||
"dhcp6.name-servers 192:168:121:0:ce0f:f1ff:fece:1;\n option dhcp6.fqdn "
|
||||
"1:c:64:66:66:36:64:65:34:66:63:62:30:66;\n option dhcp6.status-code success "
|
||||
"\"success\";\n}\n",
|
||||
"default-duid \"\\252\\013\\314\\015\\356\\016\";\nlease6 {\n interface \"eth1\";\n "
|
||||
" ia-na f1:ce:00:01 {\n starts 1671015678;\n renew 60;\n rebind 105;\n "
|
||||
"iaaddr 192:168:121::1:112c {\n starts 1671015678;\n preferred-life 120;\n "
|
||||
" max-life 120;\n }\n }\n option fqdn.encoded true;\n option "
|
||||
"fqdn.server-update true;\n option fqdn.no-client-update false;\n option fqdn.fqdn "
|
||||
"\"dff6de4fcb0f\";\n option fqdn.hostname \"dff6de4fcb0f\";\n option dhcp6.client-id "
|
||||
"aa:b:cc:d:ee:e;\n option dhcp6.server-id 0:1:0:1:2b:2c:4d:1d:0:0:0:0:0:0;\n option "
|
||||
"dhcp6.name-servers 192:168:121:0:ce0f:f1ff:fece:1;\n option dhcp6.fqdn "
|
||||
"1:c:64:66:66:36:64:65:34:66:63:62:30:66;\n option dhcp6.status-code success "
|
||||
"\"success\";\n}\n");
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -1329,12 +1382,7 @@ main(int argc, char **argv)
|
|||
g_test_add_func("/dhcp/dhclient/read_commented_duid_from_leasefile",
|
||||
test_read_commented_duid_from_leasefile);
|
||||
|
||||
g_test_add_func("/dhcp/dhclient/write_duid", test_write_duid);
|
||||
g_test_add_func("/dhcp/dhclient/write_existing_duid", test_write_existing_duid);
|
||||
g_test_add_func("/dhcp/dhclient/write_existing_commented_duid",
|
||||
test_write_existing_commented_duid);
|
||||
g_test_add_func("/dhcp/dhclient/write_existing_multiline_duid",
|
||||
test_write_existing_multiline_duid);
|
||||
g_test_add_func("/dhcp/dhclient/test_write_duid", test_write_duid);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4846,7 +4846,7 @@ nm_utils_memeqzero(gconstpointer data, gsize length)
|
|||
}
|
||||
|
||||
/**
|
||||
* nm_utils_bin2hexstr_full:
|
||||
* nm_utils_bin2hexstr_fuller:
|
||||
* @addr: pointer of @length bytes. If @length is zero, this may
|
||||
* also be %NULL.
|
||||
* @length: number of bytes in @addr. May also be zero, in which
|
||||
|
|
@ -4854,12 +4854,17 @@ nm_utils_memeqzero(gconstpointer data, gsize length)
|
|||
* @delimiter: either '\0', otherwise the output string will have the
|
||||
* given delimiter character between each two hex numbers.
|
||||
* @upper_case: if TRUE, use upper case ASCII characters for hex.
|
||||
* @with_leading_zero: if TRUE, then the hex values from 0 to 0xf
|
||||
* are written as "00" to "0f", respectively. Otherwise, the leading
|
||||
* zero is dropped. With @with_leading_zero set to FALSE, the resulting
|
||||
* string may be shorter than expected. @delimiter must be set
|
||||
* if @with_leading_zero is FALSE.
|
||||
* @out: if %NULL, the function will allocate a new buffer of
|
||||
* either (@length*2+1) or (@length*3) bytes, depending on whether
|
||||
* either (@length*2+1) or MAX(1, (@length*3)) bytes, depending on whether
|
||||
* a @delimiter is specified. In that case, the allocated buffer will
|
||||
* be returned and must be freed by the caller.
|
||||
* If not %NULL, the buffer must already be preallocated and contain
|
||||
* at least (@length*2+1) or (@length*3) bytes, depending on the delimiter.
|
||||
* at least (@length*2+1) or MAX(1, (@length*3)) bytes, depending on the delimiter.
|
||||
* If @length is zero, then of course at least one byte will be allocated
|
||||
* or @out (if given) must contain at least room for the trailing NUL byte.
|
||||
*
|
||||
|
|
@ -4869,37 +4874,43 @@ nm_utils_memeqzero(gconstpointer data, gsize length)
|
|||
* an empty string is returned.
|
||||
*/
|
||||
char *
|
||||
nm_utils_bin2hexstr_full(gconstpointer addr,
|
||||
gsize length,
|
||||
char delimiter,
|
||||
gboolean upper_case,
|
||||
char *out)
|
||||
nm_utils_bin2hexstr_fuller(gconstpointer addr,
|
||||
gsize length,
|
||||
char delimiter,
|
||||
gboolean upper_case,
|
||||
gboolean with_leading_zero,
|
||||
char *out)
|
||||
{
|
||||
const guint8 *in = addr;
|
||||
const char *LOOKUP = upper_case ? "0123456789ABCDEF" : "0123456789abcdef";
|
||||
char *out0;
|
||||
|
||||
if (out)
|
||||
out0 = out;
|
||||
else {
|
||||
out0 = out =
|
||||
g_new(char, length == 0 ? 1u : (delimiter == '\0' ? length * 2u + 1u : length * 3u));
|
||||
}
|
||||
nm_assert(with_leading_zero || delimiter != '\0');
|
||||
|
||||
/* @out must contain at least @length*3 bytes if @delimiter is set,
|
||||
/* @out must contain at least (MAX(1, @length*3)) bytes if @delimiter is set,
|
||||
* otherwise, @length*2+1. */
|
||||
|
||||
if (!out)
|
||||
out = g_new(char, length == 0 ? 1u : (delimiter == '\0' ? length * 2u + 1u : length * 3u));
|
||||
|
||||
out0 = out;
|
||||
|
||||
if (length > 0) {
|
||||
nm_assert(in);
|
||||
for (;;) {
|
||||
const guint8 v = *in++;
|
||||
guint8 v_hi;
|
||||
|
||||
*out++ = LOOKUP[v >> 4];
|
||||
v_hi = (v >> 4);
|
||||
if (v_hi != 0 || with_leading_zero) {
|
||||
nm_assert(v_hi < 16);
|
||||
*out++ = LOOKUP[v_hi];
|
||||
}
|
||||
*out++ = LOOKUP[v & 0x0F];
|
||||
length--;
|
||||
if (!length)
|
||||
if (length == 0)
|
||||
break;
|
||||
if (delimiter)
|
||||
if (delimiter != '\0')
|
||||
*out++ = delimiter;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2842,11 +2842,22 @@ nm_ascii_is_regular(char ch)
|
|||
return ch >= ' ' && ch < 127;
|
||||
}
|
||||
|
||||
char *nm_utils_bin2hexstr_full(gconstpointer addr,
|
||||
gsize length,
|
||||
char delimiter,
|
||||
gboolean upper_case,
|
||||
char *out);
|
||||
char *nm_utils_bin2hexstr_fuller(gconstpointer addr,
|
||||
gsize length,
|
||||
char delimiter,
|
||||
gboolean upper_case,
|
||||
gboolean with_leading_zero,
|
||||
char *out);
|
||||
|
||||
static inline char *
|
||||
nm_utils_bin2hexstr_full(gconstpointer addr,
|
||||
gsize length,
|
||||
char delimiter,
|
||||
gboolean upper_case,
|
||||
char *out)
|
||||
{
|
||||
return nm_utils_bin2hexstr_fuller(addr, length, delimiter, upper_case, TRUE, out);
|
||||
}
|
||||
|
||||
char *_nm_utils_bin2hexstr(gconstpointer src, gsize len, int final_len);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue