diff options
| author | Michael Biebl <biebl@debian.org> | 2026-02-22 00:40:03 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2026-02-22 00:40:03 +0100 |
| commit | ccdb9117cca7141ee709afca8b25c966ff4fa18e (patch) | |
| tree | 3b7377c95e1d4049c13dd9101ae923fee70ab91d /src/core | |
| parent | d0ea10125cc04f55c1864451198d87fb801d1457 (diff) | |
| parent | 067fb576988f685e83ac8b0ae690334aff547c85 (diff) | |
Update upstream source from tag 'upstream/1.56.0'
Update to upstream version '1.56.0' with Debian dir 15fab61a7abf1fd4e2ba46785f96d935e87d32bb
Diffstat (limited to 'src/core')
48 files changed, 1294 insertions, 247 deletions
diff --git a/src/core/devices/nm-device-bridge.c b/src/core/devices/nm-device-bridge.c index 45cdd83f..6ca3737f 100644 --- a/src/core/devices/nm-device-bridge.c +++ b/src/core/devices/nm-device-bridge.c @@ -1066,7 +1066,7 @@ attach_port(NMDevice *device, plat_vlans = setting_vlans_to_platform(vlans, &num_vlans); - /* Since the link was just enportd, there are no existing VLANs + /* Since the link was just attached, there are no existing VLANs * (except for the default one) and so there's no need to flush. */ if (plat_vlans diff --git a/src/core/devices/nm-device-ethernet.c b/src/core/devices/nm-device-ethernet.c index db1245b3..11f691de 100644 --- a/src/core/devices/nm-device-ethernet.c +++ b/src/core/devices/nm-device-ethernet.c @@ -15,7 +15,6 @@ #include <linux/if_ether.h> #include "NetworkManagerUtils.h" -#include "NetworkManagerUtils.h" #include "libnm-core-aux-intern/nm-libnm-core-utils.h" #include "libnm-core-intern/nm-core-internal.h" #include "libnm-glib-aux/nm-uuid.h" @@ -708,6 +707,9 @@ supplicant_iface_start(NMDeviceEthernet *self) NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); gs_unref_object NMSupplicantConfig *config = NULL; gs_free_error GError *error = NULL; + NMActRequest *request; + NMActiveConnection *controller_ac; + NMDevice *controller; config = build_supplicant_config(self, &error); if (!config) { @@ -722,6 +724,16 @@ supplicant_iface_start(NMDeviceEthernet *self) } nm_supplicant_interface_disconnect(priv->supplicant.iface); + + /* Tell the supplicant in which bridge the interface is */ + if ((request = nm_device_get_act_request(NM_DEVICE(self))) + && (controller_ac = nm_active_connection_get_controller(NM_ACTIVE_CONNECTION(request))) + && (controller = nm_active_connection_get_device(controller_ac)) + && nm_device_get_device_type(controller) == NM_DEVICE_TYPE_BRIDGE) { + nm_supplicant_interface_set_bridge(priv->supplicant.iface, nm_device_get_iface(controller)); + } else + nm_supplicant_interface_set_bridge(priv->supplicant.iface, NULL); + nm_supplicant_interface_assoc(priv->supplicant.iface, config, supplicant_iface_assoc_cb, self); return TRUE; } @@ -1901,7 +1913,7 @@ get_ip_method_auto(NMDevice *device, int addr_family) /* We cannot do DHCPv4 on a PPP link, instead we get "auto" IP addresses * by pppd. Return "manual" here, which has the suitable effect to a * (zero) manual addresses in addition. */ - return NM_SETTING_IP6_CONFIG_METHOD_MANUAL; + return NM_SETTING_IP4_CONFIG_METHOD_MANUAL; } return NM_SETTING_IP6_CONFIG_METHOD_AUTO; diff --git a/src/core/devices/nm-device-macsec.c b/src/core/devices/nm-device-macsec.c index 1659ea05..eb39cb2a 100644 --- a/src/core/devices/nm-device-macsec.c +++ b/src/core/devices/nm-device-macsec.c @@ -440,6 +440,9 @@ supplicant_iface_start(NMDeviceMacsec *self) NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE(self); gs_unref_object NMSupplicantConfig *config = NULL; gs_free_error GError *error = NULL; + NMActRequest *request; + NMActiveConnection *controller_ac; + NMDevice *controller; config = build_supplicant_config(self, &error); if (!config) { @@ -452,6 +455,16 @@ supplicant_iface_start(NMDeviceMacsec *self) } nm_supplicant_interface_disconnect(priv->supplicant.iface); + + /* Tell the supplicant in which bridge the interface is */ + if ((request = nm_device_get_act_request(NM_DEVICE(self))) + && (controller_ac = nm_active_connection_get_controller(NM_ACTIVE_CONNECTION(request))) + && (controller = nm_active_connection_get_device(controller_ac)) + && nm_device_get_device_type(controller) == NM_DEVICE_TYPE_BRIDGE) { + nm_supplicant_interface_set_bridge(priv->supplicant.iface, nm_device_get_iface(controller)); + } else + nm_supplicant_interface_set_bridge(priv->supplicant.iface, NULL); + nm_supplicant_interface_assoc(priv->supplicant.iface, config, supplicant_iface_assoc_cb, self); return TRUE; } diff --git a/src/core/devices/nm-device-private.h b/src/core/devices/nm-device-private.h index 2568d9f1..6d828597 100644 --- a/src/core/devices/nm-device-private.h +++ b/src/core/devices/nm-device-private.h @@ -115,9 +115,6 @@ gboolean nm_device_sysctl_ip_conf_set(NMDevice *self, NML3ConfigData *nm_device_create_l3_config_data(NMDevice *self, NMIPConfigSource source); -NML3ConfigData *nm_device_create_l3_config_data_from_connection(NMDevice *self, - NMConnection *connection); - void nm_device_ip_method_dhcp4_start(NMDevice *self); void nm_device_ip_method_autoconf6_start(NMDevice *self); diff --git a/src/core/devices/nm-device-utils.c b/src/core/devices/nm-device-utils.c index 3e86e2e8..be1de3ea 100644 --- a/src/core/devices/nm-device-utils.c +++ b/src/core/devices/nm-device-utils.c @@ -143,7 +143,9 @@ NM_UTILS_LOOKUP_STR_DEFINE( NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_USER_SETTINGS, "unmanaged-user-settings"), NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_USER_UDEV, "unmanaged-user-udev"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_NETWORKING_OFF, "networking-off"), ); + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_NETWORKING_OFF, "networking-off"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_NO_OPERATOR_CODE, + "modem-no-operator-code"), ); NM_UTILS_LOOKUP_STR_DEFINE(nm_device_mtu_source_to_string, NMDeviceMtuSource, diff --git a/src/core/devices/nm-device-wireguard.c b/src/core/devices/nm-device-wireguard.c index 299e3b30..d98059ba 100644 --- a/src/core/devices/nm-device-wireguard.c +++ b/src/core/devices/nm-device-wireguard.c @@ -1672,6 +1672,57 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) return ret; } +static gboolean +skip_peer_route(const NMIPAddr *peer_addr, + guint peer_addr_prefix, + int addr_family, + NMSettingIPConfig *s_ip) +{ + guint num_addresses; + guint i; + + /* + * If the allowed-ip subnet is already reachable on the interface via the + * prefix route of a static IP address, skip adding the peer route. + * We don't want to override the prefix route with a new one because the + * prefix route also specifies the correct source IP address. + * + * wg-quick does something similar here: + * https://git.zx2c4.com/wireguard-tools/tree/src/wg-quick/linux.bash?h=v1.0.20250521#n177 + * The condition in wg-quick is a bit different because it checks that no + * duplicate route exists on the interface. We can't do exactly the same + * because here we don't have visibility on all the platform routes. + */ + + if (!s_ip) + return FALSE; + + num_addresses = nm_setting_ip_config_get_num_addresses(s_ip); + for (i = 0; i < num_addresses; i++) { + NMIPAddr setting_addr; + NMIPAddr peer_addr_tmp; + guint setting_prefix; + NMIPAddress *a; + + peer_addr_tmp = *peer_addr; + + a = nm_setting_ip_config_get_address(s_ip, i); + nm_ip_address_get_address_binary(a, &setting_addr); + setting_prefix = nm_ip_address_get_prefix(a); + + if (setting_prefix > peer_addr_prefix) + continue; + + nm_ip_addr_clear_host_address(addr_family, &setting_addr, NULL, setting_prefix); + nm_ip_addr_clear_host_address(addr_family, &peer_addr_tmp, NULL, setting_prefix); + + if (nm_ip_addr_equal(addr_family, &peer_addr_tmp, &setting_addr)) + return TRUE; + } + + return FALSE; +} + static const NML3ConfigData * _get_dev2_ip_config(NMDeviceWireGuard *self, int addr_family) { @@ -1738,6 +1789,7 @@ _get_dev2_ip_config(NMDeviceWireGuard *self, int addr_family) n_aips = nm_wireguard_peer_get_allowed_ips_len(peer); for (j = 0; j < n_aips; j++) { + NMSettingIPConfig *s_ip; NMPlatformIPXRoute rt; NMIPAddr addrbin; const char *aip; @@ -1745,7 +1797,8 @@ _get_dev2_ip_config(NMDeviceWireGuard *self, int addr_family) int prefix; guint32 rtable_coerced; - aip = nm_wireguard_peer_get_allowed_ip(peer, j, &valid); + aip = nm_wireguard_peer_get_allowed_ip(peer, j, &valid); + s_ip = nm_connection_get_setting_ip_config(connection, addr_family); if (!valid || !nm_inet_parse_with_prefix_bin(addr_family, aip, NULL, &addrbin, &prefix)) continue; @@ -1754,9 +1807,6 @@ _get_dev2_ip_config(NMDeviceWireGuard *self, int addr_family) prefix = (addr_family == AF_INET) ? 32 : 128; if (prefix == 0) { - NMSettingIPConfig *s_ip; - - s_ip = nm_connection_get_setting_ip_config(connection, addr_family); if (nm_setting_ip_config_get_never_default(s_ip)) continue; } @@ -1769,6 +1819,9 @@ _get_dev2_ip_config(NMDeviceWireGuard *self, int addr_family) nm_ip_addr_clear_host_address(addr_family, &addrbin, NULL, prefix); + if (skip_peer_route(&addrbin, prefix, addr_family, s_ip)) + continue; + rtable_coerced = route_table_coerced; if (prefix == 0 && auto_default_route_enabled) { diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index b0a3f780..46fb2339 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -113,6 +113,19 @@ typedef enum { RELEASE_PORT_TYPE_CONFIG_FORCE, } ReleasePortType; +/** + * CleanupType: + * @CLEANUP_TYPE_KEEP: Cleanup internally but keep the real device's config. This is + * often used when moving a partially managed device to "unmanaged" (but not only). + * @CLEANUP_TYPE_REMOVED: The device suddently disappeared. Cleanup internally but don't + * make any action on the real device at all, as it no longer exists. + * @CLEANUP_TYPE_DECONFIGURE: Also deconfigure the real device. This is the typical + * action when a connection or device is set to "down", or fully managed devices + * moved to "unmanaged". + * @CLEANUP_TYPE_KEEP_REAPPLY: Like %CLEANUP_TYPE_KEEP, but indicating that it's a + * reapply. Some special actions can be done if we're doing a reapply, like keeping + * the existing DHCP lease, for example. + */ typedef enum { CLEANUP_TYPE_KEEP, CLEANUP_TYPE_REMOVED, @@ -265,11 +278,11 @@ typedef struct { NMDeviceIPState state; union { struct { - NMDnsMasqManager *dnsmasq_manager; - NMNetnsSharedIPHandle *shared_ip_handle; - NMFirewallConfig *firewall_config; - gulong dnsmasq_state_id; - const NML3ConfigData *l3cd; + NMDnsMasqManager *dnsmasq_manager; + NMNetnsIPReservation *ip_reservation; + NMFirewallConfig *firewall_config; + gulong dnsmasq_state_id; + const NML3ConfigData *l3cd; } v4; struct { } v6; @@ -1411,14 +1424,12 @@ _prop_get_ipvx_routed_dns(NMDevice *self, int addr_family) } static NMSettingConnectionMdns -_prop_get_connection_mdns(NMDevice *self) +_prop_get_connection_mdns(NMDevice *self, NMConnection *connection) { - NMConnection *connection; NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT; g_return_val_if_fail(NM_IS_DEVICE(self), NM_SETTING_CONNECTION_MDNS_DEFAULT); - connection = nm_device_get_applied_connection(self); if (connection) mdns = nm_setting_connection_get_mdns(nm_connection_get_setting_connection(connection)); if (mdns != NM_SETTING_CONNECTION_MDNS_DEFAULT) @@ -1453,14 +1464,12 @@ _prop_get_sriov_preserve_on_down(NMDevice *self, NMSettingSriov *s_sriov) } static NMSettingConnectionLlmnr -_prop_get_connection_llmnr(NMDevice *self) +_prop_get_connection_llmnr(NMDevice *self, NMConnection *connection) { - NMConnection *connection; NMSettingConnectionLlmnr llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT; g_return_val_if_fail(NM_IS_DEVICE(self), NM_SETTING_CONNECTION_LLMNR_DEFAULT); - connection = nm_device_get_applied_connection(self); if (connection) llmnr = nm_setting_connection_get_llmnr(nm_connection_get_setting_connection(connection)); if (llmnr != NM_SETTING_CONNECTION_LLMNR_DEFAULT) @@ -1475,14 +1484,12 @@ _prop_get_connection_llmnr(NMDevice *self) } static NMSettingConnectionDnsOverTls -_prop_get_connection_dns_over_tls(NMDevice *self) +_prop_get_connection_dns_over_tls(NMDevice *self, NMConnection *connection) { - NMConnection *connection; NMSettingConnectionDnsOverTls dns_over_tls = NM_SETTING_CONNECTION_DNS_OVER_TLS_DEFAULT; g_return_val_if_fail(NM_IS_DEVICE(self), NM_SETTING_CONNECTION_DNS_OVER_TLS_DEFAULT); - connection = nm_device_get_applied_connection(self); if (connection) dns_over_tls = nm_setting_connection_get_dns_over_tls( nm_connection_get_setting_connection(connection)); @@ -1497,15 +1504,33 @@ _prop_get_connection_dns_over_tls(NMDevice *self) NM_SETTING_CONNECTION_DNS_OVER_TLS_DEFAULT); } +static NMSettingConnectionDnssec +_prop_get_connection_dnssec(NMDevice *self, NMConnection *connection) +{ + NMSettingConnectionDnssec dnssec = NM_SETTING_CONNECTION_DNSSEC_DEFAULT; + + g_return_val_if_fail(NM_IS_DEVICE(self), NM_SETTING_CONNECTION_DNSSEC_DEFAULT); + + if (connection) + dnssec = nm_setting_connection_get_dnssec(nm_connection_get_setting_connection(connection)); + if (dnssec != NM_SETTING_CONNECTION_DNSSEC_DEFAULT) + return dnssec; + + return nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, + NM_CON_DEFAULT("connection.dnssec"), + self, + NM_SETTING_CONNECTION_DNSSEC_NO, + NM_SETTING_CONNECTION_DNSSEC_YES, + NM_SETTING_CONNECTION_DNSSEC_DEFAULT); +} + static NMMptcpFlags -_prop_get_connection_mptcp_flags(NMDevice *self) +_prop_get_connection_mptcp_flags(NMDevice *self, NMConnection *connection) { - NMConnection *connection; - NMMptcpFlags mptcp_flags = NM_MPTCP_FLAGS_NONE; + NMMptcpFlags mptcp_flags = NM_MPTCP_FLAGS_NONE; g_return_val_if_fail(NM_IS_DEVICE(self), NM_MPTCP_FLAGS_DISABLED); - connection = nm_device_get_applied_connection(self); if (connection) { mptcp_flags = nm_setting_connection_get_mptcp_flags(nm_connection_get_setting_connection(connection)); @@ -2471,16 +2496,14 @@ _prop_get_ipv4_dhcp_vendor_class_identifier(NMDevice *self, NMSettingIP4Config * } static NMSettingIP6ConfigPrivacy -_prop_get_ipv6_ip6_privacy(NMDevice *self) +_prop_get_ipv6_ip6_privacy(NMDevice *self, NMConnection *connection) { NMSettingIP6ConfigPrivacy ip6_privacy; - NMConnection *connection; g_return_val_if_fail(self, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); /* 1.) First look at the per-connection setting. If it is not -1 (unknown), * use it. */ - connection = nm_device_get_applied_connection(self); if (connection) { NMSettingIPConfig *s_ip6 = nm_connection_get_setting_ip6_config(connection); @@ -3613,11 +3636,12 @@ nm_device_create_l3_config_data_from_connection(NMDevice *self, NMConnection *co l3cd = nm_l3_config_data_new_from_connection(nm_device_get_multi_index(self), ifindex, connection); - nm_l3_config_data_set_mdns(l3cd, _prop_get_connection_mdns(self)); - nm_l3_config_data_set_llmnr(l3cd, _prop_get_connection_llmnr(self)); - nm_l3_config_data_set_dns_over_tls(l3cd, _prop_get_connection_dns_over_tls(self)); - nm_l3_config_data_set_ip6_privacy(l3cd, _prop_get_ipv6_ip6_privacy(self)); - nm_l3_config_data_set_mptcp_flags(l3cd, _prop_get_connection_mptcp_flags(self)); + nm_l3_config_data_set_mdns(l3cd, _prop_get_connection_mdns(self, connection)); + nm_l3_config_data_set_llmnr(l3cd, _prop_get_connection_llmnr(self, connection)); + nm_l3_config_data_set_dns_over_tls(l3cd, _prop_get_connection_dns_over_tls(self, connection)); + nm_l3_config_data_set_dnssec(l3cd, _prop_get_connection_dnssec(self, connection)); + nm_l3_config_data_set_ip6_privacy(l3cd, _prop_get_ipv6_ip6_privacy(self, connection)); + nm_l3_config_data_set_mptcp_flags(l3cd, _prop_get_connection_mptcp_flags(self, connection)); return l3cd; } @@ -12974,7 +12998,7 @@ _dev_ipac6_start(NMDevice *self) .router_solicitations = router_solicitations, .router_solicitation_interval = router_solicitation_interval, .ra_timeout = ra_timeout, - .ip6_privacy = _prop_get_ipv6_ip6_privacy(self), + .ip6_privacy = _prop_get_ipv6_ip6_privacy(self, connection), }; priv->ipac6_data.ndisc = nm_lndp_ndisc_new(&config); @@ -13161,7 +13185,6 @@ _dev_addrgenmode6_set(NMDevice *self, guint8 addr_gen_mode) if (!priv->addrgenmode6_data.previous_mode_has) { priv->addrgenmode6_data.previous_mode_has = TRUE; priv->addrgenmode6_data.previous_mode_val = cur_addr_gen_mode; - nm_assert(priv->addrgenmode6_data.previous_mode_val == cur_addr_gen_mode); } _LOGD_ip(AF_INET6, @@ -13650,7 +13673,7 @@ _dev_ipsharedx_cleanup(NMDevice *self, int addr_family) nm_clear_pointer(&priv->ipshared_data_4.v4.firewall_config, nm_firewall_config_free); } - nm_clear_pointer(&priv->ipshared_data_4.v4.shared_ip_handle, nm_netns_shared_ip_release); + nm_clear_pointer(&priv->ipshared_data_4.v4.ip_reservation, nm_netns_ip_reservation_release); nm_clear_l3cd(&priv->ipshared_data_4.v4.l3cd); _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_SHARED_4, NULL, FALSE); @@ -13684,13 +13707,14 @@ _dev_ipshared4_new_l3cd(NMDevice *self, NMConnection *connection, NMPlatformIP4A nm_ip_address_get_address_binary(user, &a); nm_platform_ip4_address_set_addr(&address, a, nm_ip_address_get_prefix(user)); - nm_clear_pointer(&priv->ipshared_data_4.v4.shared_ip_handle, nm_netns_shared_ip_release); + nm_clear_pointer(&priv->ipshared_data_4.v4.ip_reservation, nm_netns_ip_reservation_release); } else { - if (!priv->ipshared_data_4.v4.shared_ip_handle) - priv->ipshared_data_4.v4.shared_ip_handle = - nm_netns_shared_ip_reserve(nm_device_get_netns(self)); + if (!priv->ipshared_data_4.v4.ip_reservation) + priv->ipshared_data_4.v4.ip_reservation = + nm_netns_ip_reservation_get(nm_device_get_netns(self), + NM_NETNS_IP_RESERVATION_TYPE_SHARED4); nm_platform_ip4_address_set_addr(&address, - priv->ipshared_data_4.v4.shared_ip_handle->addr, + priv->ipshared_data_4.v4.ip_reservation->addr, 24); } @@ -14283,6 +14307,7 @@ can_reapply_change(NMDevice *self, NM_SETTING_CONNECTION_MDNS, NM_SETTING_CONNECTION_LLMNR, NM_SETTING_CONNECTION_DNS_OVER_TLS, + NM_SETTING_CONNECTION_DNSSEC, NM_SETTING_CONNECTION_MPTCP_FLAGS, NM_SETTING_CONNECTION_WAIT_ACTIVATION_DELAY); } @@ -14541,6 +14566,7 @@ check_and_reapply_connection(NMDevice *self, NM_SETTING_CONNECTION_MDNS, NM_SETTING_CONNECTION_LLMNR, NM_SETTING_CONNECTION_DNS_OVER_TLS, + NM_SETTING_CONNECTION_DNSSEC, NM_SETTING_CONNECTION_MPTCP_FLAGS)) { priv->ip_data_4.do_reapply = TRUE; priv->ip_data_6.do_reapply = TRUE; @@ -17285,6 +17311,25 @@ nm_device_cleanup(NMDevice *self, NMDeviceStateReason reason, CleanupType cleanu /* controller: release ports */ nm_device_controller_release_ports_all(self); + /* port: detach from controller */ + if (priv->controller) { + nm_device_controller_release_port(priv->controller, + self, + RELEASE_PORT_TYPE_CONFIG, + reason); + } + } + + /* port: mark no longer attached */ + if (priv->controller && priv->ifindex > 0 + && nm_platform_link_get_controller(nm_device_get_platform(self), priv->ifindex) <= 0) { + nm_device_controller_release_port(priv->controller, + self, + RELEASE_PORT_TYPE_NO_CONFIG, + NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); + } + + if (cleanup_type == CLEANUP_TYPE_DECONFIGURE) { /* Take out any entries in the routing table and any IP address the device had. */ if (ifindex > 0) { NMPlatform *platform = nm_device_get_platform(self); @@ -17308,15 +17353,6 @@ nm_device_cleanup(NMDevice *self, NMDeviceStateReason reason, CleanupType cleanu if (ifindex > 0) nm_platform_ip4_dev_route_blacklist_set(nm_device_get_platform(self), ifindex, NULL); - /* port: mark no longer attached */ - if (priv->controller && priv->ifindex > 0 - && nm_platform_link_get_controller(nm_device_get_platform(self), priv->ifindex) <= 0) { - nm_device_controller_release_port(priv->controller, - self, - RELEASE_PORT_TYPE_NO_CONFIG, - NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); - } - lldp_setup(self, NM_TERNARY_FALSE); nm_device_update_metered(self); diff --git a/src/core/devices/nm-device.h b/src/core/devices/nm-device.h index 8632944a..2f287953 100644 --- a/src/core/devices/nm-device.h +++ b/src/core/devices/nm-device.h @@ -853,4 +853,7 @@ void nm_routing_rules_sync(NMConnection *applied_connection, NMDevice *self, NMNetns *netns); +NML3ConfigData *nm_device_create_l3_config_data_from_connection(NMDevice *self, + NMConnection *connection); + #endif /* __NETWORKMANAGER_DEVICE_H__ */ diff --git a/src/core/devices/ovs/nm-ovsdb.c b/src/core/devices/ovs/nm-ovsdb.c index 1c9484c4..cb67848e 100644 --- a/src/core/devices/ovs/nm-ovsdb.c +++ b/src/core/devices/ovs/nm-ovsdb.c @@ -1890,7 +1890,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) == -1) { /* This doesn't really have to be an error; the key might * be missing if there really are no bridges present. */ - _LOGD("Bad update: %s", json_error.text); + _LOGD("monitor: bad update: %s", json_error.text); } if (ovs) { @@ -1936,12 +1936,12 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) &unused)) continue; - _LOGT("obj[iface:%s]: removed an '%s' interface: %s%s%s", - key, - ovs_interface->type, + _LOGT("monitor: %s: interface removed: type=%s, obj[iface:%s]%s%s", ovs_interface->name, + ovs_interface->type, + key, NM_PRINT_FMT_QUOTED2(ovs_interface->connection_uuid, - ", ", + ", connection=", ovs_interface->connection_uuid, "")); _signal_emit_device_removed(self, @@ -1989,17 +1989,18 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) gs_free char *strtmp1 = NULL; gs_free char *strtmp2 = NULL; - _LOGT("obj[iface:%s]: changed an '%s' interface: %s%s%s, external-ids=%s, " - "other-config=%s", - key, - type, - ovs_interface->name, - NM_PRINT_FMT_QUOTED2(ovs_interface->connection_uuid, - ", ", - ovs_interface->connection_uuid, - ""), - (strtmp1 = _strdict_to_string(ovs_interface->external_ids)), - (strtmp2 = _strdict_to_string(ovs_interface->other_config))); + _LOGT( + "monitor: %s: interface changed: type=%s, obj[iface:%s]%s%s, external-ids=%s, " + "other-config=%s", + ovs_interface->name, + type, + key, + NM_PRINT_FMT_QUOTED2(ovs_interface->connection_uuid, + ", connection=", + ovs_interface->connection_uuid, + ""), + (strtmp1 = _strdict_to_string(ovs_interface->external_ids)), + (strtmp2 = _strdict_to_string(ovs_interface->other_config))); } } else { gs_free char *strtmp1 = NULL; @@ -2015,17 +2016,17 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) .other_config = g_steal_pointer(&other_config_arr), }; g_hash_table_add(priv->interfaces, ovs_interface); - _LOGT( - "obj[iface:%s]: added an '%s' interface: %s%s%s, external-ids=%s, other-config=%s", - key, - ovs_interface->type, - ovs_interface->name, - NM_PRINT_FMT_QUOTED2(ovs_interface->connection_uuid, - ", ", - ovs_interface->connection_uuid, - ""), - (strtmp1 = _strdict_to_string(ovs_interface->external_ids)), - (strtmp2 = _strdict_to_string(ovs_interface->other_config))); + _LOGT("monitor: %s: interface added: type=%s, obj[iface:%s]%s%s, external-ids=%s, " + "other-config=%s", + ovs_interface->name, + ovs_interface->type, + key, + NM_PRINT_FMT_QUOTED2(ovs_interface->connection_uuid, + ", connection=", + ovs_interface->connection_uuid, + ""), + (strtmp1 = _strdict_to_string(ovs_interface->external_ids)), + (strtmp2 = _strdict_to_string(ovs_interface->other_config))); _signal_emit_device_added(self, ovs_interface->name, NM_DEVICE_TYPE_OVS_INTERFACE, @@ -2071,11 +2072,11 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) if (!g_hash_table_steal_extended(priv->ports, &key, (gpointer *) &ovs_port, &unused)) continue; - _LOGT("obj[port:%s]: removed a port: %s%s%s", - key, + _LOGT("monitor: %s: port removed: obj[port:%s]%s%s", ovs_port->name, + key, NM_PRINT_FMT_QUOTED2(ovs_port->connection_uuid, - ", ", + ", connection=", ovs_port->connection_uuid, "")); _signal_emit_device_removed(self, ovs_port->name, NM_DEVICE_TYPE_OVS_PORT, NULL); @@ -2122,15 +2123,16 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) gs_free char *strtmp1 = NULL; gs_free char *strtmp2 = NULL; - _LOGT("obj[port:%s]: changed a port: %s%s%s, external-ids=%s, other-config=%s", - key, - ovs_port->name, - NM_PRINT_FMT_QUOTED2(ovs_port->connection_uuid, - ", ", - ovs_port->connection_uuid, - ""), - (strtmp1 = _strdict_to_string(ovs_port->external_ids)), - (strtmp2 = _strdict_to_string(ovs_port->other_config))); + _LOGT( + "monitor: %s: port changed: obj[port:%s]%s%s, external-ids=%s, other-config=%s", + ovs_port->name, + key, + NM_PRINT_FMT_QUOTED2(ovs_port->connection_uuid, + ", connection=", + ovs_port->connection_uuid, + ""), + (strtmp1 = _strdict_to_string(ovs_port->external_ids)), + (strtmp2 = _strdict_to_string(ovs_port->other_config))); } } else { gs_free char *strtmp1 = NULL; @@ -2146,11 +2148,11 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) .other_config = g_steal_pointer(&other_config_arr), }; g_hash_table_add(priv->ports, ovs_port); - _LOGT("obj[port:%s]: added a port: %s%s%s, external-ids=%s, other-config=%s", - key, + _LOGT("monitor: %s: port added: obj[port:%s]%s%s, external-ids=%s, other-config=%s", ovs_port->name, + key, NM_PRINT_FMT_QUOTED2(ovs_port->connection_uuid, - ", ", + ", connection=", ovs_port->connection_uuid, ""), (strtmp1 = _strdict_to_string(ovs_port->external_ids)), @@ -2192,11 +2194,11 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) &unused)) continue; - _LOGT("obj[bridge:%s]: removed a bridge: %s%s%s", - key, + _LOGT("monitor: %s: bridge removed: obj[bridge:%s]%s%s", ovs_bridge->name, + key, NM_PRINT_FMT_QUOTED2(ovs_bridge->connection_uuid, - ", ", + ", connection=", ovs_bridge->connection_uuid, "")); _signal_emit_device_removed(self, ovs_bridge->name, NM_DEVICE_TYPE_OVS_BRIDGE, NULL); @@ -2243,11 +2245,12 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) gs_free char *strtmp1 = NULL; gs_free char *strtmp2 = NULL; - _LOGT("obj[bridge:%s]: changed a bridge: %s%s%s, external-ids=%s, other-config=%s", - key, + _LOGT("monitor: %s: bridge changed: obj[bridge:%s]%s%s, external-ids=%s, " + "other-config=%s", ovs_bridge->name, + key, NM_PRINT_FMT_QUOTED2(ovs_bridge->connection_uuid, - ", ", + ", connection=", ovs_bridge->connection_uuid, ""), (strtmp1 = _strdict_to_string(ovs_bridge->external_ids)), @@ -2267,11 +2270,11 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) .other_config = g_steal_pointer(&other_config_arr), }; g_hash_table_add(priv->bridges, ovs_bridge); - _LOGT("obj[bridge:%s]: added a bridge: %s%s%s, external-ids=%s, other-config=%s", - key, + _LOGT("monitor: %s: bridge added: obj[bridge:%s]%s%s, external-ids=%s, other-config=%s", ovs_bridge->name, + key, NM_PRINT_FMT_QUOTED2(ovs_bridge->connection_uuid, - ", ", + ", connection=", ovs_bridge->connection_uuid, ""), (strtmp1 = _strdict_to_string(ovs_bridge->external_ids)), diff --git a/src/core/devices/wifi/nm-device-wifi.c b/src/core/devices/wifi/nm-device-wifi.c index 148caa11..b41ed5e1 100644 --- a/src/core/devices/wifi/nm-device-wifi.c +++ b/src/core/devices/wifi/nm-device-wifi.c @@ -191,6 +191,9 @@ static void supplicant_iface_notify_p2p_available(NMSupplicantInterface *iface, GParamSpec *pspec, NMDeviceWifi *self); +static void supplicant_iface_notify_wpa_psk_mismatch_cb(NMSupplicantInterface *iface, + NMDeviceWifi *self); + static void periodic_update(NMDeviceWifi *self); static void ap_add_remove(NMDeviceWifi *self, @@ -624,6 +627,10 @@ supplicant_interface_acquire_cb(NMSupplicantManager *supplicant_manager, "notify::" NM_SUPPLICANT_INTERFACE_P2P_AVAILABLE, G_CALLBACK(supplicant_iface_notify_p2p_available), self); + g_signal_connect(priv->sup_iface, + NM_SUPPLICANT_INTERFACE_PSK_MISMATCH, + G_CALLBACK(supplicant_iface_notify_wpa_psk_mismatch_cb), + self); _scan_notify_is_scanning(self); @@ -2398,6 +2405,9 @@ handle_8021x_or_psk_auth_fail(NMDeviceWifi *self, g_return_val_if_fail(new_state == NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED, FALSE); + if (nm_device_get_state(device) != NM_DEVICE_STATE_CONFIG) + return FALSE; + req = nm_device_get_act_request(NM_DEVICE(self)); g_return_val_if_fail(req != NULL, FALSE); @@ -2841,6 +2851,34 @@ handle_auth_or_fail(NMDeviceWifi *self, NMActRequest *req, gboolean new_secrets) return TRUE; } +static void +supplicant_iface_notify_wpa_psk_mismatch_cb(NMSupplicantInterface *iface, NMDeviceWifi *self) +{ + NMDevice *device = NM_DEVICE(self); + NMActRequest *req; + const char *setting_name = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME; + + if (nm_device_get_state(device) != NM_DEVICE_STATE_CONFIG) + return; + + _LOGI(LOGD_DEVICE | LOGD_WIFI, + "Activation: (wifi) psk mismatch reported by supplicant, asking for new key"); + + req = nm_device_get_act_request(NM_DEVICE(self)); + g_return_if_fail(req != NULL); + + nm_act_request_clear_secrets(req); + + cleanup_association_attempt(self, TRUE); + nm_device_state_changed(device, + NM_DEVICE_STATE_NEED_AUTH, + NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); + wifi_secrets_get_secrets(self, + setting_name, + NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION + | NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW); +} + /* * supplicant_connection_timeout_cb * diff --git a/src/core/devices/wifi/nm-iwd-manager.c b/src/core/devices/wifi/nm-iwd-manager.c index 76a342e2..bb2e056d 100644 --- a/src/core/devices/wifi/nm-iwd-manager.c +++ b/src/core/devices/wifi/nm-iwd-manager.c @@ -684,7 +684,7 @@ iwd_config_write(GKeyFile *config, * in the last few filename characters -- it cannot end in .open, .psk * or .8021x. */ - return nm_utils_file_set_contents(filepath, data, length, 0600, times, NULL, error); + return nm_utils_file_set_contents(filepath, data, length, 0600, times, NULL, NULL, error); } static const char * diff --git a/src/core/devices/wwan/nm-modem-broadband.c b/src/core/devices/wwan/nm-modem-broadband.c index 018e5306..4bd0a45c 100644 --- a/src/core/devices/wwan/nm-modem-broadband.c +++ b/src/core/devices/wwan/nm-modem-broadband.c @@ -508,8 +508,9 @@ find_gsm_apn_cb(const char *apn, static gboolean try_create_connect_properties(NMModemBroadband *self) { - NMModemBroadbandPrivate *priv = NM_MODEM_BROADBAND_GET_PRIVATE(self); - ConnectContext *ctx = priv->ctx; + NMModemBroadbandPrivate *priv = NM_MODEM_BROADBAND_GET_PRIVATE(self); + ConnectContext *ctx = priv->ctx; + NMDeviceStateReason fail_reason = NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED; if (MODEM_CAPS_3GPP(ctx->caps)) { NMSettingGsm *s_gsm = nm_connection_get_setting_gsm(ctx->connection); @@ -522,7 +523,7 @@ try_create_connect_properties(NMModemBroadband *self) if (s_gsm) network_id = nm_setting_gsm_get_network_id(s_gsm); if (!network_id) { - if (mm_modem_get_state(self->_priv.modem_iface) < MM_MODEM_STATE_REGISTERED) + if (mm_modem_get_state(self->_priv.modem_iface) != MM_MODEM_STATE_REGISTERED) return FALSE; modem_3gpp = mm_object_get_modem_3gpp(priv->modem_object); network_id = mm_modem_3gpp_get_operator_code(modem_3gpp); @@ -530,6 +531,7 @@ try_create_connect_properties(NMModemBroadband *self) if (!network_id) { _LOGW("failed to connect '%s': unable to determine the network id", nm_connection_get_id(ctx->connection)); + fail_reason = NM_DEVICE_STATE_REASON_MODEM_NO_OPERATOR_CODE; goto out; } @@ -558,7 +560,7 @@ try_create_connect_properties(NMModemBroadband *self) } out: - nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED); + nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, fail_reason); connect_context_clear(self); return TRUE; } @@ -1649,6 +1651,8 @@ nm_modem_broadband_new(GObject *object, GError **error) driver, NM_MODEM_OPERATOR_CODE, operator_code, + NM_MODEM_DEVICE_UID, + mm_modem_get_device(modem_iface), NULL); } diff --git a/src/core/devices/wwan/nm-modem.c b/src/core/devices/wwan/nm-modem.c index c4852ea2..9d8f61c5 100644 --- a/src/core/devices/wwan/nm-modem.c +++ b/src/core/devices/wwan/nm-modem.c @@ -39,7 +39,8 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMModem, PROP_IP_TYPES, PROP_SIM_OPERATOR_ID, PROP_OPERATOR_CODE, - PROP_APN, ); + PROP_APN, + PROP_DEVICE_UID, ); enum { PPP_STATS, @@ -78,6 +79,7 @@ typedef struct _NMModemPrivate { char *sim_operator_id; char *operator_code; char *apn; + char *device_uid; NMPPPManager *ppp_manager; NMPppMgr *ppp_mgr; @@ -618,6 +620,12 @@ nm_modem_get_apn(NMModem *self) return NM_MODEM_GET_PRIVATE(self)->apn; } +const char * +nm_modem_get_device_uid(NMModem *self) +{ + return NM_MODEM_GET_PRIVATE(self)->device_uid; +} + /*****************************************************************************/ static void @@ -1121,6 +1129,22 @@ nm_modem_check_connection_compatible(NMModem *self, NMConnection *connection, GE } } + str = nm_setting_gsm_get_device_uid(s_gsm); + if (str) { + if (!priv->device_uid) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "GSM profile has device-uid, device does not"); + return FALSE; + } + if (!nm_streq(str, priv->device_uid)) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device has differing device-uid than GSM profile"); + return FALSE; + } + } + /* SIM properties may not be available before the SIM is unlocked, so * to ensure that autoconnect works, the connection's SIM properties * are only compared if present on the device. @@ -1644,6 +1668,9 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) case PROP_APN: g_value_set_string(value, priv->apn); break; + case PROP_DEVICE_UID: + g_value_set_string(value, priv->device_uid); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -1699,6 +1726,10 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps /* construct-only */ priv->operator_code = g_value_dup_string(value); break; + case PROP_DEVICE_UID: + /* construct-only */ + priv->device_uid = g_value_dup_string(value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -1758,6 +1789,7 @@ finalize(GObject *object) g_free(priv->sim_operator_id); g_free(priv->operator_code); g_free(priv->apn); + g_free(priv->device_uid); G_OBJECT_CLASS(nm_modem_parent_class)->finalize(object); } @@ -1863,6 +1895,13 @@ nm_modem_class_init(NMModemClass *klass) obj_properties[PROP_APN] = g_param_spec_string(NM_MODEM_APN, "", "", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_DEVICE_UID] = + g_param_spec_string(NM_MODEM_DEVICE_UID, + "", + "", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); signals[PPP_STATS] = g_signal_new(NM_MODEM_PPP_STATS, diff --git a/src/core/devices/wwan/nm-modem.h b/src/core/devices/wwan/nm-modem.h index 021d77b2..1f54b0b6 100644 --- a/src/core/devices/wwan/nm-modem.h +++ b/src/core/devices/wwan/nm-modem.h @@ -30,6 +30,7 @@ #define NM_MODEM_SIM_OPERATOR_ID "sim-operator-id" #define NM_MODEM_OPERATOR_CODE "operator-code" #define NM_MODEM_APN "apn" +#define NM_MODEM_DEVICE_UID "device-uid" /* Signals */ #define NM_MODEM_PPP_STATS "ppp-stats" @@ -154,6 +155,7 @@ const char *nm_modem_get_sim_id(NMModem *modem); const char *nm_modem_get_sim_operator_id(NMModem *modem); const char *nm_modem_get_operator_code(NMModem *modem); const char *nm_modem_get_apn(NMModem *modem); +const char *nm_modem_get_device_uid(NMModem *modem); gboolean nm_modem_set_data_port(NMModem *self, NMPlatform *platform, diff --git a/src/core/dns/nm-dns-dnsconfd.c b/src/core/dns/nm-dns-dnsconfd.c index 3789caf8..5f32f3fa 100644 --- a/src/core/dns/nm-dns-dnsconfd.c +++ b/src/core/dns/nm-dns-dnsconfd.c @@ -374,7 +374,7 @@ server_builder_append_base(GVariantBuilder *argument_builder, NMDnsServer dns_server; gsize addr_size; - if (!nm_dns_uri_parse(address_family, address_string, &dns_server)) + if (!nm_dns_uri_parse(address_family, address_string, &dns_server, NULL)) return FALSE; addr_size = nm_utils_addr_family_to_size(dns_server.addr_family); diff --git a/src/core/dns/nm-dns-dnsmasq.c b/src/core/dns/nm-dns-dnsmasq.c index 8e3c10c9..cc0a8788 100644 --- a/src/core/dns/nm-dns-dnsmasq.c +++ b/src/core/dns/nm-dns-dnsmasq.c @@ -521,9 +521,10 @@ _gl_pid_spawn_next_step(void) argv[argv_idx++] = "--no-resolv"; /* Use only commandline */ argv[argv_idx++] = "--keep-in-foreground"; argv[argv_idx++] = "--no-hosts"; /* don't use /etc/hosts to resolve */ - argv[argv_idx++] = "--bind-interfaces"; + argv[argv_idx++] = "--bind-dynamic"; argv[argv_idx++] = "--pid-file=" PIDFILE; - argv[argv_idx++] = "--listen-address=127.0.0.1"; /* Should work for both 4 and 6 */ + argv[argv_idx++] = "--listen-address=127.0.0.1"; + argv[argv_idx++] = "--listen-address=::1"; argv[argv_idx++] = "--cache-size=400"; argv[argv_idx++] = "--clear-on-reload"; /* clear cache when dns server changes */ argv[argv_idx++] = "--conf-file=/dev/null"; /* avoid loading /etc/dnsmasq.conf */ diff --git a/src/core/dns/nm-dns-manager.c b/src/core/dns/nm-dns-manager.c index 57e73226..c746e714 100644 --- a/src/core/dns/nm-dns-manager.c +++ b/src/core/dns/nm-dns-manager.c @@ -26,6 +26,7 @@ #include "libnm-core-intern/nm-core-internal.h" #include "libnm-glib-aux/nm-str-buf.h" +#include "libnm-glib-aux/nm-io-utils.h" #include "NetworkManagerUtils.h" #include "devices/nm-device.h" @@ -1006,7 +1007,8 @@ _read_link_cached(const char *path, gboolean *is_cached, char **cached) #define MY_RESOLV_CONF_TMP MY_RESOLV_CONF ".tmp" #define RESOLV_CONF_TMP "/etc/.resolv.conf.NetworkManager" -#define NO_STUB_RESOLV_CONF NMRUNDIR "/no-stub-resolv.conf" +#define NO_STUB_RESOLV_CONF NMRUNDIR "/no-stub-resolv.conf" +#define NO_STUB_RESOLV_CONF_TMP NMRUNDIR "/no-stub-resolv.conf.tmp" static void update_resolv_conf_no_stub(NMDnsManager *self, @@ -1019,7 +1021,14 @@ update_resolv_conf_no_stub(NMDnsManager *self, content = create_resolv_conf(searches, nameservers, options); - if (!g_file_set_contents(NO_STUB_RESOLV_CONF, content, -1, &local)) { + if (!nm_utils_file_set_contents(NO_STUB_RESOLV_CONF, + content, + -1, + 0644, + NULL, + NO_STUB_RESOLV_CONF_TMP, + NULL, + &local)) { _LOGD("update-resolv-no-stub: failure to write file: %s", local->message); g_error_free(local); return; diff --git a/src/core/dns/nm-dns-systemd-resolved.c b/src/core/dns/nm-dns-systemd-resolved.c index 0701a1dc..172bd0bc 100644 --- a/src/core/dns/nm-dns-systemd-resolved.c +++ b/src/core/dns/nm-dns-systemd-resolved.c @@ -37,6 +37,7 @@ static const char *const DBUS_OP_SET_LINK_DEFAULT_ROUTE = "SetLinkDefaultRoute"; static const char *const DBUS_OP_SET_LINK_DNS_OVER_TLS = "SetLinkDNSOverTLS"; static const char *const DBUS_OP_SET_LINK_DNS_EX = "SetLinkDNSEx"; +static const char *const DBUS_OP_SET_LINK_DNSSEC = "SetLinkDNSSEC"; /*****************************************************************************/ @@ -398,7 +399,7 @@ update_add_ip_config(NMDnsSystemdResolved *self, for (i = 0; i < n; i++) { NMDnsServer dns_server; - if (!nm_dns_uri_parse(ip_data->addr_family, strarr[i], &dns_server)) + if (!nm_dns_uri_parse(ip_data->addr_family, strarr[i], &dns_server, NULL)) continue; if (!NM_IN_SET(dns_server.scheme, @@ -484,9 +485,11 @@ prepare_one_interface(NMDnsSystemdResolved *self, const InterfaceConfig *ic) NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT; NMSettingConnectionLlmnr llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT; NMSettingConnectionDnsOverTls dns_over_tls = NM_SETTING_CONNECTION_DNS_OVER_TLS_DEFAULT; + NMSettingConnectionDnssec dnssec = NM_SETTING_CONNECTION_DNSSEC_DEFAULT; const char *mdns_arg = NULL; const char *llmnr_arg = NULL; const char *dns_over_tls_arg = NULL; + const char *dnssec_arg = NULL; gboolean has_config = FALSE; gboolean has_default_route = FALSE; guint i; @@ -517,6 +520,7 @@ prepare_one_interface(NMDnsSystemdResolved *self, const InterfaceConfig *ic) llmnr = NM_MAX(llmnr, nm_l3_config_data_get_llmnr(ip_data->l3cd)); dns_over_tls = NM_MAX(dns_over_tls, nm_l3_config_data_get_dns_over_tls(ip_data->l3cd)); + dnssec = NM_MAX(dnssec, nm_l3_config_data_get_dnssec(ip_data->l3cd)); } } } @@ -589,8 +593,24 @@ prepare_one_interface(NMDnsSystemdResolved *self, const InterfaceConfig *ic) } nm_assert(dns_over_tls_arg); + switch (dnssec) { + case NM_SETTING_CONNECTION_DNSSEC_NO: + dnssec_arg = "no"; + break; + case NM_SETTING_CONNECTION_DNSSEC_ALLOW_DOWNGRADE: + dnssec_arg = "allow-downgrade"; + break; + case NM_SETTING_CONNECTION_DNSSEC_YES: + dnssec_arg = "yes"; + break; + case NM_SETTING_CONNECTION_DNSSEC_DEFAULT: + dnssec_arg = ""; + break; + } + nm_assert(dnssec_arg); + if (!nm_str_is_empty(mdns_arg) || !nm_str_is_empty(llmnr_arg) - || !nm_str_is_empty(dns_over_tls_arg)) + || !nm_str_is_empty(dns_over_tls_arg) || !nm_str_is_empty(dnssec_arg)) has_config = TRUE; _request_item_append(self, "SetLinkDomains", ic->ifindex, g_variant_builder_end(&domains)); @@ -618,6 +638,10 @@ prepare_one_interface(NMDnsSystemdResolved *self, const InterfaceConfig *ic) DBUS_OP_SET_LINK_DNS_OVER_TLS, ic->ifindex, g_variant_new("(is)", ic->ifindex, dns_over_tls_arg ?: "")); + _request_item_append(self, + DBUS_OP_SET_LINK_DNSSEC, + ic->ifindex, + g_variant_new("(is)", ic->ifindex, dnssec_arg ?: "")); return has_config; } diff --git a/src/core/main-utils.c b/src/core/main-utils.c index 0f62da29..d1be6814 100644 --- a/src/core/main-utils.c +++ b/src/core/main-utils.c @@ -81,7 +81,7 @@ nm_main_utils_write_pidfile(const char *pidfile) char pid[16]; nm_sprintf_buf(pid, "%lld", (long long) getpid()); - if (!nm_utils_file_set_contents(pidfile, pid, -1, 00644, NULL, NULL, &error)) { + if (!nm_utils_file_set_contents(pidfile, pid, -1, 00644, NULL, NULL, NULL, &error)) { fprintf(stderr, _("Writing to %s failed: %s\n"), pidfile, error->message); return FALSE; } diff --git a/src/core/main.c b/src/core/main.c index 4c7de6cd..8d519c00 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -339,7 +339,7 @@ main(int argc, char *argv[]) char *path, *slash; int g; - /* exe is <basedir>/src/.libs/lt-NetworkManager, so chop off + /* exe is <builddir>/src/core/NetworkManager, so chop off * the last three components */ path = realpath("/proc/self/exe", NULL); g_assert(path != NULL); diff --git a/src/core/ndisc/nm-lndp-ndisc.c b/src/core/ndisc/nm-lndp-ndisc.c index f0de2fd5..c19dcc91 100644 --- a/src/core/ndisc/nm-lndp-ndisc.c +++ b/src/core/ndisc/nm-lndp-ndisc.c @@ -19,6 +19,7 @@ #include "libnm-systemd-shared/nm-sd-utils-shared.h" #include "nm-l3cfg.h" #include "nm-ndisc-private.h" +#include "nm-core-utils.h" #define _NMLOG_PREFIX_NAME "ndisc-lndp" @@ -27,6 +28,14 @@ typedef struct { struct ndp *ndp; GSource *event_source; + + struct { + NMRateLimit pio_lft; + NMRateLimit mtu; + NMRateLimit omit_prefix; + NMRateLimit omit_dns; + NMRateLimit omit_dnssl; + } msg_ratelimit; } NMLndpNDiscPrivate; /*****************************************************************************/ @@ -49,6 +58,36 @@ G_DEFINE_TYPE(NMLndpNDisc, nm_lndp_ndisc, NM_TYPE_NDISC) /*****************************************************************************/ +/* + * If we log a message about an invalid RA packet, don't repeat the same message + * at every packet received or sent. Rate limit the message to 6 every 12 hours + * per type and per ndisc instance. + */ + +#define LOG_INV_RA_WINDOW (12 * 3600) +#define LOG_INV_RA_BURST 6 + +#define _LOG_INVALID_RA(ndisc, rate_limit, ...) \ + G_STMT_START \ + { \ + NMNDisc *__ndisc = (ndisc); \ + NMRateLimit *__rl = (rate_limit); \ + const char *__ifname = nm_ndisc_get_ifname(__ndisc); \ + \ + if (__ifname && nm_logging_enabled(LOGL_WARN, LOGD_IP6) \ + && nm_rate_limit_check(__rl, LOG_INV_RA_WINDOW, LOG_INV_RA_BURST)) { \ + nm_log(LOGL_WARN, \ + LOGD_IP6, \ + __ifname, \ + NULL, \ + "ndisc (%s): " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + __ifname _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + } \ + G_STMT_END + +/*****************************************************************************/ + static gboolean send_rs(NMNDisc *ndisc, GError **error) { @@ -113,6 +152,7 @@ static int receive_ra(struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) { NMNDisc *ndisc = (NMNDisc *) user_data; + NMLndpNDiscPrivate *priv = NM_LNDP_NDISC_GET_PRIVATE(ndisc); NMNDiscDataInternal *rdata = ndisc->rdata; NMNDiscConfigMap changed = 0; NMNDiscGateway gateway; @@ -229,7 +269,11 @@ receive_ra(struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) * log a system management error in this case. */ if (preferred_time > valid_time) { - _LOGW("skipping PIO - preferred lifetime > valid lifetime"); + _LOG_INVALID_RA( + ndisc, + &priv->msg_ratelimit.pio_lft, + "ignoring Prefix Information Option with invalid lifetimes in received IPv6 " + "router advertisement"); continue; } @@ -349,7 +393,11 @@ receive_ra(struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) * Kernel would set it, but would flush out all IPv6 addresses away * from the link, even the link-local, and we wouldn't be able to * listen for further RAs that could fix the MTU. */ - _LOGW("MTU too small for IPv6 ignored: %d", mtu); + _LOG_INVALID_RA(ndisc, + &priv->msg_ratelimit.mtu, + "ignoring too small MTU %u in received IPv6 " + "router advertisement", + mtu); } } @@ -445,8 +493,11 @@ send_ra(NMNDisc *ndisc, GError **error) prefix = _ndp_msg_add_option(msg, sizeof(*prefix)); if (!prefix) { - /* Maybe we could sent separate RAs, but why bother... */ - _LOGW("The RA is too big, had to omit some some prefixes."); + /* Maybe we could send separate RAs, but why bother... */ + _LOG_INVALID_RA( + ndisc, + &priv->msg_ratelimit.omit_prefix, + "the outgoing IPv6 router advertisement is too big: omitting some prefixes"); break; } @@ -475,7 +526,10 @@ send_ra(NMNDisc *ndisc, GError **error) option = _ndp_msg_add_option(msg, len); if (!option) { - _LOGW("The RA is too big, had to omit DNS information."); + _LOG_INVALID_RA( + ndisc, + &priv->msg_ratelimit.omit_dns, + "the outgoing IPv6 router advertisement is too big: omitting DNS information"); goto dns_servers_done; } @@ -553,7 +607,10 @@ dns_servers_done: nm_assert(len / 8u >= 2u); if (len / 8u >= 256u || !(option = _ndp_msg_add_option(msg, len))) { - _LOGW("The RA is too big, had to omit DNS search list."); + _LOG_INVALID_RA( + ndisc, + &priv->msg_ratelimit.omit_dnssl, + "the outgoing IPv6 router advertisement is too big: omitting DNS search list"); goto dns_domains_done; } diff --git a/src/core/nm-connectivity.c b/src/core/nm-connectivity.c index 2aa22331..c7915fd9 100644 --- a/src/core/nm-connectivity.c +++ b/src/core/nm-connectivity.c @@ -77,6 +77,8 @@ struct _NMConnectivityCheckHandle { ConConfig *con_config; GCancellable *resolve_cancellable; + int resolve_ifindex; + GDBusConnection *dbus_connection; CURLM *curl_mhandle; CURL *curl_ehandle; struct curl_slist *request_headers; @@ -953,6 +955,113 @@ systemd_resolved_resolve_cb(GObject *object, GAsyncResult *res, gpointer user_da do_curl_request(cb_data, nm_str_buf_get_str(&strbuf_hosts)); } +static void +systemd_resolved_resolve(NMConnectivityCheckHandle *cb_data) +{ + _LOG2D("start request to '%s' (try resolving '%s' using systemd-resolved with ifindex %d)", + cb_data->concheck.con_config->uri, + cb_data->concheck.con_config->host, + cb_data->concheck.resolve_ifindex); + + g_dbus_connection_call(cb_data->concheck.dbus_connection, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + "org.freedesktop.resolve1.Manager", + "ResolveHostname", + g_variant_new("(isit)", + (gint32) cb_data->concheck.resolve_ifindex, + cb_data->concheck.con_config->host, + (gint32) cb_data->addr_family, + SD_RESOLVED_DNS), + G_VARIANT_TYPE("(a(iiay)st)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + cb_data->concheck.resolve_cancellable, + systemd_resolved_resolve_cb, + cb_data); +} + +static void +systemd_resolved_link_scopes_cb(GObject *object, GAsyncResult *res, gpointer user_data) +{ + NMConnectivityCheckHandle *cb_data; + gs_unref_variant GVariant *result = NULL; + gs_unref_variant GVariant *value = NULL; + gs_free_error GError *error = NULL; + guint64 scope_mask = 0; + + result = g_dbus_connection_call_finish(G_DBUS_CONNECTION(object), res, &error); + if (nm_utils_error_is_cancelled(error)) + return; + + cb_data = user_data; + + if (!result) { + _LOG2D("unable to obtain systemd-resolved link ScopesMask for interface %d: %s", + cb_data->concheck.resolve_ifindex, + error->message); + + cb_data->concheck.resolve_ifindex = 0; + systemd_resolved_resolve(cb_data); + return; + } + + g_variant_get(result, "(v)", &value); + g_variant_get(value, "t", &scope_mask); + + if (!(scope_mask & SD_RESOLVED_DNS)) { + /* there is no per-link DNS configured / active; query all available / + * system DNS resolvers instead of restricting the lookup to just this + * one, which would turn up no results. */ + _LOG2D("no per-link DNS available (scope mask %" G_GUINT64_FORMAT + "); falling back to system-wide lookups", + scope_mask); + cb_data->concheck.resolve_ifindex = 0; + } + + systemd_resolved_resolve(cb_data); +} + +static void +systemd_resolved_get_link_cb(GObject *object, GAsyncResult *res, gpointer user_data) +{ + NMConnectivityCheckHandle *cb_data; + gs_unref_variant GVariant *result = NULL; + gs_free char *link_path = NULL; + gs_free_error GError *error = NULL; + + result = g_dbus_connection_call_finish(G_DBUS_CONNECTION(object), res, &error); + if (nm_utils_error_is_cancelled(error)) + return; + + cb_data = user_data; + + if (!result) { + _LOG2D("unable to obtain systemd-resolved link D-Bus object for interface %d: %s", + cb_data->concheck.resolve_ifindex, + error->message); + + cb_data->concheck.resolve_ifindex = 0; + systemd_resolved_resolve(cb_data); + return; + } + + g_variant_get(result, "(o)", &link_path); + + g_dbus_connection_call(cb_data->concheck.dbus_connection, + "org.freedesktop.resolve1", + link_path, + "org.freedesktop.DBus.Properties", + "Get", + g_variant_new("(ss)", "org.freedesktop.resolve1.Link", "ScopesMask"), + G_VARIANT_TYPE("(v)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + cb_data->concheck.resolve_cancellable, + systemd_resolved_link_scopes_cb, + cb_data); +} + static NMConnectivityState check_platform_config(NMConnectivity *self, NMPlatform *platform, @@ -1067,6 +1176,7 @@ nm_connectivity_check_start(NMConnectivity *self, } cb_data->concheck.resolve_cancellable = g_cancellable_new(); + cb_data->concheck.resolve_ifindex = ifindex; /* note that we pick up support for systemd-resolved right away when we need it. * We don't need to remember the setting, because we can (cheaply) check anew @@ -1089,10 +1199,8 @@ nm_connectivity_check_start(NMConnectivity *self, has_systemd_resolved = !!nm_dns_manager_get_systemd_resolved(nm_dns_manager_get()); if (has_systemd_resolved) { - GDBusConnection *dbus_connection; - - dbus_connection = NM_MAIN_DBUS_CONNECTION_GET; - if (!dbus_connection) { + cb_data->concheck.dbus_connection = NM_MAIN_DBUS_CONNECTION_GET; + if (!cb_data->concheck.dbus_connection) { /* we have no D-Bus connection? That might happen in configure and quit mode. * * Anyway, something is very odd, just fail connectivity check. */ @@ -1103,25 +1211,19 @@ nm_connectivity_check_start(NMConnectivity *self, return cb_data; } - g_dbus_connection_call(dbus_connection, + /* first check whether there has been a per-link DNS configured */ + g_dbus_connection_call(cb_data->concheck.dbus_connection, "org.freedesktop.resolve1", "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", - "ResolveHostname", - g_variant_new("(isit)", - 0, - cb_data->concheck.con_config->host, - (gint32) cb_data->addr_family, - SD_RESOLVED_DNS), - G_VARIANT_TYPE("(a(iiay)st)"), + "GetLink", + g_variant_new("(i)", ifindex), + G_VARIANT_TYPE("(o)"), G_DBUS_CALL_FLAGS_NONE, -1, cb_data->concheck.resolve_cancellable, - systemd_resolved_resolve_cb, + systemd_resolved_get_link_cb, cb_data); - _LOG2D("start request to '%s' (try resolving '%s' using systemd-resolved)", - cb_data->concheck.con_config->uri, - cb_data->concheck.con_config->host); return cb_data; } diff --git a/src/core/nm-core-utils.c b/src/core/nm-core-utils.c index 4a7f760d..deac04e7 100644 --- a/src/core/nm-core-utils.c +++ b/src/core/nm-core-utils.c @@ -2865,6 +2865,7 @@ _host_id_read(guint8 **out_host_id, gsize *out_host_id_len) 0600, NULL, NULL, + NULL, &error)) { nm_log_warn( LOGD_CORE, @@ -5162,6 +5163,14 @@ helper_have_data(int fd, GIOCondition condition, gpointer user_data) n_read = nm_utils_fd_read(fd, &info->in_buffer); _LOG2T(info, "read returns %ld", (long) n_read); + if (info->in_buffer.len > 32 * 1024 * 1024) { + helper_complete(info, + g_error_new_literal(NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + "the output is larger than 32MiB")); + return G_SOURCE_CONTINUE; + } + if (n_read > 0) return G_SOURCE_CONTINUE; @@ -5504,6 +5513,155 @@ nm_utils_shorten_hostname(const char *hostname, char **shortened) return TRUE; } +/** + * nm_utils_connection_supported: + * @connection: the connection + * @error: on return, the reason why the connection in not supported + * + * Returns whether the given connection is supported by this version + * of NetworkManager. + */ +gboolean +nm_utils_connection_supported(NMConnection *connection, GError **error) +{ + const char *type; + const char *feature = NULL; + + g_return_val_if_fail(connection, FALSE); + g_return_val_if_fail(!error || !*error, FALSE); + + type = nm_connection_get_connection_type(connection); + + if (!WITH_TEAMDCTL) { + NMSettingConnection *s_con; + + if (nm_streq0(type, NM_SETTING_TEAM_SETTING_NAME)) { + feature = "team"; + goto out_disabled; + } + + /* Match team ports */ + if ((s_con = nm_connection_get_setting_connection(connection)) + && nm_streq0(nm_setting_connection_get_port_type(s_con), + NM_SETTING_TEAM_SETTING_NAME)) { + feature = "team"; + goto out_disabled; + } + } + + if (!WITH_OPENVSWITCH) { + if (NM_IN_STRSET(type, + NM_SETTING_OVS_BRIDGE_SETTING_NAME, + NM_SETTING_OVS_PORT_SETTING_NAME, + NM_SETTING_OVS_INTERFACE_SETTING_NAME)) { + feature = "Open vSwitch"; + goto out_disabled; + } + + /* Match OVS system interfaces */ + if (nm_connection_get_setting_ovs_interface(connection)) { + feature = "Open vSwitch"; + goto out_disabled; + } + } + + if (!WITH_WIFI + && NM_IN_STRSET(type, + NM_SETTING_WIRELESS_SETTING_NAME, + NM_SETTING_OLPC_MESH_SETTING_NAME, + NM_SETTING_WIFI_P2P_SETTING_NAME)) { + feature = "Wi-Fi"; + goto out_disabled; + } + + if (!WITH_WWAN + && NM_IN_STRSET(type, NM_SETTING_GSM_SETTING_NAME, NM_SETTING_CDMA_SETTING_NAME)) { + feature = "WWAN"; + goto out_disabled; + } + + if (nm_streq0(type, NM_SETTING_WIMAX_SETTING_NAME)) { + feature = "WiMAX"; + goto out_removed; + } + + return TRUE; + +out_disabled: + nm_assert(feature); + g_set_error(error, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_FEATURE_DISABLED, + "%s support is disabled in this build", + feature); + return FALSE; + +out_removed: + nm_assert(feature); + g_set_error(error, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_FEATURE_REMOVED, + "%s is no longer supported", + feature); + return FALSE; +} + +/*****************************************************************************/ + +/** + * nm_rate_limit_check(): + * @rate_limit: the NMRateLimit instance + * @window_sec: the time window in seconds, between 1 and 864000 (ten days) + * @burst: the number of max allowed event occurrences in the given time + * window + * + * The function rate limits an event. Call it multiple times with the + * same @window_sec, and @burst values. + * + * Returns: TRUE if the event is allowed, FALSE if it is rate-limited + */ +gboolean +nm_rate_limit_check(NMRateLimit *rate_limit, gint32 window_sec, gint32 burst) +{ + gint64 now; + gint64 old_ts_msec; + gint64 window_msec; + gint64 capacity; + gint64 elapsed; + + nm_assert(window_sec >= 1 && window_sec <= 864000); + nm_assert(burst >= 1); + + /* This implements a simple token bucket algorithm. For each millisecond, + * refill "burst" tokens. Thus, during a full time window we + * refill (window_msec * burst) tokens. Each event consumes @window_msec + * tokens. */ + + window_msec = (gint64) window_sec * NM_UTILS_MSEC_PER_SEC; + capacity = window_msec * (gint64) burst; + old_ts_msec = rate_limit->ts_msec; + now = nm_utils_get_monotonic_timestamp_msec(); + rate_limit->ts_msec = now; + + elapsed = now - old_ts_msec; + if (old_ts_msec == 0 || elapsed > window_msec) { + /* On the first call, or in case a whole window passed, (re)start with + * a full budget */ + rate_limit->tokens = capacity; + } else { + rate_limit->tokens += elapsed * (gint64) burst; + rate_limit->tokens = NM_MIN(rate_limit->tokens, capacity); + } + + /* Consume the tokens */ + if (rate_limit->tokens >= window_msec) { + rate_limit->tokens -= window_msec; + return TRUE; + } + + return FALSE; +} + const char * nm_utils_get_connection_first_permissions_user(NMConnection *connection) { diff --git a/src/core/nm-core-utils.h b/src/core/nm-core-utils.h index 224018c6..cccccae6 100644 --- a/src/core/nm-core-utils.h +++ b/src/core/nm-core-utils.h @@ -494,6 +494,19 @@ gid_t nm_utils_get_nm_gid(void); /*****************************************************************************/ +gboolean nm_utils_connection_supported(NMConnection *connection, GError **error); + +/*****************************************************************************/ + +typedef struct { + gint64 ts_msec; + gint64 tokens; +} NMRateLimit; + +gboolean nm_rate_limit_check(NMRateLimit *rate_limit, gint32 window_sec, gint32 burst); + +/*****************************************************************************/ + const char *nm_utils_get_connection_first_permissions_user(NMConnection *connection); /*****************************************************************************/ diff --git a/src/core/nm-l3-config-data.c b/src/core/nm-l3-config-data.c index 666aa8a3..328f59b6 100644 --- a/src/core/nm-l3-config-data.c +++ b/src/core/nm-l3-config-data.c @@ -120,6 +120,7 @@ struct _NML3ConfigData { NMSettingConnectionMdns mdns; NMSettingConnectionLlmnr llmnr; NMSettingConnectionDnsOverTls dns_over_tls; + NMSettingConnectionDnssec dnssec; NMUtilsIPv6IfaceId ip6_token; NML3ConfigDatFlags flags; @@ -577,6 +578,16 @@ nm_l3_config_data_log(const NML3ConfigData *self, NULL))); } + if (self->dnssec != NM_SETTING_CONNECTION_DNSSEC_DEFAULT) { + gs_free char *s = NULL; + + _L("dnssec: %s", + (s = _nm_utils_enum_to_str_full(nm_setting_connection_dnssec_get_type(), + self->dnssec, + " ", + NULL))); + } + if (self->mptcp_flags != NM_MPTCP_FLAGS_NONE) { gs_free char *s = NULL; @@ -694,6 +705,7 @@ nm_l3_config_data_new(NMDedupMultiIndex *multi_idx, int ifindex, NMIPConfigSourc .mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT, .llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT, .dns_over_tls = NM_SETTING_CONNECTION_DNS_OVER_TLS_DEFAULT, + .dnssec = NM_SETTING_CONNECTION_DNSSEC_DEFAULT, .flags = NM_L3_CONFIG_DAT_FLAGS_NONE, .metered = NM_TERNARY_DEFAULT, .proxy_browser_only = NM_TERNARY_DEFAULT, @@ -1767,6 +1779,26 @@ nm_l3_config_data_set_dns_over_tls(NML3ConfigData *self, NMSettingConnectionDnsO return TRUE; } +NMSettingConnectionDnssec +nm_l3_config_data_get_dnssec(const NML3ConfigData *self) +{ + nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); + + return self->dnssec; +} + +gboolean +nm_l3_config_data_set_dnssec(NML3ConfigData *self, NMSettingConnectionDnssec dnssec) +{ + nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); + + if (self->dnssec == dnssec) + return FALSE; + + self->dnssec = dnssec; + return TRUE; +} + NMIPRouteTableSyncMode nm_l3_config_data_get_route_table_sync(const NML3ConfigData *self, int addr_family) { @@ -2446,6 +2478,7 @@ nm_l3_config_data_cmp_full(const NML3ConfigData *a, NM_CMP_DIRECT(a->mdns, b->mdns); NM_CMP_DIRECT(a->llmnr, b->llmnr); NM_CMP_DIRECT(a->dns_over_tls, b->dns_over_tls); + NM_CMP_DIRECT(a->dnssec, b->dnssec); } if (NM_FLAGS_HAS(flags, NM_L3_CONFIG_CMP_FLAGS_OTHER)) { @@ -3211,6 +3244,12 @@ nm_l3_config_data_hash_dns(const NML3ConfigData *l3cd, empty = FALSE; } + val = nm_l3_config_data_get_dnssec(l3cd); + if (val != NM_SETTING_CONNECTION_DNSSEC_DEFAULT) { + g_checksum_update(sum, (const guint8 *) &val, sizeof(val)); + empty = FALSE; + } + if (!empty) { int prio = 0; @@ -3461,6 +3500,9 @@ nm_l3_config_data_merge(NML3ConfigData *self, if (self->dns_over_tls == NM_SETTING_CONNECTION_DNS_OVER_TLS_DEFAULT) self->dns_over_tls = src->dns_over_tls; + if (self->dnssec == NM_SETTING_CONNECTION_DNSSEC_DEFAULT) + self->dnssec = src->dnssec; + if (self->ip6_token.id == 0) self->ip6_token.id = src->ip6_token.id; diff --git a/src/core/nm-l3-config-data.h b/src/core/nm-l3-config-data.h index 265e126d..4102b6e1 100644 --- a/src/core/nm-l3-config-data.h +++ b/src/core/nm-l3-config-data.h @@ -458,6 +458,10 @@ NMSettingConnectionDnsOverTls nm_l3_config_data_get_dns_over_tls(const NML3Confi gboolean nm_l3_config_data_set_dns_over_tls(NML3ConfigData *self, NMSettingConnectionDnsOverTls dns_over_tls); +NMSettingConnectionDnssec nm_l3_config_data_get_dnssec(const NML3ConfigData *self); + +gboolean nm_l3_config_data_set_dnssec(NML3ConfigData *self, NMSettingConnectionDnssec dnssec); + NMIPRouteTableSyncMode nm_l3_config_data_get_route_table_sync(const NML3ConfigData *self, int addr_family); diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c index 1797cd0f..0d93f76b 100644 --- a/src/core/nm-l3cfg.c +++ b/src/core/nm-l3cfg.c @@ -40,8 +40,7 @@ G_STATIC_ASSERT(NM_ACD_TIMEOUT_RFC5227_MSEC == N_ACD_TIMEOUT_RFC5227); #define ACD_SUPPORTED_ETH_ALEN ETH_ALEN #define ACD_ENSURE_RATELIMIT_MSEC ((guint32) 4000u) -#define ACD_WAIT_PROBING_EXTRA_TIME_MSEC ((guint32) (1000u + ACD_ENSURE_RATELIMIT_MSEC)) -#define ACD_WAIT_PROBING_EXTRA_TIME2_MSEC ((guint32) 1000u) +#define ACD_WAIT_PROBING_EXTRA_TIME_MSEC ((guint32) (2000u + ACD_ENSURE_RATELIMIT_MSEC)) #define ACD_WAIT_TIME_PROBING_FULL_RESTART_MSEC ((guint32) 30000u) #define ACD_WAIT_TIME_CONFLICT_RESTART_MSEC ((guint32) 120000u) #define ACD_WAIT_TIME_ANNOUNCE_RESTART_MSEC ((guint32) 30000u) @@ -2740,9 +2739,8 @@ handle_init: nm_utils_get_monotonic_timestamp_msec_cached(p_now_msec); if (acd_data->info.state == NM_L3_ACD_ADDR_STATE_PROBING) { - if ((*p_now_msec) > acd_data->probing_timestamp_msec - + ACD_WAIT_PROBING_EXTRA_TIME_MSEC - + ACD_WAIT_PROBING_EXTRA_TIME2_MSEC) { + if ((*p_now_msec) + > acd_data->probing_timestamp_msec + ACD_WAIT_PROBING_EXTRA_TIME_MSEC) { /* hm. We failed to create a new probe too long. Something is really wrong * internally, but let's ignore the issue and assume the address is good. What * else would we do? Assume the address is USED? */ @@ -2948,7 +2946,7 @@ handle_init: nm_utils_get_monotonic_timestamp_msec_cached(p_now_msec); if (acd_data->probing_timestamp_msec + acd_data->probing_timeout_msec - + ACD_WAIT_PROBING_EXTRA_TIME_MSEC + ACD_WAIT_PROBING_EXTRA_TIME2_MSEC + + ACD_WAIT_PROBING_EXTRA_TIME_MSEC >= (*p_now_msec)) { /* The probing already started quite a while ago. We ignore the link event * and let the probe come to it's natural end. */ @@ -3058,9 +3056,10 @@ handle_start_probing: } _LOGT_acd(acd_data, - "%sstart probing (timeout %u msec, %s)", + "%sstart probing (timeout %u msec, ebpf %s; %s)", orig_state == NM_L3_ACD_ADDR_STATE_INIT ? "" : "re", acd_data->probing_timeout_msec, + n_acd_has_bpf(self->priv.p->nacd) ? "enabled" : "disabled", log_reason); return; } @@ -3155,10 +3154,11 @@ handle_start_defending: } _LOGT_acd(acd_data, - "start announcing (defend=%s) (probe created)", + "start announcing (defend=%s) (probe created with ebpf %s)", _l3_acd_defend_type_to_string(acd_data->acd_defend_type_current, sbuf256, - sizeof(sbuf256))); + sizeof(sbuf256)), + n_acd_has_bpf(self->priv.p->nacd) ? "enabled" : "disabled"); acd_data->acd_defend_type_is_active = FALSE; acd_data->nacd_probe = probe; return; @@ -3989,7 +3989,7 @@ _l3cfg_routed_dns_apply(NML3Cfg *self, const NML3ConfigData *l3cd) NMDnsServer dns; int r; - if (!nm_dns_uri_parse(addr_family, nameservers[i], &dns)) + if (!nm_dns_uri_parse(addr_family, nameservers[i], &dns, NULL)) continue; /* Find the gateway to the DNS over the current interface. When @@ -5054,8 +5054,8 @@ _l3_commit_mptcp_af(NML3Cfg *self, (NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_SIGNAL) ? MPTCP_PM_ADDR_FLAG_SIGNAL : 0) | (NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_SUBFLOW) ? MPTCP_PM_ADDR_FLAG_SUBFLOW : 0) | (NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_BACKUP) ? MPTCP_PM_ADDR_FLAG_BACKUP : 0) - | (NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_FULLMESH) ? MPTCP_PM_ADDR_FLAG_FULLMESH - : 0); + | (NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_FULLMESH) ? MPTCP_PM_ADDR_FLAG_FULLMESH : 0) + | (NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_LAMINAR) ? MPTCP_PM_ADDR_FLAG_LAMINAR : 0); NMPlatformMptcpAddr a = { .ifindex = self->priv.ifindex, .id = 0, diff --git a/src/core/nm-netns.c b/src/core/nm-netns.c index f481bc36..f55d1132 100644 --- a/src/core/nm-netns.c +++ b/src/core/nm-netns.c @@ -68,7 +68,7 @@ typedef struct { NMPNetns *platform_netns; NMPGlobalTracker *global_tracker; GHashTable *l3cfgs; - GHashTable *shared_ips; + GHashTable *ip_reservation[_NM_NETNS_IP_RESERVATION_TYPE_NUM]; GHashTable *ecmp_track_by_obj; GHashTable *ecmp_track_by_ecmpid; @@ -571,106 +571,150 @@ notify_watcher: /*****************************************************************************/ -NMNetnsSharedIPHandle * -nm_netns_shared_ip_reserve(NMNetns *self) -{ - NMNetnsPrivate *priv; - NMNetnsSharedIPHandle *handle; - const in_addr_t addr_start = ntohl(0x0a2a0001u); /* 10.42.0.1 */ - in_addr_t addr; - char sbuf_addr[NM_INET_ADDRSTRLEN]; +typedef struct { + const char *name; + guint32 start_addr; /* host byte order */ + guint prefix_len; + guint num_addrs; + gboolean allow_reuse; +} IPReservationTypeDesc; + +static const IPReservationTypeDesc ip_reservation_types[_NM_NETNS_IP_RESERVATION_TYPE_NUM] = { + [NM_NETNS_IP_RESERVATION_TYPE_SHARED4] = + { + .name = "shared-ip4", + .start_addr = 0x0a2a0001, /* 10.42.0.1 */ + .prefix_len = 24, + .num_addrs = 256, + .allow_reuse = TRUE, + }, +}; - /* Find an unused address in the 10.42.x.x range */ +NMNetnsIPReservation * +nm_netns_ip_reservation_get(NMNetns *self, NMNetnsIPReservationType type) +{ + NMNetnsPrivate *priv; + const IPReservationTypeDesc *desc; + NMNetnsIPReservation *res; + GHashTable **table; + in_addr_t addr; + char buf[NM_INET_ADDRSTRLEN]; g_return_val_if_fail(NM_IS_NETNS(self), NULL); + g_return_val_if_fail(type < _NM_NETNS_IP_RESERVATION_TYPE_NUM, NULL); - priv = NM_NETNS_GET_PRIVATE(self); + priv = NM_NETNS_GET_PRIVATE(self); + desc = &ip_reservation_types[type]; + table = &priv->ip_reservation[type]; - if (!priv->shared_ips) { - addr = addr_start; - priv->shared_ips = g_hash_table_new(nm_puint32_hash, nm_puint32_equal); + if (!*table) { + addr = htonl(desc->start_addr); + *table = g_hash_table_new(nm_puint32_hash, nm_puint32_equal); g_object_ref(self); } else { guint32 count; - nm_assert(g_hash_table_size(priv->shared_ips) > 0); + nm_assert(g_hash_table_size(*table) > 0); + nm_assert(desc->prefix_len > 0 && desc->prefix_len <= 32); count = 0u; for (;;) { - addr = addr_start + htonl(count << 8u); + addr = htonl(desc->start_addr + (count << (32 - desc->prefix_len))); - handle = g_hash_table_lookup(priv->shared_ips, &addr); - if (!handle) + res = g_hash_table_lookup(*table, &addr); + if (!res) break; count++; - if (count > 0xFFu) { - if (handle->_ref_count == 1) { - _LOGE("shared-ip4: ran out of shared IP addresses. Reuse %s/24", - nm_inet4_ntop(handle->addr, sbuf_addr)); + if (count >= desc->num_addrs) { + if (!desc->allow_reuse) { + _LOGE("%s: ran out of IP addresses", desc->name); + return NULL; + } + + if (res->_ref_count == 1) { + _LOGE("%s: ran out of IP addresses. Reuse %s/%u", + desc->name, + nm_inet4_ntop(res->addr, buf), + desc->prefix_len); } else { - _LOGD("shared-ip4: reserved IP address range %s/24 (duplicate)", - nm_inet4_ntop(handle->addr, sbuf_addr)); + _LOGD("%s: reserved IP address %s/%u (duplicate)", + desc->name, + nm_inet4_ntop(res->addr, buf), + desc->prefix_len); } - handle->_ref_count++; - return handle; + res->_ref_count++; + return res; } } } - handle = g_slice_new(NMNetnsSharedIPHandle); - *handle = (NMNetnsSharedIPHandle) { + res = g_slice_new(NMNetnsIPReservation); + *res = (NMNetnsIPReservation) { .addr = addr, ._ref_count = 1, ._self = self, + ._type = type, }; - g_hash_table_add(priv->shared_ips, handle); + g_hash_table_add(*table, res); - _LOGD("shared-ip4: reserved IP address range %s/24", nm_inet4_ntop(handle->addr, sbuf_addr)); - return handle; + _LOGD("%s: reserved IP address %s/%u", + desc->name, + nm_inet4_ntop(res->addr, buf), + desc->prefix_len); + return res; } void -nm_netns_shared_ip_release(NMNetnsSharedIPHandle *handle) +nm_netns_ip_reservation_release(NMNetnsIPReservation *res) { - NMNetns *self; - NMNetnsPrivate *priv; - char sbuf_addr[NM_INET_ADDRSTRLEN]; - - g_return_if_fail(handle); + NMNetns *self; + NMNetnsPrivate *priv; + const IPReservationTypeDesc *desc; + GHashTable **table; + char buf[NM_INET_ADDRSTRLEN]; - self = handle->_self; + g_return_if_fail(res); + g_return_if_fail(res->_type < _NM_NETNS_IP_RESERVATION_TYPE_NUM); + self = res->_self; g_return_if_fail(NM_IS_NETNS(self)); - priv = NM_NETNS_GET_PRIVATE(self); - - nm_assert(handle->_ref_count > 0); - nm_assert(handle == nm_g_hash_table_lookup(priv->shared_ips, handle)); - - if (handle->_ref_count > 1) { - nm_assert(handle->addr == ntohl(0x0A2AFF01u)); /* 10.42.255.1 */ - handle->_ref_count--; - _LOGD("shared-ip4: release IP address range %s/24 (%d more references held)", - nm_inet4_ntop(handle->addr, sbuf_addr), - handle->_ref_count); + priv = NM_NETNS_GET_PRIVATE(self); + desc = &ip_reservation_types[res->_type]; + table = &priv->ip_reservation[res->_type]; + + nm_assert(res->_ref_count > 0); + nm_assert(res == nm_g_hash_table_lookup(*table, res)); + + if (res->_ref_count > 1) { + nm_assert(desc->allow_reuse); + res->_ref_count--; + _LOGD("%s: release IP address reservation %s/%u (%d more references held)", + desc->name, + nm_inet4_ntop(res->addr, buf), + desc->prefix_len, + res->_ref_count); return; } - if (!g_hash_table_remove(priv->shared_ips, handle)) + if (!g_hash_table_remove(*table, res)) nm_assert_not_reached(); - if (g_hash_table_size(priv->shared_ips) == 0) { - nm_clear_pointer(&priv->shared_ips, g_hash_table_unref); + _LOGD("%s: release IP address reservation %s/%u", + desc->name, + nm_inet4_ntop(res->addr, buf), + desc->prefix_len); + + if (g_hash_table_size(*table) == 0) { + nm_clear_pointer(table, g_hash_table_unref); g_object_unref(self); } - _LOGD("shared-ip4: release IP address range %s/24", nm_inet4_ntop(handle->addr, sbuf_addr)); - - handle->_self = NULL; - nm_g_slice_free(handle); + res->_self = NULL; + nm_g_slice_free(res); } /*****************************************************************************/ @@ -1560,11 +1604,14 @@ dispose(GObject *object) nm_assert(nm_g_hash_table_size(priv->l3cfgs) == 0); nm_assert(c_list_is_empty(&priv->l3cfg_signal_pending_lst_head)); - nm_assert(!priv->shared_ips); nm_assert(nm_g_hash_table_size(priv->watcher_idx) == 0); nm_assert(nm_g_hash_table_size(priv->watcher_by_tag_idx) == 0); nm_assert(nm_g_hash_table_size(priv->watcher_ip_data_idx) == 0); + for (guint i = 0; i < _NM_NETNS_IP_RESERVATION_TYPE_NUM; i++) { + nm_assert(!priv->ip_reservation[i]); + } + nm_clear_pointer(&priv->ecmp_track_by_obj, g_hash_table_destroy); nm_clear_pointer(&priv->ecmp_track_by_ecmpid, g_hash_table_destroy); diff --git a/src/core/nm-netns.h b/src/core/nm-netns.h index 43e9c781..5ddb852a 100644 --- a/src/core/nm-netns.h +++ b/src/core/nm-netns.h @@ -41,15 +41,22 @@ NML3Cfg *nm_netns_l3cfg_acquire(NMNetns *netns, int ifindex); /*****************************************************************************/ +typedef enum { + NM_NETNS_IP_RESERVATION_TYPE_SHARED4, + + _NM_NETNS_IP_RESERVATION_TYPE_NUM, +} NMNetnsIPReservationType; + typedef struct { - in_addr_t addr; - int _ref_count; - NMNetns *_self; -} NMNetnsSharedIPHandle; + in_addr_t addr; + int _ref_count; + NMNetnsIPReservationType _type; + NMNetns *_self; +} NMNetnsIPReservation; -NMNetnsSharedIPHandle *nm_netns_shared_ip_reserve(NMNetns *self); +NMNetnsIPReservation *nm_netns_ip_reservation_get(NMNetns *self, NMNetnsIPReservationType type); -void nm_netns_shared_ip_release(NMNetnsSharedIPHandle *handle); +void nm_netns_ip_reservation_release(NMNetnsIPReservation *reservation); /*****************************************************************************/ diff --git a/src/core/nm-policy.c b/src/core/nm-policy.c index 0288795e..f7be1a9f 100644 --- a/src/core/nm-policy.c +++ b/src/core/nm-policy.c @@ -2353,7 +2353,10 @@ device_state_changed(NMDevice *device, } if (sett_conn) { /* Reset auto retries back to default since connection was successful */ - nm_manager_devcon_autoconnect_retries_reset(priv->manager, device, sett_conn); + nm_manager_devcon_autoconnect_reset_reconnect_all(priv->manager, + device, + sett_conn, + FALSE); } /* Since there is no guarantee that device_l3cd_changed() is called diff --git a/src/core/platform/tests/monitor.c b/src/core/platform/tests/monitor.c index c83192bb..f413facf 100644 --- a/src/core/platform/tests/monitor.c +++ b/src/core/platform/tests/monitor.c @@ -186,6 +186,7 @@ ip_again: 00644, NULL, NULL, + NULL, NULL); nm_log_dbg(LOGD_PLATFORM, "dump to file complete"); diff --git a/src/core/platform/tests/test-link.c b/src/core/platform/tests/test-link.c index fab6bd2e..77e7e641 100644 --- a/src/core/platform/tests/test-link.c +++ b/src/core/platform/tests/test-link.c @@ -123,7 +123,8 @@ software_add(NMLinkType link_type, const char *name) gboolean bond0_exists = !!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "bond0"); int r; const NMPlatformLnkBond nm_platform_lnk_bond_default = { - .mode = nmtst_rand_select(3, 1), + .mode = nmtst_rand_select(3, 1), + .use_carrier = 1, }; r = nm_platform_link_bond_add(NM_PLATFORM_GET, name, &nm_platform_lnk_bond_default, NULL); diff --git a/src/core/platform/tests/test-route.c b/src/core/platform/tests/test-route.c index f8f7070b..fbad2447 100644 --- a/src/core/platform/tests/test-route.c +++ b/src/core/platform/tests/test-route.c @@ -624,6 +624,79 @@ test_ip4_zero_gateway(void) } static void +test_via(void) +{ + int ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, DEVICE_NAME); + GPtrArray *routes; + NMPlatformIP4Route rts[1]; + struct in6_addr gateway6; + const int metric = 22987; + NMPlatformIP4Route route4; + guint mss = 1000; + in_addr_t net4; + + /* Test IPv4 routes with a IPv6 gateway (using RTA_VIA attribute) */ + + inet_pton(AF_INET6, "fd01::1", &gateway6); + inet_pton(AF_INET, "1.2.3.4", &net4); + + /* Add direct route to IPv6 gateway: ip route add dev $DEV fd01::1/128 */ + nmtstp_ip6_route_add(NM_PLATFORM_GET, + ifindex, + NM_IP_CONFIG_SOURCE_USER, + gateway6, + 128, + in6addr_any, + in6addr_any, + metric, + mss); + g_assert(nmtstp_ip6_route_get(NM_PLATFORM_GET, ifindex, &gateway6, 128, metric, NULL, 0)); + + /* Add IPv4 route via IPv6 gateway: ip route add dev $DEV 1.2.3.4/32 via inet6 fd01::1 */ + route4 = (NMPlatformIP4Route) { + .ifindex = ifindex, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + .network = net4, + .plen = 32, + .metric = metric, + .via.addr_family = AF_INET6, + .via.addr.addr6 = gateway6, + .mss = mss, + }; + g_assert(NMTST_NM_ERR_SUCCESS( + nm_platform_ip4_route_add(NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, &route4, NULL))); + g_assert(nmtstp_ip4_route_get(NM_PLATFORM_GET, ifindex, net4, 32, metric, 0)); + + /* Test route listing */ + routes = nmtstp_ip4_route_get_all(NM_PLATFORM_GET, ifindex); + g_assert_cmpint(routes->len, ==, 1); + + memset(rts, 0, sizeof(rts)); + rts[0].rt_source = nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER); + rts[0].scope_inv = nm_platform_route_scope_inv(RT_SCOPE_LINK); + rts[0].network = net4; + rts[0].plen = 32; + rts[0].ifindex = ifindex; + rts[0].gateway = INADDR_ANY; + rts[0].metric = metric; + rts[0].mss = mss; + rts[0].via.addr_family = AF_INET6; + rts[0].via.addr.addr6 = gateway6; + rts[0].n_nexthops = 1; + nmtst_platform_ip4_routes_equal_aptr((const NMPObject *const *) routes->pdata, + rts, + routes->len, + TRUE); + g_ptr_array_unref(routes); + + /* Delete routes */ + g_assert(nmtstp_platform_ip6_route_delete(NM_PLATFORM_GET, ifindex, gateway6, 128, metric)); + g_assert(!nmtstp_ip6_route_get(NM_PLATFORM_GET, ifindex, &gateway6, 128, metric, NULL, 0)); + g_assert(nmtstp_platform_ip4_route_delete(NM_PLATFORM_GET, ifindex, net4, 32, metric)); + g_assert(!nmtstp_ip4_route_get(NM_PLATFORM_GET, ifindex, net4, 32, metric, 0)); +} + +static void test_ip4_route_options(gconstpointer test_data) { const int TEST_IDX = GPOINTER_TO_INT(test_data); @@ -2421,6 +2494,7 @@ _nmtstp_setup_tests(void) add_test_func("/route/ip4_route_get", test_ip4_route_get); add_test_func("/route/ip6_route_get", test_ip6_route_get); add_test_func("/route/ip4_zero_gateway", test_ip4_zero_gateway); + add_test_func("/route/via", test_via); } if (nmtstp_is_root_test()) { diff --git a/src/core/settings/nm-settings-storage.h b/src/core/settings/nm-settings-storage.h index 65750152..8847acc3 100644 --- a/src/core/settings/nm-settings-storage.h +++ b/src/core/settings/nm-settings-storage.h @@ -27,6 +27,19 @@ struct _NMSettingsPlugin; +/** + * NMSettingsStorage: + * @_plugin: The settings plugin that provides this storage. + * @_uuid: UUID of the profile represented by this storage. + * @_filename: Backing filename (can be NULL for in-memory or meta-data). + * @_storage_lst: Node in the per-plugin storage list. + * @_storage_by_uuid_lst: Node in the per-UUID storage list. + * + * Describes the origin and identity of one profile instance as provided by a + * specific settings plugin and (optionally) a backing file. A single UUID may + * have multiple storages from different plugins; plugin order determines + * priority. + */ typedef struct NMSettingsStorage { GObject parent; struct _NMSettingsPlugin *_plugin; diff --git a/src/core/settings/nm-settings.c b/src/core/settings/nm-settings.c index 50d98ece..702c53d5 100644 --- a/src/core/settings/nm-settings.c +++ b/src/core/settings/nm-settings.c @@ -76,6 +76,17 @@ static NM_CACHED_QUARK_FCN("default-wired-connection-blocked", /*****************************************************************************/ +/** + * StorageData: + * @sd_lst: Node used in per-UUID storage lists. + * @storage: Storage provider instance for this UUID. + * @connection: Connection object backed by @storage, or NULL for meta-data. + * @prioritize: Request to prioritize this storage during merge. + * + * Per-UUID storage entry used to accumulate and merge updates from plugins. + * Items live temporarily in the dirty list and are merged into the current list + * with stable priority ordering. + */ typedef struct _StorageData { CList sd_lst; NMSettingsStorage *storage; @@ -165,6 +176,20 @@ _storage_data_is_alive(StorageData *sd) /*****************************************************************************/ +/** + * SettConnEntry: + * @uuid: Normalized UUID key for this entry (points to @_uuid_data). + * @sett_conn: Current NMSettingsConnection selected for @uuid, or NULL. + * @storage: The storage that currently owns @sett_conn, or NULL. + * @sd_lst_head: Head of current storages list for @uuid (high to low priority). + * @dirty_sd_lst_head: Head of pending storage updates to merge. + * @sce_dirty_lst: Node in the global dirty queue. + * @_uuid_data: Inline storage backing @uuid. + * + * Tracks one connection profile across all storages and its dirty state. + * It holds the authoritative in-memory connection and the sets of storages + * providing or updating it. + */ typedef struct { const char *uuid; NMSettingsConnection *sett_conn; @@ -1368,10 +1393,11 @@ _connection_changed_track(NMSettings *self, NMConnection *connection, gboolean prioritize) { - NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE(self); - SettConnEntry *sett_conn_entry; - StorageData *sd; - const char *uuid; + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE(self); + SettConnEntry *sett_conn_entry; + StorageData *sd; + const char *uuid; + gs_free_error GError *error = NULL; nm_assert_valid_settings_storage(NULL, storage); @@ -1382,6 +1408,17 @@ _connection_changed_track(NMSettings *self, || (_nm_connection_verify(connection, NULL) == NM_SETTING_VERIFY_SUCCESS)); nm_assert(!connection || nm_streq0(uuid, nm_connection_get_uuid(connection))); + if (connection && !nm_utils_connection_supported(connection, &error)) { + _LOGD("storage[%s," NM_SETTINGS_STORAGE_PRINT_FMT + "]: ignoring connection \"%s\" from file \"%s\": %s", + uuid, + NM_SETTINGS_STORAGE_PRINT_ARG(storage), + nm_connection_get_id(connection), + nm_settings_storage_get_filename(storage), + error->message); + connection = NULL; + } + nm_assert_connection_unchanging(connection); sett_conn_entry = @@ -1851,6 +1888,9 @@ nm_settings_add_connection(NMSettings *self, NM_SET_OUT(out_sett_conn, NULL); + if (!nm_utils_connection_supported(connection, error)) + return FALSE; + uuid = nm_connection_get_uuid(connection); sett_conn_entry = _sett_conn_entries_get(self, uuid); diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index 1e2e2d92..b9e3f919 100644 --- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -2056,8 +2056,9 @@ make_ip4_setting(shvarFile *ifcfg, * Pick up just IPv4 addresses (IPv6 addresses are taken by make_ip6_setting()) */ for (i = 1; i < 10000; i++) { - NMDnsServer dns; - char tag[256]; + NMDnsServer dns; + char tag[256]; + gs_free_error GError *local = NULL; numbered_tag(tag, "DNS", i); nm_clear_g_free(&value); @@ -2065,12 +2066,13 @@ make_ip4_setting(shvarFile *ifcfg, if (!v) break; - if (!nm_dns_uri_parse(AF_UNSPEC, v, &dns)) { + if (!nm_dns_uri_parse(AF_UNSPEC, v, &dns, &local)) { g_set_error(error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid DNS server address '%s'", - v); + "Invalid DNS server address '%s': %s", + v, + local->message); return NULL; } @@ -2607,8 +2609,9 @@ make_ip6_setting(shvarFile *ifcfg, shvarFile *network_ifcfg, gboolean routes_rea * Pick up just IPv6 addresses (IPv4 addresses are taken by make_ip4_setting()) */ for (i = 1; i < 10000; i++) { - NMDnsServer dns; - char tag[256]; + gs_free_error GError *err = NULL; + NMDnsServer dns; + char tag[256]; numbered_tag(tag, "DNS", i); nm_clear_g_free(&value); @@ -2616,14 +2619,15 @@ make_ip6_setting(shvarFile *ifcfg, shvarFile *network_ifcfg, gboolean routes_rea if (!v) break; - if (!nm_dns_uri_parse(AF_UNSPEC, v, &dns)) { + if (!nm_dns_uri_parse(AF_UNSPEC, v, &dns, &err)) { if (is_disabled) continue; g_set_error(error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid DNS server address '%s'", - v); + "Invalid DNS server address '%s': %s", + v, + err->message); return NULL; } if (dns.addr_family == AF_INET6) { diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index 39cbddc5..21908090 100644 --- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -320,6 +320,7 @@ write_blobs(GHashTable *blobs, GError **error) 0600, NULL, NULL, + NULL, &write_error)) { g_set_error(error, NM_SETTINGS_ERROR, @@ -3626,6 +3627,14 @@ do_write_construct(NMConnection *connection, write_ip_routing_rules(connection, ifcfg, route_ignore); + if (nm_setting_connection_get_dnssec(s_con) != NM_SETTING_CONNECTION_DNSSEC_DEFAULT) { + set_error_unsupported(error, + connection, + NM_SETTING_CONNECTION_SETTING_NAME "." NM_SETTING_CONNECTION_DNSSEC, + TRUE); + return FALSE; + } + write_connection_setting(s_con, ifcfg, interface_name); NM_SET_OUT(out_ifcfg, g_steal_pointer(&ifcfg)); diff --git a/src/core/settings/plugins/keyfile/nms-keyfile-utils.c b/src/core/settings/plugins/keyfile/nms-keyfile-utils.c index 7c0e329e..26fb3441 100644 --- a/src/core/settings/plugins/keyfile/nms-keyfile-utils.c +++ b/src/core/settings/plugins/keyfile/nms-keyfile-utils.c @@ -280,6 +280,7 @@ nms_keyfile_nmmeta_write(const char *dirname, length, 0600, NULL, + NULL, &errsv, NULL)) { NM_SET_OUT(out_full_filename, g_steal_pointer(&full_filename_tmp)); diff --git a/src/core/settings/plugins/keyfile/nms-keyfile-writer.c b/src/core/settings/plugins/keyfile/nms-keyfile-writer.c index b1dd2e44..c7c88260 100644 --- a/src/core/settings/plugins/keyfile/nms-keyfile-writer.c +++ b/src/core/settings/plugins/keyfile/nms-keyfile-writer.c @@ -133,6 +133,7 @@ cert_writer(NMConnection *connection, 0600, NULL, NULL, + NULL, &local); if (success) { /* Write the path value to the keyfile. @@ -384,7 +385,14 @@ _internal_write_connection(NMConnection *connection, } } - nm_utils_file_set_contents(path, kf_content_buf, kf_content_len, 0600, NULL, NULL, &local_err); + nm_utils_file_set_contents(path, + kf_content_buf, + kf_content_len, + 0600, + NULL, + NULL, + NULL, + &local_err); if (local_err) { g_set_error(error, NM_SETTINGS_ERROR, diff --git a/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_GSM b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_GSM index 2f6dc26c..eec403cb 100644 --- a/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_GSM +++ b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_GSM @@ -8,6 +8,7 @@ timestamp=305415219 [gsm] apn=internet2.voicestream.com device-id=da812de91eec16620b06cd0ca5cbc7ea25245222 +device-uid=MODEM1 home-only=true network-id=254098 password=parliament2 diff --git a/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c b/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c index df5dfd40..badb40d3 100644 --- a/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c +++ b/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c @@ -1408,6 +1408,8 @@ test_write_gsm_connection(void) "89148000000060671234", NM_SETTING_GSM_SIM_OPERATOR_ID, "310260", + NM_SETTING_GSM_DEVICE_UID, + "MODEM1", NULL); write_test_connection_and_reread(connection, TRUE, TEST_KEYFILES_DIR "/Test_Write_GSM"); diff --git a/src/core/supplicant/nm-supplicant-config.c b/src/core/supplicant/nm-supplicant-config.c index 56cc832b..233afe48 100644 --- a/src/core/supplicant/nm-supplicant-config.c +++ b/src/core/supplicant/nm-supplicant-config.c @@ -206,20 +206,30 @@ nm_supplicant_config_add_blob(NMSupplicantConfig *self, ConfigOption *old_opt; ConfigOption *opt; NMSupplOptType type; - const guint8 *data; gsize data_len; + gs_free char *full_value = NULL; g_return_val_if_fail(NM_IS_SUPPLICANT_CONFIG(self), FALSE); g_return_val_if_fail(key != NULL, FALSE); g_return_val_if_fail(value != NULL, FALSE); g_return_val_if_fail(blobid != NULL, FALSE); - data = g_bytes_get_data(value, &data_len); + g_bytes_get_data(value, &data_len); g_return_val_if_fail(data_len > 0, FALSE); - priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE(self); + if (data_len > 32 * 1024 * 1024) { + g_set_error(error, + NM_SUPPLICANT_ERROR, + NM_SUPPLICANT_ERROR_CONFIG, + "blob '%s' is larger than 32MiB", + key); + return FALSE; + } + + priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE(self); + full_value = g_strdup_printf("blob://%s", blobid); - type = nm_supplicant_settings_verify_setting(key, (const char *) data, data_len); + type = nm_supplicant_settings_verify_setting(key, full_value, strlen(full_value)); if (type == NM_SUPPL_OPT_TYPE_INVALID) { g_set_error(error, NM_SUPPLICANT_ERROR, @@ -240,7 +250,7 @@ nm_supplicant_config_add_blob(NMSupplicantConfig *self, } opt = g_slice_new0(ConfigOption); - opt->value = g_strdup_printf("blob://%s", blobid); + opt->value = g_steal_pointer(&full_value); opt->len = strlen(opt->value); opt->type = type; @@ -521,6 +531,7 @@ get_ap_params(guint freq, case NM_SETTING_WIRELESS_CHANNEL_WIDTH_80MHZ: { guint channel; + guint center_channel = 0; if (freq < 5000) { /* the setting is not valid */ @@ -530,12 +541,29 @@ get_ap_params(guint freq, /* Determine the center channel according to the table at * https://en.wikipedia.org/wiki/List_of_WLAN_channels */ + channel = (freq - 5000) / 5; - channel = ((channel / 4 - 1) / 4) * 16 + 10; - *out_ht40 = 1; - *out_max_oper_chwidth = 1; - *out_center_freq = 5000 + 5 * channel; + if (channel >= 36 && channel <= 48) + center_channel = 42; + else if (channel >= 52 && channel <= 64) + center_channel = 58; + else if (channel >= 100 && channel <= 112) + center_channel = 106; + else if (channel >= 116 && channel <= 128) + center_channel = 122; + else if (channel >= 132 && channel <= 144) + center_channel = 138; + else if (channel >= 149 && channel <= 161) + center_channel = 155; + else if (channel >= 165 && channel <= 177) + center_channel = 171; + + if (center_channel) { + *out_ht40 = 1; + *out_max_oper_chwidth = 1; + *out_center_freq = 5000 + 5 * center_channel; + } return; } @@ -1016,7 +1044,7 @@ nm_supplicant_config_add_setting_wireless_security(NMSupplicantConfig if (_get_capability(priv, NM_SUPPL_CAP_TYPE_SAE) && _get_capability(priv, NM_SUPPL_CAP_TYPE_PMF) && _get_capability(priv, NM_SUPPL_CAP_TYPE_BIP) - && (!is_ap || pmf != NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE)) { + && (pmf != NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE)) { g_string_append(key_mgmt_conf, " SAE"); if (!is_ap && _get_capability(priv, NM_SUPPL_CAP_TYPE_FT)) g_string_append(key_mgmt_conf, " FT-SAE"); diff --git a/src/core/supplicant/nm-supplicant-interface.c b/src/core/supplicant/nm-supplicant-interface.c index ef72447a..5c60a7b6 100644 --- a/src/core/supplicant/nm-supplicant-interface.c +++ b/src/core/supplicant/nm-supplicant-interface.c @@ -66,6 +66,7 @@ enum { WPS_CREDENTIALS, /* WPS credentials received */ GROUP_STARTED, /* a new Group (interface) was created */ GROUP_FINISHED, /* a Group (interface) has been finished */ + PSK_MISMATCH, /* supplicant reported incorrect PSK */ LAST_SIGNAL }; @@ -3232,6 +3233,10 @@ _signal_handle(NMSupplicantInterface *self, return; } + if (nm_streq(signal_name, "PskMismatch")) { + g_signal_emit(self, signals[PSK_MISMATCH], 0); + return; + } return; } @@ -3864,4 +3869,14 @@ nm_supplicant_interface_class_init(NMSupplicantInterfaceClass *klass) G_TYPE_NONE, 1, G_TYPE_STRING); + + signals[PSK_MISMATCH] = g_signal_new(NM_SUPPLICANT_INTERFACE_PSK_MISMATCH, + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 0); } diff --git a/src/core/supplicant/nm-supplicant-interface.h b/src/core/supplicant/nm-supplicant-interface.h index b8d9b013..961de1b1 100644 --- a/src/core/supplicant/nm-supplicant-interface.h +++ b/src/core/supplicant/nm-supplicant-interface.h @@ -86,6 +86,7 @@ typedef enum { #define NM_SUPPLICANT_INTERFACE_WPS_CREDENTIALS "wps-credentials" #define NM_SUPPLICANT_INTERFACE_GROUP_STARTED "group-started" #define NM_SUPPLICANT_INTERFACE_GROUP_FINISHED "group-finished" +#define NM_SUPPLICANT_INTERFACE_PSK_MISMATCH "wpa-psk-mismatch" typedef struct _NMSupplicantInterfaceClass NMSupplicantInterfaceClass; diff --git a/src/core/tests/meson.build b/src/core/tests/meson.build index 78c689f7..31acad94 100644 --- a/src/core/tests/meson.build +++ b/src/core/tests/meson.build @@ -6,6 +6,7 @@ test_units = [ 'test-core', 'test-core-with-expect', 'test-dcb', + 'test-netns', 'test-l3cfg', 'test-utils', 'test-wired-defname', diff --git a/src/core/tests/test-netns.c b/src/core/tests/test-netns.c new file mode 100644 index 00000000..26ecbcb8 --- /dev/null +++ b/src/core/tests/test-netns.c @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "src/core/nm-default-daemon.h" + +#include "nm-netns.h" +#include "nm-test-utils-core.h" + +static void +test_ip_reservation_shared4(void) +{ + gs_unref_object NMPlatform *platform = NULL; + gs_unref_object NMNetns *netns = NULL; + NMNetnsIPReservation *res[256]; + NMNetnsIPReservation *res1; + NMNetnsIPReservation *res2; + char buf[NM_INET_ADDRSTRLEN]; + guint i; + + platform = g_object_ref(NM_PLATFORM_GET); + netns = nm_netns_new(platform); + + /* Allocate addresses from 10.42.0.1 to 10.42.255.1 */ + for (i = 0; i < 256; i++) { + res[i] = nm_netns_ip_reservation_get(netns, NM_NETNS_IP_RESERVATION_TYPE_SHARED4); + g_snprintf(buf, sizeof(buf), "10.42.%u.1", i); + nmtst_assert_ip4_address(res[i]->addr, buf); + g_assert_cmpint(res[i]->_ref_count, ==, 1); + } + + /* Release an address and get it back */ + nm_netns_ip_reservation_release(res[139]); + res[139] = nm_netns_ip_reservation_get(netns, NM_NETNS_IP_RESERVATION_TYPE_SHARED4); + nmtst_assert_ip4_address(res[139]->addr, "10.42.139.1"); + + /* Reuse 10.42.255.1 once */ + NMTST_EXPECT_NM_ERROR("netns[*]: shared-ip4: ran out of IP addresses. Reuse 10.42.255.1/24"); + res1 = nm_netns_ip_reservation_get(netns, NM_NETNS_IP_RESERVATION_TYPE_SHARED4); + g_test_assert_expected_messages(); + nmtst_assert_ip4_address(res1->addr, "10.42.255.1"); + g_assert_cmpint(res1->_ref_count, ==, 2); + + /* Reuse 10.42.255.1 twice */ + res2 = nm_netns_ip_reservation_get(netns, NM_NETNS_IP_RESERVATION_TYPE_SHARED4); + g_assert(res2 == res1); + nmtst_assert_ip4_address(res1->addr, "10.42.255.1"); + g_assert_cmpint(res2->_ref_count, ==, 3); + + /* Release all */ + nm_netns_ip_reservation_release(res1); + nm_netns_ip_reservation_release(res2); + for (i = 0; i < 256; i++) { + nm_netns_ip_reservation_release(res[i]); + } +} + +/*****************************************************************************/ + +NMTST_DEFINE(); + +int +main(int argc, char **argv) +{ + nmtst_init_with_logging(&argc, &argv, NULL, "ALL"); + nm_linux_platform_setup(); + + g_test_add_func("/netns/ip_reservation/shared4", test_ip_reservation_shared4); + + return g_test_run(); +} diff --git a/src/core/tests/test-utils.c b/src/core/tests/test-utils.c index 2bcb6f69..0418d3ae 100644 --- a/src/core/tests/test-utils.c +++ b/src/core/tests/test-utils.c @@ -261,6 +261,70 @@ test_shorten_hostname(void) } /*****************************************************************************/ +typedef struct { + NMRateLimit ratelimit; + GMainLoop *loop; + GSource *source; + guint num; +} RateLimitData; + +static int +rate_limit_window_expire_cb(gpointer user_data) +{ + RateLimitData *data = user_data; + + g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5)); + g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5)); + g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5)); + g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5)); + g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5)); + + g_assert(!nm_rate_limit_check(&data->ratelimit, 1, 5)); + g_assert(!nm_rate_limit_check(&data->ratelimit, 1, 5)); + + nm_clear_g_source_inst(&data->source); + g_main_loop_quit(data->loop); + + return G_SOURCE_CONTINUE; +} + +static int +rate_limit_check_cb(gpointer user_data) +{ + RateLimitData *data = user_data; + + g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5)); + g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5)); + g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5)); + g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5)); + g_assert(nm_rate_limit_check(&data->ratelimit, 1, 5)); + + g_assert(!nm_rate_limit_check(&data->ratelimit, 1, 5)); + g_assert(!nm_rate_limit_check(&data->ratelimit, 1, 5)); + + nm_clear_g_source_inst(&data->source); + data->source = nm_g_timeout_add_source(1000, rate_limit_window_expire_cb, data); + + return G_SOURCE_CONTINUE; +} + +static void +test_rate_limit_check(void) +{ + RateLimitData data; + + data = (RateLimitData) { + .loop = g_main_loop_new(NULL, FALSE), + .ratelimit = {}, + .source = nm_g_timeout_add_source(1, rate_limit_check_cb, &data), + .num = 0, + }; + + g_main_loop_run(data.loop); + g_main_loop_unref(data.loop); +} + +/*****************************************************************************/ NMTST_DEFINE(); @@ -272,6 +336,7 @@ main(int argc, char **argv) g_test_add_func("/utils/stable_privacy", test_stable_privacy); g_test_add_func("/utils/hw_addr_gen_stable_eth", test_hw_addr_gen_stable_eth); g_test_add_func("/utils/shorten-hostname", test_shorten_hostname); + g_test_add_func("/utils/rate-limit-check", test_rate_limit_check); return g_test_run(); } diff --git a/src/core/vpn/nm-vpn-connection.c b/src/core/vpn/nm-vpn-connection.c index 22364ef9..54478c53 100644 --- a/src/core/vpn/nm-vpn-connection.c +++ b/src/core/vpn/nm-vpn-connection.c @@ -26,10 +26,12 @@ #include "nm-active-connection.h" #include "nm-config.h" #include "nm-dbus-manager.h" +#include "devices/nm-device.h" #include "nm-dispatcher.h" #include "nm-firewalld-manager.h" #include "nm-ip-config.h" #include "nm-l3-config-data.h" +#include "nm-manager.h" #include "nm-netns.h" #include "nm-pacrunner-manager.h" #include "nm-vpn-manager.h" @@ -173,6 +175,7 @@ typedef struct { }; GSource *init_fail_on_idle_source; + GSource *check_device_added_idle_source; GSource *connect_timeout_source; GCancellable *main_cancellable; GVariant *connect_hash; @@ -227,6 +230,8 @@ static void _set_vpn_state(NMVpnConnection *self, static void _l3cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMVpnConnection *self); +static void _check_complete(NMVpnConnection *self, gboolean success); + /*****************************************************************************/ #define _NMLOG_DOMAIN LOGD_VPN @@ -1403,15 +1408,29 @@ fw_change_zone_cb(NMFirewalldManager *firewalld_manager, _apply_config(self); } +static gboolean +_check_device_added_idle_cb(gpointer user_data) +{ + NMVpnConnection *self = user_data; + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + + _check_complete(self, TRUE); + nm_clear_g_source_inst(&priv->check_device_added_idle_source); + + return G_SOURCE_CONTINUE; +} + static void _check_complete(NMVpnConnection *self, gboolean success) { NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; NMConnection *connection; + NMDevice *device; NMSettingConnection *s_con; const char *zone; const char *iface; + int ifindex; if (priv->vpn_state < STATE_IP_CONFIG_GET || priv->vpn_state > STATE_ACTIVATED) return; @@ -1437,10 +1456,34 @@ _check_complete(NMVpnConnection *self, gboolean success) } connection = _get_applied_connection(self); + ifindex = nm_vpn_connection_get_ip_ifindex(self, FALSE); + device = nm_manager_get_device_by_ifindex(NM_MANAGER_GET, ifindex); + + /* We have a defined interface index, but the device is not processed yet. + * The processing of the new kernel link could be queued in an idle handler, + * so schedule an idle handler once to check if the device has been processed. + */ + if (ifindex > 0 && !device && !priv->check_device_added_idle_source) { + priv->check_device_added_idle_source = + nm_g_idle_add_source(_check_device_added_idle_cb, self); + return; + } - l3cd = nm_l3_config_data_new_from_connection(nm_netns_get_multi_idx(priv->netns), - nm_vpn_connection_get_ip_ifindex(self, TRUE), - connection); + /* Use nm_device_create_l3_config_data_from_connection here if possible. This ensures that + * connection properties like mdns, llmnr, dns-over-tls or dnssec are applied to vpn connections + * If this vpn connection does not have its own device resort to nm_l3_config_data_new_from_connection + * since we can't properly apply these properties anyway + */ + if (ifindex > 0) { + nm_assert(device); + l3cd = nm_device_create_l3_config_data_from_connection(device, connection); + } else { + l3cd = nm_l3_config_data_new_from_connection(nm_netns_get_multi_idx(priv->netns), + nm_vpn_connection_get_ip_ifindex(self, TRUE), + connection); + _LOGD("VPN connection does not have its own device. Some connection properties won't be " + "supported."); + } nm_l3_config_data_set_allow_routes_without_address(l3cd, AF_INET, TRUE); nm_l3_config_data_set_allow_routes_without_address(l3cd, AF_INET6, TRUE); @@ -3025,6 +3068,8 @@ dispose(GObject *object) nm_clear_g_source_inst(&priv->init_fail_on_idle_source); + nm_clear_g_source_inst(&priv->check_device_added_idle_source); + nm_clear_g_cancellable(&priv->main_cancellable); nm_clear_g_source_inst(&priv->start_timeout_source); |