diff options
Diffstat (limited to 'src/core')
32 files changed, 1085 insertions, 679 deletions
diff --git a/src/core/devices/nm-device-bridge.c b/src/core/devices/nm-device-bridge.c index f11c172a..9bf7ac01 100644 --- a/src/core/devices/nm-device-bridge.c +++ b/src/core/devices/nm-device-bridge.c @@ -994,7 +994,8 @@ enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gbool nm_assert(s_bridge); s_port = nm_connection_get_setting_bridge_port(connection); - bridge_set_vlan_options(device, s_bridge); + if (!nm_device_sys_iface_state_is_external(device)) + bridge_set_vlan_options(device, s_bridge); if (nm_setting_bridge_get_vlan_filtering(s_bridge)) { gs_free const NMPlatformBridgeVlan **plat_vlans = NULL; diff --git a/src/core/devices/nm-device-ppp.c b/src/core/devices/nm-device-ppp.c index 61e32348..6615b65e 100644 --- a/src/core/devices/nm-device-ppp.c +++ b/src/core/devices/nm-device-ppp.c @@ -23,6 +23,13 @@ typedef struct _NMDevicePppPrivate { NMPppMgr *ppp_mgr; + union { + struct { + NML3CfgBlockHandle *l3cfg_block_handle_6; + NML3CfgBlockHandle *l3cfg_block_handle_4; + }; + NML3CfgBlockHandle *l3cfg_block_handle_x[2]; + }; } NMDevicePppPrivate; struct _NMDevicePpp { @@ -69,8 +76,10 @@ _ppp_mgr_stage3_maybe_ready(NMDevicePpp *self) const NMPppMgrIPData *ip_data; ip_data = nm_ppp_mgr_get_ip_data(priv->ppp_mgr, addr_family); - if (ip_data->ip_received) + if (ip_data->ip_received) { + nm_clear_pointer(&priv->l3cfg_block_handle_x[IS_IPv4], nm_l3cfg_unblock_obj_pruning); nm_device_devip_set_state(device, addr_family, NM_DEVICE_IP_STATE_READY, ip_data->l3cd); + } } if (nm_ppp_mgr_get_state(priv->ppp_mgr) >= NM_PPP_MGR_STATE_HAVE_IP_CONFIG) @@ -80,9 +89,10 @@ _ppp_mgr_stage3_maybe_ready(NMDevicePpp *self) static void _ppp_mgr_callback(NMPppMgr *ppp_mgr, const NMPppMgrCallbackData *callback_data, gpointer user_data) { - NMDevicePpp *self = NM_DEVICE_PPP(user_data); - NMDevice *device = NM_DEVICE(self); - NMDeviceState device_state; + NMDevicePpp *self = NM_DEVICE_PPP(user_data); + NMDevice *device = NM_DEVICE(self); + NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE(self); + NMDeviceState device_state; if (callback_data->callback_type != NM_PPP_MGR_CALLBACK_TYPE_STATE_CHANGED) return; @@ -112,6 +122,19 @@ _ppp_mgr_callback(NMPppMgr *ppp_mgr, const NMPppMgrCallbackData *callback_data, return; } + /* pppd also tries to configure addresses by itself through some + * ioctls. If we remove between those calls an address that was added, + * pppd fails and quits. Temporarily block the removal of addresses + * and routes. */ + if (!priv->l3cfg_block_handle_4) { + priv->l3cfg_block_handle_4 = + nm_l3cfg_block_obj_pruning(nm_device_get_l3cfg(device), AF_INET); + } + if (!priv->l3cfg_block_handle_6) { + priv->l3cfg_block_handle_6 = + nm_l3cfg_block_obj_pruning(nm_device_get_l3cfg(device), AF_INET6); + } + if (old_name) nm_manager_remove_device(NM_MANAGER_GET, old_name, NM_DEVICE_TYPE_PPP); @@ -257,7 +280,11 @@ create_and_realize(NMDevice *device, static void deactivate(NMDevice *device) { - NMDevicePpp *self = NM_DEVICE_PPP(device); + NMDevicePpp *self = NM_DEVICE_PPP(device); + NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE(self); + + nm_clear_pointer(&priv->l3cfg_block_handle_4, nm_l3cfg_unblock_obj_pruning); + nm_clear_pointer(&priv->l3cfg_block_handle_6, nm_l3cfg_unblock_obj_pruning); _ppp_mgr_cleanup(self); } diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index 70b52b1a..6b854517 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -1286,7 +1286,7 @@ out_fail: duid, duid_error); - nm_utils_random_bytes(&uuid, sizeof(uuid)); + nm_random_get_bytes(&uuid, sizeof(uuid)); duid_out = nm_utils_generate_duid_uuid(&uuid); } @@ -2022,7 +2022,7 @@ out_fail: fail_reason); client_id_buf = g_malloc(1 + 15); client_id_buf[0] = 0; - nm_utils_random_bytes(&client_id_buf[1], 15); + nm_random_get_bytes(&client_id_buf[1], 15); result = g_bytes_new_take(client_id_buf, 1 + 15); out_good: @@ -4026,7 +4026,6 @@ _set_ifindex(NMDevice *self, int ifindex, gboolean is_ip_ifindex) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); gs_unref_object NML3Cfg *l3cfg_old = NULL; NML3CfgCommitTypeHandle *l3cfg_commit_type_old = NULL; - gboolean l3_changed; int ip_ifindex_new; int *p_ifindex; gboolean l3cfg_was_reset = FALSE; @@ -4067,6 +4066,10 @@ _set_ifindex(NMDevice *self, int ifindex, gboolean is_ip_ifindex) l3cfg_was_reset = TRUE; } } + + if (!priv->l3cfg && l3cfg_old) + _dev_l3_register_l3cds(self, l3cfg_old, FALSE, FALSE); + if (!priv->l3cfg && ip_ifindex_new > 0) { priv->l3cfg_ = nm_netns_l3cfg_acquire(priv->netns, ip_ifindex_new); @@ -4078,6 +4081,7 @@ _set_ifindex(NMDevice *self, int ifindex, gboolean is_ip_ifindex) _dev_l3_cfg_commit_type_reset(self); l3cfg_was_reset = TRUE; } + if (!priv->l3cfg) { _cleanup_ip_pre(self, AF_INET, CLEANUP_TYPE_KEEP, FALSE); _cleanup_ip_pre(self, AF_INET6, CLEANUP_TYPE_KEEP, FALSE); @@ -4118,11 +4122,7 @@ _set_ifindex(NMDevice *self, int ifindex, gboolean is_ip_ifindex) _notify(self, PROP_IP6_CONFIG); } - if (l3cfg_old != priv->l3cfg) { - l3_changed = FALSE; - if (_dev_l3_register_l3cds(self, l3cfg_old, FALSE, FALSE)) - l3_changed = TRUE; - + if (priv->l3cfg && l3cfg_old != priv->l3cfg) { /* Now it gets ugly. We changed the ip-ifindex, which determines the NML3Cfg instance. * But all the NML3ConfigData we currently track are still for the old ifindex. We * need to update them. @@ -4131,12 +4131,10 @@ _set_ifindex(NMDevice *self, int ifindex, gboolean is_ip_ifindex) * associated with one ifindex (and not the ifindex/ip-ifindex split). Or it * is not at all associated with an ifindex, but only a controlling device for * a real NMDevice (that has the ifindex). */ + _dev_l3_update_l3cds_ifindex(self); if (_dev_l3_register_l3cds(self, priv->l3cfg, TRUE, FALSE)) - l3_changed = TRUE; - - if (l3_changed) _dev_l3_cfg_commit(self, TRUE); } @@ -6164,10 +6162,6 @@ carrier_changed(NMDevice *self, gboolean carrier) if (nm_device_is_master(self)) { if (carrier) { - /* Force master to retry getting ip addresses when carrier - * is restored. */ - if (priv->state == NM_DEVICE_STATE_ACTIVATED) - nm_device_update_dynamic_ip_setup(self); /* If needed, also resume IP configuration that is * waiting for carrier. */ if (priv->state == NM_DEVICE_STATE_IP_CONFIG) @@ -6195,12 +6189,6 @@ carrier_changed(NMDevice *self, gboolean carrier) * the device. */ nm_device_emit_recheck_auto_activate(self); - } else if (priv->state == NM_DEVICE_STATE_ACTIVATED) { - /* If the device is active without a carrier (probably because it is - * tagged for carrier ignore) ensure that when the carrier appears we - * renew DHCP leases and such. - */ - nm_device_update_dynamic_ip_setup(self); } } else { if (priv->state == NM_DEVICE_STATE_UNAVAILABLE) { @@ -6588,6 +6576,14 @@ device_link_changed(gpointer user_data) if (priv->state >= NM_DEVICE_STATE_IP_CONFIG && priv->state <= NM_DEVICE_STATE_ACTIVATED && !nm_device_sys_iface_state_is_external(self)) nm_device_l3cfg_commit(self, NM_L3_CFG_COMMIT_TYPE_REAPPLY, FALSE); + + /* If the device is active without a carrier (probably because it is + * tagged for carrier ignore) ensure that when the carrier appears we + * renew DHCP leases and such. + */ + if (priv->state == NM_DEVICE_STATE_ACTIVATED) { + nm_device_update_dynamic_ip_setup(self); + } } if (update_unmanaged_specs) @@ -7861,7 +7857,8 @@ nm_device_slave_notify_release(NMDevice *self, NMDeviceStateReason reason) void nm_device_removed(NMDevice *self, gboolean unconfigure_ip_config) { - NMDevicePrivate *priv; + NMDevicePrivate *priv; + const NML3ConfigData *l3cd_old; g_return_if_fail(NM_IS_DEVICE(self)); @@ -7879,6 +7876,18 @@ nm_device_removed(NMDevice *self, gboolean unconfigure_ip_config) } _dev_l3_register_l3cds(self, priv->l3cfg, FALSE, unconfigure_ip_config); + + /* _dev_l3_register_l3cds() schedules a commit, but if the device has + * commit type NONE, that doesn't emit a l3cd-changed. Do it manually, + * to ensure that entries are removed from the DNS manager. */ + if (priv->l3cfg + && NM_IN_SET(priv->sys_iface_state, + NM_DEVICE_SYS_IFACE_STATE_REMOVED, + NM_DEVICE_SYS_IFACE_STATE_EXTERNAL)) { + l3cd_old = nm_l3cfg_get_combined_l3cd(priv->l3cfg, TRUE); + if (l3cd_old) + g_signal_emit(self, signals[L3CD_CHANGED], 0, l3cd_old, NULL); + } } static gboolean @@ -10117,13 +10126,6 @@ _dev_ipdhcpx_start(NMDevice *self, int addr_family) hwaddr = nmp_link_address_get_as_bytes(&pllink->l_address); - if (!IS_IPv4) { - if (!hwaddr) { - fail_reason = "interface has no MAC address to start DHCPv6"; - goto out_fail; - } - } - request_broadcast = FALSE; if (pllink) { str = nmp_object_link_udev_device_get_property_value(NMP_OBJECT_UP_CAST(pllink), @@ -11393,8 +11395,8 @@ _dev_ipac6_start(NMDevice *self) if (node_type == NM_NDISC_NODE_TYPE_ROUTER) _dev_ipac6_set_state(self, NM_DEVICE_IP_STATE_READY); - else - _dev_ipac6_grace_period_start(self, ra_timeout, TRUE); + + _dev_ipac6_grace_period_start(self, ra_timeout, TRUE); nm_ndisc_start(priv->ipac6_data.ndisc); } @@ -11634,7 +11636,7 @@ activate_stage3_ip_config_for_addr_family(NMDevice *self, int addr_family, const priv->ip_data_x[IS_IPv4].wait_for_ports = FALSE; } - if (klass->ready_for_ip_config && !klass->ready_for_ip_config(self)) + if (klass->ready_for_ip_config && !klass->ready_for_ip_config(self, FALSE)) goto out_devip; if (IS_IPv4) { @@ -11898,7 +11900,7 @@ activate_stage3_ip_config(NMDevice *self) } if (!nm_device_sys_iface_state_is_external(self) - && (!klass->ready_for_ip_config || klass->ready_for_ip_config(self))) { + && (!klass->ready_for_ip_config || klass->ready_for_ip_config(self, TRUE))) { if (priv->ipmanual_data.state_6 == NM_DEVICE_IP_STATE_NONE && !NM_IN_STRSET(ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_DISABLED, @@ -12693,6 +12695,16 @@ check_and_reapply_connection(NMDevice *self, if (nm_g_hash_table_lookup(diffs, NM_SETTING_IP6_CONFIG_SETTING_NAME)) priv->ip_data_6.do_reapply = TRUE; + if (nm_g_hash_table_contains_any( + nm_g_hash_table_lookup(diffs, NM_SETTING_CONNECTION_SETTING_NAME), + NM_SETTING_CONNECTION_LLDP, + NM_SETTING_CONNECTION_MDNS, + NM_SETTING_CONNECTION_LLMNR, + NM_SETTING_CONNECTION_DNS_OVER_TLS)) { + priv->ip_data_4.do_reapply = TRUE; + priv->ip_data_6.do_reapply = TRUE; + } + nm_device_activate_schedule_stage3_ip_config(self, FALSE); _routing_rules_sync(self, NM_TERNARY_TRUE); diff --git a/src/core/devices/nm-device.h b/src/core/devices/nm-device.h index 80def125..d59aecb2 100644 --- a/src/core/devices/nm-device.h +++ b/src/core/devices/nm-device.h @@ -346,7 +346,7 @@ typedef struct _NMDeviceClass { NMActStageReturn (*act_stage1_prepare)(NMDevice *self, NMDeviceStateReason *out_failure_reason); NMActStageReturn (*act_stage2_config)(NMDevice *self, NMDeviceStateReason *out_failure_reason); void (*act_stage3_ip_config)(NMDevice *self, int addr_family); - gboolean (*ready_for_ip_config)(NMDevice *self); + gboolean (*ready_for_ip_config)(NMDevice *self, gboolean is_manual); const char *(*get_ip_method_auto)(NMDevice *self, int addr_family); diff --git a/src/core/devices/ovs/nm-device-ovs-bridge.c b/src/core/devices/ovs/nm-device-ovs-bridge.c index 683ada13..ea77dd18 100644 --- a/src/core/devices/ovs/nm-device-ovs-bridge.c +++ b/src/core/devices/ovs/nm-device-ovs-bridge.c @@ -67,7 +67,7 @@ get_generic_capabilities(NMDevice *device) } static gboolean -ready_for_ip_config(NMDevice *device) +ready_for_ip_config(NMDevice *device, gboolean is_manual) { return FALSE; } diff --git a/src/core/devices/ovs/nm-device-ovs-interface.c b/src/core/devices/ovs/nm-device-ovs-interface.c index 6b9d3d7e..1f531a6f 100644 --- a/src/core/devices/ovs/nm-device-ovs-interface.c +++ b/src/core/devices/ovs/nm-device-ovs-interface.c @@ -198,7 +198,7 @@ set_platform_mtu(NMDevice *device, guint32 mtu) } static gboolean -ready_for_ip_config(NMDevice *device) +ready_for_ip_config(NMDevice *device, gboolean is_manual) { return nm_device_get_ip_ifindex(device) > 0; } diff --git a/src/core/devices/ovs/nm-device-ovs-port.c b/src/core/devices/ovs/nm-device-ovs-port.c index 116f58c4..6ba52f40 100644 --- a/src/core/devices/ovs/nm-device-ovs-port.c +++ b/src/core/devices/ovs/nm-device-ovs-port.c @@ -61,7 +61,7 @@ get_generic_capabilities(NMDevice *device) } static gboolean -ready_for_ip_config(NMDevice *device) +ready_for_ip_config(NMDevice *device, gboolean is_manual) { return FALSE; } diff --git a/src/core/devices/ovs/nm-ovs-factory.c b/src/core/devices/ovs/nm-ovs-factory.c index 3ff0abf8..5aaa5c01 100644 --- a/src/core/devices/ovs/nm-ovs-factory.c +++ b/src/core/devices/ovs/nm-ovs-factory.c @@ -244,7 +244,11 @@ ovsdb_interface_failed(NMOvsdb *ovsdb, TRUE); } - nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_OVSDB_FAILED); + if (nm_device_is_activating(device)) { + nm_device_state_changed(device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_OVSDB_FAILED); + } } static void diff --git a/src/core/devices/wifi/nm-device-wifi.c b/src/core/devices/wifi/nm-device-wifi.c index d83b1f35..04608d14 100644 --- a/src/core/devices/wifi/nm-device-wifi.c +++ b/src/core/devices/wifi/nm-device-wifi.c @@ -86,6 +86,7 @@ typedef struct { GCancellable *scan_request_cancellable; GSource *scan_request_delay_source; + GSource *roam_supplicant_wait_source; NMWifiAP *current_ap; @@ -939,6 +940,7 @@ deactivate(NMDevice *device) int ifindex = nm_device_get_ifindex(device); nm_clear_g_source(&priv->periodic_update_id); + nm_clear_g_source_inst(&priv->roam_supplicant_wait_source); cleanup_association_attempt(self, TRUE); @@ -1076,8 +1078,9 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError * if (s_wsec) { key_mgmt = nm_setting_wireless_security_get_key_mgmt(s_wsec); - if (nm_supplicant_interface_get_capability(priv->sup_iface, NM_SUPPL_CAP_TYPE_WEP) - == NM_TERNARY_FALSE + if (priv->sup_iface + && nm_supplicant_interface_get_capability(priv->sup_iface, NM_SUPPL_CAP_TYPE_WEP) + == NM_TERNARY_FALSE && NM_IN_STRSET(key_mgmt, "ieee8021x", "none")) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, @@ -2511,8 +2514,15 @@ supplicant_iface_state(NMDeviceWifi *self, : "Connected to wireless network", (ssid_str = _nm_utils_ssid_to_string_gbytes(ssid))); nm_device_activate_schedule_stage3_ip_config(device, FALSE); - } else if (devstate == NM_DEVICE_STATE_ACTIVATED) + } else if (devstate == NM_DEVICE_STATE_ACTIVATED) { periodic_update(self); + if (priv->roam_supplicant_wait_source) { + _LOGD(LOGD_WIFI, + "supplicant state settled after roaming, renew dynamic IP configuration"); + nm_clear_g_source_inst(&priv->roam_supplicant_wait_source); + nm_device_update_dynamic_ip_setup(device); + } + } break; case NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED: if ((devstate == NM_DEVICE_STATE_ACTIVATED) || nm_device_is_activating(device)) { @@ -2583,6 +2593,21 @@ supplicant_iface_assoc_cb(NMSupplicantInterface *iface, GError *error, gpointer } } +static gboolean +roam_supplicant_wait_timeout(gpointer user_data) +{ + NMDeviceWifi *self = NM_DEVICE_WIFI(user_data); + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); + + _LOGD(LOGD_WIFI, "timeout waiting for supplicant to settle after roaming"); + + /* Eventually we still want to restart DHCP when the supplicant + * becomes ready */ + nm_clear_g_source_inst(&priv->roam_supplicant_wait_source); + priv->roam_supplicant_wait_source = g_source_ref(nm_g_source_sentinel_get(0)); + return G_SOURCE_CONTINUE; +} + static void supplicant_iface_notify_current_bss(NMSupplicantInterface *iface, GParamSpec *pspec, @@ -2635,7 +2660,19 @@ supplicant_iface_notify_current_bss(NMSupplicantInterface *iface, * Also, some APs (e.g. Cisco) can be configured to drop * all traffic until DHCP completes. To support such * cases, renew the lease when roaming to a new AP. */ - nm_device_update_dynamic_ip_setup(NM_DEVICE(self)); + + if (nm_supplicant_interface_get_state(priv->sup_iface) + == NM_SUPPLICANT_INTERFACE_STATE_COMPLETED) { + nm_device_update_dynamic_ip_setup(NM_DEVICE(self)); + } else { + /* Wait that the authentication to new the AP completes before + * trying to renew, otherwise the DHCP REQUEST could be lost + * and the client will fall back to a DISCOVER, potentially + * getting a different address. */ + nm_clear_g_source_inst(&priv->roam_supplicant_wait_source); + priv->roam_supplicant_wait_source = + nm_g_timeout_add_source(10000, roam_supplicant_wait_timeout, self); + } } set_current_ap(self, new_ap, TRUE); @@ -3742,6 +3779,7 @@ dispose(GObject *object) nm_assert(c_list_is_empty(&priv->scanning_prohibited_lst_head)); nm_clear_g_source(&priv->periodic_update_id); + nm_clear_g_source_inst(&priv->roam_supplicant_wait_source); wifi_secrets_cancel(self); diff --git a/src/core/devices/wifi/nm-iwd-manager.c b/src/core/devices/wifi/nm-iwd-manager.c index 27222aae..2e0d51e5 100644 --- a/src/core/devices/wifi/nm-iwd-manager.c +++ b/src/core/devices/wifi/nm-iwd-manager.c @@ -306,7 +306,7 @@ iwd_agent_export(GDBusConnection *connection, gpointer user_data, char **agent_p unsigned int rnd; guint id; - nm_utils_random_bytes(&rnd, sizeof(rnd)); + nm_random_get_bytes(&rnd, sizeof(rnd)); nm_sprintf_buf(path, "/agent/%u", rnd); diff --git a/src/core/devices/wwan/nm-device-modem.c b/src/core/devices/wwan/nm-device-modem.c index 77ba1b24..e0209aff 100644 --- a/src/core/devices/wwan/nm-device-modem.c +++ b/src/core/devices/wwan/nm-device-modem.c @@ -621,13 +621,13 @@ is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) } static gboolean -ready_for_ip_config(NMDevice *device) +ready_for_ip_config(NMDevice *device, gboolean is_manual) { - /* Tell NMDevice to only run device-specific IP + /* Tell NMDevice to only run manual and device-specific IP * configuration (devip) and skip other methods - * (manual, dhcp, etc). + * (dhcp, link-local, shared, etc). */ - return FALSE; + return is_manual; } /*****************************************************************************/ diff --git a/src/core/devices/wwan/nm-modem-broadband.c b/src/core/devices/wwan/nm-modem-broadband.c index cbf30f56..997fe727 100644 --- a/src/core/devices/wwan/nm-modem-broadband.c +++ b/src/core/devices/wwan/nm-modem-broadband.c @@ -1032,7 +1032,6 @@ stage3_ip_config_start(NMModem *modem, int addr_family, NMModemIPMethod ip_metho l3cd = nm_l3_config_data_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), ifindex, NM_IP_CONFIG_SOURCE_WWAN); - nm_l3_config_data_set_dns_priority(l3cd, AF_INET, 0); address = (NMPlatformIP4Address){ .address = address_network, @@ -1116,11 +1115,9 @@ stage3_ip_config_start(NMModem *modem, int addr_family, NMModemIPMethod ip_metho _LOGI("IPv6 base configuration:"); - l3cd = nm_l3_config_data_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), + l3cd = nm_l3_config_data_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), ifindex, NM_IP_CONFIG_SOURCE_WWAN); - nm_l3_config_data_set_dns_priority(l3cd, AF_INET6, 0); - do_auto = TRUE; address.plen = mm_bearer_ip_config_get_prefix(self->_priv.ipv6_config); diff --git a/src/core/dhcp/nm-dhcp-client.c b/src/core/dhcp/nm-dhcp-client.c index 2bfd7e01..00a2d207 100644 --- a/src/core/dhcp/nm-dhcp-client.c +++ b/src/core/dhcp/nm-dhcp-client.c @@ -32,7 +32,10 @@ /*****************************************************************************/ -enum { SIGNAL_NOTIFY, LAST_SIGNAL }; +enum { + SIGNAL_NOTIFY, + LAST_SIGNAL, +}; static guint signals[LAST_SIGNAL] = {0}; @@ -42,18 +45,30 @@ typedef struct _NMDhcpClientPrivate { NMDhcpClientConfig config; const NML3ConfigData *l3cd; GSource *no_lease_timeout_source; - GSource *ipv6_lladdr_timeout_source; + GSource *watch_source; GBytes *effective_client_id; - pid_t pid; - guint watch_id; - NMDhcpState state; - bool iaid_explicit : 1; - bool is_stopped : 1; + + union { + struct { + struct { + GDBusMethodInvocation *invocation; + } bound; + } v4; + struct { + GSource *lladdr_timeout_source; + GSource *dad_timeout_source; + } v6; + }; + struct { gulong id; bool wait_dhcp_commit : 1; + bool wait_ipv6_dad : 1; bool wait_ll_address : 1; } l3cfg_notify; + + pid_t pid; + bool is_stopped : 1; } NMDhcpClientPrivate; G_DEFINE_ABSTRACT_TYPE(NMDhcpClient, nm_dhcp_client, G_TYPE_OBJECT) @@ -62,6 +77,13 @@ G_DEFINE_ABSTRACT_TYPE(NMDhcpClient, nm_dhcp_client, G_TYPE_OBJECT) /*****************************************************************************/ +static gboolean _dhcp_client_accept(NMDhcpClient *self, const NML3ConfigData *l3cd, GError **error); + +_nm_unused static gboolean _dhcp_client_decline(NMDhcpClient *self, + const NML3ConfigData *l3cd, + const char *error_message, + GError **error); + static void l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcpClient *self); @@ -72,47 +94,76 @@ G_STATIC_ASSERT(!(((pid_t) -1) > 0)); /*****************************************************************************/ -static void -_emit_notify(NMDhcpClient *self, const NMDhcpClientNotifyData *notify_data) +NM_UTILS_LOOKUP_STR_DEFINE(nm_dhcp_client_event_type_to_string, + NMDhcpClientEventType, + NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT(NULL), + NM_UTILS_LOOKUP_STR_ITEM(NM_DHCP_CLIENT_EVENT_TYPE_BOUND, "bound"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DHCP_CLIENT_EVENT_TYPE_EXPIRE, "expire"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DHCP_CLIENT_EVENT_TYPE_EXTENDED, "extended"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DHCP_CLIENT_EVENT_TYPE_FAIL, "fail"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DHCP_CLIENT_EVENT_TYPE_TERMINATED, + "terminated"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DHCP_CLIENT_EVENT_TYPE_TIMEOUT, "timeout"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DHCP_CLIENT_EVENT_TYPE_UNSPECIFIED, + "unspecified"), ); + +/*****************************************************************************/ + +int +nm_dhcp_client_get_addr_family(NMDhcpClient *self) { - g_signal_emit(G_OBJECT(self), signals[SIGNAL_NOTIFY], 0, notify_data); + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + return priv->config.addr_family; } -/*****************************************************************************/ +const char * +nm_dhcp_client_get_iface(NMDhcpClient *self) +{ + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); -static void -connect_l3cfg_notify(NMDhcpClient *self) + return priv->config.iface; +} + +NMDedupMultiIndex * +nm_dhcp_client_get_multi_idx(NMDhcpClient *self) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - gboolean do_connect; - do_connect = priv->l3cfg_notify.wait_dhcp_commit | priv->l3cfg_notify.wait_ll_address; + return nm_l3cfg_get_multi_idx(priv->config.l3cfg); +} - if (!do_connect) { - nm_clear_g_signal_handler(priv->config.l3cfg, &priv->l3cfg_notify.id); - return; - } +int +nm_dhcp_client_get_ifindex(NMDhcpClient *self) +{ + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - if (priv->l3cfg_notify.id == 0) { - priv->l3cfg_notify.id = g_signal_connect(priv->config.l3cfg, - NM_L3CFG_SIGNAL_NOTIFY, - G_CALLBACK(l3_cfg_notify_cb), - self); - } + return nm_l3cfg_get_ifindex(priv->config.l3cfg); } -pid_t -nm_dhcp_client_get_pid(NMDhcpClient *self) +const NMDhcpClientConfig * +nm_dhcp_client_get_config(NMDhcpClient *self) { - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), -1); + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - return NM_DHCP_CLIENT_GET_PRIVATE(self)->pid; + return &priv->config; } +GBytes * +nm_dhcp_client_get_effective_client_id(NMDhcpClient *self) +{ + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + return priv->effective_client_id; +} + +/*****************************************************************************/ + void nm_dhcp_client_set_effective_client_id(NMDhcpClient *self, GBytes *client_id) { - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + gs_free char *tmp_str = NULL; g_return_if_fail(NM_IS_DHCP_CLIENT(self)); g_return_if_fail(!client_id || g_bytes_get_size(client_id) >= 2); @@ -123,72 +174,63 @@ nm_dhcp_client_set_effective_client_id(NMDhcpClient *self, GBytes *client_id) return; g_bytes_unref(priv->effective_client_id); - priv->effective_client_id = client_id; - if (client_id) - g_bytes_ref(client_id); + priv->effective_client_id = nm_g_bytes_ref(client_id); - { - gs_free char *s = NULL; + _LOGT("%s: set %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"); +} - _LOGT("%s: set %s", - priv->config.addr_family == AF_INET6 ? "duid" : "client-id", - priv->effective_client_id - ? (s = nm_dhcp_utils_duid_to_string(priv->effective_client_id)) - : "default"); - } +/*****************************************************************************/ + +static void +_emit_notify(NMDhcpClient *self, const NMDhcpClientNotifyData *notify_data) +{ + g_signal_emit(G_OBJECT(self), signals[SIGNAL_NOTIFY], 0, notify_data); } /*****************************************************************************/ -NM_UTILS_LOOKUP_STR_DEFINE(nm_dhcp_state_to_string, - NMDhcpState, - NM_UTILS_LOOKUP_DEFAULT(NULL), - NM_UTILS_LOOKUP_STR_ITEM(NM_DHCP_STATE_BOUND, "bound"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DHCP_STATE_DONE, "done"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DHCP_STATE_EXPIRE, "expire"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DHCP_STATE_EXTENDED, "extended"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DHCP_STATE_FAIL, "fail"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DHCP_STATE_NOOP, "noop"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DHCP_STATE_TERMINATED, "terminated"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DHCP_STATE_TIMEOUT, "timeout"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DHCP_STATE_UNKNOWN, "unknown"), ); - -static NMDhcpState -reason_to_state(NMDhcpClient *self, const char *iface, const char *reason) +static void +l3_cfg_notify_check_connected(NMDhcpClient *self) { - if (g_ascii_strcasecmp(reason, "bound") == 0 || g_ascii_strcasecmp(reason, "bound6") == 0 - || g_ascii_strcasecmp(reason, "static") == 0) - return NM_DHCP_STATE_BOUND; - else if (g_ascii_strcasecmp(reason, "renew") == 0 || g_ascii_strcasecmp(reason, "renew6") == 0 - || g_ascii_strcasecmp(reason, "reboot") == 0 - || g_ascii_strcasecmp(reason, "rebind") == 0 - || g_ascii_strcasecmp(reason, "rebind6") == 0) - return NM_DHCP_STATE_EXTENDED; - else if (g_ascii_strcasecmp(reason, "timeout") == 0) - return NM_DHCP_STATE_TIMEOUT; - else if (g_ascii_strcasecmp(reason, "nak") == 0 || g_ascii_strcasecmp(reason, "expire") == 0 - || g_ascii_strcasecmp(reason, "expire6") == 0) - return NM_DHCP_STATE_EXPIRE; - else if (g_ascii_strcasecmp(reason, "end") == 0 || g_ascii_strcasecmp(reason, "stop") == 0 - || g_ascii_strcasecmp(reason, "stopped") == 0) - return NM_DHCP_STATE_DONE; - else if (g_ascii_strcasecmp(reason, "fail") == 0 || g_ascii_strcasecmp(reason, "abend") == 0) - return NM_DHCP_STATE_FAIL; - else if (g_ascii_strcasecmp(reason, "preinit") == 0) - return NM_DHCP_STATE_NOOP; - - _LOGD("unmapped DHCP state '%s'", reason); - return NM_DHCP_STATE_UNKNOWN; + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + gboolean do_connect; + + do_connect = priv->l3cfg_notify.wait_dhcp_commit | priv->l3cfg_notify.wait_ll_address + | priv->l3cfg_notify.wait_ipv6_dad; + + if (!do_connect) { + nm_clear_g_signal_handler(priv->config.l3cfg, &priv->l3cfg_notify.id); + return; + } + + if (priv->l3cfg_notify.id == 0) { + priv->l3cfg_notify.id = g_signal_connect(priv->config.l3cfg, + NM_L3CFG_SIGNAL_NOTIFY, + G_CALLBACK(l3_cfg_notify_cb), + self); + } } /*****************************************************************************/ +pid_t +nm_dhcp_client_get_pid(NMDhcpClient *self) +{ + g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), -1); + + return NM_DHCP_CLIENT_GET_PRIVATE(self)->pid; +} + static void watch_cleanup(NMDhcpClient *self) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - nm_clear_g_source(&priv->watch_id); + nm_clear_g_source_inst(&priv->watch_source); } void @@ -225,6 +267,8 @@ stop(NMDhcpClient *self, gboolean release) priv->pid = -1; } +/*****************************************************************************/ + static gboolean _no_lease_timeout(gpointer user_data) { @@ -237,19 +281,12 @@ _no_lease_timeout(gpointer user_data) &((NMDhcpClientNotifyData){ .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_NO_LEASE_TIMEOUT, })); - return G_SOURCE_CONTINUE; -} -const NMDhcpClientConfig * -nm_dhcp_client_get_config(NMDhcpClient *self) -{ - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - return &priv->config; + return G_SOURCE_CONTINUE; } static void -schedule_no_lease_timeout(NMDhcpClient *self) +_no_lease_timeout_schedule(NMDhcpClient *self) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); @@ -267,29 +304,55 @@ schedule_no_lease_timeout(NMDhcpClient *self) } } +/*****************************************************************************/ + void -nm_dhcp_client_set_state(NMDhcpClient *self, NMDhcpState new_state, const NML3ConfigData *l3cd) +_nm_dhcp_client_notify(NMDhcpClient *self, + NMDhcpClientEventType client_event_type, + const NML3ConfigData *l3cd) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); GHashTable *options; const int IS_IPv4 = NM_IS_IPv4(priv->config.addr_family); nm_auto_unref_l3cd const NML3ConfigData *l3cd_merged = NULL; - - g_return_if_fail(NM_IS_DHCP_CLIENT(self)); - - if (NM_IN_SET(new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED)) { - g_return_if_fail(NM_IS_L3_CONFIG_DATA(l3cd)); - g_return_if_fail(nm_l3_config_data_get_dhcp_lease(l3cd, priv->config.addr_family)); - } else - g_return_if_fail(!l3cd); + char sbuf1[NM_HASH_OBFUSCATE_PTR_STR_BUF_SIZE]; + + nm_assert(NM_IN_SET(client_event_type, + NM_DHCP_CLIENT_EVENT_TYPE_UNSPECIFIED, + NM_DHCP_CLIENT_EVENT_TYPE_BOUND, + NM_DHCP_CLIENT_EVENT_TYPE_EXTENDED, + NM_DHCP_CLIENT_EVENT_TYPE_TIMEOUT, + NM_DHCP_CLIENT_EVENT_TYPE_EXPIRE, + NM_DHCP_CLIENT_EVENT_TYPE_FAIL, + NM_DHCP_CLIENT_EVENT_TYPE_TERMINATED)); + nm_assert((client_event_type >= NM_DHCP_CLIENT_EVENT_TYPE_TIMEOUT) + == NM_IN_SET(client_event_type, + NM_DHCP_CLIENT_EVENT_TYPE_TIMEOUT, + NM_DHCP_CLIENT_EVENT_TYPE_EXPIRE, + NM_DHCP_CLIENT_EVENT_TYPE_FAIL, + NM_DHCP_CLIENT_EVENT_TYPE_TERMINATED)); + nm_assert((!!l3cd) + == NM_IN_SET(client_event_type, + NM_DHCP_CLIENT_EVENT_TYPE_BOUND, + NM_DHCP_CLIENT_EVENT_TYPE_EXTENDED)); + + nm_assert(!l3cd || NM_IS_L3_CONFIG_DATA(l3cd)); + nm_assert(!l3cd || nm_l3_config_data_get_dhcp_lease(l3cd, priv->config.addr_family)); + + _LOGT("notify: event=%s%s%s", + nm_dhcp_client_event_type_to_string(client_event_type), + NM_PRINT_FMT_QUOTED2(l3cd, ", l3cd=", NM_HASH_OBFUSCATE_PTR_STR(l3cd, sbuf1), "")); if (l3cd) nm_l3_config_data_seal(l3cd); - if (new_state >= NM_DHCP_STATE_TIMEOUT) + if (client_event_type >= NM_DHCP_CLIENT_EVENT_TYPE_TIMEOUT) watch_cleanup(self); if (!IS_IPv4 && l3cd) { + /* nm_dhcp_utils_merge_new_dhcp6_lease() relies on "life_starts" option + * for merging, which is only set by dhclient. Internal client never sets that, + * but it supports multiple IP addresses per lease. */ if (nm_dhcp_utils_merge_new_dhcp6_lease(priv->l3cd, l3cd, &l3cd_merged)) { l3cd = nm_l3_config_data_seal(l3cd_merged); } @@ -302,11 +365,11 @@ nm_dhcp_client_set_state(NMDhcpClient *self, NMDhcpState new_state, const NML3Co nm_clear_g_source_inst(&priv->no_lease_timeout_source); } else { if (priv->l3cd) - schedule_no_lease_timeout(self); + _no_lease_timeout_schedule(self); } /* FIXME(l3cfg:dhcp): the API of NMDhcpClient is changing to expose a simpler API. - * The internals like NMDhcpState should not be exposed (or possibly dropped in large + * The internals like the state should not be exposed (or possibly dropped in large * parts). */ nm_l3_config_data_reset(&priv->l3cd, l3cd); @@ -353,7 +416,7 @@ nm_dhcp_client_set_state(NMDhcpClient *self, NMDhcpState new_state, const NML3Co * as a configuration parameter (in NMDhcpClientConfig). When ACD is enabled, * when a new lease gets announced, it must first use NML3Cfg to run ACD on the * interface (the previous lease -- if any -- will still be used at that point). - * If ACD fails, we call nm_dhcp_client_decline() and try to get a different + * If ACD fails, we call _dhcp_client_decline() and try to get a different * lease. * If ACD passes, we need to notify the new lease, and the user (NMDevice) may * then configure the address. We need to watch the configured addresses (in NML3Cfg), @@ -367,13 +430,24 @@ nm_dhcp_client_set_state(NMDhcpClient *self, NMDhcpState new_state, const NML3Co * as a static address (bypassing ACD), then NML3Cfg is aware of that and signals * immediate success. */ - if (nm_dhcp_client_can_accept(self) && new_state == NM_DHCP_STATE_BOUND && priv->l3cd + if (client_event_type == NM_DHCP_CLIENT_EVENT_TYPE_BOUND && priv->l3cd && nm_l3_config_data_get_num_addresses(priv->l3cd, priv->config.addr_family) > 0) { priv->l3cfg_notify.wait_dhcp_commit = TRUE; } else { priv->l3cfg_notify.wait_dhcp_commit = FALSE; } - connect_l3cfg_notify(self); + + if (!priv->l3cfg_notify.wait_dhcp_commit && priv->l3cd) { + gs_free_error GError *error = NULL; + + _LOGD("accept lease right away"); + if (!_dhcp_client_accept(self, priv->l3cd, &error)) { + _LOGD("accept failed: %s", error->message); + /* Unclear why this happened, or what to do about it. Just proceed. */ + } + } + + l3_cfg_notify_check_connected(self); { const NMDhcpClientNotifyData notify_data = { @@ -396,14 +470,15 @@ daemon_watch_cb(GPid pid, int status, gpointer user_data) NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); gs_free char *desc = NULL; - g_return_if_fail(priv->watch_id); - priv->watch_id = 0; + g_return_if_fail(priv->watch_source); + + priv->watch_source = NULL; _LOGI("client pid %d %s", pid, (desc = nm_utils_get_process_exit_status_desc(status))); priv->pid = -1; - nm_dhcp_client_set_state(self, NM_DHCP_STATE_TERMINATED, NULL); + _nm_dhcp_client_notify(self, NM_DHCP_CLIENT_EVENT_TYPE_TERMINATED, NULL); } void @@ -414,8 +489,8 @@ nm_dhcp_client_watch_child(NMDhcpClient *self, pid_t pid) g_return_if_fail(priv->pid == -1); priv->pid = pid; - g_return_if_fail(priv->watch_id == 0); - priv->watch_id = g_child_watch_add(pid, daemon_watch_cb, self); + g_return_if_fail(!priv->watch_source); + priv->watch_source = nm_g_child_watch_add_source(pid, daemon_watch_cb, self); } void @@ -429,71 +504,74 @@ nm_dhcp_client_stop_watch_child(NMDhcpClient *self, pid_t pid) watch_cleanup(self); } -gboolean -nm_dhcp_client_start_ip4(NMDhcpClient *self, GError **error) +static gboolean +_accept(NMDhcpClient *self, const NML3ConfigData *l3cd, GError **error) { - NMDhcpClientPrivate *priv; - - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - g_return_val_if_fail(priv->pid == -1, FALSE); - g_return_val_if_fail(priv->config.addr_family == AF_INET, FALSE); - g_return_val_if_fail(priv->config.uuid, FALSE); + if (!NM_IS_IPv4(priv->config.addr_family)) + return TRUE; - schedule_no_lease_timeout(self); + if (!priv->v4.bound.invocation) + return TRUE; - return NM_DHCP_CLIENT_GET_CLASS(self)->ip4_start(self, error); + g_dbus_method_invocation_return_value(g_steal_pointer(&priv->v4.bound.invocation), NULL); + return TRUE; } -gboolean -nm_dhcp_client_accept(NMDhcpClient *self, GError **error) +static gboolean +_dhcp_client_accept(NMDhcpClient *self, const NML3ConfigData *l3cd, GError **error) { - NMDhcpClientPrivate *priv; + NMDhcpClientClass *klass; g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); + nm_assert(l3cd); - priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - g_return_val_if_fail(priv->l3cd, FALSE); + klass = NM_DHCP_CLIENT_GET_CLASS(self); - if (NM_DHCP_CLIENT_GET_CLASS(self)->accept) { - return NM_DHCP_CLIENT_GET_CLASS(self)->accept(self, error); - } + g_return_val_if_fail(NM_DHCP_CLIENT_GET_PRIVATE(self)->l3cd, FALSE); - return TRUE; + return klass->accept(self, l3cd, error); } -gboolean -nm_dhcp_client_can_accept(NMDhcpClient *self) +static gboolean +decline(NMDhcpClient *self, const NML3ConfigData *l3cd, const char *error_message, GError **error) { - gboolean can_accept; - - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - can_accept = !!(NM_DHCP_CLIENT_GET_CLASS(self)->accept); + if (!NM_IS_IPv4(priv->config.addr_family)) + return TRUE; - nm_assert(can_accept == (!!(NM_DHCP_CLIENT_GET_CLASS(self)->decline))); + if (!priv->v4.bound.invocation) { + nm_utils_error_set(error, + NM_UTILS_ERROR_UNKNOWN, + "calling decline in unexpected script state"); + return FALSE; + } - return can_accept; + g_dbus_method_invocation_return_error(g_steal_pointer(&priv->v4.bound.invocation), + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "acd failed"); + return TRUE; } -gboolean -nm_dhcp_client_decline(NMDhcpClient *self, const char *error_message, GError **error) +static gboolean +_dhcp_client_decline(NMDhcpClient *self, + const NML3ConfigData *l3cd, + const char *error_message, + GError **error) { - NMDhcpClientPrivate *priv; + NMDhcpClientClass *klass; g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); + nm_assert(l3cd); - priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - g_return_val_if_fail(priv->l3cd, FALSE); + klass = NM_DHCP_CLIENT_GET_CLASS(self); - if (NM_DHCP_CLIENT_GET_CLASS(self)->decline) { - return NM_DHCP_CLIENT_GET_CLASS(self)->decline(self, error_message, error); - } + g_return_val_if_fail(NM_DHCP_CLIENT_GET_PRIVATE(self)->l3cd, FALSE); - return TRUE; + return klass->decline(self, l3cd, error_message, error); } static GBytes * @@ -508,7 +586,7 @@ ipv6_lladdr_timeout(gpointer user_data) NMDhcpClient *self = user_data; NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - nm_clear_g_source_inst(&priv->ipv6_lladdr_timeout_source); + nm_clear_g_source_inst(&priv->v6.lladdr_timeout_source); _emit_notify( self, @@ -519,6 +597,23 @@ ipv6_lladdr_timeout(gpointer user_data) return G_SOURCE_CONTINUE; } +static gboolean +ipv6_dad_timeout(gpointer user_data) +{ + NMDhcpClient *self = user_data; + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + nm_clear_g_source_inst(&priv->v6.dad_timeout_source); + + _emit_notify( + self, + &((NMDhcpClientNotifyData){ + .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD, + .it_looks_bad.reason = "timeout reached while waiting for IPv6 DAD to complete", + })); + return G_SOURCE_CONTINUE; +} + static const NMPlatformIP6Address * ipv6_lladdr_find(NMDhcpClient *self) { @@ -528,6 +623,8 @@ ipv6_lladdr_find(NMDhcpClient *self) NMDedupMultiIter iter; const NMPObject *obj; + nm_assert(!NM_IS_IPv4(priv->config.addr_family)); + l3cfg = priv->config.l3cfg; nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP6_ADDRESS, nm_l3cfg_get_ifindex(l3cfg)); @@ -544,6 +641,37 @@ ipv6_lladdr_find(NMDhcpClient *self) return NULL; } +static const NMPlatformIP6Address * +ipv6_tentative_addr_find(NMDhcpClient *self) +{ + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + NMDedupMultiIter iter; + const NMPlatformIP6Address *addr; + NML3Cfg *l3cfg = priv->config.l3cfg; + + /* For each address in the lease, check whether it's tentative + * in platform. */ + nm_l3_config_data_iter_ip6_address_for_each (&iter, priv->l3cd, &addr) { + const NMPlatformIP6Address *pladdr; + NMPObject needle; + + nmp_object_stackinit_id_ip6_address(&needle, nm_l3cfg_get_ifindex(l3cfg), &addr->address); + pladdr = NMP_OBJECT_CAST_IP6_ADDRESS(nm_platform_lookup_obj(nm_l3cfg_get_platform(l3cfg), + NMP_CACHE_ID_TYPE_OBJECT_TYPE, + &needle)); + if (!pladdr) { + /* Address was removed from platform */ + continue; + } + + if (NM_FLAGS_HAS(pladdr->n_ifa_flags, IFA_F_TENTATIVE) + && !NM_FLAGS_HAS(pladdr->n_ifa_flags, IFA_F_OPTIMISTIC)) + return pladdr; + } + + return NULL; +} + static void l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcpClient *self) { @@ -551,23 +679,19 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp nm_assert(l3cfg == priv->config.l3cfg); - switch (notify_data->notify_type) { - case NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE: - { + if (notify_data->notify_type == NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE + && priv->l3cfg_notify.wait_ll_address) { const NMPlatformIP6Address *addr; gs_free_error GError *error = NULL; - if (!priv->l3cfg_notify.wait_ll_address) - return; - addr = ipv6_lladdr_find(self); if (addr) { _LOGD("got IPv6LL address, starting transaction"); priv->l3cfg_notify.wait_ll_address = FALSE; - connect_l3cfg_notify(self); - nm_clear_g_source_inst(&priv->ipv6_lladdr_timeout_source); + l3_cfg_notify_check_connected(self); + nm_clear_g_source_inst(&priv->v6.lladdr_timeout_source); - schedule_no_lease_timeout(self); + _no_lease_timeout_schedule(self); if (!NM_DHCP_CLIENT_GET_CLASS(self)->ip6_start(self, &addr->address, &error)) { _emit_notify(self, @@ -577,11 +701,30 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp })); } } + } - break; + if (notify_data->notify_type == NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE + && priv->l3cfg_notify.wait_ipv6_dad) { + const NMPlatformIP6Address *tentative; + + tentative = ipv6_tentative_addr_find(self); + if (!tentative) { + _LOGD("addresses in the lease completed DAD"); + priv->l3cfg_notify.wait_ipv6_dad = FALSE; + nm_clear_g_source_inst(&priv->v6.dad_timeout_source); + l3_cfg_notify_check_connected(self); + _emit_notify( + self, + &((NMDhcpClientNotifyData){.notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE, + .lease_update = { + .l3cd = priv->l3cd, + .accepted = TRUE, + }})); + } } - case NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT: - { + + if (notify_data->notify_type == NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT + && priv->l3cfg_notify.wait_dhcp_commit) { const NML3ConfigData *committed_l3cd; NMDedupMultiIter ipconf_iter; const NMPlatformIPAddress *lease_address; @@ -592,9 +735,6 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp * configured. If the address was added, we can proceed accepting the * lease and notifying NMDevice. */ - if (!priv->l3cfg_notify.wait_dhcp_commit) - return; - nm_l3_config_data_iter_ip_address_for_each (&ipconf_iter, priv->l3cd, priv->config.addr_family, @@ -610,20 +750,35 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp address4->address, address4->plen, address4->peer_address)) - return; + goto wait_dhcp_commit_done; } else { const NMPlatformIP6Address *address6 = (const NMPlatformIP6Address *) lease_address; + const NMPlatformIP6Address *tentative; + char str[NM_UTILS_TO_STRING_BUFFER_SIZE]; if (!nm_l3_config_data_lookup_address_6(committed_l3cd, &address6->address)) - return; + goto wait_dhcp_commit_done; + + tentative = ipv6_tentative_addr_find(self); + if (tentative) { + priv->l3cfg_notify.wait_ipv6_dad = TRUE; + priv->v6.dad_timeout_source = + nm_g_timeout_add_seconds_source(30, ipv6_dad_timeout, self); + _LOGD("wait DAD for address %s", + nm_platform_ip6_address_to_string(tentative, str, sizeof(str))); + } else { + priv->l3cfg_notify.wait_ipv6_dad = FALSE; + nm_clear_g_source_inst(&priv->v6.dad_timeout_source); + } } priv->l3cfg_notify.wait_dhcp_commit = FALSE; - connect_l3cfg_notify(self); - _LOGD("accept address"); + l3_cfg_notify_check_connected(self); - if (!nm_dhcp_client_accept(self, &error)) { + _LOGD("accept lease"); + + if (!_dhcp_client_accept(self, priv->l3cd, &error)) { gs_free char *reason = g_strdup_printf("error accepting lease: %s", error->message); _emit_notify(self, @@ -631,58 +786,67 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD, .it_looks_bad.reason = reason, })); - return; + goto wait_dhcp_commit_done; } - _emit_notify( - self, - &((NMDhcpClientNotifyData){.notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE, - .lease_update = { - .l3cd = priv->l3cd, - .accepted = TRUE, - }})); - break; - }; - default: - /* ignore */; + if (priv->config.addr_family == AF_INET || !priv->l3cfg_notify.wait_ipv6_dad) { + _emit_notify( + self, + &((NMDhcpClientNotifyData){.notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE, + .lease_update = { + .l3cd = priv->l3cd, + .accepted = TRUE, + }})); + } } +wait_dhcp_commit_done:; } gboolean -nm_dhcp_client_start_ip6(NMDhcpClient *self, GError **error) +nm_dhcp_client_start(NMDhcpClient *self, GError **error) { NMDhcpClientPrivate *priv; gs_unref_bytes GBytes *own_client_id = NULL; - const NMPlatformIP6Address *addr; + const NMPlatformIP6Address *addr = NULL; + int IS_IPv4; g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); + priv = NM_DHCP_CLIENT_GET_PRIVATE(self); g_return_val_if_fail(priv->pid == -1, FALSE); - g_return_val_if_fail(priv->config.addr_family == AF_INET6, FALSE); g_return_val_if_fail(priv->config.uuid, FALSE); - g_return_val_if_fail(!priv->effective_client_id, FALSE); + nm_assert(!priv->effective_client_id); - if (!priv->config.v6.enforce_duid) - own_client_id = NM_DHCP_CLIENT_GET_CLASS(self)->get_duid(self); + IS_IPv4 = NM_IS_IPv4(priv->config.addr_family); - nm_dhcp_client_set_effective_client_id(self, own_client_id ?: priv->config.client_id); + if (!IS_IPv4) { + if (!priv->config.v6.enforce_duid) + own_client_id = NM_DHCP_CLIENT_GET_CLASS(self)->get_duid(self); - addr = ipv6_lladdr_find(self); - if (!addr) { - _LOGD("waiting for IPv6LL address"); - priv->l3cfg_notify.wait_ll_address = TRUE; - connect_l3cfg_notify(self); - priv->ipv6_lladdr_timeout_source = - nm_g_timeout_add_seconds_source(10, ipv6_lladdr_timeout, self); - return TRUE; + 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"); + priv->l3cfg_notify.wait_ll_address = TRUE; + l3_cfg_notify_check_connected(self); + priv->v6.lladdr_timeout_source = + nm_g_timeout_add_seconds_source(10, ipv6_lladdr_timeout, self); + return TRUE; + } } - schedule_no_lease_timeout(self); + _no_lease_timeout_schedule(self); + + if (IS_IPv4) + return NM_DHCP_CLIENT_GET_CLASS(self)->ip4_start(self, error); return NM_DHCP_CLIENT_GET_CLASS(self)->ip6_start(self, &addr->address, error); } +/*****************************************************************************/ + void nm_dhcp_client_stop_existing(const char *pid_file, const char *binary_name) { @@ -757,9 +921,17 @@ nm_dhcp_client_stop(NMDhcpClient *self, gboolean release) priv->is_stopped = TRUE; + if (NM_IS_IPv4(priv->config.addr_family) && priv->v4.bound.invocation) { + g_dbus_method_invocation_return_error(g_steal_pointer(&priv->v4.bound.invocation), + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "dhcp stopping"); + } + priv->l3cfg_notify.wait_dhcp_commit = FALSE; priv->l3cfg_notify.wait_ll_address = FALSE; - connect_l3cfg_notify(self); + priv->l3cfg_notify.wait_ipv6_dad = FALSE; + l3_cfg_notify_check_connected(self); /* Kill the DHCP client */ old_pid = priv->pid; @@ -770,7 +942,7 @@ nm_dhcp_client_stop(NMDhcpClient *self, gboolean release) _LOGI("canceled DHCP transaction"); nm_assert(priv->pid == -1); - nm_dhcp_client_set_state(self, NM_DHCP_STATE_TERMINATED, NULL); + _nm_dhcp_client_notify(self, NM_DHCP_CLIENT_EVENT_TYPE_TERMINATED, NULL); } /*****************************************************************************/ @@ -895,16 +1067,17 @@ nm_dhcp_client_emit_ipv6_prefix_delegated(NMDhcpClient *self, const NMPlatformIP } gboolean -nm_dhcp_client_handle_event(gpointer unused, - const char *iface, - int pid, - GVariant *options, - const char *reason, - NMDhcpClient *self) +nm_dhcp_client_handle_event(gpointer unused, + const char *iface, + int pid, + GVariant *options, + const char *reason, + GDBusMethodInvocation *invocation, + NMDhcpClient *self) { NMDhcpClientPrivate *priv; - guint32 new_state; - nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + NMDhcpClientEventType client_event_type; NMPlatformIP6Address prefix = { 0, }; @@ -914,6 +1087,7 @@ nm_dhcp_client_handle_event(gpointer unused, g_return_val_if_fail(pid > 0, FALSE); g_return_val_if_fail(g_variant_is_of_type(options, G_VARIANT_TYPE_VARDICT), FALSE); g_return_val_if_fail(reason != NULL, FALSE); + g_return_val_if_fail(G_IS_DBUS_METHOD_INVOCATION(invocation), FALSE); priv = NM_DHCP_CLIENT_GET_PRIVATE(self); @@ -922,17 +1096,29 @@ nm_dhcp_client_handle_event(gpointer unused, if (priv->pid != pid) return FALSE; - new_state = reason_to_state(self, priv->config.iface, reason); - if (new_state == NM_DHCP_STATE_NOOP) - return TRUE; - - _LOGD("DHCP state '%s' -> '%s' (reason: '%s')", - nm_dhcp_state_to_string(priv->state), - nm_dhcp_state_to_string(new_state), - reason); - priv->state = new_state; + _LOGD("DHCP event (reason: '%s')", reason); + + if (NM_IN_STRSET_ASCII_CASE(reason, "preinit")) + goto out_handled; + + if (NM_IN_STRSET_ASCII_CASE(reason, "bound", "bound6", "static")) + client_event_type = NM_DHCP_CLIENT_EVENT_TYPE_BOUND; + else if (NM_IN_STRSET_ASCII_CASE(reason, "renew", "renew6", "reboot", "rebind", "rebind6")) + client_event_type = NM_DHCP_CLIENT_EVENT_TYPE_EXTENDED; + else if (NM_IN_STRSET_ASCII_CASE(reason, "timeout")) + client_event_type = NM_DHCP_CLIENT_EVENT_TYPE_TIMEOUT; + else if (NM_IN_STRSET_ASCII_CASE(reason, "nak", "expire", "expire6")) + client_event_type = NM_DHCP_CLIENT_EVENT_TYPE_EXPIRE; + else if (NM_IN_STRSET_ASCII_CASE(reason, "end", "stop", "stopped")) + client_event_type = NM_DHCP_CLIENT_EVENT_TYPE_TERMINATED; + else if (NM_IN_STRSET_ASCII_CASE(reason, "fail", "abend")) + client_event_type = NM_DHCP_CLIENT_EVENT_TYPE_FAIL; + else + client_event_type = NM_DHCP_CLIENT_EVENT_TYPE_UNSPECIFIED; - if (NM_IN_SET(new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED)) { + if (NM_IN_SET(client_event_type, + NM_DHCP_CLIENT_EVENT_TYPE_BOUND, + NM_DHCP_CLIENT_EVENT_TYPE_EXTENDED)) { gs_unref_hashtable GHashTable *str_options = NULL; GVariantIter iter; const char *name; @@ -963,8 +1149,7 @@ nm_dhcp_client_handle_event(gpointer unused, str_options, priv->config.v6.info_only); } - } else - g_warn_if_reached(); + } if (l3cd) { nm_l3_config_data_set_dhcp_lease_from_options(l3cd, @@ -978,16 +1163,32 @@ nm_dhcp_client_handle_event(gpointer unused, * of the DHCP client instance. Instead, we just signal the prefix * to the device. */ nm_dhcp_client_emit_ipv6_prefix_delegated(self, &prefix); - return TRUE; + goto out_handled; } - /* Fail if no valid IP config was received */ - if (NM_IN_SET(new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED) && !l3cd) { + if (NM_IN_SET(client_event_type, + NM_DHCP_CLIENT_EVENT_TYPE_BOUND, + NM_DHCP_CLIENT_EVENT_TYPE_EXTENDED) + && !l3cd) { + /* Fail if no valid IP config was received */ _LOGW("client bound but IP config not received"); - new_state = NM_DHCP_STATE_FAIL; + client_event_type = NM_DHCP_CLIENT_EVENT_TYPE_FAIL; } - nm_dhcp_client_set_state(self, new_state, l3cd); + if (priv->v4.bound.invocation) + g_dbus_method_invocation_return_value(g_steal_pointer(&priv->v4.bound.invocation), NULL); + + if (NM_IS_IPv4(priv->config.addr_family) + && NM_IN_SET(client_event_type, + NM_DHCP_CLIENT_EVENT_TYPE_BOUND, + NM_DHCP_CLIENT_EVENT_TYPE_EXTENDED)) + priv->v4.bound.invocation = g_steal_pointer(&invocation); + + _nm_dhcp_client_notify(self, client_event_type, l3cd); + +out_handled: + if (invocation) + g_dbus_method_invocation_return_value(invocation, NULL); return TRUE; } @@ -1023,21 +1224,26 @@ nm_dhcp_client_server_id_is_rejected(NMDhcpClient *self, gconstpointer addr) return FALSE; } +/*****************************************************************************/ + static void config_init(NMDhcpClientConfig *config, const NMDhcpClientConfig *src) { + nm_assert(config); + nm_assert(src); + nm_assert(config != src); + nm_assert_addr_family(src->addr_family); + *config = *src; + /* We must not return before un-aliasing all pointers in @config! */ + g_object_ref(config->l3cfg); - if (config->hwaddr) - g_bytes_ref(config->hwaddr); - if (config->bcast_hwaddr) - g_bytes_ref(config->bcast_hwaddr); - if (config->vendor_class_identifier) - g_bytes_ref(config->vendor_class_identifier); - if (config->client_id) - g_bytes_ref(config->client_id); + nm_g_bytes_ref(config->hwaddr); + nm_g_bytes_ref(config->bcast_hwaddr); + nm_g_bytes_ref(config->vendor_class_identifier); + nm_g_bytes_ref(config->client_id); config->iface = g_strdup(config->iface); config->uuid = g_strdup(config->uuid); @@ -1047,14 +1253,12 @@ config_init(NMDhcpClientConfig *config, const NMDhcpClientConfig *src) config->reject_servers = (const char *const *) nm_strv_dup(config->reject_servers, -1, TRUE); - if (config->addr_family == AF_INET) { + if (NM_IS_IPv4(config->addr_family)) config->v4.last_address = g_strdup(config->v4.last_address); - } else if (config->addr_family == AF_INET6) { + else { config->hwaddr = NULL; config->bcast_hwaddr = NULL; config->use_fqdn = TRUE; - } else { - nm_assert_not_reached(); } if (!config->hostname && config->send_hostname) { @@ -1114,46 +1318,6 @@ config_clear(NMDhcpClientConfig *config) } } -int -nm_dhcp_client_get_addr_family(NMDhcpClient *self) -{ - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - return priv->config.addr_family; -} - -const char * -nm_dhcp_client_get_iface(NMDhcpClient *self) -{ - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - return priv->config.iface; -} - -NMDedupMultiIndex * -nm_dhcp_client_get_multi_idx(NMDhcpClient *self) -{ - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - return nm_l3cfg_get_multi_idx(priv->config.l3cfg); -} - -int -nm_dhcp_client_get_ifindex(NMDhcpClient *self) -{ - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - return nm_l3cfg_get_ifindex(priv->config.l3cfg); -} - -GBytes * -nm_dhcp_client_get_effective_client_id(NMDhcpClient *self) -{ - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - return priv->effective_client_id; -} - /*****************************************************************************/ static void @@ -1165,6 +1329,21 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps case PROP_CONFIG: /* construct-only */ config_init(&priv->config, g_value_get_pointer(value)); + + /* I know, this is technically not necessary. It just feels nicer to + * explicitly initialize the respective union member. */ + if (NM_IS_IPv4(priv->config.addr_family)) { + priv->v4 = (typeof(priv->v4)){ + .bound = + { + .invocation = NULL, + }, + }; + } else { + priv->v6 = (typeof(priv->v6)){ + .lladdr_timeout_source = NULL, + }; + } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); @@ -1196,7 +1375,12 @@ dispose(GObject *object) watch_cleanup(self); nm_clear_g_source_inst(&priv->no_lease_timeout_source); - nm_clear_g_source_inst(&priv->ipv6_lladdr_timeout_source); + + if (!NM_IS_IPv4(priv->config.addr_family)) { + nm_clear_g_source_inst(&priv->v6.lladdr_timeout_source); + nm_clear_g_source_inst(&priv->v6.dad_timeout_source); + } + nm_clear_pointer(&priv->effective_client_id, g_bytes_unref); G_OBJECT_CLASS(nm_dhcp_client_parent_class)->dispose(object); @@ -1223,6 +1407,8 @@ nm_dhcp_client_class_init(NMDhcpClientClass *client_class) object_class->dispose = dispose; object_class->finalize = finalize; object_class->set_property = set_property; + client_class->accept = _accept; + client_class->decline = decline; client_class->stop = stop; client_class->get_duid = get_duid; diff --git a/src/core/dhcp/nm-dhcp-client.h b/src/core/dhcp/nm-dhcp-client.h index 249bd013..e4b99929 100644 --- a/src/core/dhcp/nm-dhcp-client.h +++ b/src/core/dhcp/nm-dhcp-client.h @@ -27,16 +27,16 @@ #define NM_DHCP_CLIENT_NOTIFY "dhcp-notify" typedef enum { - NM_DHCP_STATE_UNKNOWN = 0, - NM_DHCP_STATE_BOUND, /* new lease */ - NM_DHCP_STATE_EXTENDED, /* lease extended */ - NM_DHCP_STATE_TIMEOUT, /* timed out contacting server */ - NM_DHCP_STATE_DONE, /* client reported it's stopping */ - NM_DHCP_STATE_EXPIRE, /* lease expired or NAKed */ - NM_DHCP_STATE_FAIL, /* failed for some reason */ - NM_DHCP_STATE_TERMINATED, /* client is no longer running */ - NM_DHCP_STATE_NOOP, /* state is a non operation for NetworkManager */ -} NMDhcpState; + NM_DHCP_CLIENT_EVENT_TYPE_UNSPECIFIED, + + NM_DHCP_CLIENT_EVENT_TYPE_BOUND, + NM_DHCP_CLIENT_EVENT_TYPE_EXTENDED, + + NM_DHCP_CLIENT_EVENT_TYPE_TIMEOUT, + NM_DHCP_CLIENT_EVENT_TYPE_EXPIRE, + NM_DHCP_CLIENT_EVENT_TYPE_FAIL, + NM_DHCP_CLIENT_EVENT_TYPE_TERMINATED, +} NMDhcpClientEventType; typedef enum _nm_packed { NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE, @@ -82,17 +82,8 @@ typedef struct { }; } NMDhcpClientNotifyData; -const char *nm_dhcp_state_to_string(NMDhcpState state); - -/* FIXME(l3cfg:dhcp:config): nm_dhcp_manager_start_ip[46]() has a gazillion of parameters, - * those get passed on as CONSTRUCT_ONLY properties to the NMDhcpClient. Drop - * all these parameters, and let the caller provide one NMDhcpClientConfig - * instance. There will be only one GObject property (NM_DHCP_CLIENT_CONFIG), - * which is CONSTRUCT_ONLY and takes a (mandatory) G_TYPE_POINTER for the - * configuration. - * - * Since NMDhcpClientConfig has an addr_family, we also don't need separate - * nm_dhcp_manager_start_ip[46]() methods. */ +const char *nm_dhcp_client_event_type_to_string(NMDhcpClientEventType client_event_type); + typedef struct { int addr_family; @@ -156,12 +147,13 @@ typedef struct { union { struct { + /* The address from the previous lease */ + const char *last_address; + /* Set BOOTP broadcast flag in request packets, so that servers * will always broadcast replies. */ bool request_broadcast : 1; - /* The address from the previous lease */ - const char *last_address; } v4; struct { /* If set, the DUID from the connection is used; otherwise @@ -208,9 +200,12 @@ typedef struct { gboolean (*ip4_start)(NMDhcpClient *self, GError **error); - gboolean (*accept)(NMDhcpClient *self, GError **error); + gboolean (*accept)(NMDhcpClient *self, const NML3ConfigData *l3cd, GError **error); - gboolean (*decline)(NMDhcpClient *self, const char *error_message, GError **error); + gboolean (*decline)(NMDhcpClient *self, + const NML3ConfigData *l3cd, + const char *error_message, + GError **error); gboolean (*ip6_start)(NMDhcpClient *self, const struct in6_addr *ll_addr, GError **error); @@ -230,8 +225,7 @@ typedef struct { GType nm_dhcp_client_get_type(void); -gboolean nm_dhcp_client_start_ip4(NMDhcpClient *self, GError **error); -gboolean nm_dhcp_client_start_ip6(NMDhcpClient *self, GError **error); +gboolean nm_dhcp_client_start(NMDhcpClient *self, GError **error); const NMDhcpClientConfig *nm_dhcp_client_get_config(NMDhcpClient *self); @@ -250,11 +244,6 @@ nm_dhcp_client_get_lease(NMDhcpClient *self) return NULL; } -gboolean nm_dhcp_client_accept(NMDhcpClient *self, GError **error); -gboolean nm_dhcp_client_can_accept(NMDhcpClient *self); - -gboolean nm_dhcp_client_decline(NMDhcpClient *self, const char *error_message, GError **error); - void nm_dhcp_client_stop(NMDhcpClient *self, gboolean release); /* Backend helpers for subclasses */ @@ -268,15 +257,17 @@ void nm_dhcp_client_watch_child(NMDhcpClient *self, pid_t pid); void nm_dhcp_client_stop_watch_child(NMDhcpClient *self, pid_t pid); -void -nm_dhcp_client_set_state(NMDhcpClient *self, NMDhcpState new_state, const NML3ConfigData *l3cd); - -gboolean nm_dhcp_client_handle_event(gpointer unused, - const char *iface, - int pid, - GVariant *options, - const char *reason, - NMDhcpClient *self); +void _nm_dhcp_client_notify(NMDhcpClient *self, + NMDhcpClientEventType client_event_type, + const NML3ConfigData *l3cd); + +gboolean nm_dhcp_client_handle_event(gpointer unused, + const char *iface, + int pid, + GVariant *options, + const char *reason, + GDBusMethodInvocation *invocation, + NMDhcpClient *self); void nm_dhcp_client_emit_ipv6_prefix_delegated(NMDhcpClient *self, const NMPlatformIP6Address *prefix); diff --git a/src/core/dhcp/nm-dhcp-helper.c b/src/core/dhcp/nm-dhcp-helper.c index 41862f2b..aab658a2 100644 --- a/src/core/dhcp/nm-dhcp-helper.c +++ b/src/core/dhcp/nm-dhcp-helper.c @@ -100,21 +100,6 @@ next:; return g_variant_ref_sink(g_variant_new("(a{sv})", &builder)); } -static void -kill_pid(void) -{ - const char *pid_str; - pid_t pid = 0; - - pid_str = getenv("pid"); - if (pid_str) - pid = strtol(pid_str, NULL, 10); - if (pid) { - _LOGI("a fatal error occurred, kill dhclient instance with pid %d", pid); - kill(pid, SIGTERM); - } -} - int main(int argc, char *argv[]) { @@ -180,7 +165,7 @@ do_notify: parameters, NULL, G_DBUS_CALL_FLAGS_NONE, - 1000, + 60000, NULL, &error); @@ -236,7 +221,5 @@ do_notify: } out: - if (!success) - kill_pid(); return success ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/core/dhcp/nm-dhcp-listener.c b/src/core/dhcp/nm-dhcp-listener.c index 2c567593..0854c1dc 100644 --- a/src/core/dhcp/nm-dhcp-listener.c +++ b/src/core/dhcp/nm-dhcp-listener.c @@ -128,7 +128,7 @@ get_option(GVariant *options, const char *key) } static void -_method_call_handle(NMDhcpListener *self, GVariant *parameters) +_method_call_handle(NMDhcpListener *self, GDBusMethodInvocation *invocation, GVariant *parameters) { gs_free char *iface = NULL; gs_free char *pid_str = NULL; @@ -142,23 +142,23 @@ _method_call_handle(NMDhcpListener *self, GVariant *parameters) iface = get_option(options, "interface"); if (iface == NULL) { _LOGW("dhcp-event: didn't have associated interface."); - return; + goto out; } pid_str = get_option(options, "pid"); pid = _nm_utils_ascii_str_to_int64(pid_str, 10, 0, G_MAXINT32, -1); if (pid == -1) { _LOGW("dhcp-event: couldn't convert PID '%s' to an integer", pid_str ?: "(null)"); - return; + goto out; } reason = get_option(options, "reason"); if (reason == NULL) { _LOGW("dhcp-event: (pid %d) DHCP event didn't have a reason", pid); - return; + goto out; } - g_signal_emit(self, signals[EVENT], 0, iface, pid, options, reason, &handled); + g_signal_emit(self, signals[EVENT], 0, iface, pid, options, reason, invocation, &handled); if (!handled) { if (g_ascii_strcasecmp(reason, "RELEASE") == 0) { /* Ignore event when the dhcp client gets killed and we receive its last message */ @@ -166,6 +166,10 @@ _method_call_handle(NMDhcpListener *self, GVariant *parameters) } else _LOGW("dhcp-event: (pid %d) unhandled DHCP event for interface %s", pid, iface); } + +out: + if (!handled) + g_dbus_method_invocation_return_value(invocation, NULL); } static void @@ -190,8 +194,7 @@ _method_call(GDBusConnection *connection, return; } - _method_call_handle(self, parameters); - g_dbus_method_invocation_return_value(invocation, NULL); + _method_call_handle(self, invocation, parameters); } static GDBusInterfaceInfo *const interface_info = NM_DEFINE_GDBUS_INTERFACE_INFO( @@ -311,9 +314,10 @@ nm_dhcp_listener_class_init(NMDhcpListenerClass *listener_class) NULL, NULL, G_TYPE_BOOLEAN, /* listeners return TRUE if handled */ - 4, + 5, G_TYPE_STRING, /* iface */ G_TYPE_INT, /* pid */ G_TYPE_VARIANT, /* options */ - G_TYPE_STRING); /* reason */ + G_TYPE_STRING, /* reason */ + G_TYPE_DBUS_METHOD_INVOCATION /* invocation*/); } diff --git a/src/core/dhcp/nm-dhcp-manager.c b/src/core/dhcp/nm-dhcp-manager.c index f353e637..9fea1666 100644 --- a/src/core/dhcp/nm-dhcp-manager.c +++ b/src/core/dhcp/nm-dhcp-manager.c @@ -131,8 +131,7 @@ NMDhcpClient * nm_dhcp_manager_start_client(NMDhcpManager *self, NMDhcpClientConfig *config, GError **error) { NMDhcpManagerPrivate *priv; - gs_unref_object NMDhcpClient *client = NULL; - gboolean success = FALSE; + gs_unref_object NMDhcpClient *client = NULL; gsize hwaddr_len; GType gtype; @@ -202,13 +201,7 @@ nm_dhcp_manager_start_client(NMDhcpManager *self, NMDhcpClientConfig *config, GE * default outside of NetworkManager API. */ - if (config->addr_family == AF_INET) { - success = nm_dhcp_client_start_ip4(client, error); - } else { - success = nm_dhcp_client_start_ip6(client, error); - } - - if (!success) + if (!nm_dhcp_client_start(client, error)) return NULL; return g_steal_pointer(&client); diff --git a/src/core/dhcp/nm-dhcp-nettools.c b/src/core/dhcp/nm-dhcp-nettools.c index aac18967..2e41cf15 100644 --- a/src/core/dhcp/nm-dhcp-nettools.c +++ b/src/core/dhcp/nm-dhcp-nettools.c @@ -50,9 +50,14 @@ typedef struct _NMDhcpNettoolsClass NMDhcpNettoolsClass; typedef struct { NDhcp4Client *client; NDhcp4ClientProbe *probe; - NDhcp4ClientLease *lease; - GSource *event_source; - char *lease_file; + + struct { + NDhcp4ClientLease *lease; + const NML3ConfigData *lease_l3cd; + } granted; + + GSource *event_source; + char *lease_file; } NMDhcpNettoolsPrivate; struct _NMDhcpNettools { @@ -778,15 +783,19 @@ lease_save(NMDhcpNettools *self, NDhcp4ClientLease *lease, const char *lease_fil } static void -bound4_handle(NMDhcpNettools *self, NDhcp4ClientLease *lease, gboolean extended) +bound4_handle(NMDhcpNettools *self, guint event, NDhcp4ClientLease *lease) { NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); NMDhcpClient *client = NM_DHCP_CLIENT(self); const NMDhcpClientConfig *client_config; nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; - GError *error = NULL; + gs_free_error GError *error = NULL; + + nm_assert(NM_IN_SET(event, N_DHCP4_CLIENT_EVENT_GRANTED, N_DHCP4_CLIENT_EVENT_EXTENDED)); + nm_assert(lease); + + _LOGT("lease available (%s)", (event == N_DHCP4_CLIENT_EVENT_GRANTED) ? "granted" : "extended"); - _LOGT("lease available (%s)", extended ? "extended" : "new"); client_config = nm_dhcp_client_get_config(client); l3cd = lease_to_ip4_config(nm_dhcp_client_get_multi_idx(client), client_config->iface, @@ -795,29 +804,51 @@ bound4_handle(NMDhcpNettools *self, NDhcp4ClientLease *lease, gboolean extended) &error); if (!l3cd) { _LOGW("failure to parse lease: %s", error->message); - g_clear_error(&error); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL); + + if (event == N_DHCP4_CLIENT_EVENT_GRANTED) + n_dhcp4_client_lease_decline(lease, "invalid lease"); + + _nm_dhcp_client_notify(NM_DHCP_CLIENT(self), NM_DHCP_CLIENT_EVENT_TYPE_FAIL, NULL); return; } - lease_save(self, lease, priv->lease_file); - - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), - extended ? NM_DHCP_STATE_EXTENDED : NM_DHCP_STATE_BOUND, - l3cd); + if (event == N_DHCP4_CLIENT_EVENT_GRANTED) { + priv->granted.lease = n_dhcp4_client_lease_ref(lease); + priv->granted.lease_l3cd = nm_l3_config_data_ref(l3cd); + } else + lease_save(self, lease, priv->lease_file); + + _nm_dhcp_client_notify(NM_DHCP_CLIENT(self), + event == N_DHCP4_CLIENT_EVENT_GRANTED + ? NM_DHCP_CLIENT_EVENT_TYPE_BOUND + : NM_DHCP_CLIENT_EVENT_TYPE_EXTENDED, + l3cd); } static void dhcp4_event_handle(NMDhcpNettools *self, NDhcp4ClientEvent *event) { - NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); - const NMDhcpClientConfig *client_config; - struct in_addr server_id; - char addr_str[INET_ADDRSTRLEN]; - int r; + NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); + struct in_addr server_id; + struct in_addr yiaddr; + char addr_str[INET_ADDRSTRLEN]; + char addr_str2[INET_ADDRSTRLEN]; + int r; - _LOGT("client event %d", event->event); - client_config = nm_dhcp_client_get_config(NM_DHCP_CLIENT(self)); + if (event->event == N_DHCP4_CLIENT_EVENT_LOG) { + _NMLOG(nm_log_level_from_syslog(event->log.level), "event: %s", event->log.message); + return; + } + + if (!NM_IN_SET(event->event, N_DHCP4_CLIENT_EVENT_LOG)) { + /* In almost all events (even those that we don't expect below), we clear + * the currently granted lease. That is, because in GRANTED state we + * expect to follow up with accept/decline, and that only works while + * we are still in the same state. Transitioning away to another state + * (on most events) will invalidate that. */ + nm_clear_pointer(&priv->granted.lease, n_dhcp4_client_lease_unref); + nm_clear_l3cd(&priv->granted.lease_l3cd); + } switch (event->event) { case N_DHCP4_CLIENT_EVENT_OFFER: @@ -827,53 +858,51 @@ dhcp4_event_handle(NMDhcpNettools *self, NDhcp4ClientEvent *event) return; } + n_dhcp4_client_lease_get_yiaddr(event->offer.lease, &yiaddr); + if (yiaddr.s_addr == INADDR_ANY) { + _LOGD("selecting lease failed: no yiaddr address"); + return; + } + if (nm_dhcp_client_server_id_is_rejected(NM_DHCP_CLIENT(self), &server_id)) { _LOGD("server-id %s is in the reject-list, ignoring", nm_utils_inet_ntop(AF_INET, &server_id, addr_str)); return; } + _LOGT("selecting offered lease from %s for %s", + _nm_utils_inet4_ntop(server_id.s_addr, addr_str), + _nm_utils_inet4_ntop(yiaddr.s_addr, addr_str2)); + r = n_dhcp4_client_lease_select(event->offer.lease); if (r) { _LOGW("selecting lease failed: %d", r); return; } - break; + + return; case N_DHCP4_CLIENT_EVENT_RETRACTED: case N_DHCP4_CLIENT_EVENT_EXPIRED: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_EXPIRE, NULL); - break; + _nm_dhcp_client_notify(NM_DHCP_CLIENT(self), NM_DHCP_CLIENT_EVENT_TYPE_EXPIRE, NULL); + return; case N_DHCP4_CLIENT_EVENT_CANCELLED: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL); - break; + _nm_dhcp_client_notify(NM_DHCP_CLIENT(self), NM_DHCP_CLIENT_EVENT_TYPE_FAIL, NULL); + return; case N_DHCP4_CLIENT_EVENT_GRANTED: - priv->lease = n_dhcp4_client_lease_ref(event->granted.lease); - bound4_handle(self, event->granted.lease, FALSE); - break; + bound4_handle(self, event->event, event->granted.lease); + return; case N_DHCP4_CLIENT_EVENT_EXTENDED: - bound4_handle(self, event->extended.lease, TRUE); - break; + bound4_handle(self, event->event, event->extended.lease); + return; case N_DHCP4_CLIENT_EVENT_DOWN: /* ignore down events, they are purely informational */ - break; - case N_DHCP4_CLIENT_EVENT_LOG: - { - NMLogLevel nm_level; - - nm_level = nm_log_level_from_syslog(event->log.level); - if (nm_logging_enabled(nm_level, LOGD_DHCP4)) { - nm_log(nm_level, - LOGD_DHCP4, - NULL, - NULL, - "dhcp4 (%s): %s", - client_config->iface, - event->log.message); - } - } break; + _LOGT("event: down (ignore)"); + return; default: - _LOGW("unhandled DHCP event %d", event->event); - break; + _LOGE("unhandled DHCP event %d", event->event); + nm_assert(event->event != N_DHCP4_CLIENT_EVENT_LOG); + nm_assert_not_reached(); + return; } } @@ -896,7 +925,7 @@ dhcp4_event_cb(int fd, GIOCondition condition, gpointer user_data) */ _LOGE("error %d dispatching events", r); nm_clear_g_source_inst(&priv->event_source); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL); + _nm_dhcp_client_notify(NM_DHCP_CLIENT(self), NM_DHCP_CLIENT_EVENT_TYPE_FAIL, NULL); return G_SOURCE_REMOVE; } @@ -1008,46 +1037,65 @@ nettools_create(NMDhcpNettools *self, GError **error) } static gboolean -_accept(NMDhcpClient *client, GError **error) +_accept(NMDhcpClient *client, const NML3ConfigData *l3cd, GError **error) { NMDhcpNettools *self = NM_DHCP_NETTOOLS(client); NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); int r; - g_return_val_if_fail(priv->lease, FALSE); - _LOGT("accept"); - r = n_dhcp4_client_lease_accept(priv->lease); + g_return_val_if_fail(l3cd, FALSE); + + if (priv->granted.lease_l3cd != l3cd) + return TRUE; + + nm_assert(priv->granted.lease); + + r = n_dhcp4_client_lease_accept(priv->granted.lease); + if (!r) + lease_save(self, priv->granted.lease, priv->lease_file); + + nm_clear_pointer(&priv->granted.lease, n_dhcp4_client_lease_unref); + nm_clear_l3cd(&priv->granted.lease_l3cd); + if (r) { set_error_nettools(error, r, "failed to accept lease"); return FALSE; } - priv->lease = n_dhcp4_client_lease_unref(priv->lease); - return TRUE; } static gboolean -decline(NMDhcpClient *client, const char *error_message, GError **error) +decline(NMDhcpClient *client, const NML3ConfigData *l3cd, const char *error_message, GError **error) { NMDhcpNettools *self = NM_DHCP_NETTOOLS(client); NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); int r; + nm_auto(n_dhcp4_client_lease_unrefp) NDhcp4ClientLease *lease = NULL; - g_return_val_if_fail(priv->lease, FALSE); + _LOGT("decline (%s)", error_message); - _LOGT("dhcp4-client: decline (%s)", error_message); + g_return_val_if_fail(l3cd, FALSE); + + if (priv->granted.lease_l3cd != l3cd) { + nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "calling decline in unexpected state"); + return FALSE; + } + + nm_assert(priv->granted.lease); + + lease = g_steal_pointer(&priv->granted.lease); + nm_clear_l3cd(&priv->granted.lease_l3cd); + + r = n_dhcp4_client_lease_decline(lease, error_message); - r = n_dhcp4_client_lease_decline(priv->lease, error_message); if (r) { set_error_nettools(error, r, "failed to decline lease"); return FALSE; } - priv->lease = n_dhcp4_client_lease_unref(priv->lease); - return TRUE; } @@ -1256,7 +1304,8 @@ dispose(GObject *object) nm_clear_g_free(&priv->lease_file); nm_clear_g_source_inst(&priv->event_source); - nm_clear_pointer(&priv->lease, n_dhcp4_client_lease_unref); + nm_clear_pointer(&priv->granted.lease, n_dhcp4_client_lease_unref); + nm_clear_l3cd(&priv->granted.lease_l3cd); nm_clear_pointer(&priv->probe, n_dhcp4_client_probe_free); nm_clear_pointer(&priv->client, n_dhcp4_client_unref); diff --git a/src/core/dhcp/nm-dhcp-systemd.c b/src/core/dhcp/nm-dhcp-systemd.c index 4a718de9..f2dd1823 100644 --- a/src/core/dhcp/nm-dhcp-systemd.c +++ b/src/core/dhcp/nm-dhcp-systemd.c @@ -459,7 +459,7 @@ bound4_handle(NMDhcpSystemd *self, gboolean extended) if (sd_dhcp_client_get_lease(priv->client4, &lease) < 0 || !lease) { _LOGW("no lease!"); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL); + _nm_dhcp_client_notify(NM_DHCP_CLIENT(self), NM_DHCP_CLIENT_EVENT_TYPE_FAIL, NULL); return; } @@ -473,15 +473,16 @@ bound4_handle(NMDhcpSystemd *self, gboolean extended) if (!l3cd) { _LOGW("%s", error->message); g_clear_error(&error); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL); + _nm_dhcp_client_notify(NM_DHCP_CLIENT(self), NM_DHCP_CLIENT_EVENT_TYPE_FAIL, NULL); return; } dhcp_lease_save(lease, priv->lease_file); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), - extended ? NM_DHCP_STATE_EXTENDED : NM_DHCP_STATE_BOUND, - l3cd); + _nm_dhcp_client_notify(NM_DHCP_CLIENT(self), + extended ? NM_DHCP_CLIENT_EVENT_TYPE_EXTENDED + : NM_DHCP_CLIENT_EVENT_TYPE_BOUND, + l3cd); } static int @@ -500,10 +501,10 @@ dhcp_event_cb(sd_dhcp_client *client, int event, gpointer user_data) switch (event) { case SD_DHCP_CLIENT_EVENT_EXPIRED: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_EXPIRE, NULL); + _nm_dhcp_client_notify(NM_DHCP_CLIENT(user_data), NM_DHCP_CLIENT_EVENT_TYPE_EXPIRE, NULL); break; case SD_DHCP_CLIENT_EVENT_STOP: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_FAIL, NULL); + _nm_dhcp_client_notify(NM_DHCP_CLIENT(user_data), NM_DHCP_CLIENT_EVENT_TYPE_FAIL, NULL); break; case SD_DHCP_CLIENT_EVENT_RENEW: case SD_DHCP_CLIENT_EVENT_IP_CHANGE: @@ -876,7 +877,7 @@ bound6_handle(NMDhcpSystemd *self) if (sd_dhcp6_client_get_lease(priv->client6, &lease) < 0 || !lease) { _LOGW(" no lease!"); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL); + _nm_dhcp_client_notify(NM_DHCP_CLIENT(self), NM_DHCP_CLIENT_EVENT_TYPE_FAIL, NULL); return; } @@ -892,11 +893,11 @@ bound6_handle(NMDhcpSystemd *self) if (!l3cd) { _LOGW("%s", error->message); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL); + _nm_dhcp_client_notify(NM_DHCP_CLIENT(self), NM_DHCP_CLIENT_EVENT_TYPE_FAIL, NULL); return; } - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_BOUND, l3cd); + _nm_dhcp_client_notify(NM_DHCP_CLIENT(self), NM_DHCP_CLIENT_EVENT_TYPE_BOUND, l3cd); sd_dhcp6_lease_reset_pd_prefix_iter(lease); while (!sd_dhcp6_lease_get_pd(lease, @@ -921,11 +922,11 @@ dhcp6_event_cb(sd_dhcp6_client *client, int event, gpointer user_data) switch (event) { case SD_DHCP6_CLIENT_EVENT_RETRANS_MAX: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_TIMEOUT, NULL); + _nm_dhcp_client_notify(NM_DHCP_CLIENT(user_data), NM_DHCP_CLIENT_EVENT_TYPE_TIMEOUT, NULL); break; case SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE: case SD_DHCP6_CLIENT_EVENT_STOP: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_FAIL, NULL); + _nm_dhcp_client_notify(NM_DHCP_CLIENT(user_data), NM_DHCP_CLIENT_EVENT_TYPE_FAIL, NULL); break; case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE: case SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST: diff --git a/src/core/dhcp/nm-dhcp-utils.c b/src/core/dhcp/nm-dhcp-utils.c index 081e2841..88fe83f3 100644 --- a/src/core/dhcp/nm-dhcp-utils.c +++ b/src/core/dhcp/nm-dhcp-utils.c @@ -855,8 +855,7 @@ nm_dhcp_utils_merge_new_dhcp6_lease(const NML3ConfigData *l3cd_old, const char *start; const char *iaid; - nm_assert(out_l3cd_merged); - nm_assert(!*out_l3cd_merged); + nm_assert(out_l3cd_merged && !*out_l3cd_merged); if (!l3cd_old) return FALSE; diff --git a/src/core/nm-core-utils.c b/src/core/nm-core-utils.c index c8b789b3..60c286ee 100644 --- a/src/core/nm-core-utils.c +++ b/src/core/nm-core-utils.c @@ -2815,7 +2815,10 @@ _host_id_read(guint8 **out_host_id, gsize *out_host_id_len) int base64_save = 0; gsize len; - success = nm_utils_random_bytes(rnd_buf, sizeof(rnd_buf)); + if (nm_random_get_crypto_bytes(rnd_buf, sizeof(rnd_buf)) < 0) + nm_random_get_bytes_full(rnd_buf, sizeof(rnd_buf), &success); + else + success = TRUE; /* Our key is really binary data. But since we anyway generate a random seed * (with 32 random bytes), don't write it in binary, but instead create @@ -3313,7 +3316,7 @@ nm_utils_stable_id_random(void) { char buf[15]; - nm_utils_random_bytes(buf, sizeof(buf)); + nm_random_get_bytes(buf, sizeof(buf)); return g_base64_encode((guchar *) buf, sizeof(buf)); } @@ -3684,7 +3687,7 @@ nm_utils_hw_addr_gen_random_eth(const char *current_mac_address, { struct ether_addr bin_addr; - nm_utils_random_bytes(&bin_addr, ETH_ALEN); + nm_random_get_bytes(&bin_addr, ETH_ALEN); _hw_addr_eth_complete(&bin_addr, current_mac_address, generate_mac_address_mask); return nm_utils_hwaddr_ntoa(&bin_addr, ETH_ALEN); } diff --git a/src/core/nm-l3-config-data.c b/src/core/nm-l3-config-data.c index 5ab2f6b8..2a722756 100644 --- a/src/core/nm-l3-config-data.c +++ b/src/core/nm-l3-config-data.c @@ -2275,6 +2275,8 @@ nm_l3_config_data_cmp_full(const NML3ConfigData *a, } if (NM_FLAGS_HAS(flags, NM_L3_CONFIG_CMP_FLAGS_DNS)) { + const NML3ConfigDatFlags FLAG = NM_L3_CONFIG_DAT_FLAGS_HAS_DNS_PRIORITY(IS_IPv4); + NM_CMP_RETURN(_garray_inaddr_cmp(a->nameservers_x[IS_IPv4], b->nameservers_x[IS_IPv4], addr_family)); @@ -2283,7 +2285,8 @@ nm_l3_config_data_cmp_full(const NML3ConfigData *a, NM_CMP_RETURN( nm_strv_ptrarray_cmp(a->dns_options_x[IS_IPv4], b->dns_options_x[IS_IPv4])); - if (NM_FLAGS_ANY(a->flags, NM_L3_CONFIG_DAT_FLAGS_HAS_DNS_PRIORITY(IS_IPv4))) + NM_CMP_DIRECT(NM_FLAGS_ANY(a->flags, FLAG), NM_FLAGS_ANY(b->flags, FLAG)); + if (NM_FLAGS_ANY(a->flags, FLAG)) NM_CMP_DIRECT(a->dns_priority_x[IS_IPv4], b->dns_priority_x[IS_IPv4]); } diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c index 38b9d822..af6099e9 100644 --- a/src/core/nm-l3cfg.c +++ b/src/core/nm-l3cfg.c @@ -208,6 +208,12 @@ typedef struct { gboolean force_commit_once : 1; } L3ConfigData; +struct _NML3CfgBlockHandle { + NML3Cfg *self; + CList lst; + gboolean is_ipv4; +}; + /*****************************************************************************/ NM_GOBJECT_PROPERTIES_DEFINE(NML3Cfg, PROP_NETNS, PROP_IFINDEX, ); @@ -251,6 +257,14 @@ typedef struct _NML3CfgPrivate { union { struct { + CList blocked_lst_head_6; + CList blocked_lst_head_4; + }; + CList blocked_lst_head_x[2]; + }; + + union { + struct { NMIPConfig *ipconfig_6; NMIPConfig *ipconfig_4; }; @@ -4240,20 +4254,29 @@ _l3_commit_one(NML3Cfg *self, g_array_append_val(ipv6_temp_addrs_keep, addr->address); } } - addresses_prune = - nm_platform_ip_address_get_prune_list(self->priv.platform, + + if (c_list_is_empty(&self->priv.p->blocked_lst_head_x[IS_IPv4])) { + addresses_prune = + nm_platform_ip_address_get_prune_list(self->priv.platform, + addr_family, + self->priv.ifindex, + nm_g_array_data(ipv6_temp_addrs_keep), + nm_g_array_len(ipv6_temp_addrs_keep)); + + routes_prune = nm_platform_ip_route_get_prune_list(self->priv.platform, + addr_family, + self->priv.ifindex, + route_table_sync); + _obj_state_zombie_lst_prune_all(self, addr_family); + } + } else { + if (c_list_is_empty(&self->priv.p->blocked_lst_head_x[IS_IPv4])) { + _obj_state_zombie_lst_get_prune_lists(self, addr_family, - self->priv.ifindex, - nm_g_array_data(ipv6_temp_addrs_keep), - nm_g_array_len(ipv6_temp_addrs_keep)); - - routes_prune = nm_platform_ip_route_get_prune_list(self->priv.platform, - addr_family, - self->priv.ifindex, - route_table_sync); - _obj_state_zombie_lst_prune_all(self, addr_family); - } else - _obj_state_zombie_lst_get_prune_lists(self, addr_family, &addresses_prune, &routes_prune); + &addresses_prune, + &routes_prune); + } + } /* FIXME(l3cfg): need to honor and set nm_l3_config_data_get_ndisc_*(). */ /* FIXME(l3cfg): need to honor and set nm_l3_config_data_get_mtu(). */ @@ -4374,6 +4397,48 @@ _l3_commit(NML3Cfg *self, NML3CfgCommitType commit_type, gboolean is_idle) _nm_l3cfg_emit_signal_notify_simple(self, NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT); } +NML3CfgBlockHandle * +nm_l3cfg_block_obj_pruning(NML3Cfg *self, int addr_family) +{ + const int IS_IPv4 = NM_IS_IPv4(addr_family); + NML3CfgBlockHandle *handle; + + if (!self) + return NULL; + + nm_assert(NM_IS_L3CFG(self)); + + handle = g_slice_new(NML3CfgBlockHandle); + handle->self = g_object_ref(self); + handle->is_ipv4 = IS_IPv4; + c_list_link_tail(&self->priv.p->blocked_lst_head_x[IS_IPv4], &handle->lst); + + _LOGT("obj-pruning for IPv%c: blocked (%zu)", + nm_utils_addr_family_to_char(addr_family), + c_list_length(&self->priv.p->blocked_lst_head_x[IS_IPv4])); + + return handle; +} + +void +nm_l3cfg_unblock_obj_pruning(NML3CfgBlockHandle *handle) +{ + gs_unref_object NML3Cfg *self = handle->self; + const int IS_IPv4 = handle->is_ipv4; + + nm_assert(NM_IS_L3CFG(self)); + nm_assert(c_list_is_linked(&handle->lst)); + nm_assert(c_list_contains(&self->priv.p->blocked_lst_head_x[IS_IPv4], &handle->lst)); + + c_list_unlink_stale(&handle->lst); + + _LOGT("obj-pruning for IPv%c: unblocked (%zu)", + IS_IPv4 ? '4' : '6', + c_list_length(&self->priv.p->blocked_lst_head_x[IS_IPv4])); + + nm_g_slice_free(handle); +} + /* See DOC(l3cfg:commit-type) */ void nm_l3cfg_commit(NML3Cfg *self, NML3CfgCommitType commit_type) @@ -4678,6 +4743,8 @@ nm_l3cfg_init(NML3Cfg *self) c_list_init(&self->priv.p->obj_state_lst_head); c_list_init(&self->priv.p->obj_state_temporary_not_available_lst_head); c_list_init(&self->priv.p->obj_state_zombie_lst_head); + c_list_init(&self->priv.p->blocked_lst_head_4); + c_list_init(&self->priv.p->blocked_lst_head_6); self->priv.p->obj_state_hash = g_hash_table_new_full(nmp_object_indirect_id_hash, nmp_object_indirect_id_equal, @@ -4726,6 +4793,8 @@ finalize(GObject *object) nm_assert(!self->priv.p->ipv4ll); nm_assert(c_list_is_empty(&self->priv.p->commit_type_lst_head)); + nm_assert(c_list_is_empty(&self->priv.p->blocked_lst_head_4)); + nm_assert(c_list_is_empty(&self->priv.p->blocked_lst_head_6)); nm_assert(!self->priv.p->commit_on_idle_source); diff --git a/src/core/nm-l3cfg.h b/src/core/nm-l3cfg.h index f6ec39ce..215d21e9 100644 --- a/src/core/nm-l3cfg.h +++ b/src/core/nm-l3cfg.h @@ -455,4 +455,9 @@ struct _NMIPConfig *nm_l3cfg_ipconfig_acquire(NML3Cfg *self, int addr_family); /*****************************************************************************/ +typedef struct _NML3CfgBlockHandle NML3CfgBlockHandle; + +NML3CfgBlockHandle *nm_l3cfg_block_obj_pruning(NML3Cfg *self, int addr_family); +void nm_l3cfg_unblock_obj_pruning(NML3CfgBlockHandle *handle); + #endif /* __NM_L3CFG_H__ */ diff --git a/src/core/nm-policy.c b/src/core/nm-policy.c index 2d47772d..1a824fa4 100644 --- a/src/core/nm-policy.c +++ b/src/core/nm-policy.c @@ -2153,19 +2153,14 @@ device_l3cd_changed(NMDevice *device, nm_dns_manager_begin_updates(priv->dns_manager, __func__); - /* We catch already all the IP events registering on the device state changes but - * the ones where the IP changes with a stable state (i.e., activated): - * ignore IP config changes but when the device is in activated state. - * Prevents unnecessary changes to DNS information. - * FIXME(l3cfg): check why ^^^ this is needed and implement it. Note that - * this function is not always called when the device becomes ACTIVATED. - * Previously, we would also update the DNS manager's IP config in - * device_state_change(ACTIVATED). There we would also special-case - * pseudo-VPNs like wireguard. I don't see the code where this is handled - * now. + /* FIXME(l3cfg): Note that this function is not always called when the + * device becomes ACTIVATED. Previously, we would also update the DNS + * manager's IP config in device_state_change(ACTIVATED). There we would + * also special-case pseudo-VPNs like wireguard. I don't see the code where + * this is handled now. */ state = nm_device_get_state(device); - if (l3cd_new && state > NM_DEVICE_STATE_IP_CONFIG && state < NM_DEVICE_STATE_DEACTIVATING) { + if (l3cd_new && state >= NM_DEVICE_STATE_IP_CONFIG && state < NM_DEVICE_STATE_DEACTIVATING) { nm_dns_manager_set_ip_config(priv->dns_manager, AF_UNSPEC, device, diff --git a/src/core/platform/tests/test-platform-general.c b/src/core/platform/tests/test-platform-general.c index 93e525dd..908ad4dd 100644 --- a/src/core/platform/tests/test-platform-general.c +++ b/src/core/platform/tests/test-platform-general.c @@ -101,146 +101,156 @@ static void test_platform_ip_address_pretty_sort_cmp(gconstpointer test_data) { static const char *const EXPECTED_BUFFER[3] = { - [0] = ("5b1aea34648cabfec7c3523f76cf1ce34ca17a9a32f3f0f218024e48836dd1cb504e03d53e1124c5" - "0065aeb2e6fbf952902383028e3b47f280f062ea1a7e0b7be218d067530e1b0487b8c3b99f2b8a1a" - "8907c42f0000003437c5156e072b2f2f0037c9cfe07c34ddb3980deb14ab7b5af84a034703000000" - "883b0f3fd6ed84d6c959e553b887edcd6101f5d200000043b809d259e499db7d00f1853bdcb0e4bc" - "0e2b00b667b7b16d8d1e69c803000000b973972c17a47631c169f11ff9119c40b403b6630000007a" - "034f43340d01683c0045097aea4a849f060ddf57b24a5be9636360d603000000ad7c499dd538d345" - "74c038404923e75d0e02e2fc0000004acc807cdce682f80f00315c45ef817264c89a736ed55ed637" - "b96c200203000000faf1809becd2506315a6da29b2e94d3ab503e0e900000083a36035fb6297dfa7" - "00686b5efd0d53bb6215de4bb6f6f3d031a79028030000008bb836c0a25ea71f5daaed4d99eb2ebe" - "be03432f000000bf4ccf30d3aaaf02a4005d7308b67f91bf9d82c856ba942455e8d07c8403000000" - "f2abb982b001ec16901f55f960c55c22f30299a80000002b4d4647f53b1921af0088e3759a08e7a5" - "6663861eea1bf42c12ea3b9503000000fb95e8332fdfff658483a2d039a7bf148e02481e00000060" - "e89f7abdb682380a00eae374835b4a49a2b980b6aba92da6409969aa03000000e00473755d31e5b2" - "de252167c1c91b3a36020c700000007740318db913a353ed006efc068829c0e66ad0143a0554efb4" - "d149f07403000000153ece68ade15cec25a59273e7519f34c40d8d70000000f3819aa46fbe143934" - "0033ae6dec0fb124f264af67eed7c9a840e55b8b03000000c0cfb2b4386bec092fa5757ecde9348b" - "da002ebd000000ab667224dae775e5cc0041aca2ff0f576767d3648102b61886ecc8fb1103000000" - "fcebbaeb0c56535923f14874042a8aff1d028e5ec3cc13cc36bbe3c9bb0ec36f00e007bb64a2827b" - "7cdd38d0314c178e5a06c40b03000000ab90135fa636af4464d210a256be75e0500244770000004b" - "2e69220d6c0fc09c25d6534c809829af4a9df58dbfef186d416f3a1e030000002c932e655203d82a" - "3c84c4eb274ed18687030281000000f2235376239daeaacb3cae864b437baaae91921681c2162b9b" - "69e66142030000004fda8a3e0b841cf76391dd68269b53eccb02a831000000b78c54dda9ac3bb1b1" - "d43e6505621b9a7f0422ae3fc8979ee0416f95e70300000057d6249b652ba98c7dc7f17f666969e4" - "5c02af7a000000ee0b06fa9e988f80f0de6dc8dfcf2a3ad3bbcc0fa3b314f695b550c5db03000000" - "f32f4af595d785d5c1b5aad487c192f08b12a09b00000043288cd9bf66ec305a225a0c71b2ce78bb" - "16104c8eaf18c565111d891d03000000cd897619f51f44e644d7cf1d06b2b115d800549e62c12fba" - "5b1cdec48d10bbb13b8313d8cd2a24d34fc812bd2f8a59d90fcc00ac030000005292cd32dc096cd5" - "d8a4c5cf3351ee1cfc03056c00000051bbce426cfa4b861cc78592be7b14e7ba9c15acb881ae55f0" - "b16c7376030000005219061ab4c5c79489b2cc6a883c14697205cb8b000000f5e6d66df46ea13910" - "7754dee62c36d2fc70ccc567df7a49b8e5fe7d360300000066a3ae3939762df33a2d55060c78d551" - "cb0010fd00000041b9aca07b6e4925dd27943a272c171ed15abbbe1cd911db7b86ed271803000000" - "a5edc511c1507a141e0f515638c7ba31f50209450000003357ae79989870ccec3def0ad92749e016" - "663fe6ee0228c1dabb20413203000000862573c2303dd1d65c7b2cffeca6d1adac11e11f0000000f" - "855ebf3b772eb2b1c896c9a7304f66450a5f6abd850b06e382d1595603000000348352d715cf9d41" - "1ea012e5307294b6e301dac4000000075efee38dd16f8ee4ccd2f50c30706cae3fdcc2f0ee3d5e26" - "b10123e6030000001dff045298cfee0636674cdefb57b9ae541de8f4000000381ba2c4396de60f03" - "2bc7f34de2959871c0d4c0d4eb720c4a585287dc03000000cfb18b2b2cb749e2e03e544d0eb4f73e" - "751d9fcf251b32fc79685b05ddd3aa9ba511d2e40edb4d758fb554158ae5c7c0beb42b3403000000" - "895d5f24037d233302ad3b82d639272e4a02eadfbd2146bf8cfdb205f90e54b58a6ee136a779f37c" - "30d2c5053c40ecaec38b6b8e03000000bea73223e59bf0193432e9fa7a899f2d8e0ae4b89bf5a5d0" - "6776e66a9d80ab132e1ac921eb76adbb229df32e561fa80a0fc4676703000000a23eb66e720da9e0" - "7ac998b5690807d52602369ee1af4ca5a6a95581af5fd7ceacdca10f47d7b351a36b178aabc78a4a" - "1a0dd8c003000000e2815a1a37a52bddd1c2f1018b587eed720358f0e9201f17bd99fcf72909ac9e" - "7a55299e9bb4fd53bc7417940fcffe3f81cafd6302000000d6732578acd14320aefd4503189f7630" - "2403501c0000002b9f3c39f24b0572b100745cb25851429b3bbfb50168dfd04eabba4a3202000000" - "8ffe423d01883918039249f398f9b37ea0104651000000643722d9b707c0d8a400b7c8307f06b4b2" - "9088f20d9ac676d5b62f22ca02000000891715df7fc6a902edae579e2e10c7f7a202a0340436242c" - "beb0248cee3fbc160032d4f28aa28c08f80dd50c6712dfb4e4bafc4e02000000fde69eec3af2e6d0" - "bd68ab722af14548b20672e504265f6c72923e22594f3f790008ed2e2ebb0771db46a54cadb245ea" + [0] = ("5b1aea34648cabfec7c3523f76cf1ce34ca17a9a32f3f0f218074e48000000cb504e03d53e1124c5" + "0065aeb2e6fbf952902383028e3b47f2111d891d17a47631c169f11ff9119c40b468b66331bca67a" + "034f43340d02683c7545097aea4a849f060ddf57004a5be9b10123e6e4f15ecd1dff045298cfee06" + "b7f0318a03000000061db3dd7fde25654a4059d565dbc8a91e014457000000db56189572f32f4af5" + "00d785d5c1b5aad487c192f08bd7a09bdd2144439c88b02a0300000004b0595daf37deb499996bfb" + "667f072dec035d9c000000f4409bcfb3c167090e00d90a8543961b2ccd47724a3c460ba85183f4c5" + "a7afe28303000000d05ff720b16c73761a3fcb675219061ab402c7940000006a883c146972decb8b" + "00dac8f5e6d66df46ea139107754dee62c36d2fc6aae660b03000000fc1fb23d24438387def0f4c6" + "544e4b275d037146000000d349adc17647176b7c00d856e3b883efebc09dd9d61966b7ae7412041d" + "e5fe7d360300000066a3ae3939762df33a2d55060c78d551cb0310fd00000043b9aca07b6e4925dd" + "00943a272c171ed15abbbe1cd911db7b56e8f3fe6f0e9e6903000000ec2e2924348352d715cf9d41" + "1ea012e5300294b6000000c528ab20075efee38d006f8ee4ccd2f50c30706cae3fdcc2f0ee3d5e26" + "dac12ebd03000000667224dae775e5ccd141aca2ff0f57676702648100000086b62f22ca33478e1f" + "001715df7fc6a902edae579e2e10c7f7a22ba0340436242c03000000ee3fbc164632d4f28aa28c08" + "f80dd50c6702dfb400000023a28fa772a19cdf6d00c173f6078a806d329c9b008bbfc9723107f3f5" + "bcfe97e1030000007ad742d3d7320a4f880cf47f5dd0cf69cb0d840f0000007749509cb6752b2cee" + "00b7e7736a0afc9879ea40e69710fc9f6e8e99cdabf85f0c0300000008d33a2ea67776d7f88d69c8" + "c7e3b2d3c900f05400000021abb42316c533d9c90088189c471a1ff2f0ce3ff66e782110125ae2ed" + "922b6cb8030000001d5c302df59dd32a677e5a3af4fe297f6002f061d45d864d09f4ecf17625f82d" + "00c748288ae21e371051852c972ea7954079884a6c0fc09c03000000809829af4a9df58dbfef186d" + "416f3a1ef102d10f000000675203d82a3c84c4eb274ed18687780281d47a32f2235376239daeaacb" + "3cae864b0300000091921681c2162b9bfa40546cdb544e44df037c270000009a051bb2ee8192ac0c" + "fa3abc1ea0ab3e7d75a2f42b50c6a363401323780422ae3f03000000c43bd794c697895e5bfe47c6" + "f53a54e01b021d89000000d3e02d2ec587fc330003781b0f294a2b73c4421398f4de67e9cee64b38" + "ae8cb60b0300000038d856a40c67c3d4afa9c8649da90bd2ff02f2560000000bd7d5f14870c6d18d" + "6242b356955e1a13d1111b067acbce3e3bcdf382bb0ec36f0300000064a2827b7cdd38d0314c178e" + "925b568ae512c4e9000000e5264fd3ebe9cf9f6df9615189f78ee815b2781ea55c9555876b6a3f13" + "36674cde0300000054cfe8f42bf0e9381ba2c4396de60f032b00f34de2959871c0d4c0d4eb720c4a" + "e3c9472e5f2da5d9c5cfd9f2343b21362c19a09269121aec030000000fcc00ac2daa755e5292cd32" + "dc096cd5d802c5cf3351ee1cfcc2056cc1ff8e51bbce426cfa4b861cc78592be7b14e7ba9c15acb8" + "ba8110fb03000000904f288262e6ea77a22fa5f863eaeefa70031205000000f39b098b43cd68be6e" + "3f81268193fd637e585287dc6ca972a2cfb18b2bf6989d2d030000006ff7add5df2c93e05459507b" + "5d8c6a0f460554d2000000a8c67b2e48b47003c81785d3ffdbd9a617857ae8126b028c0e3e295354" + "bc51e540030000006c3d048a92d3adc69a84eb47622400207700416a00000087fbd7e2f7dea0077a" + "e9c0c0d9c386e9c6e6a2cbfa10ee58bdc75183607c52a52d030000004e8e8bc17c01ac63eca0c1cf" + "bb204132fb0213e4000000c2303dd1d65c7b2cffeca6d1adaccae11f8045a80f855ebf3b772eb2b1" + "bae87d60030000005d31e5b2de252167c1c91b3a36ba0c700e118477000000b913a353edc66efc06" + "8829c0e66ad0143a0554efb46b382ab0404cdf027a899f2d030000009bf5a5d06776e66a9d80ab13" + "2e1ac921eb01adbb0000002f561fa80a40e55b8b1dd92e18c0cfb2b4386bec092fa5757ecde9348b" + "daae7d6303000000c0982b283aa9986700b2a2b3ed257b8b041df48f000000cac72105b327335a25" + "a364d1015ffac03089f45539e1b0178462156cd6c4e1966803000000b3121cd5ef51e696c816290d" + "baee0e77260a82e1530ff5397c9125f59577d71c4b258a005116d11354edff62ceaa458fc75a91c4" + "d03bc90503000000eb760e3f004a2efc8ffc96b89b1bc8f415034e77be46bae5a1b3cae76665a268" + "abfe8a41d149f074a378b881153ece68ade15cec7625ca4a03000000e682f80f94315c45ef817264" + "c89a736ed51dd637b077ddad3108be69f9b97d05c917ad6b10e693bb6e26f2ba90c8e909e85e20e5" + "2af145480300000004265f6c72923e22594f3f79e208ed2e2e020771db46a54cadb245eafde6b025" + "67f814de39dd8f88152a58454d9ca9d20f45dfa700154d12020000009edfa7a74c1c83c18e47935e" + "8354846e3403386a000000d94064f6b021281e230094ae20ac26c7d41fd050bf8d85055bcfe3756c" + "98c39e7c02000000efc57ff447036b9551adcb22fd50793f79103c7d0000006e759d0c90bc512e13" + "00cef5e4a27985bd8d1e69c83dc21056b973972c6855676c02000000017c9148da5892bb4951c3a7" + "ed55689d3305ce7d3fd48469845f0c233dbdd2a90035df1f1782dee88487fd0db5971b46b7a350f9" "8c3b371502000000710c030690f5f18ea125dbf7d7e93bd65c01a56dfdcfc1155f236c8b9c79a620" - "00660bbf024b03ff0a8e27c405e64244e36f90d402000000fd41fe47684b370b6ec6584d64496089" - "570568ead4d1ae91c819bb068196d59900de3246e43f5e7945aaf95e2ffa3a11641e447502000000" - "b9b68c08a5e4351ea349e1ccf662e058b819a45100000045fcb6a035339d504c9726d80d9c2d89df" - "765b4d9a130257dc9c64ed0402000000a660ac824b7fae389861419c50da49bf2b02258300000025" - "9f9f0251becc987907879cca68fec7bbbb5f8edf248b4995d184e82002000000a19cdf6dd1c173f6" - "078a806d329c9b008b00c972000000f5b2cd3dbddc74e26de958e48d2ab8b0313e7f8933e315130f" - "d1e1b34902000000bcd7be07d78e6222e45aaf61814f703b401f5e6b000000cbaaa37b861e6d46da" - "fe7d6ec4ac1ea051010911915ddb05f2c43bd794010000005bfe47c6f53a54e01b0c1d89414d94d0" - "e0032ec50000000103781b0f294a2b7300421398f4de67e9cee64b38b56e03e01539ce4101000000" - "18238487a417f3da01d99dae5f190096cc012cab0000005b2363d13edc5aa115005eb914d8fbe9a4" - "fdb3d117d76b0de5bd82e9ea010000003d1b91caae8cb60b49ba9be338d856a40c02c3d400000064" - "9da90bd2fff2f2560046870bd7d5f14870c6d18d6242b356b9ef1b2101000000f90adac616a31dc2" - "e46a234558817151b300c9c900000073e64b0bd761fdf274005dca8ce1bd1871ae17bb4515856092" - "b4d9e89b010000006855676c277cf1bd017c9148da5892bb4903c3a70000009f3391ce7d3fd48469" - "005f0c233dbdd2a97835df1f1782dee86c1de913010000003ee1d76fc1ea76e98c9dfc78997ab53e" - "27001963f5b4cb2454830c68e44ea74b002b83f9b3bee14d861a4c9eeecc89f65408c1b701000000" - "d9e1825fa638e1af284a024b7f9e85ff730050a2000000276e08cb887464b93400c3127c750fabdd" - "69121aec129cdc690d58fbcc01000000d0d44ff1e51c35157666c05348e6f507ff00e89800000012" - "b900b2061d0c334b009f2dd1cdf64b0f9a60e0e289f08db3fde6b0250100000039dd8f88152a5845" - "4d9ca9d20f45dfa774028604000000fbcd7db68b9ae586da00b4070c50320427c4dd3d031e33f22c" - "210aeb09010000007000b96d06992b6a58acd3995b9663d2df02f333ef467092818aa77d6732b678" - "00844ef5a943825fcd743f59bd14c89bf121014a01000000efc67bce716c856e3973dc42a1003be9" - "4f0ed8ee0000009b5d5bbe6c10085f3d6176f78a19bb8df1804c122fce5078c1955e1a1301000000" - "7acbce3e3bcdf3824f1b134847ff26ba4400774900000017ec852d59f3d17232edd86ad6c3103a68" - "843a9aef34983882d3d38785010000005e0dfe491d1ba96742c7b5e02b2271229c01b02a06d0dc55" - "04b0595daf37deb499996bfb667f072dec1e5d9cdc8a11f4409bcfb30100000099d90a8543961b2c" - "cd47724a3c460ba85103f4c500000063eafb1ac4c0982b283aa9986700b2a2b3ed257b8b0489f48f" - "053ec8ca0100000027335a25a364d1015ffac03089f45539e1021784000000d7b83579b8da27345a" - "72437f9b6245de39ec9e71ee4b95150756e8f3fe010000000ea8042602a1f8e6f5657f3f9e3eb807" - "cb067645000000b8df6f628a70456d79f25d5895fb57fa60d9279fb2b8fcbac65ad47b8a01000000" - "da40d88d40a6d75bc404156225b7eedefc1e44574b15e2ae496ad01bf007eacb0a28aec868282510" - "b60291ea6480e356594f24a100000000e143fd52599364e13468f80fd514573fb517671c00000069" - "32d1d5f5d0ce2cf6007a70ba5193a162bc92ec1b11d9172c925b568a0000000087bb24e5264fd3eb" - "e9cf9f6df9615189f701e815000000a75c9555876b6a3f13002b6cb8360feaac1d5c302df59dd32a" - "7a859db500000000362956cd46646a0e222160e5f769bb295703ed370000005b6a813387e99bb834" - "009da86c64fefab2548759d313a5b92d8e47935e0000000034f0386a253c21d94064f6b021281e23" - "5f00ae20000000d71fd050bf8d85055b00e3756ccdb3455c60ca7b11c66af76e857ae81200000000" - "3e29535402e9b690c628d048eacce745ea053cb1000000b632ef3be6070dafa200187470e9da5570" - "9427c226d324d9a08487fd0d00000000b7a350f9fc1519defa7db45325456669371e2a3b000000dc" - "c405cbee5016c25200d8901d7a0165fe20744edb6ba04f14a4c73cf500000000a4bab14874afdf54" - "e6aae816430607ca061fe09818e9bbec5918c59068baf76a008940f6fc3bbdc7f6090f756aae660b" - "6e4c699300000000d9c1e67743efb54e54270e46042e91186a034e38000000376feecb80ac245409" - "c0becc271d9c2f67179bff0644399ae7df6b3542000000004c5cf8107ba282f4f983821918f93e74" - "2d00f0550000006f2292362e5d68265d9f98c82d9b7a559be3acf4fc36fa6b51e3c9472e00000000" - "c5cfd9f2343b21362c19a0921dce2f839200fa45000000270b9977e166bee737fe73670c439a644c" - "323b59b4cd20eb7dabea74f700000000f6989d2d6a909e986ff7add5df2c93e05412507b0000000f" - "466554d2ae4d52a8c67b2e48b47003c81785d3ffdbd9a617438a72e1000000002495a609675344f7" - "e2e3a5ebaec3c85f0a0042f70abe95c50345132a61eda239d9d083c3bf085387046ef8a36f0e9e69" - "59747cf200000000ab2dadc5a39411fd4ff1116d478987316a1f3fc2000000cfc6ebe434a7ae8ff0" - "40483e310819e3b10db116431ec6f7696b382ab0000000009a6ce5d906837dbca6a5ee19d6f63fe9" - "cb0301f7246f13b2050424a2b3a45ef7a029c896b4132bd895072cfeffe9d6815997069500000000" - "0d3c723b91adb0da7c4aa7e7eb5a15bcde035fb98b841fd84cc43c510385b9a4c2aac1d67a909b29" - "7c703915312e9c3cae02dfa000000000dd603bd35e7fa0f02f2f3313d8469d09a91709c0b7f0318a" - "575a4f8e061db3dd7fde25654a4059d565dbc8a91e3b4457b077ddad3108be69f9b97d05c917ad6b" - "10e693bb6e26f2ba900fe909a9fe20e5c7a4c656482a9b0d00625009a40aeb62a42b6a62548e3c38" - "cd3c72f203000000ca82ac5180101be4f85cef468ea086ea9a01fdc3a9fe1ec787bc45db7c52a52d" - "00bd39a44e8e8bc17c01ac63eca0c1cf5ff7f03a03000000c9a89192c1c8be55281a59d1fd338f35" - "7e00f8cea9fec34573654ea6624f138ef9531cd9367a02e4d241989477a363d5fa40546c03000000" - "df2d7c2790d3119a051bb2ee8192ac0cfa00bc1ea9fe3e7d75a2f42b50c6a36340132378b95c5931" - "3bacba64dbe996203b02239e0300000024438387def0f4c6544e4b275d9b7146a70010d2a9fec176" - "47176b7c07d856e3b883efebc09dd9d61966b7ae7412041d57393c6f03000000182c0287822a272b" - "ec4501a1e27acfee7a0188ffa9fe6cae426de59560fad65d67c624f285d7174177a47579dda0b6ea" - "a9a84c820300000070b1646d8026e9f1704f1b16286ba2dabc01f082a9feed33ef60a8b540b26f66" - "761d1f13badfad0fe8fa8f3c1aad2a826e6904f50200000047150b9b14010469823acb72bb89182f" - "93002196a9feb9153b36bc60be5b534e006527f67485ab35aca0c7ee419733853cf09e8b02000000" - "e79c10acfce165e332a62384ec04e5bab40085ada9fe0070a36dd51323b2c54200154d12f86c260a" - "9edfa7a74c1c83c1050f63f802000000443cacf59c6379a44b7892f487afa98cb102c19ca9fe942f" - "460bcea75481f25e007d0de9a7afe283bd2f22ead05ff72006c83bc0020000004bdade862c224f6f" - "36506ebd455e679cef009bb8a9fecec3f8c8fa6867a982be8a934f852cc3d4d82bc0ec7303f99f8f" - "def85b7502000000a0bef8675b29a197b7b3cceaf5f1bb12c503256aa9fe6e5d58099ffc4a503a71" - "2350acbd48411f0dc15d2f0f49dad345d966279502000000e06302aba042aaa218dc091e9aa1477f" - "6f059830a9fec95829a8838314dff34d24c332219a1b163a732d803e0e2f4f916d06412601000000" - "98c39e7cc282208fefc57ff447036b955101cb22a9fe793f797a3c7dadd1c86e009d0c90bc512e13" - "7dcef5e4a27985bd5cfd5ce601000000152f2b70eaef7443e0f79ab6902dde533601ec71a9fe9f25" - "4ac95883195580410062ed564153e17478f8c3344d89c0bbfaa100fd01000000be184524a6bdc878" - "9cf851782d895bcc8d038489a9fe8c1287e6f7bb020ffdb00012098610e52bb2a16a4008aefd545b" - "0d80684e01000000ba8110fb9733cc24904f288262e6ea77a203a5f8a9feeefa701d120523bd98f2" - "00098b43cd68be6e3f81268193fd637e9037d7a701000000c47cf0f551e96770a754ac19ef820fe0" - "2900f2d3a9fe049150b8d10ab700cc3a7cf51be0403b654ba2f56808092069af5f5b481b01000000" - "68cb3bc873b04d937a6ed8f7bc51e5406617d098a9fe048a92d3adc69a84eb47622400207799416a" - "f1f0a086fbd7e2f7dea0077a00000000c386e9c6e6a2cbfa10ee58bdc75183609900d627a9feb1cb" - "e491cbbbf9443fd6007eb3c5bf64b671d6f18dbf463f9b83f512dc1c00000000fbab244735d67c61" - "283031667b2d74a10302b1b1a9fe2aa590a2312e17f1a35900459582f4ef43c780908872746e39ef" - "a9a89f8700000000fcdf6d9be94030b34774d1d7dddedd989902f627a9fe965a87041331b2834bcf" - "00b4e3ce848518c4e3f6cbf25e5e1b992231bb0200000000173c333cd03bc905b7b899afeb760e3f" - "00022efca9fe96b89b1bc8f415bd4e77be46bae5a1b3cae76665a268abfe8a41a84e27c100000000" - "cb29efdf672d2fa57fc85ebbe276c5661a03192da9fee7af5eb888e9eb37bb046686943b101e1f55" - "3215abf8fbdf17c3677e5a3a00000000608df061d45d864d09f4ecf17625f82da1034828a9fe1e37" - "1051852c972ea7954079884af257b044fd13a6826a4c619f3d136cac000000009402a4c216772167" - "3f2b02b3256ead1f2f039bc1a9fefca162fb81e733cff620ca7feefe1933631e8e69f6d9d6962d2c"), + "00660bbf024b03ff0a8e27c405e6424457393c6f74993ade02000000e62112898dab2dade2ab2fc9" + "c56a7c86be0296228ec3f2f439d949b22b9c161c00b745cebdd06352cb2c354434819f4b248eb2b8" + "6297dfa702000000fd0d53bb6215de4bb6f6f3d031a790287e06e9c18bb836c0a25ea71f5daaed4d" + "00eb2ebebe3c432fec7d3abc4ccf30d3aaaf02a46e91b91502000000be5b534e0a6527f67485ab35" + "aca0c7ee4102338500000063e66e3a23d6732578acd14320aefd4503189f7630248e501c9052c22b" + "e3ff1a5f02000000b4425486c619147eb0216050ed7afd741000e83600000011f9c797c0c0ec468e" + "9de5a9caf493472201e48d163106cc397446a33fa349e1cc02000000b879a45176740744fcb6a035" + "339d504c9719d80d000000df765b4d9a130257dc5ff7f03a9518862bc9a89192c1c8be55281a59d1" + "bcd7be0702000000e45aaf61814f703b40125e6baf4648cbaa1f7b86000000dafe7d6ec4ac1ea051" + "010911915ddb05f2a84e27c18a06e2c9cb29efdfb56e03e0010000002f70249eefc67bce716c856e" + "3973dc42a1033be9000000efb1f14d985d5bbe6c00085f3d6176f78a19bb8df1804c122fce5078c1" + "57d6249b010000007dc7f17f666969e45c3baf7a119a65ee0b01fa9e000000f3de6dc8dfcf2a3ad3" + "00cc0fa3b314f695bd82e9ea8891ed0a3d1b91ca4f1b134801000000449a774929e86716ec852d59" + "f3d17232ed026ad600000068843a9aef34983882004f24a17dba1ee7e143fd52599364e13468f80f" + "fc1519de010000002545666937c22a3b6e9686dcc405cbee5000c2520000001f7a0165fe20744edb" + "00a04f146e4c699341b95f41d9c1e67743efb54e54270e46010000006a894e387625da376feecb80" + "ac245409c003cc2700000067179bff0644399ae70064ed0432d599eaa660ac824b7fae389861419c" + "9f3c2c8801000000f51f44e644d7cf1d06b2b115d882549e62002fba5b1cdec48d10bbb13b8313d8" + "002a24d34fc812bd2f8a59d96d064126666befbb81ae55f0010000000aa20624fbab244735d67c61" + "283031667b0274a103e0b1b153222aa590a2312e00f1a35900459582f4ef43c780908872746e39ef" + "536c75bb01000000720da9e07ac998b5690807d52617369ee1004ca500000081af5fd7ceacdca10f" + "00d7b351a36b178aabc78a4a0d80684ee5dbf45bc7a4c65601000000cd625009a40aeb62a42b6a62" + "548e3c38b9002002000000fbfaf1809becd2506300a6da29b2e94d3ab51fe0e9af98b180a36035fb" + "f05d7308010000009d82c856ba942455050f63f8282f34644402acf5000000a54b7892f487afa98c" + "0021c19c69d9942f460bcea75481f25e307d0de959747cf201000000ab2dadc5a39411fd4ff1116d" + "478987316a0e3fc2000000cfc6ebe434a7ae8ff040483e310819e3b10db116431ec6f7691539ce41" + "d514573f01000000f6932f6932d1d5f5d0ce2cf6bf7a70ba5100a1620000001b11d9172cf84a0347" + "8b82cdd8883b0f3fd6ed84d6c959e553b887edcdf90e54b501000000a779f37c30d2c5053c40ecae" + "210aeb0934012a247000b96d06992b6a58acd3995b9663d2df48f333ef467092818aa77d6732b678" + "cf844ef501000000cd743f59bd14c89b5cfd5ce6e82e785415032b7000000043e0f79ab6902dde53" + "36b3ec7127e19f254ac9588319558041fc62ed564153e174010000004d89c0bb5408c1b7d17fb084" + "d9e1825fa602e1af0000004b7f9e85ff73e050a2cd89fd276e08cb887464b9344ec3127c750fabdd" + "9985d62701000000e491cbbbf9443fd6a77eb3c5bf64b671d6068dbf0000008306c83bc026977911" + "4bdade862c224f6f36506ebd455e679cef369bb8fc2b445701000000496ad01bf007eacb0a28aec8" + "68282510b61e91ea6480e356def85b75827b26e8a0bef8675b29a197b7b3cceaf5f1bb12c535256a" + "61c2f5d200000000b809d259e499db7dc8f1853bdcb0e4bc0e1700b60000006dae02dfa0c26e7c3a" + "00603bd35e7fa0f02f2f3313d8469d09a92409c0f257b044000000006a4c619f9037d7a754655354" + "c47cf0f5510167700000001bef820fe02931f2d30075049150b8d10ab700cc3a7cf51be0403b654b" + "10613fc90000000016a31dc2e46a234558817151b38fc9c909038d71000000d761fdf274fc5dca8c" + "00bd1871ae17bb4515856092b4d9e89b676761b2eecc89f600000000d635edea8ffe423d01883918" + "039249f39800b37e00000053b2a16e643722d9b700c0d8a41fb7c8307f06b4b29088f20d9ac676d5" + "4d4647f5000000000f88e3759a08e7a56663861eea1bf42ccd0572f200000057ca82ac5180101be4" + "005cef468ea086ea9aaafdc388811ec787bc45db50da49bf00000000d94beb259f9f0251becc9879" + "07879cca681ec7bb000000df248b49953d136cac00054b019402a4c2167721673f2b02b3256ead1f" + "02e9b69000000000eacce745ea213cb1a84035b632ef3be6071fafa202187470e9da55709427c226" + "0024d9a086ed27184b443181a5edc511c1507a142fea9bc10000000062fb81e733cff620ca7feefe" + "1933631e8e03f6d90000002f6e6904f57239c09c47150b9b14010469823acb72bb89182f93112196" + "cdb3455c00000000c66af76e80f062ea1a7e0b7be218d06753001b04000000bb9f2b8a1a8982c42f" + "53700a3437c5156e072b2f2fb337c9cfe07c34ddb83579b80000000072437f9b6245de39ec9e71ee" + "4b951507be002b340000000f895d5f24037d233302ad3b82d639272e4a46eadfbd2146bf8cfdb205" + "ebfdcec30000000067a982be8a934f852cc3d4d82bc0ec7303129f8f00000087965a316af2abb982" + "b001ec16901f55f960c55c22f32099a8020bea2a25a5927300000000c4458d70911714f1819aa46f" + "be143934c900ae6dec0fb124f264af67eed7c9a8c38b6b8ee2614344bea73223e59bf0193432e9fa" + "b4d54acb00000000a417f3da01d99dae5f190096cc582cabd51fd15a0000003edc5aa115165eb914" + "d8fbe9a4fdb3d117d76b0de5416f95e7bb75d72f4cc43c5100000000c2aac1d67a909b297c703915" + "312e9c3c5a03c40b20ea99d5ab90135fa636af4464d210a256be75e0509c4477d19ac64b2e69220d" + "288cd9bf00000000225a0c71b2ce78bb16104c8eaf18c565ec17fb112087b97cfcebbaeb0c565359" + "23f14874042a8aff1d1f8e5ec3cc13cc36bbe3c9b2cd3dbd00000000e958e48d2ab8b0313e7f8933" + "e315130fa9034c8288f83f6e70b1646d8026e9f1704f1b16286ba2dabc7ef0820c91ed33ef60a8b5" + "70ccc567df7a49b8a4c73cf5ffa4ffc8a4bab14874afdf54e60fe816a9fe07ca0675e09818e9bbec" + "0018c59068baf76ab08940f6fc3bbdc7f6090f7512ea3b9503000000fb95e8332fdfff658483a2d0" + "39a7bf148e01481ea9fec460e89f7abdb682380a00eae374835b4a49a2b980b6aba92da6409969aa" + "fd338f35030000006e8cc34573654ea6624f138ef9531cd9360002e4a9fe989477a363d55ad47b8a" + "11090df8da40d88d40a6d75bc404156225b7eedeb95c593103000000dbe9962069e66142e2275334" + "4fda8a3e0b001cf7a9fedd68269b53eccb44a831714acfb58c54dda9ac3bb1b1d43e6505621b9a7f" + "1e0f515603000000f57609453df7803357ae79989870ccec3d000ad9a9fee016663fe6ee0228c1da" + "5f5b481b9f05a16768cb3bc873b04d937a6ed8f7d7ac5f9903000000822a272bec4501a1e27acfee" + "7a8588ffd5016caea9fee59560fad65d67c624f285d7174177a47579dda0b6ead1e1b34901eaedd5" + "dc335c8b030000000a3c8e7c91bf821c4b09cee3c37ff4283a011480a9fec42cac4ef3ad378ffec7" + "085a62475588456e4ead7cbda620a3abae816e345d68265d020000009b7a559be3acf4fc36fa6b51" + "3cf09e8b99009462a9fe10acfce165e332a623840004e5bab49185ad9b7d0070a36dd51323b2c542" + "dedea2030200000002a1f8e6f5657f3f9e3eb807cbad76451002edb8a9fe628a70456d79f25d5895" + "0057fa60d9279fb2b8fcbac6abea74f7a6df7979b3980deb020000006c1de913df1424ce3ee1d76f" + "c1ea76e98c00fc78a9feb53e27c21963f5b4cb2454830c68e44ea74b4f2b83f9b3bee14d861a4c9e" + "bc74179402000000438a72e12ae0436a2495a609675344f7e200a5eba9fec85f0a1742f70abe95c5" + "0345132a61eda239d9d083c3bf085387046ef8a3b0916e5d020000004a503a712350acbd48411f0d" + "c15d2f0f4903d345a9fe06954d2471f00d3c723b91adb0da7c4aa7e7eb5a15bcde015fb98b841fd8" + "9a6ce5d902000000a6a5ee19d6f63fe9cbdd01f7246f13b2050524a2a9fe5ef7a029c896b4132bd8" + "95072cfeffe9d6812231bb02f922259b173c333c1dce2f83010000003a3efc240b9977e166bee737" + "fe73670c4301644ca9fe59b4cd20eb7dd3d38785008ffad45e0dfe491d1ba96742c7b5e02b227122" + "a9a89f8701000000fcdf6d9be94030b34774d1d7dddedd989901f627a9fe965a87041331b2834bcf" + "00b4e3ce848518c4e3f6cbf25e5e1b990fc46767e36f90d401000000fd41fe47684b370b6ec6584d" + "64496089570368eaa9feae91c819bb068196d59900de3246e43f5e7945aaf95e2ffa3a11b9ef1b21" + "74e7860401000000cd7db68b9ae586dacdb4070c50320427c4033d03a9fef22c636360d696be085a" + "007c499dd538d34574c038404923e75d0e09e2fcaefd545b010000007ced4f8b362956cd46646a0e" + "222160e5f700bb29a9feed37a2123c5b6a813387e99bb834a19da86c64fefab2548759d313a5b92d" + "c896c9a7010000000a5f6abd850b06e3d9662795ce2cc1cee01702aba9feaaa218dc091e9aa1477f" + "6fdc9830d7fbc95829a8838314dff34d24c332219a1b163a000000000e2f4f911a0dd8c052ed6b13" + "e2815a1a37002bdda9fef1018b587eed72bb58f000201f17bd99fcf72909ac9e7a55299e9bb4fd53" + "7666c05300000000ffa8e89871fb9510b900b2061d0c334b81022dd1a9fe4b0f9a60e0e289f08db3" + "00bafc4e095a3230fde69eec3af2e6d0bd68ab722cb749e2000000000eb4f73e75039fcf251b32fc" + "79685b05dd02aa9ba9fed2e40edb4d758fb554158ae5c7c00d58fbcc58fc4c2fd0d44ff1e51c3515" + "40b26f6600000000badfad0fe8fa8f3c1aad2a82530b7447d902f401a9fe2f4c329f997184c9d257" + "8e4cf9c48147507e1cd59ea1ae6da48b1eba6d16672d2fa500000000e276c5661a64192db44ce7af" + "5eb888e9eb03bb04a9fe943b101e1f553215abf8fbdf17c3641e447514ca565fb9b68c08a5e4351e" + "a2f5680800000000faa100fdfdd68d34be184524a6bdc8789c035178a9fe5bcc8da98489c55b8c12" + "87e6f7bb020ffdb0e612098610e52bb2a16a40089f3c39f200000000de745cb25851429b3bbfb501" + "68dfd04edf033542a9fe5f574c5cf8107ba282f4f983821918f93e742d08f0550b55726f2292362e"), [1] = ("54270e46020000006a894e387625da376feecb80ac245409c058cc271d9c2f67179bff0644399ae7" "9c64ed0432d599eaa660ac824b7fae389861419c7a899f2d010000009bf5a5d06776e66a9d80ab13" "2e1ac921eb04adbb229df32e561fa80a40e55b8b1dd92e18c0cfb2b4386bec092fa5757ecde9348b" diff --git a/src/core/platform/tests/test-route.c b/src/core/platform/tests/test-route.c index 2d39cb37..85838267 100644 --- a/src/core/platform/tests/test-route.c +++ b/src/core/platform/tests/test-route.c @@ -1390,12 +1390,17 @@ again_table: rr->protocol = _rr_rand_choose_u8(nmtst_get_rand_uint32()); #define IPTOS_TOS_MASK 0x1E +#define INET_DSCP_MASK 0xFC again_tos: rr->tos = _rr_rand_choose_u8(nmtst_get_rand_uint32()); + if (rr->addr_family == AF_INET && rr->tos & ~IPTOS_TOS_MASK) goto again_tos; + if (rr->tos & ~INET_DSCP_MASK) + goto again_tos; + if (_rule_check_kernel_support(platform, FRA_IP_PROTO)) rr->ip_proto = _rr_rand_choose_u8(nmtst_get_rand_uint32()); diff --git a/src/core/ppp/nm-ppp-manager.c b/src/core/ppp/nm-ppp-manager.c index 896c233d..003a9806 100644 --- a/src/core/ppp/nm-ppp-manager.c +++ b/src/core/ppp/nm-ppp-manager.c @@ -545,7 +545,6 @@ impl_ppp_manager_set_ip4_config(NMDBusObject *obj, NM_IP_CONFIG_SOURCE_PPP); nm_l3_config_data_set_mtu(l3cd, mtu); - nm_l3_config_data_set_dns_priority(l3cd, AF_INET, 0); address = (NMPlatformIP4Address){ .plen = 32, @@ -642,6 +641,7 @@ impl_ppp_manager_set_ip6_config(NMDBusObject *obj, nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; NMPlatformIP6Address address; struct in6_addr a; + guint32 mtu; NMUtilsIPv6IfaceId iid = NM_UTILS_IPV6_IFACE_ID_INIT; gboolean has_peer = FALSE; gs_unref_variant GVariant *config_dict = NULL; @@ -652,13 +652,15 @@ impl_ppp_manager_set_ip6_config(NMDBusObject *obj, nm_clear_g_source(&priv->ppp_timeout_handler); - if (!set_ip_config_common(self, config_dict, NULL)) + if (!set_ip_config_common(self, config_dict, &mtu)) goto out; l3cd = nm_l3_config_data_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), priv->ifindex, NM_IP_CONFIG_SOURCE_PPP); + nm_l3_config_data_set_mtu(l3cd, mtu); + address = (NMPlatformIP6Address){ .plen = 64, .addr_source = NM_IP_CONFIG_SOURCE_PPP, diff --git a/src/core/supplicant/nm-supplicant-config.c b/src/core/supplicant/nm-supplicant-config.c index a4e5cc4d..22c422a2 100644 --- a/src/core/supplicant/nm-supplicant-config.c +++ b/src/core/supplicant/nm-supplicant-config.c @@ -1088,6 +1088,14 @@ nm_supplicant_config_add_setting_wireless_security(NMSupplicantConfig error)) return FALSE; } + + /* In case the connection is saved as OWE / Enhanced Open, prevent + * unencrypted downgrade + */ + if (nm_streq(key_mgmt, "owe")) { + if (!nm_supplicant_config_add_option(self, "owe_only", "1", -1, NULL, error)) + return FALSE; + } } /* WEP keys if required */ diff --git a/src/core/supplicant/nm-supplicant-interface.c b/src/core/supplicant/nm-supplicant-interface.c index e502ae85..e7ac0e58 100644 --- a/src/core/supplicant/nm-supplicant-interface.c +++ b/src/core/supplicant/nm-supplicant-interface.c @@ -21,6 +21,7 @@ #include "nm-supplicant-manager.h" #define DBUS_TIMEOUT_MSEC 20000 +#define PMK_LIFETIME_SEC (3600 * 24 * 7) /*****************************************************************************/ @@ -1249,6 +1250,7 @@ parse_capabilities(NMSupplicantInterface *self, GVariant *capabilities) break; } } + g_free(array); } priv->iface_capabilities = NM_SUPPL_CAP_MASK_SET(priv->iface_capabilities, @@ -2451,6 +2453,32 @@ assoc_set_ap_scan_cb(GVariant *ret, GError *error, gpointer user_data) add_network(self); } +static void +assoc_set_pmk_lifetime(GVariant *ret, GError *error, gpointer user_data) +{ + NMSupplicantInterface *self; + NMSupplicantInterfacePrivate *priv; + + if (nm_utils_error_is_cancelled(error)) + return; + + self = NM_SUPPLICANT_INTERFACE(user_data); + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self); + + if (error) { + assoc_return(self, error, "failure to set PMK lifetime"); + return; + } + + _LOGT("assoc[" NM_HASH_OBFUSCATE_PTR_FMT "]: interface PMK lifetime set to %u", + NM_HASH_OBFUSCATE_PTR(priv->assoc_data), + PMK_LIFETIME_SEC); + + nm_assert(priv->assoc_data->calls_left > 0); + if (--priv->assoc_data->calls_left == 0) + add_network(self); +} + static gboolean assoc_fail_on_idle_cb(gpointer user_data) { @@ -2534,6 +2562,21 @@ nm_supplicant_interface_assoc(NMSupplicantInterface *self, assoc_set_ap_scan_cb, self); + /* Set the PMK lifetime to a longer interval (1 week) instead of + * the default one (12 hours) that would trigger a WPA-EAP + * reauthentication after only 8:24 hours (70% of the lifetime). */ + assoc_data->calls_left++; + nm_dbus_connection_call_set(priv->dbus_connection, + priv->name_owner->str, + priv->object_path->str, + NM_WPAS_DBUS_IFACE_INTERFACE, + "Dot11RSNAConfigPMKLifetime", + g_variant_new_take_string(g_strdup_printf("%u", PMK_LIFETIME_SEC)), + DBUS_TIMEOUT_MSEC, + assoc_data->cancellable, + assoc_set_pmk_lifetime, + self); + ap_isolation = nm_supplicant_config_get_ap_isolation(priv->assoc_data->cfg); if (!priv->ap_isolate_supported) { if (ap_isolation) { diff --git a/src/core/supplicant/nm-supplicant-settings-verify.c b/src/core/supplicant/nm-supplicant-settings-verify.c index 566173af..9881c552 100644 --- a/src/core/supplicant/nm-supplicant-settings-verify.c +++ b/src/core/supplicant/nm-supplicant-settings-verify.c @@ -92,6 +92,7 @@ static const struct Opt opt_table[] = { OPT_BYTES("mka_cak", 65536), OPT_BYTES("mka_ckn", 65536), OPT_BYTES("nai", 0), + OPT_INT("owe_only", 0, 1), OPT_BYTES("pac_file", 0), OPT_KEYWORD("pairwise", NM_MAKE_STRV("CCMP", "TKIP", "GCMP-256", "NONE", )), OPT_UTF8("password", 0), diff --git a/src/core/tests/test-core.c b/src/core/tests/test-core.c index b4e1c4d5..11a7f323 100644 --- a/src/core/tests/test-core.c +++ b/src/core/tests/test-core.c @@ -15,7 +15,6 @@ #include "NetworkManagerUtils.h" #include "libnm-core-intern/nm-core-internal.h" #include "nm-core-utils.h" -#include "libnm-systemd-core/nm-sd-utils-core.h" #include "dns/nm-dns-manager.h" #include "nm-connectivity.h" @@ -2314,7 +2313,6 @@ test_dns_create_resolv_conf(void) static void test_machine_id_read(void) { - NMUuid machine_id_sd; const NMUuid *machine_id; char machine_id_str[33]; gpointer logstate; @@ -2346,27 +2344,6 @@ test_machine_id_read(void) == machine_id_str); g_assert(strlen(machine_id_str) == 32); g_assert_cmpstr(machine_id_str, ==, nm_utils_machine_id_str()); - - /* double check with systemd's implementation... */ - if (!nm_sd_utils_id128_get_machine(&machine_id_sd)) { - /* if systemd failed to read /etc/machine-id, the file likely - * is invalid. Our machine-id is fake, and we have nothing to - * compare against. */ - - if (g_file_test(LOCALSTATEDIR "/lib/dbus/machine-id", G_FILE_TEST_EXISTS)) { - /* Hm. So systemd failed to read /etc/machine-id, but we may have the one from D-Bus. - * With LOCALSTATEDIR"/lib/dbus/machine-id", we don't really know whether we - * parsed that file. Assume we don't know and skip the test on this system. */ - g_assert(!nm_utils_machine_id_is_fake()); - return; - } - - /* OK, in this case, our function should have generated a random machine ID. */ - g_assert(nm_utils_machine_id_is_fake()); - } else { - g_assert(!nm_utils_machine_id_is_fake()); - g_assert_cmpmem(&machine_id_sd, sizeof(NMUuid), machine_id, 16); - } } /*****************************************************************************/ |