diff options
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/devices/nm-device-veth.c | 32 | ||||
| -rw-r--r-- | src/core/devices/nm-device.c | 128 | ||||
| -rw-r--r-- | src/core/devices/nm-device.h | 5 | ||||
| -rw-r--r-- | src/core/dhcp/nm-dhcp-client.c | 117 | ||||
| -rw-r--r-- | src/core/dhcp/nm-dhcp-client.h | 17 | ||||
| -rw-r--r-- | src/core/dhcp/nm-dhcp-dhclient-utils.c | 91 | ||||
| -rw-r--r-- | src/core/dhcp/nm-dhcp-dhclient-utils.h | 5 | ||||
| -rw-r--r-- | src/core/dhcp/nm-dhcp-dhclient.c | 39 | ||||
| -rw-r--r-- | src/core/dhcp/nm-dhcp-nettools.c | 17 | ||||
| -rw-r--r-- | src/core/dhcp/nm-dhcp-options.c | 8 | ||||
| -rw-r--r-- | src/core/dhcp/nm-dhcp-options.h | 9 | ||||
| -rw-r--r-- | src/core/dhcp/nm-dhcp-systemd.c | 6 | ||||
| -rw-r--r-- | src/core/dhcp/tests/test-dhcp-dhclient.c | 248 | ||||
| -rw-r--r-- | src/core/dns/nm-dns-dnsmasq.c | 11 | ||||
| -rw-r--r-- | src/core/dns/nm-dns-dnsmasq.h | 2 | ||||
| -rw-r--r-- | src/core/dns/nm-dns-manager.c | 3 | ||||
| -rw-r--r-- | src/core/ndisc/nm-fake-ndisc.c | 2 | ||||
| -rw-r--r-- | src/core/nm-policy.c | 112 |
18 files changed, 449 insertions, 403 deletions
diff --git a/src/core/devices/nm-device-veth.c b/src/core/devices/nm-device-veth.c index c3482e78..17115d33 100644 --- a/src/core/devices/nm-device-veth.c +++ b/src/core/devices/nm-device-veth.c @@ -81,11 +81,13 @@ create_and_realize(NMDevice *device, const NMPlatformLink **out_plink, GError **error) { - const char *iface = nm_device_get_iface(device); - const char *peer; - NMDevice *peer_device; - NMSettingVeth *s_veth; - int r; + NMPlatform *platform = nm_device_get_platform(device); + const char *iface = nm_device_get_iface(device); + NMSettingVeth *s_veth; + const NMPlatformLink *plink; + const NMPlatformLink *peer_plink; + int peer_ifindex; + int r; s_veth = _nm_connection_get_setting(connection, NM_TYPE_SETTING_VETH); if (!s_veth) { @@ -98,15 +100,23 @@ create_and_realize(NMDevice *device, return FALSE; } - peer = nm_setting_veth_get_peer(s_veth); - peer_device = nm_manager_get_device(NM_MANAGER_GET, peer, NM_DEVICE_TYPE_VETH); - if (peer_device) { - if (nm_device_parent_get_device(peer_device)) - /* The veth device and its peer already exist. No need to create it again. */ + /* For veths, users can define two connection profiles referencing each + * other as 'veth.peer'. Only the first to be activated will actually + * create the veth pair; the other must detect that interfaces already + * exist and proceed. */ + plink = nm_platform_link_get_by_ifname(platform, iface); + if (plink && nm_platform_link_veth_get_properties(platform, plink->ifindex, &peer_ifindex)) { + peer_plink = nm_platform_link_get(platform, peer_ifindex); + if (peer_plink && peer_plink->type == NM_LINK_TYPE_VETH + && nm_streq0(peer_plink->name, nm_setting_veth_get_peer(s_veth))) { return TRUE; + } } - r = nm_platform_link_veth_add(nm_device_get_platform(device), iface, peer, out_plink); + r = nm_platform_link_veth_add(nm_device_get_platform(device), + iface, + nm_setting_veth_get_peer(s_veth), + out_plink); if (r < 0) { g_set_error(error, NM_DEVICE_ERROR, diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index 059e31f2..a723bf7f 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -96,8 +96,6 @@ #define NM_DEVICE_AUTH_RETRIES_INFINITY -2 #define NM_DEVICE_AUTH_RETRIES_DEFAULT 3 -#define AUTOCONNECT_RESET_RETRIES_TIMER 300 - /*****************************************************************************/ typedef void (*ActivationHandleFunc)(NMDevice *self); @@ -763,9 +761,6 @@ typedef struct _NMDevicePrivate { GVariant *ports_variant; /* Array of port devices D-Bus path */ char *prop_ip_iface; /* IP interface D-Bus property */ - - int autoconnect_retries; - gint32 autoconnect_retries_blocked_until; } NMDevicePrivate; G_DEFINE_ABSTRACT_TYPE(NMDevice, nm_device, NM_TYPE_DBUS_OBJECT) @@ -6397,7 +6392,8 @@ carrier_changed(NMDevice *self, gboolean carrier) if (carrier) { /* If needed, also resume IP configuration that is * waiting for carrier. */ - if (priv->state == NM_DEVICE_STATE_IP_CONFIG) + if (priv->state >= NM_DEVICE_STATE_IP_CONFIG + && priv->state <= NM_DEVICE_STATE_ACTIVATED) nm_device_activate_schedule_stage3_ip_config(self, FALSE); return; } @@ -12791,6 +12787,7 @@ reapply_connection(NMDevice *self, NMConnection *con_old, NMConnection *con_new) * the current settings connection * @version_id: either zero, or the current version id for the applied * connection. + * @reapply_flags: the #NMDeviceReapplyFlags. * @audit_args: on return, a string representing the changes * @error: the error if %FALSE is returned * @@ -12800,11 +12797,12 @@ reapply_connection(NMDevice *self, NMConnection *con_old, NMConnection *con_new) * Return: %FALSE if the new configuration can not be reapplied. */ static gboolean -check_and_reapply_connection(NMDevice *self, - NMConnection *connection, - guint64 version_id, - char **audit_args, - GError **error) +check_and_reapply_connection(NMDevice *self, + NMConnection *connection, + guint64 version_id, + NMDeviceReapplyFlags reapply_flags, + char **audit_args, + GError **error) { NMDeviceClass *klass = NM_DEVICE_GET_CLASS(self); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); @@ -12972,7 +12970,12 @@ check_and_reapply_connection(NMDevice *self, reactivate_proxy_config(self); - nm_device_l3cfg_commit(self, NM_L3_CFG_COMMIT_TYPE_REAPPLY, FALSE); + nm_device_l3cfg_commit( + self, + NM_FLAGS_HAS(reapply_flags, NM_DEVICE_REAPPLY_FLAGS_PRESERVE_EXTERNAL_IP) + ? NM_L3_CFG_COMMIT_TYPE_UPDATE + : NM_L3_CFG_COMMIT_TYPE_REAPPLY, + FALSE); } if (priv->state >= NM_DEVICE_STATE_IP_CHECK) @@ -12989,12 +12992,18 @@ nm_device_reapply(NMDevice *self, NMConnection *connection, GError **error) { g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - return check_and_reapply_connection(self, connection, 0, NULL, error); + return check_and_reapply_connection(self, + connection, + 0, + NM_DEVICE_REAPPLY_FLAGS_NONE, + NULL, + error); } typedef struct { - NMConnection *connection; - guint64 version_id; + NMConnection *connection; + guint64 version_id; + NMDeviceReapplyFlags reapply_flags; } ReapplyData; static void @@ -13005,16 +13014,16 @@ reapply_cb(NMDevice *self, gpointer user_data) { ReapplyData *reapply_data = user_data; - guint64 version_id = 0; - gs_unref_object NMConnection *connection = NULL; - GError *local = NULL; - gs_free char *audit_args = NULL; + guint64 version_id; + gs_unref_object NMConnection *connection = NULL; + NMDeviceReapplyFlags reapply_flags; + GError *local = NULL; + gs_free char *audit_args = NULL; - if (reapply_data) { - connection = reapply_data->connection; - version_id = reapply_data->version_id; - g_slice_free(ReapplyData, reapply_data); - } + connection = reapply_data->connection; + version_id = reapply_data->version_id; + reapply_flags = reapply_data->reapply_flags; + nm_g_slice_free(reapply_data); if (error) { nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_REAPPLY, @@ -13034,6 +13043,7 @@ reapply_cb(NMDevice *self, connection ?: nm_device_get_settings_connection_get_connection(self), version_id, + reapply_flags, &audit_args, &local)) { nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_REAPPLY, @@ -13067,12 +13077,12 @@ impl_device_reapply(NMDBusObject *obj, ReapplyData *reapply_data; gs_unref_variant GVariant *settings = NULL; guint64 version_id; - guint32 flags; + guint32 reapply_flags_u; + NMDeviceReapplyFlags reapply_flags; - g_variant_get(parameters, "(@a{sa{sv}}tu)", &settings, &version_id, &flags); + g_variant_get(parameters, "(@a{sa{sv}}tu)", &settings, &version_id, &reapply_flags_u); - /* No flags supported as of now. */ - if (flags != 0) { + if (NM_FLAGS_ANY(reapply_flags_u, ~((guint32) NM_DEVICE_REAPPLY_FLAGS_PRESERVE_EXTERNAL_IP))) { error = g_error_new_literal(NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "Invalid flags specified"); nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_REAPPLY, @@ -13085,6 +13095,9 @@ impl_device_reapply(NMDBusObject *obj, return; } + reapply_flags = reapply_flags_u; + nm_assert(reapply_flags_u == reapply_flags); + if (priv->state < NM_DEVICE_STATE_PREPARE || priv->state > NM_DEVICE_STATE_ACTIVATED) { error = g_error_new_literal(NM_DEVICE_ERROR, NM_DEVICE_ERROR_NOT_ACTIVE, @@ -13122,12 +13135,12 @@ impl_device_reapply(NMDBusObject *obj, nm_connection_clear_secrets(connection); } - if (connection || version_id) { - reapply_data = g_slice_new(ReapplyData); - reapply_data->connection = connection; - reapply_data->version_id = version_id; - } else - reapply_data = NULL; + reapply_data = g_slice_new(ReapplyData); + *reapply_data = (ReapplyData){ + .connection = connection, + .version_id = version_id, + .reapply_flags = reapply_flags, + }; nm_device_auth_request(self, invocation, @@ -13163,7 +13176,7 @@ impl_device_get_applied_connection(NMDBusObject *obj, if (flags != 0) { g_dbus_method_invocation_return_error_literal(invocation, NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, + NM_DEVICE_ERROR_INVALID_ARGUMENT, "Invalid flags specified"); return; } @@ -16881,49 +16894,6 @@ nm_device_get_initial_hw_address(NMDevice *self) return NM_DEVICE_GET_PRIVATE(self)->hw_addr_initial; } -void -nm_device_set_autoconnect_retries(NMDevice *self, int tries) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->autoconnect_retries != tries) { - _LOGT(LOGD_DEVICE, "autoconnect: retries set %d", tries); - priv->autoconnect_retries = tries; - } - - if (tries) - priv->autoconnect_retries_blocked_until = 0; /* we are not blocked anymore */ - else - priv->autoconnect_retries_blocked_until = - nm_utils_get_monotonic_timestamp_sec() + AUTOCONNECT_RESET_RETRIES_TIMER; -} - -int -nm_device_get_autoconnect_retries(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - return priv->autoconnect_retries; -} - -gint32 -nm_device_autoconnect_retries_blocked_until(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - return priv->autoconnect_retries_blocked_until; -} - -void -nm_device_autoconnect_retries_reset(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - /* default value, we will sync. with connection value when needed */ - priv->autoconnect_retries = -2; - priv->autoconnect_retries_blocked_until = 0; -} - /** * nm_device_spec_match_list: * @self: an #NMDevice @@ -17675,8 +17645,6 @@ nm_device_init(NMDevice *self) priv->sys_iface_state_ = NM_DEVICE_SYS_IFACE_STATE_EXTERNAL; priv->promisc_reset = NM_OPTION_BOOL_DEFAULT; - - priv->autoconnect_retries = -2; } static GObject * diff --git a/src/core/devices/nm-device.h b/src/core/devices/nm-device.h index fea46bb7..de850e68 100644 --- a/src/core/devices/nm-device.h +++ b/src/core/devices/nm-device.h @@ -464,11 +464,6 @@ const char *nm_device_get_permanent_hw_address_full(NMDevice *self, gboolean *out_is_fake); const char *nm_device_get_initial_hw_address(NMDevice *dev); -void nm_device_set_autoconnect_retries(NMDevice *self, int tries); -int nm_device_get_autoconnect_retries(NMDevice *self); -gint32 nm_device_autoconnect_retries_blocked_until(NMDevice *self); -void nm_device_autoconnect_retries_reset(NMDevice *self); - NMDhcpConfig *nm_device_get_dhcp_config(NMDevice *dev, int addr_family); NML3Cfg *nm_device_get_l3cfg(NMDevice *self); diff --git a/src/core/dhcp/nm-dhcp-client.c b/src/core/dhcp/nm-dhcp-client.c index 1329b953..805b42d2 100644 --- a/src/core/dhcp/nm-dhcp-client.c +++ b/src/core/dhcp/nm-dhcp-client.c @@ -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) { @@ -1302,8 +1331,7 @@ gboolean nm_dhcp_client_start(NMDhcpClient *self, GError **error) { NMDhcpClientPrivate *priv; - gs_unref_bytes GBytes *own_client_id = NULL; - const NMPlatformIP6Address *addr = NULL; + const NMPlatformIP6Address *addr = NULL; int IS_IPv4; g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); @@ -1317,11 +1345,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 +1472,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 +1522,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 +1541,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 +1669,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 +1960,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, diff --git a/src/core/dhcp/nm-dhcp-client.h b/src/core/dhcp/nm-dhcp-client.h index 51c6bc04..6f403b61 100644 --- a/src/core/dhcp/nm-dhcp-client.h +++ b/src/core/dhcp/nm-dhcp-client.h @@ -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 *****************************************************************************/ diff --git a/src/core/dhcp/nm-dhcp-dhclient-utils.c b/src/core/dhcp/nm-dhcp-dhclient-utils.c index 74e6b905..ea8943fa 100644 --- a/src/core/dhcp/nm-dhcp-dhclient-utils.c +++ b/src/core/dhcp/nm-dhcp-dhclient-utils.c @@ -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; diff --git a/src/core/dhcp/nm-dhcp-dhclient-utils.h b/src/core/dhcp/nm-dhcp-dhclient-utils.h index 0ce7dd90..6187cce0 100644 --- a/src/core/dhcp/nm-dhcp-dhclient-utils.h +++ b/src/core/dhcp/nm-dhcp-dhclient-utils.h @@ -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__ */ diff --git a/src/core/dhcp/nm-dhcp-dhclient.c b/src/core/dhcp/nm-dhcp-dhclient.c index d0cd5ebd..e4f40d7c 100644 --- a/src/core/dhcp/nm-dhcp-dhclient.c +++ b/src/core/dhcp/nm-dhcp-dhclient.c @@ -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 = { diff --git a/src/core/dhcp/nm-dhcp-nettools.c b/src/core/dhcp/nm-dhcp-nettools.c index 05b7b52e..df88362e 100644 --- a/src/core/dhcp/nm-dhcp-nettools.c +++ b/src/core/dhcp/nm-dhcp-nettools.c @@ -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; } diff --git a/src/core/dhcp/nm-dhcp-options.c b/src/core/dhcp/nm-dhcp-options.c index 96fef81a..a5bb06d1 100644 --- a/src/core/dhcp/nm-dhcp-options.c +++ b/src/core/dhcp/nm-dhcp-options.c @@ -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); } diff --git a/src/core/dhcp/nm-dhcp-options.h b/src/core/dhcp/nm-dhcp-options.h index 4c978c4f..fcc6f9cd 100644 --- a/src/core/dhcp/nm-dhcp-options.h +++ b/src/core/dhcp/nm-dhcp-options.h @@ -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__ */ diff --git a/src/core/dhcp/nm-dhcp-systemd.c b/src/core/dhcp/nm-dhcp-systemd.c index 49e21d97..7ce15d30 100644 --- a/src/core/dhcp/nm-dhcp-systemd.c +++ b/src/core/dhcp/nm-dhcp-systemd.c @@ -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; } diff --git a/src/core/dhcp/tests/test-dhcp-dhclient.c b/src/core/dhcp/tests/test-dhcp-dhclient.c index aaa0dbc3..e95f218e 100644 --- a/src/core/dhcp/tests/test-dhcp-dhclient.c +++ b/src/core/dhcp/tests/test-dhcp-dhclient.c @@ -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_BUILDDIR "/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); - nmtst_assert_success(success, error); -} - -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"; + 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); - _save_duid(path, duid, G_N_ELEMENTS(duid)); + duid = g_bytes_new(duid_bin, duid_len); - success = g_file_get_contents(path, &contents, NULL, &error); + success = nm_dhcp_dhclient_save_duid(path, duid, enforce_duid, &error); nmtst_assert_success(success, error); - unlink(path); - - g_assert_cmpstr(expected_contents, ==, contents); -} - -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"; - - success = g_file_set_contents(path, original_contents, -1, &error); + success = g_file_get_contents(path, &contents, &contents_len, &error); nmtst_assert_success(success, error); + g_assert(contents); - /* Save other DUID; should be overwritten */ - _save_duid(path, duid, G_N_ELEMENTS(duid)); + nmtst_file_unlink(path); - /* reread original contents */ - success = g_file_get_contents(path, &contents, NULL, &error); - nmtst_assert_success(success, error); + if (!nm_streq0(new_content, contents)) + g_error("FAILING:\n\nEXPECTED:\n%s\nACTUAL:\n%s\n\n", new_content, contents); - unlink(path); - g_assert_cmpstr(expected_contents, ==, contents); + g_assert_cmpstr(new_content, ==, contents); + g_assert_cmpint(contents_len, ==, strlen(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" +#define _DUID(...) ((const guint8[]){__VA_ARGS__}) -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 -} +#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_existing_multiline_duid(void) +test_write_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)); + _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"); - 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"); - g_assert_cmpstr(expected_contents, ==, contents); -#undef ORIG_CONTENTS + _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"); + + _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"); + + _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"); + + _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"); + + _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(); } diff --git a/src/core/dns/nm-dns-dnsmasq.c b/src/core/dns/nm-dns-dnsmasq.c index 7d0f0490..cc7c03a2 100644 --- a/src/core/dns/nm-dns-dnsmasq.c +++ b/src/core/dns/nm-dns-dnsmasq.c @@ -191,7 +191,8 @@ _gl_pid_kill_external(void) if (!g_file_get_contents(PIDFILE, &contents, NULL, &error)) { if (g_error_matches(error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) do_unlink = FALSE; - _LOGD("spawn: failure to read pidfile %s: %s", PIDFILE, error->message); + else + _LOGD("spawn: failure to read pidfile %s: %s", PIDFILE, error->message); g_clear_error(&error); goto handle_kill; } @@ -667,6 +668,14 @@ _gl_pid_spawn(const char *dm_binary, /*****************************************************************************/ +void +nm_dnsmasq_kill_external(void) +{ + _gl_pid_kill_external(); +} + +/*****************************************************************************/ + typedef struct { GDBusConnection *dbus_connection; diff --git a/src/core/dns/nm-dns-dnsmasq.h b/src/core/dns/nm-dns-dnsmasq.h index 575b0b26..98761d3d 100644 --- a/src/core/dns/nm-dns-dnsmasq.h +++ b/src/core/dns/nm-dns-dnsmasq.h @@ -25,4 +25,6 @@ GType nm_dns_dnsmasq_get_type(void); NMDnsPlugin *nm_dns_dnsmasq_new(void); +void nm_dnsmasq_kill_external(void); + #endif /* __NETWORKMANAGER_DNS_DNSMASQ_H__ */ diff --git a/src/core/dns/nm-dns-manager.c b/src/core/dns/nm-dns-manager.c index a2fead3f..edb8ce0f 100644 --- a/src/core/dns/nm-dns-manager.c +++ b/src/core/dns/nm-dns-manager.c @@ -2513,6 +2513,9 @@ again: self); } + if (!NM_IS_DNS_DNSMASQ(priv->plugin)) + nm_dnsmasq_kill_external(); + _update_pending_maybe_changed(self); g_object_thaw_notify(G_OBJECT(self)); diff --git a/src/core/ndisc/nm-fake-ndisc.c b/src/core/ndisc/nm-fake-ndisc.c index 5aea273e..59bf0c1b 100644 --- a/src/core/ndisc/nm-fake-ndisc.c +++ b/src/core/ndisc/nm-fake-ndisc.c @@ -358,7 +358,7 @@ NMNDisc * nm_fake_ndisc_new(NML3Cfg *l3cfg) { const NMNDiscConfig config = { - .l3cfg = g_object_ref(NM_L3CFG(l3cfg)), + .l3cfg = NM_L3CFG(l3cfg), .ifname = nm_l3cfg_get_ifname(l3cfg, TRUE), .node_type = NM_NDISC_NODE_TYPE_HOST, .stable_type = NM_UTILS_STABLE_TYPE_UUID, diff --git a/src/core/nm-policy.c b/src/core/nm-policy.c index 518fc596..0c07c29e 100644 --- a/src/core/nm-policy.c +++ b/src/core/nm-policy.c @@ -1579,7 +1579,6 @@ nm_policy_unblock_failed_ovs_interfaces(NMPolicy *self) NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE(self); NMSettingsConnection *const *connections = NULL; guint i; - gboolean multiconnect = FALSE; _LOGT(LOGD_DEVICE, "unblocking failed OVS interfaces"); @@ -1587,13 +1586,6 @@ nm_policy_unblock_failed_ovs_interfaces(NMPolicy *self) for (i = 0; connections[i]; i++) { NMSettingsConnection *sett_conn = connections[i]; NMConnection *connection = nm_settings_connection_get_connection(sett_conn); - NMSettingConnection *s_con = nm_connection_get_setting_connection(connection); - - /* Check if any connection is connect multiple */ - if (s_con - && nm_setting_connection_get_multi_connect(s_con) - == NM_CONNECTION_MULTI_CONNECT_MULTIPLE) - multiconnect = TRUE; if (nm_connection_get_setting_ovs_interface(connection)) { nm_settings_connection_autoconnect_retries_reset(sett_conn); @@ -1603,18 +1595,6 @@ nm_policy_unblock_failed_ovs_interfaces(NMPolicy *self) FALSE); } } - - /* There is, at least, one multiconnect connection with an OVS setting. - * Let's check the OVS devices retries */ - if (multiconnect) { - NMDevice *device; - GHashTableIter h_iter; - g_hash_table_iter_init(&h_iter, priv->devices); - while (g_hash_table_iter_next(&h_iter, (gpointer *) &device, NULL)) { - if (nm_device_get_device_type(device) == NM_DEVICE_TYPE_OVS_INTERFACE) - nm_device_autoconnect_retries_reset(device); - } - } } static gboolean @@ -1626,8 +1606,7 @@ reset_autoconnect_all( NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE(self); NMSettingsConnection *const *connections = NULL; guint i; - gboolean changed = FALSE; - gboolean multiconnect = FALSE; + gboolean changed = FALSE; _LOGD(LOGD_DEVICE, "re-enabling autoconnect for all connections%s%s%s", @@ -1638,8 +1617,6 @@ reset_autoconnect_all( connections = nm_settings_get_connections(priv->settings, NULL); for (i = 0; connections[i]; i++) { NMSettingsConnection *sett_conn = connections[i]; - NMSettingConnection *s_con = - nm_connection_get_setting_connection(nm_settings_connection_get_connection(sett_conn)); if (device && !nm_device_check_connection_compatible( @@ -1648,11 +1625,6 @@ reset_autoconnect_all( NULL)) continue; - if (s_con - && nm_setting_connection_get_multi_connect(s_con) - == NM_CONNECTION_MULTI_CONNECT_MULTIPLE) - multiconnect = TRUE; - if (only_no_secrets) { /* we only reset the no-secrets blocked flag. */ if (nm_settings_connection_autoconnect_blocked_reason_set( @@ -1681,20 +1653,6 @@ reset_autoconnect_all( } } } - - /* There is, at least, one multiconnect connection. Let's check the devices retries */ - if (multiconnect) { - NMDevice *device_iter; - GHashTableIter h_iter; - g_hash_table_iter_init(&h_iter, priv->devices); - while (g_hash_table_iter_next(&h_iter, (gpointer *) &device_iter, NULL)) { - if (nm_device_get_autoconnect_retries(device_iter) != -2) { - nm_device_autoconnect_retries_reset(device_iter); - changed = TRUE; - } - } - } - return changed; } @@ -1752,8 +1710,7 @@ reset_connections_retries(gpointer user_data) NMSettingsConnection *const *connections = NULL; guint i; gint32 con_stamp, min_stamp, now; - gboolean changed = FALSE; - gboolean multiconnect = FALSE; + gboolean changed = FALSE; priv->reset_retries_id = 0; @@ -1762,14 +1719,6 @@ reset_connections_retries(gpointer user_data) connections = nm_settings_get_connections(priv->settings, NULL); for (i = 0; connections[i]; i++) { NMSettingsConnection *connection = connections[i]; - NMSettingConnection *s_con = - nm_connection_get_setting_connection(nm_settings_connection_get_connection(connection)); - - /* Check if any connection is connect multiple */ - if (s_con - && nm_setting_connection_get_multi_connect(s_con) - == NM_CONNECTION_MULTI_CONNECT_MULTIPLE) - multiconnect = TRUE; con_stamp = nm_settings_connection_autoconnect_retries_blocked_until(connection); if (con_stamp == 0) @@ -1782,25 +1731,6 @@ reset_connections_retries(gpointer user_data) min_stamp = con_stamp; } - /* There is, at least, one multiconnect connection. Let's check the devices retries */ - if (multiconnect) { - NMDevice *device; - GHashTableIter h_iter; - g_hash_table_iter_init(&h_iter, priv->devices); - while (g_hash_table_iter_next(&h_iter, (gpointer *) &device, NULL)) { - con_stamp = nm_device_autoconnect_retries_blocked_until(device); - - /* default value in device is -2, which means, we do not care */ - if (con_stamp <= 0) - continue; - if (con_stamp <= now) { - nm_device_autoconnect_retries_reset(device); - changed = TRUE; - } else if (min_stamp == 0 || min_stamp > con_stamp) - min_stamp = con_stamp; - } - } - /* Schedule the handler again if there are some stamps left */ if (min_stamp != 0) priv->reset_retries_id = @@ -1814,31 +1744,21 @@ reset_connections_retries(gpointer user_data) } static void -_connection_autoconnect_retries_set(NMPolicy *self, - NMSettingsConnection *connection, - NMDevice *device, - int tries) +_connection_autoconnect_retries_set(NMPolicy *self, NMSettingsConnection *connection, int tries) { - NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE(self); - NMSettingConnection *s_con; - gint32 retry_time; + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE(self); nm_assert(NM_IS_SETTINGS_CONNECTION(connection)); nm_assert(tries >= 0); - s_con = nm_connection_get_setting_connection(nm_settings_connection_get_connection(connection)); - if (s_con - && nm_setting_connection_get_multi_connect(s_con) == NM_CONNECTION_MULTI_CONNECT_MULTIPLE) { - nm_device_set_autoconnect_retries(device, tries); - retry_time = nm_device_autoconnect_retries_blocked_until(device); - } else { - nm_settings_connection_autoconnect_retries_set(connection, tries); - retry_time = nm_settings_connection_autoconnect_retries_blocked_until(connection); - } + nm_settings_connection_autoconnect_retries_set(connection, tries); if (tries == 0) { /* Schedule a handler to reset retries count */ if (!priv->reset_retries_id) { + gint32 retry_time = + nm_settings_connection_autoconnect_retries_blocked_until(connection); + g_warn_if_fail(retry_time != 0); priv->reset_retries_id = g_timeout_add_seconds(MAX(0, retry_time - nm_utils_get_monotonic_timestamp_sec()), @@ -2100,25 +2020,13 @@ device_state_changed(NMDevice *device, } if (!blocked) { - s_con = nm_connection_get_setting_connection( - nm_settings_connection_get_connection(sett_conn)); - if (s_con - && nm_setting_connection_get_multi_connect(s_con) - == NM_CONNECTION_MULTI_CONNECT_MULTIPLE) { - if (nm_device_get_autoconnect_retries(device) == -2) - nm_device_set_autoconnect_retries( - device, - nm_settings_connection_autoconnect_retries_get(sett_conn)); - - tries = nm_device_get_autoconnect_retries(device); - } else - tries = nm_settings_connection_autoconnect_retries_get(sett_conn); + tries = nm_settings_connection_autoconnect_retries_get(sett_conn); if (tries > 0) { _LOGD(LOGD_DEVICE, "connection '%s' failed to autoconnect; %d tries left", nm_settings_connection_get_id(sett_conn), tries - 1); - _connection_autoconnect_retries_set(self, sett_conn, device, tries - 1); + _connection_autoconnect_retries_set(self, sett_conn, tries - 1); } else if (tries != 0) { _LOGD(LOGD_DEVICE, "connection '%s' failed to autoconnect; infinite tries left", |