diff options
| author | Michael Biebl <biebl@debian.org> | 2026-02-22 00:39:58 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2026-02-22 00:39:58 +0100 |
| commit | 067fb576988f685e83ac8b0ae690334aff547c85 (patch) | |
| tree | 204c7c8a0300691c53627cd3418cf54671ada1a8 /src | |
| parent | 6de29285e533f4fec22a219013f3687edb6b7399 (diff) | |
New upstream version 1.56.0 upstream/1.56.0
Diffstat (limited to 'src')
240 files changed, 7997 insertions, 3882 deletions
diff --git a/src/contrib/nm-vpn-plugin-utils.c b/src/contrib/nm-vpn-plugin-utils.c index a9407608..24b08ac6 100644 --- a/src/contrib/nm-vpn-plugin-utils.c +++ b/src/contrib/nm-vpn-plugin-utils.c @@ -155,3 +155,33 @@ nm_vpn_plugin_utils_load_editor(const char *module_path, g_return_val_if_fail(NM_IS_VPN_EDITOR(editor), NULL); return editor; } + +char * +nm_vpn_plugin_utils_get_cert_path(const char *plugin) +{ + const char *path; + + g_return_val_if_fail(plugin, NULL); + + /* Users can set NM_CERT_PATH=~/.cert to be compatible with the certificate + * directory used in the past. */ + path = g_getenv("NM_CERT_PATH"); + if (path) + return g_build_filename(path, plugin, NULL); + + /* Otherwise use XDG_DATA_HOME. We use subdirectory "networkmanagement/certificates" + * because the SELinux policy already has rules to set the correct labels in that + * directory. */ + path = g_getenv("XDG_DATA_HOME"); + if (path) + return g_build_filename(path, "networkmanagement", "certificates", plugin, NULL); + + /* Use the default value for XDG_DATA_HOME */ + return g_build_filename(g_get_home_dir(), + ".local", + "share", + "networkmanagement", + "certificates", + plugin, + NULL); +} diff --git a/src/contrib/nm-vpn-plugin-utils.h b/src/contrib/nm-vpn-plugin-utils.h index 6a6ea0b9..78e29d0b 100644 --- a/src/contrib/nm-vpn-plugin-utils.h +++ b/src/contrib/nm-vpn-plugin-utils.h @@ -24,4 +24,6 @@ NMVpnEditor *nm_vpn_plugin_utils_load_editor(const char *modul gpointer user_data, GError **error); +char *nm_vpn_plugin_utils_get_cert_path(const char *plugin); + #endif /* __NM_VPN_PLUGIN_UTILS_H__ */ 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); diff --git a/src/libnm-client-aux-extern/tests/test-libnm-client-aux.c b/src/libnm-client-aux-extern/tests/test-libnm-client-aux.c index f727b3d9..6a25b652 100644 --- a/src/libnm-client-aux-extern/tests/test-libnm-client-aux.c +++ b/src/libnm-client-aux-extern/tests/test-libnm-client-aux.c @@ -234,6 +234,227 @@ test_team_link_watcher_tofro_string(void) NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE); } +static void +test_wireguard_peer(void) +{ + guint i; + struct { + const char *input; + const char *canonical; /* canonical string representation */ + + gboolean invalid; + const char *pubkey; + const char *endpoint; + guint16 keepalive; + guint num_allowed_ips; + const char *allowed_ips[2]; + const char *psk; + int psk_flags; + } tests[] = {{ + /* Public key only */ + .input = "MWEKYcE9MEh5RoGDuJYrJ2YgkoosONGhuHRBAC00e14=", + .canonical = "MWEKYcE9MEh5RoGDuJYrJ2YgkoosONGhuHRBAC00e14=", + .pubkey = "MWEKYcE9MEh5RoGDuJYrJ2YgkoosONGhuHRBAC00e14=", + }, + { + /* IPv4 endpoint */ + .input = "+DIX0qWKQ4E6hy7MWzsSRXjqAHCtffWrXTdJPe/xS04=" + " endpoint=1.2.3.4:5555", + .canonical = "+DIX0qWKQ4E6hy7MWzsSRXjqAHCtffWrXTdJPe/xS04=" + " endpoint=1.2.3.4:5555", + .pubkey = "+DIX0qWKQ4E6hy7MWzsSRXjqAHCtffWrXTdJPe/xS04=", + .endpoint = "1.2.3.4:5555", + }, + { + /* IPv6 endpoint */ + .input = "aPsdPkeqH4l5Nax3g3e8A8f7g0hJk2l3m4N5p6q7R8s=" + " endpoint=[fd01:db8::1]:8080", + .canonical = "aPsdPkeqH4l5Nax3g3e8A8f7g0hJk2l3m4N5p6q7R8s=" + " endpoint=[fd01:db8::1]:8080", + .pubkey = "aPsdPkeqH4l5Nax3g3e8A8f7g0hJk2l3m4N5p6q7R8s=", + .endpoint = "[fd01:db8::1]:8080", + }, + { + /* IPv6 endpoint, without brackets */ + .input = "+DIX0qWKQ4E6hy7MWzsSRXjqAHCtffWrXTdJPe/xS04=" + " endpoint=fd01::12:8080", + .canonical = "+DIX0qWKQ4E6hy7MWzsSRXjqAHCtffWrXTdJPe/xS04=" + " endpoint=fd01::12:8080", + .pubkey = "+DIX0qWKQ4E6hy7MWzsSRXjqAHCtffWrXTdJPe/xS04=", + .endpoint = "fd01::12:8080", + }, + { + /* Single IPv4 allowed-ip */ + .input = "s4fmZZA3gMGVv8+0hkSwrmeLC6nNd+Pd6DlSaufLKhY=" + " allowed-ips=172.16.0.0/16", + .canonical = "s4fmZZA3gMGVv8+0hkSwrmeLC6nNd+Pd6DlSaufLKhY=" + " allowed-ips=172.16.0.0/16", + .pubkey = "s4fmZZA3gMGVv8+0hkSwrmeLC6nNd+Pd6DlSaufLKhY=", + .num_allowed_ips = 1, + .allowed_ips = {"172.16.0.0/16"}, + }, + { + /* Multiple allowed-ips */ + .input = "V02J2zmCi2LHX2KMK+ZOgDNhZzK4JXjGNr7CYfz9DxQ=" + " allowed-ips=192.168.2.0/24;2001:db8:a::/48", + .canonical = "V02J2zmCi2LHX2KMK+ZOgDNhZzK4JXjGNr7CYfz9DxQ=" + " allowed-ips=192.168.2.0/24;2001:db8:a::/48", + .pubkey = "V02J2zmCi2LHX2KMK+ZOgDNhZzK4JXjGNr7CYfz9DxQ=", + .num_allowed_ips = 2, + .allowed_ips = {"192.168.2.0/24", "2001:db8:a::/48"}, + }, + { + /* Persistent-keepalive */ + .input = "D1FTp8Wy1oJQI045yXo9EMdxJqjXHC3VhTCPTh3lSQM=" + " persistent-keepalive=25", + .canonical = "D1FTp8Wy1oJQI045yXo9EMdxJqjXHC3VhTCPTh3lSQM=" + " persistent-keepalive=25", + .pubkey = "D1FTp8Wy1oJQI045yXo9EMdxJqjXHC3VhTCPTh3lSQM=", + .keepalive = 25, + }, + { + /* Preshared-key without flags (should default to 0) */ + .input = "H5cWWgpWgJH+nHFhsuPS3adgZHuc6Z4cRzfiNRTinE0=" + " preshared-key=16uGwZvROnwyNGoW6Z3pvJB5GKbd6ncYROA/FFleLQA=", + .canonical = "H5cWWgpWgJH+nHFhsuPS3adgZHuc6Z4cRzfiNRTinE0=" + " preshared-key=16uGwZvROnwyNGoW6Z3pvJB5GKbd6ncYROA/FFleLQA=" + " preshared-key-flags=0", + .pubkey = "H5cWWgpWgJH+nHFhsuPS3adgZHuc6Z4cRzfiNRTinE0=", + .psk = "16uGwZvROnwyNGoW6Z3pvJB5GKbd6ncYROA/FFleLQA=", + .psk_flags = 0, + }, + { + /* Preshared-key flags as string */ + .input = "H5cWWgpWgJH+nHFhsuPS3adgZHuc6Z4cRzfiNRTinE0=" + " preshared-key=16uGwZvROnwyNGoW6Z3pvJB5GKbd6ncYROA/FFleLQA=" + " preshared-key-flags=not-saved", + .canonical = "H5cWWgpWgJH+nHFhsuPS3adgZHuc6Z4cRzfiNRTinE0=" + " preshared-key=16uGwZvROnwyNGoW6Z3pvJB5GKbd6ncYROA/FFleLQA=" + " preshared-key-flags=2", + .pubkey = "H5cWWgpWgJH+nHFhsuPS3adgZHuc6Z4cRzfiNRTinE0=", + .psk = "16uGwZvROnwyNGoW6Z3pvJB5GKbd6ncYROA/FFleLQA=", + .psk_flags = 2, + }, + { + /* Non-canonical order and extra whitespaces */ + .input = "gqQ9dUqKQNfz/KOqELJpS0MKBvRcYWL8sm/LGEWKKQY=" + " preshared-key=EVVP8pOzn8R3nQtv62/hnGsXzyagEgykSboFe4EFhQc=" + " endpoint=vpn.example.com:51820 " + " preshared-key-flags=1" + " persistent-keepalive=45" + " allowed-ips=0.0.0.0/0;::/0", + .canonical = "gqQ9dUqKQNfz/KOqELJpS0MKBvRcYWL8sm/LGEWKKQY=" + " allowed-ips=0.0.0.0/0;::/0" + " endpoint=vpn.example.com:51820" + " persistent-keepalive=45" + " preshared-key=EVVP8pOzn8R3nQtv62/hnGsXzyagEgykSboFe4EFhQc=" + " preshared-key-flags=1", + .pubkey = "gqQ9dUqKQNfz/KOqELJpS0MKBvRcYWL8sm/LGEWKKQY=", + .endpoint = "vpn.example.com:51820", + .keepalive = 45, + .num_allowed_ips = 2, + .allowed_ips = {"0.0.0.0/0", "::/0"}, + .psk = "EVVP8pOzn8R3nQtv62/hnGsXzyagEgykSboFe4EFhQc=", + .psk_flags = 1, + }, + { + /* Empty string */ + .input = "", + .invalid = TRUE, + }, + { + /* Invalid public key*/ + .input = "aaaaaaaaaaaaaaaaaaaaaaa=", + .invalid = TRUE, + }, + { + /* Missing value*/ + .input = "gqQ9dUqKQNfz/KOqELJpS0MKBvRcYWL8sm/LGEWKKQY= " + "persistent-keepalive=", + .invalid = TRUE, + }, + { + /* Unknown attribute */ + .input = "gqQ9dUqKQNfz/KOqELJpS0MKBvRcYWL8sm/LGEWKKQY= " + "persistent-keepalive=12 foobarness=13", + .invalid = TRUE, + }, + { + /* Invalid IPv4 allowed-ip*/ + .input = "gqQ9dUqKQNfz/KOqELJpS0MKBvRcYWL8sm/LGEWKKQY= " + "allowed-ips=192.168.10.256/32", + .invalid = TRUE, + }, + { + /* Invalid IPv6 allowed-ip */ + .input = "gqQ9dUqKQNfz/KOqELJpS0MKBvRcYWL8sm/LGEWKKQY= " + "allowed-ips=fd01::1::3/64", + .invalid = TRUE, + }, + { + /* Endpoint with no port */ + .input = "+DIX0qWKQ4E6hy7MWzsSRXjqAHCtffWrXTdJPe/xS04=" + " endpoint=1.2.3.4", + .invalid = TRUE, + }, + { + /* Invalid endpoint */ + .input = "+DIX0qWKQ4E6hy7MWzsSRXjqAHCtffWrXTdJPe/xS04=" + " endpoint=1.2.3.5.6", + .invalid = TRUE, + }, + { + /* Invalid persistent-keepalive */ + .input = "gqQ9dUqKQNfz/KOqELJpS0MKBvRcYWL8sm/LGEWKKQY= " + "persistent-keepalive=yes", + .invalid = TRUE, + }, + { + /* Invalid PSK */ + .input = "gqQ9dUqKQNfz/KOqELJpS0MKBvRcYWL8sm/LGEWKKQY=" + " preshared-key=pskpskpskpskpskpskpskpskpskpskpskpsk", + .invalid = TRUE, + }}; + + for (i = 0; i < G_N_ELEMENTS(tests); i++) { + nm_auto_unref_wgpeer NMWireGuardPeer *peer = NULL; + gs_free_error GError *error = NULL; + gs_free char *newstr = NULL; + guint j; + + peer = _nm_utils_wireguard_peer_from_string(tests[i].input, &error); + if (tests[i].invalid) { + g_assert(!peer); + g_assert(error); + continue; + } + g_assert_no_error(error); + g_assert_nonnull(peer); + + newstr = _nm_utils_wireguard_peer_to_string(peer); + g_assert_nonnull(newstr); + g_assert_cmpstr(tests[i].canonical, ==, newstr); + + g_assert_cmpstr(tests[i].pubkey, ==, nm_wireguard_peer_get_public_key(peer)); + g_assert_cmpstr(tests[i].endpoint, ==, nm_wireguard_peer_get_endpoint(peer)); + + g_assert_cmpint(tests[i].num_allowed_ips, ==, nm_wireguard_peer_get_allowed_ips_len(peer)); + for (j = 0; j < tests[i].num_allowed_ips; j++) { + g_assert_cmpstr(tests[i].allowed_ips[j], + ==, + nm_wireguard_peer_get_allowed_ip(peer, j, NULL)); + } + + g_assert_cmpint(tests[i].keepalive, ==, nm_wireguard_peer_get_persistent_keepalive(peer)); + g_assert_cmpstr(tests[i].psk, ==, nm_wireguard_peer_get_preshared_key(peer)); + if (tests[i].psk) { + g_assert_cmpint(tests[i].psk_flags, + ==, + nm_wireguard_peer_get_preshared_key_flags(peer)); + } + } +} + /*****************************************************************************/ NMTST_DEFINE(); @@ -245,6 +466,7 @@ main(int argc, char **argv) g_test_add_func("/libnm-core-aux/test_team_link_watcher_tofro_string", test_team_link_watcher_tofro_string); + g_test_add_func("/libnm-core-aux/test-wireguard-peer", test_wireguard_peer); return g_test_run(); } diff --git a/src/libnm-client-impl/libnm.ver b/src/libnm-client-impl/libnm.ver index bd66e61d..6c48978a 100644 --- a/src/libnm-client-impl/libnm.ver +++ b/src/libnm-client-impl/libnm.ver @@ -2064,6 +2064,11 @@ global: nm_ethtool_optname_is_fec; } libnm_1_50_0; +libnm_1_52_2 { + #nm_utils_copy_cert_as_user@libnm_1_52_2; + #nm_vpn_plugin_info_supports_safe_private_file_access@libnm_1_52_2; +} libnm_1_52_0; + libnm_1_54_0 { global: nm_setting_ip_config_forwarding_get_type; @@ -2085,7 +2090,16 @@ global: } libnm_1_54_0; libnm_1_54_3 { + #nm_utils_copy_cert_as_user@libnm_1_54_3; + #nm_vpn_plugin_info_supports_safe_private_file_access@libnm_1_54_3; +} libnm_1_54_2; + +libnm_1_56_0 { global: + nm_dns_server_validate; + nm_setting_gsm_get_device_uid; + nm_setting_connection_get_dnssec; + nm_setting_connection_dnssec_get_type; nm_utils_copy_cert_as_user; nm_vpn_plugin_info_supports_safe_private_file_access; -} libnm_1_54_2; +} libnm_1_54_0; diff --git a/src/libnm-client-impl/nm-client.c b/src/libnm-client-impl/nm-client.c index 13343cbf..b81ac6e5 100644 --- a/src/libnm-client-impl/nm-client.c +++ b/src/libnm-client-impl/nm-client.c @@ -9339,3 +9339,27 @@ NM_BACKPORT_SYMBOL(libnm_1_50_4, (optname)); NM_BACKPORT_SYMBOL(libnm_1_50_4, GType, nm_setting_ethtool_fec_mode_get_type, (void), ()); + +NM_BACKPORT_SYMBOL(libnm_1_52_2, + char *, + nm_utils_copy_cert_as_user, + (const char *filename, const char *user, GError **error), + (filename, user, error)); + +NM_BACKPORT_SYMBOL(libnm_1_52_2, + gboolean, + nm_vpn_plugin_info_supports_safe_private_file_access, + (NMVpnPluginInfo * self), + (self)); + +NM_BACKPORT_SYMBOL(libnm_1_54_3, + char *, + nm_utils_copy_cert_as_user, + (const char *filename, const char *user, GError **error), + (filename, user, error)); + +NM_BACKPORT_SYMBOL(libnm_1_54_3, + gboolean, + nm_vpn_plugin_info_supports_safe_private_file_access, + (NMVpnPluginInfo * self), + (self)); diff --git a/src/libnm-client-impl/tests/test-gir.py b/src/libnm-client-impl/tests/test-gir.py index 81518e37..554080fa 100755 --- a/src/libnm-client-impl/tests/test-gir.py +++ b/src/libnm-client-impl/tests/test-gir.py @@ -93,8 +93,6 @@ def syms_from_ver(verfile): # hardcode it. c_syms["nm_ethtool_optname_is_feature"] = "1.20" c_syms["nm_setting_bond_port_get_prio"] = "1.44" - c_syms["nm_utils_copy_cert_as_user"] = "1.56" - c_syms["nm_vpn_plugin_info_supports_safe_private_file_access"] = "1.56" return c_syms diff --git a/src/libnm-client-impl/tests/test-libnm.c b/src/libnm-client-impl/tests/test-libnm.c index f56521a4..b30d02a5 100644 --- a/src/libnm-client-impl/tests/test-libnm.c +++ b/src/libnm-client-impl/tests/test-libnm.c @@ -2756,6 +2756,8 @@ test_types(void) G(nm_setting_connection_lldp_get_type), G(nm_setting_connection_llmnr_get_type), G(nm_setting_connection_mdns_get_type), + G(nm_setting_connection_dns_over_tls_get_type), + G(nm_setting_connection_dnssec_get_type), G(nm_setting_dcb_flags_get_type), G(nm_setting_dcb_get_type), G(nm_setting_diff_result_get_type), diff --git a/src/libnm-core-aux-extern/nm-libnm-core-aux.c b/src/libnm-core-aux-extern/nm-libnm-core-aux.c index dfc70e35..b12000fc 100644 --- a/src/libnm-core-aux-extern/nm-libnm-core-aux.c +++ b/src/libnm-core-aux-extern/nm-libnm-core-aux.c @@ -7,6 +7,7 @@ #include "nm-libnm-core-aux.h" +#include "nm-errors.h" #include "libnm-core-aux-intern/nm-libnm-core-utils.h" #include "libnm-glib-aux/nm-str-buf.h" @@ -475,3 +476,177 @@ _nm_ip_route_to_string(NMIPRoute *route, NMStrBuf *strbuf) nm_str_buf_append_printf(strbuf, " metric %" G_GINT64_FORMAT, metric); } } + +/*****************************************************************************/ + +char * +_nm_utils_wireguard_peer_to_string(NMWireGuardPeer *peer) +{ + GString *str; + const char *endpoint; + const char *psk; + guint16 keepalive; + guint i; + guint len; + + g_return_val_if_fail(peer, ""); + + nm_assert(nm_wireguard_peer_is_valid(peer, TRUE, TRUE, NULL)); + + str = g_string_new(""); + g_string_append(str, nm_wireguard_peer_get_public_key(peer)); + + len = nm_wireguard_peer_get_allowed_ips_len(peer); + if (len > 0) { + g_string_append(str, " allowed-ips="); + for (i = 0; i < len; i++) { + g_string_append(str, nm_wireguard_peer_get_allowed_ip(peer, i, NULL)); + if (i < len - 1) + g_string_append(str, ";"); + } + } + + endpoint = nm_wireguard_peer_get_endpoint(peer); + if (endpoint) { + g_string_append_printf(str, " endpoint=%s", endpoint); + } + + keepalive = nm_wireguard_peer_get_persistent_keepalive(peer); + if (keepalive != 0) { + g_string_append_printf(str, " persistent-keepalive=%hu", keepalive); + } + + psk = nm_wireguard_peer_get_preshared_key(peer); + if (psk) { + g_string_append_printf(str, " preshared-key=%s", psk); + g_string_append_printf(str, + " preshared-key-flags=%u", + (guint) nm_wireguard_peer_get_preshared_key_flags(peer)); + } + + return g_string_free(str, FALSE); +} + +NMWireGuardPeer * +_nm_utils_wireguard_peer_from_string(const char *str, GError **error) +{ + nm_auto_unref_wgpeer NMWireGuardPeer *peer = NULL; + gs_strfreev char **tokens = NULL; + gboolean has_psk = FALSE; + gboolean has_psk_flags = FALSE; + char *value; + guint i; + + peer = nm_wireguard_peer_new(); + + tokens = g_strsplit_set(str, " ", 0); + for (i = 0; tokens[i]; i++) { + if (i == 0) { + if (!nm_wireguard_peer_set_public_key(peer, tokens[i], FALSE)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "invalid public key '%s'", + tokens[i]); + return NULL; + } + continue; + } + + if (tokens[i][0] == '\0') + continue; + + value = strchr(tokens[i], '='); + if (!value || value[1] == '\0') { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "attribute without value '%s'", + tokens[i]); + return NULL; + } + + *value = '\0'; + value++; + + if (nm_streq(tokens[i], "allowed-ips")) { + gs_strfreev char **ips = NULL; + guint j; + + ips = g_strsplit_set(value, ";", 0); + for (j = 0; ips[j]; j++) { + if (!nm_wireguard_peer_append_allowed_ip(peer, ips[j], FALSE)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "invalid allowed-ip '%s'", + ips[j]); + return NULL; + } + } + } else if (nm_streq(tokens[i], "endpoint")) { + if (!nm_wireguard_peer_set_endpoint(peer, value, FALSE)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "invalid endpoint '%s'", + value); + return NULL; + } + } else if (nm_streq(tokens[i], "persistent-keepalive")) { + gint64 keepalive; + + keepalive = _nm_utils_ascii_str_to_int64(value, 10, 0, G_MAXUINT16, -1); + if (keepalive == -1) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "invalid persistent-keepalive value '%s'", + value); + return NULL; + } + nm_wireguard_peer_set_persistent_keepalive(peer, (guint16) keepalive); + } else if (nm_streq(tokens[i], "preshared-key")) { + if (!nm_wireguard_peer_set_preshared_key(peer, value, FALSE)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "invalid preshared-key '%s'", + value); + return NULL; + } + has_psk = TRUE; + } else if (nm_streq(tokens[i], "preshared-key-flags")) { + int flags; + + if (!nm_utils_enum_from_str(NM_TYPE_SETTING_SECRET_FLAGS, value, &flags, NULL)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "invalid preshared-key-flags '%s'", + value); + return NULL; + } + nm_wireguard_peer_set_preshared_key_flags(peer, (NMSettingSecretFlags) flags); + has_psk_flags = TRUE; + } else { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "invalid attribute '%s'", + tokens[i]); + return NULL; + } + } + + if (has_psk && !has_psk_flags) { + /* The flags are NOT_REQUIRED by default. With this flag, the PSK would not + * be saved by default, unless the user explicitly sets a different value. */ + nm_wireguard_peer_set_preshared_key_flags(peer, NM_SETTING_SECRET_FLAG_NONE); + } + + if (!nm_wireguard_peer_is_valid(peer, TRUE, TRUE, error)) + return NULL; + + return g_steal_pointer(&peer); +} diff --git a/src/libnm-core-aux-extern/nm-libnm-core-aux.h b/src/libnm-core-aux-extern/nm-libnm-core-aux.h index e45e98ab..aa7ea631 100644 --- a/src/libnm-core-aux-extern/nm-libnm-core-aux.h +++ b/src/libnm-core-aux-extern/nm-libnm-core-aux.h @@ -6,8 +6,9 @@ #ifndef __NM_LIBNM_CORE_AUX_H__ #define __NM_LIBNM_CORE_AUX_H__ -#include "nm-setting-team.h" #include "nm-setting-ip-config.h" +#include "nm-setting-team.h" +#include "nm-setting-wireguard.h" typedef enum { NM_TEAM_LINK_WATCHER_TYPE_NONE = 0, @@ -39,4 +40,7 @@ void _nm_ip_route_to_string(NMIPRoute *route, struct _NMStrBuf *strbuf); NMTeamLinkWatcher *nm_utils_team_link_watcher_from_string(const char *str, GError **error); +char *_nm_utils_wireguard_peer_to_string(NMWireGuardPeer *peer); +NMWireGuardPeer *_nm_utils_wireguard_peer_from_string(const char *str, GError **error); + #endif /* __NM_LIBNM_CORE_AUX_H__ */ diff --git a/src/libnm-core-aux-intern/nm-libnm-core-utils.c b/src/libnm-core-aux-intern/nm-libnm-core-utils.c index 94aa42bc..2d709e20 100644 --- a/src/libnm-core-aux-intern/nm-libnm-core-utils.c +++ b/src/libnm-core-aux-intern/nm-libnm-core-utils.c @@ -705,6 +705,7 @@ nm_mptcp_flags_normalize(NMMptcpFlags flags) * @addr_family: the address family, or AF_UNSPEC to autodetect it * @str: the name server URI string to parse * @dns: the name server descriptor to fill, or %NULL + * @error: the error to set if the string cannot be parsed * * Parses the given name server URI string. Each name server is represented * by the following grammar: @@ -731,7 +732,7 @@ nm_mptcp_flags_normalize(NMMptcpFlags flags) * Returns: %TRUE on success, %FALSE on failure */ gboolean -nm_dns_uri_parse(int addr_family, const char *str, NMDnsServer *dns) +nm_dns_uri_parse(int addr_family, const char *str, NMDnsServer *dns, GError **error) { NMDnsServer dns_stack; gs_free char *addr_port_heap = NULL; @@ -746,8 +747,13 @@ nm_dns_uri_parse(int addr_family, const char *str, NMDnsServer *dns) if (!dns) dns = &dns_stack; - if (!str) + if (!str) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("the string is empty")); return FALSE; + } *dns = (NMDnsServer) {0}; @@ -765,12 +771,21 @@ nm_dns_uri_parse(int addr_family, const char *str, NMDnsServer *dns) } if (name && name[0] == '\0') { - /* empty DoT server name is not allowed */ + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("the DNS-over-TLS server name is empty")); return FALSE; } - if (!nm_inet_parse_bin(addr_family, str, &dns->addr_family, &dns->addr)) + if (!nm_inet_parse_bin(addr_family, str, &dns->addr_family, &dns->addr)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("\"%s\" is not a valid IP address or a supported URI"), + str); return FALSE; + } dns->servername = name; dns->scheme = NM_DNS_URI_SCHEME_NONE; @@ -784,7 +799,10 @@ nm_dns_uri_parse(int addr_family, const char *str, NMDnsServer *dns) addr_port = nm_strndup_a(100, addr_port, name - addr_port, &addr_port_heap); name++; if (*name == '\0') { - /* empty DoT server name not allowed */ + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("the DNS-over-TLS server name is empty")); return FALSE; } dns->servername = name; @@ -797,8 +815,13 @@ nm_dns_uri_parse(int addr_family, const char *str, NMDnsServer *dns) addr_family = AF_INET6; addr_port++; end = strchr(addr_port, ']'); - if (!end) + if (!end) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("unterminated square bracket")); return FALSE; + } addr = nm_strndup_a(100, addr_port, end - addr_port, &addr_heap); /* IPv6 link-local scope-id */ @@ -806,8 +829,13 @@ nm_dns_uri_parse(int addr_family, const char *str, NMDnsServer *dns) if (perc) { *perc = '\0'; if (g_strlcpy(dns->interface, perc + 1, sizeof(dns->interface)) - >= sizeof(dns->interface)) + >= sizeof(dns->interface)) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("the interface name is too long")); return FALSE; + } } /* port */ @@ -815,8 +843,14 @@ nm_dns_uri_parse(int addr_family, const char *str, NMDnsServer *dns) if (*end == ':') { end++; dns->port = _nm_utils_ascii_str_to_int64(end, 10, 1, 65535, 0); - if (dns->port == 0) + if (dns->port == 0) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("\"%s\" is not a valid port number"), + end); return FALSE; + } } } else if (addr_family != AF_INET6) { /* square brackets are mandatory for IPv6, so it must be IPv4 */ @@ -830,23 +864,49 @@ nm_dns_uri_parse(int addr_family, const char *str, NMDnsServer *dns) addr = nm_strndup_a(100, addr_port, port - addr_port, &addr_heap); port++; dns->port = _nm_utils_ascii_str_to_int64(port, 10, 1, 65535, 0); - if (dns->port == 0) + if (dns->port == 0) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("\"%s\" is not a valid port number"), + port); return FALSE; + } } } else { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("IPv6 addresses must be enclosed in square brackets")); return FALSE; } - if (!nm_inet_parse_bin(addr_family, addr, &dns->addr_family, &dns->addr)) + if (!nm_inet_parse_bin(addr_family, addr, &dns->addr_family, &dns->addr)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("\"%s\" is not a valid IP address"), + addr); return FALSE; + } - if (dns->scheme != NM_DNS_URI_SCHEME_TLS && dns->servername) + if (dns->scheme != NM_DNS_URI_SCHEME_TLS && dns->servername) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("the server name is only supported for DNS-over-TLS")); return FALSE; + } /* For now, allow the interface only for IPv6 link-local addresses */ if (dns->interface[0] - && (dns->addr_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&dns->addr.addr6))) + && (dns->addr_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&dns->addr.addr6))) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("the scope-id is only supported for IPv6 link-local addresses")); return FALSE; + } return TRUE; } @@ -870,7 +930,7 @@ nm_dns_uri_parse_plain(int addr_family, const char *str, char *out_addrstr, NMIP { NMDnsServer dns; - if (!nm_dns_uri_parse(addr_family, str, &dns)) + if (!nm_dns_uri_parse(addr_family, str, &dns, NULL)) return FALSE; switch (dns.scheme) { @@ -922,7 +982,7 @@ nm_dns_uri_normalize(int addr_family, const char *str, char **out_free) nm_assert(str); nm_assert(out_free && !*out_free); - if (!nm_dns_uri_parse(addr_family, str, &dns)) + if (!nm_dns_uri_parse(addr_family, str, &dns, NULL)) return NULL; nm_inet_ntop(dns.addr_family, &dns.addr, addrstr); diff --git a/src/libnm-core-aux-intern/nm-libnm-core-utils.h b/src/libnm-core-aux-intern/nm-libnm-core-utils.h index eeb720d9..0e75982e 100644 --- a/src/libnm-core-aux-intern/nm-libnm-core-utils.h +++ b/src/libnm-core-aux-intern/nm-libnm-core-utils.h @@ -300,13 +300,15 @@ gpointer _nm_connection_new_setting(NMConnection *connection, GType gtype); /*****************************************************************************/ -#define _NM_MPTCP_FLAGS_ALL \ - ((NMMptcpFlags) (NM_MPTCP_FLAGS_DISABLED | NM_MPTCP_FLAGS_ENABLED \ - | NM_MPTCP_FLAGS_ALSO_WITHOUT_SYSCTL \ - | NM_MPTCP_FLAGS_ALSO_WITHOUT_DEFAULT_ROUTE | NM_MPTCP_FLAGS_SIGNAL \ - | NM_MPTCP_FLAGS_SUBFLOW | NM_MPTCP_FLAGS_BACKUP | NM_MPTCP_FLAGS_FULLMESH)) +#define _NM_MPTCP_FLAGS_ALL \ + ((NMMptcpFlags) (NM_MPTCP_FLAGS_DISABLED | NM_MPTCP_FLAGS_ENABLED \ + | NM_MPTCP_FLAGS_ALSO_WITHOUT_SYSCTL \ + | NM_MPTCP_FLAGS_ALSO_WITHOUT_DEFAULT_ROUTE | NM_MPTCP_FLAGS_SIGNAL \ + | NM_MPTCP_FLAGS_SUBFLOW | NM_MPTCP_FLAGS_BACKUP | NM_MPTCP_FLAGS_FULLMESH \ + | NM_MPTCP_FLAGS_LAMINAR)) -#define _NM_MPTCP_FLAGS_DEFAULT ((NMMptcpFlags) (NM_MPTCP_FLAGS_ENABLED | NM_MPTCP_FLAGS_SUBFLOW)) +#define _NM_MPTCP_FLAGS_DEFAULT \ + ((NMMptcpFlags) (NM_MPTCP_FLAGS_ENABLED | NM_MPTCP_FLAGS_SUBFLOW | NM_MPTCP_FLAGS_LAMINAR)) NMMptcpFlags nm_mptcp_flags_normalize(NMMptcpFlags flags); @@ -330,7 +332,7 @@ typedef struct { guint16 port; } NMDnsServer; -gboolean nm_dns_uri_parse(int addr_family, const char *str, NMDnsServer *out_dns); +gboolean nm_dns_uri_parse(int addr_family, const char *str, NMDnsServer *out_dns, GError **error); gboolean nm_dns_uri_parse_plain(int addr_family, const char *str, char *out_addrstr, NMIPAddr *out_addr); const char *nm_dns_uri_normalize(int addr_family, const char *str, char **out_free); diff --git a/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in b/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in index ce4832dc..c83deea9 100644 --- a/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in +++ b/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in @@ -810,6 +810,10 @@ dbus-type="i" gprop-type="gint" /> + <property name="dnssec" + dbus-type="i" + gprop-type="gint" + /> <property name="down-on-poweroff" dbus-type="i" gprop-type="gint" @@ -1393,6 +1397,10 @@ dbus-type="s" gprop-type="gchararray" /> + <property name="device-uid" + dbus-type="s" + gprop-type="gchararray" + /> <property name="home-only" dbus-type="b" gprop-type="gboolean" diff --git a/src/libnm-core-impl/nm-keyfile.c b/src/libnm-core-impl/nm-keyfile.c index f8f735e9..70758f0f 100644 --- a/src/libnm-core-impl/nm-keyfile.c +++ b/src/libnm-core-impl/nm-keyfile.c @@ -1158,14 +1158,17 @@ ip_dns_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) addr_family = NM_SETTING_IP_CONFIG_GET_ADDR_FAMILY(setting); for (i = 0, n = 0; i < length; i++) { - if (!nm_dns_uri_parse(addr_family, list[i], NULL)) { + gs_free_error GError *error = NULL; + + if (!nm_dns_uri_parse(addr_family, list[i], NULL, &error)) { if (!read_handle_warn(info, key, key, NM_KEYFILE_WARN_SEVERITY_WARN, - _("ignoring invalid DNS server IPv%c address '%s'"), + _("ignoring invalid DNS server IPv%c address '%s': %s"), nm_utils_addr_family_to_char(addr_family), - list[i])) { + list[i], + error->message)) { do { nm_clear_g_free(&list[i]); } while (++i < length); @@ -1184,6 +1187,46 @@ ip_dns_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) } static void +ip_dns_search_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) +{ + gs_strfreev char **list = NULL; + gsize length; + + nm_assert(NM_IS_SETTING_IP4_CONFIG(setting) || NM_IS_SETTING_IP6_CONFIG(setting)); + + list = nm_keyfile_plugin_kf_get_string_list(info->keyfile, + nm_setting_get_name(setting), + key, + &length, + NULL); + nm_assert(length == NM_PTRARRAY_LEN(list)); + if (length == 0) + return; + + if (length == 1 && strpbrk(list[0], ", ")) { + /* By mistake, we accepted invalid characters like ',' in DNS search domains. + * Now we do some validation that would cause the connection to be rejected by + * the daemon. Let's continue accepting ',' and ' ' as separators but emit a + * warning */ + char **list2; + + read_handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("normalizing invalid separator ',' or ' ' in DNS search value '%s', " + "only ';' will be valid separators in keyfiles in the future"), + list[0]); + + list2 = g_strsplit_set(list[0], ", ", -1); + g_strfreev(list); + list = list2; + } + + g_object_set(setting, key, list, NULL); +} + +static void ip6_addr_gen_mode_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) { NMSettingIP6ConfigAddrGenMode addr_gen_mode; @@ -3081,6 +3124,7 @@ static const ParseInfoSetting *const parse_infos[_NM_META_SETTING_TYPE_NUM] = { .parser = ip_dns_parser, .writer = dns_writer, ), PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_DNS_OPTIONS, .always_write = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_DNS_SEARCH, .parser = ip_dns_search_parser, ), PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_GATEWAY, .parser = gateway_parser, ), PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_ROUTES, .parser_no_check_key = TRUE, @@ -3109,6 +3153,7 @@ static const ParseInfoSetting *const parse_infos[_NM_META_SETTING_TYPE_NUM] = { .parser = ip_dns_parser, .writer = dns_writer, ), PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_DNS_OPTIONS, .always_write = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_DNS_SEARCH, .parser = ip_dns_search_parser, ), PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_GATEWAY, .parser = gateway_parser, ), PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_ROUTES, .parser_no_check_key = TRUE, diff --git a/src/libnm-core-impl/nm-setting-connection.c b/src/libnm-core-impl/nm-setting-connection.c index ec3a1fed..0ad97846 100644 --- a/src/libnm-core-impl/nm-setting-connection.c +++ b/src/libnm-core-impl/nm-setting-connection.c @@ -71,6 +71,7 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMSettingConnection, PROP_MDNS, PROP_LLMNR, PROP_DNS_OVER_TLS, + PROP_DNSSEC, PROP_MPTCP_FLAGS, PROP_STABLE_ID, PROP_AUTH_RETRIES, @@ -103,6 +104,7 @@ typedef struct { gint32 mdns; gint32 llmnr; gint32 dns_over_tls; + gint32 dnssec; gint32 wait_device_timeout; gint32 lldp; gint32 wait_activation_delay; @@ -1335,6 +1337,22 @@ nm_setting_connection_get_dns_over_tls(NMSettingConnection *setting) } /** + * nm_setting_connection_get_dnssec: + * @setting: the #NMSettingConnection + * + * Returns: the #NMSettingConnection:dnssec property of the setting. + * + * Since: 1.56 + **/ +NMSettingConnectionDnssec +nm_setting_connection_get_dnssec(NMSettingConnection *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_CONNECTION(setting), NM_SETTING_CONNECTION_DNSSEC_DEFAULT); + + return NM_SETTING_CONNECTION_GET_PRIVATE(setting)->dnssec; +} + +/** * nm_setting_connection_get_mptcp_flags: * @setting: the #NMSettingConnection * @@ -3447,6 +3465,33 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass) NMSettingConnectionPrivate, dns_over_tls); + /** + * NMSettingConnection:dnssec: + * + * Whether DNSSEC (dnssec) is enabled for the connection. + * + * The permitted values are: "yes" (2) use DNSSEC and disable fallback, + * "allow-downgrade" (1) use DNSSEC but allow fallback if the server does not support it, + * "no" (0) don't ever use DNSSEC. + * The effect of "default" (-1) depends on the dns plugin used. + * Systemd-resolved uses its global setting in this case. + * + * This feature requires a plugin which supports DNSSEC. Otherwise, the + * setting has no effect. One such plugin is systemd-resolved. + * + * Since: 1.56 + **/ + _nm_setting_property_define_direct_enum(properties_override, + obj_properties, + NM_SETTING_CONNECTION_DNSSEC, + PROP_DNSSEC, + NM_TYPE_SETTING_CONNECTION_DNSSEC, + NM_SETTING_CONNECTION_DNSSEC_DEFAULT, + NM_SETTING_PARAM_NONE, + NULL, + NMSettingConnectionPrivate, + dnssec); + /* Notes about "mptcp-flags": * * It is a bit odd that NMMptcpFlags mixes flags with different purposes: @@ -3454,7 +3499,7 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass) * - "disabled", "disabled-on-local-iface", "enable": whether MPTCP handling * is enabled. The flag "disabled-on-local-iface" enables it based on whether * the interface has a default route. - * - "signal", "subflow", "backup", "fullmesh": the endpoint flags + * - "signal", "subflow", "backup", "fullmesh", "laminar": the endpoint flags * that are used. * * The reason is, that it is useful to have one "connection.mptcp-flags" @@ -3514,7 +3559,8 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass) * * When MPTCP handling is enabled then endpoints are configured with * the specified address flags "signal" (0x10), "subflow" (0x20), "backup" (0x40), - * "fullmesh" (0x80). See ip-mptcp(8) manual for additional information about the flags. + * "fullmesh" (0x80), "laminar" (0x100). See ip-mptcp(8) manual for + * additional information about the flags. * * If the flags are zero (0x0), the global connection default from NetworkManager.conf is * honored. If still unspecified, the fallback is "enabled,subflow". diff --git a/src/libnm-core-impl/nm-setting-gsm.c b/src/libnm-core-impl/nm-setting-gsm.c index 02e0e236..e6c43c96 100644 --- a/src/libnm-core-impl/nm-setting-gsm.c +++ b/src/libnm-core-impl/nm-setting-gsm.c @@ -47,7 +47,8 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_AUTO_CONFIG, PROP_INITIAL_EPS_REFUSE_PAP, PROP_INITIAL_EPS_REFUSE_CHAP, PROP_INITIAL_EPS_REFUSE_MSCHAP, - PROP_INITIAL_EPS_REFUSE_MSCHAPV2, ); + PROP_INITIAL_EPS_REFUSE_MSCHAPV2, + PROP_DEVICE_UID, ); typedef struct { char *number; @@ -75,6 +76,7 @@ typedef struct { bool auto_config; bool home_only; bool initial_eps_config; + char *device_uid; } NMSettingGsmPrivate; /** @@ -465,6 +467,22 @@ nm_setting_gsm_get_initial_eps_refuse_mschapv2(NMSettingGsm *setting) return NM_SETTING_GSM_GET_PRIVATE(setting)->initial_eps_refuse_mschapv2; } +/** + * nm_setting_gsm_get_device_uid: + * @setting: the #NMSettingGsm + * + * Returns: the #NMSettingGsm:device-uid property of the setting + * + * Since: 1.56 + **/ +const char * +nm_setting_gsm_get_device_uid(NMSettingGsm *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_GSM(setting), NULL); + + return NM_SETTING_GSM_GET_PRIVATE(setting)->device_uid; +} + static gboolean _verify_apn(const char *apn, gboolean allow_empty, const char *property_name, GError **error) { @@ -1149,6 +1167,26 @@ nm_setting_gsm_class_init(NMSettingGsmClass *klass) NMSettingGsmPrivate, initial_eps_refuse_mschapv2); + /** + * NMSettingGsm:device-uid: + * + * The device UID (as given by the WWAN management service) which this + * connection applies to. In contrast to #NMSettingGsm:device-id, which is + * an inherent property of the connected device, this setting refers to + * a property set by a UDEV-rule. Refer to the "Common udev tags" -> + * "ID_MM_PHYSDEV_UID" documentation of ModemManager. If given, the + * connection will only apply to the specified device. + * + * Since: 1.56 + **/ + _nm_setting_property_define_direct_string(properties_override, + obj_properties, + NM_SETTING_GSM_DEVICE_UID, + PROP_DEVICE_UID, + NM_SETTING_PARAM_NONE, + NMSettingGsmPrivate, + device_uid); + /* Ignore incoming deprecated properties */ _nm_properties_override_dbus(properties_override, "allowed-bands", diff --git a/src/libnm-core-impl/nm-setting-hsr.c b/src/libnm-core-impl/nm-setting-hsr.c index 1edf4a14..2f6bf9de 100644 --- a/src/libnm-core-impl/nm-setting-hsr.c +++ b/src/libnm-core-impl/nm-setting-hsr.c @@ -131,7 +131,7 @@ nm_setting_hsr_get_prp(NMSettingHsr *setting) * * Returns: the #NMSettingHsr:protocol-version property of the setting * - * Since: 1.56, 1.54.2 + * Since: 1.56 **/ NMSettingHsrProtocolVersion nm_setting_hsr_get_protocol_version(NMSettingHsr *setting) @@ -147,7 +147,7 @@ nm_setting_hsr_get_protocol_version(NMSettingHsr *setting) * * Returns: the #NMSettingHsr:interlink property of the setting * - * Since: 1.56, 1.54.2 + * Since: 1.56 **/ const char * nm_setting_hsr_get_interlink(NMSettingHsr *setting) @@ -320,7 +320,7 @@ nm_setting_hsr_class_init(NMSettingHsrClass *klass) * %NM_SETTING_HSR_PROTOCOL_VERSION_HSR_2010 sets the protocol version to HSRv0 (IEC 62439-3:2010). * %NM_SETTING_HSR_PROTOCOL_VERSION_HSR_2012 sets the protocol version to HSRv1 (IEC 62439-3:2012). * - * Since: 1.56, 1.54.2 + * Since: 1.56 **/ _nm_setting_property_define_direct_enum(properties_override, obj_properties, @@ -338,7 +338,7 @@ nm_setting_hsr_class_init(NMSettingHsrClass *klass) * * The optional interlink port name of the HSR interface. * - * Since: 1.56, 1.54.2 + * Since: 1.56 **/ _nm_setting_property_define_direct_string(properties_override, obj_properties, diff --git a/src/libnm-core-impl/nm-setting-ip-config.c b/src/libnm-core-impl/nm-setting-ip-config.c index ad95eb1a..1aecc20c 100644 --- a/src/libnm-core-impl/nm-setting-ip-config.c +++ b/src/libnm-core-impl/nm-setting-ip-config.c @@ -4221,6 +4221,25 @@ nm_setting_ip_config_clear_dns(NMSettingIPConfig *setting) } } +/** + * nm_dns_server_validate: + * @str: the string containing the DNS server + * @family: the IP address family (%AF_INET for IPv4, %AF_INET6 for IPv6, + * %AF_UNSPEC to accept both IPv4 and IPv6) + * @error: (nullable): a pointer to %NULL #GError, or %NULL + * + * Validates a DNS name server string. + * + * Return: %TRUE if the name server is valid, %FALSE otherwise + * + * Since: 1.56 + */ +gboolean +nm_dns_server_validate(const char *str, int family, GError **error) +{ + return nm_dns_uri_parse(family, str, NULL, error); +} + GPtrArray * _nm_setting_ip_config_get_dns_array(NMSettingIPConfig *setting) { @@ -5630,14 +5649,19 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) /* Validate DNS */ if (priv->dns) { for (i = 0; i < priv->dns->len; i++) { - const char *dns = priv->dns->pdata[i]; + const char *dns = priv->dns->pdata[i]; + gs_free_error GError *local = NULL; - if (!nm_dns_uri_parse(NM_SETTING_IP_CONFIG_GET_ADDR_FAMILY(setting), dns, NULL)) { + if (!nm_dns_uri_parse(NM_SETTING_IP_CONFIG_GET_ADDR_FAMILY(setting), + dns, + NULL, + &local)) { g_set_error(error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("%u. DNS server address is invalid"), - (i + 1u)); + _("%u. DNS server address is invalid: %s"), + (i + 1u), + local->message); g_prefix_error(error, "%s.%s: ", nm_setting_get_name(setting), @@ -5647,6 +5671,28 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) } } + /* Validate DNS search domains */ + if (nm_strvarray_get_strv_notempty(priv->dns_search.arr, NULL)) { + for (i = 0; i < priv->dns_search.arr->len; i++) { + const char *dns_search = nm_strvarray_get_idx(priv->dns_search.arr, i); + + /* TODO: currently we only check that no wrong list separators have + * been used by mistake. Proper domain name validation would be better. */ + if (strpbrk(dns_search, ",; ")) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("DNS search domain '%s' is invalid"), + dns_search); + g_prefix_error(error, + "%s.%s: ", + nm_setting_get_name(setting), + NM_SETTING_IP_CONFIG_DNS_SEARCH); + return FALSE; + } + } + } + /* Validate addresses */ for (i = 0; i < priv->addresses->len; i++) { NMIPAddress *addr = (NMIPAddress *) priv->addresses->pdata[i]; @@ -6694,7 +6740,7 @@ nm_setting_ip_config_class_init(NMSettingIPConfigClass *klass) * NMSettingIPConfig:gateway: * * The gateway associated with this configuration. This is only meaningful - * if #NMSettingIPConfig:addresses is also set. + * if addresses are also set on the device. * * Setting the gateway causes NetworkManager to configure a standard default route * with the gateway as next hop. This is ignored if #NMSettingIPConfig:never-default diff --git a/src/libnm-core-impl/nm-setting-wireguard.c b/src/libnm-core-impl/nm-setting-wireguard.c index 614be0f6..9a324188 100644 --- a/src/libnm-core-impl/nm-setting-wireguard.c +++ b/src/libnm-core-impl/nm-setting-wireguard.c @@ -2532,6 +2532,73 @@ nm_setting_wireguard_class_init(NMSettingWireGuardClass *klass) NMSettingWireGuard, _priv.ip6_auto_default_route); + /* ---nmcli--- + * property: peers + * format: a comma-separated list of WireGuard peers + * description: + * A comma-separated list of WireGuard peers. Each peer has the following syntax: + * + * PUBLIC_KEY [ATTRIBUTE=VALUE [ATTRIBUTE=VALUE]...] + * + * The supported attributes are: endpoint, allowed-ips, persistent-keepalive, + * preshared-key, preshared-key-flags. + * description-docbook: + * <para> + * A comma-separated list of WireGuard peers. Each peer has the following syntax: + * </para> + * <para> + * <literal> + * <replaceable>public-key</replaceable> + * [<replaceable>attribute</replaceable>=<replaceable>value</replaceable> + * [<replaceable>attribute</replaceable>=<replaceable>value</replaceable>]...] + * </literal> + * </para> + * <para> + * The public key is required and must be encoded as base64; it can be + * calculated by running <command>wg pubkey</command> on the private key, + * and it is usually transmitted out of band to the author of the configuration + * file. + * </para> + * <para> + * The supported attributes are: + * <variablelist> + * <varlistentry> + * <term><varname>endpoint</varname></term> + * <listitem><para>An endpoint IP or hostname, followed by a colon, and then + * a port number.</para></listitem> + * </varlistentry> + * + * <varlistentry> + * <term><varname></varname></term> + * <listitem><para></para></listitem> + * </varlistentry> + * <varlistentry> + * <term><varname>allowed-ips</varname></term> + * <listitem><para>A semicolon-separated list of IP (v4 or v6) addresses + * with CIDR masks from which incoming traffic for this peer is allowed + * and to which outgoing traffic for this peer is directed + * </para></listitem> + * </varlistentry> + * <varlistentry> + * <term><varname>persistent-keepalive</varname></term> + * <listitem><para>An interval in seconds, between 1 and 65535, of + * how often to send an authenticated empty packet to the peer for the + * purpose of keeping a stateful firewall or NAT mapping valid persistently. + * </para></listitem> + * </varlistentry> + * <varlistentry> + * <term><varname>preshared-key</varname></term> + * <listitem><para>A base64 preshared key generated by "wg genpsk". Optional, + * and may be omitted.</para></listitem> + * </varlistentry> + * <varlistentry> + * <term><varname>preshared-key-flags</varname></term> + * <listitem><para>The secret flags for the preshared-key.</para></listitem> + * </varlistentry> + * </variablelist> + * </para> + * ---end--- + */ /* ---dbus--- * property: peers * format: array of 'a{sv}' diff --git a/src/libnm-core-impl/nm-utils.c b/src/libnm-core-impl/nm-utils.c index 9a78e947..1bf00831 100644 --- a/src/libnm-core-impl/nm-utils.c +++ b/src/libnm-core-impl/nm-utils.c @@ -6336,7 +6336,7 @@ helper_child_terminated(GPid pid, int status, gpointer user_data) * if an error occurred, including when the given user can't access the * file. * - * Since: 1.56, 1.54.3 + * Since: 1.56 */ char * nm_utils_copy_cert_as_user(const char *filename, const char *user, GError **error) @@ -6444,6 +6444,7 @@ nm_utils_copy_cert_as_user(const char *filename, const char *user, GError **erro 0600, NULL, NULL, + NULL, error)) { return NULL; } diff --git a/src/libnm-core-impl/nm-vpn-plugin-info.c b/src/libnm-core-impl/nm-vpn-plugin-info.c index 04b0fb16..47dc9e3b 100644 --- a/src/libnm-core-impl/nm-vpn-plugin-info.c +++ b/src/libnm-core-impl/nm-vpn-plugin-info.c @@ -921,7 +921,7 @@ nm_vpn_plugin_info_supports_multiple(NMVpnPluginInfo *self) * private connections in a safe way (i.e. checking user permissions), or if the service doesn't need to read any file from disk. * - * Since: 1.56, 1.54.3 + * Since: 1.56 */ gboolean nm_vpn_plugin_info_supports_safe_private_file_access(NMVpnPluginInfo *self) diff --git a/src/libnm-core-impl/tests/test-general.c b/src/libnm-core-impl/tests/test-general.c index 43e73c3d..cd480045 100644 --- a/src/libnm-core-impl/tests/test-general.c +++ b/src/libnm-core-impl/tests/test-general.c @@ -4032,6 +4032,7 @@ test_connection_diff_a_only(void) {NM_SETTING_CONNECTION_MDNS, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_CONNECTION_LLMNR, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_CONNECTION_DNS_OVER_TLS, NM_SETTING_DIFF_RESULT_IN_A}, + {NM_SETTING_CONNECTION_DNSSEC, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_CONNECTION_MPTCP_FLAGS, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_CONNECTION_MUD_URL, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT, NM_SETTING_DIFF_RESULT_IN_A}, @@ -11400,12 +11401,16 @@ test_connection_path(void) static void t_dns_0(const char *str) { - NMDnsServer server = {}; - gboolean ret; + gs_free_error GError *error = NULL; + NMDnsServer server = {}; + gboolean ret; - ret = nm_dns_uri_parse(AF_UNSPEC, str, &server); + ret = nm_dns_uri_parse(AF_UNSPEC, str, &server, &error); g_assert(!ret); + g_assert(error); + g_assert(error->message); + g_assert(error->message[0] != '\0'); } static void @@ -11422,10 +11427,12 @@ dns_uri_parse_ok(const char *str, gboolean ret; for (int i = 0; i < 2; i++) { - gboolean af_unspec = i; + gs_free_error GError *error = NULL; + gboolean af_unspec = i; - ret = nm_dns_uri_parse(af_unspec ? AF_UNSPEC : addr_family, str, &dns); + ret = nm_dns_uri_parse(af_unspec ? AF_UNSPEC : addr_family, str, &dns, &error); g_assert(ret); + g_assert_no_error(error); g_assert_cmpint(addr_family, ==, dns.addr_family); g_assert_cmpint(port, ==, dns.port); @@ -11436,8 +11443,9 @@ dns_uri_parse_ok(const char *str, g_assert_cmpstr(addrstr, ==, addr); /* Parse with the wrong address family must fail */ - ret = nm_dns_uri_parse(addr_family == AF_INET ? AF_INET6 : AF_INET, str, &dns); + ret = nm_dns_uri_parse(addr_family == AF_INET ? AF_INET6 : AF_INET, str, &dns, &error); g_assert(!ret); + g_assert(error); } } diff --git a/src/libnm-core-impl/tests/test-setting.c b/src/libnm-core-impl/tests/test-setting.c index 13d95189..f3070c17 100644 --- a/src/libnm-core-impl/tests/test-setting.c +++ b/src/libnm-core-impl/tests/test-setting.c @@ -5460,6 +5460,44 @@ test_settings_dns(void) } } +static void +_assert_dns_searches(gboolean valid, ...) +{ + NMConnection *con; + NMSettingIPConfig *ip4, *ip6; + const char *dns_search; + va_list args; + + con = nmtst_create_minimal_connection("test-dns-search", + NULL, + NM_SETTING_WIRED_SETTING_NAME, + NULL); + nmtst_connection_normalize(con); + ip4 = nm_connection_get_setting_ip4_config(con); + ip6 = nm_connection_get_setting_ip6_config(con); + + va_start(args, valid); + while ((dns_search = va_arg(args, const char *))) { + nm_setting_ip_config_add_dns_search(ip4, dns_search); + nm_setting_ip_config_add_dns_search(ip6, dns_search); + } + va_end(args); + + g_assert(valid == nm_setting_verify((NMSetting *) ip4, con, NULL)); + g_assert(valid == nm_setting_verify((NMSetting *) ip6, con, NULL)); +} + +static void +test_settings_dns_search_domains(void) +{ + _assert_dns_searches(TRUE, "example.com", NULL); + _assert_dns_searches(TRUE, "sub.example.com", NULL); + _assert_dns_searches(TRUE, "example.com", "sub.example.com", NULL); + _assert_dns_searches(FALSE, "example.com,sub.example.com", NULL); + _assert_dns_searches(FALSE, "example.com;sub.example.com", NULL); + _assert_dns_searches(FALSE, "example.com sub.example.com", NULL); +} + /*****************************************************************************/ static void @@ -5787,6 +5825,7 @@ main(int argc, char **argv) g_test_add_func("/libnm/settings/6lowpan/1", test_6lowpan_1); g_test_add_func("/libnm/settings/dns", test_settings_dns); + g_test_add_func("/libnm/settings/dns_search_domain", test_settings_dns_search_domains); g_test_add_func("/libnm/settings/sriov/vf", test_sriov_vf); g_test_add_func("/libnm/settings/sriov/vf-dup", test_sriov_vf_dup); diff --git a/src/libnm-core-public/nm-dbus-interface.h b/src/libnm-core-public/nm-dbus-interface.h index e62d64e1..42bff04a 100644 --- a/src/libnm-core-public/nm-dbus-interface.h +++ b/src/libnm-core-public/nm-dbus-interface.h @@ -648,6 +648,8 @@ typedef enum { * Since: 1.48 * @NM_DEVICE_STATE_REASON_UNMANAGED_USER_UDEV: The device is unmanaged via udev rule. Since: 1.48 * @NM_DEVICE_STATE_REASON_NETWORKING_OFF: NetworkManager was disabled (networking off). Since: 1.56 + * @NM_DEVICE_STATE_REASON_MODEM_NO_OPERATOR_CODE: The modem's operator code wasn't available, + * and auto-configuration was requested. Since: 1.56 * * Device state change reason codes */ @@ -732,6 +734,7 @@ typedef enum { NM_DEVICE_STATE_REASON_UNMANAGED_USER_SETTINGS = 76, NM_DEVICE_STATE_REASON_UNMANAGED_USER_UDEV = 77, NM_DEVICE_STATE_REASON_NETWORKING_OFF = 78, + NM_DEVICE_STATE_REASON_MODEM_NO_OPERATOR_CODE = 79, } NMDeviceStateReason; /** @@ -1457,6 +1460,16 @@ typedef enum /*< flags >*/ { * any additional addresses using the MPTCP ADD_ADDR sub-option, this will behave the same * as a plain subflow endpoint. When the peer does announce addresses, each received ADD_ADDR * sub-option will trigger creation of an additional subflow to generate a full mesh topology. + * @NM_MPTCP_FLAGS_LAMINAR: Flag for the MPTCP endpoint. The endpoint will be + * used to create new subflows from the associated address to additional + * addresses announced by the other peer. This will be done if allowed by the + * MPTCP limits, and if the associated address is not already being used by + * another subflow from the same MPTCP connection. Note that the 'fullmesh' + * flag takes precedence over the 'laminar' one. Without any of these two + * flags, the path-manager will create new subflows to additional addresses + * announced by the other peer by selecting the source address from the + * routing tables, which is harder to configure if the announced address is + * not known in advance. Since: 1.56 * * Since: 1.40 */ @@ -1473,6 +1486,7 @@ typedef enum /*< flags >*/ { NM_MPTCP_FLAGS_SUBFLOW = 0x20, NM_MPTCP_FLAGS_BACKUP = 0x40, NM_MPTCP_FLAGS_FULLMESH = 0x80, + NM_MPTCP_FLAGS_LAMINAR = 0x100, } NMMptcpFlags; /* For secrets requests, hints starting with "x-vpn-message:" are a message to show, not diff --git a/src/libnm-core-public/nm-errors.h b/src/libnm-core-public/nm-errors.h index 11ce25f1..1cf238c0 100644 --- a/src/libnm-core-public/nm-errors.h +++ b/src/libnm-core-public/nm-errors.h @@ -256,6 +256,11 @@ GQuark nm_secret_agent_error_quark(void); * @NM_SETTINGS_ERROR_NOT_SUPPORTED_BY_PLUGIN: the requested operation is not * supported by the settings plugin currently in use for the specified object. * Since: 1.44. + * @NM_SETTINGS_ERROR_FEATURE_DISABLED: the requested operation failed because it + * requires a feature that is disabled in this build of NetworkManager. + * Since: 1.56 + * @NM_SETTINGS_ERROR_FEATURE_REMOVED: the requested operation failed because it + * requires a feature that is no longer supported. Since: 1.56 * * Errors related to the settings/persistent configuration interface of * NetworkManager. @@ -275,6 +280,8 @@ typedef enum { NM_SETTINGS_ERROR_INVALID_ARGUMENTS, /*< nick=InvalidArguments >*/ NM_SETTINGS_ERROR_VERSION_ID_MISMATCH, /*< nick=VersionIdMismatch >*/ NM_SETTINGS_ERROR_NOT_SUPPORTED_BY_PLUGIN, /*< nick=NotSupportedByPlugin >*/ + NM_SETTINGS_ERROR_FEATURE_DISABLED, /*< nick=FeatureDisabled >*/ + NM_SETTINGS_ERROR_FEATURE_REMOVED, /*< nick=FeatureRemoved >*/ } NMSettingsError; GQuark nm_settings_error_quark(void); diff --git a/src/libnm-core-public/nm-setting-connection.h b/src/libnm-core-public/nm-setting-connection.h index 6547c5be..51cf99fb 100644 --- a/src/libnm-core-public/nm-setting-connection.h +++ b/src/libnm-core-public/nm-setting-connection.h @@ -60,6 +60,7 @@ G_BEGIN_DECLS #define NM_SETTING_CONNECTION_MDNS "mdns" #define NM_SETTING_CONNECTION_LLMNR "llmnr" #define NM_SETTING_CONNECTION_DNS_OVER_TLS "dns-over-tls" +#define NM_SETTING_CONNECTION_DNSSEC "dnssec" #define NM_SETTING_CONNECTION_MPTCP_FLAGS "mptcp-flags" #define NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT "wait-device-timeout" #define NM_SETTING_CONNECTION_MUD_URL "mud-url" @@ -163,6 +164,24 @@ typedef enum { } NMSettingConnectionDnsOverTls; /** + * NMSettingConnectionDnssec: + * @NM_SETTING_CONNECTION_DNSSEC_DEFAULT: default value + * @NM_SETTING_CONNECTION_DNSSEC_NO: disable DNSSEC + * @NM_SETTING_CONNECTION_DNSSEC_ALLOW_DOWNGRADE: enable DNSSEC but allow fallback to non-DNSSEC mode + * @NM_SETTING_CONNECTION_DNSSEC_YES: force enable DNSSEC + * + * #NMSettingConnectionDnssec values indicate whether DNSSEC should be enabled. + * + * Since: 1.56 + */ +typedef enum { + NM_SETTING_CONNECTION_DNSSEC_DEFAULT = -1, + NM_SETTING_CONNECTION_DNSSEC_NO = 0, + NM_SETTING_CONNECTION_DNSSEC_ALLOW_DOWNGRADE = 1, + NM_SETTING_CONNECTION_DNSSEC_YES = 2, +} NMSettingConnectionDnssec; + +/** * NMSettingConnectionDownOnPoweroff: * @NM_SETTING_CONNECTION_DOWN_ON_POWEROFF_DEFAULT: default value * @NM_SETTING_CONNECTION_DOWN_ON_POWEROFF_NO: disable down-on-poweroff @@ -304,6 +323,9 @@ void nm_setting_connection_clear_ip_ping_addresses(NMSettingConnection *setting) NM_AVAILABLE_IN_1_52 NMTernary nm_setting_connection_get_ip_ping_addresses_require_all(NMSettingConnection *setting); +NM_AVAILABLE_IN_1_56 +NMSettingConnectionDnssec nm_setting_connection_get_dnssec(NMSettingConnection *setting); + G_END_DECLS #endif /* __NM_SETTING_CONNECTION_H__ */ diff --git a/src/libnm-core-public/nm-setting-gsm.h b/src/libnm-core-public/nm-setting-gsm.h index c8663502..4f71f70e 100644 --- a/src/libnm-core-public/nm-setting-gsm.h +++ b/src/libnm-core-public/nm-setting-gsm.h @@ -50,6 +50,7 @@ G_BEGIN_DECLS #define NM_SETTING_GSM_INITIAL_EPS_BEARER_REFUSE_CHAP "initial-eps-bearer-refuse-chap" #define NM_SETTING_GSM_INITIAL_EPS_BEARER_REFUSE_MSCHAP "initial-eps-bearer-refuse-mschap" #define NM_SETTING_GSM_INITIAL_EPS_BEARER_REFUSE_MSCHAPV2 "initial-eps-bearer-refuse-mschapv2" +#define NM_SETTING_GSM_DEVICE_UID "device-uid" /* Deprecated */ #define NM_SETTING_GSM_NUMBER "number" @@ -99,6 +100,8 @@ gboolean nm_setting_gsm_get_initial_eps_refuse_mschap(NMSettingGsm *setting); NM_AVAILABLE_IN_1_52 gboolean nm_setting_gsm_get_initial_eps_refuse_mschapv2(NMSettingGsm *setting); +const char *nm_setting_gsm_get_device_uid(NMSettingGsm *setting); + NM_DEPRECATED_IN_1_16 const char *nm_setting_gsm_get_number(NMSettingGsm *setting); diff --git a/src/libnm-core-public/nm-setting-hsr.h b/src/libnm-core-public/nm-setting-hsr.h index 414f2b34..3110bd9a 100644 --- a/src/libnm-core-public/nm-setting-hsr.h +++ b/src/libnm-core-public/nm-setting-hsr.h @@ -38,7 +38,7 @@ G_BEGIN_DECLS * * #NMSettingHsrProtocolVersion values indicate the HSR protocol version. * - * Since: 1.56, 1.54.2 + * Since: 1.56 */ typedef enum { NM_SETTING_HSR_PROTOCOL_VERSION_DEFAULT = -1, @@ -61,9 +61,9 @@ NM_AVAILABLE_IN_1_46 guint32 nm_setting_hsr_get_multicast_spec(NMSettingHsr *setting); NM_AVAILABLE_IN_1_46 gboolean nm_setting_hsr_get_prp(NMSettingHsr *setting); -NM_AVAILABLE_IN_1_54_2 +NM_AVAILABLE_IN_1_56 NMSettingHsrProtocolVersion nm_setting_hsr_get_protocol_version(NMSettingHsr *setting); -NM_AVAILABLE_IN_1_54_2 +NM_AVAILABLE_IN_1_56 const char *nm_setting_hsr_get_interlink(NMSettingHsr *setting); G_END_DECLS diff --git a/src/libnm-core-public/nm-setting-ip-config.h b/src/libnm-core-public/nm-setting-ip-config.h index 625b941f..de05325f 100644 --- a/src/libnm-core-public/nm-setting-ip-config.h +++ b/src/libnm-core-public/nm-setting-ip-config.h @@ -567,6 +567,9 @@ int nm_setting_ip_config_get_shared_dhcp_lease_time(NMSettingIPConfig *setting); NM_AVAILABLE_IN_1_54 NMSettingIPConfigForwarding nm_setting_ip_config_get_forwarding(NMSettingIPConfig *setting); +NM_AVAILABLE_IN_1_56 +gboolean nm_dns_server_validate(const char *str, int family, GError **error); + G_END_DECLS #endif /* NM_SETTING_IP_CONFIG_H */ diff --git a/src/libnm-core-public/nm-utils.h b/src/libnm-core-public/nm-utils.h index dd7977a1..e46bf472 100644 --- a/src/libnm-core-public/nm-utils.h +++ b/src/libnm-core-public/nm-utils.h @@ -261,7 +261,7 @@ nm_utils_base64secret_decode(const char *base64_key, gsize required_key_len, gui NM_AVAILABLE_IN_1_42 void nm_utils_ensure_gtypes(void); -NM_AVAILABLE_IN_1_54_3 +NM_AVAILABLE_IN_1_56 char *nm_utils_copy_cert_as_user(const char *filename, const char *user, GError **error); G_END_DECLS diff --git a/src/libnm-core-public/nm-version-macros.h.in b/src/libnm-core-public/nm-version-macros.h.in index 9771944d..b8b89a44 100644 --- a/src/libnm-core-public/nm-version-macros.h.in +++ b/src/libnm-core-public/nm-version-macros.h.in @@ -78,20 +78,19 @@ #define NM_VERSION_1_50 (NM_ENCODE_VERSION(1, 50, 0)) #define NM_VERSION_1_52 (NM_ENCODE_VERSION(1, 52, 0)) #define NM_VERSION_1_54 (NM_ENCODE_VERSION(1, 54, 0)) -#define NM_VERSION_1_54_2 (NM_ENCODE_VERSION(1, 54, 2)) -#define NM_VERSION_1_54_3 (NM_ENCODE_VERSION(1, 54, 3)) +#define NM_VERSION_1_56 (NM_ENCODE_VERSION(1, 56, 0)) /* For releases, NM_API_VERSION is equal to NM_VERSION. * - * For development builds, NM_API_VERSION is the next - * stable API after NM_VERSION. When you run a development + * For development and RC builds, NM_API_VERSION is the next + * stable API after NM_VERSION. When you run a devel or RC * version, you are already using the future API, even if * it is not yet released. Hence, the currently used API * version is the future one. */ #define NM_API_VERSION \ (((NM_MINOR_VERSION % 2) == 1) \ ? NM_ENCODE_VERSION(NM_MAJOR_VERSION, NM_MINOR_VERSION + 1, 0) \ - : NM_ENCODE_VERSION(NM_MAJOR_VERSION, NM_MINOR_VERSION, NM_MICRO_VERSION + 1)) + : NM_VERSION) /* deprecated. */ #define NM_VERSION_CUR_STABLE NM_API_VERSION diff --git a/src/libnm-core-public/nm-version.h b/src/libnm-core-public/nm-version.h index 26ede654..af45b679 100644 --- a/src/libnm-core-public/nm-version.h +++ b/src/libnm-core-public/nm-version.h @@ -12,16 +12,16 @@ /* Deprecation / Availability macros */ -#if !defined(NM_VERSION_MIN_REQUIRED) || (NM_VERSION_MIN_REQUIRED == 0) -#undef NM_VERSION_MIN_REQUIRED -#define NM_VERSION_MIN_REQUIRED (NM_API_VERSION) -#endif - #if !defined(NM_VERSION_MAX_ALLOWED) || (NM_VERSION_MAX_ALLOWED == 0) #undef NM_VERSION_MAX_ALLOWED #define NM_VERSION_MAX_ALLOWED (NM_API_VERSION) #endif +#if !defined(NM_VERSION_MIN_REQUIRED) || (NM_VERSION_MIN_REQUIRED == 0) +#undef NM_VERSION_MIN_REQUIRED +#define NM_VERSION_MIN_REQUIRED (NM_VERSION_MAX_ALLOWED) +#endif + /* sanity checks */ #if NM_VERSION_MIN_REQUIRED > NM_API_VERSION #error "NM_VERSION_MIN_REQUIRED must be <= NM_API_VERSION" @@ -439,16 +439,18 @@ #define NM_AVAILABLE_IN_1_54 #endif -#if NM_VERSION_MAX_ALLOWED < NM_VERSION_1_54_2 -#define NM_AVAILABLE_IN_1_54_2 G_UNAVAILABLE(1, 54.2) +#if NM_VERSION_MIN_REQUIRED >= NM_VERSION_1_56 +#define NM_DEPRECATED_IN_1_56 G_DEPRECATED +#define NM_DEPRECATED_IN_1_56_FOR(f) G_DEPRECATED_FOR(f) #else -#define NM_AVAILABLE_IN_1_54_2 +#define NM_DEPRECATED_IN_1_56 +#define NM_DEPRECATED_IN_1_56_FOR(f) #endif -#if NM_VERSION_MAX_ALLOWED < NM_VERSION_1_54_3 -#define NM_AVAILABLE_IN_1_54_3 G_UNAVAILABLE(1, 54.3) +#if NM_VERSION_MAX_ALLOWED < NM_VERSION_1_56 +#define NM_AVAILABLE_IN_1_56 G_UNAVAILABLE(1, 56) #else -#define NM_AVAILABLE_IN_1_54_3 +#define NM_AVAILABLE_IN_1_56 #endif /* diff --git a/src/libnm-core-public/nm-vpn-plugin-info.h b/src/libnm-core-public/nm-vpn-plugin-info.h index a6396862..0f2618ac 100644 --- a/src/libnm-core-public/nm-vpn-plugin-info.h +++ b/src/libnm-core-public/nm-vpn-plugin-info.h @@ -64,7 +64,7 @@ NM_AVAILABLE_IN_1_4 gboolean nm_vpn_plugin_info_supports_hints(NMVpnPluginInfo *self); NM_AVAILABLE_IN_1_42 gboolean nm_vpn_plugin_info_supports_multiple(NMVpnPluginInfo *self); -NM_AVAILABLE_IN_1_54_3 +NM_AVAILABLE_IN_1_56 gboolean nm_vpn_plugin_info_supports_safe_private_file_access(NMVpnPluginInfo *self); NM_AVAILABLE_IN_1_4 const char *const *nm_vpn_plugin_info_get_aliases(NMVpnPluginInfo *self); diff --git a/src/libnm-glib-aux/nm-io-utils.c b/src/libnm-glib-aux/nm-io-utils.c index 9443172b..d26ecee4 100644 --- a/src/libnm-glib-aux/nm-io-utils.c +++ b/src/libnm-glib-aux/nm-io-utils.c @@ -415,8 +415,10 @@ nm_utils_file_get_contents(int dirfd, /* * Copied from GLib's g_file_set_contents() et al., but allows - * specifying a mode for the new file and optionally the last access - * and last modification times. + * specifying: + * - the file mode (@mode) + * - optionally, the last access and modification times (@times) + * - optionally, a fixed name for the temporary file (@tmp_name) */ gboolean nm_utils_file_set_contents(const char *filename, @@ -424,10 +426,11 @@ nm_utils_file_set_contents(const char *filename, gssize length, mode_t mode, const struct timespec *times, + const char *tmp_name, int *out_errsv, GError **error) { - gs_free char *tmp_name = NULL; + gs_free char *tmp_name_free = NULL; struct stat statbuf; int errsv; gssize s; @@ -442,8 +445,13 @@ nm_utils_file_set_contents(const char *filename, if (length == -1) length = strlen(contents); - tmp_name = g_strdup_printf("%s.XXXXXX", filename); - fd = g_mkstemp_full(tmp_name, O_RDWR | O_CLOEXEC, mode); + if (tmp_name) { + fd = open(tmp_name, O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC, mode); + } else { + tmp_name_free = g_strdup_printf("%s.XXXXXX", filename); + tmp_name = tmp_name_free; + fd = g_mkstemp_full(tmp_name_free, O_RDWR | O_CLOEXEC, mode); + } if (fd < 0) { return _get_contents_error_errno(error, out_errsv, "failed to create file %s", tmp_name); } diff --git a/src/libnm-glib-aux/nm-io-utils.h b/src/libnm-glib-aux/nm-io-utils.h index 0021138f..ff02ecb1 100644 --- a/src/libnm-glib-aux/nm-io-utils.h +++ b/src/libnm-glib-aux/nm-io-utils.h @@ -55,6 +55,7 @@ gboolean nm_utils_file_set_contents(const char *filename, gssize length, mode_t mode, const struct timespec *times, + const char *tmp_name, int *out_errsv, GError **error); diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 0c1097c2..cc5b99e0 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -59,6 +59,7 @@ G_STATIC_ASSERT(NM_MPTCP_PM_ADDR_FLAG_SUBFLOW == MPTCP_PM_ADDR_FLAG_SUBFLOW); G_STATIC_ASSERT(NM_MPTCP_PM_ADDR_FLAG_BACKUP == MPTCP_PM_ADDR_FLAG_BACKUP); G_STATIC_ASSERT(NM_MPTCP_PM_ADDR_FLAG_FULLMESH == MPTCP_PM_ADDR_FLAG_FULLMESH); G_STATIC_ASSERT(NM_MPTCP_PM_ADDR_FLAG_IMPLICIT == MPTCP_PM_ADDR_FLAG_IMPLICIT); +G_STATIC_ASSERT(NM_MPTCP_PM_ADDR_FLAG_LAMINAR == MPTCP_PM_ADDR_FLAG_LAMINAR); /*****************************************************************************/ @@ -4014,6 +4015,7 @@ _new_from_nl_route(const struct nlmsghdr *nlh, gboolean id_only, ParseNlmsgIter [RTA_PREF] = {.type = NLA_U8}, [RTA_FLOW] = {.type = NLA_U32}, [RTA_CACHEINFO] = {.minlen = nm_offsetofend(struct rta_cacheinfo, rta_tsage)}, + [RTA_VIA] = {.minlen = nm_offsetofend(struct rtvia, rtvia_family)}, [RTA_METRICS] = {.type = NLA_NESTED}, [RTA_MULTIPATH] = {.type = NLA_NESTED}, }; @@ -4030,9 +4032,11 @@ _new_from_nl_route(const struct nlmsghdr *nlh, gboolean id_only, ParseNlmsgIter guint8 weight; int ifindex; NMIPAddr gateway; + gboolean is_via; } nh = { .found = FALSE, .has_more = FALSE, + .is_via = FALSE, }; guint v4_n_nexthops = 0; NMPlatformIP4RtNextHop v4_nh_extra_nexthops_stack[10]; @@ -4201,13 +4205,26 @@ rta_multipath_done: return nm_assert_unreachable_val(NULL); } - if (tb[RTA_OIF] || tb[RTA_GATEWAY] || tb[RTA_FLOW]) { + if (tb[RTA_OIF] || tb[RTA_GATEWAY] || tb[RTA_FLOW] || tb[RTA_VIA]) { int ifindex = 0; NMIPAddr gateway = {}; if (tb[RTA_OIF]) ifindex = nla_get_u32(tb[RTA_OIF]); - if (_check_addr_or_return_null(tb, RTA_GATEWAY, addr_len)) + + if (tb[RTA_VIA]) { + struct rtvia *rtvia; + + /* Used when the gateway family doesn't match the route family */ + rtvia = nla_data(tb[RTA_VIA]); + if (rtvia->rtvia_family != AF_INET6) + return NULL; + if (nla_len(tb[RTA_VIA]) < sizeof(struct rtvia) + sizeof(struct in6_addr)) + return NULL; + + nh.is_via = TRUE; + memcpy(&gateway, rtvia->rtvia_addr, sizeof(struct in6_addr)); + } else if (_check_addr_or_return_null(tb, RTA_GATEWAY, addr_len)) memcpy(&gateway, nla_data(tb[RTA_GATEWAY]), addr_len); if (!nh.found) { @@ -4223,6 +4240,9 @@ rta_multipath_done: } else { /* Kernel supports new style nexthop configuration, * verify that it is a duplicate and ignore old-style nexthop. */ + if (nh.is_via) + return NULL; + if (nh.ifindex != ifindex || memcmp(&nh.gateway, &gateway, addr_len) != 0) { /* we have a RTA_MULTIPATH attribute that does not agree. * That seems not right. Error out. */ @@ -4238,7 +4258,7 @@ rta_multipath_done: * 1 (lo). Of course it does!! */ if (nh.found) { if (IS_IPv4) { - if (nh.ifindex != 0 || nh.gateway.addr4 != 0) { + if (nh.ifindex != 0 || nh.gateway.addr4 != 0 || nh.is_via) { /* we only accept kernel to notify about the ifindex/gateway, if it * is zero. This is only to be a bit forgiving, but we really don't * know how to handle such routes that have an ifindex. */ @@ -4337,9 +4357,14 @@ rta_multipath_done: if (tb[RTA_PRIORITY]) obj->ip_route.metric = nla_get_u32(tb[RTA_PRIORITY]); - if (IS_IPv4) - obj->ip4_route.gateway = nh.gateway.addr4; - else + if (IS_IPv4) { + if (nh.is_via) { + obj->ip4_route.via.addr_family = AF_INET6; + obj->ip4_route.via.addr = nh.gateway; + } else { + obj->ip4_route.gateway = nh.gateway.addr4; + } + } else obj->ip6_route.gateway = nh.gateway.addr6; if (IS_IPv4) @@ -5838,7 +5863,24 @@ _nl_msg_new_route(uint16_t nlmsg_type, uint16_t nlmsg_flags, const NMPObject *ob /* We currently don't have need for multi-hop routes... */ if (IS_IPv4) { - NLA_PUT(msg, RTA_GATEWAY, addr_len, &obj->ip4_route.gateway); + if (obj->ip4_route.gateway == INADDR_ANY && obj->ip4_route.via.addr_family != AF_UNSPEC) { + struct rtvia *rtvia; + + nm_assert(obj->ip4_route.via.addr_family == AF_INET6); + + rtvia = nla_data(nla_reserve( + msg, + RTA_VIA, + sizeof(*rtvia) + nm_utils_addr_family_to_size(obj->ip4_route.via.addr_family))); + if (!rtvia) + goto nla_put_failure; + rtvia->rtvia_family = obj->ip4_route.via.addr_family; + memcpy(rtvia->rtvia_addr, + obj->ip4_route.via.addr.addr_ptr, + nm_utils_addr_family_to_size(obj->ip4_route.via.addr_family)); + } else { + NLA_PUT(msg, RTA_GATEWAY, addr_len, &obj->ip4_route.gateway); + } } else { if (!IN6_IS_ADDR_UNSPECIFIED(&obj->ip6_route.gateway)) NLA_PUT(msg, RTA_GATEWAY, addr_len, &obj->ip6_route.gateway); diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index 33c763c3..853157d2 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -7206,7 +7206,7 @@ nm_platform_ip4_route_to_string_full(const NMPlatformIP4Route *route, { char *buf0; char s_network[INET_ADDRSTRLEN]; - char s_gateway[INET_ADDRSTRLEN]; + char s_gateway[INET6_ADDRSTRLEN]; char s_pref_src[INET_ADDRSTRLEN]; char str_dev[30]; char str_mss[32]; @@ -7235,10 +7235,13 @@ nm_platform_ip4_route_to_string_full(const NMPlatformIP4Route *route, inet_ntop(AF_INET, &route->network, s_network, sizeof(s_network)); - if (route->gateway == 0) - s_gateway[0] = '\0'; - else + if (route->gateway != INADDR_ANY) { inet_ntop(AF_INET, &route->gateway, s_gateway, sizeof(s_gateway)); + } else if (route->via.addr_family == AF_INET6) { + inet_ntop(AF_INET6, route->via.addr.addr_ptr, s_gateway, sizeof(s_gateway)); + } else { + s_gateway[0] = '\0'; + } nm_strbuf_append( &buf, @@ -7979,7 +7982,8 @@ static NM_UTILS_FLAGS2STR_DEFINE(_mptcp_flags_to_string, NM_UTILS_FLAGS2STR(NM_MPTCP_PM_ADDR_FLAG_SIGNAL, "signal"), NM_UTILS_FLAGS2STR(NM_MPTCP_PM_ADDR_FLAG_SUBFLOW, "subflow"), NM_UTILS_FLAGS2STR(NM_MPTCP_PM_ADDR_FLAG_BACKUP, "backup"), - NM_UTILS_FLAGS2STR(NM_MPTCP_PM_ADDR_FLAG_FULLMESH, "fullmesh")); + NM_UTILS_FLAGS2STR(NM_MPTCP_PM_ADDR_FLAG_FULLMESH, "fullmesh"), + NM_UTILS_FLAGS2STR(NM_MPTCP_PM_ADDR_FLAG_LAMINAR, "laminar")); const char * nm_platform_mptcp_addr_to_string(const NMPlatformMptcpAddr *mptcp_addr, char *buf, gsize len) @@ -8978,6 +8982,9 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj, nm_hash_update_vals(h, obj->ifindex, n_nexthops, + obj->via.addr_family, + obj->via.addr_family == AF_INET6 ? obj->via.addr.addr6 + : in6addr_any, obj->gateway, _ip4_route_weight_normalize(n_nexthops, obj->weight, FALSE)); } @@ -9128,6 +9135,10 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a, if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) { NM_CMP_FIELD(a, b, ifindex); NM_CMP_FIELD(a, b, gateway); + NM_CMP_FIELD(a, b, via.addr_family); + if (a->via.addr_family == AF_INET6) { + NM_CMP_FIELD_IN6ADDR(a, b, via.addr.addr6); + } n_nexthops = nm_platform_ip4_route_get_n_nexthops(a); NM_CMP_DIRECT(n_nexthops, nm_platform_ip4_route_get_n_nexthops(b)); NM_CMP_DIRECT(_ip4_route_weight_normalize(n_nexthops, a->weight, FALSE), @@ -9153,6 +9164,10 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a, NM_CMP_FIELD_UNSAFE(a, b, metric_any); NM_CMP_FIELD(a, b, metric); NM_CMP_FIELD(a, b, gateway); + NM_CMP_FIELD(a, b, via.addr_family); + if (a->via.addr_family == AF_INET6) { + NM_CMP_FIELD_IN6ADDR(a, b, via.addr.addr6); + } if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) { n_nexthops = nm_platform_ip4_route_get_n_nexthops(a); NM_CMP_DIRECT(n_nexthops, nm_platform_ip4_route_get_n_nexthops(b)); diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index a63f40c7..033dc515 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -46,6 +46,7 @@ typedef gboolean (*NMPObjectPredicateFunc)(const NMPObject *obj, gpointer user_d #define NM_MPTCP_PM_ADDR_FLAG_BACKUP ((guint32) (1 << 2)) #define NM_MPTCP_PM_ADDR_FLAG_FULLMESH ((guint32) (1 << 3)) #define NM_MPTCP_PM_ADDR_FLAG_IMPLICIT ((guint32) (1 << 4)) +#define NM_MPTCP_PM_ADDR_FLAG_LAMINAR ((guint32) (1 << 5)) /* Redefine this in host's endianness */ #define NM_GRE_KEY 0x2000 @@ -443,6 +444,12 @@ struct _NMPlatformIP4Route { * the first hop. */ in_addr_t gateway; + /* RTA_VIA. Part of the primary key for a route. Allows a gateway for a + * route to exist in a different address family. + * Only valid if: n_nexthops == 1, gateway == 0, via.family != AF_UNSPEC + */ + NMIPAddrTyped via; + /* RTA_PREFSRC (called "src" by iproute2). * * pref_src is part of the ID of an IPv4 route. When deleting a route, @@ -2406,6 +2413,14 @@ nm_platform_ip_route_get_gateway(int addr_family, const NMPlatformIPRoute *route return &((NMPlatformIP6Route *) route)->gateway; } +static inline const NMIPAddrTyped * +nm_platform_ip4_route_get_via(const NMPlatformIP4Route *route) +{ + nm_assert(route); + + return &route->via; +} + static inline gconstpointer nm_platform_ip_route_get_pref_src(int addr_family, const NMPlatformIPRoute *route) { diff --git a/src/libnm-platform/nmp-ethtool.c b/src/libnm-platform/nmp-ethtool.c index ed028f6a..28d12ffb 100644 --- a/src/libnm-platform/nmp-ethtool.c +++ b/src/libnm-platform/nmp-ethtool.c @@ -153,7 +153,7 @@ ethtool_send_and_recv(struct nl_sock *sock, out: if (nle < 0 && err_msg && *err_msg == NULL) - *err_msg = strdup(nm_strerror(nle)); + *err_msg = g_strdup(nm_strerror(nle)); if (nle >= 0 && cb_result < 0) nle = cb_result; diff --git a/src/libnm-platform/nmp-object.c b/src/libnm-platform/nmp-object.c index e11bfb3f..56533c99 100644 --- a/src/libnm-platform/nmp-object.c +++ b/src/libnm-platform/nmp-object.c @@ -893,7 +893,7 @@ const NMPObject * nmp_object_stackinit_id_ip6_address(NMPObject *obj, int ifindex, const struct in6_addr *address) { _nmp_object_stackinit_from_type(obj, NMP_OBJECT_TYPE_IP6_ADDRESS); - obj->ip4_address.ifindex = ifindex; + obj->ip6_address.ifindex = ifindex; if (address) obj->ip6_address.address = *address; return obj; diff --git a/src/libnm-systemd-core/meson.build b/src/libnm-systemd-core/meson.build index 15e1c8a6..00d8a77b 100644 --- a/src/libnm-systemd-core/meson.build +++ b/src/libnm-systemd-core/meson.build @@ -12,6 +12,7 @@ libnm_systemd_core = static_library( 'src/libsystemd-network/sd-dhcp6-lease.c', 'src/libsystemd/sd-device/device-private.c', 'src/libsystemd/sd-device/sd-device.c', + 'src/libsystemd/sd-device/device-util.c', 'src/libsystemd/sd-event/event-util.c', 'src/libsystemd/sd-event/sd-event.c', 'src/libsystemd/sd-id128/id128-util.c', diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h index ecd62ea8..2ef8dc86 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h +++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h @@ -8,8 +8,8 @@ #include <net/ethernet.h> #include <netinet/in.h> -#include "sd-event.h" #include "sd-dhcp6-client.h" +#include "sd-event.h" #include "dhcp-duid-internal.h" #include "dhcp6-client-internal.h" diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-lease-internal.h b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-lease-internal.h index 60cd84f2..62c38588 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-lease-internal.h +++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-lease-internal.h @@ -8,10 +8,10 @@ #include <inttypes.h> #include "sd-dhcp6-lease.h" -#include "dns-resolver-internal.h" #include "dhcp6-option.h" #include "dhcp6-protocol.h" +#include "dns-resolver-internal.h" #include "macro.h" #include "set.h" #include "time-util.h" diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-network.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-network.c index 03732692..1c695a87 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-network.c +++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-network.c @@ -6,13 +6,13 @@ #include "nm-sd-adapt-core.h" #include <errno.h> +#include <linux/if_packet.h> #include <netinet/in.h> #include <netinet/ip6.h> #include <stdio.h> #include <string.h> #include <sys/types.h> #include <unistd.h> -#include <linux/if_packet.h> #include "dhcp6-internal.h" #include "dhcp6-protocol.h" diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c index 5655c0d7..a7cd6a24 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c @@ -6,11 +6,11 @@ #include "nm-sd-adapt-core.h" #include <errno.h> -#include <sys/ioctl.h> #ifdef __GLIBC__ #include <linux/if_arp.h> #endif #include <linux/if_infiniband.h> +#include <sys/ioctl.h> #include "sd-dhcp6-client.h" @@ -1295,7 +1295,8 @@ static int client_receive_message( sd_dhcp6_client *client = ASSERT_PTR(userdata); DHCP6_CLIENT_DONT_DESTROY(client); - /* This needs to be initialized with zero. See #20741. */ + /* This needs to be initialized with zero. See #20741. + * The issue is fixed on glibc-2.35 (8fba672472ae0055387e9315fc2eddfa6775ca79). */ CMSG_BUFFER_TYPE(CMSG_SPACE_TIMEVAL) control = {}; struct iovec iov; union sockaddr_union sa = {}; diff --git a/src/libnm-systemd-core/src/libsystemd/sd-device/device-internal.h b/src/libnm-systemd-core/src/libsystemd/sd-device/device-internal.h index a465eb25..cbd89849 100644 --- a/src/libnm-systemd-core/src/libsystemd/sd-device/device-internal.h +++ b/src/libnm-systemd-core/src/libsystemd/sd-device/device-internal.h @@ -13,6 +13,43 @@ struct sd_device { unsigned n_ref; + /* syspath */ + char *syspath; + const char *devpath; + const char *sysnum; + char *sysname; + + /* only set when device is passed through netlink */ + sd_device_action_t action; + uint64_t seqnum; + + /* basic kernel properties */ + char *subsystem; + char *driver_subsystem; /* only set for the 'drivers' subsystem */ + char *driver; + char *devtype; + + /* device node properties */ + char *devname; + dev_t devnum; + mode_t devmode; + uid_t devuid; + gid_t devgid; + + /* block device properties */ + uint64_t diskseq; /* Block device sequence number, monothonically incremented by the kernel on create/attach */ + + /* network interface properties */ + int ifindex; + + /* determined by devnnum, ifindex, subsystem, and sysname */ + char *device_id; + + /* sysfs attributes */ + Hashmap *sysattr_values; /* cached sysattr values */ + Set *sysattrs; /* names of sysattrs */ + Iterator sysattrs_iterator; + /* The database version indicates the supported features by the udev database. * This is saved and parsed in V field. * @@ -21,68 +58,38 @@ struct sd_device { */ unsigned database_version; - sd_device *parent; + /* when device is initialized by udevd */ + usec_t usec_initialized; - OrderedHashmap *properties; + /* properties */ + OrderedHashmap *properties; /* all properties set from uevent and by udevd */ Iterator properties_iterator; uint64_t properties_generation; /* changes whenever the properties are changed */ uint64_t properties_iterator_generation; /* generation when iteration was started */ + OrderedHashmap *properties_db; /* the subset of the properties that should be written to the db */ + char **properties_strv; /* the properties hashmap as a strv */ + char *properties_nulstr; /* the same as a nulstr */ + size_t properties_nulstr_len; - /* the subset of the properties that should be written to the db */ - OrderedHashmap *properties_db; - - Hashmap *sysattr_values; /* cached sysattr values */ - - Set *sysattrs; /* names of sysattrs */ - Iterator sysattrs_iterator; - + /* TAG keyword */ Set *all_tags, *current_tags; Iterator all_tags_iterator, current_tags_iterator; uint64_t all_tags_iterator_generation, current_tags_iterator_generation; /* generation when iteration was started */ uint64_t tags_generation; /* changes whenever the tags are changed */ + /* SYMLINK keyword */ Set *devlinks; Iterator devlinks_iterator; uint64_t devlinks_generation; /* changes whenever the devlinks are changed */ uint64_t devlinks_iterator_generation; /* generation when iteration was started */ int devlink_priority; + /* parent and child devices */ + sd_device *parent; Hashmap *children; Iterator children_iterator; bool children_enumerated; - int ifindex; - char *devtype; - char *devname; - dev_t devnum; - - char **properties_strv; /* the properties hashmap as a strv */ - char *properties_nulstr; /* the same as a nulstr */ - size_t properties_nulstr_len; - - char *syspath; - const char *devpath; - const char *sysnum; - char *sysname; - - char *subsystem; - char *driver_subsystem; /* only set for the 'drivers' subsystem */ - char *driver; - - char *device_id; - - usec_t usec_initialized; - - mode_t devmode; - uid_t devuid; - gid_t devgid; - - uint64_t diskseq; /* Block device sequence number, monothonically incremented by the kernel on create/attach */ - - /* only set when device is passed through netlink */ - sd_device_action_t action; - uint64_t seqnum; - bool parent_set:1; /* no need to try to reload parent */ bool sysattrs_read:1; /* don't try to re-read sysattrs once read */ bool property_tags_outdated:1; /* need to update TAGS= or CURRENT_TAGS= property */ @@ -92,7 +99,6 @@ struct sd_device { bool driver_set:1; /* don't reread driver */ bool uevent_loaded:1; /* don't reread uevent */ bool db_loaded; /* don't reread db */ - bool is_initialized:1; bool sealed:1; /* don't read more information from uevent/db */ bool db_persist:1; /* don't clean up the db when switching from initrd to real root */ @@ -106,6 +112,8 @@ static inline int device_add_property_internal(sd_device *device, const char *ke int device_set_syspath(sd_device *device, const char *_syspath, bool verify); int device_set_ifindex(sd_device *device, const char *ifindex); +int device_set_devuid(sd_device *device, const char *uid); +int device_set_devgid(sd_device *device, const char *gid); int device_set_devmode(sd_device *device, const char *devmode); int device_set_devname(sd_device *device, const char *devname); int device_set_devtype(sd_device *device, const char *devtype); diff --git a/src/libnm-systemd-core/src/libsystemd/sd-device/device-private.c b/src/libnm-systemd-core/src/libsystemd/sd-device/device-private.c index 6b17e772..aa73184d 100644 --- a/src/libnm-systemd-core/src/libsystemd/sd-device/device-private.c +++ b/src/libnm-systemd-core/src/libsystemd/sd-device/device-private.c @@ -119,6 +119,10 @@ int device_get_devnode_mode(sd_device *device, mode_t *ret) { assert(device); + r = device_read_uevent_file(device); + if (r < 0) + return r; + r = device_read_db(device); if (r < 0) return r; @@ -137,6 +141,10 @@ int device_get_devnode_uid(sd_device *device, uid_t *ret) { assert(device); + r = device_read_uevent_file(device); + if (r < 0) + return r; + r = device_read_db(device); if (r < 0) return r; @@ -150,7 +158,9 @@ int device_get_devnode_uid(sd_device *device, uid_t *ret) { return 0; } -static int device_set_devuid(sd_device *device, const char *uid) { +#endif /* NM_IGNORED */ + +int device_set_devuid(sd_device *device, const char *uid) { uid_t u; int r; @@ -175,6 +185,10 @@ int device_get_devnode_gid(sd_device *device, gid_t *ret) { assert(device); + r = device_read_uevent_file(device); + if (r < 0) + return r; + r = device_read_db(device); if (r < 0) return r; @@ -188,7 +202,7 @@ int device_get_devnode_gid(sd_device *device, gid_t *ret) { return 0; } -static int device_set_devgid(sd_device *device, const char *gid) { +int device_set_devgid(sd_device *device, const char *gid) { gid_t g; int r; @@ -208,6 +222,8 @@ static int device_set_devgid(sd_device *device, const char *gid) { return 0; } +#if 0 /* NM_IGNORED */ + int device_set_action(sd_device *device, sd_device_action_t a) { int r; @@ -432,10 +448,11 @@ static int device_verify(sd_device *device) { return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL), "sd-device: Device created from strv or nulstr lacks devpath, subsystem, action or seqnum."); - if (streq(device->subsystem, "drivers")) { + if (device_in_subsystem(device, "drivers")) { r = device_set_drivers_subsystem(device); if (r < 0) - return r; + return log_device_debug_errno(device, r, + "sd-device: Failed to set driver subsystem: %m"); } device->sealed = true; @@ -682,8 +699,8 @@ int device_clone_with_db(sd_device *device, sd_device **ret) { void device_cleanup_tags(sd_device *device) { assert(device); - device->all_tags = set_free_free(device->all_tags); - device->current_tags = set_free_free(device->current_tags); + device->all_tags = set_free(device->all_tags); + device->current_tags = set_free(device->current_tags); device->property_tags_outdated = true; device->tags_generation++; } @@ -691,7 +708,7 @@ void device_cleanup_tags(sd_device *device) { void device_cleanup_devlinks(sd_device *device) { assert(device); - set_free_free(device->devlinks); + set_free(device->devlinks); device->devlinks = NULL; device->property_devlinks_outdated = true; device->devlinks_generation++; @@ -955,8 +972,4 @@ static const char* const device_action_table[_SD_DEVICE_ACTION_MAX] = { }; DEFINE_STRING_TABLE_LOOKUP(device_action, sd_device_action_t); - -void dump_device_action_table(void) { - DUMP_STRING_TABLE(device_action, sd_device_action_t, _SD_DEVICE_ACTION_MAX); -} #endif /* NM_IGNORED */ diff --git a/src/libnm-systemd-core/src/libsystemd/sd-device/device-private.h b/src/libnm-systemd-core/src/libsystemd/sd-device/device-private.h index eab54203..e07ca602 100644 --- a/src/libnm-systemd-core/src/libsystemd/sd-device/device-private.h +++ b/src/libnm-systemd-core/src/libsystemd/sd-device/device-private.h @@ -9,6 +9,7 @@ #include "sd-device.h" +#include "chase.h" #include "macro.h" int device_new_from_mode_and_devnum(sd_device **ret, mode_t mode, dev_t devnum); @@ -17,8 +18,10 @@ int device_new_from_strv(sd_device **ret, char **strv); int device_opendir(sd_device *device, const char *subdir, DIR **ret); +int device_get_sysnum_unsigned(sd_device *device, unsigned *ret); int device_get_property_bool(sd_device *device, const char *key); int device_get_property_int(sd_device *device, const char *key, int *ret); +int device_get_ifname(sd_device *device, const char **ret); int device_get_sysattr_int(sd_device *device, const char *sysattr, int *ret_value); int device_get_sysattr_unsigned_full(sd_device *device, const char *sysattr, unsigned base, unsigned *ret_value); static inline int device_get_sysattr_unsigned(sd_device *device, const char *sysattr, unsigned *ret_value) { @@ -31,9 +34,11 @@ int device_get_devnode_mode(sd_device *device, mode_t *ret); int device_get_devnode_uid(sd_device *device, uid_t *ret); int device_get_devnode_gid(sd_device *device, gid_t *ret); +#if 0 /* NM_IGNORED */ +int device_chase(sd_device *device, const char *path, ChaseFlags flags, char **ret_resolved, int *ret_fd); void device_clear_sysattr_cache(sd_device *device); -int device_cache_sysattr_value(sd_device *device, const char *key, char *value); -int device_get_cached_sysattr_value(sd_device *device, const char *key, const char **ret_value); +int device_cache_sysattr_value(sd_device *device, char *key, char *value, int error); +#endif /* NM_IGNORED */ void device_seal(sd_device *device); void device_set_is_initialized(sd_device *device); @@ -76,4 +81,3 @@ int device_read_uevent_file(sd_device *device); int device_set_action(sd_device *device, sd_device_action_t a); sd_device_action_t device_action_from_string(const char *s) _pure_; const char* device_action_to_string(sd_device_action_t a) _const_; -void dump_device_action_table(void); diff --git a/src/libnm-systemd-core/src/libsystemd/sd-device/device-util.c b/src/libnm-systemd-core/src/libsystemd/sd-device/device-util.c new file mode 100644 index 00000000..e289523f --- /dev/null +++ b/src/libnm-systemd-core/src/libsystemd/sd-device/device-util.c @@ -0,0 +1,156 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "nm-sd-adapt-shared.h" + +#include "device-private.h" +#include "device-util.h" +#include "devnum-util.h" +#include "fd-util.h" +#include "string-util.h" +#include "strv.h" + +#if 0 /* NM_IGNORED */ +int devname_from_devnum(mode_t mode, dev_t devnum, char **ret) { + _cleanup_(sd_device_unrefp) sd_device *dev = NULL; + const char *devname; + int r; + + assert(ret); + + if (devnum_is_zero(devnum)) + return device_path_make_inaccessible(mode, ret); + + r = device_new_from_mode_and_devnum(&dev, mode, devnum); + if (r < 0) + return r; + + r = sd_device_get_devname(dev, &devname); + if (r < 0) + return r; + + return strdup_to(ret, devname); +} + +int device_open_from_devnum(mode_t mode, dev_t devnum, int flags, char **ret_devname) { + _cleanup_(sd_device_unrefp) sd_device *dev = NULL; + _cleanup_close_ int fd = -EBADF; + int r; + + r = device_new_from_mode_and_devnum(&dev, mode, devnum); + if (r < 0) + return r; + + fd = sd_device_open(dev, flags); + if (fd < 0) + return fd; + + if (ret_devname) { + const char *devname; + + r = sd_device_get_devname(dev, &devname); + if (r < 0) + return r; + + r = strdup_to(ret_devname, devname); + if (r < 0) + return r; + } + + return TAKE_FD(fd); +} + +static int add_string_field( + sd_device *device, + const char *field, + int (*func)(sd_device *dev, const char **s), + char ***strv) { + + const char *s; + int r; + + assert(device); + assert(field); + assert(func); + assert(strv); + + r = func(device, &s); + if (r < 0 && r != -ENOENT) + log_device_debug_errno(device, r, "Failed to get device \"%s\" property, ignoring: %m", field); + if (r >= 0) + (void) strv_extend_assignment(strv, field, s); + + return 0; +} + +char** device_make_log_fields(sd_device *device) { + _cleanup_strv_free_ char **strv = NULL; + dev_t devnum; + int ifindex; + sd_device_action_t action; + uint64_t seqnum, diskseq; + int r; + + assert(device); + + (void) add_string_field(device, "SYSPATH", sd_device_get_syspath, &strv); + (void) add_string_field(device, "SUBSYSTEM", sd_device_get_subsystem, &strv); + (void) add_string_field(device, "DEVTYPE", sd_device_get_devtype, &strv); + (void) add_string_field(device, "DRIVER", sd_device_get_driver, &strv); + (void) add_string_field(device, "DEVPATH", sd_device_get_devpath, &strv); + (void) add_string_field(device, "DEVNAME", sd_device_get_devname, &strv); + (void) add_string_field(device, "SYSNAME", sd_device_get_sysname, &strv); + (void) add_string_field(device, "SYSNUM", sd_device_get_sysnum, &strv); + + r = sd_device_get_devnum(device, &devnum); + if (r < 0 && r != -ENOENT) + log_device_debug_errno(device, r, "Failed to get device \"DEVNUM\" property, ignoring: %m"); + if (r >= 0) + (void) strv_extendf(&strv, "DEVNUM="DEVNUM_FORMAT_STR, DEVNUM_FORMAT_VAL(devnum)); + + r = sd_device_get_ifindex(device, &ifindex); + if (r < 0 && r != -ENOENT) + log_device_debug_errno(device, r, "Failed to get device \"IFINDEX\" property, ignoring: %m"); + if (r >= 0) + (void) strv_extendf(&strv, "IFINDEX=%i", ifindex); + + r = sd_device_get_action(device, &action); + if (r < 0 && r != -ENOENT) + log_device_debug_errno(device, r, "Failed to get device \"ACTION\" property, ignoring: %m"); + if (r >= 0) + (void) strv_extendf(&strv, "ACTION=%s", device_action_to_string(action)); + + r = sd_device_get_seqnum(device, &seqnum); + if (r < 0 && r != -ENOENT) + log_device_debug_errno(device, r, "Failed to get device \"SEQNUM\" property, ignoring: %m"); + if (r >= 0) + (void) strv_extendf(&strv, "SEQNUM=%"PRIu64, seqnum); + + r = sd_device_get_diskseq(device, &diskseq); + if (r < 0 && r != -ENOENT) + log_device_debug_errno(device, r, "Failed to get device \"DISKSEQ\" property, ignoring: %m"); + if (r >= 0) + (void) strv_extendf(&strv, "DISKSEQ=%"PRIu64, diskseq); + + return TAKE_PTR(strv); +} +#endif /* NM_IGNORED */ + +bool device_in_subsystem(sd_device *device, const char *subsystem) { + const char *s = NULL; + + assert(device); + + (void) sd_device_get_subsystem(device, &s); + return streq_ptr(s, subsystem); +} + +#if 0 /* NM_IGNORED */ +bool device_is_devtype(sd_device *device, const char *devtype) { + const char *s = NULL; + + assert(device); + + (void) sd_device_get_devtype(device, &s); + return streq_ptr(s, devtype); +} +#endif /* NM_IGNORED */ diff --git a/src/libnm-systemd-core/src/libsystemd/sd-device/device-util.h b/src/libnm-systemd-core/src/libsystemd/sd-device/device-util.h index b17993d5..070e564a 100644 --- a/src/libnm-systemd-core/src/libsystemd/sd-device/device-util.h +++ b/src/libnm-systemd-core/src/libsystemd/sd-device/device-util.h @@ -110,6 +110,19 @@ bool device_is_devtype(sd_device *device, const char *devtype); static inline bool device_property_can_set(const char *property) { return property && !STR_IN_SET(property, - "ACTION", "DEVLINKS", "DEVNAME", "DEVPATH", "DEVTYPE", "DRIVER", - "IFINDEX", "MAJOR", "MINOR", "SEQNUM", "SUBSYSTEM", "TAGS"); + /* basic properties set by kernel, only in netlink event */ + "ACTION", "SEQNUM", "SYNTH_UUID", + /* basic properties set by kernel, both in netlink event and uevent file */ + "DEVPATH", "DEVPATH_OLD", "SUBSYSTEM", "DEVTYPE", "DRIVER", "MODALIAS", + /* device node */ + "DEVNAME", "DEVMODE", "DEVUID", "DEVGID", "MAJOR", "MINOR", + /* block device */ + "DISKSEQ", "PARTN", + /* network interface (INTERFACE_OLD is set by udevd) */ + "IFINDEX", "INTERFACE", "INTERFACE_OLD", + /* basic properties set by udevd */ + "DEVLINKS", "TAGS", "CURRENT_TAGS", "USEC_INITIALIZED", "UDEV_DATABASE_VERSION") && + /* Similar to SYNTH_UUID, but set based on KEY=VALUE arguments passed by userspace. + * See kernel's f36776fafbaa0094390dd4e7e3e29805e0b82730 (v4.13) */ + !startswith(property, "SYNTH_ARG_"); } diff --git a/src/libnm-systemd-core/src/libsystemd/sd-device/sd-device.c b/src/libnm-systemd-core/src/libsystemd/sd-device/sd-device.c index 480223d0..fce184df 100644 --- a/src/libnm-systemd-core/src/libsystemd/sd-device/sd-device.c +++ b/src/libnm-systemd-core/src/libsystemd/sd-device/sd-device.c @@ -375,7 +375,7 @@ _public_ int sd_device_new_from_ifindex(sd_device **ret, int ifindex) { assert_return(ret, -EINVAL); assert_return(ifindex > 0, -EINVAL); - r = rtnl_get_ifname_full(NULL, ifindex, &ifname, NULL); + r = rtnl_get_ifname(NULL, ifindex, &ifname); if (r < 0) return r; @@ -516,7 +516,7 @@ _public_ int sd_device_new_from_subsystem_sysname( if (streq(sep, "drivers")) /* If the sysname is "drivers", then it's the drivers directory itself that is meant. */ r = device_new_from_path_join(&device, subsystem, subsys, "drivers", "/sys/bus/", subsys, "/drivers", NULL); else - r = device_new_from_path_join(&device, subsystem, subsys, sep, "/sys/bus/", subsys, "/drivers/", sep); + r = device_new_from_path_join(&device, subsystem, subsys, sysname + (sep - name), "/sys/bus/", subsys, "/drivers/", sep); if (r < 0) return r; } @@ -776,16 +776,24 @@ static int handle_uevent_line( assert(major); assert(minor); + if (streq(key, "SUBSYSTEM")) + return device_set_subsystem(device, value); if (streq(key, "DEVTYPE")) return device_set_devtype(device, value); if (streq(key, "IFINDEX")) return device_set_ifindex(device, value); if (streq(key, "DEVNAME")) return device_set_devname(device, value); + if (streq(key, "DEVUID")) + return device_set_devuid(device, value); + if (streq(key, "DEVGID")) + return device_set_devgid(device, value); if (streq(key, "DEVMODE")) return device_set_devmode(device, value); if (streq(key, "DISKSEQ")) return device_set_diskseq(device, value); + if (streq(key, "DRIVER")) + return device_set_driver(device, value); if (streq(key, "MAJOR")) *major = value; else if (streq(key, "MINOR")) @@ -800,7 +808,7 @@ int device_read_uevent_file(sd_device *device) { _cleanup_free_ char *uevent = NULL; const char *syspath, *key = NULL, *value = NULL, *major = NULL, *minor = NULL; char *path; - size_t uevent_len = 0; + size_t uevent_len; int r; enum { @@ -882,6 +890,13 @@ int device_read_uevent_file(sd_device *device) { log_device_debug_errno(device, r, "sd-device: Failed to set 'MAJOR=%s' or 'MINOR=%s' from '%s', ignoring: %m", major, strna(minor), path); } + if (device_in_subsystem(device, "drivers")) { + r = device_set_drivers_subsystem(device); + if (r < 0) + log_device_debug_errno(device, r, + "sd-device: Failed to set driver subsystem, ignoring: %m"); + } + return 0; } @@ -904,6 +919,21 @@ _public_ int sd_device_get_ifindex(sd_device *device, int *ifindex) { } #if 0 /* NM_IGNORED */ +int device_get_ifname(sd_device *device, const char **ret) { + int r; + + assert_return(device, -EINVAL); + + /* First, check if the device is a network interface. */ + r = sd_device_get_ifindex(device, NULL); + if (r < 0) + return r; + + /* The sysname and ifname may be different, as '!' in sysname are replaced with '/'. + * For network interfaces, we can use INTERFACE property. */ + return sd_device_get_property_value(device, "INTERFACE", ret); +} + _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) { int r; @@ -1228,6 +1258,10 @@ _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) { assert_return(device, -EINVAL); + r = device_read_uevent_file(device); + if (r < 0) + return r; + if (!device->subsystem_set) { _cleanup_free_ char *subsystem = NULL; const char *syspath; @@ -1371,6 +1405,10 @@ int device_set_driver(sd_device *device, const char *driver) { _public_ int sd_device_get_driver(sd_device *device, const char **ret) { assert_return(device, -EINVAL); + r = device_read_uevent_file(device); + if (r < 0) + return r; + if (!device->driver_set) { _cleanup_free_ char *driver = NULL; const char *syspath; @@ -1497,6 +1535,26 @@ _public_ int sd_device_get_sysnum(sd_device *device, const char **ret) { return 0; } +int device_get_sysnum_unsigned(sd_device *device, unsigned *ret) { + int r; + + assert(device); + + const char *s; + r = sd_device_get_sysnum(device, &s); + if (r < 0) + return r; + + unsigned n; + r = safe_atou_full(s, SAFE_ATO_REFUSE_PLUS_MINUS | SAFE_ATO_REFUSE_LEADING_WHITESPACE | 10, &n); + if (r < 0) + return r; + + if (ret) + *ret = n; + return 0; +} + _public_ int sd_device_get_action(sd_device *device, sd_device_action_t *ret) { assert_return(device, -EINVAL); @@ -1726,18 +1784,13 @@ _public_ int sd_device_get_device_id(sd_device *device, const char **ret) { if (!device->device_id) { _cleanup_free_ char *id = NULL; - const char *subsystem; dev_t devnum; int ifindex, r; - r = sd_device_get_subsystem(device, &subsystem); - if (r < 0) - return r; - if (sd_device_get_devnum(device, &devnum) >= 0) { /* use dev_t — b259:131072, c254:0 */ if (asprintf(&id, "%c" DEVNUM_FORMAT_STR, - streq(subsystem, "block") ? 'b' : 'c', + device_in_subsystem(device, "block") ? 'b' : 'c', DEVNUM_FORMAT_VAL(devnum)) < 0) return -ENOMEM; } else if (sd_device_get_ifindex(device, &ifindex) >= 0) { @@ -1755,13 +1808,18 @@ _public_ int sd_device_get_device_id(sd_device *device, const char **ret) { if (r == O_DIRECTORY) return -EINVAL; - if (streq(subsystem, "drivers")) { + if (device_in_subsystem(device, "drivers")) /* the 'drivers' pseudo-subsystem is special, and needs the real * subsystem encoded as well */ - assert(device->driver_subsystem); - id = strjoin("+drivers:", device->driver_subsystem, ":", sysname); - } else + id = strjoin("+drivers:", ASSERT_PTR(device->driver_subsystem), ":", sysname); + else { + const char *subsystem; + r = sd_device_get_subsystem(device, &subsystem); + if (r < 0) + return r; + id = strjoin("+", subsystem, ":", sysname); + } if (!id) return -ENOMEM; } @@ -2355,134 +2413,224 @@ void device_clear_sysattr_cache(sd_device *device) { device->sysattr_values = hashmap_free(device->sysattr_values); } -int device_cache_sysattr_value(sd_device *device, const char *key, char *value) { - _unused_ _cleanup_free_ char *old_value = NULL; - _cleanup_free_ char *new_key = NULL; +typedef struct SysAttrCacheEntry { + char *key; + char *value; + int error; +} SysAttrCacheEntry; + +static SysAttrCacheEntry* sysattr_cache_entry_free(SysAttrCacheEntry *p) { + if (!p) + return NULL; + + free(p->key); + free(p->value); + return mfree(p); +} + +DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR( + sysattr_cache_hash_ops, + char, path_hash_func, path_compare, + SysAttrCacheEntry, sysattr_cache_entry_free); + +static int device_cache_sysattr_value_full(sd_device *device, char *key, char *value, int error, bool ignore_uevent) { int r; assert(device); assert(key); + assert(value || error > 0); - /* This takes the reference of the input value. The input value may be NULL. - * This replaces the value if it already exists. */ + /* This takes the reference of the input arguments when cached, hence the caller must not free them + * when a positive return value is returned. The input value may be NULL. This replaces an already + * existing entry. */ - /* First, remove the old cache entry. So, we do not need to clear cache on error. */ - old_value = hashmap_remove2(device->sysattr_values, key, (void **) &new_key); - if (!new_key) { - new_key = strdup(key); - if (!new_key) - return -ENOMEM; - } + if (ignore_uevent && streq(last_path_component(key), "uevent")) + return 0; /* not cached */ - r = hashmap_ensure_put(&device->sysattr_values, &path_hash_ops_free_free, new_key, value); + /* Remove the old cache entry. So, we do not need to clear cache on error. */ + sysattr_cache_entry_free(hashmap_remove(device->sysattr_values, key)); + + /* We use ENOANO as a recognizable error code when we have not read the attribute. */ + if (error == ENOANO) + error = ESTALE; + + _cleanup_free_ SysAttrCacheEntry *entry = new(SysAttrCacheEntry, 1); + if (!entry) + return -ENOMEM; + + *entry = (SysAttrCacheEntry) { + .key = key, + .value = value, + .error = error, + }; + + r = hashmap_ensure_put(&device->sysattr_values, &sysattr_cache_hash_ops, entry->key, entry); if (r < 0) return r; - TAKE_PTR(new_key); + TAKE_PTR(entry); + return 1; /* cached */ +} - return 0; +int device_cache_sysattr_value(sd_device *device, char *key, char *value, int error) { + return device_cache_sysattr_value_full(device, key, value, error, /* ignore_uevent = */ true); } -int device_get_cached_sysattr_value(sd_device *device, const char *key, const char **ret_value) { - const char *k = NULL, *value; +static int device_get_cached_sysattr_value(sd_device *device, const char *key, const char **ret_value) { + SysAttrCacheEntry *entry; assert(device); assert(key); - value = hashmap_get2(device->sysattr_values, key, (void **) &k); - if (!k) - return -ESTALE; /* We have not read the attribute. */ - if (!value) - return -ENOENT; /* We have looked up the attribute before and it did not exist. */ + entry = hashmap_get(device->sysattr_values, key); + if (!entry) + return -ENOANO; /* We have not read the attribute. */ + if (!entry->value) { + /* We have looked up the attribute before and failed. Return the cached error code. */ + assert(entry->error > 0); + return -entry->error; + } if (ret_value) - *ret_value = value; + *ret_value = entry->value; return 0; } -/* We cache all sysattr lookups. If an attribute does not exist, it is stored - * with a NULL value in the cache, otherwise the returned string is stored */ -_public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **ret_value) { - _cleanup_free_ char *value = NULL, *path = NULL; - const char *syspath; - struct stat statbuf; +int device_chase(sd_device *device, const char *path, ChaseFlags flags, char **ret_resolved, int *ret_fd) { int r; - assert_return(device, -EINVAL); - assert_return(sysattr, -EINVAL); + assert(device); + assert(path); - /* look for possibly already cached result */ - r = device_get_cached_sysattr_value(device, sysattr, ret_value); - if (r != -ESTALE) + const char *syspath; + r = sd_device_get_syspath(device, &syspath); + if (r < 0) return r; - r = sd_device_get_syspath(device, &syspath); + /* Here, CHASE_PREFIX_ROOT is borrowed. If the flag is set or the specified path is relative, then + * the path will be prefixed with the syspath. Note, we do not pass CHASE_PREFIX_ROOT flag with + * syspath as root to chase(), but we manually concatenate the specified path with syspath before + * calling chase(). Otherwise, we cannot set/get attributes of parent or sibling devices. */ + _cleanup_free_ char *prefixed = NULL; + if (FLAGS_SET(flags, CHASE_PREFIX_ROOT) || !path_is_absolute(path)) { + prefixed = path_join(syspath, path); + if (!prefixed) + return -ENOMEM; + path = prefixed; + flags &= ~CHASE_PREFIX_ROOT; + } + + _cleanup_free_ char *resolved = NULL; + _cleanup_close_ int fd = -EBADF; + r = chase(path, /* root = */ NULL, CHASE_NO_AUTOFS | flags, &resolved, ret_fd ? &fd : NULL); if (r < 0) return r; - path = path_join(syspath, sysattr); - if (!path) - return -ENOMEM; + /* Refuse to reading/writing files outside of sysfs. */ + if (!path_startswith(resolved, "/sys/")) + return -EINVAL; - if (lstat(path, &statbuf) < 0) { - int k; + if (ret_resolved) { + /* Always return relative path. */ + r = path_make_relative(syspath, resolved, ret_resolved); + if (r < 0) + return r; + } - r = -errno; + if (ret_fd) + *ret_fd = TAKE_FD(fd); - /* remember that we could not access the sysattr */ - k = device_cache_sysattr_value(device, sysattr, NULL); - if (k < 0) - log_device_debug_errno(device, k, - "sd-device: failed to cache attribute '%s' with NULL, ignoring: %m", - sysattr); + return 0; +} + +_public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **ret_value) { + _cleanup_free_ char *resolved = NULL, *value = NULL; + _cleanup_close_ int fd = -EBADF; + int r; + assert_return(device, -EINVAL); + assert_return(sysattr, -EINVAL); + + /* Look for possibly already cached result. */ + r = device_get_cached_sysattr_value(device, sysattr, ret_value); + if (r != -ENOANO) return r; - } else if (S_ISLNK(statbuf.st_mode)) { - /* Some core links return only the last element of the target path, - * these are just values, the paths should not be exposed. */ - if (STR_IN_SET(sysattr, "driver", "subsystem", "module")) { - r = readlink_value(path, &value); - if (r < 0) - return r; - } else - return -EINVAL; - } else if (S_ISDIR(statbuf.st_mode)) - /* skip directories */ - return -EISDIR; - else if (!(statbuf.st_mode & S_IRUSR)) - /* skip non-readable files */ - return -EPERM; - else { - size_t size; - - /* Read attribute value, Some attributes contain embedded '\0'. So, it is necessary to - * also get the size of the result. See issue #20025. */ - r = read_full_virtual_file(path, &value, &size); + + /* Special cases: read the symlink and return the last component of the value. Some core links return + * only the last element of the target path, these are just values, the paths should not be exposed. */ + if (STR_IN_SET(sysattr, "driver", "subsystem", "module")) { + _cleanup_free_ char *prefixed = NULL; + const char *syspath; + + r = sd_device_get_syspath(device, &syspath); if (r < 0) return r; - /* drop trailing newlines */ - while (size > 0 && strchr(NEWLINE, value[--size])) - value[size] = '\0'; + prefixed = path_join(syspath, sysattr); + if (!prefixed) + return -ENOMEM; + + r = readlink_value(prefixed, &value); + if (r != -EINVAL) /* -EINVAL means the path is not a symlink. */ + goto cache_result; } - /* Unfortunately, we need to return 'const char*' instead of 'char*'. Hence, failure in caching - * sysattr value is critical unlike the other places. */ - r = device_cache_sysattr_value(device, sysattr, value); - if (r < 0) { - log_device_debug_errno(device, r, - "sd-device: failed to cache attribute '%s' with '%s'%s: %m", - sysattr, value, ret_value ? "" : ", ignoring"); - if (ret_value) - return r; + r = device_chase(device, sysattr, CHASE_PREFIX_ROOT, &resolved, &fd); + if (r < 0) + goto cache_result; - return 0; + /* Look for cached result again with the resolved path. */ + r = device_get_cached_sysattr_value(device, resolved, ret_value); + if (r != -ENOANO) + return r; + + /* Read attribute value, Some attributes contain embedded '\0'. So, it is necessary to also get the + * size of the result. See issue #20025. */ + size_t size; + r = read_virtual_file_fd(fd, SIZE_MAX, &value, &size); + if (r < 0) + goto cache_result; + + delete_trailing_chars(value, NEWLINE); + r = 0; + +cache_result: + if (r == -ENOMEM) + return r; /* Do not cache -ENOMEM, as the failure may be transient. */ + + if (!resolved) { + /* If we have not or could not chase the path, assume 'sysattr' is normalized. */ + resolved = strdup(sysattr); + if (!resolved) + return RET_GATHER(r, -ENOMEM); } - if (ret_value) + int k = device_cache_sysattr_value_full(device, resolved, value, -r, /* ignore_uevent = */ false); + if (k < 0) { + if (r < 0) + log_device_debug_errno(device, k, + "sd-device: failed to cache error code (%i) in reading attribute '%s', ignoring: %m", + -r, resolved); + else { + /* Unfortunately, we need to return 'const char*' instead of 'char*'. Hence, failure in caching + * sysattr value is critical unlike the other places. */ + log_device_debug_errno(device, k, + "sd-device: failed to cache attribute '%s' with '%s'%s: %m", + resolved, value, ret_value ? "" : ", ignoring"); + if (ret_value) + return k; + } + + return r; + } + assert(k > 0); + + if (ret_value && r >= 0) *ret_value = value; + /* device_cache_sysattr_value_full() takes 'resolved' and 'value' on success. */ + TAKE_PTR(resolved); TAKE_PTR(value); - return 0; + return r; } int device_get_sysattr_int(sd_device *device, const char *sysattr, int *ret_value) { @@ -2556,19 +2704,22 @@ int device_get_sysattr_bool(sd_device *device, const char *sysattr) { return parse_boolean(value); } -static void device_remove_cached_sysattr_value(sd_device *device, const char *_key) { - _cleanup_free_ char *key = NULL; +static int device_remove_cached_sysattr_value(sd_device *device, const char *sysattr) { + int r; assert(device); - assert(_key); + assert(sysattr); - free(hashmap_remove2(device->sysattr_values, _key, (void **) &key)); + _cleanup_free_ char *resolved = NULL; + r = device_chase(device, sysattr, CHASE_PREFIX_ROOT | CHASE_NONEXISTENT, &resolved, /* ret_fd = */ NULL); + if (r < 0) + return r; + + sysattr_cache_entry_free(hashmap_remove(device->sysattr_values, resolved)); + return 0; } -_public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, const char *_value) { - _cleanup_free_ char *value = NULL, *path = NULL; - const char *syspath; - size_t len; +_public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, const char *value) { int r; assert_return(device, -EINVAL); @@ -2576,52 +2727,43 @@ _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, /* Set the attribute and save it in the cache. */ - if (!_value) { + if (!value) /* If input value is NULL, then clear cache and not write anything. */ - device_remove_cached_sysattr_value(device, sysattr); - return 0; - } + return device_remove_cached_sysattr_value(device, sysattr); - r = sd_device_get_syspath(device, &syspath); - if (r < 0) + _cleanup_free_ char *resolved = NULL; + _cleanup_close_ int fd = -EBADF; + r = device_chase(device, sysattr, CHASE_PREFIX_ROOT, &resolved, &fd); + if (r < 0) { + /* On failure, clear cache entry, hopefully, 'sysattr' is normalized. */ + sysattr_cache_entry_free(hashmap_remove(device->sysattr_values, sysattr)); return r; + } - path = path_join(syspath, sysattr); - if (!path) + /* value length is limited to 4k */ + _cleanup_free_ char *copied = strndup(value, 4096); + if (!copied) return -ENOMEM; - len = strlen(_value); - /* drop trailing newlines */ - while (len > 0 && strchr(NEWLINE, _value[len - 1])) - len--; + delete_trailing_chars(copied, NEWLINE); - /* value length is limited to 4k */ - if (len > 4096) - return -EINVAL; - - value = strndup(_value, len); - if (!value) - return -ENOMEM; - - r = write_string_file(path, value, WRITE_STRING_FILE_DISABLE_BUFFER | WRITE_STRING_FILE_NOFOLLOW); + r = write_string_file_fd(fd, copied, WRITE_STRING_FILE_DISABLE_BUFFER | WRITE_STRING_FILE_AVOID_NEWLINE); if (r < 0) { /* On failure, clear cache entry, as we do not know how it fails. */ - device_remove_cached_sysattr_value(device, sysattr); + sysattr_cache_entry_free(hashmap_remove(device->sysattr_values, resolved)); return r; } - /* Do not cache action string written into uevent file. */ - if (streq(sysattr, "uevent")) - return 0; - - r = device_cache_sysattr_value(device, sysattr, value); + r = device_cache_sysattr_value(device, resolved, copied, 0); if (r < 0) log_device_debug_errno(device, r, - "sd-device: failed to cache attribute '%s' with '%s', ignoring: %m", - sysattr, value); - else - TAKE_PTR(value); + "sd-device: failed to cache written attribute '%s' with '%s', ignoring: %m", + resolved, copied); + else if (r > 0) { + TAKE_PTR(resolved); + TAKE_PTR(copied); + } return 0; } @@ -2634,10 +2776,8 @@ _public_ int sd_device_set_sysattr_valuef(sd_device *device, const char *sysattr assert_return(device, -EINVAL); assert_return(sysattr, -EINVAL); - if (!format) { - device_remove_cached_sysattr_value(device, sysattr); - return 0; - } + if (!format) + return device_remove_cached_sysattr_value(device, sysattr); va_start(ap, format); r = vasprintf(&value, format, ap); @@ -2650,16 +2790,7 @@ _public_ int sd_device_set_sysattr_valuef(sd_device *device, const char *sysattr } _public_ int sd_device_trigger(sd_device *device, sd_device_action_t action) { - const char *s; - - assert_return(device, -EINVAL); - - s = device_action_to_string(action); - if (!s) - return -EINVAL; - - /* This uses the simple no-UUID interface of kernel < 4.13 */ - return sd_device_set_sysattr_value(device, "uevent", s); + return sd_device_trigger_with_uuid(device, action, NULL); } _public_ int sd_device_trigger_with_uuid( @@ -2673,10 +2804,6 @@ _public_ int sd_device_trigger_with_uuid( assert_return(device, -EINVAL); - /* If no one wants to know the UUID, use the simple interface from pre-4.13 times */ - if (!ret_uuid) - return sd_device_trigger(device, action); - s = device_action_to_string(action); if (!s) return -EINVAL; @@ -2691,7 +2818,8 @@ _public_ int sd_device_trigger_with_uuid( if (r < 0) return r; - *ret_uuid = u; + if (ret_uuid) + *ret_uuid = u; return 0; } diff --git a/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c b/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c index ac986e48..f8c374b9 100644 --- a/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c +++ b/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c @@ -4,12 +4,21 @@ #include <errno.h> +#include "errno-util.h" #include "event-source.h" #include "event-util.h" #include "fd-util.h" #include "log.h" #include "string-util.h" +#define SI_FLAG_FORWARD (INT32_C(1) << 30) +#define SI_FLAG_POSITIVE (INT32_C(1) << 29) + +DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR( + event_source_hash_ops, + void, trivial_hash_func, trivial_compare_func, + sd_event_source, sd_event_source_disable_unref); + int event_reset_time( sd_event *e, sd_event_source **s, @@ -157,19 +166,73 @@ int event_add_time_change(sd_event *e, sd_event_source **ret, sd_event_io_handle int event_add_child_pidref( sd_event *e, - sd_event_source **s, + sd_event_source **ret, const PidRef *pid, int options, sd_event_child_handler_t callback, void *userdata) { + int r; + + assert(e); + if (!pidref_is_set(pid)) return -ESRCH; - if (pid->fd >= 0) - return sd_event_add_child_pidfd(e, s, pid->fd, options, callback, userdata); + if (pidref_is_remote(pid)) + return -EREMOTE; + + if (pid->fd < 0) + return sd_event_add_child(e, ret, pid->pid, options, callback, userdata); + + _cleanup_close_ int copy_fd = fcntl(pid->fd, F_DUPFD_CLOEXEC, 3); + if (copy_fd < 0) + return -errno; - return sd_event_add_child(e, s, pid->pid, options, callback, userdata); + _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL; + r = sd_event_add_child_pidfd(e, &s, copy_fd, options, callback, userdata); + if (r < 0) + return r; + + r = sd_event_source_set_child_pidfd_own(s, true); + if (r < 0) + return r; + + TAKE_FD(copy_fd); + + if (ret) + *ret = TAKE_PTR(s); + else { + r = sd_event_source_set_floating(s, true); + if (r < 0) + return r; + } + + return 0; +} + +int event_source_get_child_pidref(sd_event_source *s, PidRef *ret) { + int r; + + assert(s); + assert(ret); + + pid_t pid; + r = sd_event_source_get_child_pid(s, &pid); + if (r < 0) + return r; + + int pidfd = sd_event_source_get_child_pidfd(s); + if (pidfd < 0) + return pidfd; + + /* Note, we don't actually duplicate the fd here, i.e. we do not pass ownership of this PidRef to the caller */ + *ret = (PidRef) { + .pid = pid, + .fd = pidfd, + }; + + return 0; } dual_timestamp* event_dual_timestamp_now(sd_event *e, dual_timestamp *ts) { @@ -180,4 +243,91 @@ dual_timestamp* event_dual_timestamp_now(sd_event *e, dual_timestamp *ts) { assert_se(sd_event_now(e, CLOCK_MONOTONIC, &ts->monotonic) >= 0); return ts; } + +void event_source_unref_many(sd_event_source **array, size_t n) { + FOREACH_ARRAY(v, array, n) + sd_event_source_unref(*v); + + free(array); +} + +static int event_forward_signal_callback(sd_event_source *s, const struct signalfd_siginfo *ssi, void *userdata) { + sd_event_source *child = ASSERT_PTR(userdata); + + assert(ssi); + + siginfo_t si = { + .si_signo = ssi->ssi_signo, + /* We include some extra information to indicate the signal was forwarded and originally a positive + * value since we can only set negative values ourselves as positive values are prohibited by the + * kernel. */ + .si_code = (ssi->ssi_code & (SI_FLAG_FORWARD|SI_FLAG_POSITIVE)) ? INT_MIN : + (ssi->ssi_code >= 0 ? (-ssi->ssi_code - 1) | SI_FLAG_POSITIVE | SI_FLAG_FORWARD : ssi->ssi_code | SI_FLAG_FORWARD), + .si_errno = ssi->ssi_errno, + }; + + /* The following fields are implemented as macros, hence we cannot use compound initialization for them. */ + si.si_pid = ssi->ssi_pid; + si.si_uid = ssi->ssi_uid; + si.si_int = ssi->ssi_int; + si.si_ptr = UINT64_TO_PTR(ssi->ssi_ptr); + + return sd_event_source_send_child_signal(child, ssi->ssi_signo, &si, /* flags = */ 0); +} + +static void event_forward_signal_destroy(void *userdata) { + sd_event_source *child = ASSERT_PTR(userdata); + sd_event_source_unref(child); +} + +int event_forward_signals( + sd_event *e, + sd_event_source *child, + const int *signals, + size_t n_signals, + sd_event_source ***ret_sources, + size_t *ret_n_sources) { + + sd_event_source **sources = NULL; + size_t n_sources = 0; + int r; + + CLEANUP_ARRAY(sources, n_sources, event_source_unref_many); + + assert(e); + assert(child); + assert(child->type == SOURCE_CHILD); + assert(signals || n_signals == 0); + assert(ret_sources); + assert(ret_n_sources); + + if (n_signals == 0) { + *ret_sources = NULL; + *ret_n_sources = 0; + return 0; + } + + sources = new0(sd_event_source*, n_signals); + if (!sources) + return -ENOMEM; + + FOREACH_ARRAY(sig, signals, n_signals) { + _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL; + r = sd_event_add_signal(e, &s, *sig | SD_EVENT_SIGNAL_PROCMASK, event_forward_signal_callback, child); + if (r < 0) + return r; + + r = sd_event_source_set_destroy_callback(s, event_forward_signal_destroy); + if (r < 0) + return r; + + sd_event_source_ref(child); + sources[n_sources++] = TAKE_PTR(s); + } + + *ret_sources = TAKE_PTR(sources); + *ret_n_sources = n_sources; + + return 0; +} #endif /* NM_IGNORED */ diff --git a/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.h b/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.h index c0db014f..692184db 100644 --- a/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.h +++ b/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.h @@ -5,8 +5,11 @@ #include "sd-event.h" +#include "hash-funcs.h" #include "pidref.h" +extern const struct hash_ops event_source_hash_ops; + int event_reset_time( sd_event *e, sd_event_source **s, @@ -38,5 +41,11 @@ int event_add_time_change(sd_event *e, sd_event_source **ret, sd_event_io_handle #if 0 /* NM_IGNORED */ int event_add_child_pidref(sd_event *e, sd_event_source **s, const PidRef *pid, int options, sd_event_child_handler_t callback, void *userdata); +int event_source_get_child_pidref(sd_event_source *s, PidRef *ret); + dual_timestamp* event_dual_timestamp_now(sd_event *e, dual_timestamp *ts); + +void event_source_unref_many(sd_event_source **array, size_t n); + +int event_forward_signals(sd_event *e, sd_event_source *child, const int *signals, size_t n_signals, sd_event_source ***ret_sources, size_t *ret_n_sources); #endif /* NM_IGNORED */ diff --git a/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c b/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c index b345b145..4f04e058 100644 --- a/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c +++ b/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c @@ -5,6 +5,7 @@ #include <sys/epoll.h> #include <sys/timerfd.h> #include <sys/wait.h> +#include <threads.h> #include "sd-daemon.h" #include "sd-event.h" @@ -26,12 +27,11 @@ #include "memory-util.h" #include "missing_magic.h" #include "missing_syscall.h" -#include "missing_threads.h" #include "missing_wait.h" #include "origin-id.h" #include "path-util.h" -#include "prioq.h" #include "pidfd-util.h" +#include "prioq.h" #include "process-util.h" #include "psi-util.h" #include "set.h" @@ -45,11 +45,10 @@ #define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC) -static bool EVENT_SOURCE_WATCH_PIDFD(sd_event_source *s) { +static bool EVENT_SOURCE_WATCH_PIDFD(const sd_event_source *s) { /* Returns true if this is a PID event source and can be implemented by watching EPOLLIN */ return s && s->type == SOURCE_CHILD && - s->child.pidfd >= 0 && s->child.options == WEXITED; } @@ -434,7 +433,7 @@ _public_ int sd_event_new(sd_event** ret) { if (secure_getenv("SD_EVENT_PROFILE_DELAYS")) { log_debug("Event loop profiling enabled. Logarithmic histogram of event loop iterations in the range 2^0 %s 2^63 us will be logged every 5s.", - special_glyph(SPECIAL_GLYPH_ELLIPSIS)); + glyph(GLYPH_ELLIPSIS)); e->profile_delays = true; } @@ -992,7 +991,7 @@ static void source_disconnect(sd_event_source *s) { s->event->n_online_child_sources--; } - (void) hashmap_remove(s->event->child_sources, PID_TO_PTR(s->child.pid)); + assert_se(hashmap_remove(s->event->child_sources, PID_TO_PTR(s->child.pid))); } if (EVENT_SOURCE_WATCH_PIDFD(s)) @@ -1092,12 +1091,11 @@ static sd_event_source* source_free(sd_event_source *s) { /* Eventually the kernel will do this automatically for us, but for now let's emulate this (unreliably) in userspace. */ if (s->child.process_owned) { + assert(s->child.pid > 0); + assert(s->child.pidfd >= 0); if (!s->child.exited) { - if (s->child.pidfd >= 0) - r = RET_NERRNO(pidfd_send_signal(s->child.pidfd, SIGKILL, NULL, 0)); - else - r = RET_NERRNO(kill(s->child.pid, SIGKILL)); + r = RET_NERRNO(pidfd_send_signal(s->child.pidfd, SIGKILL, NULL, 0)); if (r < 0 && r != -ESRCH) log_debug_errno(r, "Failed to kill process " PID_FMT ", ignoring: %m", s->child.pid); @@ -1107,10 +1105,7 @@ static sd_event_source* source_free(sd_event_source *s) { siginfo_t si = {}; /* Reap the child if we can */ - if (s->child.pidfd >= 0) - (void) waitid(P_PIDFD, s->child.pidfd, &si, WEXITED); - else - (void) waitid(P_PID, s->child.pid, &si, WEXITED); + (void) waitid(P_PIDFD, s->child.pidfd, &si, WEXITED); } } @@ -1903,15 +1898,15 @@ _public_ int sd_event_trim_memory(void) { LOG_MESSAGE("Memory trimming took %s, returned %s to OS.", FORMAT_TIMESPAN(period, 0), FORMAT_BYTES(l)), - "MESSAGE_ID=" SD_MESSAGE_MEMORY_TRIM_STR, - "TRIMMED_BYTES=%zu", l, - "TRIMMED_USEC=" USEC_FMT, period); + LOG_MESSAGE_ID(SD_MESSAGE_MEMORY_TRIM_STR), + LOG_ITEM("TRIMMED_BYTES=%zu", l), + LOG_ITEM("TRIMMED_USEC=" USEC_FMT, period)); #else log_struct(LOG_DEBUG, LOG_MESSAGE("Memory trimming took %s.", FORMAT_TIMESPAN(period, 0)), - "MESSAGE_ID=" SD_MESSAGE_MEMORY_TRIM_STR, - "TRIMMED_USEC=" USEC_FMT, period); + LOG_MESSAGE_ID(SD_MESSAGE_MEMORY_TRIM_STR), + LOG_ITEM("TRIMMED_USEC=" USEC_FMT, period)); #endif return 0; @@ -2740,9 +2735,11 @@ _public_ int sd_event_source_get_io_revents(sd_event_source *s, uint32_t *ret) { assert_return(s, -EINVAL); assert_return(ret, -EINVAL); assert_return(s->type == SOURCE_IO, -EDOM); - assert_return(s->pending, -ENODATA); assert_return(!event_origin_changed(s->event), -ECHILD); + if (!s->pending) + return -ENODATA; + *ret = s->io.revents; return 0; } @@ -3009,13 +3006,13 @@ static int event_source_online( case SOURCE_CHILD: if (EVENT_SOURCE_WATCH_PIDFD(s)) { - /* yes, we have pidfd */ + /* yes, we can rely on pidfd */ r = source_child_pidfd_register(s, enabled); if (r < 0) return r; } else { - /* no pidfd, or something other to watch for than WEXITED */ + /* something other to watch for than WEXITED */ r = event_make_signal_data(s->event, SIGCHLD, NULL); if (r < 0) { @@ -3208,9 +3205,6 @@ _public_ int sd_event_source_get_child_pidfd(sd_event_source *s) { assert_return(s->type == SOURCE_CHILD, -EDOM); assert_return(!event_origin_changed(s->event), -ECHILD); - if (s->child.pidfd < 0) - return -EOPNOTSUPP; - return s->child.pidfd; } @@ -3219,51 +3213,26 @@ _public_ int sd_event_source_send_child_signal(sd_event_source *s, int sig, cons assert_return(s->type == SOURCE_CHILD, -EDOM); assert_return(!event_origin_changed(s->event), -ECHILD); assert_return(SIGNAL_VALID(sig), -EINVAL); + assert(s->child.pidfd >= 0); - /* If we already have seen indication the process exited refuse sending a signal early. This way we - * can be sure we don't accidentally kill the wrong process on PID reuse when pidfds are not - * available. */ + /* If we already have seen indication the process exited refuse sending a signal early. */ if (s->child.exited) return -ESRCH; + assert(!s->child.waited); - if (s->child.pidfd >= 0) { - siginfo_t copy; - - /* pidfd_send_signal() changes the siginfo_t argument. This is weird, let's hence copy the - * structure here */ - if (si) - copy = *si; - - if (pidfd_send_signal(s->child.pidfd, sig, si ? © : NULL, 0) < 0) - return -errno; - - return 0; - } - - /* Flags are only supported for pidfd_send_signal(), not for rt_sigqueueinfo(), hence let's refuse - * this here. */ - if (flags != 0) - return -EOPNOTSUPP; + /* pidfd_send_signal() changes the siginfo_t argument. This is weird, let's hence copy the structure here. */ + siginfo_t copy; + if (si) + copy = *si; - if (si) { - /* We use rt_sigqueueinfo() only if siginfo_t is specified. */ - siginfo_t copy = *si; - - if (rt_sigqueueinfo(s->child.pid, sig, ©) < 0) - return -errno; - } else if (kill(s->child.pid, sig) < 0) - return -errno; - - return 0; + return RET_NERRNO(pidfd_send_signal(s->child.pidfd, sig, si ? © : NULL, flags)); } _public_ int sd_event_source_get_child_pidfd_own(sd_event_source *s) { assert_return(s, -EINVAL); assert_return(s->type == SOURCE_CHILD, -EDOM); assert_return(!event_origin_changed(s->event), -ECHILD); - - if (s->child.pidfd < 0) - return -EOPNOTSUPP; + assert(s->child.pidfd >= 0); return s->child.pidfd_owned; } @@ -3272,9 +3241,7 @@ _public_ int sd_event_source_set_child_pidfd_own(sd_event_source *s, int own) { assert_return(s, -EINVAL); assert_return(s->type == SOURCE_CHILD, -EDOM); assert_return(!event_origin_changed(s->event), -ECHILD); - - if (s->child.pidfd < 0) - return -EOPNOTSUPP; + assert(s->child.pidfd >= 0); s->child.pidfd_owned = own; return 0; @@ -3733,9 +3700,9 @@ static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priori e->need_process_child = false; - /* So, this is ugly. We iteratively invoke waitid() with P_PID + WNOHANG for each PID we wait - * for, instead of using P_ALL. This is because we only want to get child information of very - * specific child processes, and not all of them. We might not have processed the SIGCHLD event + /* So, this is ugly. We iteratively invoke waitid() + WNOHANG with each child process we shall wait for, + * instead of using P_ALL. This is because we only want to get child information of very specific + * child processes, and not all of them. We might not have processed the SIGCHLD event * of a previous invocation and we don't want to maintain a unbounded *per-child* event queue, * hence we really don't want anything flushed out of the kernel's queue that we don't care * about. Since this is O(n) this means that if you have a lot of processes you probably want @@ -3746,6 +3713,7 @@ static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priori HASHMAP_FOREACH(s, e->child_sources) { assert(s->type == SOURCE_CHILD); + assert(s->child.pidfd >= 0); if (s->priority > threshold) continue; @@ -3765,23 +3733,21 @@ static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priori continue; zero(s->child.siginfo); - if (waitid(P_PID, s->child.pid, &s->child.siginfo, + if (waitid(P_PIDFD, s->child.pidfd, &s->child.siginfo, WNOHANG | (s->child.options & WEXITED ? WNOWAIT : 0) | s->child.options) < 0) return negative_errno(); if (s->child.siginfo.si_pid != 0) { - bool zombie = IN_SET(s->child.siginfo.si_code, CLD_EXITED, CLD_KILLED, CLD_DUMPED); + bool zombie = SIGINFO_CODE_IS_DEAD(s->child.siginfo.si_code); if (zombie) s->child.exited = true; - - if (!zombie && (s->child.options & WEXITED)) { - /* If the child isn't dead then let's immediately remove the state - * change from the queue, since there's no benefit in leaving it - * queued. */ + else if (s->child.options & WEXITED) { + /* If the child isn't dead then let's immediately remove the state change + * from the queue, since there's no benefit in leaving it queued. */ assert(s->child.options & (WSTOPPED|WCONTINUED)); - (void) waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|(s->child.options & (WSTOPPED|WCONTINUED))); + (void) waitid(P_PIDFD, s->child.pidfd, &s->child.siginfo, WNOHANG|(s->child.options & (WSTOPPED|WCONTINUED))); } r = source_set_pending(s, true); @@ -3802,6 +3768,7 @@ static int process_pidfd(sd_event *e, sd_event_source *s, uint32_t revents) { assert(e); assert(s); assert(s->type == SOURCE_CHILD); + assert(s->child.pidfd >= 0); if (s->pending) return 0; @@ -3812,14 +3779,19 @@ static int process_pidfd(sd_event *e, sd_event_source *s, uint32_t revents) { if (!EVENT_SOURCE_WATCH_PIDFD(s)) return 0; + /* Note that pidfd would also generate EPOLLHUP when the process gets reaped. But at this point we + * only permit EPOLLIN, under the assumption that upon EPOLLHUP the child source should already + * be set to pending, and we would have returned early above. */ + assert(!s->child.exited); + zero(s->child.siginfo); - if (waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG | WNOWAIT | s->child.options) < 0) + if (waitid(P_PIDFD, s->child.pidfd, &s->child.siginfo, WNOHANG | WNOWAIT | s->child.options) < 0) return -errno; if (s->child.siginfo.si_pid == 0) return 0; - if (IN_SET(s->child.siginfo.si_code, CLD_EXITED, CLD_KILLED, CLD_DUMPED)) + if (SIGINFO_CODE_IS_DEAD(s->child.siginfo.si_code)) s->child.exited = true; return source_set_pending(s, true); @@ -4232,15 +4204,13 @@ static int source_dispatch(sd_event_source *s) { break; case SOURCE_CHILD: { - bool zombie; - - zombie = IN_SET(s->child.siginfo.si_code, CLD_EXITED, CLD_KILLED, CLD_DUMPED); + bool zombie = SIGINFO_CODE_IS_DEAD(s->child.siginfo.si_code); r = s->child.callback(s, &s->child.siginfo, s->userdata); /* Now, reap the PID for good. */ if (zombie) { - (void) waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|WEXITED); + (void) waitid(P_PIDFD, s->child.pidfd, &s->child.siginfo, WNOHANG|WEXITED); s->child.waited = true; } diff --git a/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c b/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c index 6d515a94..406e6f22 100644 --- a/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c +++ b/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c @@ -11,6 +11,7 @@ #include "hexdecoct.h" #include "id128-util.h" #include "io-util.h" +#include "log.h" #include "namespace-util.h" #include "process-util.h" #include "sha256.h" diff --git a/src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c b/src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c index 9f6ef719..8f3cd8c4 100644 --- a/src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c +++ b/src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c @@ -4,6 +4,7 @@ #include <errno.h> #include <fcntl.h> +#include <threads.h> #include <unistd.h> #include "sd-id128.h" @@ -16,16 +17,16 @@ #include "id128-util.h" #include "io-util.h" #include "keyring-util.h" +#include "log.h" #include "macro.h" #include "missing_syscall.h" -#include "missing_threads.h" #include "path-util.h" #include "random-util.h" #include "stat-util.h" #include "user-util.h" #if 0 /* NM_IGNORED */ -_public_ char *sd_id128_to_string(sd_id128_t id, char s[_SD_ARRAY_STATIC SD_ID128_STRING_MAX]) { +_public_ char *sd_id128_to_string(sd_id128_t id, char s[static SD_ID128_STRING_MAX]) { size_t k = 0; assert_return(s, NULL); @@ -41,7 +42,7 @@ _public_ char *sd_id128_to_string(sd_id128_t id, char s[_SD_ARRAY_STATIC SD_ID12 return s; } -_public_ char *sd_id128_to_uuid_string(sd_id128_t id, char s[_SD_ARRAY_STATIC SD_ID128_UUID_STRING_MAX]) { +_public_ char *sd_id128_to_uuid_string(sd_id128_t id, char s[static SD_ID128_UUID_STRING_MAX]) { size_t k = 0; assert_return(s, NULL); @@ -221,8 +222,10 @@ static int get_invocation_from_keyring(sd_id128_t *ret) { key = request_key("user", "invocation_id", NULL, 0); if (key == -1) { - /* Keyring support not available? No invocation key stored? */ - if (IN_SET(errno, ENOSYS, ENOKEY)) + /* Keyring support not available? Keyring access locked down? No invocation key stored? */ + if (ERRNO_IS_NOT_SUPPORTED(errno) || + ERRNO_IS_PRIVILEGE(errno) || + errno == ENOKEY) return -ENXIO; return -errno; diff --git a/src/libnm-systemd-core/src/systemd/_sd-common.h b/src/libnm-systemd-core/src/systemd/_sd-common.h index 5792dd81..00537eaf 100644 --- a/src/libnm-systemd-core/src/systemd/_sd-common.h +++ b/src/libnm-systemd-core/src/systemd/_sd-common.h @@ -19,7 +19,7 @@ /* This is a private header; never even think of including this directly! */ -#if defined(__INCLUDE_LEVEL__) && __INCLUDE_LEVEL__ <= 1 && !defined(__COVERITY__) +#if defined(__INCLUDE_LEVEL__) && __INCLUDE_LEVEL__ <= 1 && !defined(__COVERITY__) && !defined(__clang_analyzer__) # error "Do not include _sd-common.h directly; it is a private header." #endif diff --git a/src/libnm-systemd-core/src/systemd/sd-device.h b/src/libnm-systemd-core/src/systemd/sd-device.h index f627ae6d..8f6141b3 100644 --- a/src/libnm-systemd-core/src/systemd/sd-device.h +++ b/src/libnm-systemd-core/src/systemd/sd-device.h @@ -23,11 +23,10 @@ #include <sys/sysmacros.h> #include <sys/types.h> +#include "_sd-common.h" #include "sd-event.h" #include "sd-id128.h" -#include "_sd-common.h" - _SD_BEGIN_DECLARATIONS; typedef struct sd_device sd_device; diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h b/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h index d551b4dd..6054dc44 100644 --- a/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h +++ b/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h @@ -23,14 +23,13 @@ #include <net/ethernet.h> #include <sys/types.h> +#include "_sd-common.h" #include "sd-device.h" #include "sd-dhcp-duid.h" #include "sd-dhcp6-lease.h" #include "sd-dhcp6-option.h" #include "sd-event.h" -#include "_sd-common.h" - _SD_BEGIN_DECLARATIONS; enum { diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h b/src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h index d6bcceb2..5d082b0c 100644 --- a/src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h +++ b/src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h @@ -23,9 +23,8 @@ #include <netinet/in.h> #include <sys/types.h> -#include "sd-dhcp6-option.h" - #include "_sd-common.h" +#include "sd-dhcp6-option.h" _SD_BEGIN_DECLARATIONS; diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp6-option.h b/src/libnm-systemd-core/src/systemd/sd-dhcp6-option.h index 32012426..69f3eaa3 100644 --- a/src/libnm-systemd-core/src/systemd/sd-dhcp6-option.h +++ b/src/libnm-systemd-core/src/systemd/sd-dhcp6-option.h @@ -20,9 +20,8 @@ #include <inttypes.h> #include <sys/types.h> -#include "sd-dhcp6-protocol.h" - #include "_sd-common.h" +#include "sd-dhcp6-protocol.h" _SD_BEGIN_DECLARATIONS; diff --git a/src/libnm-systemd-core/src/systemd/sd-ndisc.h b/src/libnm-systemd-core/src/systemd/sd-ndisc.h index 85fcf6bc..a8f8c47b 100644 --- a/src/libnm-systemd-core/src/systemd/sd-ndisc.h +++ b/src/libnm-systemd-core/src/systemd/sd-ndisc.h @@ -25,14 +25,13 @@ #include <netinet/in.h> #include <sys/types.h> +#include "_sd-common.h" #include "sd-event.h" #include "sd-ndisc-neighbor.h" #include "sd-ndisc-protocol.h" #include "sd-ndisc-redirect.h" #include "sd-ndisc-router.h" -#include "_sd-common.h" - _SD_BEGIN_DECLARATIONS; typedef struct sd_ndisc sd_ndisc; diff --git a/src/libnm-systemd-shared/meson.build b/src/libnm-systemd-shared/meson.build index 7a88d78d..27199546 100644 --- a/src/libnm-systemd-shared/meson.build +++ b/src/libnm-systemd-shared/meson.build @@ -30,6 +30,7 @@ libnm_systemd_shared = static_library( 'src/basic/locale-util.c', 'src/basic/memory-util.c', 'src/basic/mempool.c', + 'src/basic/mountpoint-util.c', 'src/basic/ordered-set.c', 'src/basic/parse-util.c', 'src/basic/path-util.c', @@ -49,6 +50,7 @@ libnm_systemd_shared = static_library( 'src/basic/time-util.c', 'src/basic/tmpfile-util.c', 'src/basic/utf8.c', + 'src/basic/user-util.c', 'src/fundamental/sha256-fundamental.c', 'src/fundamental/string-util-fundamental.c', 'src/shared/dns-domain.c', diff --git a/src/libnm-systemd-shared/src/basic/alloc-util.c b/src/libnm-systemd-shared/src/basic/alloc-util.c index f9686666..a2c0caa1 100644 --- a/src/libnm-systemd-shared/src/basic/alloc-util.c +++ b/src/libnm-systemd-shared/src/basic/alloc-util.c @@ -8,7 +8,6 @@ #include "alloc-util.h" #include "macro.h" -#include "memory-util.h" void* memdup(const void *p, size_t l) { void *ret; diff --git a/src/libnm-systemd-shared/src/basic/alloc-util.h b/src/libnm-systemd-shared/src/basic/alloc-util.h index ba712982..764a364a 100644 --- a/src/libnm-systemd-shared/src/basic/alloc-util.h +++ b/src/libnm-systemd-shared/src/basic/alloc-util.h @@ -7,7 +7,9 @@ #include <stdlib.h> #include <string.h> +#include "assert-util.h" #include "macro.h" +#include "memory-util.h" #if HAS_FEATURE_MEMORY_SANITIZER # include <sanitizer/msan_interface.h> @@ -119,15 +121,6 @@ _malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t need, size_t s return malloc(size * need ?: 1); } -#if !HAVE_REALLOCARRAY -_alloc_(2, 3) static inline void *reallocarray(void *p, size_t need, size_t size) { - if (size_multiply_overflow(size, need)) - return NULL; - - return realloc(p, size * need ?: 1); -} -#endif - _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t need, size_t size) { if (size_multiply_overflow(size, need)) return NULL; @@ -275,5 +268,3 @@ _alloc_(2) static inline void *realloc0(void *p, size_t new_size) { return q; } - -#include "memory-util.h" diff --git a/src/libnm-systemd-shared/src/basic/assert-util.h b/src/libnm-systemd-shared/src/basic/assert-util.h new file mode 100644 index 00000000..30860594 --- /dev/null +++ b/src/libnm-systemd-shared/src/basic/assert-util.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "assert-fundamental.h" +#include "macro.h" + +/* Logging for various assertions */ + +void log_set_assert_return_is_critical(bool b); +bool log_get_assert_return_is_critical(void) _pure_; + +#if 0 /* NM_IGNORED */ +void log_assert_failed_return(const char *text, const char *file, int line, const char *func); +#else /* NM_IGNORED */ +#define log_assert_failed_return(text, file, line, func) \ + ({ \ + log_internal(LOG_DEBUG, \ + 0, \ + file, \ + line, \ + func, \ + "Assertion '%s' failed at %s:%u, function %s(). Ignoring.", \ + text, \ + file, \ + line, \ + func); \ + g_return_if_fail_warning(G_LOG_DOMAIN, G_STRFUNC, text); \ + (void) 0; \ + }) +#endif /* NM_IGNORED */ + +#define assert_log(expr, message) ((_likely_(expr)) \ + ? (true) \ + : (log_assert_failed_return(message, PROJECT_FILE, __LINE__, __func__), false)) + +#define assert_return(expr, r) \ + do { \ + if (!assert_log(expr, #expr)) \ + return (r); \ + } while (false) + +#define assert_return_errno(expr, r, err) \ + do { \ + if (!assert_log(expr, #expr)) { \ + errno = err; \ + return (r); \ + } \ + } while (false) diff --git a/src/libnm-systemd-shared/src/basic/bitfield.h b/src/libnm-systemd-shared/src/basic/bitfield.h index 048e08d7..c6eaaa48 100644 --- a/src/libnm-systemd-shared/src/basic/bitfield.h +++ b/src/libnm-systemd-shared/src/basic/bitfield.h @@ -7,6 +7,7 @@ #define _INDEX_TO_MASK(type, i, uniq) \ ({ \ int UNIQ_T(_i, uniq) = (i); \ + assert(UNIQ_T(_i, uniq) >= 0); \ assert(UNIQ_T(_i, uniq) < (int)sizeof(type) * 8); \ ((type)1) << UNIQ_T(_i, uniq); \ }) diff --git a/src/libnm-systemd-shared/src/basic/cgroup-util.h b/src/libnm-systemd-shared/src/basic/cgroup-util.h index 77294779..269d68c5 100644 --- a/src/libnm-systemd-shared/src/basic/cgroup-util.h +++ b/src/libnm-systemd-shared/src/basic/cgroup-util.h @@ -263,8 +263,7 @@ int cg_get_attribute_as_bool(const char *controller, const char *path, const cha int cg_get_owner(const char *path, uid_t *ret_uid); int cg_set_xattr(const char *path, const char *name, const void *value, size_t size, int flags); -int cg_get_xattr(const char *path, const char *name, void *value, size_t size); -int cg_get_xattr_malloc(const char *path, const char *name, char **ret); +int cg_get_xattr_malloc(const char *path, const char *name, char **ret, size_t *ret_size); /* Returns negative on error, and 0 or 1 on success for the bool value */ int cg_get_xattr_bool(const char *path, const char *name); int cg_remove_xattr(const char *path, const char *name); @@ -312,10 +311,6 @@ int cg_mask_supported_subtree(const char *root, CGroupMask *ret); int cg_mask_from_string(const char *s, CGroupMask *ret); int cg_mask_to_string(CGroupMask mask, char **ret); -int cg_kernel_controllers(Set **controllers); - -bool cg_ns_supported(void); -bool cg_freezer_supported(void); bool cg_kill_supported(void); int cg_all_unified(void); @@ -329,9 +324,6 @@ static inline int cg_unified(void) { const char* cgroup_controller_to_string(CGroupController c) _const_; CGroupController cgroup_controller_from_string(const char *s) _pure_; -bool is_cgroup_fs(const struct statfs *s); -bool fd_is_cgroup_fs(int fd); - typedef enum ManagedOOMMode { MANAGED_OOM_AUTO, MANAGED_OOM_KILL, @@ -365,4 +357,4 @@ typedef union { .file_handle.handle_type = FILEID_KERNFS, \ } -#define CG_FILE_HANDLE_CGROUPID(fh) (*(uint64_t*) (fh).file_handle.f_handle) +#define CG_FILE_HANDLE_CGROUPID(fh) (*CAST_ALIGN_PTR(uint64_t, (fh).file_handle.f_handle)) diff --git a/src/libnm-systemd-shared/src/basic/chattr-util.c b/src/libnm-systemd-shared/src/basic/chattr-util.c index 2a63e46d..0a27e023 100644 --- a/src/libnm-systemd-shared/src/basic/chattr-util.c +++ b/src/libnm-systemd-shared/src/basic/chattr-util.c @@ -6,13 +6,13 @@ #include <fcntl.h> #include <sys/ioctl.h> #include <sys/stat.h> -#include <linux/fs.h> #include "bitfield.h" #include "chattr-util.h" #include "errno-util.h" #include "fd-util.h" #include "fs-util.h" +#include "log.h" #include "macro.h" #include "string-util.h" diff --git a/src/libnm-systemd-shared/src/basic/chattr-util.h b/src/libnm-systemd-shared/src/basic/chattr-util.h index 1fe38e32..472054d5 100644 --- a/src/libnm-systemd-shared/src/basic/chattr-util.h +++ b/src/libnm-systemd-shared/src/basic/chattr-util.h @@ -2,7 +2,6 @@ #pragma once #include <fcntl.h> -#include <linux/fs.h> #include <stdbool.h> #include <stddef.h> @@ -41,14 +40,14 @@ typedef enum ChattrApplyFlags { } ChattrApplyFlags; int chattr_full(int dir_fd, const char *path, unsigned value, unsigned mask, unsigned *ret_previous, unsigned *ret_final, ChattrApplyFlags flags); -static inline int chattr_at(int dir_fd, const char *path, unsigned value, unsigned mask, unsigned *previous) { - return chattr_full(dir_fd, path, value, mask, previous, NULL, 0); +static inline int chattr_at(int dir_fd, const char *path, unsigned value, unsigned mask) { + return chattr_full(dir_fd, path, value, mask, NULL, NULL, 0); } -static inline int chattr_fd(int fd, unsigned value, unsigned mask, unsigned *previous) { - return chattr_full(fd, NULL, value, mask, previous, NULL, 0); +static inline int chattr_fd(int fd, unsigned value, unsigned mask) { + return chattr_full(fd, NULL, value, mask, NULL, NULL, 0); } -static inline int chattr_path(const char *path, unsigned value, unsigned mask, unsigned *previous) { - return chattr_full(AT_FDCWD, path, value, mask, previous, NULL, 0); +static inline int chattr_path(const char *path, unsigned value, unsigned mask) { + return chattr_full(AT_FDCWD, path, value, mask, NULL, NULL, 0); } int read_attr_fd(int fd, unsigned *ret); diff --git a/src/libnm-systemd-shared/src/basic/devnum-util.h b/src/libnm-systemd-shared/src/basic/devnum-util.h index e109de99..0efca567 100644 --- a/src/libnm-systemd-shared/src/basic/devnum-util.h +++ b/src/libnm-systemd-shared/src/basic/devnum-util.h @@ -9,6 +9,9 @@ int parse_devnum(const char *s, dev_t *ret); +#define DEVNUM_MAJOR_MAX ((UINT32_C(1) << 12) - 1U) +#define DEVNUM_MINOR_MAX ((UINT32_C(1) << 20) - 1U) + /* glibc and the Linux kernel have different ideas about the major/minor size. These calls will check whether the * specified major is valid by the Linux kernel's standards, not by glibc's. Linux has 20bits of minor, and 12 bits of * major space. See MINORBITS in linux/kdev_t.h in the kernel sources. (If you wonder why we define _y here, instead of @@ -18,14 +21,14 @@ int parse_devnum(const char *s, dev_t *ret); #define DEVICE_MAJOR_VALID(x) \ ({ \ typeof(x) _x = (x), _y = 0; \ - _x >= _y && _x < (UINT32_C(1) << 12); \ + _x >= _y && _x <= DEVNUM_MAJOR_MAX; \ \ }) #define DEVICE_MINOR_VALID(x) \ ({ \ typeof(x) _x = (x), _y = 0; \ - _x >= _y && _x < (UINT32_C(1) << 20); \ + _x >= _y && _x <= DEVNUM_MINOR_MAX; \ }) int device_path_make_major_minor(mode_t mode, dev_t devnum, char **ret); @@ -54,3 +57,6 @@ static inline char *format_devnum(dev_t d, char buf[static DEVNUM_STR_MAX]) { static inline bool devnum_is_zero(dev_t d) { return major(d) == 0 && minor(d) == 0; } + +#define DEVNUM_TO_PTR(u) ((void*) (uintptr_t) (u)) +#define PTR_TO_DEVNUM(p) ((dev_t) ((uintptr_t) (p))) diff --git a/src/libnm-systemd-shared/src/basic/env-file.c b/src/libnm-systemd-shared/src/basic/env-file.c index 75b2febf..d705765b 100644 --- a/src/libnm-systemd-shared/src/basic/env-file.c +++ b/src/libnm-systemd-shared/src/basic/env-file.c @@ -9,6 +9,7 @@ #include "fd-util.h" #include "fileio.h" #include "fs-util.h" +#include "log.h" #include "string-util.h" #include "strv.h" #include "tmpfile-util.h" diff --git a/src/libnm-systemd-shared/src/basic/env-util.c b/src/libnm-systemd-shared/src/basic/env-util.c index 2fe7332c..8dd52c09 100644 --- a/src/libnm-systemd-shared/src/basic/env-util.c +++ b/src/libnm-systemd-shared/src/basic/env-util.c @@ -13,6 +13,7 @@ #include "errno-util.h" #include "escape.h" #include "extract-word.h" +#include "log.h" #include "macro.h" #include "parse-util.h" #include "path-util.h" @@ -549,7 +550,7 @@ char* strv_env_get_n(char * const *l, const char *name, size_t k, ReplaceEnvFlag return NULL; t = strndupa_safe(name, k); - return getenv(t); + return secure_getenv(t); }; return NULL; @@ -700,7 +701,7 @@ int replace_env_full( _cleanup_strv_free_ char **unset_variables = NULL, **bad_variables = NULL; const char *e, *word = format, *test_value = NULL; /* test_value is initialized to appease gcc */ _cleanup_free_ char *s = NULL; - char ***pu, ***pb, *k; + char ***pu, ***pb; size_t i, len = 0; /* len is initialized to appease gcc */ int nest = 0, r; @@ -722,33 +723,24 @@ int replace_env_full( case CURLY: if (*e == '{') { - k = strnappend(s, word, e-word-1); - if (!k) + if (!strextendn(&s, word, e-word-1)) return -ENOMEM; - free_and_replace(s, k); - word = e-1; state = VARIABLE; nest++; } else if (*e == '$') { - k = strnappend(s, word, e-word); - if (!k) + if (!strextendn(&s, word, e-word)) return -ENOMEM; - free_and_replace(s, k); - word = e+1; state = WORD; } else if (FLAGS_SET(flags, REPLACE_ENV_ALLOW_BRACELESS) && strchr(VALID_BASH_ENV_NAME_CHARS, *e)) { - k = strnappend(s, word, e-word-1); - if (!k) + if (!strextendn(&s, word, e-word-1)) return -ENOMEM; - free_and_replace(s, k); - word = e-1; state = VARIABLE_RAW; @@ -1121,7 +1113,7 @@ int getenv_steal_erase(const char *name, char **ret) { * it from there. Usecase: reading passwords from the env block (which is a bad idea, but useful for * testing, and given that people are likely going to misuse this, be thorough) */ - e = getenv(name); + e = secure_getenv(name); if (!e) { if (ret) *ret = NULL; @@ -1145,25 +1137,6 @@ int getenv_steal_erase(const char *name, char **ret) { return 1; } -int set_full_environment(char **env) { - int r; - - clearenv(); - - STRV_FOREACH(e, env) { - _cleanup_free_ char *k = NULL, *v = NULL; - - r = split_pair(*e, "=", &k, &v); - if (r < 0) - return r; - - if (setenv(k, v, /* overwrite= */ true) < 0) - return -errno; - } - - return 0; -} - int setenvf(const char *name, bool overwrite, const char *valuef, ...) { _cleanup_free_ char *value = NULL; va_list ap; diff --git a/src/libnm-systemd-shared/src/basic/env-util.h b/src/libnm-systemd-shared/src/basic/env-util.h index 203ed65b..52771ecc 100644 --- a/src/libnm-systemd-shared/src/basic/env-util.h +++ b/src/libnm-systemd-shared/src/basic/env-util.h @@ -82,6 +82,4 @@ int getenv_path_list(const char *name, char ***ret_paths); int getenv_steal_erase(const char *name, char **ret); -int set_full_environment(char **env); - int setenvf(const char *name, bool overwrite, const char *valuef, ...) _printf_(3,4); diff --git a/src/libnm-systemd-shared/src/basic/errno-util.h b/src/libnm-systemd-shared/src/basic/errno-util.h index 02572e3b..01b4d59e 100644 --- a/src/libnm-systemd-shared/src/basic/errno-util.h +++ b/src/libnm-systemd-shared/src/basic/errno-util.h @@ -5,6 +5,7 @@ #include <stdlib.h> #include <string.h> +#include "assert-util.h" #include "macro.h" /* strerror(3) says that glibc uses a maximum length of 1024 bytes. */ diff --git a/src/libnm-systemd-shared/src/basic/escape.c b/src/libnm-systemd-shared/src/basic/escape.c index e882aced..ff1d817c 100644 --- a/src/libnm-systemd-shared/src/basic/escape.c +++ b/src/libnm-systemd-shared/src/basic/escape.c @@ -82,10 +82,15 @@ char* cescape_length(const char *s, size_t n) { const char *f; char *r, *t; + /* Does C style string escaping. May be reversed with cunescape(). */ + assert(s || n == 0); - /* Does C style string escaping. May be reversed with - * cunescape(). */ + if (n == SIZE_MAX) + n = strlen(s); + + if (n > (SIZE_MAX - 1) / 4) + return NULL; r = new(char, n*4 + 1); if (!r) @@ -99,12 +104,6 @@ char* cescape_length(const char *s, size_t n) { return r; } -char* cescape(const char *s) { - assert(s); - - return cescape_length(s, strlen(s)); -} - int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit, bool accept_nul) { int r = 1; @@ -452,7 +451,7 @@ char* escape_non_printable_full(const char *str, size_t console_width, XEscapeFl char* octescape(const char *s, size_t len) { char *buf, *t; - /* Escapes all chars in bad, in addition to \ and " chars, in \nnn style escaping. */ + /* Escapes \ and " chars, in \nnn style escaping. */ assert(s || len == 0); @@ -482,13 +481,19 @@ char* octescape(const char *s, size_t len) { return buf; } -char* decescape(const char *s, const char *bad, size_t len) { +char* decescape(const char *s, size_t len, const char *bad) { char *buf, *t; /* Escapes all chars in bad, in addition to \ and " chars, in \nnn decimal style escaping. */ assert(s || len == 0); + if (len == SIZE_MAX) + len = strlen(s); + + if (len > (SIZE_MAX - 1) / 4) + return NULL; + t = buf = new(char, len * 4 + 1); if (!buf) return NULL; diff --git a/src/libnm-systemd-shared/src/basic/escape.h b/src/libnm-systemd-shared/src/basic/escape.h index 65caf0db..05c27f68 100644 --- a/src/libnm-systemd-shared/src/basic/escape.h +++ b/src/libnm-systemd-shared/src/basic/escape.h @@ -8,7 +8,6 @@ #include <uchar.h> #include "string-util.h" -#include "missing_type.h" /* What characters are special in the shell? */ /* must be escaped outside and inside double-quotes */ @@ -41,9 +40,11 @@ typedef enum ShellEscapeFlags { SHELL_ESCAPE_EMPTY = 1 << 2, /* Format empty arguments as "". */ } ShellEscapeFlags; -char* cescape(const char *s); -char* cescape_length(const char *s, size_t n); int cescape_char(char c, char *buf); +char* cescape_length(const char *s, size_t n) _nonnull_if_nonzero_(1, 2); +static inline char* cescape(const char *s) { + return cescape_length(s, SIZE_MAX); +} int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit, bool accept_nul); @@ -65,7 +66,7 @@ static inline char* xescape(const char *s, const char *bad) { return xescape_full(s, bad, SIZE_MAX, 0); } char* octescape(const char *s, size_t len); -char* decescape(const char *s, const char *bad, size_t len); +char* decescape(const char *s, size_t len, const char *bad) _nonnull_if_nonzero_(1, 2); char* escape_non_printable_full(const char *str, size_t console_width, XEscapeFlags flags); char* shell_escape(const char *s, const char *bad); diff --git a/src/libnm-systemd-shared/src/basic/ether-addr-util.c b/src/libnm-systemd-shared/src/basic/ether-addr-util.c index 2643c974..168fd329 100644 --- a/src/libnm-systemd-shared/src/basic/ether-addr-util.c +++ b/src/libnm-systemd-shared/src/basic/ether-addr-util.c @@ -10,6 +10,7 @@ #include "ether-addr-util.h" #include "hexdecoct.h" +#include "log.h" #include "macro.h" #include "string-util.h" @@ -87,22 +88,6 @@ char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR return buffer; } -int ether_addr_to_string_alloc(const struct ether_addr *addr, char **ret) { - char *buf; - - assert(addr); - assert(ret); - - buf = new(char, ETHER_ADDR_TO_STRING_MAX); - if (!buf) - return -ENOMEM; - - ether_addr_to_string(addr, buf); - - *ret = buf; - return 0; -} - int ether_addr_compare(const struct ether_addr *a, const struct ether_addr *b) { return memcmp(a, b, ETH_ALEN); } diff --git a/src/libnm-systemd-shared/src/basic/ether-addr-util.h b/src/libnm-systemd-shared/src/basic/ether-addr-util.h index 8ebf9c03..168c6500 100644 --- a/src/libnm-systemd-shared/src/basic/ether-addr-util.h +++ b/src/libnm-systemd-shared/src/basic/ether-addr-util.h @@ -72,7 +72,6 @@ extern const struct hash_ops hw_addr_hash_ops_free; #define ETHER_ADDR_TO_STRING_MAX (3*6) char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]); -int ether_addr_to_string_alloc(const struct ether_addr *addr, char **ret); /* Use only as function argument, never stand-alone! */ #define ETHER_ADDR_TO_STR(addr) ether_addr_to_string((addr), (char[ETHER_ADDR_TO_STRING_MAX]){}) diff --git a/src/libnm-systemd-shared/src/basic/fd-util.c b/src/libnm-systemd-shared/src/basic/fd-util.c index e052a6a2..fd6a95e0 100644 --- a/src/libnm-systemd-shared/src/basic/fd-util.c +++ b/src/libnm-systemd-shared/src/basic/fd-util.c @@ -4,9 +4,7 @@ #include <errno.h> #include <fcntl.h> -#if WANT_LINUX_FS_H -#include <linux/fs.h> -#endif +#include <linux/kcmp.h> #include <linux/magic.h> #include <sys/ioctl.h> #include <sys/resource.h> @@ -19,6 +17,7 @@ #include "fileio.h" #include "fs-util.h" #include "io-util.h" +#include "log.h" #include "macro.h" #include "missing_fcntl.h" #include "missing_fs.h" @@ -31,7 +30,6 @@ #include "sort-util.h" #include "stat-util.h" #include "stdio-util.h" -#include "tmpfile-util.h" /* The maximum number of iterations in the loop to close descriptors in the fallback case * when /proc/self/fd/ is inaccessible. */ @@ -1012,13 +1010,13 @@ int fd_verify_safe_flags_full(int fd, int extra_flags) { if (flags < 0) return -errno; - unexpected_flags = flags & ~(O_ACCMODE|O_NOFOLLOW|RAW_O_LARGEFILE|extra_flags); + unexpected_flags = flags & ~(O_ACCMODE_STRICT|O_NOFOLLOW|RAW_O_LARGEFILE|extra_flags); if (unexpected_flags != 0) return log_debug_errno(SYNTHETIC_ERRNO(EREMOTEIO), "Unexpected flags set for extrinsic fd: 0%o", (unsigned) unexpected_flags); - return flags & (O_ACCMODE | extra_flags); /* return the flags variable, but remove the noise */ + return flags & (O_ACCMODE_STRICT | extra_flags); /* return the flags variable, but remove the noise */ } int read_nr_open(void) { @@ -1095,30 +1093,27 @@ int path_is_root_at(int dir_fd, const char *path) { } int fds_are_same_mount(int fd1, int fd2) { - STRUCT_NEW_STATX_DEFINE(st1); - STRUCT_NEW_STATX_DEFINE(st2); + struct statx sx1 = {}, sx2 = {}; /* explicitly initialize the struct to make msan silent. */ int r; assert(fd1 >= 0); assert(fd2 >= 0); - r = statx_fallback(fd1, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &st1.sx); - if (r < 0) - return r; + if (statx(fd1, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sx1) < 0) + return -errno; - r = statx_fallback(fd2, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &st2.sx); - if (r < 0) - return r; + if (statx(fd2, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sx2) < 0) + return -errno; /* First, compare inode. If these are different, the fd does not point to the root directory "/". */ - if (!statx_inode_same(&st1.sx, &st2.sx)) + if (!statx_inode_same(&sx1, &sx2)) return false; /* Note, statx() does not provide the mount ID and path_get_mnt_id_at() does not work when an old * kernel is used. In that case, let's assume that we do not have such spurious mount points in an * early boot stage, and silently skip the following check. */ - if (!FLAGS_SET(st1.nsx.stx_mask, STATX_MNT_ID)) { + if (!FLAGS_SET(sx1.stx_mask, STATX_MNT_ID)) { int mntid; r = path_get_mnt_id_at_fallback(fd1, "", &mntid); @@ -1126,11 +1121,11 @@ int fds_are_same_mount(int fd1, int fd2) { return r; assert(mntid >= 0); - st1.nsx.stx_mnt_id = mntid; - st1.nsx.stx_mask |= STATX_MNT_ID; + sx1.stx_mnt_id = mntid; + sx1.stx_mask |= STATX_MNT_ID; } - if (!FLAGS_SET(st2.nsx.stx_mask, STATX_MNT_ID)) { + if (!FLAGS_SET(sx2.stx_mask, STATX_MNT_ID)) { int mntid; r = path_get_mnt_id_at_fallback(fd2, "", &mntid); @@ -1138,15 +1133,15 @@ int fds_are_same_mount(int fd1, int fd2) { return r; assert(mntid >= 0); - st2.nsx.stx_mnt_id = mntid; - st2.nsx.stx_mask |= STATX_MNT_ID; + sx2.stx_mnt_id = mntid; + sx2.stx_mask |= STATX_MNT_ID; } - return statx_mount_same(&st1.nsx, &st2.nsx); + return statx_mount_same(&sx1, &sx2); } const char* accmode_to_string(int flags) { - switch (flags & O_ACCMODE) { + switch (flags & O_ACCMODE_STRICT) { case O_RDONLY: return "ro"; case O_WRONLY: diff --git a/src/libnm-systemd-shared/src/basic/fd-util.h b/src/libnm-systemd-shared/src/basic/fd-util.h index 93b254c6..59c43e81 100644 --- a/src/libnm-systemd-shared/src/basic/fd-util.h +++ b/src/libnm-systemd-shared/src/basic/fd-util.h @@ -8,6 +8,7 @@ #include <sys/socket.h> #include "macro.h" +#include "memory-util.h" #include "missing_fcntl.h" #include "stdio-util.h" diff --git a/src/libnm-systemd-shared/src/basic/fileio.c b/src/libnm-systemd-shared/src/basic/fileio.c index 78231228..0d83faf2 100644 --- a/src/libnm-systemd-shared/src/basic/fileio.c +++ b/src/libnm-systemd-shared/src/basic/fileio.c @@ -247,17 +247,13 @@ static int write_string_file_atomic_at( } r = fopen_temporary_at(dir_fd, fn, &f, &p); + if (call_label_ops_post) + /* If fopen_temporary_at() failed in the above, propagate the error code, and ignore failures + * in label_ops_post(). */ + RET_GATHER(r, label_ops_post(f ? fileno(f) : dir_fd, f ? NULL : fn, /* created= */ !!f)); if (r < 0) goto fail; - if (call_label_ops_post) { - call_label_ops_post = false; - - r = label_ops_post(fileno(f), /* path= */ NULL, /* created= */ true); - if (r < 0) - goto fail; - } - r = write_string_stream_full(f, line, flags, ts); if (r < 0) goto fail; @@ -280,9 +276,6 @@ static int write_string_file_atomic_at( return 0; fail: - if (call_label_ops_post) - (void) label_ops_post(f ? fileno(f) : dir_fd, f ? NULL : fn, /* created= */ !!f); - if (f) (void) unlinkat(dir_fd, p, 0); return r; @@ -296,24 +289,27 @@ int write_string_file_full( const struct timespec *ts, const char *label_fn) { - bool call_label_ops_post = false, made_file = false; + bool made_file = false; _cleanup_fclose_ FILE *f = NULL; _cleanup_close_ int fd = -EBADF; int r; - assert(fn); + assert(dir_fd == AT_FDCWD || dir_fd >= 0); assert(line); /* We don't know how to verify whether the file contents was already on-disk. */ assert(!((flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE) && (flags & WRITE_STRING_FILE_SYNC))); if (flags & WRITE_STRING_FILE_MKDIR_0755) { + assert(fn); + r = mkdirat_parents(dir_fd, fn, 0755); if (r < 0) return r; } if (flags & WRITE_STRING_FILE_ATOMIC) { + assert(fn); assert(flags & WRITE_STRING_FILE_CREATE); r = write_string_file_atomic_at(dir_fd, fn, line, flags, ts); @@ -323,37 +319,39 @@ int write_string_file_full( return r; } - mode_t mode = write_string_file_flags_to_mode(flags); - - if (FLAGS_SET(flags, WRITE_STRING_FILE_LABEL|WRITE_STRING_FILE_CREATE)) { - r = label_ops_pre(dir_fd, label_fn ?: fn, mode); - if (r < 0) - goto fail; - - call_label_ops_post = true; - } - /* We manually build our own version of fopen(..., "we") that works without O_CREAT and with O_NOFOLLOW if needed. */ - fd = openat_report_new( - dir_fd, fn, O_CLOEXEC | O_NOCTTY | - (FLAGS_SET(flags, WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0) | - (FLAGS_SET(flags, WRITE_STRING_FILE_CREATE) ? O_CREAT : 0) | - (FLAGS_SET(flags, WRITE_STRING_FILE_TRUNCATE) ? O_TRUNC : 0) | - (FLAGS_SET(flags, WRITE_STRING_FILE_SUPPRESS_REDUNDANT_VIRTUAL) ? O_RDWR : O_WRONLY), - mode, - &made_file); - if (fd < 0) { - r = fd; - goto fail; - } + if (isempty(fn)) + r = fd = fd_reopen( + ASSERT_FD(dir_fd), O_CLOEXEC | O_NOCTTY | + (FLAGS_SET(flags, WRITE_STRING_FILE_TRUNCATE) ? O_TRUNC : 0) | + (FLAGS_SET(flags, WRITE_STRING_FILE_SUPPRESS_REDUNDANT_VIRTUAL) ? O_RDWR : O_WRONLY)); + else { + mode_t mode = write_string_file_flags_to_mode(flags); + bool call_label_ops_post = false; + + if (FLAGS_SET(flags, WRITE_STRING_FILE_LABEL|WRITE_STRING_FILE_CREATE)) { + r = label_ops_pre(dir_fd, label_fn ?: fn, mode); + if (r < 0) + goto fail; - if (call_label_ops_post) { - call_label_ops_post = false; + call_label_ops_post = true; + } - r = label_ops_post(fd, /* path= */ NULL, made_file); - if (r < 0) - goto fail; + r = fd = openat_report_new( + dir_fd, fn, O_CLOEXEC | O_NOCTTY | + (FLAGS_SET(flags, WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0) | + (FLAGS_SET(flags, WRITE_STRING_FILE_CREATE) ? O_CREAT : 0) | + (FLAGS_SET(flags, WRITE_STRING_FILE_TRUNCATE) ? O_TRUNC : 0) | + (FLAGS_SET(flags, WRITE_STRING_FILE_SUPPRESS_REDUNDANT_VIRTUAL) ? O_RDWR : O_WRONLY), + mode, + &made_file); + if (call_label_ops_post) + /* If openat_report_new() failed in the above, propagate the error code, and ignore + * failures in label_ops_post(). */ + RET_GATHER(r, label_ops_post(fd >= 0 ? fd : dir_fd, fd >= 0 ? NULL : fn, made_file)); } + if (r < 0) + goto fail; r = take_fdopen_unlocked(&fd, "w", &f); if (r < 0) @@ -369,9 +367,6 @@ int write_string_file_full( return 0; fail: - if (call_label_ops_post) - (void) label_ops_post(fd >= 0 ? fd : dir_fd, fd >= 0 ? NULL : fn, made_file); - if (made_file) (void) unlinkat(dir_fd, fn, 0); @@ -383,7 +378,7 @@ fail: /* OK, the operation failed, but let's see if the right contents in place already. If so, eat up the * error. */ - if (verify_file(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE) || (flags & WRITE_STRING_FILE_VERIFY_IGNORE_NEWLINE)) > 0) + if (verify_file_at(dir_fd, fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE) || (flags & WRITE_STRING_FILE_VERIFY_IGNORE_NEWLINE)) > 0) return 0; return r; @@ -445,7 +440,6 @@ int verify_file_at(int dir_fd, const char *fn, const char *blob, bool accept_ext size_t l, k; int r; - assert(fn); assert(blob); l = strlen(blob); @@ -457,7 +451,7 @@ int verify_file_at(int dir_fd, const char *fn, const char *blob, bool accept_ext if (!buf) return -ENOMEM; - r = fopen_unlocked_at(dir_fd, fn, "re", 0, &f); + r = fopen_unlocked_at(dir_fd, strempty(fn), "re", 0, &f); if (r < 0) return r; @@ -478,7 +472,13 @@ int verify_file_at(int dir_fd, const char *fn, const char *blob, bool accept_ext } #endif /* NM_IGNORED */ -int read_virtual_file_fd(int fd, size_t max_size, char **ret_contents, size_t *ret_size) { +int read_virtual_file_at( + int dir_fd, + const char *filename, + size_t max_size, + char **ret_contents, + size_t *ret_size) { + _cleanup_free_ char *buf = NULL; size_t n, size; int n_retries; @@ -495,11 +495,23 @@ int read_virtual_file_fd(int fd, size_t max_size, char **ret_contents, size_t *r * max_size specifies a limit on the bytes read. If max_size is SIZE_MAX, the full file is read. If * the full file is too large to read, an error is returned. For other values of max_size, *partial * contents* may be returned. (Though the read is still done using one syscall.) Returns 0 on - * partial success, 1 if untruncated contents were read. */ + * partial success, 1 if untruncated contents were read. + * + * Rule: for kernfs files using "seq_file" → use regular read_full_file_at() + * for kernfs files using "raw" → use read_virtual_file_at() + */ - assert(fd >= 0); + assert(dir_fd >= 0 || dir_fd == AT_FDCWD); assert(max_size <= READ_VIRTUAL_BYTES_MAX || max_size == SIZE_MAX); + _cleanup_close_ int fd = -EBADF; + if (isempty(filename)) + fd = fd_reopen(ASSERT_FD(dir_fd), O_RDONLY | O_NOCTTY | O_CLOEXEC); + else + fd = RET_NERRNO(openat(dir_fd, filename, O_RDONLY | O_NOCTTY | O_CLOEXEC)); + if (fd < 0) + return fd; + /* Limit the number of attempts to read the number of bytes returned by fstat(). */ n_retries = 3; @@ -623,31 +635,6 @@ int read_virtual_file_fd(int fd, size_t max_size, char **ret_contents, size_t *r return !truncated; } -int read_virtual_file_at( - int dir_fd, - const char *filename, - size_t max_size, - char **ret_contents, - size_t *ret_size) { - - _cleanup_close_ int fd = -EBADF; - - assert(dir_fd >= 0 || dir_fd == AT_FDCWD); - - if (!filename) { - if (dir_fd == AT_FDCWD) - return -EBADF; - - return read_virtual_file_fd(dir_fd, max_size, ret_contents, ret_size); - } - - fd = openat(dir_fd, filename, O_RDONLY | O_NOCTTY | O_CLOEXEC); - if (fd < 0) - return -errno; - - return read_virtual_file_fd(fd, max_size, ret_contents, ret_size); -} - int read_full_stream_full( FILE *f, const char *filename, @@ -727,7 +714,7 @@ int read_full_stream_full( size_t k; /* If we shall fail when reading overly large data, then read exactly one byte more than the - * specified size at max, since that'll tell us if there's anymore data beyond the limit*/ + * specified size at max, since that'll tell us if there's anymore data beyond the limit. */ if (FLAGS_SET(flags, READ_FULL_FILE_FAIL_WHEN_LARGER) && n_next > size) n_next = size + 1; @@ -907,74 +894,46 @@ int script_get_shebang_interpreter(const char *path, char **ret) { return 0; } -/** - * Retrieve one field from a file like /proc/self/status. pattern - * should not include whitespace or the delimiter (':'). pattern matches only - * the beginning of a line. Whitespace before ':' is skipped. Whitespace and - * zeros after the ':' will be skipped. field must be freed afterwards. - * terminator specifies the terminating characters of the field value (not - * included in the value). - */ -int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) { - _cleanup_free_ char *status = NULL; - char *t, *f; +int get_proc_field(const char *path, const char *key, char **ret) { + _cleanup_fclose_ FILE *f = NULL; int r; - assert(terminator); - assert(filename); - assert(pattern); - assert(field); + /* Retrieve one field from a file like /proc/self/status. "key" matches the beginning of the line + * and should not include whitespace or the delimiter (':'). + * Whitespaces after the ':' will be skipped. Only the first element is returned + * (i.e. for /proc/meminfo line "MemTotal: 1024 kB" -> return "1024"). */ + + assert(path); + assert(key); - r = read_full_virtual_file(filename, &status, NULL); + r = fopen_unlocked(path, "re", &f); + if (r == -ENOENT && proc_mounted() == 0) + return -ENOSYS; if (r < 0) return r; - t = status; - - do { - bool pattern_ok; - - do { - t = strstr(t, pattern); - if (!t) - return -ENOENT; - - /* Check that pattern occurs in beginning of line. */ - pattern_ok = (t == status || t[-1] == '\n'); - - t += strlen(pattern); - - } while (!pattern_ok); - - t += strspn(t, " \t"); - if (!*t) - return -ENOENT; - - } while (*t != ':'); - - t++; - - if (*t) { - t += strspn(t, " \t"); - - /* Also skip zeros, because when this is used for - * capabilities, we don't want the zeros. This way the - * same capability set always maps to the same string, - * irrespective of the total capability set size. For - * other numbers it shouldn't matter. */ - t += strspn(t, "0"); - /* Back off one char if there's nothing but whitespace - and zeros */ - if (!*t || isspace(*t)) - t--; + for (;;) { + _cleanup_free_ char *line = NULL; + + r = read_line(f, LONG_LINE_MAX, &line); + if (r < 0) + return r; + if (r == 0) + return -ENODATA; + + char *l = startswith(line, key); + if (l && *l == ':') { + if (ret) { + char *s = strdupcspn(skip_leading_chars(l + 1, " \t"), WHITESPACE); + if (!s) + return -ENOMEM; + + *ret = s; + } + + return 0; + } } - - f = strdupcspn(t, terminator); - if (!f) - return -ENOMEM; - - *field = f; - return 0; } DIR* xopendirat(int dir_fd, const char *name, int flags) { diff --git a/src/libnm-systemd-shared/src/basic/fileio.h b/src/libnm-systemd-shared/src/basic/fileio.h index bd053050..eff98802 100644 --- a/src/libnm-systemd-shared/src/basic/fileio.h +++ b/src/libnm-systemd-shared/src/basic/fileio.h @@ -56,6 +56,9 @@ int write_string_file_full(int dir_fd, const char *fn, const char *line, WriteSt static inline int write_string_file_at(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags) { return write_string_file_full(dir_fd, fn, line, flags, NULL, NULL); } +static inline int write_string_file_fd(int dir_fd, const char *line, WriteStringFileFlags flags) { + return write_string_file_at(dir_fd, NULL, line, flags); +} static inline int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) { return write_string_file_at(AT_FDCWD, fn, line, flags); } @@ -75,8 +78,10 @@ static inline int read_full_file(const char *filename, char **ret_contents, size return read_full_file_full(AT_FDCWD, filename, UINT64_MAX, SIZE_MAX, 0, NULL, ret_contents, ret_size); } -int read_virtual_file_fd(int fd, size_t max_size, char **ret_contents, size_t *ret_size); int read_virtual_file_at(int dir_fd, const char *filename, size_t max_size, char **ret_contents, size_t *ret_size); +static inline int read_virtual_file_fd(int fd, size_t max_size, char **ret_contents, size_t *ret_size) { + return read_virtual_file_at(fd, NULL, max_size, ret_contents, ret_size); +} static inline int read_virtual_file(const char *filename, size_t max_size, char **ret_contents, size_t *ret_size) { return read_virtual_file_at(AT_FDCWD, filename, max_size, ret_contents, ret_size); } @@ -90,13 +95,10 @@ static inline int read_full_stream(FILE *f, char **ret_contents, size_t *ret_siz } int verify_file_at(int dir_fd, const char *fn, const char *blob, bool accept_extra_nl); -static inline int verify_file(const char *fn, const char *blob, bool accept_extra_nl) { - return verify_file_at(AT_FDCWD, fn, blob, accept_extra_nl); -} int script_get_shebang_interpreter(const char *path, char **ret); -int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field); +int get_proc_field(const char *path, const char *key, char **ret); DIR* xopendirat(int dir_fd, const char *name, int flags); diff --git a/src/libnm-systemd-shared/src/basic/format-ifname.c b/src/libnm-systemd-shared/src/basic/format-ifname.c index 81592998..57f39c30 100644 --- a/src/libnm-systemd-shared/src/basic/format-ifname.c +++ b/src/libnm-systemd-shared/src/basic/format-ifname.c @@ -3,6 +3,8 @@ #include "nm-sd-adapt-shared.h" #include "format-ifname.h" +#include "log.h" +#include "stdio-util.h" #include "string-util.h" assert_cc(STRLEN("%") + DECIMAL_STR_MAX(int) <= IF_NAMESIZE); diff --git a/src/libnm-systemd-shared/src/basic/format-util.c b/src/libnm-systemd-shared/src/basic/format-util.c index b2a5d2d0..6b767ef2 100644 --- a/src/libnm-systemd-shared/src/basic/format-util.c +++ b/src/libnm-systemd-shared/src/basic/format-util.c @@ -64,5 +64,4 @@ char* format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag) { finish: buf[l-1] = 0; return buf; - } diff --git a/src/libnm-systemd-shared/src/basic/fs-util.c b/src/libnm-systemd-shared/src/basic/fs-util.c index 0202933d..bdc341f6 100644 --- a/src/libnm-systemd-shared/src/basic/fs-util.c +++ b/src/libnm-systemd-shared/src/basic/fs-util.c @@ -3,11 +3,11 @@ #include "nm-sd-adapt-shared.h" #include <errno.h> +#include <linux/falloc.h> +#include <linux/magic.h> #include <stddef.h> #include <stdlib.h> #include <sys/file.h> -#include <linux/falloc.h> -#include <linux/magic.h> #include <unistd.h> #include "alloc-util.h" @@ -80,6 +80,11 @@ int rmdir_parents(const char *path, const char *stop) { int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) { int r; + assert(olddirfd >= 0 || olddirfd == AT_FDCWD); + assert(oldpath); + assert(newdirfd >= 0 || newdirfd == AT_FDCWD); + assert(newpath); + /* Try the ideal approach first */ if (renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE) >= 0) return 0; @@ -792,7 +797,7 @@ int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags) { } } - /* Don't dallocate if there's nothing to deallocate or if the file is linked elsewhere */ + /* Don't deallocate if there's nothing to deallocate or if the file is linked elsewhere */ if (st.st_blocks == 0 || st.st_nlink > 0) return 0; @@ -1041,7 +1046,7 @@ int open_mkdir_at_full(int dirfd, const char *path, int flags, XOpenFlags xopen_ if (flags & ~(O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_EXCL|O_NOATIME|O_NOFOLLOW|O_PATH)) return -EINVAL; - if ((flags & O_ACCMODE) != O_RDONLY) + if ((flags & O_ACCMODE_STRICT) != O_RDONLY) return -EINVAL; /* Note that O_DIRECTORY|O_NOFOLLOW is implied, but we allow specifying it anyway. The following @@ -1264,7 +1269,7 @@ int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_ } if (FLAGS_SET(xopen_flags, XO_NOCOW)) { - r = chattr_fd(fd, FS_NOCOW_FL, FS_NOCOW_FL, NULL); + r = chattr_fd(fd, FS_NOCOW_FL, FS_NOCOW_FL); if (r < 0 && !ERRNO_IS_NOT_SUPPORTED(r)) goto error; } diff --git a/src/libnm-systemd-shared/src/basic/fs-util.h b/src/libnm-systemd-shared/src/basic/fs-util.h index eb031a0c..b2c01079 100644 --- a/src/libnm-systemd-shared/src/basic/fs-util.h +++ b/src/libnm-systemd-shared/src/basic/fs-util.h @@ -172,3 +172,12 @@ static inline int at_flags_normalize_nofollow(int flags) { flags |= AT_SYMLINK_NOFOLLOW; return flags; } + +static inline int at_flags_normalize_follow(int flags) { + if (FLAGS_SET(flags, AT_SYMLINK_NOFOLLOW)) { + assert(!FLAGS_SET(flags, AT_SYMLINK_FOLLOW)); + flags &= ~AT_SYMLINK_NOFOLLOW; + } else + flags |= AT_SYMLINK_FOLLOW; + return flags; +} diff --git a/src/libnm-systemd-shared/src/basic/glyph-util.c b/src/libnm-systemd-shared/src/basic/glyph-util.c index d38698b6..aedd47c2 100644 --- a/src/libnm-systemd-shared/src/basic/glyph-util.c +++ b/src/libnm-systemd-shared/src/basic/glyph-util.c @@ -25,7 +25,7 @@ bool emoji_enabled(void) { return cached_emoji_enabled; } -const char* special_glyph_full(SpecialGlyph code, bool force_utf) { +const char* glyph_full(Glyph code, bool force_utf) { /* A list of a number of interesting unicode glyphs we can use to decorate our output. It's probably wise to be * conservative here, and primarily stick to the glyphs defined in the eurlatgr font, so that display still @@ -34,133 +34,139 @@ const char* special_glyph_full(SpecialGlyph code, bool force_utf) { * http://git.altlinux.org/people/legion/packages/kbd.git?p=kbd.git;a=blob;f=data/consolefonts/README.eurlatgr */ - static const char* const draw_table[2][_SPECIAL_GLYPH_MAX] = { + static const char* const draw_table[2][_GLYPH_MAX] = { /* ASCII fallback */ [false] = { - [SPECIAL_GLYPH_TREE_VERTICAL] = "| ", - [SPECIAL_GLYPH_TREE_BRANCH] = "|-", - [SPECIAL_GLYPH_TREE_RIGHT] = "`-", - [SPECIAL_GLYPH_TREE_SPACE] = " ", - [SPECIAL_GLYPH_TREE_TOP] = ",-", - [SPECIAL_GLYPH_VERTICAL_DOTTED] = ":", - [SPECIAL_GLYPH_HORIZONTAL_DOTTED] = "-", - [SPECIAL_GLYPH_HORIZONTAL_FAT] = "=", - [SPECIAL_GLYPH_TRIANGULAR_BULLET] = ">", - [SPECIAL_GLYPH_BLACK_CIRCLE] = "*", - [SPECIAL_GLYPH_WHITE_CIRCLE] = "*", - [SPECIAL_GLYPH_MULTIPLICATION_SIGN] = "x", - [SPECIAL_GLYPH_CIRCLE_ARROW] = "*", - [SPECIAL_GLYPH_BULLET] = "*", - [SPECIAL_GLYPH_MU] = "u", - [SPECIAL_GLYPH_CHECK_MARK] = "+", - [SPECIAL_GLYPH_CROSS_MARK] = "-", - [SPECIAL_GLYPH_LIGHT_SHADE] = "-", - [SPECIAL_GLYPH_DARK_SHADE] = "X", - [SPECIAL_GLYPH_FULL_BLOCK] = "#", - [SPECIAL_GLYPH_SIGMA] = "S", - [SPECIAL_GLYPH_ARROW_UP] = "^", - [SPECIAL_GLYPH_ARROW_DOWN] = "v", - [SPECIAL_GLYPH_ARROW_LEFT] = "<-", - [SPECIAL_GLYPH_ARROW_RIGHT] = "->", - [SPECIAL_GLYPH_ELLIPSIS] = "...", - [SPECIAL_GLYPH_EXTERNAL_LINK] = "[LNK]", - [SPECIAL_GLYPH_ECSTATIC_SMILEY] = ":-]", - [SPECIAL_GLYPH_HAPPY_SMILEY] = ":-}", - [SPECIAL_GLYPH_SLIGHTLY_HAPPY_SMILEY] = ":-)", - [SPECIAL_GLYPH_NEUTRAL_SMILEY] = ":-|", - [SPECIAL_GLYPH_SLIGHTLY_UNHAPPY_SMILEY] = ":-(", - [SPECIAL_GLYPH_UNHAPPY_SMILEY] = ":-{", - [SPECIAL_GLYPH_DEPRESSED_SMILEY] = ":-[", - [SPECIAL_GLYPH_LOCK_AND_KEY] = "o-,", - [SPECIAL_GLYPH_TOUCH] = "O=", /* Yeah, not very convincing, can you do it better? */ - [SPECIAL_GLYPH_RECYCLING] = "~", - [SPECIAL_GLYPH_DOWNLOAD] = "\\", - [SPECIAL_GLYPH_SPARKLES] = "*", - [SPECIAL_GLYPH_LOW_BATTERY] = "!", - [SPECIAL_GLYPH_WARNING_SIGN] = "!", - [SPECIAL_GLYPH_RED_CIRCLE] = "o", - [SPECIAL_GLYPH_YELLOW_CIRCLE] = "o", - [SPECIAL_GLYPH_BLUE_CIRCLE] = "o", - [SPECIAL_GLYPH_GREEN_CIRCLE] = "o", - [SPECIAL_GLYPH_SUPERHERO] = "S", - [SPECIAL_GLYPH_IDCARD] = "@", + [GLYPH_SPACE] = " ", + [GLYPH_TREE_VERTICAL] = "| ", + [GLYPH_TREE_BRANCH] = "|-", + [GLYPH_TREE_RIGHT] = "`-", + [GLYPH_TREE_SPACE] = " ", + [GLYPH_TREE_TOP] = ",-", + [GLYPH_VERTICAL_DOTTED] = ":", + [GLYPH_HORIZONTAL_DOTTED] = "-", + [GLYPH_HORIZONTAL_FAT] = "=", + [GLYPH_TRIANGULAR_BULLET] = ">", + [GLYPH_BLACK_CIRCLE] = "*", + [GLYPH_WHITE_CIRCLE] = "*", + [GLYPH_MULTIPLICATION_SIGN] = "x", + [GLYPH_CIRCLE_ARROW] = "*", + [GLYPH_BULLET] = "*", + [GLYPH_MU] = "u", + [GLYPH_CHECK_MARK] = "+", + [GLYPH_CROSS_MARK] = "-", + [GLYPH_LIGHT_SHADE] = "-", + [GLYPH_DARK_SHADE] = "X", + [GLYPH_FULL_BLOCK] = "#", + [GLYPH_SIGMA] = "S", + [GLYPH_ARROW_UP] = "^", + [GLYPH_ARROW_DOWN] = "v", + [GLYPH_ARROW_LEFT] = "<-", + [GLYPH_ARROW_RIGHT] = "->", + [GLYPH_ELLIPSIS] = "...", + [GLYPH_EXTERNAL_LINK] = "[LNK]", + [GLYPH_ECSTATIC_SMILEY] = ":-]", + [GLYPH_HAPPY_SMILEY] = ":-}", + [GLYPH_SLIGHTLY_HAPPY_SMILEY] = ":-)", + [GLYPH_NEUTRAL_SMILEY] = ":-|", + [GLYPH_SLIGHTLY_UNHAPPY_SMILEY] = ":-(", + [GLYPH_UNHAPPY_SMILEY] = ":-{", + [GLYPH_DEPRESSED_SMILEY] = ":-[", + [GLYPH_LOCK_AND_KEY] = "o-,", + [GLYPH_TOUCH] = "O=", /* Yeah, not very convincing, can you do it better? */ + [GLYPH_RECYCLING] = "~", + [GLYPH_DOWNLOAD] = "\\", + [GLYPH_SPARKLES] = "*", + [GLYPH_LOW_BATTERY] = "!", + [GLYPH_WARNING_SIGN] = "!", + [GLYPH_RED_CIRCLE] = "o", + [GLYPH_YELLOW_CIRCLE] = "o", + [GLYPH_BLUE_CIRCLE] = "o", + [GLYPH_GREEN_CIRCLE] = "o", + [GLYPH_SUPERHERO] = "S", + [GLYPH_IDCARD] = "@", + [GLYPH_HOME] = "^", }, /* UTF-8 */ [true] = { + /* This exists to allow more consistent handling of optional whitespace */ + [GLYPH_SPACE] = " ", + /* The following are multiple glyphs in both ASCII and in UNICODE */ - [SPECIAL_GLYPH_TREE_VERTICAL] = u8"│ ", - [SPECIAL_GLYPH_TREE_BRANCH] = u8"├─", - [SPECIAL_GLYPH_TREE_RIGHT] = u8"└─", - [SPECIAL_GLYPH_TREE_SPACE] = u8" ", - [SPECIAL_GLYPH_TREE_TOP] = u8"┌─", + [GLYPH_TREE_VERTICAL] = UTF8("│ "), + [GLYPH_TREE_BRANCH] = UTF8("├─"), + [GLYPH_TREE_RIGHT] = UTF8("└─"), + [GLYPH_TREE_SPACE] = UTF8(" "), + [GLYPH_TREE_TOP] = UTF8("┌─"), /* Single glyphs in both cases */ - [SPECIAL_GLYPH_VERTICAL_DOTTED] = u8"┆", - [SPECIAL_GLYPH_HORIZONTAL_DOTTED] = u8"┄", - [SPECIAL_GLYPH_HORIZONTAL_FAT] = u8"━", - [SPECIAL_GLYPH_TRIANGULAR_BULLET] = u8"‣", - [SPECIAL_GLYPH_BLACK_CIRCLE] = u8"●", - [SPECIAL_GLYPH_WHITE_CIRCLE] = u8"○", - [SPECIAL_GLYPH_MULTIPLICATION_SIGN] = u8"×", - [SPECIAL_GLYPH_CIRCLE_ARROW] = u8"↻", - [SPECIAL_GLYPH_BULLET] = u8"•", - [SPECIAL_GLYPH_MU] = u8"μ", /* actually called: GREEK SMALL LETTER MU */ - [SPECIAL_GLYPH_CHECK_MARK] = u8"✓", - [SPECIAL_GLYPH_CROSS_MARK] = u8"✗", /* actually called: BALLOT X */ - [SPECIAL_GLYPH_LIGHT_SHADE] = u8"░", - [SPECIAL_GLYPH_DARK_SHADE] = u8"▒", - [SPECIAL_GLYPH_FULL_BLOCK] = u8"█", - [SPECIAL_GLYPH_SIGMA] = u8"Σ", - [SPECIAL_GLYPH_ARROW_UP] = u8"↑", /* actually called: UPWARDS ARROW */ - [SPECIAL_GLYPH_ARROW_DOWN] = u8"↓", /* actually called: DOWNWARDS ARROW */ + [GLYPH_VERTICAL_DOTTED] = UTF8("┆"), + [GLYPH_HORIZONTAL_DOTTED] = UTF8("┄"), + [GLYPH_HORIZONTAL_FAT] = UTF8("━"), + [GLYPH_TRIANGULAR_BULLET] = UTF8("‣"), + [GLYPH_BLACK_CIRCLE] = UTF8("●"), + [GLYPH_WHITE_CIRCLE] = UTF8("○"), + [GLYPH_MULTIPLICATION_SIGN] = UTF8("×"), + [GLYPH_CIRCLE_ARROW] = UTF8("↻"), + [GLYPH_BULLET] = UTF8("•"), + [GLYPH_MU] = UTF8("μ"), /* actually called: GREEK SMALL LETTER MU */ + [GLYPH_CHECK_MARK] = UTF8("✓"), + [GLYPH_CROSS_MARK] = UTF8("✗"), /* actually called: BALLOT X */ + [GLYPH_LIGHT_SHADE] = UTF8("░"), + [GLYPH_DARK_SHADE] = UTF8("▒"), + [GLYPH_FULL_BLOCK] = UTF8("█"), + [GLYPH_SIGMA] = UTF8("Σ"), + [GLYPH_ARROW_UP] = UTF8("↑"), /* actually called: UPWARDS ARROW */ + [GLYPH_ARROW_DOWN] = UTF8("↓"), /* actually called: DOWNWARDS ARROW */ /* Single glyph in Unicode, two in ASCII */ - [SPECIAL_GLYPH_ARROW_LEFT] = u8"←", /* actually called: LEFTWARDS ARROW */ - [SPECIAL_GLYPH_ARROW_RIGHT] = u8"→", /* actually called: RIGHTWARDS ARROW */ + [GLYPH_ARROW_LEFT] = UTF8("←"), /* actually called: LEFTWARDS ARROW */ + [GLYPH_ARROW_RIGHT] = UTF8("→"), /* actually called: RIGHTWARDS ARROW */ /* Single glyph in Unicode, three in ASCII */ - [SPECIAL_GLYPH_ELLIPSIS] = u8"…", /* actually called: HORIZONTAL ELLIPSIS */ + [GLYPH_ELLIPSIS] = UTF8("…"), /* actually called: HORIZONTAL ELLIPSIS */ /* Three glyphs in Unicode, five in ASCII */ - [SPECIAL_GLYPH_EXTERNAL_LINK] = u8"[🡕]", /* actually called: NORTH EAST SANS-SERIF ARROW, enclosed in [] */ + [GLYPH_EXTERNAL_LINK] = UTF8("[🡕]"), /* actually called: NORTH EAST SANS-SERIF ARROW, enclosed in [] */ /* These smileys are a single glyph in Unicode, and three in ASCII */ - [SPECIAL_GLYPH_ECSTATIC_SMILEY] = u8"😇", /* actually called: SMILING FACE WITH HALO */ - [SPECIAL_GLYPH_HAPPY_SMILEY] = u8"😀", /* actually called: GRINNING FACE */ - [SPECIAL_GLYPH_SLIGHTLY_HAPPY_SMILEY] = u8"🙂", /* actually called: SLIGHTLY SMILING FACE */ - [SPECIAL_GLYPH_NEUTRAL_SMILEY] = u8"😐", /* actually called: NEUTRAL FACE */ - [SPECIAL_GLYPH_SLIGHTLY_UNHAPPY_SMILEY] = u8"🙁", /* actually called: SLIGHTLY FROWNING FACE */ - [SPECIAL_GLYPH_UNHAPPY_SMILEY] = u8"😨", /* actually called: FEARFUL FACE */ - [SPECIAL_GLYPH_DEPRESSED_SMILEY] = u8"🤢", /* actually called: NAUSEATED FACE */ + [GLYPH_ECSTATIC_SMILEY] = UTF8("😇"), /* actually called: SMILING FACE WITH HALO */ + [GLYPH_HAPPY_SMILEY] = UTF8("😀"), /* actually called: GRINNING FACE */ + [GLYPH_SLIGHTLY_HAPPY_SMILEY] = UTF8("🙂"), /* actually called: SLIGHTLY SMILING FACE */ + [GLYPH_NEUTRAL_SMILEY] = UTF8("😐"), /* actually called: NEUTRAL FACE */ + [GLYPH_SLIGHTLY_UNHAPPY_SMILEY] = UTF8("🙁"), /* actually called: SLIGHTLY FROWNING FACE */ + [GLYPH_UNHAPPY_SMILEY] = UTF8("😨"), /* actually called: FEARFUL FACE */ + [GLYPH_DEPRESSED_SMILEY] = UTF8("🤢"), /* actually called: NAUSEATED FACE */ /* This emoji is a single character cell glyph in Unicode, and three in ASCII */ - [SPECIAL_GLYPH_LOCK_AND_KEY] = u8"🔐", /* actually called: CLOSED LOCK WITH KEY */ + [GLYPH_LOCK_AND_KEY] = UTF8("🔐"), /* actually called: CLOSED LOCK WITH KEY */ /* This emoji is a single character cell glyph in Unicode, and two in ASCII */ - [SPECIAL_GLYPH_TOUCH] = u8"👆", /* actually called: BACKHAND INDEX POINTING UP */ + [GLYPH_TOUCH] = UTF8("👆"), /* actually called: BACKHAND INDEX POINTING UP */ /* These four emojis are single character cell glyphs in Unicode and also in ASCII. */ - [SPECIAL_GLYPH_RECYCLING] = u8"♻️", /* actually called: UNIVERSAL RECYCLNG SYMBOL */ - [SPECIAL_GLYPH_DOWNLOAD] = u8"⤵️", /* actually called: RIGHT ARROW CURVING DOWN */ - [SPECIAL_GLYPH_SPARKLES] = u8"✨", - [SPECIAL_GLYPH_LOW_BATTERY] = u8"🪫", - [SPECIAL_GLYPH_WARNING_SIGN] = u8"⚠️", - [SPECIAL_GLYPH_COMPUTER_DISK] = u8"💽", - [SPECIAL_GLYPH_WORLD] = u8"🌍", - - [SPECIAL_GLYPH_RED_CIRCLE] = u8"🔴", - [SPECIAL_GLYPH_YELLOW_CIRCLE] = u8"🟡", - [SPECIAL_GLYPH_BLUE_CIRCLE] = u8"🔵", - [SPECIAL_GLYPH_GREEN_CIRCLE] = u8"🟢", - [SPECIAL_GLYPH_SUPERHERO] = u8"🦸", - [SPECIAL_GLYPH_IDCARD] = u8"🪪", + [GLYPH_RECYCLING] = UTF8("♻️"), /* actually called: UNIVERSAL RECYCLNG SYMBOL */ + [GLYPH_DOWNLOAD] = UTF8("⤵️"), /* actually called: RIGHT ARROW CURVING DOWN */ + [GLYPH_SPARKLES] = UTF8("✨"), + [GLYPH_LOW_BATTERY] = UTF8("🪫"), + [GLYPH_WARNING_SIGN] = UTF8("⚠️"), + [GLYPH_COMPUTER_DISK] = UTF8("💽"), + [GLYPH_WORLD] = UTF8("🌍"), + + [GLYPH_RED_CIRCLE] = UTF8("🔴"), + [GLYPH_YELLOW_CIRCLE] = UTF8("🟡"), + [GLYPH_BLUE_CIRCLE] = UTF8("🔵"), + [GLYPH_GREEN_CIRCLE] = UTF8("🟢"), + [GLYPH_SUPERHERO] = UTF8("🦸"), + [GLYPH_IDCARD] = UTF8("🪪"), + [GLYPH_HOME] = UTF8("🏠"), }, }; if (code < 0) return NULL; - assert(code < _SPECIAL_GLYPH_MAX); - return draw_table[force_utf || (code >= _SPECIAL_GLYPH_FIRST_EMOJI ? emoji_enabled() : is_locale_utf8())][code]; + assert(code < _GLYPH_MAX); + return draw_table[force_utf || (code >= _GLYPH_FIRST_EMOJI ? emoji_enabled() : is_locale_utf8())][code]; } diff --git a/src/libnm-systemd-shared/src/basic/glyph-util.h b/src/libnm-systemd-shared/src/basic/glyph-util.h index ca4d4eda..730f2695 100644 --- a/src/libnm-systemd-shared/src/basic/glyph-util.h +++ b/src/libnm-systemd-shared/src/basic/glyph-util.h @@ -6,73 +6,79 @@ #include "macro.h" -typedef enum SpecialGlyph { - SPECIAL_GLYPH_TREE_VERTICAL, - SPECIAL_GLYPH_TREE_BRANCH, - SPECIAL_GLYPH_TREE_RIGHT, - SPECIAL_GLYPH_TREE_SPACE, - SPECIAL_GLYPH_TREE_TOP, - SPECIAL_GLYPH_VERTICAL_DOTTED, - SPECIAL_GLYPH_HORIZONTAL_DOTTED, - SPECIAL_GLYPH_HORIZONTAL_FAT, - SPECIAL_GLYPH_TRIANGULAR_BULLET, - SPECIAL_GLYPH_BLACK_CIRCLE, - SPECIAL_GLYPH_WHITE_CIRCLE, - SPECIAL_GLYPH_MULTIPLICATION_SIGN, - SPECIAL_GLYPH_CIRCLE_ARROW, - SPECIAL_GLYPH_BULLET, - SPECIAL_GLYPH_MU, - SPECIAL_GLYPH_CHECK_MARK, - SPECIAL_GLYPH_CROSS_MARK, - SPECIAL_GLYPH_LIGHT_SHADE, - SPECIAL_GLYPH_DARK_SHADE, - SPECIAL_GLYPH_FULL_BLOCK, - SPECIAL_GLYPH_SIGMA, - SPECIAL_GLYPH_ARROW_UP, - SPECIAL_GLYPH_ARROW_DOWN, - SPECIAL_GLYPH_ARROW_LEFT, - SPECIAL_GLYPH_ARROW_RIGHT, - SPECIAL_GLYPH_ELLIPSIS, - SPECIAL_GLYPH_EXTERNAL_LINK, - _SPECIAL_GLYPH_FIRST_EMOJI, - SPECIAL_GLYPH_ECSTATIC_SMILEY = _SPECIAL_GLYPH_FIRST_EMOJI, - SPECIAL_GLYPH_HAPPY_SMILEY, - SPECIAL_GLYPH_SLIGHTLY_HAPPY_SMILEY, - SPECIAL_GLYPH_NEUTRAL_SMILEY, - SPECIAL_GLYPH_SLIGHTLY_UNHAPPY_SMILEY, - SPECIAL_GLYPH_UNHAPPY_SMILEY, - SPECIAL_GLYPH_DEPRESSED_SMILEY, - SPECIAL_GLYPH_LOCK_AND_KEY, - SPECIAL_GLYPH_TOUCH, - SPECIAL_GLYPH_RECYCLING, - SPECIAL_GLYPH_DOWNLOAD, - SPECIAL_GLYPH_SPARKLES, - SPECIAL_GLYPH_LOW_BATTERY, - SPECIAL_GLYPH_WARNING_SIGN, - SPECIAL_GLYPH_COMPUTER_DISK, - SPECIAL_GLYPH_WORLD, - SPECIAL_GLYPH_RED_CIRCLE, - SPECIAL_GLYPH_YELLOW_CIRCLE, - SPECIAL_GLYPH_BLUE_CIRCLE, - SPECIAL_GLYPH_GREEN_CIRCLE, - SPECIAL_GLYPH_SUPERHERO, - SPECIAL_GLYPH_IDCARD, - _SPECIAL_GLYPH_MAX, - _SPECIAL_GLYPH_INVALID = -EINVAL, -} SpecialGlyph; +typedef enum Glyph { + GLYPH_SPACE, + GLYPH_TREE_VERTICAL, + GLYPH_TREE_BRANCH, + GLYPH_TREE_RIGHT, + GLYPH_TREE_SPACE, + GLYPH_TREE_TOP, + GLYPH_VERTICAL_DOTTED, + GLYPH_HORIZONTAL_DOTTED, + GLYPH_HORIZONTAL_FAT, + GLYPH_TRIANGULAR_BULLET, + GLYPH_BLACK_CIRCLE, + GLYPH_WHITE_CIRCLE, + GLYPH_MULTIPLICATION_SIGN, + GLYPH_CIRCLE_ARROW, + GLYPH_BULLET, + GLYPH_MU, + GLYPH_CHECK_MARK, + GLYPH_CROSS_MARK, + GLYPH_LIGHT_SHADE, + GLYPH_DARK_SHADE, + GLYPH_FULL_BLOCK, + GLYPH_SIGMA, + GLYPH_ARROW_UP, + GLYPH_ARROW_DOWN, + GLYPH_ARROW_LEFT, + GLYPH_ARROW_RIGHT, + GLYPH_ELLIPSIS, + GLYPH_EXTERNAL_LINK, + _GLYPH_FIRST_EMOJI, + GLYPH_ECSTATIC_SMILEY = _GLYPH_FIRST_EMOJI, + GLYPH_HAPPY_SMILEY, + GLYPH_SLIGHTLY_HAPPY_SMILEY, + GLYPH_NEUTRAL_SMILEY, + GLYPH_SLIGHTLY_UNHAPPY_SMILEY, + GLYPH_UNHAPPY_SMILEY, + GLYPH_DEPRESSED_SMILEY, + GLYPH_LOCK_AND_KEY, + GLYPH_TOUCH, + GLYPH_RECYCLING, + GLYPH_DOWNLOAD, + GLYPH_SPARKLES, + GLYPH_LOW_BATTERY, + GLYPH_WARNING_SIGN, + GLYPH_COMPUTER_DISK, + GLYPH_WORLD, + GLYPH_RED_CIRCLE, + GLYPH_YELLOW_CIRCLE, + GLYPH_BLUE_CIRCLE, + GLYPH_GREEN_CIRCLE, + GLYPH_SUPERHERO, + GLYPH_IDCARD, + GLYPH_HOME, + _GLYPH_MAX, + _GLYPH_INVALID = -EINVAL, +} Glyph; bool emoji_enabled(void); -const char* special_glyph_full(SpecialGlyph code, bool force_utf) _const_; +const char* glyph_full(Glyph code, bool force_utf) _const_; -static inline const char* special_glyph(SpecialGlyph code) { - return special_glyph_full(code, false); +static inline const char* glyph(Glyph code) { + return glyph_full(code, false); } -static inline const char* special_glyph_check_mark(bool b) { - return b ? special_glyph(SPECIAL_GLYPH_CHECK_MARK) : special_glyph(SPECIAL_GLYPH_CROSS_MARK); +static inline const char* optional_glyph(Glyph code) { + return emoji_enabled() ? glyph(code) : ""; } -static inline const char* special_glyph_check_mark_space(bool b) { - return b ? special_glyph(SPECIAL_GLYPH_CHECK_MARK) : " "; +static inline const char* glyph_check_mark(bool b) { + return b ? glyph(GLYPH_CHECK_MARK) : glyph(GLYPH_CROSS_MARK); +} + +static inline const char* glyph_check_mark_space(bool b) { + return b ? glyph(GLYPH_CHECK_MARK) : " "; } diff --git a/src/libnm-systemd-shared/src/basic/hash-funcs.c b/src/libnm-systemd-shared/src/basic/hash-funcs.c index d20ca3c3..b1975cfe 100644 --- a/src/libnm-systemd-shared/src/basic/hash-funcs.c +++ b/src/libnm-systemd-shared/src/basic/hash-funcs.c @@ -12,15 +12,23 @@ void string_hash_func(const char *p, struct siphash *state) { siphash24_compress(p, strlen(p) + 1, state); } -DEFINE_HASH_OPS(string_hash_ops, char, string_hash_func, string_compare_func); -DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(string_hash_ops_free, - char, string_hash_func, string_compare_func, free); -DEFINE_HASH_OPS_FULL(string_hash_ops_free_free, - char, string_hash_func, string_compare_func, free, - void, free); -DEFINE_HASH_OPS_FULL(string_hash_ops_free_strv_free, - char, string_hash_func, string_compare_func, free, - char*, strv_free); +DEFINE_HASH_OPS(string_hash_ops, + char, string_hash_func, string_compare_func); +DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR( + string_hash_ops_free, + char, string_hash_func, string_compare_func, free); +DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR( + string_hash_ops_value_free, + char, string_hash_func, string_compare_func, + void, free); +DEFINE_HASH_OPS_FULL( + string_hash_ops_free_free, + char, string_hash_func, string_compare_func, free, + void, free); +DEFINE_HASH_OPS_FULL( + string_hash_ops_free_strv_free, + char, string_hash_func, string_compare_func, free, + char*, strv_free); void path_hash_func(const char *q, struct siphash *state) { bool add_slash = false; @@ -61,12 +69,15 @@ void path_hash_func(const char *q, struct siphash *state) { } } -DEFINE_HASH_OPS(path_hash_ops, char, path_hash_func, path_compare); -DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(path_hash_ops_free, - char, path_hash_func, path_compare, free); -DEFINE_HASH_OPS_FULL(path_hash_ops_free_free, - char, path_hash_func, path_compare, free, - void, free); +DEFINE_HASH_OPS(path_hash_ops, + char, path_hash_func, path_compare); +DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR( + path_hash_ops_free, + char, path_hash_func, path_compare, free); +DEFINE_HASH_OPS_FULL( + path_hash_ops_free_free, + char, path_hash_func, path_compare, free, + void, free); void trivial_hash_func(const void *p, struct siphash *state) { siphash24_compress_typesafe(p, state); @@ -76,23 +87,19 @@ int trivial_compare_func(const void *a, const void *b) { return CMP(a, b); } -const struct hash_ops trivial_hash_ops = { - .hash = trivial_hash_func, - .compare = trivial_compare_func, -}; - -const struct hash_ops trivial_hash_ops_free = { - .hash = trivial_hash_func, - .compare = trivial_compare_func, - .free_key = free, -}; - -const struct hash_ops trivial_hash_ops_free_free = { - .hash = trivial_hash_func, - .compare = trivial_compare_func, - .free_key = free, - .free_value = free, -}; +DEFINE_HASH_OPS(trivial_hash_ops, + void, trivial_hash_func, trivial_compare_func); +DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR( + trivial_hash_ops_free, + void, trivial_hash_func, trivial_compare_func, free); +DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR( + trivial_hash_ops_value_free, + void, trivial_hash_func, trivial_compare_func, + void, free); +DEFINE_HASH_OPS_FULL( + trivial_hash_ops_free_free, + void, trivial_hash_func, trivial_compare_func, free, + void, free); void uint64_hash_func(const uint64_t *p, struct siphash *state) { siphash24_compress_typesafe(*p, state); @@ -102,7 +109,12 @@ int uint64_compare_func(const uint64_t *a, const uint64_t *b) { return CMP(*a, *b); } -DEFINE_HASH_OPS(uint64_hash_ops, uint64_t, uint64_hash_func, uint64_compare_func); +DEFINE_HASH_OPS(uint64_hash_ops, + uint64_t, uint64_hash_func, uint64_compare_func); +DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR( + uint64_hash_ops_value_free, + uint64_t, uint64_hash_func, uint64_compare_func, + void, free); #if 0 /* NM_IGNORED */ #if SIZEOF_DEV_T != 8 diff --git a/src/libnm-systemd-shared/src/basic/hash-funcs.h b/src/libnm-systemd-shared/src/basic/hash-funcs.h index 3804e94d..d0736807 100644 --- a/src/libnm-systemd-shared/src/basic/hash-funcs.h +++ b/src/libnm-systemd-shared/src/basic/hash-funcs.h @@ -77,6 +77,7 @@ void string_hash_func(const char *p, struct siphash *state); #define string_compare_func strcmp extern const struct hash_ops string_hash_ops; extern const struct hash_ops string_hash_ops_free; +extern const struct hash_ops string_hash_ops_value_free; extern const struct hash_ops string_hash_ops_free_free; extern const struct hash_ops string_hash_ops_free_strv_free; @@ -91,6 +92,7 @@ void trivial_hash_func(const void *p, struct siphash *state); int trivial_compare_func(const void *a, const void *b) _const_; extern const struct hash_ops trivial_hash_ops; extern const struct hash_ops trivial_hash_ops_free; +extern const struct hash_ops trivial_hash_ops_value_free; extern const struct hash_ops trivial_hash_ops_free_free; /* 32-bit values we can always just embed in the pointer itself, but in order to support 32-bit archs we need store 64-bit @@ -98,6 +100,7 @@ extern const struct hash_ops trivial_hash_ops_free_free; void uint64_hash_func(const uint64_t *p, struct siphash *state); int uint64_compare_func(const uint64_t *a, const uint64_t *b) _pure_; extern const struct hash_ops uint64_hash_ops; +extern const struct hash_ops uint64_hash_ops_value_free; /* On some archs dev_t is 32-bit, and on others 64-bit. And sometimes it's 64-bit on 32-bit archs, and sometimes 32-bit on * 64-bit archs. Yuck! */ diff --git a/src/libnm-systemd-shared/src/basic/hashmap.c b/src/libnm-systemd-shared/src/basic/hashmap.c index 6b0247c3..e58375c9 100644 --- a/src/libnm-systemd-shared/src/basic/hashmap.c +++ b/src/libnm-systemd-shared/src/basic/hashmap.c @@ -14,6 +14,7 @@ #include "alloc-util.h" #include "fileio.h" #include "hashmap.h" +#include "log.h" #include "logarithm.h" #include "macro.h" #include "memory-util.h" @@ -916,24 +917,20 @@ static void hashmap_free_no_clear(HashmapBase *h) { free(h); } -HashmapBase* _hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) { +HashmapBase* _hashmap_free(HashmapBase *h) { if (h) { - _hashmap_clear(h, default_free_key, default_free_value); + _hashmap_clear(h); hashmap_free_no_clear(h); } return NULL; } -void _hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) { - free_func_t free_key, free_value; +void _hashmap_clear(HashmapBase *h) { if (!h) return; - free_key = h->hash_ops->free_key ?: default_free_key; - free_value = h->hash_ops->free_value ?: default_free_value; - - if (free_key || free_value) { + if (h->hash_ops->free_key || h->hash_ops->free_value) { /* If destructor calls are defined, let's destroy things defensively: let's take the item out of the * hash table, and only then call the destructor functions. If these destructors then try to unregister @@ -945,11 +942,11 @@ void _hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t de v = _hashmap_first_key_and_value(h, true, &k); - if (free_key) - free_key(k); + if (h->hash_ops->free_key) + h->hash_ops->free_key(k); - if (free_value) - free_value(v); + if (h->hash_ops->free_value) + h->hash_ops->free_value(v); } } @@ -1784,7 +1781,7 @@ HashmapBase* _hashmap_copy(HashmapBase *h HASHMAP_DEBUG_PARAMS) { } if (r < 0) - return _hashmap_free(copy, NULL, NULL); + return _hashmap_free(copy); return copy; } @@ -1809,6 +1806,23 @@ char** _hashmap_get_strv(HashmapBase *h) { return sv; } +char** set_to_strv(Set **s) { + assert(s); + + /* This is similar to set_get_strv(), but invalidates the set on success. */ + + char **v = new(char*, set_size(*s) + 1); + if (!v) + return NULL; + + for (char **p = v; (*p = set_steal_first(*s)); p++) + ; + + assert(set_isempty(*s)); + *s = set_free(*s); + return v; +} + void* ordered_hashmap_next(OrderedHashmap *h, const void *key) { struct ordered_hashmap_entry *e; unsigned hash, idx; diff --git a/src/libnm-systemd-shared/src/basic/hashmap.h b/src/libnm-systemd-shared/src/basic/hashmap.h index 01a4fb32..8ced7e6a 100644 --- a/src/libnm-systemd-shared/src/basic/hashmap.h +++ b/src/libnm-systemd-shared/src/basic/hashmap.h @@ -88,36 +88,17 @@ OrderedHashmap* _ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DE #define hashmap_new(ops) _hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS) #define ordered_hashmap_new(ops) _ordered_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS) -#define hashmap_free_and_replace(a, b) \ +#define hashmap_free_and_replace(a, b) \ free_and_replace_full(a, b, hashmap_free) +#define ordered_hashmap_free_and_replace(a, b) \ + free_and_replace_full(a, b, ordered_hashmap_free) -HashmapBase* _hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value); +HashmapBase* _hashmap_free(HashmapBase *h); static inline Hashmap* hashmap_free(Hashmap *h) { - return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, NULL); + return (void*) _hashmap_free(HASHMAP_BASE(h)); } static inline OrderedHashmap* ordered_hashmap_free(OrderedHashmap *h) { - return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, NULL); -} - -static inline Hashmap* hashmap_free_free(Hashmap *h) { - return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, free); -} -static inline OrderedHashmap* ordered_hashmap_free_free(OrderedHashmap *h) { - return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, free); -} - -static inline Hashmap* hashmap_free_free_key(Hashmap *h) { - return (void*) _hashmap_free(HASHMAP_BASE(h), free, NULL); -} -static inline OrderedHashmap* ordered_hashmap_free_free_key(OrderedHashmap *h) { - return (void*) _hashmap_free(HASHMAP_BASE(h), free, NULL); -} - -static inline Hashmap* hashmap_free_free_free(Hashmap *h) { - return (void*) _hashmap_free(HASHMAP_BASE(h), free, free); -} -static inline OrderedHashmap* ordered_hashmap_free_free_free(OrderedHashmap *h) { - return (void*) _hashmap_free(HASHMAP_BASE(h), free, free); + return (void*) _hashmap_free(HASHMAP_BASE(h)); } IteratedCache* iterated_cache_free(IteratedCache *cache); @@ -285,33 +266,12 @@ static inline bool ordered_hashmap_iterate(OrderedHashmap *h, Iterator *i, void return _hashmap_iterate(HASHMAP_BASE(h), i, value, key); } -void _hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value); +void _hashmap_clear(HashmapBase *h); static inline void hashmap_clear(Hashmap *h) { - _hashmap_clear(HASHMAP_BASE(h), NULL, NULL); + _hashmap_clear(HASHMAP_BASE(h)); } static inline void ordered_hashmap_clear(OrderedHashmap *h) { - _hashmap_clear(HASHMAP_BASE(h), NULL, NULL); -} - -static inline void hashmap_clear_free(Hashmap *h) { - _hashmap_clear(HASHMAP_BASE(h), NULL, free); -} -static inline void ordered_hashmap_clear_free(OrderedHashmap *h) { - _hashmap_clear(HASHMAP_BASE(h), NULL, free); -} - -static inline void hashmap_clear_free_key(Hashmap *h) { - _hashmap_clear(HASHMAP_BASE(h), free, NULL); -} -static inline void ordered_hashmap_clear_free_key(OrderedHashmap *h) { - _hashmap_clear(HASHMAP_BASE(h), free, NULL); -} - -static inline void hashmap_clear_free_free(Hashmap *h) { - _hashmap_clear(HASHMAP_BASE(h), free, free); -} -static inline void ordered_hashmap_clear_free_free(OrderedHashmap *h) { - _hashmap_clear(HASHMAP_BASE(h), free, free); + _hashmap_clear(HASHMAP_BASE(h)); } /* @@ -371,27 +331,6 @@ static inline void *ordered_hashmap_first_key(OrderedHashmap *h) { return _hashmap_first_key(HASHMAP_BASE(h), false); } -#define hashmap_clear_with_destructor(h, f) \ - ({ \ - Hashmap *_h = (h); \ - void *_item; \ - while ((_item = hashmap_steal_first(_h))) \ - f(_item); \ - _h; \ - }) -#define hashmap_free_with_destructor(h, f) \ - hashmap_free(hashmap_clear_with_destructor(h, f)) -#define ordered_hashmap_clear_with_destructor(h, f) \ - ({ \ - OrderedHashmap *_h = (h); \ - void *_item; \ - while ((_item = ordered_hashmap_steal_first(_h))) \ - f(_item); \ - _h; \ - }) -#define ordered_hashmap_free_with_destructor(h, f) \ - ordered_hashmap_free(ordered_hashmap_clear_with_destructor(h, f)) - /* no hashmap_next */ void* ordered_hashmap_next(OrderedHashmap *h, const void *key); @@ -459,20 +398,10 @@ static inline int ordered_hashmap_dump_keys_sorted(OrderedHashmap *h, void ***re _ORDERED_HASHMAP_FOREACH_KEY(e, k, h, UNIQ_T(i, UNIQ)) DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_key); -DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_free); DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_key); -DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_free); #define _cleanup_hashmap_free_ _cleanup_(hashmap_freep) -#define _cleanup_hashmap_free_free_ _cleanup_(hashmap_free_freep) -#define _cleanup_hashmap_free_free_free_ _cleanup_(hashmap_free_free_freep) #define _cleanup_ordered_hashmap_free_ _cleanup_(ordered_hashmap_freep) -#define _cleanup_ordered_hashmap_free_free_ _cleanup_(ordered_hashmap_free_freep) -#define _cleanup_ordered_hashmap_free_free_free_ _cleanup_(ordered_hashmap_free_free_freep) DEFINE_TRIVIAL_CLEANUP_FUNC(IteratedCache*, iterated_cache_free); diff --git a/src/libnm-systemd-shared/src/basic/hexdecoct.h b/src/libnm-systemd-shared/src/basic/hexdecoct.h index d160ca28..b456200e 100644 --- a/src/libnm-systemd-shared/src/basic/hexdecoct.h +++ b/src/libnm-systemd-shared/src/basic/hexdecoct.h @@ -17,8 +17,8 @@ int undecchar(char c) _const_; char hexchar(int x) _const_; int unhexchar(char c) _const_; -char* hexmem(const void *p, size_t l); -int unhexmem_full(const char *p, size_t l, bool secure, void **ret_data, size_t *ret_size); +char* hexmem(const void *p, size_t l) _nonnull_if_nonzero_(1, 2); +int unhexmem_full(const char *p, size_t l, bool secure, void **ret_data, size_t *ret_size) _nonnull_if_nonzero_(1, 2); static inline int unhexmem(const char *p, void **ret_data, size_t *ret_size) { return unhexmem_full(p, SIZE_MAX, false, ret_data, ret_size); } @@ -30,10 +30,10 @@ char base64char(int x) _const_; char urlsafe_base64char(int x) _const_; int unbase64char(char c) _const_; -char* base32hexmem(const void *p, size_t l, bool padding); -int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *len); +char* base32hexmem(const void *p, size_t l, bool padding) _nonnull_if_nonzero_(1, 2); +int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *len) _nonnull_if_nonzero_(1, 2); -ssize_t base64mem_full(const void *p, size_t l, size_t line_break, char **ret); +ssize_t base64mem_full(const void *p, size_t l, size_t line_break, char **ret) _nonnull_if_nonzero_(1, 2); static inline ssize_t base64mem(const void *p, size_t l, char **ret) { return base64mem_full(p, l, SIZE_MAX, ret); } @@ -45,9 +45,9 @@ ssize_t base64_append( size_t l, size_t margin, size_t width); -int unbase64mem_full(const char *p, size_t l, bool secure, void **ret_data, size_t *ret_size); +int unbase64mem_full(const char *p, size_t l, bool secure, void **ret_data, size_t *ret_size) _nonnull_if_nonzero_(1, 2); static inline int unbase64mem(const char *p, void **ret_data, size_t *ret_size) { return unbase64mem_full(p, SIZE_MAX, false, ret_data, ret_size); } -void hexdump(FILE *f, const void *p, size_t s); +void hexdump(FILE *f, const void *p, size_t s) _nonnull_if_nonzero_(2, 3); diff --git a/src/libnm-systemd-shared/src/basic/hostname-util.c b/src/libnm-systemd-shared/src/basic/hostname-util.c index 26e196f3..eed3bf0a 100644 --- a/src/libnm-systemd-shared/src/basic/hostname-util.c +++ b/src/libnm-systemd-shared/src/basic/hostname-util.c @@ -12,18 +12,22 @@ #include "alloc-util.h" #include "env-file.h" #include "hostname-util.h" +#include "log.h" #include "os-util.h" #include "string-util.h" #include "strv.h" #if 0 /* NM_IGNORED */ -char* get_default_hostname(void) { +char* get_default_hostname_raw(void) { int r; + /* Returns the default hostname, and leaves any ??? in place. */ + const char *e = secure_getenv("SYSTEMD_DEFAULT_HOSTNAME"); if (e) { - if (hostname_is_valid(e, 0)) + if (hostname_is_valid(e, VALID_HOSTNAME_QUESTION_MARK)) return strdup(e); + log_debug("Invalid hostname in $SYSTEMD_DEFAULT_HOSTNAME, ignoring: %s", e); } @@ -32,48 +36,14 @@ char* get_default_hostname(void) { if (r < 0) log_debug_errno(r, "Failed to parse os-release, ignoring: %m"); else if (f) { - if (hostname_is_valid(f, 0)) + if (hostname_is_valid(f, VALID_HOSTNAME_QUESTION_MARK)) return TAKE_PTR(f); + log_debug("Invalid hostname in os-release, ignoring: %s", f); } return strdup(FALLBACK_HOSTNAME); } - -int gethostname_full(GetHostnameFlags flags, char **ret) { - _cleanup_free_ char *buf = NULL, *fallback = NULL; - struct utsname u; - const char *s; - - assert(ret); - - assert_se(uname(&u) >= 0); - - s = u.nodename; - if (isempty(s) || streq(s, "(none)") || - (!FLAGS_SET(flags, GET_HOSTNAME_ALLOW_LOCALHOST) && is_localhost(s)) || - (FLAGS_SET(flags, GET_HOSTNAME_SHORT) && s[0] == '.')) { - if (!FLAGS_SET(flags, GET_HOSTNAME_FALLBACK_DEFAULT)) - return -ENXIO; - - s = fallback = get_default_hostname(); - if (!s) - return -ENOMEM; - - if (FLAGS_SET(flags, GET_HOSTNAME_SHORT) && s[0] == '.') - return -ENXIO; - } - - if (FLAGS_SET(flags, GET_HOSTNAME_SHORT)) - buf = strdupcspn(s, "."); - else - buf = strdup(s); - if (!buf) - return -ENOMEM; - - *ret = TAKE_PTR(buf); - return 0; -} #endif /* NM_IGNORED */ bool valid_ldh_char(char c) { @@ -120,7 +90,7 @@ bool hostname_is_valid(const char *s, ValidHostnameFlags flags) { hyphen = true; } else { - if (!valid_ldh_char(*p)) + if (!valid_ldh_char(*p) && (*p != '?' || !FLAGS_SET(flags, VALID_HOSTNAME_QUESTION_MARK))) return false; dot = false; @@ -163,7 +133,7 @@ char* hostname_cleanup(char *s) { dot = false; hyphen = true; - } else if (valid_ldh_char(*p)) { + } else if (valid_ldh_char(*p) || *p == '?') { *(d++) = *p; dot = false; hyphen = false; diff --git a/src/libnm-systemd-shared/src/basic/hostname-util.h b/src/libnm-systemd-shared/src/basic/hostname-util.h index bcac3d9f..4c5abe76 100644 --- a/src/libnm-systemd-shared/src/basic/hostname-util.h +++ b/src/libnm-systemd-shared/src/basic/hostname-util.h @@ -7,42 +7,14 @@ #include "macro.h" #include "strv.h" -typedef enum GetHostnameFlags { - GET_HOSTNAME_ALLOW_LOCALHOST = 1 << 0, /* accepts "localhost" or friends. */ - GET_HOSTNAME_FALLBACK_DEFAULT = 1 << 1, /* use default hostname if no hostname is set. */ - GET_HOSTNAME_SHORT = 1 << 2, /* kills the FQDN part if present. */ -} GetHostnameFlags; - -int gethostname_full(GetHostnameFlags flags, char **ret); -static inline int gethostname_strict(char **ret) { - return gethostname_full(0, ret); -} - -static inline char* gethostname_malloc(void) { - char *s; - - if (gethostname_full(GET_HOSTNAME_ALLOW_LOCALHOST | GET_HOSTNAME_FALLBACK_DEFAULT, &s) < 0) - return NULL; - - return s; -} - -static inline char* gethostname_short_malloc(void) { - char *s; - - if (gethostname_full(GET_HOSTNAME_ALLOW_LOCALHOST | GET_HOSTNAME_FALLBACK_DEFAULT | GET_HOSTNAME_SHORT, &s) < 0) - return NULL; - - return s; -} - -char* get_default_hostname(void); +char* get_default_hostname_raw(void); bool valid_ldh_char(char c) _const_; typedef enum ValidHostnameFlags { - VALID_HOSTNAME_TRAILING_DOT = 1 << 0, /* Accept trailing dot on multi-label names */ - VALID_HOSTNAME_DOT_HOST = 1 << 1, /* Accept ".host" as valid hostname */ + VALID_HOSTNAME_TRAILING_DOT = 1 << 0, /* Accept trailing dot on multi-label names */ + VALID_HOSTNAME_DOT_HOST = 1 << 1, /* Accept ".host" as valid hostname */ + VALID_HOSTNAME_QUESTION_MARK = 1 << 2, /* Accept "?" as place holder for hashed machine ID value */ } ValidHostnameFlags; bool hostname_is_valid(const char *s, ValidHostnameFlags flags) _pure_; diff --git a/src/libnm-systemd-shared/src/basic/in-addr-util.c b/src/libnm-systemd-shared/src/basic/in-addr-util.c index 44445f1e..b7a64b18 100644 --- a/src/libnm-systemd-shared/src/basic/in-addr-util.c +++ b/src/libnm-systemd-shared/src/basic/in-addr-util.c @@ -15,6 +15,7 @@ #include "in-addr-util.h" #include "logarithm.h" #include "macro.h" +#include "memory-util.h" #include "parse-util.h" #include "random-util.h" #include "stdio-util.h" @@ -30,7 +31,7 @@ bool in4_addr_is_null(const struct in_addr *a) { bool in6_addr_is_null(const struct in6_addr *a) { assert(a); - return IN6_IS_ADDR_UNSPECIFIED(a); + return eqzero(a->s6_addr32); } int in_addr_is_null(int family, const union in_addr_union *u) { @@ -68,7 +69,7 @@ bool in4_addr_is_link_local_dynamic(const struct in_addr *a) { bool in6_addr_is_link_local(const struct in6_addr *a) { assert(a); - return IN6_IS_ADDR_LINKLOCAL(a); + return (a->s6_addr32[0] & htobe32(0xffc00000)) == htobe32(0xfe800000); } int in_addr_is_link_local(int family, const union in_addr_union *u) { @@ -102,7 +103,7 @@ bool in4_addr_is_multicast(const struct in_addr *a) { bool in6_addr_is_multicast(const struct in6_addr *a) { assert(a); - return IN6_IS_ADDR_MULTICAST(a); + return a->s6_addr[0] == 0xff; } int in_addr_is_multicast(int family, const union in_addr_union *u) { @@ -138,6 +139,10 @@ bool in4_addr_is_non_local(const struct in_addr *a) { !in4_addr_is_localhost(a); } +static bool in6_addr_is_loopback(const struct in6_addr *a) { + return memcmp(a, &(struct in6_addr) IN6ADDR_LOOPBACK_INIT, sizeof(struct in6_addr)) == 0; +} + int in_addr_is_localhost(int family, const union in_addr_union *u) { assert(u); @@ -145,7 +150,7 @@ int in_addr_is_localhost(int family, const union in_addr_union *u) { return in4_addr_is_localhost(&u->in); if (family == AF_INET6) - return IN6_IS_ADDR_LOOPBACK(&u->in6); + return in6_addr_is_loopback(&u->in6); return -EAFNOSUPPORT; } @@ -158,7 +163,7 @@ int in_addr_is_localhost_one(int family, const union in_addr_union *u) { return be32toh(u->in.s_addr) == UINT32_C(0x7F000001); if (family == AF_INET6) - return IN6_IS_ADDR_LOOPBACK(&u->in6); + return in6_addr_is_loopback(&u->in6); return -EAFNOSUPPORT; } @@ -180,7 +185,7 @@ bool in6_addr_equal(const struct in6_addr *a, const struct in6_addr *b) { assert(a); assert(b); - return IN6_ARE_ADDR_EQUAL(a, b); + return memcmp(a, b, sizeof(struct in6_addr)) == 0; } int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b) { @@ -951,7 +956,6 @@ int in_addr_prefix_from_string_auto_full( *ret_prefixlen = k; return 0; - } void in_addr_hash_func(const union in_addr_union *u, int family, struct siphash *state) { diff --git a/src/libnm-systemd-shared/src/basic/include/net/if.h b/src/libnm-systemd-shared/src/basic/include/net/if.h new file mode 100644 index 00000000..7d5b61ba --- /dev/null +++ b/src/libnm-systemd-shared/src/basic/include/net/if.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include <linux/if.h> + +#define IF_NAMESIZE 16 + +extern unsigned int if_nametoindex(const char *__ifname) __THROW; +extern char *if_indextoname(unsigned int __ifindex, char __ifname[IF_NAMESIZE]) __THROW; diff --git a/src/libnm-systemd-shared/src/basic/include/netinet/in.h b/src/libnm-systemd-shared/src/basic/include/netinet/in.h new file mode 100644 index 00000000..97475ac8 --- /dev/null +++ b/src/libnm-systemd-shared/src/basic/include/netinet/in.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include <linux/in.h> +#include <linux/in6.h> +#include <linux/ipv6.h> +#include <stddef.h> +#include <stdint.h> +#include <sys/socket.h> + +#define INET_ADDRSTRLEN 16 +#define INET6_ADDRSTRLEN 46 + +extern const struct in6_addr in6addr_any; /* :: */ +extern const struct in6_addr in6addr_loopback; /* ::1 */ +#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } } +#define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } + +typedef uint32_t in_addr_t; diff --git a/src/libnm-systemd-shared/src/basic/io-util.c b/src/libnm-systemd-shared/src/basic/io-util.c index abe61ed5..706535a1 100644 --- a/src/libnm-systemd-shared/src/basic/io-util.c +++ b/src/libnm-systemd-shared/src/basic/io-util.c @@ -90,6 +90,7 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { return n; assert((size_t) k <= nbytes); + assert(k <= SSIZE_MAX - n); p += k; nbytes -= k; @@ -194,7 +195,7 @@ int pipe_eof(int fd) { } #endif /* NM_IGNORED */ -int ppoll_usec(struct pollfd *fds, size_t nfds, usec_t timeout) { +int ppoll_usec_full(struct pollfd *fds, size_t nfds, usec_t timeout, const sigset_t *ss) { int r; assert(fds || nfds == 0); @@ -214,10 +215,10 @@ int ppoll_usec(struct pollfd *fds, size_t nfds, usec_t timeout) { * to handle signals, such as signalfd() or signal handlers. ⚠️ ⚠️ ⚠️ */ - if (nfds == 0) + if (nfds == 0 && timeout == 0) return 0; - r = ppoll(fds, nfds, timeout == USEC_INFINITY ? NULL : TIMESPEC_STORE(timeout), NULL); + r = ppoll(fds, nfds, timeout == USEC_INFINITY ? NULL : TIMESPEC_STORE(timeout), ss); if (r < 0) return -errno; if (r == 0) diff --git a/src/libnm-systemd-shared/src/basic/io-util.h b/src/libnm-systemd-shared/src/basic/io-util.h index e027c1a8..208e1683 100644 --- a/src/libnm-systemd-shared/src/basic/io-util.h +++ b/src/libnm-systemd-shared/src/basic/io-util.h @@ -15,14 +15,18 @@ int flush_fd(int fd); ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll); int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll); -int loop_write_full(int fd, const void *buf, size_t nbytes, usec_t timeout); +int loop_write_full(int fd, const void *buf, size_t nbytes, usec_t timeout) _nonnull_if_nonzero_(2, 3); static inline int loop_write(int fd, const void *buf, size_t nbytes) { return loop_write_full(fd, buf, nbytes, 0); } int pipe_eof(int fd); -int ppoll_usec(struct pollfd *fds, size_t nfds, usec_t timeout); +int ppoll_usec_full(struct pollfd *fds, size_t nfds, usec_t timeout, const sigset_t *ss) _nonnull_if_nonzero_(1, 2); +_nonnull_if_nonzero_(1, 2) static inline int ppoll_usec(struct pollfd *fds, size_t nfds, usec_t timeout) { + return ppoll_usec_full(fds, nfds, timeout, NULL); +} + int fd_wait_for_event(int fd, int event, usec_t timeout); ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length); @@ -42,5 +46,4 @@ static inline bool FILE_SIZE_VALID_OR_INFINITY(uint64_t l) { return true; return FILE_SIZE_VALID(l); - } diff --git a/src/libnm-systemd-shared/src/basic/iovec-util.h b/src/libnm-systemd-shared/src/basic/iovec-util.h index 86845404..ace20098 100644 --- a/src/libnm-systemd-shared/src/basic/iovec-util.h +++ b/src/libnm-systemd-shared/src/basic/iovec-util.h @@ -12,9 +12,9 @@ extern const struct iovec iovec_nul_byte; /* Points to a single NUL byte */ extern const struct iovec iovec_empty; /* Points to an empty, but valid (i.e. non-NULL) pointer */ -size_t iovec_total_size(const struct iovec *iovec, size_t n); +size_t iovec_total_size(const struct iovec *iovec, size_t n) _nonnull_if_nonzero_(1, 2); -bool iovec_increment(struct iovec *iovec, size_t n, size_t k); +bool iovec_increment(struct iovec *iovec, size_t n, size_t k) _nonnull_if_nonzero_(1, 2); static inline struct iovec* iovec_make_string(struct iovec *iovec, const char *s) { assert(iovec); @@ -42,7 +42,7 @@ static inline void iovec_done_erase(struct iovec *iovec) { char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value); char* set_iovec_string_field_free(struct iovec *iovec, size_t *n_iovec, const char *field, char *value); -void iovec_array_free(struct iovec *iovec, size_t n_iovec); +void iovec_array_free(struct iovec *iovec, size_t n_iovec) _nonnull_if_nonzero_(1, 2); static inline int iovec_memcmp(const struct iovec *a, const struct iovec *b) { @@ -55,7 +55,7 @@ static inline int iovec_memcmp(const struct iovec *a, const struct iovec *b) { b ? b->iov_len : 0); } -static inline struct iovec *iovec_memdup(const struct iovec *source, struct iovec *ret) { +static inline struct iovec* iovec_memdup(const struct iovec *source, struct iovec *ret) { assert(ret); if (!iovec_is_set(source)) diff --git a/src/libnm-systemd-shared/src/basic/list.h b/src/libnm-systemd-shared/src/basic/list.h index 10e69541..090bdc7b 100644 --- a/src/libnm-systemd-shared/src/basic/list.h +++ b/src/libnm-systemd-shared/src/basic/list.h @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include "macro.h" + /* The head of the linked list. Use this in the structure that shall * contain the head of the linked list */ #define LIST_HEAD(t,name) \ @@ -203,7 +205,3 @@ free_func(elem); \ head; \ }) - -/* Now include "macro.h", because we want our definition of assert() which the macros above use. We include - * it down here instead of up top, since macro.h pulls in log.h which in turn needs our own definitions. */ -#include "macro.h" diff --git a/src/libnm-systemd-shared/src/basic/locale-util.c b/src/libnm-systemd-shared/src/basic/locale-util.c index 0654fde8..d491d81f 100644 --- a/src/libnm-systemd-shared/src/basic/locale-util.c +++ b/src/libnm-systemd-shared/src/basic/locale-util.c @@ -19,8 +19,9 @@ #include "fileio.h" #include "hashmap.h" #include "locale-util.h" -#include "missing_syscall.h" +#include "log.h" #include "path-util.h" +#include "process-util.h" #include "set.h" #include "string-table.h" #include "string-util.h" @@ -28,7 +29,7 @@ #include "utf8.h" #if 0 /* NM_IGNORED */ -static char *normalize_locale(const char *name) { +static char* normalize_locale(const char *name) { const char *e; /* Locale names are weird: glibc has some magic rules when looking for the charset name on disk: it @@ -96,18 +97,15 @@ static int add_locales_from_archive(Set *locales) { uint32_t locrec_offset; }; - const struct locarhead *h; - const struct namehashent *e; - const void *p = MAP_FAILED; - _cleanup_close_ int fd = -EBADF; - size_t sz = 0; - struct stat st; int r; - fd = open("/usr/lib/locale/locale-archive", O_RDONLY|O_NOCTTY|O_CLOEXEC); + assert(locales); + + _cleanup_close_ int fd = open("/usr/lib/locale/locale-archive", O_RDONLY|O_NOCTTY|O_CLOEXEC); if (fd < 0) return errno == ENOENT ? 0 : -errno; + struct stat st; if (fstat(fd, &st) < 0) return -errno; @@ -120,11 +118,12 @@ static int add_locales_from_archive(Set *locales) { if (file_offset_beyond_memory_size(st.st_size)) return -EFBIG; - p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + void *p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); if (p == MAP_FAILED) return -errno; - h = (const struct locarhead *) p; + const struct namehashent *e; + const struct locarhead *h = p; if (h->magic != 0xde020109 || h->namehash_offset + h->namehash_size > st.st_size || h->string_offset + h->string_size > st.st_size || @@ -157,9 +156,9 @@ static int add_locales_from_archive(Set *locales) { r = 0; - finish: +finish: if (p != MAP_FAILED) - munmap((void*) p, sz); + munmap((void*) p, st.st_size); return r; } @@ -168,6 +167,8 @@ static int add_locales_from_libdir(Set *locales) { _cleanup_closedir_ DIR *dir = NULL; int r; + assert(locales); + dir = opendir("/usr/lib/locale"); if (!dir) return errno == ENOENT ? 0 : -errno; @@ -183,7 +184,7 @@ static int add_locales_from_libdir(Set *locales) { return -ENOMEM; r = set_consume(locales, z); - if (r < 0 && r != -EEXIST) + if (r < 0) return r; } @@ -191,11 +192,10 @@ static int add_locales_from_libdir(Set *locales) { } int get_locales(char ***ret) { - _cleanup_set_free_free_ Set *locales = NULL; - _cleanup_strv_free_ char **l = NULL; + _cleanup_set_free_ Set *locales = NULL; int r; - locales = set_new(&string_hash_ops); + locales = set_new(&string_hash_ops_free); if (!locales) return -ENOMEM; @@ -216,31 +216,25 @@ int get_locales(char ***ret) { free(set_remove(locales, locale)); } - l = set_get_strv(locales); + _cleanup_strv_free_ char **l = set_to_strv(&locales); if (!l) return -ENOMEM; - /* Now, all elements are owned by strv 'l'. Hence, do not call set_free_free(). */ - locales = set_free(locales); - r = getenv_bool("SYSTEMD_LIST_NON_UTF8_LOCALES"); - if (IN_SET(r, -ENXIO, 0)) { - char **a, **b; + if (r <= 0) { + if (!IN_SET(r, -ENXIO, 0)) + log_debug_errno(r, "Failed to parse $SYSTEMD_LIST_NON_UTF8_LOCALES as boolean, ignoring: %m"); /* Filter out non-UTF-8 locales, because it's 2019, by default */ - for (a = b = l; *a; a++) { - - if (endswith(*a, "UTF-8") || - strstr(*a, ".UTF-8@")) + char **b = l; + STRV_FOREACH(a, l) + if (endswith(*a, "UTF-8") || strstr(*a, ".UTF-8@")) *(b++) = *a; else free(*a); - } *b = NULL; - - } else if (r < 0) - log_debug_errno(r, "Failed to parse $SYSTEMD_LIST_NON_UTF8_LOCALES as boolean"); + } strv_sort(l); @@ -287,64 +281,48 @@ int locale_is_installed(const char *name) { } #endif /* NM_IGNORED */ -bool is_locale_utf8(void) { - static int cached_answer = -1; +static bool is_locale_utf8_impl(void) { const char *set; int r; - /* Note that we default to 'true' here, since today UTF8 is - * pretty much supported everywhere. */ - - if (cached_answer >= 0) - goto out; + /* Note that we default to 'true' here, since today UTF8 is pretty much supported everywhere. */ r = secure_getenv_bool("SYSTEMD_UTF8"); - if (r >= 0) { - cached_answer = r; - goto out; - } else if (r != -ENXIO) + if (r >= 0) + return r; + if (r != -ENXIO) log_debug_errno(r, "Failed to parse $SYSTEMD_UTF8, ignoring: %m"); /* This function may be called from libsystemd, and setlocale() is not thread safe. Assuming yes. */ - if (gettid() != raw_getpid()) { - cached_answer = true; - goto out; - } + if (!is_main_thread()) + return true; - if (!setlocale(LC_ALL, "")) { - cached_answer = true; - goto out; - } + if (!setlocale(LC_ALL, "")) + return true; set = nl_langinfo(CODESET); - if (!set) { - cached_answer = true; - goto out; - } - - if (streq(set, "UTF-8")) { - cached_answer = true; - goto out; - } + if (!set || streq(set, "UTF-8")) + return true; - /* For LC_CTYPE=="C" return true, because CTYPE is effectively - * unset and everything can do to UTF-8 nowadays. */ set = setlocale(LC_CTYPE, NULL); - if (!set) { - cached_answer = true; - goto out; - } + if (!set) + return true; - /* Check result, but ignore the result if C was set - * explicitly. */ - cached_answer = - STR_IN_SET(set, "C", "POSIX") && + /* Unless LC_CTYPE is explicitly overridden, return true. Because here CTYPE is effectively unset + * and everything can do to UTF-8 nowadays. */ + return STR_IN_SET(set, "C", "POSIX") && !getenv("LC_ALL") && !getenv("LC_CTYPE") && !getenv("LANG"); +} + +bool is_locale_utf8(void) { + static int cached = -1; + + if (cached < 0) + cached = is_locale_utf8_impl(); -out: - return (bool) cached_answer; + return cached; } #if 0 /* NM_IGNORED */ diff --git a/src/libnm-systemd-shared/src/basic/lock-util.h b/src/libnm-systemd-shared/src/basic/lock-util.h index a67d8b2c..b327b8e5 100644 --- a/src/libnm-systemd-shared/src/basic/lock-util.h +++ b/src/libnm-systemd-shared/src/basic/lock-util.h @@ -5,6 +5,8 @@ /* Include here so consumers have LOCK_{EX,SH,NB} available. */ #include <sys/file.h> +#include "time-util.h" + typedef struct LockFile { int dir_fd; char *path; diff --git a/src/libnm-systemd-shared/src/basic/log.h b/src/libnm-systemd-shared/src/basic/log.h index 6477bff4..4741f580 100644 --- a/src/libnm-systemd-shared/src/basic/log.h +++ b/src/libnm-systemd-shared/src/basic/log.h @@ -7,10 +7,7 @@ #include <string.h> #include <syslog.h> -#include "list.h" #include "macro.h" -#include "ratelimit.h" -#include "stdio-util.h" /* Some structures we reference but don't want to pull in headers for */ struct iovec; @@ -90,13 +87,6 @@ int log_show_tid_from_string(const char *e); * environment should not be called from library code — this is always a job * for the application itself. */ -#if 0 /* NM_IGNORED */ -assert_cc(STRLEN(__FILE__) > STRLEN(RELATIVE_SOURCE_PATH) + 1); -#define PROJECT_FILE (&__FILE__[STRLEN(RELATIVE_SOURCE_PATH) + 1]) -#else /* NM_IGNORED */ -#define PROJECT_FILE __FILE__ -#endif /* NM_IGNORED */ - bool stderr_is_journal(void); int log_open(void); void log_close(void); @@ -224,7 +214,7 @@ int log_struct_internal( const char *file, int line, const char *func, - const char *format, ...) _printf_(6,0) _sentinel_; + const char *format, ...) _sentinel_; #endif /* NM_IGNORED */ #if 0 /* NM_IGNORED */ @@ -294,53 +284,6 @@ _noreturn_ void log_assert_failed( #endif /* NM_IGNORED */ #if 0 /* NM_IGNORED */ -_noreturn_ void log_assert_failed_unreachable( - const char *file, - int line, - const char *func); -#else /* NM_IGNORED */ -#define log_assert_failed_unreachable(file, line, func) \ - G_STMT_START \ - { \ - log_internal(LOG_CRIT, \ - 0, \ - file, \ - line, \ - func, \ - "Code should not be reached at %s:%u, function %s(). Aborting.", \ - file, \ - line, \ - func); \ - g_assert_not_reached(); \ - } \ - G_STMT_END -#endif /* NM_IGNORED */ - -#if 0 /* NM_IGNORED */ -void log_assert_failed_return( - const char *text, - const char *file, - int line, - const char *func); -#else /* NM_IGNORED */ -#define log_assert_failed_return(text, file, line, func) \ - ({ \ - log_internal(LOG_DEBUG, \ - 0, \ - file, \ - line, \ - func, \ - "Assertion '%s' failed at %s:%u, function %s(). Ignoring.", \ - text, \ - file, \ - line, \ - func); \ - g_return_if_fail_warning(G_LOG_DOMAIN, G_STRFUNC, text); \ - (void) 0; \ - }) -#endif /* NM_IGNORED */ - -#if 0 /* NM_IGNORED */ #define log_dispatch(level, error, buffer) \ log_dispatch_internal(level, error, PROJECT_FILE, __LINE__, __func__, NULL, NULL, NULL, NULL, buffer) #endif /* NM_IGNORED */ @@ -450,11 +393,15 @@ bool log_on_console(void) _pure_; /* Do a fake formatting of the message string to let the scanner verify the arguments against the format * message. The variable will never be set to true, but we don't tell the compiler that :) */ extern bool _log_message_dummy; -# define LOG_MESSAGE(fmt, ...) "MESSAGE=%.0d" fmt, (_log_message_dummy && printf(fmt, ##__VA_ARGS__)), ##__VA_ARGS__ +# define LOG_ITEM(fmt, ...) "%.0d" fmt, (_log_message_dummy && printf(fmt, ##__VA_ARGS__)), ##__VA_ARGS__ +# define LOG_MESSAGE(fmt, ...) LOG_ITEM("MESSAGE=" fmt, ##__VA_ARGS__) #else +# define LOG_ITEM(fmt, ...) fmt, ##__VA_ARGS__ # define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__ #endif +#define LOG_MESSAGE_ID(id) LOG_ITEM("MESSAGE_ID=" id) + void log_received_signal(int level, const struct signalfd_siginfo *si); /* If turned on, any requests for a log target involving "syslog" will be implicitly upgraded to the equivalent journal target */ @@ -471,9 +418,6 @@ void log_set_open_when_needed(bool b); * stderr, the console or kmsg */ void log_set_prohibit_ipc(bool b); -void log_set_assert_return_is_critical(bool b); -bool log_get_assert_return_is_critical(void) _pure_; - int log_dup_console(void); #if 0 /* NM_IGNORED */ @@ -540,58 +484,6 @@ int log_syntax_parse_error_internal( void log_setup(void); -typedef struct LogRateLimit { - int error; - int level; - RateLimit ratelimit; -} LogRateLimit; - -#define log_ratelimit_internal(_level, _error, _ratelimit, _file, _line, _func, _format, ...) \ -({ \ - int _log_ratelimit_error = (_error); \ - int _log_ratelimit_level = (_level); \ - static LogRateLimit _log_ratelimit = { \ - .ratelimit = (_ratelimit), \ - }; \ - unsigned _num_dropped_errors = ratelimit_num_dropped(&_log_ratelimit.ratelimit); \ - if (_log_ratelimit_error != _log_ratelimit.error || _log_ratelimit_level != _log_ratelimit.level) { \ - ratelimit_reset(&_log_ratelimit.ratelimit); \ - _log_ratelimit.error = _log_ratelimit_error; \ - _log_ratelimit.level = _log_ratelimit_level; \ - } \ - if (log_get_max_level() == LOG_DEBUG || ratelimit_below(&_log_ratelimit.ratelimit)) \ - _log_ratelimit_error = _num_dropped_errors > 0 \ - ? log_internal(_log_ratelimit_level, _log_ratelimit_error, _file, _line, _func, _format " (Dropped %u similar message(s))", ##__VA_ARGS__, _num_dropped_errors) \ - : log_internal(_log_ratelimit_level, _log_ratelimit_error, _file, _line, _func, _format, ##__VA_ARGS__); \ - _log_ratelimit_error; \ -}) - -#define log_ratelimit_full_errno(level, error, _ratelimit, format, ...) \ - ({ \ - int _level = (level), _e = (error); \ - _e = (log_get_max_level() >= LOG_PRI(_level)) \ - ? log_ratelimit_internal(_level, _e, _ratelimit, PROJECT_FILE, __LINE__, __func__, format, ##__VA_ARGS__) \ - : -ERRNO_VALUE(_e); \ - _e < 0 ? _e : -ESTRPIPE; \ - }) - -#define log_ratelimit_full(level, _ratelimit, format, ...) \ - log_ratelimit_full_errno(level, 0, _ratelimit, format, ##__VA_ARGS__) - -/* Normal logging */ -#define log_ratelimit_info(...) log_ratelimit_full(LOG_INFO, __VA_ARGS__) -#define log_ratelimit_notice(...) log_ratelimit_full(LOG_NOTICE, __VA_ARGS__) -#define log_ratelimit_warning(...) log_ratelimit_full(LOG_WARNING, __VA_ARGS__) -#define log_ratelimit_error(...) log_ratelimit_full(LOG_ERR, __VA_ARGS__) -#define log_ratelimit_emergency(...) log_ratelimit_full(log_emergency_level(), __VA_ARGS__) - -/* Logging triggered by an errno-like error */ -#define log_ratelimit_info_errno(error, ...) log_ratelimit_full_errno(LOG_INFO, error, __VA_ARGS__) -#define log_ratelimit_notice_errno(error, ...) log_ratelimit_full_errno(LOG_NOTICE, error, __VA_ARGS__) -#define log_ratelimit_warning_errno(error, ...) log_ratelimit_full_errno(LOG_WARNING, error, __VA_ARGS__) -#define log_ratelimit_error_errno(error, ...) log_ratelimit_full_errno(LOG_ERR, error, __VA_ARGS__) -#define log_ratelimit_emergency_errno(error, ...) log_ratelimit_full_errno(log_emergency_level(), error, __VA_ARGS__) - const char* _log_set_prefix(const char *prefix, bool force); static inline const char* _log_unset_prefixp(const char **p) { assert(p); @@ -601,112 +493,3 @@ static inline const char* _log_unset_prefixp(const char **p) { #define LOG_SET_PREFIX(prefix) \ _cleanup_(_log_unset_prefixp) _unused_ const char *CONCATENATE(_cleanup_log_unset_prefix_, UNIQ) = _log_set_prefix(prefix, false); - -/* - * The log context allows attaching extra metadata to log messages written to the journal via log.h. We keep - * track of a thread local log context onto which we can push extra metadata fields that should be logged. - * - * LOG_CONTEXT_PUSH() will add the provided field to the log context and will remove it again when the - * current block ends. LOG_CONTEXT_PUSH_STRV() will do the same but for all fields in the given strv. - * LOG_CONTEXT_PUSHF() is like LOG_CONTEXT_PUSH() but takes a format string and arguments. - * - * Using the macros is as simple as putting them anywhere inside a block to add a field to all following log - * messages logged from inside that block. - * - * void myfunction(...) { - * ... - * - * LOG_CONTEXT_PUSHF("MYMETADATA=%s", "abc"); - * - * // Every journal message logged will now have the MYMETADATA=abc - * // field included. - * } - * - * One special case to note is async code, where we use callbacks that are invoked to continue processing - * when some event occurs. For async code, there's usually an associated "userdata" struct containing all the - * information associated with the async operation. In this "userdata" struct, we can store a log context - * allocated with log_context_new() and freed with log_context_free(). We can then add and remove fields to - * the `fields` member of the log context object and all those fields will be logged along with each log - * message. - */ - -typedef struct LogContext LogContext; - -bool log_context_enabled(void); - -LogContext* log_context_new(const char *key, const char *value); -LogContext* log_context_new_strv(char **fields, bool owned); -LogContext* log_context_new_iov(struct iovec *input_iovec, size_t n_input_iovec, bool owned); - -/* Same as log_context_new(), but frees the given fields strv/iovec on failure. */ -LogContext* log_context_new_strv_consume(char **fields); -LogContext* log_context_new_iov_consume(struct iovec *input_iovec, size_t n_input_iovec); - -LogContext *log_context_ref(LogContext *c); -LogContext *log_context_unref(LogContext *c); - -DEFINE_TRIVIAL_CLEANUP_FUNC(LogContext*, log_context_unref); - -/* Returns the number of attached log context objects. */ -size_t log_context_num_contexts(void); -/* Returns the number of fields in all attached log contexts. */ -size_t log_context_num_fields(void); - -static inline void _reset_log_level(int *saved_log_level) { - assert(saved_log_level); - - log_set_max_level(*saved_log_level); -} - -#define LOG_CONTEXT_SET_LOG_LEVEL(level) \ - _cleanup_(_reset_log_level) _unused_ int _saved_log_level_ = log_set_max_level(level); - -#define LOG_CONTEXT_PUSH(...) \ - LOG_CONTEXT_PUSH_STRV(STRV_MAKE(__VA_ARGS__)) - -#define LOG_CONTEXT_PUSHF(...) \ - LOG_CONTEXT_PUSH(snprintf_ok((char[LINE_MAX]) {}, LINE_MAX, __VA_ARGS__)) - -#define _LOG_CONTEXT_PUSH_KEY_VALUE(key, value, c) \ - _unused_ _cleanup_(log_context_unrefp) LogContext *c = log_context_new(key, value); - -#define LOG_CONTEXT_PUSH_KEY_VALUE(key, value) \ - _LOG_CONTEXT_PUSH_KEY_VALUE(key, value, UNIQ_T(c, UNIQ)) - -#define _LOG_CONTEXT_PUSH_STRV(strv, c) \ - _unused_ _cleanup_(log_context_unrefp) LogContext *c = log_context_new_strv(strv, /*owned=*/ false); - -#define LOG_CONTEXT_PUSH_STRV(strv) \ - _LOG_CONTEXT_PUSH_STRV(strv, UNIQ_T(c, UNIQ)) - -#define _LOG_CONTEXT_PUSH_IOV(input_iovec, n_input_iovec, c) \ - _unused_ _cleanup_(log_context_unrefp) LogContext *c = log_context_new_iov(input_iovec, n_input_iovec, /*owned=*/ false); - -#define LOG_CONTEXT_PUSH_IOV(input_iovec, n_input_iovec) \ - _LOG_CONTEXT_PUSH_IOV(input_iovec, n_input_iovec, UNIQ_T(c, UNIQ)) - -/* LOG_CONTEXT_CONSUME_STR()/LOG_CONTEXT_CONSUME_STRV()/LOG_CONTEXT_CONSUME_IOV() are identical to - * LOG_CONTEXT_PUSH_STR()/LOG_CONTEXT_PUSH_STRV()/LOG_CONTEXT_PUSH_IOV() except they take ownership of the - * given str/strv argument. - */ - -#define _LOG_CONTEXT_CONSUME_STR(s, c, strv) \ - _unused_ _cleanup_strv_free_ strv = strv_new(s); \ - if (!strv) \ - free(s); \ - _unused_ _cleanup_(log_context_unrefp) LogContext *c = log_context_new_strv_consume(TAKE_PTR(strv)) - -#define LOG_CONTEXT_CONSUME_STR(s) \ - _LOG_CONTEXT_CONSUME_STR(s, UNIQ_T(c, UNIQ), UNIQ_T(sv, UNIQ)) - -#define _LOG_CONTEXT_CONSUME_STRV(strv, c) \ - _unused_ _cleanup_(log_context_unrefp) LogContext *c = log_context_new_strv_consume(strv); - -#define LOG_CONTEXT_CONSUME_STRV(strv) \ - _LOG_CONTEXT_CONSUME_STRV(strv, UNIQ_T(c, UNIQ)) - -#define _LOG_CONTEXT_CONSUME_IOV(input_iovec, n_input_iovec, c) \ - _unused_ _cleanup_(log_context_unrefp) LogContext *c = log_context_new_iov_consume(input_iovec, n_input_iovec); - -#define LOG_CONTEXT_CONSUME_IOV(input_iovec, n_input_iovec) \ - _LOG_CONTEXT_CONSUME_IOV(input_iovec, n_input_iovec, UNIQ_T(c, UNIQ)) diff --git a/src/libnm-systemd-shared/src/basic/macro.h b/src/libnm-systemd-shared/src/basic/macro.h index 026ec136..4ee1ad4d 100644 --- a/src/libnm-systemd-shared/src/basic/macro.h +++ b/src/libnm-systemd-shared/src/basic/macro.h @@ -103,76 +103,6 @@ static inline size_t GREEDY_ALLOC_ROUND_UP(size_t l) { (type*)( (char *)UNIQ_T(A, uniq) - offsetof(type, member) ); \ }) -#ifdef __COVERITY__ - -/* Use special definitions of assertion macros in order to prevent - * false positives of ASSERT_SIDE_EFFECT on Coverity static analyzer - * for uses of assert_se() and assert_return(). - * - * These definitions make expression go through a (trivial) function - * call to ensure they are not discarded. Also use ! or !! to ensure - * the boolean expressions are seen as such. - * - * This technique has been described and recommended in: - * https://community.synopsys.com/s/question/0D534000046Yuzb/suppressing-assertsideeffect-for-functions-that-allow-for-sideeffects - */ - -extern void __coverity_panic__(void); - -static inline void __coverity_check__(int condition) { - if (!condition) - __coverity_panic__(); -} - -static inline int __coverity_check_and_return__(int condition) { - return condition; -} - -#define assert_message_se(expr, message) __coverity_check__(!!(expr)) - -#define assert_log(expr, message) __coverity_check_and_return__(!!(expr)) - -#else /* ! __COVERITY__ */ - -#define assert_message_se(expr, message) \ - do { \ - if (_unlikely_(!(expr))) \ - log_assert_failed(message, PROJECT_FILE, __LINE__, __func__); \ - } while (false) - -#define assert_log(expr, message) ((_likely_(expr)) \ - ? (true) \ - : (log_assert_failed_return(message, PROJECT_FILE, __LINE__, __func__), false)) - -#endif /* __COVERITY__ */ - -#define assert_se(expr) assert_message_se(expr, #expr) - -/* We override the glibc assert() here. */ -#undef assert -#ifdef NDEBUG -#define assert(expr) ({ if (!(expr)) __builtin_unreachable(); }) -#else -#define assert(expr) assert_message_se(expr, #expr) -#endif - -#define assert_not_reached() \ - log_assert_failed_unreachable(PROJECT_FILE, __LINE__, __func__) - -#define assert_return(expr, r) \ - do { \ - if (!assert_log(expr, #expr)) \ - return (r); \ - } while (false) - -#define assert_return_errno(expr, r, err) \ - do { \ - if (!assert_log(expr, #expr)) { \ - errno = err; \ - return (r); \ - } \ - } while (false) - #define return_with_errno(r, err) \ do { \ errno = abs(err); \ @@ -251,59 +181,6 @@ static inline int __coverity_check_and_return__(int condition) { /* Pointers range from NULL to POINTER_MAX */ #define POINTER_MAX ((void*) UINTPTR_MAX) -#define _DEFINE_TRIVIAL_REF_FUNC(type, name, scope) \ - scope type *name##_ref(type *p) { \ - if (!p) \ - return NULL; \ - \ - /* For type check. */ \ - unsigned *q = &p->n_ref; \ - assert(*q > 0); \ - assert_se(*q < UINT_MAX); \ - \ - (*q)++; \ - return p; \ - } - -#define _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, scope) \ - scope type *name##_unref(type *p) { \ - if (!p) \ - return NULL; \ - \ - assert(p->n_ref > 0); \ - p->n_ref--; \ - if (p->n_ref > 0) \ - return NULL; \ - \ - return free_func(p); \ - } - -#define DEFINE_TRIVIAL_REF_FUNC(type, name) \ - _DEFINE_TRIVIAL_REF_FUNC(type, name,) -#define DEFINE_PRIVATE_TRIVIAL_REF_FUNC(type, name) \ - _DEFINE_TRIVIAL_REF_FUNC(type, name, static) -#define DEFINE_PUBLIC_TRIVIAL_REF_FUNC(type, name) \ - _DEFINE_TRIVIAL_REF_FUNC(type, name, _public_) - -#define DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func) \ - _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func,) -#define DEFINE_PRIVATE_TRIVIAL_UNREF_FUNC(type, name, free_func) \ - _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, static) -#define DEFINE_PUBLIC_TRIVIAL_UNREF_FUNC(type, name, free_func) \ - _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, _public_) - -#define DEFINE_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \ - DEFINE_TRIVIAL_REF_FUNC(type, name); \ - DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func); - -#define DEFINE_PRIVATE_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \ - DEFINE_PRIVATE_TRIVIAL_REF_FUNC(type, name); \ - DEFINE_PRIVATE_TRIVIAL_UNREF_FUNC(type, name, free_func); - -#define DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \ - DEFINE_PUBLIC_TRIVIAL_REF_FUNC(type, name); \ - DEFINE_PUBLIC_TRIVIAL_UNREF_FUNC(type, name, free_func); - /* A macro to force copying of a variable from memory. This is useful whenever we want to read something from * memory and want to make sure the compiler won't optimize away the destination variable for us. It's not * supposed to be a full CPU memory barrier, i.e. CPU is still allowed to reorder the reads, but it is not @@ -328,12 +205,6 @@ static inline size_t size_add(size_t x, size_t y) { return saturate_add(x, y, SIZE_MAX); } -typedef struct { - int _empty[0]; -} dummy_t; - -assert_cc(sizeof(dummy_t) == 0); - /* A little helper for subtracting 1 off a pointer in a safe UB-free way. This is intended to be used for * loops that count down from a high pointer until some base. A naive loop would implement this like this: * @@ -358,5 +229,3 @@ assert_cc(sizeof(dummy_t) == 0); for (typeof(entry) _va_sentinel_[1] = {}, _entries_[] = { __VA_ARGS__ __VA_OPT__(,) _va_sentinel_[0] }, *_current_ = _entries_; \ ((long)(_current_ - _entries_) < (long)(ELEMENTSOF(_entries_) - 1)) && ({ entry = *_current_; true; }); \ _current_++) - -#include "log.h" diff --git a/src/libnm-systemd-shared/src/basic/memory-util.c b/src/libnm-systemd-shared/src/basic/memory-util.c index 789e96a9..3e9a3683 100644 --- a/src/libnm-systemd-shared/src/basic/memory-util.c +++ b/src/libnm-systemd-shared/src/basic/memory-util.c @@ -2,10 +2,11 @@ #include "nm-sd-adapt-shared.h" +#include <threads.h> #include <unistd.h> +#include "alloc-util.h" #include "memory-util.h" -#include "missing_threads.h" size_t page_size(void) { static thread_local size_t pgsz = 0; @@ -42,7 +43,7 @@ bool memeqbyte(uint8_t byte, const void *data, size_t length) { return memcmp(data, p + 16, length) == 0; } -void *memdup_reverse(const void *mem, size_t size) { +void* memdup_reverse(const void *mem, size_t size) { assert(mem); assert(size != 0); @@ -57,3 +58,14 @@ void *memdup_reverse(const void *mem, size_t size) { return p; } + +void* erase_and_free(void *p) { + size_t l; + + if (!p) + return NULL; + + l = MALLOC_SIZEOF_SAFE(p); + explicit_bzero_safe(p, l); + return mfree(p); +} diff --git a/src/libnm-systemd-shared/src/basic/memory-util.h b/src/libnm-systemd-shared/src/basic/memory-util.h index 1f604cc4..443fc3a8 100644 --- a/src/libnm-systemd-shared/src/basic/memory-util.h +++ b/src/libnm-systemd-shared/src/basic/memory-util.h @@ -7,7 +7,6 @@ #include <string.h> #include <sys/types.h> -#include "alloc-util.h" #include "macro.h" #include "memory-util-fundamental.h" @@ -35,13 +34,16 @@ static inline void* mempcpy_safe(void *dst, const void *src, size_t n) { return mempcpy(dst, src, n); } -#define mempcpy_typesafe(dst, src, n) \ +#define _mempcpy_typesafe(dst, src, n, sz) \ ({ \ - size_t _sz_; \ - assert_se(MUL_SAFE(&_sz_, sizeof((dst)[0]), n)); \ - (typeof((dst)[0])*) mempcpy_safe(dst, src, _sz_); \ + size_t sz; \ + assert_se(MUL_SAFE(&sz, sizeof((dst)[0]), n)); \ + (typeof((dst)[0])*) mempcpy_safe(dst, src, sz); \ }) +#define mempcpy_typesafe(dst, src, n) \ + _mempcpy_typesafe(dst, src, n, UNIQ_T(sz, UNIQ)) + /* Normal memcmp() requires s1 and s2 to be nonnull. We do nothing if n is 0. */ static inline int memcmp_safe(const void *s1, const void *s2, size_t n) { if (n == 0) @@ -59,19 +61,19 @@ static inline int memcmp_nn(const void *s1, size_t n1, const void *s2, size_t n2 #define zero(x) (memzero(&(x), sizeof(x))) -bool memeqbyte(uint8_t byte, const void *data, size_t length); +bool memeqbyte(uint8_t byte, const void *data, size_t length) _nonnull_if_nonzero_(2, 3); #define memeqzero(data, length) memeqbyte(0x00, data, length) #define eqzero(x) memeqzero(x, sizeof(x)) -static inline void *mempset(void *s, int c, size_t n) { +static inline void* mempset(void *s, int c, size_t n) { memset(s, c, n); - return (uint8_t*)s + n; + return (uint8_t*) s + n; } /* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */ -static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) { +static inline void* memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) { if (needlelen <= 0) return (void*) haystack; @@ -85,7 +87,7 @@ static inline void *memmem_safe(const void *haystack, size_t haystacklen, const return memmem(haystack, haystacklen, needle, needlelen); } -static inline void *mempmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) { +static inline void* mempmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) { const uint8_t *p; p = memmem_safe(haystack, haystacklen, needle, needlelen); @@ -95,16 +97,7 @@ static inline void *mempmem_safe(const void *haystack, size_t haystacklen, const return (uint8_t*) p + needlelen; } -static inline void* erase_and_free(void *p) { - size_t l; - - if (!p) - return NULL; - - l = MALLOC_SIZEOF_SAFE(p); - explicit_bzero_safe(p, l); - return mfree(p); -} +void* erase_and_free(void *p); static inline void erase_and_freep(void *p) { erase_and_free(*(void**) p); @@ -116,4 +109,57 @@ static inline void erase_char(char *p) { } /* Makes a copy of the buffer with reversed order of bytes */ -void *memdup_reverse(const void *mem, size_t size); +void* memdup_reverse(const void *mem, size_t size); + +#define _DEFINE_TRIVIAL_REF_FUNC(type, name, scope) \ + scope type *name##_ref(type *p) { \ + if (!p) \ + return NULL; \ + \ + /* For type check. */ \ + unsigned *q = &p->n_ref; \ + assert(*q > 0); \ + assert_se(*q < UINT_MAX); \ + \ + (*q)++; \ + return p; \ + } + +#define _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, scope) \ + scope type *name##_unref(type *p) { \ + if (!p) \ + return NULL; \ + \ + assert(p->n_ref > 0); \ + p->n_ref--; \ + if (p->n_ref > 0) \ + return NULL; \ + \ + return free_func(p); \ + } + +#define DEFINE_TRIVIAL_REF_FUNC(type, name) \ + _DEFINE_TRIVIAL_REF_FUNC(type, name,) +#define DEFINE_PRIVATE_TRIVIAL_REF_FUNC(type, name) \ + _DEFINE_TRIVIAL_REF_FUNC(type, name, static) +#define DEFINE_PUBLIC_TRIVIAL_REF_FUNC(type, name) \ + _DEFINE_TRIVIAL_REF_FUNC(type, name, _public_) + +#define DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func) \ + _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func,) +#define DEFINE_PRIVATE_TRIVIAL_UNREF_FUNC(type, name, free_func) \ + _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, static) +#define DEFINE_PUBLIC_TRIVIAL_UNREF_FUNC(type, name, free_func) \ + _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, _public_) + +#define DEFINE_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \ + DEFINE_TRIVIAL_REF_FUNC(type, name); \ + DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func); + +#define DEFINE_PRIVATE_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \ + DEFINE_PRIVATE_TRIVIAL_REF_FUNC(type, name); \ + DEFINE_PRIVATE_TRIVIAL_UNREF_FUNC(type, name, free_func); + +#define DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \ + DEFINE_PUBLIC_TRIVIAL_REF_FUNC(type, name); \ + DEFINE_PUBLIC_TRIVIAL_UNREF_FUNC(type, name, free_func); diff --git a/src/libnm-systemd-shared/src/basic/mempool.c b/src/libnm-systemd-shared/src/basic/mempool.c index e467d706..60a89a6b 100644 --- a/src/libnm-systemd-shared/src/basic/mempool.c +++ b/src/libnm-systemd-shared/src/basic/mempool.c @@ -6,6 +6,7 @@ #include <stdlib.h> #include "format-util.h" +#include "log.h" #include "macro.h" #include "memory-util.h" #include "mempool.h" diff --git a/src/libnm-systemd-shared/src/basic/missing_fcntl.h b/src/libnm-systemd-shared/src/basic/missing_fcntl.h index a6188879..280e233b 100644 --- a/src/libnm-systemd-shared/src/basic/missing_fcntl.h +++ b/src/libnm-systemd-shared/src/basic/missing_fcntl.h @@ -3,74 +3,16 @@ #include <fcntl.h> -#ifndef F_LINUX_SPECIFIC_BASE -#define F_LINUX_SPECIFIC_BASE 1024 -#endif - +/* This is defined since glibc-2.41. */ #ifndef F_DUPFD_QUERY -#define F_DUPFD_QUERY (F_LINUX_SPECIFIC_BASE + 3) -#endif - -#ifndef F_SETPIPE_SZ -#define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7) -#endif - -#ifndef F_GETPIPE_SZ -#define F_GETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 8) -#endif - -#ifndef F_ADD_SEALS -#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9) -#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10) - -#define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */ -#define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */ -#define F_SEAL_GROW 0x0004 /* prevent file from growing */ -#define F_SEAL_WRITE 0x0008 /* prevent writes */ -#endif - -#ifndef F_SEAL_FUTURE_WRITE -#define F_SEAL_FUTURE_WRITE 0x0010 /* prevent future writes while mapped */ +#define F_DUPFD_QUERY 1027 #endif +/* This is defined since glibc-2.39. */ #ifndef F_SEAL_EXEC #define F_SEAL_EXEC 0x0020 /* prevent chmod modifying exec bits */ #endif -#ifndef F_OFD_GETLK -#define F_OFD_GETLK 36 -#define F_OFD_SETLK 37 -#define F_OFD_SETLKW 38 -#endif - -#ifndef MAX_HANDLE_SZ -#define MAX_HANDLE_SZ 128 -#endif - -/* The precise definition of __O_TMPFILE is arch specific; use the - * values defined by the kernel (note: some are hexa, some are octal, - * duplicated as-is from the kernel definitions): - * - alpha, parisc, sparc: each has a specific value; - * - others: they use the "generic" value. - */ - -#ifndef __O_TMPFILE -#if defined(__alpha__) -#define __O_TMPFILE 0100000000 -#elif defined(__parisc__) || defined(__hppa__) -#define __O_TMPFILE 0400000000 -#elif defined(__sparc__) || defined(__sparc64__) -#define __O_TMPFILE 0x2000000 -#else -#define __O_TMPFILE 020000000 -#endif -#endif - -/* a horrid kludge trying to make sure that this will fail on old kernels */ -#ifndef O_TMPFILE -#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) -#endif - /* So O_LARGEFILE is generally implied by glibc, and defined to zero hence, because we only build in LFS * mode. However, when invoking fcntl(F_GETFL) the flag is ORed into the result anyway — glibc does not mask * it away. Which sucks. Let's define the actual value here, so that we can mask it ourselves. @@ -79,6 +21,7 @@ * are hexa and others are octal; duplicated as-is from the kernel definitions): * - alpha, arm, arm64, m68k, mips, parisc, powerpc, sparc: each has a specific value; * - others: they use the "generic" value (defined in include/uapi/asm-generic/fcntl.h) */ +#if 0 /* NM_IGNORED */ #if O_LARGEFILE != 0 #define RAW_O_LARGEFILE O_LARGEFILE #else @@ -96,7 +39,15 @@ #define RAW_O_LARGEFILE 00100000 #endif #endif +#endif /* NM_IGNORED */ +/* This is defined since glibc-2.39. */ #ifndef AT_HANDLE_FID #define AT_HANDLE_FID AT_REMOVEDIR #endif + +/* On musl, O_ACCMODE is defined as (03|O_SEARCH), unlike glibc which defines it as + * (O_RDONLY|O_WRONLY|O_RDWR). Additionally, O_SEARCH is simply defined as O_PATH. This changes the behaviour + * of O_ACCMODE in certain situations, which we don't want. This definition is copied from glibc and works + * around the problems with musl's definition. */ +#define O_ACCMODE_STRICT (O_RDONLY|O_WRONLY|O_RDWR) diff --git a/src/libnm-systemd-shared/src/basic/missing_fs.h b/src/libnm-systemd-shared/src/basic/missing_fs.h new file mode 100644 index 00000000..1e2f07e5 --- /dev/null +++ b/src/libnm-systemd-shared/src/basic/missing_fs.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include <linux/fs.h> + +/* Not exposed yet. Defined at fs/ext4/ext4.h */ +#ifndef EXT4_IOC_RESIZE_FS +#define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64) +#endif + +/* linux/exportfs.h (33c5ac9175195c36a0b7005aaf503a2e81f117a1, 5.5) */ +#ifndef FILEID_KERNFS +#define FILEID_KERNFS 0xfe +#endif diff --git a/src/libnm-systemd-shared/src/basic/missing_random.h b/src/libnm-systemd-shared/src/basic/missing_random.h index 5f40c4e5..69002196 100644 --- a/src/libnm-systemd-shared/src/basic/missing_random.h +++ b/src/libnm-systemd-shared/src/basic/missing_random.h @@ -1,26 +1,11 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include "macro.h" - -#if HAVE_GETRANDOM -# include <sys/random.h> -#else -# include <linux/random.h> -#endif - -#ifndef GRND_NONBLOCK -# define GRND_NONBLOCK 0x0001 -#else -assert_cc(GRND_NONBLOCK == 0x0001); -#endif +#include <sys/random.h> -#ifndef GRND_RANDOM -# define GRND_RANDOM 0x0002 -#else -assert_cc(GRND_RANDOM == 0x0002); -#endif +#include "macro.h" +/* Defined since glibc-2.32. */ #ifndef GRND_INSECURE # define GRND_INSECURE 0x0004 #else diff --git a/src/libnm-systemd-shared/src/basic/missing_socket.h b/src/libnm-systemd-shared/src/basic/missing_socket.h index 8460ce13..874e93f3 100644 --- a/src/libnm-systemd-shared/src/basic/missing_socket.h +++ b/src/libnm-systemd-shared/src/basic/missing_socket.h @@ -3,75 +3,36 @@ #include <sys/socket.h> -#ifndef AF_VSOCK -#define AF_VSOCK 40 -#endif - -#ifndef SO_REUSEPORT -#define SO_REUSEPORT 15 -#endif - -#ifndef SO_PEERGROUPS -#define SO_PEERGROUPS 59 -#endif - +/* Supported since kernel v6.5 (5e2ff6704a275be009be8979af17c52361b79b89) */ #ifndef SO_PASSPIDFD #define SO_PASSPIDFD 76 #endif +/* Supported since kernel v6.5 (7b26952a91cf65ff1cc867a2382a8964d8c0ee7d) */ #ifndef SO_PEERPIDFD #define SO_PEERPIDFD 77 #endif -#ifndef SO_BINDTOIFINDEX -#define SO_BINDTOIFINDEX 62 -#endif - -#ifndef SOL_NETLINK -#define SOL_NETLINK 270 -#endif - -#ifndef SOL_ALG -#define SOL_ALG 279 -#endif - /* Not exposed yet. Defined in include/linux/socket.h. */ #ifndef SOL_SCTP #define SOL_SCTP 132 #endif +/* Supported since kernel v2.6.17 (2c7946a7bf45ae86736ab3b43d0085e43947945c). + * Defined since glibc-2.39 */ #ifndef SCM_SECURITY #define SCM_SECURITY 0x03 #endif +/* Supported since kernel v6.5 (5e2ff6704a275be009be8979af17c52361b79b89). + * Defined since glibc-2.39 */ #ifndef SCM_PIDFD #define SCM_PIDFD 0x04 #endif -/* netinet/in.h */ -#ifndef IP_FREEBIND -#define IP_FREEBIND 15 -#endif - -#ifndef IP_TRANSPARENT -#define IP_TRANSPARENT 19 -#endif - -#ifndef IPV6_FREEBIND -#define IPV6_FREEBIND 78 -#endif - -#ifndef IP_RECVFRAGSIZE -#define IP_RECVFRAGSIZE 25 -#endif - -#ifndef IPV6_RECVFRAGSIZE -#define IPV6_RECVFRAGSIZE 77 -#endif - -/* The maximum number of fds that SCM_RIGHTS accepts. This is an internal kernel constant, but very much - * useful for userspace too. It's documented in unix(7) these days, hence should be fairly reliable to define - * here. */ +/* The maximum number of fds that SCM_RIGHTS accepts. This is an internal kernel constant defined in + * include/net/scm.h, but very much useful for userspace too. It's documented in unix(7) these days, hence + * should be fairly reliable to define here. */ #ifndef SCM_MAX_FD #define SCM_MAX_FD 253U #endif diff --git a/src/libnm-systemd-shared/src/basic/missing_stat.h b/src/libnm-systemd-shared/src/basic/missing_stat.h deleted file mode 100644 index 18a15ab0..00000000 --- a/src/libnm-systemd-shared/src/basic/missing_stat.h +++ /dev/null @@ -1,139 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -#include <linux/types.h> -#include <sys/stat.h> - -#if 0 /* NM_IGNORED */ -#if WANT_LINUX_STAT_H -#include <linux/stat.h> -#endif - -/* The newest definition we are aware of (fa2fcf4f1df1559a0a4ee0f46915b496cc2ebf60; 5.8) */ -#define STATX_DEFINITION { \ - __u32 stx_mask; \ - __u32 stx_blksize; \ - __u64 stx_attributes; \ - __u32 stx_nlink; \ - __u32 stx_uid; \ - __u32 stx_gid; \ - __u16 stx_mode; \ - __u16 __spare0[1]; \ - __u64 stx_ino; \ - __u64 stx_size; \ - __u64 stx_blocks; \ - __u64 stx_attributes_mask; \ - struct statx_timestamp stx_atime; \ - struct statx_timestamp stx_btime; \ - struct statx_timestamp stx_ctime; \ - struct statx_timestamp stx_mtime; \ - __u32 stx_rdev_major; \ - __u32 stx_rdev_minor; \ - __u32 stx_dev_major; \ - __u32 stx_dev_minor; \ - __u64 stx_mnt_id; \ - __u64 __spare2; \ - __u64 __spare3[12]; \ -} - -#if !HAVE_STRUCT_STATX -struct statx_timestamp { - __s64 tv_sec; - __u32 tv_nsec; - __s32 __reserved; -}; - -struct statx STATX_DEFINITION; -#endif - -/* Always define the newest version we are aware of as a distinct type, so that we can use it even if glibc - * defines an older definition */ -struct new_statx STATX_DEFINITION; -#else /* NM_IGNORED */ -struct new_statx; -#endif /* NM_IGNORED */ - -/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ -#ifndef AT_STATX_SYNC_AS_STAT -#define AT_STATX_SYNC_AS_STAT 0x0000 -#endif - -/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ -#ifndef AT_STATX_FORCE_SYNC -#define AT_STATX_FORCE_SYNC 0x2000 -#endif - -/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ -#ifndef AT_STATX_DONT_SYNC -#define AT_STATX_DONT_SYNC 0x4000 -#endif - -/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ -#ifndef STATX_TYPE -#define STATX_TYPE 0x00000001U -#endif - -/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ -#ifndef STATX_MODE -#define STATX_MODE 0x00000002U -#endif - -/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ -#ifndef STATX_NLINK -#define STATX_NLINK 0x00000004U -#endif - -/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ -#ifndef STATX_UID -#define STATX_UID 0x00000008U -#endif - -/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ -#ifndef STATX_GID -#define STATX_GID 0x00000010U -#endif - -/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ -#ifndef STATX_ATIME -#define STATX_ATIME 0x00000020U -#endif - -/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ -#ifndef STATX_MTIME -#define STATX_MTIME 0x00000040U -#endif - -/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ -#ifndef STATX_CTIME -#define STATX_CTIME 0x00000080U -#endif - -/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ -#ifndef STATX_INO -#define STATX_INO 0x00000100U -#endif - -/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ -#ifndef STATX_SIZE -#define STATX_SIZE 0x00000200U -#endif - -/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ -#ifndef STATX_BLOCKS -#define STATX_BLOCKS 0x00000400U -#endif - -/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ -#ifndef STATX_BTIME -#define STATX_BTIME 0x00000800U -#endif - -/* fa2fcf4f1df1559a0a4ee0f46915b496cc2ebf60 (5.8) */ -#ifndef STATX_MNT_ID -#define STATX_MNT_ID 0x00001000U -#endif - -/* 80340fe3605c0e78cfe496c3b3878be828cfdbfe (5.8) */ -#ifndef STATX_ATTR_MOUNT_ROOT -#define STATX_ATTR_MOUNT_ROOT 0x00002000 /* Root of a mount */ -#endif diff --git a/src/libnm-systemd-shared/src/basic/missing_syscall.h b/src/libnm-systemd-shared/src/basic/missing_syscall.h index da6f9827..55475f7e 100644 --- a/src/libnm-systemd-shared/src/basic/missing_syscall.h +++ b/src/libnm-systemd-shared/src/basic/missing_syscall.h @@ -4,12 +4,7 @@ /* Missing glibc definitions to access certain kernel APIs */ #include <errno.h> -#include <fcntl.h> -#if HAVE_LINUX_TIME_TYPES_H -/* This header defines __kernel_timespec for us, but is only available since Linux 5.1, hence conditionally - * include this. */ #include <linux/time_types.h> -#endif #include <signal.h> #include <sys/syscall.h> #include <sys/types.h> @@ -23,26 +18,15 @@ #include "macro.h" #include "missing_keyctl.h" #include "missing_sched.h" -#include "missing_stat.h" #include "missing_syscall_def.h" #if 0 /* NM_IGNORED */ - -/* linux/kcmp.h */ -#ifndef KCMP_FILE /* 3f4994cfc15f38a3159c6e3a4b3ab2e1481a6b02 (3.19) */ -#define KCMP_FILE 0 -#endif - /* ======================================================================= */ #if !HAVE_FCHMODAT2 +/* since kernel v6.6 (78252deb023cf0879256fcfbafe37022c390762b) */ static inline int missing_fchmodat2(int dirfd, const char *path, mode_t mode, int flags) { -# ifdef __NR_fchmodat2 return syscall(__NR_fchmodat2, dirfd, path, mode, flags); -# else - errno = ENOSYS; - return -1; -# endif } # define fchmodat2 missing_fchmodat2 @@ -80,95 +64,6 @@ static inline int missing_ioprio_set(int which, int who, int ioprio) { /* ======================================================================= */ -#if !HAVE_MEMFD_CREATE -static inline int missing_memfd_create(const char *name, unsigned int flags) { - return syscall(__NR_memfd_create, name, flags); -} - -# define memfd_create missing_memfd_create -#endif -#endif /* NM_IGNORED */ - -/* ======================================================================= */ - -#if !HAVE_GETRANDOM -/* glibc says getrandom() returns ssize_t */ -static inline ssize_t missing_getrandom(void *buffer, size_t count, unsigned flags) { - return syscall(__NR_getrandom, buffer, count, flags); -} - -# define getrandom missing_getrandom -#endif - -/* ======================================================================= */ - -#if 0 /* NM_IGNORED */ -/* The syscall has been defined since forever, but the glibc wrapper was missing. */ -#if !HAVE_GETTID -static inline pid_t missing_gettid(void) { -# if defined __NR_gettid && __NR_gettid >= 0 - return (pid_t) syscall(__NR_gettid); -# else -# error "__NR_gettid not defined" -# endif -} - -# define gettid missing_gettid -#endif - -/* ======================================================================= */ - -#if !HAVE_NAME_TO_HANDLE_AT -struct file_handle { - unsigned int handle_bytes; - int handle_type; - unsigned char f_handle[0]; -}; - -static inline int missing_name_to_handle_at(int fd, const char *name, struct file_handle *handle, int *mnt_id, int flags) { -# ifdef __NR_name_to_handle_at - return syscall(__NR_name_to_handle_at, fd, name, handle, mnt_id, flags); -# else - errno = ENOSYS; - return -1; -# endif -} - -# define name_to_handle_at missing_name_to_handle_at -#endif - -/* ======================================================================= */ - -#if !HAVE_SETNS -static inline int missing_setns(int fd, int nstype) { - return syscall(__NR_setns, fd, nstype); -} - -# define setns missing_setns -#endif - -/* ======================================================================= */ - -static inline pid_t raw_getpid(void) { -#if defined(__alpha__) - return (pid_t) syscall(__NR_getxpid); -#else - return (pid_t) syscall(__NR_getpid); -#endif -} - -/* ======================================================================= */ - -#if !HAVE_RENAMEAT2 -static inline int missing_renameat2(int oldfd, const char *oldname, int newfd, const char *newname, unsigned flags) { - return syscall(__NR_renameat2, oldfd, oldname, newfd, newname, flags); -} - -# define renameat2 missing_renameat2 -#endif - -/* ======================================================================= */ - #if !HAVE_KCMP static inline int missing_kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) { return syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2); @@ -186,12 +81,16 @@ static inline long missing_keyctl(int cmd, unsigned long arg2, unsigned long arg # define keyctl missing_keyctl } +/* ======================================================================= */ + static inline key_serial_t missing_add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t ringid) { return syscall(__NR_add_key, type, description, payload, plen, ringid); # define add_key missing_add_key } +/* ======================================================================= */ + static inline key_serial_t missing_request_key(const char *type, const char *description, const char * callout_info, key_serial_t destringid) { return syscall(__NR_request_key, type, description, callout_info, destringid); @@ -201,34 +100,11 @@ static inline key_serial_t missing_request_key(const char *type, const char *des /* ======================================================================= */ -#if !HAVE_COPY_FILE_RANGE -static inline ssize_t missing_copy_file_range(int fd_in, loff_t *off_in, - int fd_out, loff_t *off_out, - size_t len, - unsigned int flags) { -# ifdef __NR_copy_file_range - return syscall(__NR_copy_file_range, fd_in, off_in, fd_out, off_out, len, flags); -# else - errno = ENOSYS; - return -1; -# endif -} - -# define copy_file_range missing_copy_file_range -#endif - -/* ======================================================================= */ - #if !HAVE_BPF union bpf_attr; static inline int missing_bpf(int cmd, union bpf_attr *attr, size_t size) { -#ifdef __NR_bpf return (int) syscall(__NR_bpf, cmd, attr, size); -#else - errno = ENOSYS; - return -1; -#endif } # define bpf missing_bpf @@ -236,28 +112,6 @@ static inline int missing_bpf(int cmd, union bpf_attr *attr, size_t size) { /* ======================================================================= */ -#if !HAVE_STATX -struct statx; - -static inline ssize_t missing_statx(int dfd, const char *filename, unsigned flags, unsigned int mask, struct statx *buffer) { -# ifdef __NR_statx - return syscall(__NR_statx, dfd, filename, flags, mask, buffer); -# else - errno = ENOSYS; - return -1; -# endif -} -#endif - -/* This typedef is supposed to be always defined. */ -typedef struct statx struct_statx; - -#if !HAVE_STATX -# define statx(dfd, filename, flags, mask, buffer) missing_statx(dfd, filename, flags, mask, buffer) -#endif - -/* ======================================================================= */ - #if !HAVE_SET_MEMPOLICY enum { MPOL_DEFAULT, @@ -269,14 +123,7 @@ enum { static inline long missing_set_mempolicy(int mode, const unsigned long *nodemask, unsigned long maxnode) { - long i; -# if defined __NR_set_mempolicy && __NR_set_mempolicy >= 0 - i = syscall(__NR_set_mempolicy, mode, nodemask, maxnode); -# else - errno = ENOSYS; - i = -1; -# endif - return i; + return syscall(__NR_set_mempolicy, mode, nodemask, maxnode); } # define set_mempolicy missing_set_mempolicy @@ -286,14 +133,7 @@ static inline long missing_set_mempolicy(int mode, const unsigned long *nodemask static inline long missing_get_mempolicy(int *mode, unsigned long *nodemask, unsigned long maxnode, void *addr, unsigned long flags) { - long i; -# if defined __NR_get_mempolicy && __NR_get_mempolicy >= 0 - i = syscall(__NR_get_mempolicy, mode, nodemask, maxnode, addr, flags); -# else - errno = ENOSYS; - i = -1; -# endif - return i; + return syscall(__NR_get_mempolicy, mode, nodemask, maxnode, addr, flags); } # define get_mempolicy missing_get_mempolicy @@ -304,6 +144,7 @@ static inline long missing_get_mempolicy(int *mode, unsigned long *nodemask, /* ======================================================================= */ #if !HAVE_PIDFD_SEND_SIGNAL +/* since kernel v5.1 (3eb39f47934f9d5a3027fe00d906a45fe3a15fad) */ static inline int missing_pidfd_send_signal(int fd, int sig, siginfo_t *info, unsigned flags) { return syscall(__NR_pidfd_send_signal, fd, sig, info, flags); } @@ -311,7 +152,10 @@ static inline int missing_pidfd_send_signal(int fd, int sig, siginfo_t *info, un # define pidfd_send_signal missing_pidfd_send_signal #endif +/* ======================================================================= */ + #if !HAVE_PIDFD_OPEN +/* since kernel v5.3 (7615d9e1780e26e0178c93c55b73309a5dc093d7) */ static inline int missing_pidfd_open(pid_t pid, unsigned flags) { return syscall(__NR_pidfd_open, pid, flags); } @@ -321,28 +165,10 @@ static inline int missing_pidfd_open(pid_t pid, unsigned flags) { /* ======================================================================= */ -#if !HAVE_RT_SIGQUEUEINFO -static inline int missing_rt_sigqueueinfo(pid_t tgid, int sig, siginfo_t *info) { -# if defined __NR_rt_sigqueueinfo && __NR_rt_sigqueueinfo >= 0 - return syscall(__NR_rt_sigqueueinfo, tgid, sig, info); -# else -# error "__NR_rt_sigqueueinfo not defined" -# endif -} - -# define rt_sigqueueinfo missing_rt_sigqueueinfo -#endif - -/* ======================================================================= */ - #if 0 /* NM_IGNORED */ #if !HAVE_RT_TGSIGQUEUEINFO static inline int missing_rt_tgsigqueueinfo(pid_t tgid, pid_t tid, int sig, siginfo_t *info) { -# if defined __NR_rt_tgsigqueueinfo && __NR_rt_tgsigqueueinfo >= 0 return syscall(__NR_rt_tgsigqueueinfo, tgid, tid, sig, info); -# else -# error "__NR_rt_tgsigqueueinfo not defined" -# endif } # define rt_tgsigqueueinfo missing_rt_tgsigqueueinfo @@ -351,27 +177,21 @@ static inline int missing_rt_tgsigqueueinfo(pid_t tgid, pid_t tid, int sig, sigi /* ======================================================================= */ #if !HAVE_EXECVEAT +/* since kernel v3.19 (51f39a1f0cea1cacf8c787f652f26dfee9611874) */ static inline int missing_execveat(int dirfd, const char *pathname, char *const argv[], char *const envp[], int flags) { -# if defined __NR_execveat && __NR_execveat >= 0 return syscall(__NR_execveat, dirfd, pathname, argv, envp, flags); -# else - errno = ENOSYS; - return -1; -# endif } -# undef AT_EMPTY_PATH -# define AT_EMPTY_PATH 0x1000 # define execveat missing_execveat #endif /* ======================================================================= */ #if !HAVE_CLOSE_RANGE +/* since kernel v5.9 (9b4feb630e8e9801603f3cab3a36369e3c1cf88d) */ static inline int missing_close_range(unsigned first_fd, unsigned end_fd, unsigned flags) { -# ifdef __NR_close_range /* Kernel-side the syscall expects fds as unsigned integers (just like close() actually), while * userspace exclusively uses signed integers for fds. glibc chose to expose it 1:1 however, hence we * do so here too, even if we end up passing signed fds to it most of the time. */ @@ -379,10 +199,6 @@ static inline int missing_close_range(unsigned first_fd, unsigned end_fd, unsign first_fd, end_fd, flags); -# else - errno = ENOSYS; - return -1; -# endif } # define close_range missing_close_range @@ -390,243 +206,8 @@ static inline int missing_close_range(unsigned first_fd, unsigned end_fd, unsign /* ======================================================================= */ -#if !HAVE_MOUNT_SETATTR - -#if !HAVE_STRUCT_MOUNT_ATTR -struct mount_attr { - uint64_t attr_set; - uint64_t attr_clr; - uint64_t propagation; - uint64_t userns_fd; -}; -#else -struct mount_attr; -#endif - -#ifndef MOUNT_ATTR_RDONLY -#define MOUNT_ATTR_RDONLY 0x00000001 /* Mount read-only */ -#endif - -#ifndef MOUNT_ATTR_NOSUID -#define MOUNT_ATTR_NOSUID 0x00000002 /* Ignore suid and sgid bits */ -#endif - -#ifndef MOUNT_ATTR_NODEV -#define MOUNT_ATTR_NODEV 0x00000004 /* Disallow access to device special files */ -#endif - -#ifndef MOUNT_ATTR_NOEXEC -#define MOUNT_ATTR_NOEXEC 0x00000008 /* Disallow program execution */ -#endif - -#ifndef MOUNT_ATTR__ATIME -#define MOUNT_ATTR__ATIME 0x00000070 /* Setting on how atime should be updated */ -#endif - -#ifndef MOUNT_ATTR_RELATIME -#define MOUNT_ATTR_RELATIME 0x00000000 /* - Update atime relative to mtime/ctime. */ -#endif - -#ifndef MOUNT_ATTR_NOATIME -#define MOUNT_ATTR_NOATIME 0x00000010 /* - Do not update access times. */ -#endif - -#ifndef MOUNT_ATTR_STRICTATIME -#define MOUNT_ATTR_STRICTATIME 0x00000020 /* - Always perform atime updates */ -#endif - -#ifndef MOUNT_ATTR_NODIRATIME -#define MOUNT_ATTR_NODIRATIME 0x00000080 /* Do not update directory access times */ -#endif - -#ifndef MOUNT_ATTR_IDMAP -#define MOUNT_ATTR_IDMAP 0x00100000 /* Idmap mount to @userns_fd in struct mount_attr. */ -#endif - -#ifndef MOUNT_ATTR_NOSYMFOLLOW -#define MOUNT_ATTR_NOSYMFOLLOW 0x00200000 /* Do not follow symlinks */ -#endif - -#ifndef MOUNT_ATTR_SIZE_VER0 -#define MOUNT_ATTR_SIZE_VER0 32 /* sizeof first published struct */ -#endif - -#ifndef AT_RECURSIVE -#define AT_RECURSIVE 0x8000 -#endif - -static inline int missing_mount_setattr( - int dfd, - const char *path, - unsigned flags, - struct mount_attr *attr, - size_t size) { - -# if defined __NR_mount_setattr && __NR_mount_setattr >= 0 - return syscall(__NR_mount_setattr, dfd, path, flags, attr, size); -# else - errno = ENOSYS; - return -1; -# endif -} - -# define mount_setattr missing_mount_setattr -#endif - -/* ======================================================================= */ - -#if !HAVE_OPEN_TREE - -#ifndef OPEN_TREE_CLONE -#define OPEN_TREE_CLONE 1 -#endif - -#ifndef OPEN_TREE_CLOEXEC -#define OPEN_TREE_CLOEXEC O_CLOEXEC -#endif - -static inline int missing_open_tree( - int dfd, - const char *filename, - unsigned flags) { - -# if defined __NR_open_tree && __NR_open_tree >= 0 - return syscall(__NR_open_tree, dfd, filename, flags); -# else - errno = ENOSYS; - return -1; -# endif -} - -# define open_tree missing_open_tree -#endif - -/* ======================================================================= */ - -#ifndef MOVE_MOUNT_BENEATH -#define MOVE_MOUNT_BENEATH 0x00000200 -#endif - -#if !HAVE_MOVE_MOUNT - -#ifndef MOVE_MOUNT_F_EMPTY_PATH -#define MOVE_MOUNT_F_EMPTY_PATH 0x00000004 /* Empty from path permitted */ -#endif - -#ifndef MOVE_MOUNT_T_EMPTY_PATH -#define MOVE_MOUNT_T_EMPTY_PATH 0x00000040 /* Empty to path permitted */ -#endif - -static inline int missing_move_mount( - int from_dfd, - const char *from_pathname, - int to_dfd, - const char *to_pathname, - unsigned flags) { - -# if defined __NR_move_mount && __NR_move_mount >= 0 - return syscall(__NR_move_mount, from_dfd, from_pathname, to_dfd, to_pathname, flags); -# else - errno = ENOSYS; - return -1; -# endif -} - -# define move_mount missing_move_mount -#endif - -/* ======================================================================= */ - -#if !HAVE_FSOPEN - -#ifndef FSOPEN_CLOEXEC -#define FSOPEN_CLOEXEC 0x00000001 -#endif - -static inline int missing_fsopen(const char *fsname, unsigned flags) { -# if defined __NR_fsopen && __NR_fsopen >= 0 - return syscall(__NR_fsopen, fsname, flags); -# else - errno = ENOSYS; - return -1; -# endif -} - -# define fsopen missing_fsopen -#endif - -/* ======================================================================= */ - -#if !HAVE_FSCONFIG - -#ifndef FSCONFIG_SET_FLAG -#define FSCONFIG_SET_FLAG 0 /* Set parameter, supplying no value */ -#endif - -#ifndef FSCONFIG_SET_STRING -#define FSCONFIG_SET_STRING 1 /* Set parameter, supplying a string value */ -#endif - -#ifndef FSCONFIG_SET_FD -#define FSCONFIG_SET_FD 5 /* Set parameter, supplying an object by fd */ -#endif - -#ifndef FSCONFIG_CMD_CREATE -#define FSCONFIG_CMD_CREATE 6 /* Invoke superblock creation */ -#endif - -static inline int missing_fsconfig(int fd, unsigned cmd, const char *key, const void *value, int aux) { -# if defined __NR_fsconfig && __NR_fsconfig >= 0 - return syscall(__NR_fsconfig, fd, cmd, key, value, aux); -# else - errno = ENOSYS; - return -1; -# endif -} - -# define fsconfig missing_fsconfig -#endif - -/* ======================================================================= */ - -#if !HAVE_FSMOUNT - -#ifndef FSMOUNT_CLOEXEC -#define FSMOUNT_CLOEXEC 0x00000001 -#endif - -static inline int missing_fsmount(int fd, unsigned flags, unsigned ms_flags) { -# if defined __NR_fsmount && __NR_fsmount >= 0 - return syscall(__NR_fsmount, fd, flags, ms_flags); -# else - errno = ENOSYS; - return -1; -# endif -} - -# define fsmount missing_fsmount -#endif - -/* ======================================================================= */ - -#if !HAVE_GETDENTS64 - -static inline ssize_t missing_getdents64(int fd, void *buffer, size_t length) { -# if defined __NR_getdents64 && __NR_getdents64 >= 0 - return syscall(__NR_getdents64, fd, buffer, length); -# else - errno = ENOSYS; - return -1; -# endif -} - -# define getdents64 missing_getdents64 -#endif - -/* ======================================================================= */ - #if !HAVE_SCHED_SETATTR - +/* since kernel 3.14 (e6cfc0295c7d51b008999a8b13a44fb43f8685ea) */ static inline ssize_t missing_sched_setattr(pid_t pid, struct sched_attr *attr, unsigned int flags) { return syscall(__NR_sched_setattr, pid, attr, flags); } @@ -653,16 +234,39 @@ int __clone2(int (*fn)(void *), void *stack_base, size_t stack_size, int flags, #if 0 /* NM_IGNORED */ #if !HAVE_QUOTACTL_FD - +/* since kernel v5.14 (64c2c2c62f92339b176ea24403d8db16db36f9e6) */ static inline int missing_quotactl_fd(int fd, int cmd, int id, void *addr) { -#if defined __NR_quotactl_fd return syscall(__NR_quotactl_fd, fd, cmd, id, addr); -#else - errno = ENOSYS; - return -1; -#endif } # define quotactl_fd missing_quotactl_fd #endif + +/* ======================================================================= */ + +#if !HAVE_SETXATTRAT +/* since kernel v6.13 (6140be90ec70c39fa844741ca3cc807dd0866394) */ +struct xattr_args { + _align_(8) uint64_t value; + uint32_t size; + uint32_t flags; +}; + +static inline int missing_setxattrat(int fd, const char *path, int at_flags, const char *name, const struct xattr_args *args, size_t size) { + return syscall(__NR_setxattrat, fd, path, at_flags, name, args, size); +} + +# define setxattrat missing_setxattrat +#endif + +/* ======================================================================= */ + +#if !HAVE_REMOVEXATTRAT +/* since kernel v6.13 (6140be90ec70c39fa844741ca3cc807dd0866394) */ +static inline int missing_removexattrat(int fd, const char *path, int at_flags, const char *name) { + return syscall(__NR_removexattrat, fd, path, at_flags, name); +} + +# define removexattrat missing_removexattrat +#endif #endif /* NM_IGNORED */ diff --git a/src/libnm-systemd-shared/src/basic/missing_threads.h b/src/libnm-systemd-shared/src/basic/missing_threads.h deleted file mode 100644 index c7da1dbd..00000000 --- a/src/libnm-systemd-shared/src/basic/missing_threads.h +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -/* If threads.h doesn't exist, then define our own thread_local to match C11's thread_local. */ -#if HAVE_THREADS_H -# include <threads.h> -#elif !(defined(thread_local)) -# ifndef __STDC_NO_THREADS__ -# define thread_local _Thread_local -# else -# define thread_local __thread -# endif -#endif diff --git a/src/libnm-systemd-shared/src/basic/missing_type.h b/src/libnm-systemd-shared/src/basic/missing_type.h deleted file mode 100644 index 1d17705c..00000000 --- a/src/libnm-systemd-shared/src/basic/missing_type.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -#include <uchar.h> - -#if !HAVE_CHAR32_T -# define char32_t uint32_t -#endif - -#if !HAVE_CHAR16_T -# define char16_t uint16_t -#endif diff --git a/src/libnm-systemd-shared/src/basic/missing_wait.h b/src/libnm-systemd-shared/src/basic/missing_wait.h index 3965b5bd..05648779 100644 --- a/src/libnm-systemd-shared/src/basic/missing_wait.h +++ b/src/libnm-systemd-shared/src/basic/missing_wait.h @@ -5,6 +5,7 @@ #include "macro.h" +/* since glibc-2.36 */ #ifndef P_PIDFD # define P_PIDFD 3 #else diff --git a/src/libnm-systemd-shared/src/basic/mountpoint-util.c b/src/libnm-systemd-shared/src/basic/mountpoint-util.c new file mode 100644 index 00000000..7d7ef5eb --- /dev/null +++ b/src/libnm-systemd-shared/src/basic/mountpoint-util.c @@ -0,0 +1,823 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "nm-sd-adapt-shared.h" + +#include <errno.h> +#include <fcntl.h> +#include <sys/mount.h> + +#include "alloc-util.h" +#include "chase.h" +#include "fd-util.h" +#include "fileio.h" +#include "filesystems.h" +#include "fs-util.h" +#include "log.h" +#include "missing_fcntl.h" +#include "missing_fs.h" +#include "missing_syscall.h" +#include "mkdir.h" +#include "mountpoint-util.h" +#include "nulstr-util.h" +#include "parse-util.h" +#include "path-util.h" +#include "stat-util.h" +#include "stdio-util.h" +#include "strv.h" +#include "user-util.h" + +/* This is the original MAX_HANDLE_SZ definition from the kernel, when the API was introduced. We use that in place of + * any more currently defined value to future-proof things: if the size is increased in the API headers, and our code + * is recompiled then it would cease working on old kernels, as those refuse any sizes larger than this value with + * EINVAL right-away. Hence, let's disconnect ourselves from any such API changes, and stick to the original definition + * from when it was introduced. We use it as a start value only anyway (see below), and hence should be able to deal + * with large file handles anyway. */ +#define ORIGINAL_MAX_HANDLE_SZ 128 + +bool is_name_to_handle_at_fatal_error(int err) { + /* name_to_handle_at() can return "acceptable" errors that are due to the context. For example + * the file system does not support name_to_handle_at() (EOPNOTSUPP), or the syscall was blocked + * (EACCES/EPERM; maybe through seccomp, because we are running inside of a container), or + * the mount point is not triggered yet (EOVERFLOW, think autofs+nfs4), or some general name_to_handle_at() + * flakiness (EINVAL). However other errors are not supposed to happen and therefore are considered + * fatal ones. */ + + assert(err < 0); + + if (ERRNO_IS_NEG_NOT_SUPPORTED(err)) + return false; + if (ERRNO_IS_NEG_PRIVILEGE(err)) + return false; + + return !IN_SET(err, -EOVERFLOW, -EINVAL); +} + +#if 0 /* NM_IGNORED */ +int name_to_handle_at_loop( + int fd, + const char *path, + struct file_handle **ret_handle, + int *ret_mnt_id, + int flags) { + + size_t n = ORIGINAL_MAX_HANDLE_SZ; + + assert(fd >= 0 || fd == AT_FDCWD); + assert((flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH|AT_HANDLE_FID)) == 0); + + /* We need to invoke name_to_handle_at() in a loop, given that it might return EOVERFLOW when the specified + * buffer is too small. Note that in contrast to what the docs might suggest, MAX_HANDLE_SZ is only good as a + * start value, it is not an upper bound on the buffer size required. + * + * This improves on raw name_to_handle_at() also in one other regard: ret_handle and ret_mnt_id can be passed + * as NULL if there's no interest in either. */ + + for (;;) { + _cleanup_free_ struct file_handle *h = NULL; + int mnt_id = -1; + + h = malloc0(offsetof(struct file_handle, f_handle) + n); + if (!h) + return -ENOMEM; + + h->handle_bytes = n; + + if (name_to_handle_at(fd, strempty(path), h, &mnt_id, flags) >= 0) { + + if (ret_handle) + *ret_handle = TAKE_PTR(h); + + if (ret_mnt_id) + *ret_mnt_id = mnt_id; + + return 0; + } + if (errno != EOVERFLOW) + return -errno; + + if (!ret_handle && ret_mnt_id && mnt_id >= 0) { + + /* As it appears, name_to_handle_at() fills in mnt_id even when it returns EOVERFLOW when the + * buffer is too small, but that's undocumented. Hence, let's make use of this if it appears to + * be filled in, and the caller was interested in only the mount ID an nothing else. */ + + *ret_mnt_id = mnt_id; + return 0; + } + + /* If name_to_handle_at() didn't increase the byte size, then this EOVERFLOW is caused by + * something else (apparently EOVERFLOW is returned for untriggered nfs4 autofs mounts + * sometimes), not by the too small buffer. In that case propagate EOVERFLOW */ + if (h->handle_bytes <= n) + return -EOVERFLOW; + + /* The buffer was too small. Size the new buffer by what name_to_handle_at() returned. */ + n = h->handle_bytes; + + /* paranoia: check for overflow (note that .handle_bytes is unsigned only) */ + if (n > UINT_MAX - offsetof(struct file_handle, f_handle)) + return -EOVERFLOW; + } +} + +int name_to_handle_at_try_fid( + int fd, + const char *path, + struct file_handle **ret_handle, + int *ret_mnt_id, + int flags) { + + int r; + + assert(fd >= 0 || fd == AT_FDCWD); + + /* First issues name_to_handle_at() with AT_HANDLE_FID. If this fails and this is not a fatal error + * we'll try without the flag, in order to support older kernels that didn't have AT_HANDLE_FID + * (i.e. older than Linux 6.5). */ + + r = name_to_handle_at_loop(fd, path, ret_handle, ret_mnt_id, flags | AT_HANDLE_FID); + if (r >= 0 || is_name_to_handle_at_fatal_error(r)) + return r; + + return name_to_handle_at_loop(fd, path, ret_handle, ret_mnt_id, flags & ~AT_HANDLE_FID); +} + +static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *ret_mnt_id) { + char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)]; + _cleanup_close_ int subfd = -EBADF; + int r; + + assert((flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH)) == 0); + assert(ret_mnt_id); + + if ((flags & AT_EMPTY_PATH) && isempty(filename)) + xsprintf(path, "/proc/self/fdinfo/%i", fd); + else { + subfd = openat(fd, filename, O_CLOEXEC|O_PATH|(flags & AT_SYMLINK_FOLLOW ? 0 : O_NOFOLLOW)); + if (subfd < 0) + return -errno; + + xsprintf(path, "/proc/self/fdinfo/%i", subfd); + } + + _cleanup_free_ char *p = NULL; + r = get_proc_field(path, "mnt_id", &p); + if (r == -ENOENT) + return -EBADF; + if (r < 0) + return r; + + return safe_atoi(p, ret_mnt_id); +} + +static bool filename_possibly_with_slash_suffix(const char *s) { + const char *slash, *copied; + + /* Checks whether the specified string is either file name, or a filename with a suffix of + * slashes. But nothing else. + * + * this is OK: foo, bar, foo/, bar/, foo//, bar/// + * this is not OK: "", "/", "/foo", "foo/bar", ".", ".." … */ + + slash = strchr(s, '/'); + if (!slash) + return filename_is_valid(s); + + if (slash - s > PATH_MAX) /* We want to allocate on the stack below, hence do a size check first */ + return false; + + if (slash[strspn(slash, "/")] != 0) /* Check that the suffix consist only of one or more slashes */ + return false; + + copied = strndupa_safe(s, slash - s); + return filename_is_valid(copied); +} + +bool file_handle_equal(const struct file_handle *a, const struct file_handle *b) { + if (a == b) + return true; + if (!a != !b) + return false; + if (a->handle_type != b->handle_type) + return false; + + return memcmp_nn(a->f_handle, a->handle_bytes, b->f_handle, b->handle_bytes) == 0; +} + +int is_mount_point_at(int fd, const char *filename, int flags) { + bool fd_is_self; + int r; + + assert(fd >= 0 || fd == AT_FDCWD); + assert((flags & ~AT_SYMLINK_FOLLOW) == 0); + + if (isempty(filename)) { + if (fd == AT_FDCWD) + filename = "."; + else { + /* If the file name is empty we'll see if the specified 'fd' is a mount point. + * That's only supported by statx(), or if the inode specified via 'fd' refers to a + * directory. Otherwise, we'll have to fail (ENOTDIR), because we have no kernel API + * to query the information we need. */ + flags |= AT_EMPTY_PATH; + filename = ""; + } + + fd_is_self = true; + } else if (STR_IN_SET(filename, ".", "./")) + fd_is_self = true; + else { + /* Insist that the specified filename is actually a filename, and not a path, i.e. some inode + * further up or down the tree then immediately below the specified directory fd. */ + if (!filename_possibly_with_slash_suffix(filename)) + return -EINVAL; + + fd_is_self = false; + } + + /* First we will try statx()' STATX_ATTR_MOUNT_ROOT attribute, which is our ideal API, available + * since kernel 5.8. + * + * If that fails, our second try is the name_to_handle_at() syscall, which tells us the mount id and + * an opaque file "handle". It is not supported everywhere though (kernel compile-time option, not + * all file systems are hooked up). If it works the mount id is usually good enough to tell us + * whether something is a mount point. + * + * If that didn't work we will try to read the mount id from /proc/self/fdinfo/<fd>. This is almost + * as good as name_to_handle_at(), however, does not return the opaque file handle. The opaque file + * handle is pretty useful to detect the root directory, which we should always consider a mount + * point. Hence we use this only as fallback. + * + * Note that traditionally the check is done via fstat()-based st_dev comparisons. However, various + * file systems don't guarantee same st_dev across single fs anymore, e.g. unionfs exposes file systems + * with a variety of st_dev reported. Also, btrfs subvolumes have different st_dev, even though + * they aren't real mounts of their own. */ + + struct statx sx = {}; /* explicitly initialize the struct to make msan silent. */ + if (statx(fd, filename, + at_flags_normalize_nofollow(flags) | + AT_NO_AUTOMOUNT | /* don't trigger automounts – mounts are a local concept, hence no need to trigger automounts to determine STATX_ATTR_MOUNT_ROOT */ + AT_STATX_DONT_SYNC, /* don't go to the network for this – for similar reasons */ + STATX_TYPE, + &sx) < 0) + return -errno; + + if (FLAGS_SET(sx.stx_attributes_mask, STATX_ATTR_MOUNT_ROOT)) /* yay! */ + return FLAGS_SET(sx.stx_attributes, STATX_ATTR_MOUNT_ROOT); + + _cleanup_free_ struct file_handle *h = NULL, *h_parent = NULL; + int mount_id = -1, mount_id_parent = -1; + bool nosupp = false; + + r = name_to_handle_at_try_fid(fd, filename, &h, &mount_id, flags); + if (r < 0) { + if (is_name_to_handle_at_fatal_error(r)) + return r; + if (!ERRNO_IS_NOT_SUPPORTED(r)) + goto fallback_fdinfo; + + /* This file system does not support name_to_handle_at(), hence let's see if the upper fs + * supports it (in which case it is a mount point), otherwise fall back to the fdinfo logic. */ + nosupp = true; + } + + if (fd_is_self) + r = name_to_handle_at_try_fid(fd, "..", &h_parent, &mount_id_parent, 0); /* can't work for non-directories 😢 */ + else + r = name_to_handle_at_try_fid(fd, "", &h_parent, &mount_id_parent, AT_EMPTY_PATH); + if (r < 0) { + if (is_name_to_handle_at_fatal_error(r)) + return r; + if (!ERRNO_IS_NOT_SUPPORTED(r)) + goto fallback_fdinfo; + if (nosupp) + /* Both the parent and the directory can't do name_to_handle_at() */ + goto fallback_fdinfo; + + /* The parent can't do name_to_handle_at() but the directory we are + * interested in can? If so, it must be a mount point. */ + return 1; + } + + /* The parent can do name_to_handle_at() but the directory we are interested in can't? If + * so, it must be a mount point. */ + if (nosupp) + return 1; + + /* If the file handle for the directory we are interested in and its parent are identical, + * we assume this is the root directory, which is a mount point. */ + if (file_handle_equal(h_parent, h)) + return 1; + + return mount_id != mount_id_parent; + +fallback_fdinfo: + r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id); + if (r < 0) + return r; + + if (fd_is_self) + r = fd_fdinfo_mnt_id(fd, "..", 0, &mount_id_parent); /* can't work for non-directories 😢 */ + else + r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent); + if (r < 0) + return r; + + if (mount_id != mount_id_parent) + return 1; + + /* Hmm, so, the mount ids are the same. This leaves one special case though for the root file + * system. For that, let's see if the parent directory has the same inode as we are interested + * in. */ + + struct stat a, b; + + /* yay for fstatat() taking a different set of flags than the other _at() above */ + if (fstatat(fd, filename, &a, at_flags_normalize_nofollow(flags)) < 0) + return -errno; + + if (fd_is_self) + r = fstatat(fd, "..", &b, 0); + else + r = fstatat(fd, "", &b, AT_EMPTY_PATH); + if (r < 0) + return -errno; + + /* A directory with same device and inode as its parent must be the root directory. Otherwise + * not a mount point. + * + * NB: we avoid inode_same_at() here because it internally attempts name_to_handle_at_try_fid() first, + * which is redundant. */ + return stat_inode_same(&a, &b); +} + +/* flags can be AT_SYMLINK_FOLLOW or 0 */ +int path_is_mount_point_full(const char *path, const char *root, int flags) { + _cleanup_close_ int dfd = -EBADF; + _cleanup_free_ char *fn = NULL; + + assert(path); + assert((flags & ~AT_SYMLINK_FOLLOW) == 0); + + if (path_equal(path, "/")) + return 1; + + /* we need to resolve symlinks manually, we can't just rely on is_mount_point_at() to do that for us; + * if we have a structure like /bin -> /usr/bin/ and /usr is a mount point, then the parent that we + * look at needs to be /usr, not /. */ + dfd = chase_and_open_parent(path, root, + CHASE_TRAIL_SLASH|(FLAGS_SET(flags, AT_SYMLINK_FOLLOW) ? 0 : CHASE_NOFOLLOW), + &fn); + if (dfd < 0) + return dfd; + + return is_mount_point_at(dfd, fn, flags); +} + +int path_get_mnt_id_at_fallback(int dir_fd, const char *path, int *ret) { + int r; + + assert(dir_fd >= 0 || dir_fd == AT_FDCWD); + assert(ret); + + r = name_to_handle_at_loop(dir_fd, path, NULL, ret, isempty(path) ? AT_EMPTY_PATH : 0); + if (r >= 0 || is_name_to_handle_at_fatal_error(r)) + return r; + + return fd_fdinfo_mnt_id(dir_fd, path, isempty(path) ? AT_EMPTY_PATH : 0, ret); +} + +int path_get_mnt_id_at(int dir_fd, const char *path, int *ret) { + struct statx sx; + + assert(dir_fd >= 0 || dir_fd == AT_FDCWD); + assert(ret); + + if (statx(dir_fd, + strempty(path), + (isempty(path) ? AT_EMPTY_PATH : AT_SYMLINK_NOFOLLOW) | + AT_NO_AUTOMOUNT | /* don't trigger automounts, mnt_id is a local concept */ + AT_STATX_DONT_SYNC, /* don't go to the network, mnt_id is a local concept */ + STATX_MNT_ID, + &sx) < 0) + return -errno; + + if (FLAGS_SET(sx.stx_mask, STATX_MNT_ID)) { + *ret = sx.stx_mnt_id; + return 0; + } + + return path_get_mnt_id_at_fallback(dir_fd, path, ret); +} + +bool fstype_is_network(const char *fstype) { + const char *x; + + x = startswith(fstype, "fuse."); + if (x) + fstype = x; + + if (nulstr_contains(filesystem_sets[FILESYSTEM_SET_NETWORK].value, fstype)) + return true; + + /* Filesystems not present in the internal database */ + return STR_IN_SET(fstype, + "davfs", + "glusterfs", + "lustre", + "sshfs"); +} + +bool fstype_needs_quota(const char *fstype) { + /* 1. quotacheck needs to be run for some filesystems after they are mounted + * if the filesystem was not unmounted cleanly. + * 2. You may need to run quotaon to enable quota usage tracking and/or + * enforcement. + * ext2 - needs 1) and 2) + * ext3 - needs 2) if configured using usrjquota/grpjquota mount options + * ext4 - needs 1) if created without journal, needs 2) if created without QUOTA + * filesystem feature + * reiserfs - needs 2). + * jfs - needs 2) + * f2fs - needs 2) if configured using usrjquota/grpjquota/prjjquota mount options + * xfs - nothing needed + * gfs2 - nothing needed + * ocfs2 - nothing needed + * btrfs - nothing needed + * for reference see filesystem and quota manpages */ + return STR_IN_SET(fstype, + "ext2", + "ext3", + "ext4", + "reiserfs", + "jfs", + "f2fs"); +} + +bool fstype_is_api_vfs(const char *fstype) { + assert(fstype); + + const FilesystemSet *fs; + FOREACH_ARGUMENT(fs, + filesystem_sets + FILESYSTEM_SET_BASIC_API, + filesystem_sets + FILESYSTEM_SET_AUXILIARY_API, + filesystem_sets + FILESYSTEM_SET_PRIVILEGED_API, + filesystem_sets + FILESYSTEM_SET_TEMPORARY) + if (nulstr_contains(fs->value, fstype)) + return true; + + /* Filesystems not present in the internal database */ + return STR_IN_SET(fstype, + "autofs", + "cpuset", + "devtmpfs"); +} + +bool fstype_is_blockdev_backed(const char *fstype) { + const char *x; + + x = startswith(fstype, "fuse."); + if (x) + fstype = x; + + return !streq(fstype, "9p") && !fstype_is_network(fstype) && !fstype_is_api_vfs(fstype); +} + +bool fstype_is_ro(const char *fstype) { + /* All Linux file systems that are necessarily read-only */ + return STR_IN_SET(fstype, + "DM_verity_hash", + "cramfs", + "erofs", + "iso9660", + "squashfs"); +} + +bool fstype_can_discard(const char *fstype) { + assert(fstype); + + /* Use a curated list as first check, to avoid calling fsopen() which might load kmods, which might + * not be allowed in our MAC context. */ + if (STR_IN_SET(fstype, "btrfs", "f2fs", "ext4", "vfat", "xfs")) + return true; + + /* On new kernels we can just ask the kernel */ + return mount_option_supported(fstype, "discard", NULL) > 0; +} + +const char* fstype_norecovery_option(const char *fstype) { + int r; + + assert(fstype); + + /* Use a curated list as first check, to avoid calling fsopen() which might load kmods, which might + * not be allowed in our MAC context. */ + if (STR_IN_SET(fstype, "ext3", "ext4", "xfs")) + return "norecovery"; + + /* btrfs dropped support for the "norecovery" option in 6.8 + * (https://github.com/torvalds/linux/commit/a1912f712188291f9d7d434fba155461f1ebef66) and replaced + * it with rescue=nologreplay, so we check for the new name first and fall back to checking for the + * old name if the new name doesn't work. */ + if (streq(fstype, "btrfs")) { + r = mount_option_supported(fstype, "rescue=nologreplay", NULL); + if (r == -EAGAIN) { + log_debug_errno(r, "Failed to check for btrfs 'rescue=nologreplay' option, assuming old kernel with 'norecovery': %m"); + return "norecovery"; + } + if (r < 0) + log_debug_errno(r, "Failed to check for btrfs 'rescue=nologreplay' option, assuming it is not supported: %m"); + if (r > 0) + return "rescue=nologreplay"; + } + + /* On new kernels we can just ask the kernel */ + return mount_option_supported(fstype, "norecovery", NULL) > 0 ? "norecovery" : NULL; +} + +bool fstype_can_fmask_dmask(const char *fstype) { + assert(fstype); + + /* Use a curated list as first check, to avoid calling fsopen() which might load kmods, which might + * not be allowed in our MAC context. If we don't know ourselves, on new kernels we can just ask the + * kernel. */ + return streq(fstype, "vfat") || (mount_option_supported(fstype, "fmask", "0177") > 0 && mount_option_supported(fstype, "dmask", "0077") > 0); +} + +bool fstype_can_uid_gid(const char *fstype) { + /* All file systems that have a uid=/gid= mount option that fixates the owners of all files and + * directories, current and future. Note that this does *not* ask the kernel via + * mount_option_supported() here because the uid=/gid= setting of various file systems mean different + * things: some apply it only to the root dir inode, others to all inodes in the file system. Thus we + * maintain the curated list below. 😢 */ + + return STR_IN_SET(fstype, + "adfs", + "exfat", + "fat", + "hfs", + "hpfs", + "iso9660", + "msdos", + "ntfs", + "vfat"); +} + +int dev_is_devtmpfs(void) { + _cleanup_fclose_ FILE *proc_self_mountinfo = NULL; + int mount_id, r; + char *e; + + r = path_get_mnt_id("/dev", &mount_id); + if (r < 0) + return r; + + r = fopen_unlocked("/proc/self/mountinfo", "re", &proc_self_mountinfo); + if (r == -ENOENT) + return proc_mounted() > 0 ? -ENOENT : -ENOSYS; + if (r < 0) + return r; + + for (;;) { + _cleanup_free_ char *line = NULL; + int mid; + + r = read_line(proc_self_mountinfo, LONG_LINE_MAX, &line); + if (r < 0) + return r; + if (r == 0) + break; + + if (sscanf(line, "%i", &mid) != 1) + continue; + + if (mid != mount_id) + continue; + + e = strstrafter(line, " - "); + if (!e) + continue; + + /* accept any name that starts with the currently expected type */ + if (startswith(e, "devtmpfs")) + return true; + } + + return false; +} + +static int mount_fd( + const char *source, + int target_fd, + const char *filesystemtype, + unsigned long mountflags, + const void *data) { + + assert(target_fd >= 0); + + if (mount(source, FORMAT_PROC_FD_PATH(target_fd), filesystemtype, mountflags, data) < 0) { + if (errno != ENOENT) + return -errno; + + /* ENOENT can mean two things: either that the source is missing, or that /proc/ isn't + * mounted. Check for the latter to generate better error messages. */ + if (proc_mounted() == 0) + return -ENOSYS; + + return -ENOENT; + } + + return 0; +} + +int mount_nofollow( + const char *source, + const char *target, + const char *filesystemtype, + unsigned long mountflags, + const void *data) { + + _cleanup_close_ int fd = -EBADF; + + assert(target); + + /* In almost all cases we want to manipulate the mount table without following symlinks, hence + * mount_nofollow() is usually the way to go. The only exceptions are environments where /proc/ is + * not available yet, since we need /proc/self/fd/ for this logic to work. i.e. during the early + * initialization of namespacing/container stuff where /proc is not yet mounted (and maybe even the + * fs to mount) we can only use traditional mount() directly. + * + * Note that this disables following only for the final component of the target, i.e symlinks within + * the path of the target are honoured, as are symlinks in the source path everywhere. */ + + fd = open(target, O_PATH|O_CLOEXEC|O_NOFOLLOW); + if (fd < 0) + return -errno; + + return mount_fd(source, fd, filesystemtype, mountflags, data); +} + +const char* mount_propagation_flag_to_string(unsigned long flags) { + + switch (flags & (MS_SHARED|MS_SLAVE|MS_PRIVATE)) { + case 0: + return ""; + case MS_SHARED: + return "shared"; + case MS_SLAVE: + return "slave"; + case MS_PRIVATE: + return "private"; + } + + return NULL; +} + +int mount_propagation_flag_from_string(const char *name, unsigned long *ret) { + + if (isempty(name)) + *ret = 0; + else if (streq(name, "shared")) + *ret = MS_SHARED; + else if (streq(name, "slave")) + *ret = MS_SLAVE; + else if (streq(name, "private")) + *ret = MS_PRIVATE; + else + return -EINVAL; + return 0; +} + +bool mount_propagation_flag_is_valid(unsigned long flag) { + return IN_SET(flag, 0, MS_SHARED, MS_PRIVATE, MS_SLAVE); +} + +bool mount_new_api_supported(void) { + static int cache = -1; + int r; + + if (cache >= 0) + return cache; + + /* This is the newer API among the ones we use, so use it as boundary */ + r = RET_NERRNO(mount_setattr(-EBADF, NULL, 0, NULL, 0)); + if (r == 0 || ERRNO_IS_NOT_SUPPORTED(r)) /* This should return an error if it is working properly */ + return (cache = false); + + return (cache = true); +} + +unsigned long ms_nosymfollow_supported(void) { + _cleanup_close_ int fsfd = -EBADF, mntfd = -EBADF; + static int cache = -1; + + /* Returns MS_NOSYMFOLLOW if it is supported, zero otherwise. */ + + if (cache >= 0) + return cache ? MS_NOSYMFOLLOW : 0; + + if (!mount_new_api_supported()) + goto not_supported; + + /* Checks if MS_NOSYMFOLLOW is supported (which was added in 5.10). We use the new mount API's + * mount_setattr() call for that, which was added in 5.12, which is close enough. */ + + fsfd = fsopen("tmpfs", FSOPEN_CLOEXEC); + if (fsfd < 0) { + if (ERRNO_IS_NOT_SUPPORTED(errno)) + goto not_supported; + + log_debug_errno(errno, "Failed to open superblock context for tmpfs: %m"); + return 0; + } + + if (fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0) < 0) { + if (ERRNO_IS_NOT_SUPPORTED(errno)) + goto not_supported; + + log_debug_errno(errno, "Failed to create tmpfs superblock: %m"); + return 0; + } + + mntfd = fsmount(fsfd, FSMOUNT_CLOEXEC, 0); + if (mntfd < 0) { + if (ERRNO_IS_NOT_SUPPORTED(errno)) + goto not_supported; + + log_debug_errno(errno, "Failed to turn superblock fd into mount fd: %m"); + return 0; + } + + if (mount_setattr(mntfd, "", AT_EMPTY_PATH|AT_RECURSIVE, + &(struct mount_attr) { + .attr_set = MOUNT_ATTR_NOSYMFOLLOW, + }, sizeof(struct mount_attr)) < 0) { + if (ERRNO_IS_NOT_SUPPORTED(errno)) + goto not_supported; + + log_debug_errno(errno, "Failed to set MOUNT_ATTR_NOSYMFOLLOW mount attribute: %m"); + return 0; + } + + cache = true; + return MS_NOSYMFOLLOW; + +not_supported: + cache = false; + return 0; +} + +int mount_option_supported(const char *fstype, const char *key, const char *value) { + _cleanup_close_ int fd = -EBADF; + int r; + + /* Checks if the specified file system supports a mount option. Returns > 0 if it supports it, == 0 if + * it does not. Return -EAGAIN if we can't determine it. And any other error otherwise. */ + + assert(fstype); + assert(key); + + fd = fsopen(fstype, FSOPEN_CLOEXEC); + if (fd < 0) + return log_debug_errno(errno, "Failed to open superblock context for '%s': %m", fstype); + + /* Various file systems support fs context only in recent kernels (e.g. btrfs). For older kernels + * fsconfig() with FSCONFIG_SET_STRING/FSCONFIG_SET_FLAG never fail. Which sucks, because we want to + * use it for testing support, after all. Let's hence do a check if the file system got converted yet + * first. */ + if (fsconfig(fd, FSCONFIG_SET_FD, "adefinitelynotexistingmountoption", NULL, fd) < 0) { + /* If FSCONFIG_SET_FD is not supported for the fs, then the file system was not converted to + * the new mount API yet. If it returns EINVAL the mount option doesn't exist, but the fstype + * is converted. */ + if (errno == EOPNOTSUPP) + return -EAGAIN; /* fs not converted to new mount API → don't know */ + if (errno != EINVAL) + return log_debug_errno(errno, "Failed to check if file system '%s' has been converted to new mount API: %m", fstype); + + /* So FSCONFIG_SET_FD worked, but the option didn't exist (we got EINVAL), this means the fs + * is converted. Let's now ask the actual question we wonder about. */ + } else + return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN), "FSCONFIG_SET_FD worked unexpectedly for '%s', whoa!", fstype); + + if (value) + r = fsconfig(fd, FSCONFIG_SET_STRING, key, value, 0); + else + r = fsconfig(fd, FSCONFIG_SET_FLAG, key, NULL, 0); + if (r < 0) { + if (errno == EINVAL) + return false; /* EINVAL means option not supported. */ + + return log_debug_errno(errno, "Failed to set '%s%s%s' on '%s' superblock context: %m", + key, value ? "=" : "", strempty(value), fstype); + } + + return true; /* works! */ +} + +bool path_below_api_vfs(const char *p) { + assert(p); + + /* API VFS are either directly mounted on any of these three paths, or below it. */ + return PATH_STARTSWITH_SET(p, "/dev", "/sys", "/proc"); +} +#endif /* NM_IGNORED */ \ No newline at end of file diff --git a/src/libnm-systemd-shared/src/basic/mountpoint-util.h b/src/libnm-systemd-shared/src/basic/mountpoint-util.h new file mode 100644 index 00000000..43e47581 --- /dev/null +++ b/src/libnm-systemd-shared/src/basic/mountpoint-util.h @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include <fcntl.h> +#include <stdbool.h> +#include <stddef.h> +#include <sys/types.h> + +/* The limit used for /dev itself. 4MB should be enough since device nodes and symlinks don't + * consume any space and udev isn't supposed to create regular file either. There's no limit on the + * max number of inodes since such limit is hard to guess especially on large storage array + * systems. */ +#define TMPFS_LIMITS_DEV ",size=4m" + +/* The limit used for /dev in private namespaces. 4MB for contents of regular files. The number of + * inodes should be relatively low in private namespaces but for now use a 64k limit. */ +#define TMPFS_LIMITS_PRIVATE_DEV ",size=4m,nr_inodes=64k" + +/* Very little, if any use expected */ +#define TMPFS_LIMITS_EMPTY_OR_ALMOST ",size=4m,nr_inodes=1k" +#define TMPFS_LIMITS_SYS TMPFS_LIMITS_EMPTY_OR_ALMOST +#define TMPFS_LIMITS_SYS_FS_CGROUP TMPFS_LIMITS_EMPTY_OR_ALMOST + +/* On an extremely small device with only 256MB of RAM, 20% of RAM should be enough for the re-execution of + * PID1 because 16MB of free space is required. */ +#define TMPFS_LIMITS_RUN ",size=20%,nr_inodes=800k" + +/* The limit used for various nested tmpfs mounts, in particular for guests started by systemd-nspawn. + * 10% of RAM (using 16GB of RAM as a baseline) translates to 400k inodes (assuming 4k each) and 25% + * translates to 1M inodes. + * (On the host, /tmp is configured through a .mount unit file.) */ +#define NESTED_TMPFS_LIMITS ",size=10%,nr_inodes=400k" + +/* More space for volatile root and /var */ +#define TMPFS_LIMITS_VAR ",size=25%,nr_inodes=1m" +#define TMPFS_LIMITS_ROOTFS TMPFS_LIMITS_VAR +#define TMPFS_LIMITS_VOLATILE_STATE TMPFS_LIMITS_VAR + +bool is_name_to_handle_at_fatal_error(int err); + +int name_to_handle_at_loop(int fd, const char *path, struct file_handle **ret_handle, int *ret_mnt_id, int flags); +int name_to_handle_at_try_fid(int fd, const char *path, struct file_handle **ret_handle, int *ret_mnt_id, int flags); + +bool file_handle_equal(const struct file_handle *a, const struct file_handle *b); + +int path_get_mnt_id_at_fallback(int dir_fd, const char *path, int *ret); +int path_get_mnt_id_at(int dir_fd, const char *path, int *ret); +static inline int path_get_mnt_id(const char *path, int *ret) { + return path_get_mnt_id_at(AT_FDCWD, path, ret); +} + +int is_mount_point_at(int fd, const char *filename, int flags); +int path_is_mount_point_full(const char *path, const char *root, int flags); +static inline int path_is_mount_point(const char *path) { + return path_is_mount_point_full(path, NULL, 0); +} + +bool fstype_is_network(const char *fstype); +bool fstype_needs_quota(const char *fstype); +bool fstype_is_api_vfs(const char *fstype); +bool fstype_is_blockdev_backed(const char *fstype); +bool fstype_is_ro(const char *fsype); +bool fstype_can_discard(const char *fstype); +bool fstype_can_uid_gid(const char *fstype); +bool fstype_can_fmask_dmask(const char *fstype); + +const char* fstype_norecovery_option(const char *fstype); + +int dev_is_devtmpfs(void); + +int mount_nofollow( + const char *source, + const char *target, + const char *filesystemtype, + unsigned long mountflags, + const void *data); + +const char* mount_propagation_flag_to_string(unsigned long flags); +int mount_propagation_flag_from_string(const char *name, unsigned long *ret); +bool mount_propagation_flag_is_valid(unsigned long flag); + +bool mount_new_api_supported(void); +unsigned long ms_nosymfollow_supported(void); + +int mount_option_supported(const char *fstype, const char *key, const char *value); + +bool path_below_api_vfs(const char *p); diff --git a/src/libnm-systemd-shared/src/basic/namespace-util.h b/src/libnm-systemd-shared/src/basic/namespace-util.h index 3d40a515..d7ac8156 100644 --- a/src/libnm-systemd-shared/src/basic/namespace-util.h +++ b/src/libnm-systemd-shared/src/basic/namespace-util.h @@ -28,6 +28,8 @@ extern const struct namespace_info { NamespaceType clone_flag_to_namespace_type(unsigned long clone_flag); +bool namespace_type_supported(NamespaceType type); + int pidref_namespace_open_by_type(const PidRef *pidref, NamespaceType type); int namespace_open_by_type(NamespaceType type); @@ -86,7 +88,8 @@ static inline bool userns_shift_range_valid(uid_t shift, uid_t range) { int parse_userns_uid_range(const char *s, uid_t *ret_uid_shift, uid_t *ret_uid_range); int userns_acquire_empty(void); -int userns_acquire(const char *uid_map, const char *gid_map); +int userns_acquire(const char *uid_map, const char *gid_map, bool setgroups_deny); +int userns_acquire_self_root(void); int userns_enter_and_pin(int userns_fd, pid_t *ret_pid); int userns_get_base_uid(int userns_fd, uid_t *ret_uid, gid_t *ret_gid); diff --git a/src/libnm-systemd-shared/src/basic/ordered-set.h b/src/libnm-systemd-shared/src/basic/ordered-set.h index e73da205..b7113ad9 100644 --- a/src/libnm-systemd-shared/src/basic/ordered-set.h +++ b/src/libnm-systemd-shared/src/basic/ordered-set.h @@ -22,18 +22,10 @@ static inline void ordered_set_clear(OrderedSet *s) { return ordered_hashmap_clear((OrderedHashmap*) s); } -static inline void ordered_set_clear_free(OrderedSet *s) { - return ordered_hashmap_clear_free((OrderedHashmap*) s); -} - static inline OrderedSet* ordered_set_free(OrderedSet *s) { return (OrderedSet*) ordered_hashmap_free((OrderedHashmap*) s); } -static inline OrderedSet* ordered_set_free_free(OrderedSet *s) { - return (OrderedSet*) ordered_hashmap_free_free((OrderedHashmap*) s); -} - static inline int ordered_set_contains(OrderedSet *s, const void *p) { return ordered_hashmap_contains((OrderedHashmap*) s, p); } @@ -91,19 +83,6 @@ void ordered_set_print(FILE *f, const char *field, OrderedSet *s); #define ORDERED_SET_FOREACH(e, s) \ _ORDERED_SET_FOREACH(e, s, UNIQ_T(i, UNIQ)) -#define ordered_set_clear_with_destructor(s, f) \ - ({ \ - OrderedSet *_s = (s); \ - void *_item; \ - while ((_item = ordered_set_steal_first(_s))) \ - f(_item); \ - _s; \ - }) -#define ordered_set_free_with_destructor(s, f) \ - ordered_set_free(ordered_set_clear_with_destructor(s, f)) - DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedSet*, ordered_set_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedSet*, ordered_set_free_free); #define _cleanup_ordered_set_free_ _cleanup_(ordered_set_freep) -#define _cleanup_ordered_set_free_free_ _cleanup_(ordered_set_free_freep) diff --git a/src/libnm-systemd-shared/src/basic/parse-util.c b/src/libnm-systemd-shared/src/basic/parse-util.c index bff09b74..e524d9d5 100644 --- a/src/libnm-systemd-shared/src/basic/parse-util.c +++ b/src/libnm-systemd-shared/src/basic/parse-util.c @@ -5,6 +5,7 @@ #include <errno.h> #include <inttypes.h> #include <linux/ipv6.h> +#include <linux/netfilter/nf_tables.h> #include <net/if.h> #include <stdio.h> #include <stdlib.h> @@ -14,6 +15,7 @@ #include "errno-list.h" #include "extract-word.h" #include "locale-util.h" +#include "log.h" #include "macro.h" #include "missing_network.h" #include "parse-util.h" @@ -533,7 +535,7 @@ int safe_atollu_full(const char *s, unsigned base, unsigned long long *ret_llu) return 0; } -int safe_atolli(const char *s, long long int *ret_lli) { +int safe_atolli(const char *s, long long *ret_lli) { unsigned base = 0; char *x = NULL; long long l; @@ -784,19 +786,15 @@ int parse_loadavg_fixed_point(const char *s, loadavg_t *ret) { /* Limitations are described in https://www.netfilter.org/projects/nftables/manpage.html and * https://bugzilla.netfilter.org/show_bug.cgi?id=1175 */ bool nft_identifier_valid(const char *id) { - if (!id) + if (isempty(id)) return false; - size_t len = strlen(id); - if (len == 0 || len > 31) + if (strlen(id) >= NFT_NAME_MAXLEN) return false; if (!ascii_isalpha(id[0])) return false; - for (size_t i = 1; i < len; i++) - if (!ascii_isalpha(id[i]) && !ascii_isdigit(id[i]) && !IN_SET(id[i], '/', '\\', '_', '.')) - return false; - return true; + return in_charset(id + 1, ALPHANUMERICAL "/\\_."); } #endif /* NM_IGNORED */ diff --git a/src/libnm-systemd-shared/src/basic/parse-util.h b/src/libnm-systemd-shared/src/basic/parse-util.h index a47c8c79..0af407b3 100644 --- a/src/libnm-systemd-shared/src/basic/parse-util.h +++ b/src/libnm-systemd-shared/src/basic/parse-util.h @@ -41,7 +41,7 @@ static inline int safe_atou(const char *s, unsigned *ret_u) { int safe_atou_bounded(const char *s, unsigned min, unsigned max, unsigned *ret); int safe_atoi(const char *s, int *ret_i); -int safe_atolli(const char *s, long long int *ret_i); +int safe_atolli(const char *s, long long *ret_i); int safe_atou8_full(const char *s, unsigned base, uint8_t *ret); @@ -87,8 +87,8 @@ static inline int safe_atou64(const char *s, uint64_t *ret_u) { } static inline int safe_atoi64(const char *s, int64_t *ret_i) { - assert_cc(sizeof(int64_t) == sizeof(long long int)); - return safe_atolli(s, (long long int*) ret_i); + assert_cc(sizeof(int64_t) == sizeof(long long)); + return safe_atolli(s, (long long*) ret_i); } static inline int safe_atoux64(const char *s, uint64_t *ret) { @@ -101,8 +101,8 @@ static inline int safe_atolu_full(const char *s, unsigned base, unsigned long *r assert_cc(sizeof(unsigned long) == sizeof(unsigned)); return safe_atou_full(s, base, (unsigned*) ret_u); } -static inline int safe_atoli(const char *s, long int *ret_u) { - assert_cc(sizeof(long int) == sizeof(int)); +static inline int safe_atoli(const char *s, long *ret_u) { + assert_cc(sizeof(long) == sizeof(int)); return safe_atoi(s, (int*) ret_u); } #else @@ -110,9 +110,9 @@ static inline int safe_atolu_full(const char *s, unsigned base, unsigned long *r assert_cc(sizeof(unsigned long) == sizeof(unsigned long long)); return safe_atollu_full(s, base, (unsigned long long*) ret_u); } -static inline int safe_atoli(const char *s, long int *ret_u) { - assert_cc(sizeof(long int) == sizeof(long long int)); - return safe_atolli(s, (long long int*) ret_u); +static inline int safe_atoli(const char *s, long *ret_u) { + assert_cc(sizeof(long) == sizeof(long long)); + return safe_atolli(s, (long long*) ret_u); } #endif diff --git a/src/libnm-systemd-shared/src/basic/path-util.c b/src/libnm-systemd-shared/src/basic/path-util.c index 1de055d5..74f256a6 100644 --- a/src/libnm-systemd-shared/src/basic/path-util.c +++ b/src/libnm-systemd-shared/src/basic/path-util.c @@ -624,37 +624,9 @@ char* path_extend_internal(char **x, ...) { } #if 0 /* NM_IGNORED */ -static int check_x_access(const char *path, int *ret_fd) { +int open_and_check_executable(const char *name, const char *root, char **ret_path, int *ret_fd) { _cleanup_close_ int fd = -EBADF; - int r; - - /* We need to use O_PATH because there may be executables for which we have only exec - * permissions, but not read (usually suid executables). */ - fd = open(path, O_PATH|O_CLOEXEC); - if (fd < 0) - return -errno; - - r = fd_verify_regular(fd); - if (r < 0) - return r; - - r = access_fd(fd, X_OK); - if (r == -ENOSYS) { - /* /proc is not mounted. Fallback to access(). */ - if (access(path, X_OK) < 0) - return -errno; - } else if (r < 0) - return r; - - if (ret_fd) - *ret_fd = TAKE_FD(fd); - - return 0; -} - -static int find_executable_impl(const char *name, const char *root, char **ret_filename, int *ret_fd) { - _cleanup_close_ int fd = -EBADF; - _cleanup_free_ char *path_name = NULL; + _cleanup_free_ char *resolved = NULL; int r; assert(name); @@ -665,23 +637,40 @@ static int find_executable_impl(const char *name, const char *root, char **ret_f * needed to avoid unforeseen regression or other complicated changes. */ if (root) { /* prefix root to name in case full paths are not specified */ - r = chase(name, root, CHASE_PREFIX_ROOT, &path_name, /* ret_fd= */ NULL); + r = chase(name, root, CHASE_PREFIX_ROOT, &resolved, &fd); if (r < 0) return r; - name = path_name; + name = resolved; + } else { + /* We need to use O_PATH because there may be executables for which we have only exec permissions, + * but not read (usually suid executables). */ + fd = open(name, O_PATH|O_CLOEXEC); + if (fd < 0) + return -errno; } - r = check_x_access(name, ret_fd ? &fd : NULL); + r = fd_verify_regular(fd); if (r < 0) return r; - if (ret_filename) { - r = path_make_absolute_cwd(name, ret_filename); - if (r < 0) - return r; + r = access_fd(fd, X_OK); + if (r == -ENOSYS) + /* /proc/ is not mounted. Fall back to access(). */ + r = RET_NERRNO(access(name, X_OK)); + if (r < 0) + return r; - path_simplify(*ret_filename); + if (ret_path) { + if (resolved) + *ret_path = TAKE_PTR(resolved); + else { + r = path_make_absolute_cwd(name, ret_path); + if (r < 0) + return r; + + path_simplify(*ret_path); + } } if (ret_fd) @@ -703,7 +692,7 @@ int find_executable_full( assert(name); if (is_path(name)) - return find_executable_impl(name, root, ret_filename, ret_fd); + return open_and_check_executable(name, root, ret_filename, ret_fd); if (exec_search_path) { STRV_FOREACH(element, exec_search_path) { @@ -718,7 +707,7 @@ int find_executable_full( if (!full_path) return -ENOMEM; - r = find_executable_impl(full_path, root, ret_filename, ret_fd); + r = open_and_check_executable(full_path, root, ret_filename, ret_fd); if (r >= 0) return 0; if (r != -EACCES) @@ -754,7 +743,7 @@ int find_executable_full( if (!path_extend(&element, name)) return -ENOMEM; - r = find_executable_impl(element, root, ret_filename, ret_fd); + r = open_and_check_executable(element, root, ret_filename, ret_fd); if (r >= 0) /* Found it! */ return 0; /* PATH entries which we don't have access to are ignored, as per tradition. */ diff --git a/src/libnm-systemd-shared/src/basic/path-util.h b/src/libnm-systemd-shared/src/basic/path-util.h index 9b13d958..5bfa8fc7 100644 --- a/src/libnm-systemd-shared/src/basic/path-util.h +++ b/src/libnm-systemd-shared/src/basic/path-util.h @@ -117,6 +117,7 @@ int path_strv_make_absolute_cwd(char **l); char** path_strv_resolve(char **l, const char *root); char** path_strv_resolve_uniq(char **l, const char *root); +int open_and_check_executable(const char *name, const char *root, char **ret_path, int *ret_fd); int find_executable_full( const char *name, const char *root, diff --git a/src/libnm-systemd-shared/src/basic/pidfd-util.c b/src/libnm-systemd-shared/src/basic/pidfd-util.c index d6bd5517..91638c77 100644 --- a/src/libnm-systemd-shared/src/basic/pidfd-util.c +++ b/src/libnm-systemd-shared/src/basic/pidfd-util.c @@ -3,15 +3,18 @@ #include "nm-sd-adapt-shared.h" #include <sys/ioctl.h> +#include <threads.h> #include <unistd.h> #include "errno-util.h" #include "fd-util.h" #include "fileio.h" +#include "log.h" #include "macro.h" #include "memory-util.h" +#include "missing_fs.h" #include "missing_magic.h" -#include "missing_threads.h" +#include "mountpoint-util.h" #include "parse-util.h" #include "path-util.h" #include "pidfd-util.h" @@ -89,26 +92,21 @@ static int pidfd_get_info(int fd, struct pidfd_info *info) { static int pidfd_get_pid_fdinfo(int fd, pid_t *ret) { char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)]; - _cleanup_free_ char *fdinfo = NULL; + _cleanup_free_ char *p = NULL; int r; assert(fd >= 0); xsprintf(path, "/proc/self/fdinfo/%i", fd); - r = read_full_virtual_file(path, &fdinfo, NULL); + r = get_proc_field(path, "Pid", &p); if (r == -ENOENT) - return proc_fd_enoent_errno(); + return -EBADF; + if (r == -ENODATA) /* not a pidfd? */ + return -ENOTTY; if (r < 0) return r; - char *p = find_line_startswith(fdinfo, "Pid:"); - if (!p) - return -ENOTTY; /* not a pidfd? */ - - p = skip_leading_chars(p, /* bad = */ NULL); - p[strcspn(p, WHITESPACE)] = 0; - if (streq(p, "0")) return -EREMOTE; /* PID is in foreign PID namespace? */ if (streq(p, "-1")) @@ -230,6 +228,7 @@ int pidfd_get_cgroupid(int fd, uint64_t *ret) { #endif /* NM_IGNORED */ int pidfd_get_inode_id(int fd, uint64_t *ret) { + static bool file_handle_supported = true; int r; assert(fd >= 0); @@ -240,6 +239,30 @@ int pidfd_get_inode_id(int fd, uint64_t *ret) { if (r == 0) return -EOPNOTSUPP; + if (file_handle_supported) { + union { + struct file_handle file_handle; + uint8_t space[offsetof(struct file_handle, f_handle) + sizeof(uint64_t)]; + } fh = { + .file_handle.handle_bytes = sizeof(uint64_t), + .file_handle.handle_type = FILEID_KERNFS, + }; + int mnt_id; + + r = RET_NERRNO(name_to_handle_at(fd, "", &fh.file_handle, &mnt_id, AT_EMPTY_PATH)); + if (r >= 0) { + if (ret) + *ret = *CAST_ALIGN_PTR(uint64_t, fh.file_handle.f_handle); + return 0; + } + assert(r != -EOVERFLOW); + if (is_name_to_handle_at_fatal_error(r)) + return r; + + file_handle_supported = false; + } + +#if SIZEOF_INO_T == 8 struct stat st; if (fstat(fd, &st) < 0) return -errno; @@ -247,6 +270,16 @@ int pidfd_get_inode_id(int fd, uint64_t *ret) { if (ret) *ret = (uint64_t) st.st_ino; return 0; + +#elif SIZEOF_INO_T == 4 + /* On 32-bit systems (where sizeof(ino_t) == 4), the inode id returned by fstat() cannot be used to + * reliably identify the process, nor can we communicate the origin of the id with the clients. + * Hence let's just refuse to acquire pidfdid through fstat() here. All clients shall also insist on + * the 64-bit id from name_to_handle_at(). */ + return -EOPNOTSUPP; +#else +# error Unsupported ino_t size +#endif } int pidfd_get_inode_id_self_cached(uint64_t *ret) { diff --git a/src/libnm-systemd-shared/src/basic/pidref.h b/src/libnm-systemd-shared/src/basic/pidref.h index 9e8a39ec..064b9d85 100644 --- a/src/libnm-systemd-shared/src/basic/pidref.h +++ b/src/libnm-systemd-shared/src/basic/pidref.h @@ -1,10 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -typedef struct PidRef PidRef; - #include "macro.h" -#include "process-util.h" +#include "memory-util.h" /* An embeddable structure carrying a reference to a process. Supposed to be used when tracking processes * continuously. This combines a PID, a modern Linux pidfd and the 64bit inode number of the pidfd into one @@ -29,22 +27,22 @@ typedef struct PidRef PidRef; * process. Moreover, most operations will fail with -EREMOTE. Only PidRef structures that are not marked * *unset* can be marked *remote*. */ -struct PidRef { - pid_t pid; /* > 0 if the PidRef is set, otherwise set to PID_AUTOMATIC if automatic mode is - * desired, or 0 otherwise. */ +typedef struct PidRef { + pid_t pid; /* > 0 if the PidRef is set, otherwise set to INT_MIN (PID_AUTOMATIC) if automatic + * mode is desired, or 0 otherwise. */ int fd; /* only valid if pidfd are available in the kernel, and we manage to get an fd. If we * know that the PID is not from the local machine we set this to -EREMOTE, otherwise * we use -EBADF as indicator the fd is invalid. */ uint64_t fd_id; /* the inode number of pidfd. only useful in kernel 6.9+ where pidfds live in their own pidfs and each process comes with a unique inode number */ -}; +} PidRef; #define PIDREF_NULL (PidRef) { .fd = -EBADF } /* A special pidref value that we are using when a PID shall be automatically acquired from some surrounding * context, for example connection peer. Much like PIDREF_NULL it will be considered unset by - * pidref_is_set().*/ -#define PIDREF_AUTOMATIC (const PidRef) { .pid = PID_AUTOMATIC, .fd = -EBADF } + * pidref_is_set(). */ +#define PIDREF_AUTOMATIC (const PidRef) { .pid = (pid_t) INT_MIN, .fd = -EBADF } /* Turns a pid_t into a PidRef structure on-the-fly *without* acquiring a pidfd for it. (As opposed to * pidref_set_pid() which does so *with* acquiring one, see below) */ @@ -70,7 +68,7 @@ bool pidref_equal(PidRef *a, PidRef *b); int pidref_set_pid(PidRef *pidref, pid_t pid); int pidref_set_pidstr(PidRef *pidref, const char *pid); int pidref_set_pidfd(PidRef *pidref, int fd); -int pidref_set_pidfd_take(PidRef *pidref, int fd); /* takes ownership of the passed pidfd on success*/ +int pidref_set_pidfd_take(PidRef *pidref, int fd); /* takes ownership of the passed pidfd on success */ int pidref_set_pidfd_consume(PidRef *pidref, int fd); /* takes ownership of the passed pidfd in both success and failure */ int pidref_set_parent(PidRef *ret); static inline int pidref_set_self(PidRef *pidref) { @@ -108,5 +106,9 @@ int pidref_verify(const PidRef *pidref); #define TAKE_PIDREF(p) TAKE_GENERIC((p), PidRef, PIDREF_NULL) +struct siphash; +void pidref_hash_func(const PidRef *pidref, struct siphash *state); +int pidref_compare_func(const PidRef *a, const PidRef *b); + extern const struct hash_ops pidref_hash_ops; extern const struct hash_ops pidref_hash_ops_free; /* Has destructor call for pidref_free(), i.e. expects heap allocated PidRef as keys */ diff --git a/src/libnm-systemd-shared/src/basic/prioq.c b/src/libnm-systemd-shared/src/basic/prioq.c index c36d0ddd..0a007a29 100644 --- a/src/libnm-systemd-shared/src/basic/prioq.c +++ b/src/libnm-systemd-shared/src/basic/prioq.c @@ -48,6 +48,11 @@ Prioq* prioq_free(Prioq *q) { if (!q) return NULL; + /* Invalidate the index fields of any remaining objects */ + FOREACH_ARRAY(item, q->items, q->n_items) + if (item->idx) + *(item->idx) = PRIOQ_IDX_NULL; + free(q->items); return mfree(q); } @@ -180,6 +185,11 @@ static void remove_item(Prioq *q, struct prioq_item *i) { assert(q); assert(i); + /* Let's invalidate the index pointer stored in the user's object to indicate the item is now removed + * from the priority queue */ + if (i->idx) + *(i->idx) = PRIOQ_IDX_NULL; + l = q->items + q->n_items - 1; if (i == l) @@ -191,6 +201,7 @@ static void remove_item(Prioq *q, struct prioq_item *i) { /* Not last entry, let's replace the last entry with * this one, and reshuffle */ + assert(i >= q->items); k = i - q->items; i->data = l->data; @@ -254,6 +265,7 @@ void prioq_reshuffle(Prioq *q, void *data, unsigned *idx) { if (!i) return; + assert(i >= q->items); k = i - q->items; k = shuffle_down(q, k); shuffle_up(q, k); diff --git a/src/libnm-systemd-shared/src/basic/process-util.c b/src/libnm-systemd-shared/src/basic/process-util.c index 85187562..517990b5 100644 --- a/src/libnm-systemd-shared/src/basic/process-util.c +++ b/src/libnm-systemd-shared/src/basic/process-util.c @@ -17,6 +17,7 @@ #include <sys/types.h> #include <sys/wait.h> #include <syslog.h> +#include <threads.h> #include <unistd.h> #if 0 /* NM_IGNORED */ #if HAVE_VALGRIND_VALGRIND_H @@ -38,13 +39,13 @@ #include "fs-util.h" #include "hostname-util.h" #include "io-util.h" +#include "iovec-util.h" #include "locale-util.h" #include "log.h" #include "macro.h" #include "memory-util.h" #include "missing_sched.h" #include "missing_syscall.h" -#include "missing_threads.h" #include "mountpoint-util.h" #include "namespace-util.h" #include "nulstr-util.h" @@ -55,6 +56,7 @@ #include "raw-clone.h" #include "rlimit-util.h" #include "signal-util.h" +#include "socket-util.h" #include "stat-util.h" #include "stdio-util.h" #include "string-table.h" @@ -509,56 +511,25 @@ int get_process_exe(pid_t pid, char **ret) { return 0; } -static int get_process_id(pid_t pid, const char *field, uid_t *ret) { - _cleanup_fclose_ FILE *f = NULL; - const char *p; +int pid_get_uid(pid_t pid, uid_t *ret) { int r; - assert(field); + assert(pid >= 0); assert(ret); - if (pid < 0) - return -EINVAL; + if (pid == 0 || pid == getpid_cached()) { + *ret = getuid(); + return 0; + } - p = procfs_file_alloca(pid, "status"); - r = fopen_unlocked(p, "re", &f); + _cleanup_free_ char *v = NULL; + r = procfs_file_get_field(pid, "status", "Uid", &v); if (r == -ENOENT) return -ESRCH; if (r < 0) return r; - for (;;) { - _cleanup_free_ char *line = NULL; - char *l; - - r = read_stripped_line(f, LONG_LINE_MAX, &line); - if (r < 0) - return r; - if (r == 0) - break; - - l = startswith(line, field); - if (l) { - l += strspn(l, WHITESPACE); - - l[strcspn(l, WHITESPACE)] = 0; - - return parse_uid(l, ret); - } - } - - return -EIO; -} - -int pid_get_uid(pid_t pid, uid_t *ret) { - assert(ret); - - if (pid == 0 || pid == getpid_cached()) { - *ret = getuid(); - return 0; - } - - return get_process_id(pid, "Uid:", ret); + return parse_uid(v, ret); } int pidref_get_uid(const PidRef *pid, uid_t *ret) { @@ -591,14 +562,24 @@ int pidref_get_uid(const PidRef *pid, uid_t *ret) { } int get_process_gid(pid_t pid, gid_t *ret) { + int r; + + assert(pid >= 0); + assert(ret); if (pid == 0 || pid == getpid_cached()) { *ret = getgid(); return 0; } - assert_cc(sizeof(uid_t) == sizeof(gid_t)); - return get_process_id(pid, "Gid:", ret); + _cleanup_free_ char *v = NULL; + r = procfs_file_get_field(pid, "status", "Gid", &v); + if (r == -ENOENT) + return -ESRCH; + if (r < 0) + return r; + + return parse_gid(v, ret); } int get_process_cwd(pid_t pid, char **ret) { @@ -864,15 +845,12 @@ int pidref_get_start_time(const PidRef *pid, usec_t *ret) { int get_process_umask(pid_t pid, mode_t *ret) { _cleanup_free_ char *m = NULL; - const char *p; int r; assert(pid >= 0); assert(ret); - p = procfs_file_alloca(pid, "status"); - - r = get_proc_field(p, "Umask", WHITESPACE, &m); + r = procfs_file_get_field(pid, "status", "Umask", &m); if (r == -ENOENT) return -ESRCH; if (r < 0) @@ -881,27 +859,8 @@ int get_process_umask(pid_t pid, mode_t *ret) { return parse_mode(m, ret); } -int wait_for_terminate(pid_t pid, siginfo_t *status) { - siginfo_t dummy; - - assert(pid >= 1); - - if (!status) - status = &dummy; - - for (;;) { - zero(*status); - - if (waitid(P_PID, pid, status, WEXITED) < 0) { - - if (errno == EINTR) - continue; - - return negative_errno(); - } - - return 0; - } +int wait_for_terminate(pid_t pid, siginfo_t *ret) { + return pidref_wait_for_terminate(&PIDREF_MAKE_FROM_PID(pid), ret); } /* @@ -918,24 +877,29 @@ int wait_for_terminate(pid_t pid, siginfo_t *status) { * A warning is emitted if the process terminates abnormally, * and also if it returns non-zero unless check_exit_code is true. */ -int wait_for_terminate_and_check(const char *name, pid_t pid, WaitFlags flags) { - _cleanup_free_ char *buffer = NULL; - siginfo_t status; - int r, prio; +int pidref_wait_for_terminate_and_check(const char *name, PidRef *pidref, WaitFlags flags) { + int r; - assert(pid > 1); + if (!pidref_is_set(pidref)) + return -ESRCH; + if (pidref_is_remote(pidref)) + return -EREMOTE; + if (pidref->pid == 1 || pidref_is_self(pidref)) + return -ECHILD; + _cleanup_free_ char *buffer = NULL; if (!name) { - r = pid_get_comm(pid, &buffer); + r = pidref_get_comm(pidref, &buffer); if (r < 0) - log_debug_errno(r, "Failed to acquire process name of " PID_FMT ", ignoring: %m", pid); + log_debug_errno(r, "Failed to acquire process name of " PID_FMT ", ignoring: %m", pidref->pid); else name = buffer; } - prio = flags & WAIT_LOG_ABNORMAL ? LOG_ERR : LOG_DEBUG; + int prio = flags & WAIT_LOG_ABNORMAL ? LOG_ERR : LOG_DEBUG; - r = wait_for_terminate(pid, &status); + siginfo_t status; + r = pidref_wait_for_terminate(pidref, &status); if (r < 0) return log_full_errno(prio, r, "Failed to wait for %s: %m", strna(name)); @@ -958,6 +922,10 @@ int wait_for_terminate_and_check(const char *name, pid_t pid, WaitFlags flags) { return -EPROTO; } +int wait_for_terminate_and_check(const char *name, pid_t pid, WaitFlags flags) { + return pidref_wait_for_terminate_and_check(name, &PIDREF_MAKE_FROM_PID(pid), flags); +} + /* * Return values: * @@ -1385,8 +1353,8 @@ void valgrind_summary_hack(void) { if (pid < 0) log_struct_errno( LOG_EMERG, errno, - "MESSAGE_ID=" SD_MESSAGE_VALGRIND_HELPER_FORK_STR, - LOG_MESSAGE( "Failed to fork off valgrind helper: %m")); + LOG_MESSAGE_ID(SD_MESSAGE_VALGRIND_HELPER_FORK_STR), + LOG_MESSAGE("Failed to fork off valgrind helper: %m")); else if (pid == 0) exit(EXIT_SUCCESS); else { @@ -1446,7 +1414,7 @@ pid_t getpid_cached(void) { case CACHED_PID_UNSET: { /* Not initialized yet, then do so now */ pid_t new_pid; - new_pid = raw_getpid(); + new_pid = getpid(); if (!installed) { /* __register_atfork() either returns 0 or -ENOMEM, in its glibc implementation. Since it's @@ -1467,7 +1435,7 @@ pid_t getpid_cached(void) { } case CACHED_PID_BUSY: /* Somebody else is currently initializing */ - return raw_getpid(); + return getpid(); default: /* Properly initialized */ return current_value; @@ -1533,25 +1501,28 @@ static int fork_flags_to_signal(ForkFlags flags) { SIGKILL; } -int safe_fork_full( +int pidref_safe_fork_full( const char *name, const int stdio_fds[3], int except_fds[], size_t n_except_fds, ForkFlags flags, - pid_t *ret_pid) { + PidRef *ret_pid) { pid_t original_pid, pid; sigset_t saved_ss, ss; _unused_ _cleanup_(restore_sigsetp) sigset_t *saved_ssp = NULL; bool block_signals = false, block_all = false, intermediary = false; + _cleanup_close_pair_ int pidref_transport_fds[2] = EBADF_PAIR; int prio, r; + assert(!FLAGS_SET(flags, FORK_WAIT|FORK_FREEZE)); assert(!FLAGS_SET(flags, FORK_DETACH) || - (!ret_pid && (flags & (FORK_WAIT|FORK_DEATHSIG_SIGTERM|FORK_DEATHSIG_SIGINT|FORK_DEATHSIG_SIGKILL)) == 0)); + (flags & (FORK_WAIT|FORK_DEATHSIG_SIGTERM|FORK_DEATHSIG_SIGINT|FORK_DEATHSIG_SIGKILL)) == 0); - /* A wrapper around fork(), that does a couple of important initializations in addition to mere forking. Always - * returns the child's PID in *ret_pid. Returns == 0 in the child, and > 0 in the parent. */ + /* A wrapper around fork(), that does a couple of important initializations in addition to mere + * forking. If provided, ret_pid is initialized in both the parent and the child process, both times + * referencing the child process. Returns == 0 in the child and > 0 in the parent. */ prio = flags & FORK_LOG ? LOG_ERR : LOG_DEBUG; @@ -1594,14 +1565,43 @@ int safe_fork_full( if (!r) { /* Not a reaper process, hence do a double fork() so we are reparented to one */ + if (ret_pid && socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, pidref_transport_fds) < 0) + return log_full_errno(prio, errno, "Failed to allocate pidref socket: %m"); + pid = fork(); if (pid < 0) return log_full_errno(prio, errno, "Failed to fork off '%s': %m", strna(name)); if (pid > 0) { log_debug("Successfully forked off intermediary '%s' as PID " PID_FMT ".", strna(name), pid); + + pidref_transport_fds[1] = safe_close(pidref_transport_fds[1]); + + if (pidref_transport_fds[0] >= 0) { + /* Wait for the intermediary child to exit so the caller can be certain the actual child + * process has been reparented by the time this function returns. */ + r = wait_for_terminate_and_check(name, pid, FLAGS_SET(flags, FORK_LOG) ? WAIT_LOG : 0); + if (r < 0) + return log_full_errno(prio, r, "Failed to wait for intermediary process: %m"); + if (r != EXIT_SUCCESS) /* exit status > 0 should be treated as failure, too */ + return -EPROTO; + + int pidfd; + ssize_t n = receive_one_fd_iov( + pidref_transport_fds[0], + &IOVEC_MAKE(&pid, sizeof(pid)), + /* iovlen= */ 1, + /* flags= */ 0, + &pidfd); + if (n < 0) + return log_full_errno(prio, n, "Failed to receive child pidref: %m"); + + *ret_pid = (PidRef) { .pid = pid, .fd = pidfd }; + } + return 1; /* return in the parent */ } + pidref_transport_fds[0] = safe_close(pidref_transport_fds[0]); intermediary = true; } } @@ -1619,8 +1619,30 @@ int safe_fork_full( if (pid > 0) { /* If we are in the intermediary process, exit now */ - if (intermediary) + if (intermediary) { + if (pidref_transport_fds[1] >= 0) { + _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; + + r = pidref_set_pid(&pidref, pid); + if (r < 0) { + log_full_errno(prio, r, "Failed to open reference to PID "PID_FMT": %m", pid); + _exit(EXIT_FAILURE); + } + + r = send_one_fd_iov( + pidref_transport_fds[1], + pidref.fd, + &IOVEC_MAKE(&pidref.pid, sizeof(pidref.pid)), + /* iovlen= */ 1, + /* flags= */ 0); + if (r < 0) { + log_full_errno(prio, r, "Failed to send child pidref: %m"); + _exit(EXIT_FAILURE); + } + } + _exit(EXIT_SUCCESS); + } /* We are in the parent process */ log_debug("Successfully forked off '%s' as PID " PID_FMT ".", strna(name), pid); @@ -1638,16 +1660,31 @@ int safe_fork_full( return r; if (r != EXIT_SUCCESS) /* exit status > 0 should be treated as failure, too */ return -EPROTO; + + /* If we are in the parent and successfully waited, then the process doesn't exist anymore. */ + if (ret_pid) + *ret_pid = PIDREF_NULL; + + return 1; } - if (ret_pid) - *ret_pid = pid; + if (ret_pid) { + if (FLAGS_SET(flags, FORK_PID_ONLY)) + *ret_pid = PIDREF_MAKE_FROM_PID(pid); + else { + r = pidref_set_pid(ret_pid, pid); + if (r < 0) /* Let's not fail for this, no matter what, the process exists after all, and that's key */ + *ret_pid = PIDREF_MAKE_FROM_PID(pid); + } + } return 1; } /* We are in the child process */ + pidref_transport_fds[1] = safe_close(pidref_transport_fds[1]); + /* Restore signal mask manually */ saved_ssp = NULL; @@ -1809,36 +1846,41 @@ int safe_fork_full( if (FLAGS_SET(flags, FORK_FREEZE)) freeze(); - if (ret_pid) - *ret_pid = getpid_cached(); + if (ret_pid) { + if (FLAGS_SET(flags, FORK_PID_ONLY)) + *ret_pid = PIDREF_MAKE_FROM_PID(getpid_cached()); + else { + r = pidref_set_self(ret_pid); + if (r < 0) { + log_full_errno(prio, r, "Failed to acquire PID reference on ourselves: %m"); + _exit(EXIT_FAILURE); + } + } + } return 0; } -int pidref_safe_fork_full( +int safe_fork_full( const char *name, const int stdio_fds[3], int except_fds[], size_t n_except_fds, ForkFlags flags, - PidRef *ret_pid) { + pid_t *ret_pid) { - pid_t pid; - int r, q; + _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; + int r; - r = safe_fork_full(name, stdio_fds, except_fds, n_except_fds, flags, &pid); - if (r < 0 || !ret_pid) - return r; + /* Getting the detached child process pid without pidfd is racy, so don't allow it if not returning + * a pidref to the caller. */ + assert(!FLAGS_SET(flags, FORK_DETACH) || !ret_pid); - if (r > 0 && FLAGS_SET(flags, FORK_WAIT)) { - /* If we are in the parent and successfully waited, then the process doesn't exist anymore */ - *ret_pid = PIDREF_NULL; + r = pidref_safe_fork_full(name, stdio_fds, except_fds, n_except_fds, flags|FORK_PID_ONLY, ret_pid ? &pidref : NULL); + if (r < 0 || !ret_pid) return r; - } - q = pidref_set_pid(ret_pid, pid); - if (q < 0) /* Let's not fail for this, no matter what, the process exists after all, and that's key */ - *ret_pid = PIDREF_MAKE_FROM_PID(pid); + *ret_pid = pidref.pid; return r; } @@ -2013,17 +2055,14 @@ _noreturn_ void freeze(void) { int get_process_threads(pid_t pid) { _cleanup_free_ char *t = NULL; - const char *p; int n, r; if (pid < 0) return -EINVAL; - p = procfs_file_alloca(pid, "status"); - - r = get_proc_field(p, "Threads", WHITESPACE, &t); + r = procfs_file_get_field(pid, "status", "Threads", &t); if (r == -ENOENT) - return proc_mounted() == 0 ? -ENOSYS : -ESRCH; + return -ESRCH; if (r < 0) return r; diff --git a/src/libnm-systemd-shared/src/basic/process-util.h b/src/libnm-systemd-shared/src/basic/process-util.h index 19ac55dd..395df64a 100644 --- a/src/libnm-systemd-shared/src/basic/process-util.h +++ b/src/libnm-systemd-shared/src/basic/process-util.h @@ -12,6 +12,8 @@ #include <sys/types.h> #include "alloc-util.h" +#include "assert-util.h" +#include "fileio.h" #include "format-util.h" #include "macro.h" #include "pidref.h" @@ -22,16 +24,20 @@ pid_t _pid_ = (pid); \ const char *_field_ = (field); \ char *_r_; \ - if (_pid_ == 0) { \ - _r_ = newa(char, STRLEN("/proc/self/") + strlen(_field_) + 1); \ - strcpy(stpcpy(_r_, "/proc/self/"), _field_); \ - } else { \ + if (_pid_ == 0) \ + _r_ = strjoina("/proc/self/", _field_); \ + else { \ + assert(_pid_ > 0); \ _r_ = newa(char, STRLEN("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + strlen(_field_) + 1); \ sprintf(_r_, "/proc/" PID_FMT "/%s", _pid_, _field_); \ } \ (const char*) _r_; \ }) +static inline int procfs_file_get_field(pid_t pid, const char *name, const char *key, char **ret) { + return get_proc_field(procfs_file_alloca(pid, name), key, ret); +} + typedef enum ProcessCmdlineFlags { PROCESS_CMDLINE_COMM_FALLBACK = 1 << 0, PROCESS_CMDLINE_USE_LOCALE = 1 << 1, @@ -61,7 +67,11 @@ int get_process_umask(pid_t pid, mode_t *ret); int container_get_leader(const char *machine, pid_t *pid); -int wait_for_terminate(pid_t pid, siginfo_t *status); +static inline bool SIGINFO_CODE_IS_DEAD(int code) { + return IN_SET(code, CLD_EXITED, CLD_KILLED, CLD_DUMPED); +} + +int wait_for_terminate(pid_t pid, siginfo_t *ret); typedef enum WaitFlags { WAIT_LOG_ABNORMAL = 1 << 0, @@ -71,7 +81,9 @@ typedef enum WaitFlags { WAIT_LOG = WAIT_LOG_ABNORMAL|WAIT_LOG_NON_ZERO_EXIT_STATUS, } WaitFlags; +int pidref_wait_for_terminate_and_check(const char *name, PidRef *pidref, WaitFlags flags); int wait_for_terminate_and_check(const char *name, pid_t pid, WaitFlags flags); + int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout); void sigkill_wait(pid_t pid); @@ -195,30 +207,31 @@ typedef enum ForkFlags { FORK_NEW_NETNS = 1 << 20, /* Run child in its own network namespace 💣 DO NOT USE IN THREADED PROGRAMS! 💣 */ FORK_NEW_PIDNS = 1 << 21, /* Run child in its own PID namespace 💣 DO NOT USE IN THREADED PROGRAMS! 💣 */ FORK_FREEZE = 1 << 22, /* Don't return in child, just call freeze() instead */ + FORK_PID_ONLY = 1 << 23, /* Don't open a pidfd referencing the child process */ } ForkFlags; -int safe_fork_full( +int pidref_safe_fork_full( const char *name, const int stdio_fds[3], int except_fds[], size_t n_except_fds, ForkFlags flags, - pid_t *ret_pid); + PidRef *ret_pid); -static inline int safe_fork(const char *name, ForkFlags flags, pid_t *ret_pid) { - return safe_fork_full(name, NULL, NULL, 0, flags, ret_pid); +static inline int pidref_safe_fork(const char *name, ForkFlags flags, PidRef *ret_pid) { + return pidref_safe_fork_full(name, NULL, NULL, 0, flags, ret_pid); } -int pidref_safe_fork_full( +int safe_fork_full( const char *name, const int stdio_fds[3], int except_fds[], size_t n_except_fds, ForkFlags flags, - PidRef *ret_pid); + pid_t *ret_pid); -static inline int pidref_safe_fork(const char *name, ForkFlags flags, PidRef *ret_pid) { - return pidref_safe_fork_full(name, NULL, NULL, 0, flags, ret_pid); +static inline int safe_fork(const char *name, ForkFlags flags, pid_t *ret_pid) { + return safe_fork_full(name, NULL, NULL, 0, flags, ret_pid); } int namespace_fork( diff --git a/src/libnm-systemd-shared/src/basic/random-util.c b/src/libnm-systemd-shared/src/basic/random-util.c index 1e1a24bd..dab4334a 100644 --- a/src/libnm-systemd-shared/src/basic/random-util.c +++ b/src/libnm-systemd-shared/src/basic/random-util.c @@ -13,6 +13,7 @@ #include <sys/auxv.h> #include <sys/ioctl.h> #include <sys/time.h> +#include <threads.h> #include "alloc-util.h" #include "env-util.h" @@ -21,9 +22,9 @@ #include "fileio.h" #include "io-util.h" #include "iovec-util.h" +#include "log.h" #include "missing_random.h" #include "missing_syscall.h" -#include "missing_threads.h" #include "parse-util.h" #include "pidfd-util.h" #include "process-util.h" diff --git a/src/libnm-systemd-shared/src/basic/random-util.h b/src/libnm-systemd-shared/src/basic/random-util.h index 0b5ba771..587ca1c2 100644 --- a/src/libnm-systemd-shared/src/basic/random-util.h +++ b/src/libnm-systemd-shared/src/basic/random-util.h @@ -6,8 +6,10 @@ #include <stdint.h> #include <sys/uio.h> -void random_bytes(void *p, size_t n); /* Returns random bytes suitable for most uses, but may be insecure sometimes. */ -int crypto_random_bytes(void *p, size_t n); /* Returns secure random bytes after waiting for the RNG to initialize. */ +#include "macro.h" + +void random_bytes(void *p, size_t n) _nonnull_if_nonzero_(1, 2); /* Returns random bytes suitable for most uses, but may be insecure sometimes. */ +int crypto_random_bytes(void *p, size_t n) _nonnull_if_nonzero_(1, 2); /* Returns secure random bytes after waiting for the RNG to initialize. */ int crypto_random_bytes_allocate_iovec(size_t n, struct iovec *ret); static inline uint64_t random_u64(void) { @@ -29,6 +31,6 @@ static inline uint32_t random_u32(void) { size_t random_pool_size(void); -int random_write_entropy(int fd, const void *seed, size_t size, bool credit); +int random_write_entropy(int fd, const void *seed, size_t size, bool credit) _nonnull_if_nonzero_(2, 3); uint64_t random_u64_range(uint64_t max); diff --git a/src/libnm-systemd-shared/src/basic/ratelimit.h b/src/libnm-systemd-shared/src/basic/ratelimit.h index 7801ef42..fd834263 100644 --- a/src/libnm-systemd-shared/src/basic/ratelimit.h +++ b/src/libnm-systemd-shared/src/basic/ratelimit.h @@ -28,3 +28,55 @@ unsigned ratelimit_num_dropped(const RateLimit *rl); usec_t ratelimit_end(const RateLimit *rl); usec_t ratelimit_left(const RateLimit *rl); + +typedef struct LogRateLimit { + int error; + int level; + RateLimit ratelimit; +} LogRateLimit; + +#define log_ratelimit_internal(_level, _error, _ratelimit, _file, _line, _func, _format, ...) \ +({ \ + int _log_ratelimit_error = (_error); \ + int _log_ratelimit_level = (_level); \ + static LogRateLimit _log_ratelimit = { \ + .ratelimit = (_ratelimit), \ + }; \ + unsigned _num_dropped_errors = ratelimit_num_dropped(&_log_ratelimit.ratelimit); \ + if (_log_ratelimit_error != _log_ratelimit.error || _log_ratelimit_level != _log_ratelimit.level) { \ + ratelimit_reset(&_log_ratelimit.ratelimit); \ + _log_ratelimit.error = _log_ratelimit_error; \ + _log_ratelimit.level = _log_ratelimit_level; \ + } \ + if (log_get_max_level() == LOG_DEBUG || ratelimit_below(&_log_ratelimit.ratelimit)) \ + _log_ratelimit_error = _num_dropped_errors > 0 \ + ? log_internal(_log_ratelimit_level, _log_ratelimit_error, _file, _line, _func, _format " (Dropped %u similar message(s))", ##__VA_ARGS__, _num_dropped_errors) \ + : log_internal(_log_ratelimit_level, _log_ratelimit_error, _file, _line, _func, _format, ##__VA_ARGS__); \ + _log_ratelimit_error; \ +}) + +#define log_ratelimit_full_errno(level, error, _ratelimit, format, ...) \ + ({ \ + int _level = (level), _e = (error); \ + _e = (log_get_max_level() >= LOG_PRI(_level)) \ + ? log_ratelimit_internal(_level, _e, _ratelimit, PROJECT_FILE, __LINE__, __func__, format, ##__VA_ARGS__) \ + : -ERRNO_VALUE(_e); \ + _e < 0 ? _e : -ESTRPIPE; \ + }) + +#define log_ratelimit_full(level, _ratelimit, format, ...) \ + log_ratelimit_full_errno(level, 0, _ratelimit, format, ##__VA_ARGS__) + +/* Normal logging */ +#define log_ratelimit_info(...) log_ratelimit_full(LOG_INFO, __VA_ARGS__) +#define log_ratelimit_notice(...) log_ratelimit_full(LOG_NOTICE, __VA_ARGS__) +#define log_ratelimit_warning(...) log_ratelimit_full(LOG_WARNING, __VA_ARGS__) +#define log_ratelimit_error(...) log_ratelimit_full(LOG_ERR, __VA_ARGS__) +#define log_ratelimit_emergency(...) log_ratelimit_full(log_emergency_level(), __VA_ARGS__) + +/* Logging triggered by an errno-like error */ +#define log_ratelimit_info_errno(error, ...) log_ratelimit_full_errno(LOG_INFO, error, __VA_ARGS__) +#define log_ratelimit_notice_errno(error, ...) log_ratelimit_full_errno(LOG_NOTICE, error, __VA_ARGS__) +#define log_ratelimit_warning_errno(error, ...) log_ratelimit_full_errno(LOG_WARNING, error, __VA_ARGS__) +#define log_ratelimit_error_errno(error, ...) log_ratelimit_full_errno(LOG_ERR, error, __VA_ARGS__) +#define log_ratelimit_emergency_errno(error, ...) log_ratelimit_full_errno(log_emergency_level(), error, __VA_ARGS__) diff --git a/src/libnm-systemd-shared/src/basic/set.h b/src/libnm-systemd-shared/src/basic/set.h index 618e7297..c7b84e0a 100644 --- a/src/libnm-systemd-shared/src/basic/set.h +++ b/src/libnm-systemd-shared/src/basic/set.h @@ -12,15 +12,9 @@ Set* _set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); #define set_new(ops) _set_new(ops HASHMAP_DEBUG_SRC_ARGS) static inline Set* set_free(Set *s) { - return (Set*) _hashmap_free(HASHMAP_BASE(s), NULL, NULL); + return (Set*) _hashmap_free(HASHMAP_BASE(s)); } -static inline Set* set_free_free(Set *s) { - return (Set*) _hashmap_free(HASHMAP_BASE(s), free, NULL); -} - -/* no set_free_free_free */ - #define set_copy(s) ((Set*) _hashmap_copy(HASHMAP_BASE(s) HASHMAP_DEBUG_SRC_ARGS)) int _set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); @@ -77,30 +71,13 @@ static inline bool set_iterate(const Set *s, Iterator *i, void **value) { } static inline void set_clear(Set *s) { - _hashmap_clear(HASHMAP_BASE(s), NULL, NULL); -} - -static inline void set_clear_free(Set *s) { - _hashmap_clear(HASHMAP_BASE(s), free, NULL); + _hashmap_clear(HASHMAP_BASE(s)); } -/* no set_clear_free_free */ - static inline void *set_steal_first(Set *s) { return _hashmap_first_key_and_value(HASHMAP_BASE(s), true, NULL); } -#define set_clear_with_destructor(s, f) \ - ({ \ - Set *_s = (s); \ - void *_item; \ - while ((_item = set_steal_first(_s))) \ - f(_item); \ - _s; \ - }) -#define set_free_with_destructor(s, f) \ - set_free(set_clear_with_destructor(s, f)) - /* no set_steal_first_key */ /* no set_first_key */ @@ -114,6 +91,8 @@ static inline char **set_get_strv(Set *s) { return _hashmap_get_strv(HASHMAP_BASE(s)); } +char** set_to_strv(Set **s); + int _set_ensure_put(Set **s, const struct hash_ops *hash_ops, const void *key HASHMAP_DEBUG_PARAMS); #define set_ensure_put(s, hash_ops, key) _set_ensure_put(s, hash_ops, key HASHMAP_DEBUG_SRC_ARGS) @@ -143,10 +122,8 @@ int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags for (; ({ e = set_first(s); assert_se(!e || set_move_one(d, s, e) >= 0); e; }); ) DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free); #define _cleanup_set_free_ _cleanup_(set_freep) -#define _cleanup_set_free_free_ _cleanup_(set_free_freep) int set_strjoin(Set *s, const char *separator, bool wrap_with_separator, char **ret); diff --git a/src/libnm-systemd-shared/src/basic/signal-util.c b/src/libnm-systemd-shared/src/basic/signal-util.c index 05b2b50d..6722e4bc 100644 --- a/src/libnm-systemd-shared/src/basic/signal-util.c +++ b/src/libnm-systemd-shared/src/basic/signal-util.c @@ -4,11 +4,11 @@ #include <errno.h> #include <stdarg.h> +#include <threads.h> #include "errno-util.h" #include "macro.h" #include "missing_syscall.h" -#include "missing_threads.h" #include "parse-util.h" #include "signal-util.h" #include "stdio-util.h" @@ -283,13 +283,13 @@ void propagate_signal(int sig, siginfo_t *siginfo) { /* To be called from a signal handler. Will raise the same signal again, in our process + in our threads. * - * Note that we use raw_getpid() instead of getpid_cached(). We might have forked with raw_clone() + * Note that we use getpid() instead of getpid_cached(). We might have forked with raw_clone() * earlier (see PID 1), and hence let's go to the raw syscall here. In particular as this is not * performance sensitive code. * * Note that we use kill() rather than raise() as fallback, for similar reasons. */ - p = raw_getpid(); + p = getpid(); if (rt_tgsigqueueinfo(p, gettid(), sig, siginfo) < 0) assert_se(kill(p, sig) >= 0); diff --git a/src/libnm-systemd-shared/src/basic/signal-util.h b/src/libnm-systemd-shared/src/basic/signal-util.h index dc2b9de1..d64d5031 100644 --- a/src/libnm-systemd-shared/src/basic/signal-util.h +++ b/src/libnm-systemd-shared/src/basic/signal-util.h @@ -3,6 +3,7 @@ #include <signal.h> +#include "assert-util.h" #include "macro.h" int reset_all_signal_handlers(void); diff --git a/src/libnm-systemd-shared/src/basic/socket-util.c b/src/libnm-systemd-shared/src/basic/socket-util.c index 9cb0d7f4..7c83551c 100644 --- a/src/libnm-systemd-shared/src/basic/socket-util.c +++ b/src/libnm-systemd-shared/src/basic/socket-util.c @@ -2,11 +2,12 @@ #include "nm-sd-adapt-shared.h" -/* Make sure the net/if.h header is included before any linux/ one */ -#include <net/if.h> #include <arpa/inet.h> #include <errno.h> #include <limits.h> +#include <net/if.h> +#include <linux/if.h> +#include <linux/if_arp.h> #include <netdb.h> #include <netinet/ip.h> #include <poll.h> @@ -16,9 +17,6 @@ #include <stdlib.h> #include <sys/ioctl.h> #include <unistd.h> -#if 0 /* NM_IGNORED */ -#include <linux/if.h> -#endif /* NM_IGNORED */ #include "alloc-util.h" #include "errno-util.h" @@ -32,6 +30,7 @@ #include "parse-util.h" #include "path-util.h" #include "process-util.h" +#include "random-util.h" #include "socket-util.h" #include "string-table.h" #include "string-util.h" @@ -1361,6 +1360,53 @@ void* cmsg_find_and_copy_data(struct msghdr *mh, int level, int type, void *buf, } #if 0 /* NM_IGNORED */ +size_t sockaddr_ll_len(const struct sockaddr_ll *sa) { + /* Certain hardware address types (e.g Infiniband) do not fit into sll_addr + * (8 bytes) and run over the structure. This function returns the correct size that + * must be passed to kernel. */ + + assert(sa->sll_family == AF_PACKET); + + size_t mac_len = sizeof(sa->sll_addr); + + if (be16toh(sa->sll_hatype) == ARPHRD_ETHER) + mac_len = MAX(mac_len, (size_t) ETH_ALEN); + if (be16toh(sa->sll_hatype) == ARPHRD_INFINIBAND) + mac_len = MAX(mac_len, (size_t) INFINIBAND_ALEN); + + return offsetof(struct sockaddr_ll, sll_addr) + mac_len; +} + +size_t sockaddr_un_len(const struct sockaddr_un *sa) { + /* Covers only file system and abstract AF_UNIX socket addresses, but not unnamed socket addresses. */ + + assert(sa->sun_family == AF_UNIX); + + return offsetof(struct sockaddr_un, sun_path) + + (sa->sun_path[0] == 0 ? + 1 + strnlen(sa->sun_path+1, sizeof(sa->sun_path)-1) : + strnlen(sa->sun_path, sizeof(sa->sun_path))+1); +} + +size_t sockaddr_len(const union sockaddr_union *sa) { + switch (sa->sa.sa_family) { + case AF_INET: + return sizeof(struct sockaddr_in); + case AF_INET6: + return sizeof(struct sockaddr_in6); + case AF_UNIX: + return sockaddr_un_len(&sa->un); + case AF_PACKET: + return sockaddr_ll_len(&sa->ll); + case AF_NETLINK: + return sizeof(struct sockaddr_nl); + case AF_VSOCK: + return sizeof(struct sockaddr_vm); + default: + assert_not_reached(); + } +} + int socket_ioctl_fd(void) { int fd; @@ -1457,25 +1503,43 @@ int socket_bind_to_ifname(int fd, const char *ifname) { } int socket_bind_to_ifindex(int fd, int ifindex) { - char ifname[IF_NAMESIZE]; - int r; - assert(fd >= 0); if (ifindex <= 0) /* Drop binding */ return RET_NERRNO(setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, NULL, 0)); - r = setsockopt_int(fd, SOL_SOCKET, SO_BINDTOIFINDEX, ifindex); - if (r != -ENOPROTOOPT) - return r; + return setsockopt_int(fd, SOL_SOCKET, SO_BINDTOIFINDEX, ifindex); +} + +int socket_autobind(int fd, char **ret_name) { + _cleanup_free_ char *name = NULL; + uint64_t random; + int r; + + /* Generate a random abstract socket name and bind fd to it. This is modeled after the kernel + * "autobind" feature, but uses 64-bit random number internally. */ - /* Fall back to SO_BINDTODEVICE on kernels < 5.0 which didn't have SO_BINDTOIFINDEX */ - r = format_ifname(ifindex, ifname); + assert(fd >= 0); + assert(ret_name); + + random = random_u64(); + + if (asprintf(&name, "@%" PRIu64, random) < 0) + return -ENOMEM; + + union sockaddr_union sa; + assert_cc(DECIMAL_STR_MAX(uint64_t) < sizeof(sa.un.sun_path)); + + r = sockaddr_un_set_path(&sa.un, name); if (r < 0) return r; - return socket_bind_to_ifname(fd, ifname); + if (bind(fd, &sa.sa, r) < 0) + return -errno; + + *ret_name = TAKE_PTR(name); + return 0; } ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags) { @@ -1815,8 +1879,6 @@ int netlink_socket_get_multicast_groups(int fd, size_t *ret_len, uint32_t **ret_ assert(fd >= 0); - /* This returns ENOPROTOOPT if the kernel is older than 4.2. */ - if (getsockopt(fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, NULL, &len) < 0) return -errno; diff --git a/src/libnm-systemd-shared/src/basic/socket-util.h b/src/libnm-systemd-shared/src/basic/socket-util.h index b6c38725..e5eda855 100644 --- a/src/libnm-systemd-shared/src/basic/socket-util.h +++ b/src/libnm-systemd-shared/src/basic/socket-util.h @@ -6,12 +6,12 @@ #include <linux/if_infiniband.h> #include <linux/if_packet.h> #include <linux/netlink.h> -#include <sys/socket.h> /* linux/vms_sockets.h requires 'struct sockaddr' */ #include <linux/vm_sockets.h> #include <netinet/in.h> #include <stdbool.h> #include <stddef.h> #include <string.h> +#include <sys/socket.h> #include <sys/types.h> #include <sys/un.h> @@ -240,62 +240,11 @@ void* cmsg_find_and_copy_data(struct msghdr *mh, int level, int type, void *buf, (size) == CMSG_ALIGN(size) ? 1 : -1]; \ } -/* - * Certain hardware address types (e.g Infiniband) do not fit into sll_addr - * (8 bytes) and run over the structure. This macro returns the correct size that - * must be passed to kernel. - */ -#define SOCKADDR_LL_LEN(sa) \ - ({ \ - const struct sockaddr_ll *_sa = &(sa); \ - size_t _mac_len = sizeof(_sa->sll_addr); \ - assert(_sa->sll_family == AF_PACKET); \ - if (be16toh(_sa->sll_hatype) == ARPHRD_ETHER) \ - _mac_len = MAX(_mac_len, (size_t) ETH_ALEN); \ - if (be16toh(_sa->sll_hatype) == ARPHRD_INFINIBAND) \ - _mac_len = MAX(_mac_len, (size_t) INFINIBAND_ALEN); \ - offsetof(struct sockaddr_ll, sll_addr) + _mac_len; \ - }) +size_t sockaddr_ll_len(const struct sockaddr_ll *sa); -/* Covers only file system and abstract AF_UNIX socket addresses, but not unnamed socket addresses. */ -#define SOCKADDR_UN_LEN(sa) \ - ({ \ - const struct sockaddr_un *_sa = &(sa); \ - assert(_sa->sun_family == AF_UNIX); \ - offsetof(struct sockaddr_un, sun_path) + \ - (_sa->sun_path[0] == 0 ? \ - 1 + strnlen(_sa->sun_path+1, sizeof(_sa->sun_path)-1) : \ - strnlen(_sa->sun_path, sizeof(_sa->sun_path))+1); \ - }) +size_t sockaddr_un_len(const struct sockaddr_un *sa); -#define SOCKADDR_LEN(saddr) \ - ({ \ - const union sockaddr_union *__sa = &(saddr); \ - size_t _len; \ - switch (__sa->sa.sa_family) { \ - case AF_INET: \ - _len = sizeof(struct sockaddr_in); \ - break; \ - case AF_INET6: \ - _len = sizeof(struct sockaddr_in6); \ - break; \ - case AF_UNIX: \ - _len = SOCKADDR_UN_LEN(__sa->un); \ - break; \ - case AF_PACKET: \ - _len = SOCKADDR_LL_LEN(__sa->ll); \ - break; \ - case AF_NETLINK: \ - _len = sizeof(struct sockaddr_nl); \ - break; \ - case AF_VSOCK: \ - _len = sizeof(struct sockaddr_vm); \ - break; \ - default: \ - assert_not_reached(); \ - } \ - _len; \ - }) +size_t sockaddr_len(const union sockaddr_union *sa); int socket_ioctl_fd(void); @@ -324,6 +273,8 @@ static inline int getsockopt_int(int fd, int level, int optname, int *ret) { int socket_bind_to_ifname(int fd, const char *ifname); int socket_bind_to_ifindex(int fd, int ifindex); +int socket_autobind(int fd, char **ret_name); + /* Define a 64-bit version of timeval/timespec in any case, even on 32-bit userspace. */ struct timeval_large { uint64_t tvl_sec, tvl_usec; diff --git a/src/libnm-systemd-shared/src/basic/stat-util.c b/src/libnm-systemd-shared/src/basic/stat-util.c index ef813e19..1b352290 100644 --- a/src/libnm-systemd-shared/src/basic/stat-util.c +++ b/src/libnm-systemd-shared/src/basic/stat-util.c @@ -18,10 +18,10 @@ #include "filesystems.h" #include "fs-util.h" #include "hash-funcs.h" +#include "log.h" #include "macro.h" #include "missing_fs.h" #include "missing_magic.h" -#include "missing_syscall.h" #include "mountpoint-util.h" #include "nulstr-util.h" #include "parse-util.h" @@ -175,7 +175,7 @@ int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup) struct dirent *de; ssize_t n; - n = getdents64(fd, buf, m); + n = posix_getdents(fd, buf, m, /* flags = */ 0); if (n < 0) return -errno; if (n == 0) @@ -301,7 +301,7 @@ int inode_same_at(int fda, const char *filea, int fdb, const char *fileb, int fl flags |= AT_EMPTY_PATH; } - int ntha_flags = (flags & AT_EMPTY_PATH) | (FLAGS_SET(flags, AT_SYMLINK_NOFOLLOW) ? 0 : AT_SYMLINK_FOLLOW); + int ntha_flags = at_flags_normalize_follow(flags) & (AT_EMPTY_PATH|AT_SYMLINK_FOLLOW); _cleanup_free_ struct file_handle *ha = NULL, *hb = NULL; int mntida = -1, mntidb = -1; @@ -478,8 +478,8 @@ bool statx_inode_same(const struct statx *a, const struct statx *b) { a->stx_ino == b->stx_ino; } -bool statx_mount_same(const struct new_statx *a, const struct new_statx *b) { - if (!new_statx_is_set(a) || !new_statx_is_set(b)) +bool statx_mount_same(const struct statx *a, const struct statx *b) { + if (!statx_is_set(a) || !statx_is_set(b)) return false; /* if we have the mount ID, that's all we need */ @@ -490,76 +490,6 @@ bool statx_mount_same(const struct new_statx *a, const struct new_statx *b) { return a->stx_dev_major == b->stx_dev_major && a->stx_dev_minor == b->stx_dev_minor; } - -static bool is_statx_fatal_error(int err, int flags) { - assert(err < 0); - - /* If statx() is not supported or if we see EPERM (which might indicate seccomp filtering or so), - * let's do a fallback. Note that on EACCES we'll not fall back, since that is likely an indication of - * fs access issues, which we should propagate. */ - if (ERRNO_IS_NOT_SUPPORTED(err) || err == -EPERM) - return false; - - /* When unsupported flags are specified, glibc's fallback function returns -EINVAL. - * See statx_generic() in glibc. */ - if (err != -EINVAL) - return true; - - if ((flags & ~(AT_EMPTY_PATH | AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | AT_STATX_SYNC_AS_STAT)) != 0) - return false; /* Unsupported flags are specified. Let's try to use our implementation. */ - - return true; -} - -int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct statx *sx) { - static bool avoid_statx = false; - struct stat st; - int r; - - if (!avoid_statx) { - r = RET_NERRNO(statx(dfd, path, flags, mask, sx)); - if (r >= 0 || is_statx_fatal_error(r, flags)) - return r; - - avoid_statx = true; - } - - /* Only do fallback if fstatat() supports the flag too, or if it's one of the sync flags, which are - * OK to ignore */ - if ((flags & ~(AT_EMPTY_PATH|AT_NO_AUTOMOUNT|AT_SYMLINK_NOFOLLOW| - AT_STATX_SYNC_AS_STAT|AT_STATX_FORCE_SYNC|AT_STATX_DONT_SYNC)) != 0) - return -EOPNOTSUPP; - - if (fstatat(dfd, path, &st, flags & (AT_EMPTY_PATH|AT_NO_AUTOMOUNT|AT_SYMLINK_NOFOLLOW)) < 0) - return -errno; - - *sx = (struct statx) { - .stx_mask = STATX_TYPE|STATX_MODE| - STATX_NLINK|STATX_UID|STATX_GID| - STATX_ATIME|STATX_MTIME|STATX_CTIME| - STATX_INO|STATX_SIZE|STATX_BLOCKS, - .stx_blksize = st.st_blksize, - .stx_nlink = st.st_nlink, - .stx_uid = st.st_uid, - .stx_gid = st.st_gid, - .stx_mode = st.st_mode, - .stx_ino = st.st_ino, - .stx_size = st.st_size, - .stx_blocks = st.st_blocks, - .stx_rdev_major = major(st.st_rdev), - .stx_rdev_minor = minor(st.st_rdev), - .stx_dev_major = major(st.st_dev), - .stx_dev_minor = minor(st.st_dev), - .stx_atime.tv_sec = st.st_atim.tv_sec, - .stx_atime.tv_nsec = st.st_atim.tv_nsec, - .stx_mtime.tv_sec = st.st_mtim.tv_sec, - .stx_mtime.tv_nsec = st.st_mtim.tv_nsec, - .stx_ctime.tv_sec = st.st_ctim.tv_sec, - .stx_ctime.tv_nsec = st.st_ctim.tv_nsec, - }; - - return 0; -} #endif /* NM_IGNORED */ int xstatfsat(int dir_fd, const char *path, struct statfs *ret) { @@ -568,11 +498,14 @@ int xstatfsat(int dir_fd, const char *path, struct statfs *ret) { assert(dir_fd >= 0 || dir_fd == AT_FDCWD); assert(ret); - fd = xopenat(dir_fd, path, O_PATH|O_CLOEXEC|O_NOCTTY); - if (fd < 0) - return fd; + if (!isempty(path)) { + fd = xopenat(dir_fd, path, O_PATH|O_CLOEXEC|O_NOCTTY); + if (fd < 0) + return fd; + dir_fd = fd; + } - return RET_NERRNO(fstatfs(fd, ret)); + return RET_NERRNO(fstatfs(dir_fd, ret)); } #if 0 /* NM_IGNORED */ diff --git a/src/libnm-systemd-shared/src/basic/stat-util.h b/src/libnm-systemd-shared/src/basic/stat-util.h index 17fb520f..fcde7784 100644 --- a/src/libnm-systemd-shared/src/basic/stat-util.h +++ b/src/libnm-systemd-shared/src/basic/stat-util.h @@ -11,7 +11,6 @@ #include "fs-util.h" #include "macro.h" -#include "missing_stat.h" #include "siphash24.h" #include "time-util.h" @@ -52,10 +51,11 @@ int inode_same_at(int fda, const char *filea, int fdb, const char *fileb, int fl static inline int inode_same(const char *filea, const char *fileb, int flags) { return inode_same_at(AT_FDCWD, filea, AT_FDCWD, fileb, flags); } +#if 0 /* NM_IGNORED */ static inline int fd_inode_same(int fda, int fdb) { return inode_same_at(fda, NULL, fdb, NULL, AT_EMPTY_PATH); } - +#endif /* NM_IGNORED */ /* The .f_type field of struct statfs is really weird defined on * different archs. Let's give its type a name. */ typedef typeof(((struct statfs*)NULL)->f_type) statfs_f_type_t; @@ -90,31 +90,10 @@ bool stat_inode_same(const struct stat *a, const struct stat *b); bool stat_inode_unmodified(const struct stat *a, const struct stat *b); bool statx_inode_same(const struct statx *a, const struct statx *b); -bool statx_mount_same(const struct new_statx *a, const struct new_statx *b); - -int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct statx *sx); +bool statx_mount_same(const struct statx *a, const struct statx *b); int xstatfsat(int dir_fd, const char *path, struct statfs *ret); -#if HAS_FEATURE_MEMORY_SANITIZER -# warning "Explicitly initializing struct statx, to work around msan limitation. Please remove as soon as msan has been updated to not require this." -# define STRUCT_STATX_DEFINE(var) \ - struct statx var = {} -# define STRUCT_NEW_STATX_DEFINE(var) \ - union { \ - struct statx sx; \ - struct new_statx nsx; \ - } var = {} -#else -# define STRUCT_STATX_DEFINE(var) \ - struct statx var -# define STRUCT_NEW_STATX_DEFINE(var) \ - union { \ - struct statx sx; \ - struct new_statx nsx; \ - } var -#endif - #if 0 /* NM_IGNORED */ static inline usec_t statx_timestamp_load(const struct statx_timestamp *ts) { return timespec_load(&(const struct timespec) { .tv_sec = ts->tv_sec, .tv_nsec = ts->tv_nsec }); @@ -143,7 +122,4 @@ static inline bool stat_is_set(const struct stat *st) { static inline bool statx_is_set(const struct statx *sx) { return sx && sx->stx_mask != 0; } -static inline bool new_statx_is_set(const struct new_statx *sx) { - return sx && sx->stx_mask != 0; -} #endif /* NM_IGNORED */ diff --git a/src/libnm-systemd-shared/src/basic/stdio-util.h b/src/libnm-systemd-shared/src/basic/stdio-util.h index c35e6655..6914d998 100644 --- a/src/libnm-systemd-shared/src/basic/stdio-util.h +++ b/src/libnm-systemd-shared/src/basic/stdio-util.h @@ -8,6 +8,7 @@ #include <stdio.h> #include <sys/types.h> +#include "assert-util.h" #include "macro.h" _printf_(3, 4) diff --git a/src/libnm-systemd-shared/src/basic/string-util.c b/src/libnm-systemd-shared/src/basic/string-util.c index 6a06594a..5efd11ea 100644 --- a/src/libnm-systemd-shared/src/basic/string-util.c +++ b/src/libnm-systemd-shared/src/basic/string-util.c @@ -16,6 +16,7 @@ #include "glyph-util.h" #include "gunicode.h" #include "locale-util.h" +#include "log.h" #include "macro.h" #include "memory-util.h" #include "memstream-util.h" @@ -48,35 +49,42 @@ char* first_word(const char *s, const char *word) { return (char*) nw; } -char* strnappend(const char *s, const char *suffix, size_t b) { - size_t a; - char *r; +char* strprepend(char **x, const char *s) { + assert(x); - if (!s && !suffix) - return strdup(""); + if (isempty(s) && *x) + return *x; - if (!s) - return strndup(suffix, b); + char *p = strjoin(strempty(s), *x); + if (!p) + return NULL; - if (!suffix) - return strdup(s); + free_and_replace(*x, p); + return *x; +} - assert(s); - assert(suffix); +char* strextendn(char **x, const char *s, size_t l) { + assert(x); + assert(s || l == 0); - a = strlen(s); - if (b > SIZE_MAX - a) - return NULL; + if (l > 0) + l = strnlen(s, l); /* ignore trailing noise */ - r = new(char, a+b+1); - if (!r) - return NULL; + if (l > 0 || !*x) { + size_t q; + char *m; + + q = strlen_ptr(*x); + m = realloc(*x, q + l + 1); + if (!m) + return NULL; - memcpy(r, s, a); - memcpy(r+a, suffix, b); - r[a+b] = 0; + *mempcpy_typesafe(m + q, s, l) = 0; - return r; + *x = m; + } + + return *x; } #if 0 /* NM_IGNORED */ @@ -245,7 +253,7 @@ bool string_has_cc(const char *p, const char *ok) { #if 0 /* NM_IGNORED */ static int write_ellipsis(char *buf, bool unicode) { - const char *s = special_glyph_full(SPECIAL_GLYPH_ELLIPSIS, unicode); + const char *s = glyph_full(GLYPH_ELLIPSIS, unicode); assert(strlen(s) == 3); memcpy(buf, s, 3); return 3; @@ -333,10 +341,6 @@ static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_le case 2: if (!is_locale_utf8()) return strdup(".."); - - break; - - default: break; } @@ -983,33 +987,6 @@ oom: return -ENOMEM; } -char* strextendn(char **x, const char *s, size_t l) { - assert(x); - assert(s || l == 0); - - if (l == SIZE_MAX) - l = strlen_ptr(s); - else if (l > 0) - l = strnlen(s, l); /* ignore trailing noise */ - - if (l > 0 || !*x) { - size_t q; - char *m; - - q = strlen_ptr(*x); - m = realloc(*x, q + l + 1); - if (!m) - return NULL; - - memcpy_safe(m + q, s, l); - m[q + l] = 0; - - *x = m; - } - - return *x; -} - char* strrep(const char *s, unsigned n) { char *r, *p; size_t l; @@ -1074,6 +1051,15 @@ int free_and_strdup(char **p, const char *s) { return 1; } +int free_and_strdup_warn(char **p, const char *s) { + int r; + + r = free_and_strdup(p, s); + if (r < 0) + return log_oom(); + return r; +} + int free_and_strndup(char **p, const char *s, size_t l) { char *t; @@ -1502,3 +1488,19 @@ char* strrstr(const char *haystack, const char *needle) { } return NULL; } + +size_t str_common_prefix(const char *a, const char *b) { + assert(a); + assert(b); + + /* Returns the length of the common prefix of the two specified strings, or SIZE_MAX in case the + * strings are fully identical. */ + + for (size_t n = 0;; n++) { + char c = a[n]; + if (c != b[n]) + return n; + if (c == 0) + return SIZE_MAX; + } +} diff --git a/src/libnm-systemd-shared/src/basic/string-util.h b/src/libnm-systemd-shared/src/basic/string-util.h index 1bcb1c40..91e63c9b 100644 --- a/src/libnm-systemd-shared/src/basic/string-util.h +++ b/src/libnm-systemd-shared/src/basic/string-util.h @@ -106,7 +106,8 @@ static inline const char* empty_or_dash_to_null(const char *p) { char* first_word(const char *s, const char *word) _pure_; -char* strnappend(const char *s, const char *suffix, size_t length); +char* strprepend(char **x, const char *s); +char* strextendn(char **x, const char *s, size_t l) _nonnull_if_nonzero_(2, 3); #define strjoin(a, ...) strextend_with_separator_internal(NULL, NULL, a, __VA_ARGS__, NULL) @@ -193,8 +194,6 @@ char* strextend_with_separator_internal(char **x, const char *separator, ...) _s #define strextend_with_separator(x, separator, ...) strextend_with_separator_internal(x, separator, __VA_ARGS__, NULL) #define strextend(x, ...) strextend_with_separator_internal(x, NULL, __VA_ARGS__, NULL) -char* strextendn(char **x, const char *s, size_t l); - int strextendf_with_separator(char **x, const char *separator, const char *format, ...) _printf_(3,4); #define strextendf(x, ...) strextendf_with_separator(x, NULL, __VA_ARGS__) @@ -216,15 +215,8 @@ char* strrep(const char *s, unsigned n); int split_pair(const char *s, const char *sep, char **ret_first, char **ret_second); int free_and_strdup(char **p, const char *s); -static inline int free_and_strdup_warn(char **p, const char *s) { - int r; - - r = free_and_strdup(p, s); - if (r < 0) - return log_oom(); - return r; -} -int free_and_strndup(char **p, const char *s, size_t l); +int free_and_strdup_warn(char **p, const char *s); +int free_and_strndup(char **p, const char *s, size_t l) _nonnull_if_nonzero_(2, 3); int strdup_to_full(char **ret, const char *src); static inline int strdup_to(char **ret, const char *src) { @@ -309,3 +301,5 @@ bool version_is_valid_versionspec(const char *s); ssize_t strlevenshtein(const char *x, const char *y); char* strrstr(const char *haystack, const char *needle); + +size_t str_common_prefix(const char *a, const char *b); diff --git a/src/libnm-systemd-shared/src/basic/strv.c b/src/libnm-systemd-shared/src/basic/strv.c index 38466696..f433afc7 100644 --- a/src/libnm-systemd-shared/src/basic/strv.c +++ b/src/libnm-systemd-shared/src/basic/strv.c @@ -14,6 +14,7 @@ #include "extract-word.h" #include "fileio.h" #include "gunicode.h" +#include "log.h" #include "memory-util.h" #include "nulstr-util.h" #include "sort-util.h" @@ -637,7 +638,7 @@ int strv_insert(char ***l, size_t position, char *value) { n = strv_length(*l); position = MIN(position, n); - /* check for overflow and increase*/ + /* check for overflow and increase */ if (n > SIZE_MAX - 2) return -ENOMEM; m = n + 2; @@ -868,11 +869,11 @@ int strv_compare(char * const *a, char * const *b) { return 0; } -bool strv_equal_ignore_order(char **a, char **b) { +bool strv_equal_ignore_order(char * const *a, char * const *b) { /* Just like strv_equal(), but doesn't care about the order of elements or about redundant entries * (i.e. it's even ok if the number of entries in the array differ, as long as the difference just - * consists of repititions) */ + * consists of repetitions). */ if (a == b) return true; @@ -892,6 +893,7 @@ void strv_print_full(char * const *l, const char *prefix) { STRV_FOREACH(s, l) printf("%s%s\n", strempty(prefix), *s); } +#endif /* NM_IGNORED */ int strv_extendf(char ***l, const char *format, ...) { va_list ap; @@ -907,7 +909,7 @@ int strv_extendf(char ***l, const char *format, ...) { return strv_consume(l, x); } -#endif /* NM_IGNORED */ + char* startswith_strv(const char *s, char * const *l) { STRV_FOREACH(i, l) { @@ -986,14 +988,16 @@ bool strv_fnmatch_full( } char** strv_skip(char **l, size_t n) { - while (n > 0) { if (strv_isempty(l)) - return l; + return NULL; l++, n--; } + /* To simplify callers, always return NULL instead of a zero-item array. */ + if (strv_isempty(l)) + return NULL; return l; } @@ -1074,7 +1078,22 @@ int fputstrv(FILE *f, char * const *l, const char *separator, bool *space) { } #if 0 /* NM_IGNORED */ -DEFINE_PRIVATE_HASH_OPS_FULL(string_strv_hash_ops, char, string_hash_func, string_compare_func, free, char*, strv_free); +void string_strv_hashmap_remove(Hashmap *h, const char *key, const char *value) { + assert(key); + + if (value) { + char **l = hashmap_get(h, key); + if (!l) + return; + + strv_remove(l, value); + if (!strv_isempty(l)) + return; + } + + _unused_ _cleanup_free_ char *key_free = NULL; + strv_free(hashmap_remove2(h, key, (void**) &key_free)); +} static int string_strv_hashmap_put_internal(Hashmap *h, const char *key, const char *value) { char **l; @@ -1126,7 +1145,7 @@ int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value HA assert(key); assert(value); - r = _hashmap_ensure_allocated(h, &string_strv_hash_ops HASHMAP_DEBUG_PASS_ARGS); + r = _hashmap_ensure_allocated(h, &string_hash_ops_free_strv_free HASHMAP_DEBUG_PASS_ARGS); if (r < 0) return r; @@ -1140,7 +1159,7 @@ int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const assert(key); assert(value); - r = _ordered_hashmap_ensure_allocated(h, &string_strv_hash_ops HASHMAP_DEBUG_PASS_ARGS); + r = _ordered_hashmap_ensure_allocated(h, &string_hash_ops_free_strv_free HASHMAP_DEBUG_PASS_ARGS); if (r < 0) return r; @@ -1234,4 +1253,25 @@ int strv_rebreak_lines(char **l, size_t width, char ***ret) { *ret = TAKE_PTR(broken); return 0; } + +char** strv_filter_prefix(char * const *l, const char *prefix) { + + /* Allocates a copy of 'l', but only copies over entries starting with 'prefix' */ + + if (isempty(prefix)) + return strv_copy(l); + + _cleanup_strv_free_ char **f = NULL; + size_t sz = 0; + + STRV_FOREACH(i, l) { + if (!startswith(*i, prefix)) + continue; + + if (strv_extend_with_size(&f, &sz, *i) < 0) + return NULL; + } + + return TAKE_PTR(f); +} #endif /* NM_IGNORED */ diff --git a/src/libnm-systemd-shared/src/basic/strv.h b/src/libnm-systemd-shared/src/basic/strv.h index 86ba06f8..0ca90087 100644 --- a/src/libnm-systemd-shared/src/basic/strv.h +++ b/src/libnm-systemd-shared/src/basic/strv.h @@ -33,7 +33,7 @@ char** strv_free_erase(char **l); DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free_erase); #define _cleanup_strv_free_erase_ _cleanup_(strv_free_erasep) -void strv_free_many(char ***strvs, size_t n); +void strv_free_many(char ***strvs, size_t n) _nonnull_if_nonzero_(1, 2); char** strv_copy_n(char * const *l, size_t n); static inline char** strv_copy(char * const *l) { @@ -96,7 +96,7 @@ static inline bool strv_equal(char * const *a, char * const *b) { return strv_compare(a, b) == 0; } -bool strv_equal_ignore_order(char **a, char **b); +bool strv_equal_ignore_order(char * const *a, char * const *b); char** strv_new_internal(const char *x, ...) _sentinel_; char** strv_new_ap(const char *x, va_list ap); @@ -258,9 +258,15 @@ int fputstrv(FILE *f, char * const *l, const char *separator, bool *space); #define strv_free_and_replace(a, b) \ free_and_replace_full(a, b, strv_free) +void string_strv_hashmap_remove(Hashmap *h, const char *key, const char *value); +static inline void string_strv_ordered_hashmap_remove(OrderedHashmap *h, const char *key, const char *value) { + string_strv_hashmap_remove(PLAIN_HASHMAP(h), key, value); +} int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS); int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS); #define string_strv_hashmap_put(h, k, v) _string_strv_hashmap_put(h, k, v HASHMAP_DEBUG_SRC_ARGS) #define string_strv_ordered_hashmap_put(h, k, v) _string_strv_ordered_hashmap_put(h, k, v HASHMAP_DEBUG_SRC_ARGS) int strv_rebreak_lines(char **l, size_t width, char ***ret); + +char** strv_filter_prefix(char * const *l, const char *prefix); diff --git a/src/libnm-systemd-shared/src/basic/time-util.c b/src/libnm-systemd-shared/src/basic/time-util.c index 594d5315..06e27cfb 100644 --- a/src/libnm-systemd-shared/src/basic/time-util.c +++ b/src/libnm-systemd-shared/src/basic/time-util.c @@ -10,6 +10,7 @@ #include <sys/time.h> #include <sys/timerfd.h> #include <sys/types.h> +#include <threads.h> #include <unistd.h> #include "alloc-util.h" @@ -19,8 +20,6 @@ #include "io-util.h" #include "log.h" #include "macro.h" -#include "missing_threads.h" -#include "missing_timerfd.h" #include "parse-util.h" #include "path-util.h" #include "process-util.h" @@ -1643,7 +1642,7 @@ int mktime_or_timegm_usec( assert(tm); - if (tm->tm_year < 69) /* early check for negative (i.e. before 1970) time_t (Note that in some timezones the epoch is in the year 1969!)*/ + if (tm->tm_year < 69) /* early check for negative (i.e. before 1970) time_t (Note that in some timezones the epoch is in the year 1969!) */ return -ERANGE; if ((usec_t) tm->tm_year > CONST_MIN(USEC_INFINITY / USEC_PER_YEAR, (usec_t) TIME_T_MAX / (365U * 24U * 60U * 60U)) - 1900) /* early check for possible overrun of usec_t or time_t */ return -ERANGE; diff --git a/src/libnm-systemd-shared/src/basic/time-util.h b/src/libnm-systemd-shared/src/basic/time-util.h index 14d660ee..3f6e3c9f 100644 --- a/src/libnm-systemd-shared/src/basic/time-util.h +++ b/src/libnm-systemd-shared/src/basic/time-util.h @@ -222,8 +222,8 @@ static inline int usleep_safe(usec_t usec) { if (usec == 0) return 0; - // FIXME: use RET_NERRNO() macro here. Currently, this header cannot include errno-util.h. - return clock_nanosleep(CLOCK_MONOTONIC, 0, TIMESPEC_STORE(usec), NULL) < 0 ? -errno : 0; + /* `clock_nanosleep()` does not use `errno`, but returns positive error codes. */ + return -clock_nanosleep(CLOCK_MONOTONIC, 0, TIMESPEC_STORE(usec), NULL); } /* The last second we can format is 31. Dec 9999, 1s before midnight, because otherwise we'd enter 5 digit diff --git a/src/libnm-systemd-shared/src/basic/tmpfile-util.c b/src/libnm-systemd-shared/src/basic/tmpfile-util.c index 3d1b8d04..4e1fe711 100644 --- a/src/libnm-systemd-shared/src/basic/tmpfile-util.c +++ b/src/libnm-systemd-shared/src/basic/tmpfile-util.c @@ -9,6 +9,7 @@ #include "fileio.h" #include "fs-util.h" #include "hexdecoct.h" +#include "log.h" #include "macro.h" #include "memfd-util.h" #include "missing_fcntl.h" diff --git a/src/libnm-systemd-shared/src/basic/user-util.c b/src/libnm-systemd-shared/src/basic/user-util.c new file mode 100644 index 00000000..9b80750a --- /dev/null +++ b/src/libnm-systemd-shared/src/basic/user-util.c @@ -0,0 +1,1243 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "nm-sd-adapt-shared.h" + +#include <errno.h> +#include <fcntl.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <unistd.h> +#include <utmpx.h> + +#include "sd-messages.h" + +#include "alloc-util.h" +#include "chase.h" +#include "errno-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "format-util.h" +#include "lock-util.h" +#include "log.h" +#include "macro.h" +#include "mkdir.h" +#include "parse-util.h" +#include "path-util.h" +#include "random-util.h" +#include "string-util.h" +#include "strv.h" +#include "terminal-util.h" +#include "user-util.h" +#include "utf8.h" + +bool uid_is_valid(uid_t uid) { + + /* Also see POSIX IEEE Std 1003.1-2008, 2016 Edition, 3.436. */ + + /* Some libc APIs use UID_INVALID as special placeholder */ + if (uid == (uid_t) UINT32_C(0xFFFFFFFF)) + return false; + + /* A long time ago UIDs where 16 bit, hence explicitly avoid the 16-bit -1 too */ + if (uid == (uid_t) UINT32_C(0xFFFF)) + return false; + + return true; +} + +int parse_uid(const char *s, uid_t *ret) { + uint32_t uid = 0; + int r; + + assert(s); + + assert_cc(sizeof(uid_t) == sizeof(uint32_t)); + + /* We are very strict when parsing UIDs, and prohibit +/- as prefix, leading zero as prefix, and + * whitespace. We do this, since this call is often used in a context where we parse things as UID + * first, and if that doesn't work we fall back to NSS. Thus we really want to make sure that UIDs + * are parsed as UIDs only if they really really look like UIDs. */ + r = safe_atou32_full(s, 10 + | SAFE_ATO_REFUSE_PLUS_MINUS + | SAFE_ATO_REFUSE_LEADING_ZERO + | SAFE_ATO_REFUSE_LEADING_WHITESPACE, &uid); + if (r < 0) + return r; + + if (!uid_is_valid(uid)) + return -ENXIO; /* we return ENXIO instead of EINVAL + * here, to make it easy to distinguish + * invalid numeric uids from invalid + * strings. */ + + if (ret) + *ret = uid; + + return 0; +} + +#if 0 /* NM_IGNORED */ +int parse_uid_range(const char *s, uid_t *ret_lower, uid_t *ret_upper) { + _cleanup_free_ char *word = NULL; + uid_t l, u; + int r; + + assert(s); + assert(ret_lower); + assert(ret_upper); + + r = extract_first_word(&s, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return r; + if (r == 0) + return -EINVAL; + + r = parse_uid(word, &l); + if (r < 0) + return r; + + /* Check for the upper bound and extract it if needed */ + if (!s) + /* Single number with no dash. */ + u = l; + else if (!*s) + /* Trailing dash is an error. */ + return -EINVAL; + else { + r = parse_uid(s, &u); + if (r < 0) + return r; + + if (l > u) + return -EINVAL; + } + + *ret_lower = l; + *ret_upper = u; + return 0; +} + +char* getlogname_malloc(void) { + uid_t uid; + struct stat st; + + if (isatty_safe(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0) + uid = st.st_uid; + else + uid = getuid(); + + return uid_to_name(uid); +} + +char* getusername_malloc(void) { + const char *e; + + e = secure_getenv("USER"); + if (e) + return strdup(e); + + return uid_to_name(getuid()); +} + +bool is_nologin_shell(const char *shell) { + return PATH_IN_SET(shell, + /* 'nologin' is the friendliest way to disable logins for a user account. It prints a nice + * message and exits. Different distributions place the binary at different places though, + * hence let's list them all. */ + "/bin/nologin", + "/sbin/nologin", + "/usr/bin/nologin", + "/usr/sbin/nologin", + /* 'true' and 'false' work too for the same purpose, but are less friendly as they don't do + * any message printing. Different distributions place the binary at various places but at + * least not in the 'sbin' directory. */ + "/bin/false", + "/usr/bin/false", + "/bin/true", + "/usr/bin/true"); +} + +const char* default_root_shell_at(int rfd) { + /* We want to use the preferred shell, i.e. DEFAULT_USER_SHELL, which usually + * will be /bin/bash. Fall back to /bin/sh if DEFAULT_USER_SHELL is not found, + * or any access errors. */ + + assert(rfd >= 0 || rfd == AT_FDCWD); + + int r = chaseat(rfd, DEFAULT_USER_SHELL, CHASE_AT_RESOLVE_IN_ROOT, NULL, NULL); + if (r < 0 && r != -ENOENT) + log_debug_errno(r, "Failed to look up shell '%s': %m", DEFAULT_USER_SHELL); + if (r > 0) + return DEFAULT_USER_SHELL; + + return "/bin/sh"; +} + +const char* default_root_shell(const char *root) { + _cleanup_close_ int rfd = -EBADF; + + rfd = open(empty_to_root(root), O_CLOEXEC | O_DIRECTORY | O_PATH); + if (rfd < 0) + return "/bin/sh"; + + return default_root_shell_at(rfd); +} + +static int synthesize_user_creds( + const char **username, + uid_t *ret_uid, gid_t *ret_gid, + const char **ret_home, + const char **ret_shell, + UserCredsFlags flags) { + + assert(username); + assert(*username); + + /* We enforce some special rules for uid=0 and uid=65534: in order to avoid NSS lookups for root we hardcode + * their user record data. */ + + if (STR_IN_SET(*username, "root", "0")) { + *username = "root"; + + if (ret_uid) + *ret_uid = 0; + if (ret_gid) + *ret_gid = 0; + if (ret_home) + *ret_home = "/root"; + if (ret_shell) + *ret_shell = default_root_shell(NULL); + + return 0; + } + + if (STR_IN_SET(*username, NOBODY_USER_NAME, "65534") && + synthesize_nobody()) { + *username = NOBODY_USER_NAME; + + if (ret_uid) + *ret_uid = UID_NOBODY; + if (ret_gid) + *ret_gid = GID_NOBODY; + if (ret_home) + *ret_home = FLAGS_SET(flags, USER_CREDS_SUPPRESS_PLACEHOLDER) ? NULL : "/"; + if (ret_shell) + *ret_shell = FLAGS_SET(flags, USER_CREDS_SUPPRESS_PLACEHOLDER) ? NULL : NOLOGIN; + + return 0; + } + + return -ENOMEDIUM; +} + +int get_user_creds( + const char **username, + uid_t *ret_uid, gid_t *ret_gid, + const char **ret_home, + const char **ret_shell, + UserCredsFlags flags) { + + bool patch_username = false; + uid_t u = UID_INVALID; + struct passwd *p; + int r; + + assert(username); + assert(*username); + assert((ret_home || ret_shell) || !(flags & (USER_CREDS_SUPPRESS_PLACEHOLDER|USER_CREDS_CLEAN))); + + if (!FLAGS_SET(flags, USER_CREDS_PREFER_NSS) || + (!ret_home && !ret_shell)) { + + /* So here's the deal: normally, we'll try to synthesize all records we can synthesize, and override + * the user database with that. However, if the user specifies USER_CREDS_PREFER_NSS then the + * user database will override the synthetic records instead — except if the user is only interested in + * the UID and/or GID (but not the home directory, or the shell), in which case we'll always override + * the user database (i.e. the USER_CREDS_PREFER_NSS flag has no effect in this case). Why? + * Simply because there are valid usecase where the user might change the home directory or the shell + * of the relevant users, but changing the UID/GID mappings for them is something we explicitly don't + * support. */ + + r = synthesize_user_creds(username, ret_uid, ret_gid, ret_home, ret_shell, flags); + if (r >= 0) + return 0; + if (r != -ENOMEDIUM) /* not a username we can synthesize */ + return r; + } + + if (parse_uid(*username, &u) >= 0) { + errno = 0; + p = getpwuid(u); + + /* If there are multiple users with the same id, make sure to leave $USER to the configured value + * instead of the first occurrence in the database. However if the uid was configured by a numeric uid, + * then let's pick the real username from /etc/passwd. */ + if (p) + patch_username = true; + else if (FLAGS_SET(flags, USER_CREDS_ALLOW_MISSING) && !ret_gid && !ret_home && !ret_shell) { + + /* If the specified user is a numeric UID and it isn't in the user database, and the caller + * passed USER_CREDS_ALLOW_MISSING and was only interested in the UID, then just return that + * and don't complain. */ + + if (ret_uid) + *ret_uid = u; + + return 0; + } + } else { + errno = 0; + p = getpwnam(*username); + } + if (!p) { + /* getpwnam() may fail with ENOENT if /etc/passwd is missing. + * For us that is equivalent to the name not being defined. */ + r = IN_SET(errno, 0, ENOENT) ? -ESRCH : -errno; + + /* If the user requested that we only synthesize as fallback, do so now */ + if (FLAGS_SET(flags, USER_CREDS_PREFER_NSS)) + if (synthesize_user_creds(username, ret_uid, ret_gid, ret_home, ret_shell, flags) >= 0) + return 0; + + return r; + } + + if (ret_uid && !uid_is_valid(p->pw_uid)) + return -EBADMSG; + + if (ret_gid && !gid_is_valid(p->pw_gid)) + return -EBADMSG; + + if (ret_uid) + *ret_uid = p->pw_uid; + + if (ret_gid) + *ret_gid = p->pw_gid; + + if (ret_home) + /* Note: we don't insist on normalized paths, since there are setups that have /./ in the path */ + *ret_home = (FLAGS_SET(flags, USER_CREDS_SUPPRESS_PLACEHOLDER) && empty_or_root(p->pw_dir)) || + (FLAGS_SET(flags, USER_CREDS_CLEAN) && (!path_is_valid(p->pw_dir) || !path_is_absolute(p->pw_dir))) + ? NULL : p->pw_dir; + + if (ret_shell) + *ret_shell = (FLAGS_SET(flags, USER_CREDS_SUPPRESS_PLACEHOLDER) && shell_is_placeholder(p->pw_shell)) || + (FLAGS_SET(flags, USER_CREDS_CLEAN) && (!path_is_valid(p->pw_shell) || !path_is_absolute(p->pw_shell))) + ? NULL : p->pw_shell; + + if (patch_username) + *username = p->pw_name; + + return 0; +} + +static int synthesize_group_creds( + const char **groupname, + gid_t *ret_gid) { + + assert(groupname); + assert(*groupname); + + if (STR_IN_SET(*groupname, "root", "0")) { + *groupname = "root"; + + if (ret_gid) + *ret_gid = 0; + + return 0; + } + + if (STR_IN_SET(*groupname, NOBODY_GROUP_NAME, "65534") && + synthesize_nobody()) { + *groupname = NOBODY_GROUP_NAME; + + if (ret_gid) + *ret_gid = GID_NOBODY; + + return 0; + } + + return -ENOMEDIUM; +} + +int get_group_creds(const char **groupname, gid_t *ret_gid, UserCredsFlags flags) { + bool patch_groupname = false; + struct group *g; + gid_t id; + int r; + + assert(groupname); + assert(*groupname); + + if (!FLAGS_SET(flags, USER_CREDS_PREFER_NSS)) { + r = synthesize_group_creds(groupname, ret_gid); + if (r >= 0) + return 0; + if (r != -ENOMEDIUM) /* not a groupname we can synthesize */ + return r; + } + + if (parse_gid(*groupname, &id) >= 0) { + errno = 0; + g = getgrgid(id); + + if (g) + patch_groupname = true; + else if (FLAGS_SET(flags, USER_CREDS_ALLOW_MISSING)) { + if (ret_gid) + *ret_gid = id; + + return 0; + } + } else { + errno = 0; + g = getgrnam(*groupname); + } + + if (!g) { + /* getgrnam() may fail with ENOENT if /etc/group is missing. + * For us that is equivalent to the name not being defined. */ + r = IN_SET(errno, 0, ENOENT) ? -ESRCH : -errno; + + if (FLAGS_SET(flags, USER_CREDS_PREFER_NSS)) + if (synthesize_group_creds(groupname, ret_gid) >= 0) + return 0; + + return r; + } + + if (ret_gid) { + if (!gid_is_valid(g->gr_gid)) + return -EBADMSG; + + *ret_gid = g->gr_gid; + } + + if (patch_groupname) + *groupname = g->gr_name; + + return 0; +} + +char* uid_to_name(uid_t uid) { + char *ret; + int r; + + /* Shortcut things to avoid NSS lookups */ + if (uid == 0) + return strdup("root"); + if (uid == UID_NOBODY && synthesize_nobody()) + return strdup(NOBODY_USER_NAME); + + if (uid_is_valid(uid)) { + _cleanup_free_ struct passwd *pw = NULL; + + r = getpwuid_malloc(uid, &pw); + if (r >= 0) + return strdup(pw->pw_name); + } + + if (asprintf(&ret, UID_FMT, uid) < 0) + return NULL; + + return ret; +} + +char* gid_to_name(gid_t gid) { + char *ret; + int r; + + if (gid == 0) + return strdup("root"); + if (gid == GID_NOBODY && synthesize_nobody()) + return strdup(NOBODY_GROUP_NAME); + + if (gid_is_valid(gid)) { + _cleanup_free_ struct group *gr = NULL; + + r = getgrgid_malloc(gid, &gr); + if (r >= 0) + return strdup(gr->gr_name); + } + + if (asprintf(&ret, GID_FMT, gid) < 0) + return NULL; + + return ret; +} + +static bool gid_list_has(const gid_t *list, size_t size, gid_t val) { + assert(list || size == 0); + + FOREACH_ARRAY(i, list, size) + if (*i == val) + return true; + + return false; +} + +int in_gid(gid_t gid) { + _cleanup_free_ gid_t *gids = NULL; + int ngroups; + + if (getgid() == gid) + return 1; + + if (getegid() == gid) + return 1; + + if (!gid_is_valid(gid)) + return -EINVAL; + + ngroups = getgroups_alloc(&gids); + if (ngroups < 0) + return ngroups; + + return gid_list_has(gids, ngroups, gid); +} + +int in_group(const char *name) { + int r; + gid_t gid; + + r = get_group_creds(&name, &gid, 0); + if (r < 0) + return r; + + return in_gid(gid); +} + +int merge_gid_lists(const gid_t *list1, size_t size1, const gid_t *list2, size_t size2, gid_t **ret) { + size_t nresult = 0; + assert(ret); + + if (size2 > INT_MAX - size1) + return -ENOBUFS; + + gid_t *buf = new(gid_t, size1 + size2); + if (!buf) + return -ENOMEM; + + /* Duplicates need to be skipped on merging, otherwise they'll be passed on and stored in the kernel. */ + for (size_t i = 0; i < size1; i++) + if (!gid_list_has(buf, nresult, list1[i])) + buf[nresult++] = list1[i]; + for (size_t i = 0; i < size2; i++) + if (!gid_list_has(buf, nresult, list2[i])) + buf[nresult++] = list2[i]; + *ret = buf; + return (int)nresult; +} + +int getgroups_alloc(gid_t **ret) { + int ngroups = 8; + + assert(ret); + + for (unsigned attempt = 0;;) { + _cleanup_free_ gid_t *p = NULL; + + p = new(gid_t, ngroups); + if (!p) + return -ENOMEM; + + ngroups = getgroups(ngroups, p); + if (ngroups > 0) { + *ret = TAKE_PTR(p); + return ngroups; + } + if (ngroups == 0) + break; + if (errno != EINVAL) + return -errno; + + /* Give up eventually */ + if (attempt++ > 10) + return -EINVAL; + + /* Get actual size needed, and size the array explicitly. Note that this is potentially racy + * to use (in multi-threaded programs), hence let's call this in a loop. */ + ngroups = getgroups(0, NULL); + if (ngroups < 0) + return -errno; + if (ngroups == 0) + break; + } + + *ret = NULL; + return 0; +} + +int get_home_dir(char **ret) { + _cleanup_free_ struct passwd *p = NULL; + const char *e; + uid_t u; + int r; + + assert(ret); + + /* Take the user specified one */ + e = secure_getenv("HOME"); + if (e && path_is_valid(e) && path_is_absolute(e)) + goto found; + + /* Hardcode home directory for root and nobody to avoid NSS */ + u = getuid(); + if (u == 0) { + e = "/root"; + goto found; + } + if (u == UID_NOBODY && synthesize_nobody()) { + e = "/"; + goto found; + } + + /* Check the database... */ + r = getpwuid_malloc(u, &p); + if (r < 0) + return r; + + e = p->pw_dir; + if (!path_is_valid(e) || !path_is_absolute(e)) + return -EINVAL; + + found: + return path_simplify_alloc(e, ret); +} + +int get_shell(char **ret) { + _cleanup_free_ struct passwd *p = NULL; + const char *e; + uid_t u; + int r; + + assert(ret); + + /* Take the user specified one */ + e = secure_getenv("SHELL"); + if (e && path_is_valid(e) && path_is_absolute(e)) + goto found; + + /* Hardcode shell for root and nobody to avoid NSS */ + u = getuid(); + if (u == 0) { + e = default_root_shell(NULL); + goto found; + } + if (u == UID_NOBODY && synthesize_nobody()) { + e = NOLOGIN; + goto found; + } + + /* Check the database... */ + r = getpwuid_malloc(u, &p); + if (r < 0) + return r; + + e = p->pw_shell; + if (!path_is_valid(e) || !path_is_absolute(e)) + return -EINVAL; + + found: + return path_simplify_alloc(e, ret); +} + +int fully_set_uid_gid(uid_t uid, gid_t gid, const gid_t supplementary_gids[], size_t n_supplementary_gids) { + int r; + + assert(supplementary_gids || n_supplementary_gids == 0); + + /* Sets all UIDs and all GIDs to the specified ones. Drops all auxiliary GIDs */ + + r = maybe_setgroups(n_supplementary_gids, supplementary_gids); + if (r < 0) + return r; + + if (gid_is_valid(gid)) + if (setresgid(gid, gid, gid) < 0) + return -errno; + + if (uid_is_valid(uid)) + if (setresuid(uid, uid, uid) < 0) + return -errno; + + return 0; +} + +int take_etc_passwd_lock(const char *root) { + int r; + + /* This is roughly the same as lckpwdf(), but not as awful. We don't want to use alarm() and signals, + * hence we implement our own trivial version of this. + * + * Note that shadow-utils also takes per-database locks in addition to lckpwdf(). However, we don't, + * given that they are redundant: they invoke lckpwdf() first and keep it during everything they do. + * The per-database locks are awfully racy, and thus we just won't do them. */ + + _cleanup_free_ char *path = path_join(root, ETC_PASSWD_LOCK_PATH); + if (!path) + return log_oom_debug(); + + (void) mkdir_parents(path, 0755); + + _cleanup_close_ int fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0600); + if (fd < 0) + return log_debug_errno(errno, "Cannot open %s: %m", path); + + r = unposix_lock(fd, LOCK_EX); + if (r < 0) + return log_debug_errno(r, "Locking %s failed: %m", path); + + return TAKE_FD(fd); +} + +bool valid_user_group_name(const char *u, ValidUserFlags flags) { + const char *i; + + /* Checks if the specified name is a valid user/group name. There are two flavours of this call: + * strict mode is the default which is POSIX plus some extra rules; and relaxed mode where we accept + * pretty much everything except the really worst offending names. + * + * Whenever we synthesize users ourselves we should use the strict mode. But when we process users + * created by other stuff, let's be more liberal. */ + + if (isempty(u)) /* An empty user name is never valid */ + return false; + + if (parse_uid(u, NULL) >= 0) /* Something that parses as numeric UID string is valid exactly when the + * flag for it is set */ + return FLAGS_SET(flags, VALID_USER_ALLOW_NUMERIC); + + if (FLAGS_SET(flags, VALID_USER_RELAX)) { + + /* In relaxed mode we just check very superficially. Apparently SSSD and other stuff is + * extremely liberal (way too liberal if you ask me, even inserting "@" in user names, which + * is bound to cause problems for example when used with an MTA), hence only filter the most + * obvious cases, or where things would result in an invalid entry if such a user name would + * show up in /etc/passwd (or equivalent getent output). + * + * Note that we stepped far out of POSIX territory here. It's not our fault though, but + * SSSD's, Samba's and everybody else who ignored POSIX on this. (I mean, I am happy to step + * outside of POSIX' bounds any day, but I must say in this case I probably wouldn't + * have...) */ + + if (startswith(u, " ") || endswith(u, " ")) /* At least expect whitespace padding is removed + * at front and back (accept in the middle, since + * that's apparently a thing on Windows). Note + * that this also blocks usernames consisting of + * whitespace only. */ + return false; + + if (!utf8_is_valid(u)) /* We want to synthesize JSON from this, hence insist on UTF-8 */ + return false; + + if (string_has_cc(u, NULL)) /* CC characters are just dangerous (and \n in particular is the + * record separator in /etc/passwd), so we can't allow that. */ + return false; + + if (strpbrk(u, ":/")) /* Colons are the field separator in /etc/passwd, we can't allow + * that. Slashes are special to file systems paths and user names + * typically show up in the file system as home directories, hence + * don't allow slashes. */ + return false; + + if (in_charset(u, "0123456789")) /* Don't allow fully numeric strings, they might be confused + * with UIDs (note that this test is more broad than + * the parse_uid() test above, as it will cover more than + * the 32-bit range, and it will detect 65535 (which is in + * invalid UID, even though in the unsigned 32 bit range) */ + return false; + + if (u[0] == '-' && in_charset(u + 1, "0123456789")) /* Don't allow negative fully numeric + * strings either. After all some people + * write 65535 as -1 (even though that's + * not even true on 32-bit uid_t + * anyway) */ + return false; + + if (dot_or_dot_dot(u)) /* User names typically become home directory names, and these two are + * special in that context, don't allow that. */ + return false; + + /* Compare with strict result and warn if result doesn't match */ + if (FLAGS_SET(flags, VALID_USER_WARN) && !valid_user_group_name(u, 0)) + log_struct(LOG_NOTICE, + LOG_MESSAGE("Accepting user/group name '%s', which does not match strict user/group name rules.", u), + LOG_ITEM("USER_GROUP_NAME=%s", u), + LOG_MESSAGE_ID(SD_MESSAGE_UNSAFE_USER_NAME_STR)); + + /* Note that we make no restrictions on the length in relaxed mode! */ + } else { + long sz; + size_t l; + + /* Also see POSIX IEEE Std 1003.1-2008, 2016 Edition, 3.437. We are a bit stricter here + * however. Specifically we deviate from POSIX rules: + * + * - We don't allow empty user names (see above) + * - We require that names fit into the appropriate utmp field + * - We don't allow any dots (this conflicts with chown syntax which permits dots as user/group name separator) + * - We don't allow dashes or digit as the first character + * + * Note that other systems are even more restrictive, and don't permit underscores or uppercase characters. + */ + + if (!ascii_isalpha(u[0]) && + u[0] != '_') + return false; + + for (i = u+1; *i; i++) + if (!ascii_isalpha(*i) && + !ascii_isdigit(*i) && + !IN_SET(*i, '_', '-')) + return false; + + l = i - u; + + sz = sysconf(_SC_LOGIN_NAME_MAX); + assert_se(sz > 0); + + if (l > (size_t) sz) /* glibc: 256 */ + return false; + if (l > NAME_MAX) /* must fit in a filename: 255 */ + return false; + if (l > sizeof_field(struct utmpx, ut_user) - 1) /* must fit in utmp: 31 */ + return false; + } + + return true; +} + +bool valid_gecos(const char *d) { + + if (!d) + return false; + + if (!utf8_is_valid(d)) + return false; + + if (string_has_cc(d, NULL)) + return false; + + /* Colons are used as field separators, and hence not OK */ + if (strchr(d, ':')) + return false; + + return true; +} + +char* mangle_gecos(const char *d) { + char *mangled; + + /* Makes sure the provided string becomes valid as a GEGOS field, by dropping bad chars. glibc's + * putwent() only changes \n and : to spaces. We do more: replace all CC too, and remove invalid + * UTF-8 */ + + mangled = strdup(d); + if (!mangled) + return NULL; + + for (char *i = mangled; *i; i++) { + int len; + + if ((uint8_t) *i < (uint8_t) ' ' || *i == ':') { + *i = ' '; + continue; + } + + len = utf8_encoded_valid_unichar(i, SIZE_MAX); + if (len < 0) { + *i = ' '; + continue; + } + + i += len - 1; + } + + return mangled; +} + +bool valid_home(const char *p) { + /* Note that this function is also called by valid_shell(), any + * changes must account for that. */ + + if (isempty(p)) + return false; + + if (!utf8_is_valid(p)) + return false; + + if (string_has_cc(p, NULL)) + return false; + + if (!path_is_absolute(p)) + return false; + + if (!path_is_normalized(p)) + return false; + + /* Colons are used as field separators, and hence not OK */ + if (strchr(p, ':')) + return false; + + return true; +} + +bool valid_shell(const char *p) { + /* We have the same requirements, so just piggy-back on the home check. + * + * Let's ignore /etc/shells because this is only applicable to real and not system users. It is also + * incompatible with the idea of empty /etc/. */ + if (!valid_home(p)) + return false; + + return !endswith(p, "/"); /* one additional restriction: shells may not be dirs */ +} + +int maybe_setgroups(size_t size, const gid_t *list) { + int r; + + /* Check if setgroups is allowed before we try to drop all the auxiliary groups */ + if (size == 0) { /* Dropping all aux groups? */ + _cleanup_free_ char *setgroups_content = NULL; + bool can_setgroups; + + r = read_one_line_file("/proc/self/setgroups", &setgroups_content); + if (r == -ENOENT) + /* Old kernels don't have /proc/self/setgroups, so assume we can use setgroups */ + can_setgroups = true; + else if (r < 0) + return r; + else + can_setgroups = streq(setgroups_content, "allow"); + + if (!can_setgroups) { + log_debug("Skipping setgroups(), /proc/self/setgroups is set to 'deny'"); + return 0; + } + } + + return RET_NERRNO(setgroups(size, list)); +} + +bool synthesize_nobody(void) { + /* Returns true when we shall synthesize the "nobody" user (which we do by default). This can be turned off by + * touching /etc/systemd/dont-synthesize-nobody in order to provide upgrade compatibility with legacy systems + * that used the "nobody" user name and group name for other UIDs/GIDs than 65534. + * + * Note that we do not employ any kind of synchronization on the following caching variable. If the variable is + * accessed in multi-threaded programs in the worst case it might happen that we initialize twice, but that + * shouldn't matter as each initialization should come to the same result. */ + static int cache = -1; + + if (cache < 0) + cache = access("/etc/systemd/dont-synthesize-nobody", F_OK) < 0; + + return cache; +} + +int putpwent_sane(const struct passwd *pw, FILE *stream) { + assert(pw); + assert(stream); + + errno = 0; + if (putpwent(pw, stream) != 0) + return errno_or_else(EIO); + + return 0; +} + +int putspent_sane(const struct spwd *sp, FILE *stream) { + assert(sp); + assert(stream); + + errno = 0; + if (putspent(sp, stream) != 0) + return errno_or_else(EIO); + + return 0; +} + +int putgrent_sane(const struct group *gr, FILE *stream) { + assert(gr); + assert(stream); + + errno = 0; + if (putgrent(gr, stream) != 0) + return errno_or_else(EIO); + + return 0; +} + +#if ENABLE_GSHADOW +int putsgent_sane(const struct sgrp *sg, FILE *stream) { + assert(sg); + assert(stream); + + errno = 0; + if (putsgent(sg, stream) != 0) + return errno_or_else(EIO); + + return 0; +} +#endif + +int fgetpwent_sane(FILE *stream, struct passwd **pw) { + assert(stream); + assert(pw); + + errno = 0; + struct passwd *p = fgetpwent(stream); + if (!p && !IN_SET(errno, 0, ENOENT)) + return -errno; + + *pw = p; + return !!p; +} + +int fgetspent_sane(FILE *stream, struct spwd **sp) { + assert(stream); + assert(sp); + + errno = 0; + struct spwd *s = fgetspent(stream); + if (!s && !IN_SET(errno, 0, ENOENT)) + return -errno; + + *sp = s; + return !!s; +} + +int fgetgrent_sane(FILE *stream, struct group **gr) { + assert(stream); + assert(gr); + + errno = 0; + struct group *g = fgetgrent(stream); + if (!g && !IN_SET(errno, 0, ENOENT)) + return -errno; + + *gr = g; + return !!g; +} + +#if ENABLE_GSHADOW +int fgetsgent_sane(FILE *stream, struct sgrp **sg) { + assert(stream); + assert(sg); + + errno = 0; + struct sgrp *s = fgetsgent(stream); + if (!s && !IN_SET(errno, 0, ENOENT)) + return -errno; + + *sg = s; + return !!s; +} +#endif + +int is_this_me(const char *username) { + uid_t uid; + int r; + + /* Checks if the specified username is our current one. Passed string might be a UID or a user name. */ + + r = get_user_creds(&username, &uid, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING); + if (r < 0) + return r; + + return uid == getuid(); +} + +const char* get_home_root(void) { + const char *e; + + /* For debug purposes allow overriding where we look for home dirs */ + e = secure_getenv("SYSTEMD_HOME_ROOT"); + if (e && path_is_absolute(e) && path_is_normalized(e)) + return e; + + return "/home"; +} + +static size_t getpw_buffer_size(void) { + long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); + return bufsize <= 0 ? 4096U : (size_t) bufsize; +} + +static bool errno_is_user_doesnt_exist(int error) { + /* See getpwnam(3) and getgrnam(3): those codes and others can be returned if the user or group are + * not found. */ + return IN_SET(abs(error), ENOENT, ESRCH, EBADF, EPERM); +} + +int getpwnam_malloc(const char *name, struct passwd **ret) { + size_t bufsize = getpw_buffer_size(); + int r; + + /* A wrapper around getpwnam_r() that allocates the necessary buffer on the heap. The caller must + * free() the returned structures! */ + + if (isempty(name)) + return -EINVAL; + + for (;;) { + _cleanup_free_ void *buf = NULL; + + buf = malloc(ALIGN(sizeof(struct passwd)) + bufsize); + if (!buf) + return -ENOMEM; + + struct passwd *pw = NULL; + r = getpwnam_r(name, buf, (char*) buf + ALIGN(sizeof(struct passwd)), (size_t) bufsize, &pw); + if (r == 0) { + if (pw) { + if (ret) + *ret = TAKE_PTR(buf); + return 0; + } + + return -ESRCH; + } + + assert(r > 0); + + /* getpwnam() may fail with ENOENT if /etc/passwd is missing. For us that is equivalent to + * the name not being defined. */ + if (errno_is_user_doesnt_exist(r)) + return -ESRCH; + if (r != ERANGE) + return -r; + + if (bufsize > SIZE_MAX/2 - ALIGN(sizeof(struct passwd))) + return -ENOMEM; + bufsize *= 2; + } +} + +int getpwuid_malloc(uid_t uid, struct passwd **ret) { + size_t bufsize = getpw_buffer_size(); + int r; + + if (!uid_is_valid(uid)) + return -EINVAL; + + for (;;) { + _cleanup_free_ void *buf = NULL; + + buf = malloc(ALIGN(sizeof(struct passwd)) + bufsize); + if (!buf) + return -ENOMEM; + + struct passwd *pw = NULL; + r = getpwuid_r(uid, buf, (char*) buf + ALIGN(sizeof(struct passwd)), (size_t) bufsize, &pw); + if (r == 0) { + if (pw) { + if (ret) + *ret = TAKE_PTR(buf); + return 0; + } + + return -ESRCH; + } + + assert(r > 0); + + if (errno_is_user_doesnt_exist(r)) + return -ESRCH; + if (r != ERANGE) + return -r; + + if (bufsize > SIZE_MAX/2 - ALIGN(sizeof(struct passwd))) + return -ENOMEM; + bufsize *= 2; + } +} + +static size_t getgr_buffer_size(void) { + long bufsize = sysconf(_SC_GETGR_R_SIZE_MAX); + return bufsize <= 0 ? 4096U : (size_t) bufsize; +} + +int getgrnam_malloc(const char *name, struct group **ret) { + size_t bufsize = getgr_buffer_size(); + int r; + + if (isempty(name)) + return -EINVAL; + + for (;;) { + _cleanup_free_ void *buf = NULL; + + buf = malloc(ALIGN(sizeof(struct group)) + bufsize); + if (!buf) + return -ENOMEM; + + struct group *gr = NULL; + r = getgrnam_r(name, buf, (char*) buf + ALIGN(sizeof(struct group)), (size_t) bufsize, &gr); + if (r == 0) { + if (gr) { + if (ret) + *ret = TAKE_PTR(buf); + return 0; + } + + return -ESRCH; + } + + assert(r > 0); + + if (errno_is_user_doesnt_exist(r)) + return -ESRCH; + if (r != ERANGE) + return -r; + + if (bufsize > SIZE_MAX/2 - ALIGN(sizeof(struct group))) + return -ENOMEM; + bufsize *= 2; + } +} + +int getgrgid_malloc(gid_t gid, struct group **ret) { + size_t bufsize = getgr_buffer_size(); + int r; + + if (!gid_is_valid(gid)) + return -EINVAL; + + for (;;) { + _cleanup_free_ void *buf = NULL; + + buf = malloc(ALIGN(sizeof(struct group)) + bufsize); + if (!buf) + return -ENOMEM; + + struct group *gr = NULL; + r = getgrgid_r(gid, buf, (char*) buf + ALIGN(sizeof(struct group)), (size_t) bufsize, &gr); + if (r == 0) { + if (gr) { + if (ret) + *ret = TAKE_PTR(buf); + return 0; + } + + return -ESRCH; + } + + assert(r > 0); + + if (errno_is_user_doesnt_exist(r)) + return -ESRCH; + if (r != ERANGE) + return -r; + + if (bufsize > SIZE_MAX/2 - ALIGN(sizeof(struct group))) + return -ENOMEM; + bufsize *= 2; + } +} +#endif /* NM_IGNORED */ \ No newline at end of file diff --git a/src/libnm-systemd-shared/src/basic/utf8.c b/src/libnm-systemd-shared/src/basic/utf8.c index 33fdd96e..74d60f56 100644 --- a/src/libnm-systemd-shared/src/basic/utf8.c +++ b/src/libnm-systemd-shared/src/basic/utf8.c @@ -616,4 +616,29 @@ size_t utf8_console_width(const char *str) { return n; } + +size_t utf8_last_length(const char *s, size_t n) { + int r; + + assert(s); + + if (n == SIZE_MAX) + n = strlen(s); + + /* Determines length in bytes of last UTF-8 codepoint in string. If the string is empty, returns + * zero. Treats invalid UTF-8 codepoints as 1 sized ones. */ + + for (size_t last = 0;;) { + if (n == 0) + return last; + + r = utf8_encoded_valid_unichar(s, n); + if (r <= 0) + r = 1; /* treat invalid UTF-8 as byte-wide */ + + s += r; + n -= r; + last = r; + } +} #endif /* NM_IGNORED */ diff --git a/src/libnm-systemd-shared/src/basic/utf8.h b/src/libnm-systemd-shared/src/basic/utf8.h index 221bc46a..3b1a468c 100644 --- a/src/libnm-systemd-shared/src/basic/utf8.h +++ b/src/libnm-systemd-shared/src/basic/utf8.h @@ -7,7 +7,6 @@ #include <uchar.h> #include "macro.h" -#include "missing_type.h" #define UTF8_REPLACEMENT_CHARACTER "\xef\xbf\xbd" #define UTF8_BYTE_ORDER_MARK "\xef\xbb\xbf" @@ -62,3 +61,5 @@ static inline char32_t utf16_surrogate_pair_to_unichar(char16_t lead, char16_t t size_t utf8_n_codepoints(const char *str); int utf8_char_console_width(const char *str); size_t utf8_console_width(const char *str); + +size_t utf8_last_length(const char *s, size_t n); diff --git a/src/libnm-systemd-shared/src/fundamental/assert-fundamental.h b/src/libnm-systemd-shared/src/fundamental/assert-fundamental.h new file mode 100644 index 00000000..e207958b --- /dev/null +++ b/src/libnm-systemd-shared/src/fundamental/assert-fundamental.h @@ -0,0 +1,141 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#if !SD_BOOT +# include <assert.h> +#endif + +#include "macro-fundamental.h" +#include "log.h" + +#if SD_BOOT + _noreturn_ void efi_assert(const char *expr, const char *file, unsigned line, const char *function); + + #ifdef NDEBUG + #define assert(expr) ({ if (!(expr)) __builtin_unreachable(); }) + #define assert_not_reached() __builtin_unreachable() + #else + #define assert(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __func__); }) + #define assert_not_reached() efi_assert("Code should not be reached", __FILE__, __LINE__, __func__) + #endif + #define assert_se(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __func__); }) +#else + +#if 0 /* NM_IGNORED */ +_noreturn_ void log_assert_failed(const char *text, const char *file, int line, const char *func); +#else /* NM_IGNORED */ +#define log_assert_failed(text, file, line, func) \ + G_STMT_START \ + { \ + log_internal(LOG_CRIT, \ + 0, \ + file, \ + line, \ + func, \ + "Assertion '%s' failed at %s:%u, function %s(). Aborting.", \ + text, \ + file, \ + line, \ + func); \ + g_assert_not_reached(); \ + } \ + G_STMT_END +#endif /* NM_IGNORED */ + +#if 0 /* NM_IGNORED */ +_noreturn_ void log_assert_failed_unreachable(const char *file, int line, const char *func); +#else /* NM_IGNORED */ +#define log_assert_failed_unreachable(file, line, func) \ + G_STMT_START \ + { \ + log_internal(LOG_CRIT, \ + 0, \ + file, \ + line, \ + func, \ + "Code should not be reached at %s:%u, function %s(). Aborting.", \ + file, \ + line, \ + func); \ + g_assert_not_reached(); \ + } \ + G_STMT_END +#endif /* NM_IGNORED */ + +#ifdef __COVERITY__ + +/* Use special definitions of assertion macros in order to prevent + * false positives of ASSERT_SIDE_EFFECT on Coverity static analyzer + * for uses of assert_se() and assert_return(). + * + * These definitions make expression go through a (trivial) function + * call to ensure they are not discarded. Also use ! or !! to ensure + * the boolean expressions are seen as such. + * + * This technique has been described and recommended in: + * https://community.synopsys.com/s/question/0D534000046Yuzb/suppressing-assertsideeffect-for-functions-that-allow-for-sideeffects + */ + +extern void __coverity_panic__(void); + +static inline void __coverity_check__(int condition) { + if (!condition) + __coverity_panic__(); +} + +static inline int __coverity_check_and_return__(int condition) { + return condition; +} + +#define assert_message_se(expr, message) __coverity_check__(!!(expr)) + +#define assert_log(expr, message) __coverity_check_and_return__(!!(expr)) + +#else /* ! __COVERITY__ */ + +#define assert_message_se(expr, message) \ + do { \ + if (_unlikely_(!(expr))) \ + log_assert_failed(message, PROJECT_FILE, __LINE__, __func__); \ + } while (false) + +#endif /* __COVERITY__ */ + +#define assert_se(expr) assert_message_se(expr, #expr) + +/* We override the glibc assert() here. */ +#undef assert +#ifdef NDEBUG +#define assert(expr) ({ if (!(expr)) __builtin_unreachable(); }) +#else +#define assert(expr) assert_message_se(expr, #expr) +#endif + +#define assert_not_reached() \ + log_assert_failed_unreachable(PROJECT_FILE, __LINE__, __func__) + +#endif + +/* This passes the argument through after (if asserts are enabled) checking that it is not null. */ +#define ASSERT_PTR(expr) _ASSERT_PTR(expr, UNIQ_T(_expr_, UNIQ), assert) +#define ASSERT_SE_PTR(expr) _ASSERT_PTR(expr, UNIQ_T(_expr_, UNIQ), assert_se) +#define _ASSERT_PTR(expr, var, check) \ + ({ \ + typeof(expr) var = (expr); \ + check(var); \ + var; \ + }) + +#define ASSERT_NONNEG(expr) \ + ({ \ + typeof(expr) _expr_ = (expr), _zero = 0; \ + assert(_expr_ >= _zero); \ + _expr_; \ + }) + +#define ASSERT_SE_NONNEG(expr) \ + ({ \ + typeof(expr) _expr_ = (expr), _zero = 0; \ + assert_se(_expr_ >= _zero); \ + _expr_; \ + }) diff --git a/src/libnm-systemd-shared/src/fundamental/iovec-util-fundamental.h b/src/libnm-systemd-shared/src/fundamental/iovec-util-fundamental.h index 68d5bf4e..4c86197e 100644 --- a/src/libnm-systemd-shared/src/fundamental/iovec-util-fundamental.h +++ b/src/libnm-systemd-shared/src/fundamental/iovec-util-fundamental.h @@ -1,6 +1,14 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#if !SD_BOOT +#include <stdlib.h> +#include <sys/uio.h> +#endif + +#include "assert-fundamental.h" +#include "macro-fundamental.h" + #if SD_BOOT /* struct iovec is a POSIX userspace construct. Let's introduce it also in EFI mode, it's just so useful */ struct iovec { @@ -8,7 +16,9 @@ struct iovec { size_t iov_len; }; -static inline void free(void *p); +DISABLE_WARNING_REDUNDANT_DECLS; +void free(void *p); +REENABLE_WARNING; #endif /* This accepts both const and non-const pointers */ diff --git a/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h index 418ea55f..abdfb9b6 100644 --- a/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h +++ b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h @@ -1,16 +1,19 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#if !SD_BOOT -# include <assert.h> -#endif - #include <limits.h> #include <stdalign.h> #include <stdbool.h> #include <stddef.h> #include <stdint.h> +/* This header unconditionally defines MAX() so include it here already so + * it won't override our own definition of MAX() that we define later in this + * file. */ +#if !SD_BOOT +#include <sys/param.h> +#endif + /* Temporarily disable some warnings */ #define DISABLE_WARNING_DEPRECATED_DECLARATIONS \ _Pragma("GCC diagnostic push"); \ @@ -53,6 +56,9 @@ _Pragma("GCC diagnostic ignored \"-Wstringop-truncation\"") #if 0 /* NM_IGNORED */ +#define DISABLE_WARNING_REDUNDANT_DECLS \ + _Pragma("GCC diagnostic push"); \ + _Pragma("GCC diagnostic ignored \"-Wredundant-decls\"") #if HAVE_WARNING_ZERO_LENGTH_BOUNDS # define DISABLE_WARNING_ZERO_LENGTH_BOUNDS \ @@ -123,9 +129,19 @@ # define _fallthrough_ __attribute__((__fallthrough__)) #endif +#if __GNUC__ >= 15 +# define _nonnull_if_nonzero_(p, n) __attribute__((nonnull_if_nonzero(p, n))) +#else +# define _nonnull_if_nonzero_(p, n) +#endif + #define XSTRINGIFY(x) #x #define STRINGIFY(x) XSTRINGIFY(x) +/* C23 changed char8_t from char to unsigned char, hence we cannot pass u8 literals to e.g. fputs() without + * casting. Let's introduce our own way to declare UTF-8 literals, which casts u8 literals to const char*. */ +#define UTF8(s) ((const char*) (u8"" s)) + #ifndef __COVERITY__ # define VOID_0 ((void)0) #else @@ -141,45 +157,7 @@ #define XCONCATENATE(x, y) x ## y #define CONCATENATE(x, y) XCONCATENATE(x, y) -#if SD_BOOT - _noreturn_ void efi_assert(const char *expr, const char *file, unsigned line, const char *function); - - #ifdef NDEBUG - #define assert(expr) ({ if (!(expr)) __builtin_unreachable(); }) - #define assert_not_reached() __builtin_unreachable() - #else - #define assert(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __func__); }) - #define assert_not_reached() efi_assert("Code should not be reached", __FILE__, __LINE__, __func__) - #endif - #define static_assert _Static_assert - #define assert_se(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __func__); }) -#endif - -/* This passes the argument through after (if asserts are enabled) checking that it is not null. */ -#define ASSERT_PTR(expr) _ASSERT_PTR(expr, UNIQ_T(_expr_, UNIQ), assert) -#define ASSERT_SE_PTR(expr) _ASSERT_PTR(expr, UNIQ_T(_expr_, UNIQ), assert_se) -#define _ASSERT_PTR(expr, var, check) \ - ({ \ - typeof(expr) var = (expr); \ - check(var); \ - var; \ - }) - -#define ASSERT_NONNEG(expr) \ - ({ \ - typeof(expr) _expr_ = (expr), _zero = 0; \ - assert(_expr_ >= _zero); \ - _expr_; \ - }) - -#define ASSERT_SE_NONNEG(expr) \ - ({ \ - typeof(expr) _expr_ = (expr), _zero = 0; \ - assert_se(_expr_ >= _zero); \ - _expr_; \ - }) - -#define assert_cc(expr) static_assert(expr, #expr) +#define assert_cc(expr) _Static_assert(expr, #expr) #define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq)) #define UNIQ __COUNTER__ @@ -434,7 +412,7 @@ _found = true; \ break; \ default: \ - break; \ + ; \ } \ _found; \ }) @@ -467,82 +445,6 @@ (typeof(memory)) NULL; \ }) -static inline size_t ALIGN_TO(size_t l, size_t ali) { - assert(ISPOWEROF2(ali)); - - if (l > SIZE_MAX - (ali - 1)) - return SIZE_MAX; /* indicate overflow */ - - return ((l + (ali - 1)) & ~(ali - 1)); -} - -static inline uint64_t ALIGN_TO_U64(uint64_t l, uint64_t ali) { - assert(ISPOWEROF2(ali)); - - if (l > UINT64_MAX - (ali - 1)) - return UINT64_MAX; /* indicate overflow */ - - return ((l + (ali - 1)) & ~(ali - 1)); -} - -static inline size_t ALIGN_DOWN(size_t l, size_t ali) { - assert(ISPOWEROF2(ali)); - - return l & ~(ali - 1); -} - -static inline uint64_t ALIGN_DOWN_U64(uint64_t l, uint64_t ali) { - assert(ISPOWEROF2(ali)); - - return l & ~(ali - 1); -} - -static inline size_t ALIGN_OFFSET(size_t l, size_t ali) { - assert(ISPOWEROF2(ali)); - - return l & (ali - 1); -} - -static inline uint64_t ALIGN_OFFSET_U64(uint64_t l, uint64_t ali) { - assert(ISPOWEROF2(ali)); - - return l & (ali - 1); -} - -#define ALIGN2(l) ALIGN_TO(l, 2) -#define ALIGN4(l) ALIGN_TO(l, 4) -#define ALIGN8(l) ALIGN_TO(l, 8) -#define ALIGN2_PTR(p) ((void*) ALIGN2((uintptr_t) p)) -#define ALIGN4_PTR(p) ((void*) ALIGN4((uintptr_t) p)) -#define ALIGN8_PTR(p) ((void*) ALIGN8((uintptr_t) p)) -#define ALIGN(l) ALIGN_TO(l, sizeof(void*)) -#define ALIGN_PTR(p) ((void*) ALIGN((uintptr_t) (p))) - -/* Checks if the specified pointer is aligned as appropriate for the specific type */ -#define IS_ALIGNED16(p) (((uintptr_t) p) % alignof(uint16_t) == 0) -#define IS_ALIGNED32(p) (((uintptr_t) p) % alignof(uint32_t) == 0) -#define IS_ALIGNED64(p) (((uintptr_t) p) % alignof(uint64_t) == 0) - -/* Same as ALIGN_TO but callable in constant contexts. */ -#define CONST_ALIGN_TO(l, ali) \ - __builtin_choose_expr( \ - __builtin_constant_p(l) && \ - __builtin_constant_p(ali) && \ - CONST_ISPOWEROF2(ali) && \ - (l <= SIZE_MAX - (ali - 1)), /* overflow? */ \ - ((l) + (ali) - 1) & ~((ali) - 1), \ - VOID_0) - -/* Similar to ((t *) (void *) (p)) to cast a pointer. The macro asserts that the pointer has a suitable - * alignment for type "t". This exists for places where otherwise "-Wcast-align=strict" would issue a - * warning or if you want to assert that the cast gives a pointer of suitable alignment. */ -#define CAST_ALIGN_PTR(t, p) \ - ({ \ - const void *_p = (p); \ - assert(((uintptr_t) _p) % alignof(t) == 0); \ - (t *) _p; \ - }) - #define UPDATE_FLAG(orig, flag, b) \ ((b) ? ((orig) | (flag)) : ((orig) & ~(flag))) #define SET_FLAG(v, flag, b) \ @@ -550,41 +452,11 @@ static inline uint64_t ALIGN_OFFSET_U64(uint64_t l, uint64_t ali) { #define FLAGS_SET(v, flags) \ ((~(v) & (flags)) == 0) -/* A wrapper for 'func' to return void. - * Only useful when a void-returning function is required by some API. */ -#define DEFINE_TRIVIAL_DESTRUCTOR(name, type, func) \ - static inline void name(type *p) { \ - func(p); \ - } - -/* When func() returns the void value (NULL, -1, …) of the appropriate type */ -#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \ - static inline void func##p(type *p) { \ - if (*p) \ - *p = func(*p); \ - } - -/* When func() doesn't return the appropriate type, set variable to empty afterwards. - * The func() may be provided by a dynamically loaded shared library, hence add an assertion. */ -#define DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(type, func, empty) \ - static inline void func##p(type *p) { \ - if (*p != (empty)) { \ - DISABLE_WARNING_ADDRESS; \ - assert(func); \ - REENABLE_WARNING; \ - func(*p); \ - *p = (empty); \ - } \ - } +typedef struct { + int _empty[0]; +} dummy_t; -/* When func() doesn't return the appropriate type, and is also a macro, set variable to empty afterwards. */ -#define DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_MACRO(type, func, empty) \ - static inline void func##p(type *p) { \ - if (*p != (empty)) { \ - func(*p); \ - *p = (empty); \ - } \ - } +assert_cc(sizeof(dummy_t) == 0); /* Restriction/bug (see below) was fixed in GCC 15 and clang 19. */ #if __GNUC__ >= 15 || (defined(__clang__) && __clang_major__ >= 19) @@ -633,3 +505,10 @@ static inline uint64_t ALIGN_OFFSET_U64(uint64_t l, uint64_t ali) { #define PTR_TO_SIZE(p) ((size_t) ((uintptr_t) (p))) #define SIZE_TO_PTR(u) ((void *) ((uintptr_t) (u))) + +#if 0 /* NM_IGNORED */ +assert_cc(STRLEN(__FILE__) > STRLEN(RELATIVE_SOURCE_PATH) + 1); +#define PROJECT_FILE (&__FILE__[STRLEN(RELATIVE_SOURCE_PATH) + 1]) +#else /* NM_IGNORED */ +#define PROJECT_FILE __FILE__ +#endif /* NM_IGNORED */ \ No newline at end of file diff --git a/src/libnm-systemd-shared/src/fundamental/memory-util-fundamental.h b/src/libnm-systemd-shared/src/fundamental/memory-util-fundamental.h index 6870f54f..4b50714f 100644 --- a/src/libnm-systemd-shared/src/fundamental/memory-util-fundamental.h +++ b/src/libnm-systemd-shared/src/fundamental/memory-util-fundamental.h @@ -9,6 +9,7 @@ # include <string.h> #endif +#include "assert-fundamental.h" #include "macro-fundamental.h" #define memzero(x, l) \ @@ -17,7 +18,7 @@ _l_ > 0 ? memset((x), 0, _l_) : (x); \ }) -#if !SD_BOOT && HAVE_EXPLICIT_BZERO +#if !SD_BOOT static inline void *explicit_bzero_safe(void *p, size_t l) { if (p && l > 0) explicit_bzero(p, l); @@ -106,3 +107,115 @@ static inline void array_cleanup(const ArrayCleanup *c) { _f; \ }), \ } + +/* A wrapper for 'func' to return void. + * Only useful when a void-returning function is required by some API. */ +#define DEFINE_TRIVIAL_DESTRUCTOR(name, type, func) \ + static inline void name(type *p) { \ + func(p); \ + } + +/* When func() returns the void value (NULL, -1, …) of the appropriate type */ +#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \ + static inline void func##p(type *p) { \ + if (*p) \ + *p = func(*p); \ + } + +/* When func() doesn't return the appropriate type, set variable to empty afterwards. + * The func() may be provided by a dynamically loaded shared library, hence add an assertion. */ +#define DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(type, func, empty) \ + static inline void func##p(type *p) { \ + if (*p != (empty)) { \ + DISABLE_WARNING_ADDRESS; \ + assert(func); \ + REENABLE_WARNING; \ + func(*p); \ + *p = (empty); \ + } \ + } + +/* When func() doesn't return the appropriate type, and is also a macro, set variable to empty afterwards. */ +#define DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_MACRO(type, func, empty) \ + static inline void func##p(type *p) { \ + if (*p != (empty)) { \ + func(*p); \ + *p = (empty); \ + } \ + } + +static inline size_t ALIGN_TO(size_t l, size_t ali) { + assert(ISPOWEROF2(ali)); + + if (l > SIZE_MAX - (ali - 1)) + return SIZE_MAX; /* indicate overflow */ + + return ((l + (ali - 1)) & ~(ali - 1)); +} + +static inline uint64_t ALIGN_TO_U64(uint64_t l, uint64_t ali) { + assert(ISPOWEROF2(ali)); + + if (l > UINT64_MAX - (ali - 1)) + return UINT64_MAX; /* indicate overflow */ + + return ((l + (ali - 1)) & ~(ali - 1)); +} + +static inline size_t ALIGN_DOWN(size_t l, size_t ali) { + assert(ISPOWEROF2(ali)); + + return l & ~(ali - 1); +} + +static inline uint64_t ALIGN_DOWN_U64(uint64_t l, uint64_t ali) { + assert(ISPOWEROF2(ali)); + + return l & ~(ali - 1); +} + +static inline size_t ALIGN_OFFSET(size_t l, size_t ali) { + assert(ISPOWEROF2(ali)); + + return l & (ali - 1); +} + +static inline uint64_t ALIGN_OFFSET_U64(uint64_t l, uint64_t ali) { + assert(ISPOWEROF2(ali)); + + return l & (ali - 1); +} + +#define ALIGN2(l) ALIGN_TO(l, 2) +#define ALIGN4(l) ALIGN_TO(l, 4) +#define ALIGN8(l) ALIGN_TO(l, 8) +#define ALIGN2_PTR(p) ((void*) ALIGN2((uintptr_t) p)) +#define ALIGN4_PTR(p) ((void*) ALIGN4((uintptr_t) p)) +#define ALIGN8_PTR(p) ((void*) ALIGN8((uintptr_t) p)) +#define ALIGN(l) ALIGN_TO(l, sizeof(void*)) +#define ALIGN_PTR(p) ((void*) ALIGN((uintptr_t) (p))) + +/* Checks if the specified pointer is aligned as appropriate for the specific type */ +#define IS_ALIGNED16(p) (((uintptr_t) p) % alignof(uint16_t) == 0) +#define IS_ALIGNED32(p) (((uintptr_t) p) % alignof(uint32_t) == 0) +#define IS_ALIGNED64(p) (((uintptr_t) p) % alignof(uint64_t) == 0) + +/* Same as ALIGN_TO but callable in constant contexts. */ +#define CONST_ALIGN_TO(l, ali) \ + __builtin_choose_expr( \ + __builtin_constant_p(l) && \ + __builtin_constant_p(ali) && \ + CONST_ISPOWEROF2(ali) && \ + (l <= SIZE_MAX - (ali - 1)), /* overflow? */ \ + ((l) + (ali) - 1) & ~((ali) - 1), \ + VOID_0) + +/* Similar to ((t *) (void *) (p)) to cast a pointer. The macro asserts that the pointer has a suitable + * alignment for type "t". This exists for places where otherwise "-Wcast-align=strict" would issue a + * warning or if you want to assert that the cast gives a pointer of suitable alignment. */ +#define CAST_ALIGN_PTR(t, p) \ + ({ \ + const void *_p = (p); \ + assert(((uintptr_t) _p) % alignof(t) == 0); \ + (t *) _p; \ + }) diff --git a/src/libnm-systemd-shared/src/fundamental/sha256-fundamental.c b/src/libnm-systemd-shared/src/fundamental/sha256-fundamental.c index 6682bc87..8e842535 100644 --- a/src/libnm-systemd-shared/src/fundamental/sha256-fundamental.c +++ b/src/libnm-systemd-shared/src/fundamental/sha256-fundamental.c @@ -23,6 +23,13 @@ License along with the GNU C Library; if not, see <https://www.gnu.org/licenses/>. */ +#if SD_BOOT +# include "efi-string.h" +#else +# include <string.h> +#endif + +#include "assert-fundamental.h" #include "macro-fundamental.h" #include "memory-util-fundamental.h" #include "sha256-fundamental.h" diff --git a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c index da810cb7..0a62dbb2 100644 --- a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c +++ b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c @@ -85,7 +85,7 @@ static bool is_valid_version_char(sd_char a) { int strverscmp_improved(const sd_char *a, const sd_char *b) { /* This function is similar to strverscmp(3), but it treats '-' and '.' as separators. * - * The logic is based on rpm's rpmvercmp(), but unlike rpmvercmp(), it distiguishes e.g. + * The logic is based on rpm's rpmvercmp(), but unlike rpmvercmp(), it distinguishes e.g. * '123a' and '123.a', with '123a' being newer. * * It allows direct comparison of strings which contain both a version and a release; e.g. diff --git a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h index 419f1cc3..a9638b4d 100644 --- a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h +++ b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h @@ -8,6 +8,7 @@ # include <string.h> #endif +#include "assert-fundamental.h" #include "macro-fundamental.h" #if SD_BOOT @@ -16,6 +17,8 @@ # define strncmp strncmp16 # define strcasecmp strcasecmp16 # define strncasecmp strncasecmp16 +# define strspn strspn16 +# define strcspn strcspn16 # define STR_C(str) (L ## str) typedef char16_t sd_char; #else diff --git a/src/libnm-systemd-shared/src/shared/dns-domain.c b/src/libnm-systemd-shared/src/shared/dns-domain.c index 42efd04a..eaca0715 100644 --- a/src/libnm-systemd-shared/src/shared/dns-domain.c +++ b/src/libnm-systemd-shared/src/shared/dns-domain.c @@ -15,6 +15,7 @@ #include "hostname-util.h" #include "idn-util.h" #include "in-addr-util.h" +#include "log.h" #include "macro.h" #include "parse-util.h" #include "string-util.h" @@ -1395,7 +1396,7 @@ int dns_name_apply_idna(const char *name, char **ret) { r = sym_idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t, IDN2_NFC_INPUT | IDN2_TRANSITIONAL); - log_debug("idn2_lookup_u8: %s %s %s", name, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), t); + log_debug("idn2_lookup_u8: %s %s %s", name, glyph(GLYPH_ARROW_RIGHT), t); if (r == IDN2_OK) { if (!startswith(name, "xn--")) { _cleanup_free_ char *s = NULL; @@ -1410,8 +1411,8 @@ int dns_name_apply_idna(const char *name, char **ret) { if (!streq_ptr(name, s)) { log_debug("idn2 roundtrip failed: \"%s\" %s \"%s\" %s \"%s\", ignoring.", - name, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), t, - special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), s); + name, glyph(GLYPH_ARROW_RIGHT), t, + glyph(GLYPH_ARROW_RIGHT), s); *ret = NULL; return 0; } diff --git a/src/libnmc-base/nm-client-utils.c b/src/libnmc-base/nm-client-utils.c index 326d8d20..10c2c295 100644 --- a/src/libnmc-base/nm-client-utils.c +++ b/src/libnmc-base/nm-client-utils.c @@ -483,7 +483,7 @@ NM_UTILS_LOOKUP_STR_DEFINE( "(\"unmanaged-devices\" for keyfile or \"NM_CONTROLLED=no\" for ifcfg-rh)")), NM_UTILS_LOOKUP_ITEM(NM_DEVICE_STATE_REASON_UNMANAGED_USER_CONF, N_("The device is unmanaged by user decision in NetworkManager.conf " - "('unmanaged' in a [device*] section")), + "('unmanaged' in a [device*] section)")), NM_UTILS_LOOKUP_ITEM( NM_DEVICE_STATE_REASON_UNMANAGED_BY_DEFAULT, N_("The device is unmanaged because the device type is unmanaged by default")), @@ -493,6 +493,8 @@ NM_UTILS_LOOKUP_STR_DEFINE( N_("The device is unmanaged because it is an external device and is " "unconfigured (down or without addresses)")), NM_UTILS_LOOKUP_ITEM(NM_DEVICE_STATE_REASON_NETWORKING_OFF, N_("Networking was disabled")), + NM_UTILS_LOOKUP_ITEM(NM_DEVICE_STATE_REASON_MODEM_NO_OPERATOR_CODE, + N_("The modem didn't have an operator code")), ); diff --git a/src/libnmc-setting/nm-meta-setting-desc.c b/src/libnmc-setting/nm-meta-setting-desc.c index c035ad54..e2ab8dfa 100644 --- a/src/libnmc-setting/nm-meta-setting-desc.c +++ b/src/libnmc-setting/nm-meta-setting-desc.c @@ -4156,6 +4156,50 @@ _optionlist_set_fcn_vpn_secrets(NMSetting *setting, return TRUE; } +static void +_objlist_obj_to_str_fcn_wireguard_peers(NMMetaAccessorGetType get_type, + NMSetting *setting, + guint idx, + GString *str) +{ + NMWireGuardPeer *peer; + gs_free char *peer_str = NULL; + + peer = nm_setting_wireguard_get_peer(NM_SETTING_WIREGUARD(setting), idx); + peer_str = _nm_utils_wireguard_peer_to_string(peer); + g_string_append(str, peer_str); +} + +static gboolean +_objlist_set_fcn_wireguard_peers(NMSetting *setting, + gboolean do_add, + const char *value, + GError **error) +{ + NMSettingWireGuard *s_wg = NM_SETTING_WIREGUARD(setting); + nm_auto_unref_wgpeer NMWireGuardPeer *peer = NULL; + + peer = _nm_utils_wireguard_peer_from_string(value, error); + if (!peer) + return FALSE; + + if (do_add) { + nm_setting_wireguard_append_peer(s_wg, peer); + } else { + NMWireGuardPeer *match; + guint idx; + + match = nm_setting_wireguard_get_peer_by_public_key(s_wg, + nm_wireguard_peer_get_public_key(peer), + &idx); + if (match) { + nm_setting_wireguard_remove_peer(s_wg, idx); + } + } + + return TRUE; +} + static gboolean _set_fcn_wired_s390_subchannels(ARGS_SET_FCN) { @@ -5801,6 +5845,9 @@ static const NMMetaPropertyInfo *const property_infos_CONNECTION[] = { ), ), ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_DNSSEC, + .property_type = &_pt_gobject_enum, + ), PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_MPTCP_FLAGS, .property_type = &_pt_gobject_enum, .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( @@ -6169,6 +6216,9 @@ static const NMMetaPropertyInfo *const property_infos_GSM[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_GSM_INITIAL_EPS_BEARER_REFUSE_MSCHAPV2, .property_type = &_pt_gobject_bool, ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_GSM_DEVICE_UID, + .property_type = &_pt_gobject_string, + ), NULL }; @@ -8432,6 +8482,21 @@ static const NMMetaPropertyInfo *const property_infos_WIREGUARD[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_WIREGUARD_IP6_AUTO_DEFAULT_ROUTE, .property_type = &_pt_gobject_ternary, ), + + PROPERTY_INFO_WITH_DESC (NM_SETTING_WIREGUARD_PEERS, + .property_type = &_pt_objlist, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (objlist, + .get_num_fcn = OBJLIST_GET_NUM_FCN (NMSettingWireGuard, nm_setting_wireguard_get_peers_len), + .clear_all_fcn = (void (*) (NMSetting *))(void (*)(void)) nm_setting_wireguard_clear_peers, + .obj_to_str_fcn = _objlist_obj_to_str_fcn_wireguard_peers, + .set_fcn = _objlist_set_fcn_wireguard_peers, + .remove_by_idx_fcn_u = (void (*) (NMSetting *, guint idx))(void (*)(void)) nm_setting_wireguard_remove_peer, + .strsplit_plain = TRUE, + ), + ), + ), + NULL }; diff --git a/src/libnmc-setting/settings-docs.h.in b/src/libnmc-setting/settings-docs.h.in index ce9f27f9..89f8c6d1 100644 --- a/src/libnmc-setting/settings-docs.h.in +++ b/src/libnmc-setting/settings-docs.h.in @@ -8,6 +8,7 @@ #define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES N_("Whether or not ports of this connection should be automatically brought up when NetworkManager activates this connection. This only has a real effect for controller connections. The properties \"autoconnect\", \"autoconnect-priority\" and \"autoconnect-retries\" are unrelated to this setting. The permitted values are: 0: leave port connections untouched, 1: activate all the port connections with this connection, -1: default. If -1 (default) is set, global connection.autoconnect-slaves is read to determine the real value. If it is default as well, this fallbacks to 0. Deprecated 1.46. Use \"autoconnect-ports\" instead, this is just an alias.") #define DESCRIBE_DOC_NM_SETTING_CONNECTION_CONTROLLER N_("Interface name of the controller device or UUID of the controller connection.") #define DESCRIBE_DOC_NM_SETTING_CONNECTION_DNS_OVER_TLS N_("Whether DNSOverTls (dns-over-tls) is enabled for the connection. DNSOverTls is a technology which uses TLS to encrypt dns traffic. The permitted values are: \"yes\" (2) use DNSOverTls and disabled fallback, \"opportunistic\" (1) use DNSOverTls but allow fallback to unencrypted resolution, \"no\" (0) don't ever use DNSOverTls. If unspecified \"default\" depends on the plugin used. Systemd-resolved uses global setting. This feature requires a plugin which supports DNSOverTls. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_DNSSEC N_("Whether DNSSEC (dnssec) is enabled for the connection. The permitted values are: \"yes\" (2) use DNSSEC and disable fallback, \"allow-downgrade\" (1) use DNSSEC but allow fallback if the server does not support it, \"no\" (0) don't ever use DNSSEC. The effect of \"default\" (-1) depends on the dns plugin used. Systemd-resolved uses its global setting in this case. This feature requires a plugin which supports DNSSEC. Otherwise, the setting has no effect. One such plugin is systemd-resolved.") #define DESCRIBE_DOC_NM_SETTING_CONNECTION_DOWN_ON_POWEROFF N_("Whether the connection will be brought down before the system is powered off. The default value is \"default\" (-1). When the default value is specified, then the global value from NetworkManager configuration is looked up, if not set, it is considered as \"no\" (0).") #define DESCRIBE_DOC_NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT N_("If greater than zero, delay success of IP addressing until either the timeout is reached, or an IP gateway replies to a ping.") #define DESCRIBE_DOC_NM_SETTING_CONNECTION_ID N_("A human readable unique identifier for the connection, like \"Work Wi-Fi\" or \"T-Mobile 3G\".") @@ -20,7 +21,7 @@ #define DESCRIBE_DOC_NM_SETTING_CONNECTION_MASTER N_("Interface name of the controller device or UUID of the controller connection. Deprecated 1.46. Use \"controller\" instead, this is just an alias.") #define DESCRIBE_DOC_NM_SETTING_CONNECTION_MDNS N_("Whether mDNS is enabled for the connection. The permitted values are: \"yes\" (2) register hostname and resolving for the connection, \"no\" (0) disable mDNS for the interface, \"resolve\" (1) do not register hostname but allow resolving of mDNS host names and \"default\" (-1) to allow lookup of a global default in NetworkManager.conf. If unspecified, \"default\" ultimately depends on the DNS plugin. This feature requires a plugin which supports mDNS. Otherwise, the setting has no effect. Currently the only supported DNS plugin is systemd-resolved. For systemd-resolved, the default is configurable via MulticastDNS= setting in resolved.conf.") #define DESCRIBE_DOC_NM_SETTING_CONNECTION_METERED N_("Whether the connection is metered. When updating this property on a currently activated connection, the change takes effect immediately.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MPTCP_FLAGS N_("Whether to configure MPTCP endpoints and the address flags. If MPTCP is enabled in NetworkManager, it will configure the addresses of the interface as MPTCP endpoints. Note that IPv4 loopback addresses (127.0.0.0/8), IPv4 link local addresses (169.254.0.0/16), the IPv6 loopback address (::1), IPv6 link local addresses (fe80::/10), IPv6 unique local addresses (ULA, fc00::/7) and IPv6 privacy extension addresses (rfc3041, ipv6.ip6-privacy) will be excluded from being configured as endpoints. If \"disabled\" (0x1), MPTCP handling for the interface is disabled and no endpoints are registered. The \"enabled\" (0x2) flag means that MPTCP handling is enabled. This flag can also be implied from the presence of other flags. Even when enabled, MPTCP handling will by default still be disabled unless \"/proc/sys/net/mptcp/enabled\" sysctl is on. NetworkManager does not change the sysctl and this is up to the administrator or distribution. To configure endpoints even if the sysctl is disabled, \"also-without-sysctl\" (0x4) flag can be used. In that case, NetworkManager doesn't look at the sysctl and configures endpoints regardless. Even when enabled, NetworkManager will only configure MPTCP endpoints for a certain address family, if there is a unicast default route (0.0.0.0/0 or ::/0) in the main routing table. The flag \"also-without-default-route\" (0x8) can override that. When MPTCP handling is enabled then endpoints are configured with the specified address flags \"signal\" (0x10), \"subflow\" (0x20), \"backup\" (0x40), \"fullmesh\" (0x80). See ip-mptcp(8) manual for additional information about the flags. If the flags are zero (0x0), the global connection default from NetworkManager.conf is honored. If still unspecified, the fallback is \"enabled,subflow\". Note that this means that MPTCP is by default done depending on the \"/proc/sys/net/mptcp/enabled\" sysctl. NetworkManager does not change the MPTCP limits nor enable MPTCP via \"/proc/sys/net/mptcp/enabled\". That is a host configuration which the admin can change via sysctl and ip-mptcp. Strict reverse path filtering (rp_filter) breaks many MPTCP use cases, so when MPTCP handling for IPv4 addresses on the interface is enabled, NetworkManager would loosen the strict reverse path filtering (1) to the loose setting (2).") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MPTCP_FLAGS N_("Whether to configure MPTCP endpoints and the address flags. If MPTCP is enabled in NetworkManager, it will configure the addresses of the interface as MPTCP endpoints. Note that IPv4 loopback addresses (127.0.0.0/8), IPv4 link local addresses (169.254.0.0/16), the IPv6 loopback address (::1), IPv6 link local addresses (fe80::/10), IPv6 unique local addresses (ULA, fc00::/7) and IPv6 privacy extension addresses (rfc3041, ipv6.ip6-privacy) will be excluded from being configured as endpoints. If \"disabled\" (0x1), MPTCP handling for the interface is disabled and no endpoints are registered. The \"enabled\" (0x2) flag means that MPTCP handling is enabled. This flag can also be implied from the presence of other flags. Even when enabled, MPTCP handling will by default still be disabled unless \"/proc/sys/net/mptcp/enabled\" sysctl is on. NetworkManager does not change the sysctl and this is up to the administrator or distribution. To configure endpoints even if the sysctl is disabled, \"also-without-sysctl\" (0x4) flag can be used. In that case, NetworkManager doesn't look at the sysctl and configures endpoints regardless. Even when enabled, NetworkManager will only configure MPTCP endpoints for a certain address family, if there is a unicast default route (0.0.0.0/0 or ::/0) in the main routing table. The flag \"also-without-default-route\" (0x8) can override that. When MPTCP handling is enabled then endpoints are configured with the specified address flags \"signal\" (0x10), \"subflow\" (0x20), \"backup\" (0x40), \"fullmesh\" (0x80), \"laminar\" (0x100). See ip-mptcp(8) manual for additional information about the flags. If the flags are zero (0x0), the global connection default from NetworkManager.conf is honored. If still unspecified, the fallback is \"enabled,subflow\". Note that this means that MPTCP is by default done depending on the \"/proc/sys/net/mptcp/enabled\" sysctl. NetworkManager does not change the MPTCP limits nor enable MPTCP via \"/proc/sys/net/mptcp/enabled\". That is a host configuration which the admin can change via sysctl and ip-mptcp. Strict reverse path filtering (rp_filter) breaks many MPTCP use cases, so when MPTCP handling for IPv4 addresses on the interface is enabled, NetworkManager would loosen the strict reverse path filtering (1) to the loose setting (2).") #define DESCRIBE_DOC_NM_SETTING_CONNECTION_MUD_URL N_("If configured, set to a Manufacturer Usage Description (MUD) URL that points to manufacturer-recommended network policies for IoT devices. It is transmitted as a DHCPv4 or DHCPv6 option. The value must be a valid URL starting with \"https://\". The special value \"none\" is allowed to indicate that no MUD URL is used. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the ultimate default is \"none\".") #define DESCRIBE_DOC_NM_SETTING_CONNECTION_MULTI_CONNECT N_("Specifies whether the profile can be active multiple times at a particular moment. The value is of type NMConnectionMultiConnect.") #define DESCRIBE_DOC_NM_SETTING_CONNECTION_PERMISSIONS N_("An array of strings defining what access a given user has to this connection. If this is NULL or empty, all users are allowed to access this connection; otherwise users are allowed if and only if they are in this list. When this is not empty, the connection can be active only when one of the specified users is logged into an active session. Each entry is of the form \"[type]:[id]:[reserved]\"; for example, \"user:dcbw:blah\". At this time only the \"user\" [type] is allowed. Any other values are ignored and reserved for future use. [id] is the username that this permission refers to, which may not contain the \":\" character. Any [reserved] information present must be ignored and is reserved for future use. All of [type], [id], and [reserved] must be valid UTF-8.") @@ -149,6 +150,7 @@ #define DESCRIBE_DOC_NM_SETTING_GSM_APN N_("The GPRS Access Point Name specifying the APN used when establishing a data session with the GSM-based network. The APN often determines how the user will be billed for their network usage and whether the user has access to the Internet or just a provider-specific walled-garden, so it is important to use the correct APN for the user's mobile broadband plan. The APN may only be composed of the characters a-z, 0-9, ., and - per GSM 03.60 Section 14.9. If the APN is unset (the default) then it may be detected based on \"auto-config\" setting. The property can be explicitly set to the empty string to prevent that and use no APN.") #define DESCRIBE_DOC_NM_SETTING_GSM_AUTO_CONFIG N_("When TRUE, the settings such as APN, username, or password will default to values that match the network the modem will register to in the Mobile Broadband Provider database.") #define DESCRIBE_DOC_NM_SETTING_GSM_DEVICE_ID N_("The device unique identifier (as given by the WWAN management service) which this connection applies to. If given, the connection will only apply to the specified device.") +#define DESCRIBE_DOC_NM_SETTING_GSM_DEVICE_UID N_("The device UID (as given by the WWAN management service) which this connection applies to. In contrast to \"device-id\", which is an inherent property of the connected device, this setting refers to a property set by a UDEV-rule. Refer to the \"Common udev tags\" -> \"ID_MM_PHYSDEV_UID\" documentation of ModemManager. If given, the connection will only apply to the specified device.") #define DESCRIBE_DOC_NM_SETTING_GSM_HOME_ONLY N_("When TRUE, only connections to the home network will be allowed. Connections to roaming networks will not be made.") #define DESCRIBE_DOC_NM_SETTING_GSM_INITIAL_EPS_BEARER_APN N_("For LTE modems, this sets the APN for the initial EPS bearer that is set up when attaching to the network. Setting this parameter implies initial-eps-bearer-configure to be TRUE.") #define DESCRIBE_DOC_NM_SETTING_GSM_INITIAL_EPS_BEARER_CONFIGURE N_("For LTE modems, this setting determines whether the initial EPS bearer shall be configured when bringing up the connection. It is inferred TRUE if initial-eps-bearer-apn is set.") @@ -203,7 +205,7 @@ #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting. A lower numerical value is better (higher priority). Negative values have the special effect of excluding other configurations with a greater numerical priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. To avoid all DNS leaks, set the priority of the profile that should be used to the most negative value of all active connections profiles. Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs (including WireGuard) and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices. When using dns=default, servers with higher priority will be on top of resolv.conf. To prioritize a given server over another one within the same connection, just specify them in the desired order. Note that commonly the resolver tries name servers in /etc/resolv.conf in the order listed, proceeding with the next server in the list on failure. See for example the \"rotate\" option of the dns-options setting. If there are any negative DNS priorities, then only name servers from the devices with that lowest priority will be considered. When using a DNS resolver that supports Conditional Forwarding or Split DNS (with dns=dnsmasq or dns=systemd-resolved settings), each connection is used to query domains in its search list. The search domains determine which name servers to ask, and the DNS priority is used to prioritize name servers based on the domain. Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually). When multiple connections specify the same domain, the one with the best priority (lowest numerical value) wins. If a sub domain is configured on another interface it will be accepted regardless the priority, unless parent domain on the other interface has a negative priority, which causes the sub domain to be shadowed. With Split DNS one can avoid undesired DNS leaks by properly configuring DNS priorities and the search domains, so that only name servers of the desired interface are configured.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_SEARCH N_("List of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names. When using a DNS plugin that supports Conditional Forwarding or Split DNS, then the search domains specify which name servers to query. This makes the behavior different from running with plain /etc/resolv.conf. For more information see also the dns-priority setting. When set on a profile that also enabled DHCP, the DNS search list received automatically (option 119 for DHCPv4 and option 24 for DHCPv6) gets merged with the manual list. This can be prevented by setting \"ignore-auto-dns\". Note that if no DNS searches are configured, the fallback will be derived from the domain from DHCP (option 15).") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_FORWARDING N_("Whether to configure sysctl interface-specific forwarding. When enabled, the interface will act as a router to forward the packet from one interface to another. When set to \"default\" (-1), the value from global configuration is used; if no global default is defined, \"auto\" (2) will be used. The \"forwarding\" property is ignored when \"method\" is set to \"shared\", because forwarding is always enabled in this case. The accepted values are: \"default\" (-1): use global default. \"no\" (0): disabled. \"yes\" (1): enabled. \"auto\" (2): enable if any shared connection is active, use kernel default otherwise.") -#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set. Setting the gateway causes NetworkManager to configure a standard default route with the gateway as next hop. This is ignored if \"never-default\" is set. An alternative is to configure the default route explicitly with a manual route and /0 as prefix length. Note that the gateway usually conflicts with routing that NetworkManager configures for WireGuard interfaces, so usually it should not be set in that case. See \"ip4-auto-default-route\".") +#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if addresses are also set on the device. Setting the gateway causes NetworkManager to configure a standard default route with the gateway as next hop. This is ignored if \"never-default\" is set. An alternative is to configure the default route explicitly with a manual route and /0 as prefix length. Note that the gateway usually conflicts with routing that NetworkManager configures for WireGuard interfaces, so usually it should not be set in that case. See \"ip4-auto-default-route\".") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured name servers and search domains are ignored and only name servers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_IGNORE_AUTO_ROUTES N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured routes are ignored and only routes specified in the \"routes\" property, if any, are used.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_LINK_LOCAL N_("Enable and disable the IPv4 link-local configuration independently of the ipv4.method configuration. This allows a link-local address (169.254.x.y/16) to be obtained in addition to other addresses, such as those manually configured or obtained from a DHCP server. When set to \"auto\", the value is dependent on \"ipv4.method\". When set to \"default\", it honors the global connection default, before falling back to \"auto\". Note that if \"ipv4.method\" is \"disabled\", then link local addressing is always disabled too. The default is \"default\". Since 1.52, when set to \"fallback\", a link-local address is obtained if no other IPv4 address is set.") @@ -239,7 +241,7 @@ #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting. A lower numerical value is better (higher priority). Negative values have the special effect of excluding other configurations with a greater numerical priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. To avoid all DNS leaks, set the priority of the profile that should be used to the most negative value of all active connections profiles. Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs (including WireGuard) and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices. When using dns=default, servers with higher priority will be on top of resolv.conf. To prioritize a given server over another one within the same connection, just specify them in the desired order. Note that commonly the resolver tries name servers in /etc/resolv.conf in the order listed, proceeding with the next server in the list on failure. See for example the \"rotate\" option of the dns-options setting. If there are any negative DNS priorities, then only name servers from the devices with that lowest priority will be considered. When using a DNS resolver that supports Conditional Forwarding or Split DNS (with dns=dnsmasq or dns=systemd-resolved settings), each connection is used to query domains in its search list. The search domains determine which name servers to ask, and the DNS priority is used to prioritize name servers based on the domain. Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually). When multiple connections specify the same domain, the one with the best priority (lowest numerical value) wins. If a sub domain is configured on another interface it will be accepted regardless the priority, unless parent domain on the other interface has a negative priority, which causes the sub domain to be shadowed. With Split DNS one can avoid undesired DNS leaks by properly configuring DNS priorities and the search domains, so that only name servers of the desired interface are configured.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_SEARCH N_("List of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names. When using a DNS plugin that supports Conditional Forwarding or Split DNS, then the search domains specify which name servers to query. This makes the behavior different from running with plain /etc/resolv.conf. For more information see also the dns-priority setting. When set on a profile that also enabled DHCP, the DNS search list received automatically (option 119 for DHCPv4 and option 24 for DHCPv6) gets merged with the manual list. This can be prevented by setting \"ignore-auto-dns\". Note that if no DNS searches are configured, the fallback will be derived from the domain from DHCP (option 15).") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_FORWARDING N_("Whether to configure sysctl interface-specific forwarding. When enabled, the interface will act as a router to forward the packet from one interface to another. When set to \"default\" (-1), the value from global configuration is used; if no global default is defined, \"auto\" (2) will be used. The \"forwarding\" property is ignored when \"method\" is set to \"shared\", because forwarding is always enabled in this case. The accepted values are: \"default\" (-1): use global default. \"no\" (0): disabled. \"yes\" (1): enabled. \"auto\" (2): enable if any shared connection is active, use kernel default otherwise.") -#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set. Setting the gateway causes NetworkManager to configure a standard default route with the gateway as next hop. This is ignored if \"never-default\" is set. An alternative is to configure the default route explicitly with a manual route and /0 as prefix length. Note that the gateway usually conflicts with routing that NetworkManager configures for WireGuard interfaces, so usually it should not be set in that case. See \"ip4-auto-default-route\".") +#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if addresses are also set on the device. Setting the gateway causes NetworkManager to configure a standard default route with the gateway as next hop. This is ignored if \"never-default\" is set. An alternative is to configure the default route explicitly with a manual route and /0 as prefix length. Note that the gateway usually conflicts with routing that NetworkManager configures for WireGuard interfaces, so usually it should not be set in that case. See \"ip4-auto-default-route\".") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured name servers and search domains are ignored and only name servers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_IGNORE_AUTO_ROUTES N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured routes are ignored and only routes specified in the \"routes\" property, if any, are used.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_IP6_PRIVACY N_("Configure IPv6 Privacy Extensions for SLAAC, described in RFC4941. If enabled, it makes the kernel generate a temporary IPv6 address in addition to the public one generated from MAC address via modified EUI-64. This enhances privacy, but could cause problems in some applications, on the other hand. The permitted values are: -1: unknown, 0: disabled, 1: enabled (prefer public address), 2: enabled (prefer temporary addresses). Having a per-connection setting set to \"-1\" (default) means fallback to global configuration \"ipv6.ip6-privacy\". If it's also unspecified or set to \"-1\", fallback to read \"/proc/sys/net/ipv6/conf/default/use_tempaddr\". Note that this setting is distinct from the Stable Privacy addresses that can be enabled with the \"addr-gen-mode\" property's \"stable-privacy\" setting as another way of avoiding host tracking with IPv6 addresses.") @@ -446,6 +448,7 @@ #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_LISTEN_PORT N_("The listen-port. If listen-port is not specified, the port will be chosen randomly when the interface comes up.") #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple fragments. If zero a default MTU is used. Note that contrary to wg-quick's MTU setting, this does not take into account the current routes at the time of activation.") #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_PEER_ROUTES N_("Whether to automatically add routes for the AllowedIPs ranges of the peers. If TRUE (the default), NetworkManager will automatically add routes in the routing tables according to ipv4.route-table and ipv6.route-table. Usually you want this automatism enabled. If FALSE, no such routes are added automatically. In this case, the user may want to configure static routes in ipv4.routes and ipv6.routes, respectively. Note that if the peer's AllowedIPs is \"0.0.0.0/0\" or \"::/0\" and the profile's ipv4.never-default or ipv6.never-default setting is enabled, the peer route for this peer won't be added automatically.") +#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_PEERS N_("A comma-separated list of WireGuard peers. Each peer has the following syntax: PUBLIC_KEY [ATTRIBUTE=VALUE [ATTRIBUTE=VALUE]...] The supported attributes are: endpoint, allowed-ips, persistent-keepalive, preshared-key, preshared-key-flags.") #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_PRIVATE_KEY N_("The 256 bit private-key in base64 encoding.") #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS N_("Flags indicating how to handle the \"private-key\" property.") #define DESCRIBE_DOC_NM_SETTING_WIRELESS_AP_ISOLATION N_("Configures AP isolation, which prevents communication between wireless devices connected to this AP. This property can be set to a value different from \"default\" (-1) only when the interface is configured in AP mode. If set to \"true\" (1), devices are not able to communicate with each other. This increases security because it protects devices against attacks from other clients in the network. At the same time, it prevents devices to access resources on the same wireless networks as file shares, printers, etc. If set to \"false\" (0), devices can talk to each other. When set to \"default\" (-1), the global default is used; in case the global default is unspecified it is assumed to be \"false\" (0).") diff --git a/src/linux-headers/mptcp.h b/src/linux-headers/mptcp.h index ca502f1e..ed44b950 100644 --- a/src/linux-headers/mptcp.h +++ b/src/linux-headers/mptcp.h @@ -80,6 +80,7 @@ enum { #define MPTCP_PM_ADDR_FLAG_BACKUP (1 << 2) #define MPTCP_PM_ADDR_FLAG_FULLMESH (1 << 3) #define MPTCP_PM_ADDR_FLAG_IMPLICIT (1 << 4) +#define MPTCP_PM_ADDR_FLAG_LAMINAR (1 << 5) enum { MPTCP_PM_CMD_UNSPEC, diff --git a/src/meson.build b/src/meson.build index 0cf93bfd..7c020809 100644 --- a/src/meson.build +++ b/src/meson.build @@ -24,7 +24,7 @@ libn_acd = static_library( 'n-acd/src/n-acd.c', 'n-acd/src/n-acd-probe.c', 'n-acd/src/util/timer.c', - enable_ebpf ? 'n-acd/src/n-acd-bpf.c' : 'n-acd/src/n-acd-bpf-fallback.c', + 'n-acd/src/n-acd-bpf.c', ), include_directories: include_directories( 'c-list/src', diff --git a/src/n-acd/.github/workflows/ci.yml b/src/n-acd/.github/workflows/ci.yml index 22fc8141..f6987414 100644 --- a/src/n-acd/.github/workflows/ci.yml +++ b/src/n-acd/.github/workflows/ci.yml @@ -49,42 +49,6 @@ jobs: "--m32=1" \ "--source=/github/workspace" - ci-no-ebpf: - name: CI without eBPF - runs-on: ubuntu-latest - - steps: - # See above in 'ci' job. - - name: Fetch CI - uses: actions/checkout@v2 - with: - repository: c-util/automation - ref: v1 - path: automation - - name: Build CI - working-directory: automation/src/ci-c-util - run: docker build --tag ci-c-util:v1 . - - # - # Run CI - # - # This again runs the CI, but this time disables eBPF. We do support the - # legacy BPF fallback, so lets make sure we test for it. - # - - name: Fetch Sources - uses: actions/checkout@v2 - with: - path: source - - name: Run through C-Util CI - run: | - docker run \ - --privileged \ - -v "$(pwd)/source:/github/workspace" \ - "ci-c-util:v1" \ - "--m32=1" \ - "--mesonargs=-Debpf=false" \ - "--source=/github/workspace" - ci-valgrind: name: CI through Valgrind runs-on: ubuntu-latest diff --git a/src/n-acd/README.md b/src/n-acd/README.md index 08954182..d207e700 100644 --- a/src/n-acd/README.md +++ b/src/n-acd/README.md @@ -41,13 +41,6 @@ meson test ninja install ``` -The following configuration options are available: - - * `ebpf`: This boolean controls whether `ebpf` features are used to improve - the package filtering performance. If disabled, classic bpf will be - used. This feature requires a rather recent kernel (>=3.19). - Default is: true - ### Repository: - **web**: <https://github.com/nettools/n-acd> diff --git a/src/n-acd/meson.build b/src/n-acd/meson.build index 6479eb1a..ca72e567 100644 --- a/src/n-acd/meson.build +++ b/src/n-acd/meson.build @@ -22,6 +22,4 @@ dep_crbtree = sub_crbtree.get_variable('libcrbtree_dep') dep_csiphash = sub_csiphash.get_variable('libcsiphash_dep') dep_cstdaux = sub_cstdaux.get_variable('libcstdaux_dep') -use_ebpf = get_option('ebpf') - subdir('src') diff --git a/src/n-acd/meson_options.txt b/src/n-acd/meson_options.txt deleted file mode 100644 index b024ee1d..00000000 --- a/src/n-acd/meson_options.txt +++ /dev/null @@ -1 +0,0 @@ -option('ebpf', type: 'boolean', value: true, description: 'Enable eBPF packet filtering') diff --git a/src/n-acd/src/libnacd.sym b/src/n-acd/src/libnacd.sym index f85e13ac..537eab3e 100644 --- a/src/n-acd/src/libnacd.sym +++ b/src/n-acd/src/libnacd.sym @@ -15,6 +15,7 @@ global: n_acd_ref; n_acd_unref; n_acd_get_fd; + n_acd_has_bpf; n_acd_dispatch; n_acd_pop_event; n_acd_probe; diff --git a/src/n-acd/src/meson.build b/src/n-acd/src/meson.build index 3e92681f..c1582f42 100644 --- a/src/n-acd/src/meson.build +++ b/src/n-acd/src/meson.build @@ -15,18 +15,9 @@ libnacd_sources = [ 'n-acd.c', 'n-acd-probe.c', 'util/timer.c', + 'n-acd-bpf.c', ] -if use_ebpf - libnacd_sources += [ - 'n-acd-bpf.c', - ] -else - libnacd_sources += [ - 'n-acd-bpf-fallback.c', - ] -endif - libnacd_private = static_library( 'nacd-private', libnacd_sources, @@ -77,10 +68,8 @@ endif test_api = executable('test-api', ['test-api.c'], link_with: libnacd_shared) test('API Symbol Visibility', test_api) -if use_ebpf - test_bpf = executable('test-bpf', ['test-bpf.c'], dependencies: libnacd_dep) - test('eBPF socket filtering', test_bpf) -endif +test_bpf = executable('test-bpf', ['test-bpf.c'], dependencies: libnacd_dep) +test('eBPF socket filtering', test_bpf) test_loopback = executable('test-loopback', ['test-loopback.c'], dependencies: libnacd_dep) test('Echo Suppression via Loopback', test_loopback) diff --git a/src/n-acd/src/n-acd-bpf-fallback.c b/src/n-acd/src/n-acd-bpf-fallback.c deleted file mode 100644 index 3cf4eb06..00000000 --- a/src/n-acd/src/n-acd-bpf-fallback.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * A noop implementation of eBPF filter for IPv4 Address Conflict Detection - * - * These are a collection of dummy functions that have no effect, but allows - * n-acd to compile without eBPF support. - * - * See n-acd-bpf.c for documentation. - */ - -#include <c-stdaux.h> -#include <stddef.h> -#include "n-acd-private.h" - -int n_acd_bpf_map_create(int *mapfdp, size_t max_entries) { - *mapfdp = -1; - return 0; -} - -int n_acd_bpf_map_add(int mapfd, struct in_addr *addrp) { - return 0; -} - -int n_acd_bpf_map_remove(int mapfd, struct in_addr *addrp) { - return 0; -} - -int n_acd_bpf_compile(int *progfdp, int mapfd, struct ether_addr *macp) { - *progfdp = -1; - return 0; -} diff --git a/src/n-acd/src/n-acd-bpf.c b/src/n-acd/src/n-acd-bpf.c index 57b29ddf..55b44ab9 100644 --- a/src/n-acd/src/n-acd-bpf.c +++ b/src/n-acd/src/n-acd-bpf.c @@ -170,6 +170,10 @@ int n_acd_bpf_map_add(int mapfd, struct in_addr *addrp) { uint8_t _dummy = 0; int r; + /* If we don't have a map to update, there is nothing to do. */ + if (mapfd == -1) + return 0; + memset(&attr, 0, sizeof(attr)); attr = (union bpf_attr){ .map_fd = mapfd, @@ -190,6 +194,10 @@ int n_acd_bpf_map_remove(int mapfd, struct in_addr *addrp) { union bpf_attr attr; int r; + /* If we don't have a map to update, there is nothing to do. */ + if (mapfd == -1) + return 0; + memset(&attr, 0, sizeof(attr)); attr = (union bpf_attr){ .map_fd = mapfd, diff --git a/src/n-acd/src/n-acd.c b/src/n-acd/src/n-acd.c index c1d92865..9bc32244 100644 --- a/src/n-acd/src/n-acd.c +++ b/src/n-acd/src/n-acd.c @@ -284,6 +284,11 @@ int n_acd_ensure_bpf_map_space(NAcd *acd) { max_map = 2 * acd->max_bpf_map; + /* If we didn't succeed in creating a map during n_acd_new(), + * let's assume we are unable to create it here, and skip it. */ + if (!n_acd_has_bpf(acd)) + goto out; + r = n_acd_bpf_map_create(&fd_map, max_map); if (r) return r; @@ -308,6 +313,8 @@ int n_acd_ensure_bpf_map_space(NAcd *acd) { close(acd->fd_bpf_map); acd->fd_bpf_map = fd_map; fd_map = -1; + +out: acd->max_bpf_map = max_map; return 0; } @@ -359,13 +366,16 @@ _c_public_ int n_acd_new(NAcd **acdp, NAcdConfig *config) { acd->max_bpf_map = 8; + /* Let's try to create a BPF map. If we fail, we want to ignore it + * only if we lack permissions to create it, and proceed without eBPF. */ r = n_acd_bpf_map_create(&acd->fd_bpf_map, acd->max_bpf_map); - if (r) - return r; - - r = n_acd_bpf_compile(&fd_bpf_prog, acd->fd_bpf_map, (struct ether_addr*) acd->mac); - if (r) + if (r == 0) { + r = n_acd_bpf_compile(&fd_bpf_prog, acd->fd_bpf_map, (struct ether_addr*) acd->mac); + if (r) + return r; + } else if (r != -EPERM) { return r; + } r = n_acd_socket_new(&acd->fd_socket, fd_bpf_prog, config); if (r) @@ -572,6 +582,20 @@ _c_public_ void n_acd_get_fd(NAcd *acd, int *fdp) { *fdp = acd->fd_epoll; } +/** + * n_acd_has_bpf() - query the usage of eBPF + * @acd: context object to operate on + * + * Checks whether the ACD probe is using eBPF or not. + * + * Return: true if the probe is using eBPF, or + * false if the probe failed to configure eBPF + * (e.g. due to missing capabilities) + */ +_c_public_ bool n_acd_has_bpf(NAcd *acd) { + return acd->fd_bpf_map != -1; +} + static int n_acd_handle_timeout(NAcd *acd) { NAcdProbe *probe; uint64_t now; diff --git a/src/n-acd/src/n-acd.h b/src/n-acd/src/n-acd.h index e2b01270..8e5cf59a 100644 --- a/src/n-acd/src/n-acd.h +++ b/src/n-acd/src/n-acd.h @@ -93,6 +93,7 @@ NAcd *n_acd_ref(NAcd *acd); NAcd *n_acd_unref(NAcd *acd); void n_acd_get_fd(NAcd *acd, int *fdp); +bool n_acd_has_bpf(NAcd *acd); int n_acd_dispatch(NAcd *acd); int n_acd_pop_event(NAcd *acd, NAcdEvent **eventp); diff --git a/src/n-acd/src/test-api.c b/src/n-acd/src/test-api.c index 70f75208..009838aa 100644 --- a/src/n-acd/src/test-api.c +++ b/src/n-acd/src/test-api.c @@ -56,6 +56,7 @@ static void test_api_functions(void) { (void *)n_acd_ref, (void *)n_acd_unref, (void *)n_acd_get_fd, + (void *)n_acd_has_bpf, (void *)n_acd_dispatch, (void *)n_acd_pop_event, (void *)n_acd_probe, diff --git a/src/n-acd/src/test-bpf.c b/src/n-acd/src/test-bpf.c index 78f9d0f1..17e89803 100644 --- a/src/n-acd/src/test-bpf.c +++ b/src/n-acd/src/test-bpf.c @@ -19,6 +19,9 @@ #include "n-acd-private.h" #include "test.h" +// https://mesonbuild.com/Unit-tests.html#skipped-tests-and-hard-errors +#define RETURN_TEST_SKIPPED 77 + #define ETHER_ARP_PACKET_INIT(_op, _mac, _sip, _tip) { \ .ea_hdr = { \ .ar_hrd = htobe16(ARPHRD_ETHER), \ @@ -43,11 +46,15 @@ .arp_tpa[3] = be32toh((_tip)->s_addr) & 0xff, \ } -static void test_map(void) { +static int test_map(void) { int r, mapfd = -1; struct in_addr addr = { 1 }; r = n_acd_bpf_map_create(&mapfd, 8); + if (r == -EPERM) { + return RETURN_TEST_SKIPPED; + } + c_assert(r >= 0); c_assert(mapfd >= 0); @@ -67,6 +74,7 @@ static void test_map(void) { c_assert(r == -ENOENT); close(mapfd); + return 0; } static void verify_success(struct ether_arp *packet, int out_fd, int in_fd) { @@ -92,7 +100,7 @@ static void verify_failure(struct ether_arp *packet, int out_fd, int in_fd) { c_assert(errno == EAGAIN); } -static void test_filter(void) { +static int test_filter(void) { uint8_t buf[sizeof(struct ether_arp) + 1] = {}; struct ether_addr mac1 = { { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } }; struct ether_addr mac2 = { { 0x01, 0x02, 0x03, 0x04, 0x05, 0x07 } }; @@ -103,6 +111,10 @@ static void test_filter(void) { int r, mapfd = -1, progfd = -1, pair[2]; r = n_acd_bpf_map_create(&mapfd, 1); + if (r == -EPERM) { + return RETURN_TEST_SKIPPED; + } + c_assert(r >= 0); r = n_acd_bpf_compile(&progfd, mapfd, &mac1); @@ -214,13 +226,21 @@ static void test_filter(void) { close(pair[1]); close(progfd); close(mapfd); + + return 0; } int main(int argc, char **argv) { + int r; test_setup(); - test_map(); - test_filter(); + if ((r = test_map())) { + return r; + } + + if ((r = test_filter())) { + return r; + } return 0; } diff --git a/src/n-dhcp4/src/n-dhcp4-c-connection.c b/src/n-dhcp4/src/n-dhcp4-c-connection.c index e76ea165..707c6604 100644 --- a/src/n-dhcp4/src/n-dhcp4-c-connection.c +++ b/src/n-dhcp4/src/n-dhcp4-c-connection.c @@ -379,6 +379,10 @@ void n_dhcp4_c_connection_get_timeout(NDhcp4CConnection *connection, *timeoutp = timeout; } +void n_dhcp4_c_connection_clear_client_ip(NDhcp4CConnection *connection) { + connection->client_ip = INADDR_ANY; +} + static int n_dhcp4_c_connection_packet_broadcast(NDhcp4CConnection *connection, NDhcp4Outgoing *message) { int r; diff --git a/src/n-dhcp4/src/n-dhcp4-c-probe.c b/src/n-dhcp4/src/n-dhcp4-c-probe.c index 58d61e72..43dff7b0 100644 --- a/src/n-dhcp4/src/n-dhcp4-c-probe.c +++ b/src/n-dhcp4/src/n-dhcp4-c-probe.c @@ -198,7 +198,7 @@ _c_public_ void n_dhcp4_client_probe_config_set_init_reboot(NDhcp4ClientProbeCon * * This sets the DSCP property of the configuration object, which specifies * the DSCP value to set in the first six bits of the DS field in the IPv4 - * header. If this function is not called, the DSCP will be set to CS0. + * header. If this function is not called, the DSCP will be set to CS0 (0). */ _c_public_ void n_dhcp4_client_probe_config_set_dscp(NDhcp4ClientProbeConfig *config, uint8_t dscp) { config->dscp = dscp & 0x3F; @@ -703,6 +703,8 @@ static int n_dhcp4_client_probe_transition_deferred(NDhcp4ClientProbe *probe, ui switch (probe->state) { case N_DHCP4_CLIENT_PROBE_STATE_INIT: + /* reset client IP (CIADDR) */ + n_dhcp4_c_connection_clear_client_ip(&probe->connection); r = n_dhcp4_c_connection_listen(&probe->connection); if (r) return r; diff --git a/src/n-dhcp4/src/n-dhcp4-private.h b/src/n-dhcp4/src/n-dhcp4-private.h index dbfe9b4a..7e71406e 100644 --- a/src/n-dhcp4/src/n-dhcp4-private.h +++ b/src/n-dhcp4/src/n-dhcp4-private.h @@ -617,6 +617,8 @@ void n_dhcp4_c_connection_close(NDhcp4CConnection *connection); void n_dhcp4_c_connection_get_timeout(NDhcp4CConnection *connection, uint64_t *timeoutp); +void n_dhcp4_c_connection_clear_client_ip(NDhcp4CConnection *connection); + int n_dhcp4_c_connection_discover_new(NDhcp4CConnection *connection, NDhcp4Outgoing **request); int n_dhcp4_c_connection_select_new(NDhcp4CConnection *connection, diff --git a/src/nm-cloud-setup/main.c b/src/nm-cloud-setup/main.c index d2a5a1cf..51c65107 100644 --- a/src/nm-cloud-setup/main.c +++ b/src/nm-cloud-setup/main.c @@ -797,8 +797,8 @@ _oci_new_vlan_dev(SigTermData *sigterm_data, connection = _new_connection(); - macvlan_name = g_strdup_printf("macvlan%ld", config_data->iface_idx); - connection_id = g_strdup_printf("%s%ld", connection_type, config_data->iface_idx); + macvlan_name = g_strdup_printf("macvlan%" G_GSSIZE_FORMAT, config_data->iface_idx); + connection_id = g_strdup_printf("%s%" G_GSSIZE_FORMAT, connection_type, config_data->iface_idx); wired_mac_addr = parent_hwaddr; if (nm_streq(connection_type, NM_SETTING_MACVLAN_SETTING_NAME)) { diff --git a/src/nm-initrd-generator/nm-initrd-generator.c b/src/nm-initrd-generator/nm-initrd-generator.c index b89b4e41..68993c00 100644 --- a/src/nm-initrd-generator/nm-initrd-generator.c +++ b/src/nm-initrd-generator/nm-initrd-generator.c @@ -78,7 +78,7 @@ output_conn(gpointer key, gpointer value, gpointer user_data) filename = nm_keyfile_utils_create_filename(basename, TRUE); full_filename = g_build_filename(connections_dir, filename, NULL); - if (!nm_utils_file_set_contents(full_filename, data, len, 0600, NULL, NULL, &error)) + if (!nm_utils_file_set_contents(full_filename, data, len, 0600, NULL, NULL, NULL, &error)) goto err_out; } else g_print("\n*** Connection '%s' ***\n\n%s", basename, data); diff --git a/src/nm-initrd-generator/nmi-cmdline-reader.c b/src/nm-initrd-generator/nmi-cmdline-reader.c index fdd7283e..5cdb3bcd 100644 --- a/src/nm-initrd-generator/nmi-cmdline-reader.c +++ b/src/nm-initrd-generator/nmi-cmdline-reader.c @@ -1063,27 +1063,44 @@ reader_parse_vlan(Reader *reader, char *argument) const char *vlan; const char *phy; const char *vlanid; + guint64 id; vlan = get_word(&argument, ':'); phy = get_word(&argument, ':'); + if (!vlan) { + _LOGW(LOGD_CORE, "missing VLAN interface name"); + return; + } + + if (!phy) { + _LOGW(LOGD_CORE, "missing VLAN parent"); + return; + } + for (vlanid = vlan + strlen(vlan); vlanid > vlan; vlanid--) { if (!g_ascii_isdigit(*(vlanid - 1))) break; } + if (vlanid[0] == '\0') { + _LOGW(LOGD_CORE, "missing VLAN id in '%s'", vlan); + return; + } + + id = _nm_utils_ascii_str_to_int64(vlanid, 10, 0, 4094, G_MAXUINT); + if (id == G_MAXUINT) { + _LOGW(LOGD_CORE, "invalid VLAN id '%s'", vlanid); + return; + } + connection = reader_get_connection(reader, vlan, NM_SETTING_VLAN_SETTING_NAME, TRUE); s_vlan = nm_connection_get_setting_vlan(connection); - g_object_set(s_vlan, - NM_SETTING_VLAN_PARENT, - phy, - NM_SETTING_VLAN_ID, - (guint) _nm_utils_ascii_str_to_int64(vlanid, 10, 0, G_MAXUINT, G_MAXUINT), - NULL); + g_object_set(s_vlan, NM_SETTING_VLAN_PARENT, phy, NM_SETTING_VLAN_ID, (guint32) id, NULL); if (argument && *argument) - _LOGW(LOGD_CORE, "Ignoring extra: '%s'.", argument); + _LOGW(LOGD_CORE, "ignoring extra VLAN argument '%s'", argument); if (!nm_strv_ptrarray_contains(reader->vlan_parents, phy)) g_ptr_array_add(reader->vlan_parents, g_strdup(phy)); @@ -1256,8 +1273,10 @@ reader_parse_rd_znet(Reader *reader, char *argument, gboolean net_ifnames) static void reader_parse_global_dns(Reader *reader, char *argument) { - if (!nm_dns_uri_parse(AF_UNSPEC, argument, NULL)) { - _LOGW(LOGD_CORE, "rd.net.dns: invalid server '%s'", argument); + gs_free_error GError *error = NULL; + + if (!nm_dns_uri_parse(AF_UNSPEC, argument, NULL, &error)) { + _LOGW(LOGD_CORE, "rd.net.dns: invalid server '%s': %s", argument, error->message); return; } diff --git a/src/nm-initrd-generator/tests/test-cmdline-reader.c b/src/nm-initrd-generator/tests/test-cmdline-reader.c index ac722872..b49905fb 100644 --- a/src/nm-initrd-generator/tests/test-cmdline-reader.c +++ b/src/nm-initrd-generator/tests/test-cmdline-reader.c @@ -1847,6 +1847,66 @@ test_vlan_over_bond(void) } static void +test_vlan_invalid(void) +{ + { + /* Case 1: Missing name */ + const char *const *ARGV0 = NM_MAKE_STRV("vlan="); + gs_unref_hashtable GHashTable *connections = NULL; + + NMTST_EXPECT_NM_WARN("cmdline-reader: missing VLAN interface name"); + connections = _parse_cons(ARGV0); + g_assert_cmpint(g_hash_table_size(connections), ==, 0); + g_test_assert_expected_messages(); + } + + { + /* Case 2: Missing parent */ + const char *const *ARGV0 = NM_MAKE_STRV("vlan=vlan12"); + gs_unref_hashtable GHashTable *connections = NULL; + + NMTST_EXPECT_NM_WARN("cmdline-reader: missing VLAN parent"); + connections = _parse_cons(ARGV0); + g_assert_cmpint(g_hash_table_size(connections), ==, 0); + g_test_assert_expected_messages(); + } + + { + /* Case 3: Interface name without trailing digits should fail, + * not trigger a GLib assertion. */ + const char *const *ARGV0 = NM_MAKE_STRV("vlan=myvlan:eth0"); + gs_unref_hashtable GHashTable *connections = NULL; + + NMTST_EXPECT_NM_WARN("cmdline-reader: missing VLAN id in 'myvlan'"); + connections = _parse_cons(ARGV0); + g_assert_cmpint(g_hash_table_size(connections), ==, 0); + g_test_assert_expected_messages(); + } + + { + /* Case 4: An invalid VLAN id should be rejected */ + const char *const *ARGV0 = NM_MAKE_STRV("vlan=myvlan4095:eth0"); + gs_unref_hashtable GHashTable *connections = NULL; + + NMTST_EXPECT_NM_WARN("cmdline-reader: invalid VLAN id '4095'"); + connections = _parse_cons(ARGV0); + g_assert_cmpint(g_hash_table_size(connections), ==, 0); + g_test_assert_expected_messages(); + } + + { + /* Case 5: Extra arguments */ + const char *const *ARGV0 = NM_MAKE_STRV("vlan=eth0.80:eth0:reorder_hdr=on"); + gs_unref_hashtable GHashTable *connections = NULL; + + NMTST_EXPECT_NM_WARN("cmdline-reader: ignoring extra VLAN argument 'reorder_hdr=on'"); + connections = _parse_cons(ARGV0); + g_assert_cmpint(g_hash_table_size(connections), ==, 2); + g_test_assert_expected_messages(); + } +} + +static void test_ibft_ip_dev(void) { const char *const *ARGV = NM_MAKE_STRV("ip=eth0:ibft"); @@ -2604,7 +2664,7 @@ test_global_dns(void) gs_free char *dns_resolve_mode = NULL; gint64 carrier_timeout_sec = 0; - NMTST_EXPECT_NM_WARN("cmdline-reader: rd.net.dns: invalid server 'foobar'"); + NMTST_EXPECT_NM_WARN("cmdline-reader: rd.net.dns: invalid server 'foobar':*"); connections = _parse(ARGV, &hostname, &carrier_timeout_sec, @@ -2963,6 +3023,7 @@ main(int argc, char **argv) g_test_add_func("/initrd/cmdline/vlan", test_vlan); g_test_add_func("/initrd/cmdline/vlan/dhcp-on-parent", test_vlan_with_dhcp_on_parent); g_test_add_func("/initrd/cmdline/vlan/over-bond", test_vlan_over_bond); + g_test_add_func("/initrd/cmdline/vlan/invalid", test_vlan_invalid); g_test_add_func("/initrd/cmdline/bridge", test_bridge); g_test_add_func("/initrd/cmdline/bridge/default", test_bridge_default); g_test_add_func("/initrd/cmdline/bridge/ip", test_bridge_ip); diff --git a/src/nmcli/devices.c b/src/nmcli/devices.c index 9a018113..e81e710f 100644 --- a/src/nmcli/devices.c +++ b/src/nmcli/devices.c @@ -2090,6 +2090,7 @@ typedef struct { char *specific_object; bool hotspot : 1; bool create : 1; + bool start_agent : 1; } AddAndActivateInfo; static AddAndActivateInfo * @@ -2097,6 +2098,7 @@ add_and_activate_info_new(NmCli *nmc, NMDevice *device, gboolean hotspot, gboolean create, + gboolean start_agent, const char *specific_object) { AddAndActivateInfo *info; @@ -2107,6 +2109,7 @@ add_and_activate_info_new(NmCli *nmc, .device = g_object_ref(device), .hotspot = hotspot, .create = create, + .start_agent = start_agent, .specific_object = g_strdup(specific_object), }; return info; @@ -2364,7 +2367,7 @@ do_device_connect(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const nmc); } - info = add_and_activate_info_new(nmc, device, FALSE, FALSE, NULL); + info = add_and_activate_info_new(nmc, device, FALSE, FALSE, FALSE, NULL); nm_client_activate_connection_async(nmc->client, NULL, /* let NM find a connection automatically */ @@ -3603,6 +3606,16 @@ activate_update2_cb(GObject *source_object, GAsyncResult *res, gpointer user_dat return; } + if (info->start_agent && !nmc->secret_agent) { + nmc->secret_agent = nm_secret_agent_simple_new("nmcli-connect"); + if (nmc->secret_agent) { + g_signal_connect(nmc->secret_agent, + NM_SECRET_AGENT_SIMPLE_REQUEST_SECRETS, + G_CALLBACK(nmc_secrets_requested), + nmc); + } + } + nm_client_activate_connection_async(nmc->client, NM_CONNECTION(remote_con), info->device, @@ -3617,6 +3630,7 @@ save_and_activate_connection(NmCli *nmc, NMDevice *device, NMConnection *connection, gboolean hotspot, + gboolean start_agent, const char *specific_object) { AddAndActivateInfo *info; @@ -3625,9 +3639,15 @@ save_and_activate_connection(NmCli *nmc, device, hotspot, !NM_IS_REMOTE_CONNECTION(connection), + start_agent, specific_object); if (NM_IS_REMOTE_CONNECTION(connection)) { + /* Don't start the agent immediately. Otherwise the agent registration + * to the daemon will trigger a new activation if the connection was + * blocked due to bad secrets. This new activation would use the old + * secrets. + */ nm_remote_connection_update2(NM_REMOTE_CONNECTION(connection), nm_connection_to_dbus(connection, NM_CONNECTION_SERIALIZE_ALL), NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT, @@ -3636,6 +3656,16 @@ save_and_activate_connection(NmCli *nmc, activate_update2_cb, info); } else { + if (start_agent) { + nmc->secret_agent = nm_secret_agent_simple_new("nmcli-connect"); + if (nmc->secret_agent) { + g_signal_connect(nmc->secret_agent, + NM_SECRET_AGENT_SIMPLE_REQUEST_SECRETS, + G_CALLBACK(nmc_secrets_requested), + nmc); + } + } + nm_client_add_and_activate_connection_async(nmc->client, connection, info->device, @@ -3665,6 +3695,7 @@ do_device_wifi_connect(const NMCCommand *cmd, NmCli *nmc, int argc, const char * gboolean private = FALSE; gboolean hidden = FALSE; gboolean wep_passphrase = FALSE; + gboolean start_agent = FALSE; GByteArray *bssid1_arr = NULL; GByteArray *bssid2_arr = NULL; gs_free NMDevice **devices = NULL; @@ -4029,18 +4060,13 @@ do_device_wifi_connect(const NMCCommand *cmd, NmCli *nmc, int argc, const char * NM_802_11_AP_SEC_KEY_MGMT_OWE | NM_802_11_AP_SEC_KEY_MGMT_OWE_TM))) { NMSettingWirelessSecurity *s_wsec = NULL; - /* Create secret agent */ - nmc->secret_agent = nm_secret_agent_simple_new("nmcli-connect"); - if (nmc->secret_agent) { - g_signal_connect(nmc->secret_agent, - NM_SECRET_AGENT_SIMPLE_REQUEST_SECRETS, - G_CALLBACK(nmc_secrets_requested), - nmc); - } + /* Start the secret agent just before initiating the activation. */ + start_agent = TRUE; if (password) { if (!connection) connection = nm_simple_connection_new(); + s_wsec = nm_connection_get_setting_wireless_security(connection); if (!s_wsec) { s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new(); nm_connection_add_setting(connection, NM_SETTING(s_wsec)); @@ -4075,7 +4101,12 @@ do_device_wifi_connect(const NMCCommand *cmd, NmCli *nmc, int argc, const char * nmc->nowait_flag = (nmc->timeout == 0); nmc->should_wait++; - save_and_activate_connection(nmc, device, connection, FALSE, nm_object_get_path(NM_OBJECT(ap))); + save_and_activate_connection(nmc, + device, + connection, + FALSE, + start_agent, + nm_object_get_path(NM_OBJECT(ap))); finish: if (bssid1_arr) @@ -4535,7 +4566,7 @@ do_device_wifi_hotspot(const NMCCommand *cmd, NmCli *nmc, int argc, const char * nmc->nowait_flag = (nmc->timeout == 0); nmc->should_wait++; - save_and_activate_connection(nmc, device, connection, TRUE, NULL); + save_and_activate_connection(nmc, device, connection, TRUE, FALSE, NULL); } static void diff --git a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in index 854a0227..881c41ca 100644 --- a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in +++ b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in @@ -733,10 +733,14 @@ nmcli-description="Whether DNSOverTls (dns-over-tls) is enabled for the connection. DNSOverTls is a technology which uses TLS to encrypt dns traffic. The permitted values are: "yes" (2) use DNSOverTls and disabled fallback, "opportunistic" (1) use DNSOverTls but allow fallback to unencrypted resolution, "no" (0) don't ever use DNSOverTls. If unspecified "default" depends on the plugin used. Systemd-resolved uses global setting. This feature requires a plugin which supports DNSOverTls. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved." format="choice (NMSettingConnectionDnsOverTls)" values="default (-1), no (0), opportunistic (1), yes (2)" /> + <property name="dnssec" + nmcli-description="Whether DNSSEC (dnssec) is enabled for the connection. The permitted values are: "yes" (2) use DNSSEC and disable fallback, "allow-downgrade" (1) use DNSSEC but allow fallback if the server does not support it, "no" (0) don't ever use DNSSEC. The effect of "default" (-1) depends on the dns plugin used. Systemd-resolved uses its global setting in this case. This feature requires a plugin which supports DNSSEC. Otherwise, the setting has no effect. One such plugin is systemd-resolved." + format="choice (NMSettingConnectionDnssec)" + values="default (-1), no (0), allow-downgrade (1), yes (2)" /> <property name="mptcp-flags" - nmcli-description="Whether to configure MPTCP endpoints and the address flags. If MPTCP is enabled in NetworkManager, it will configure the addresses of the interface as MPTCP endpoints. Note that IPv4 loopback addresses (127.0.0.0/8), IPv4 link local addresses (169.254.0.0/16), the IPv6 loopback address (::1), IPv6 link local addresses (fe80::/10), IPv6 unique local addresses (ULA, fc00::/7) and IPv6 privacy extension addresses (rfc3041, ipv6.ip6-privacy) will be excluded from being configured as endpoints. If "disabled" (0x1), MPTCP handling for the interface is disabled and no endpoints are registered. The "enabled" (0x2) flag means that MPTCP handling is enabled. This flag can also be implied from the presence of other flags. Even when enabled, MPTCP handling will by default still be disabled unless "/proc/sys/net/mptcp/enabled" sysctl is on. NetworkManager does not change the sysctl and this is up to the administrator or distribution. To configure endpoints even if the sysctl is disabled, "also-without-sysctl" (0x4) flag can be used. In that case, NetworkManager doesn't look at the sysctl and configures endpoints regardless. Even when enabled, NetworkManager will only configure MPTCP endpoints for a certain address family, if there is a unicast default route (0.0.0.0/0 or ::/0) in the main routing table. The flag "also-without-default-route" (0x8) can override that. When MPTCP handling is enabled then endpoints are configured with the specified address flags "signal" (0x10), "subflow" (0x20), "backup" (0x40), "fullmesh" (0x80). See ip-mptcp(8) manual for additional information about the flags. If the flags are zero (0x0), the global connection default from NetworkManager.conf is honored. If still unspecified, the fallback is "enabled,subflow". Note that this means that MPTCP is by default done depending on the "/proc/sys/net/mptcp/enabled" sysctl. NetworkManager does not change the MPTCP limits nor enable MPTCP via "/proc/sys/net/mptcp/enabled". That is a host configuration which the admin can change via sysctl and ip-mptcp. Strict reverse path filtering (rp_filter) breaks many MPTCP use cases, so when MPTCP handling for IPv4 addresses on the interface is enabled, NetworkManager would loosen the strict reverse path filtering (1) to the loose setting (2)." + nmcli-description="Whether to configure MPTCP endpoints and the address flags. If MPTCP is enabled in NetworkManager, it will configure the addresses of the interface as MPTCP endpoints. Note that IPv4 loopback addresses (127.0.0.0/8), IPv4 link local addresses (169.254.0.0/16), the IPv6 loopback address (::1), IPv6 link local addresses (fe80::/10), IPv6 unique local addresses (ULA, fc00::/7) and IPv6 privacy extension addresses (rfc3041, ipv6.ip6-privacy) will be excluded from being configured as endpoints. If "disabled" (0x1), MPTCP handling for the interface is disabled and no endpoints are registered. The "enabled" (0x2) flag means that MPTCP handling is enabled. This flag can also be implied from the presence of other flags. Even when enabled, MPTCP handling will by default still be disabled unless "/proc/sys/net/mptcp/enabled" sysctl is on. NetworkManager does not change the sysctl and this is up to the administrator or distribution. To configure endpoints even if the sysctl is disabled, "also-without-sysctl" (0x4) flag can be used. In that case, NetworkManager doesn't look at the sysctl and configures endpoints regardless. Even when enabled, NetworkManager will only configure MPTCP endpoints for a certain address family, if there is a unicast default route (0.0.0.0/0 or ::/0) in the main routing table. The flag "also-without-default-route" (0x8) can override that. When MPTCP handling is enabled then endpoints are configured with the specified address flags "signal" (0x10), "subflow" (0x20), "backup" (0x40), "fullmesh" (0x80), "laminar" (0x100). See ip-mptcp(8) manual for additional information about the flags. If the flags are zero (0x0), the global connection default from NetworkManager.conf is honored. If still unspecified, the fallback is "enabled,subflow". Note that this means that MPTCP is by default done depending on the "/proc/sys/net/mptcp/enabled" sysctl. NetworkManager does not change the MPTCP limits nor enable MPTCP via "/proc/sys/net/mptcp/enabled". That is a host configuration which the admin can change via sysctl and ip-mptcp. Strict reverse path filtering (rp_filter) breaks many MPTCP use cases, so when MPTCP handling for IPv4 addresses on the interface is enabled, NetworkManager would loosen the strict reverse path filtering (1) to the loose setting (2)." format="flags (NMMptcpFlags)" - values="none/default (0x0), disabled (0x1), enabled (0x2), also-without-sysctl (0x4), also-without-default-route (0x8), signal (0x10), subflow (0x20), backup (0x40), fullmesh (0x80)" /> + values="none/default (0x0), disabled (0x1), enabled (0x2), also-without-sysctl (0x4), also-without-default-route (0x8), signal (0x10), subflow (0x20), backup (0x40), fullmesh (0x80), laminar (0x100)" /> <property name="mud-url" nmcli-description="If configured, set to a Manufacturer Usage Description (MUD) URL that points to manufacturer-recommended network policies for IoT devices. It is transmitted as a DHCPv4 or DHCPv6 option. The value must be a valid URL starting with "https://". The special value "none" is allowed to indicate that no MUD URL is used. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the ultimate default is "none"." format="string" /> @@ -1198,6 +1202,9 @@ nmcli-description="For LTE modems, this disables MSCHAPV2 authentication method for the initial EPS bearer that is set up when attaching to the network." format="boolean" values="true/yes/on, false/no/off" /> + <property name="device-uid" + nmcli-description="The device UID (as given by the WWAN management service) which this connection applies to. In contrast to "device-id", which is an inherent property of the connected device, this setting refers to a property set by a UDEV-rule. Refer to the "Common udev tags" -> "ID_MM_PHYSDEV_UID" documentation of ModemManager. If given, the connection will only apply to the specified device." + format="string" /> </setting> <setting name="hostname" > <property name="priority" @@ -1350,7 +1357,7 @@ format="list of ipv4.addresses objects" /> <property name="gateway" alias="gw4" - nmcli-description="The gateway associated with this configuration. This is only meaningful if "addresses" is also set. Setting the gateway causes NetworkManager to configure a standard default route with the gateway as next hop. This is ignored if "never-default" is set. An alternative is to configure the default route explicitly with a manual route and /0 as prefix length. Note that the gateway usually conflicts with routing that NetworkManager configures for WireGuard interfaces, so usually it should not be set in that case. See "ip4-auto-default-route"." + nmcli-description="The gateway associated with this configuration. This is only meaningful if addresses are also set on the device. Setting the gateway causes NetworkManager to configure a standard default route with the gateway as next hop. This is ignored if "never-default" is set. An alternative is to configure the default route explicitly with a manual route and /0 as prefix length. Note that the gateway usually conflicts with routing that NetworkManager configures for WireGuard interfaces, so usually it should not be set in that case. See "ip4-auto-default-route"." format="IPv4 address" /> <property name="routes" nmcli-description="A list of IPv4 destination addresses, prefix length, optional IPv4 next hop addresses, optional route metric, optional attribute. The valid syntax is: "ip[/prefix] [next-hop] [metric] [attribute=val]...[,ip[/prefix]...]". For example "192.0.2.0/24 10.1.1.1 77, 198.51.100.0/24"." @@ -1492,7 +1499,7 @@ format="list of ipv6.addresses objects" /> <property name="gateway" alias="gw6" - nmcli-description="The gateway associated with this configuration. This is only meaningful if "addresses" is also set. Setting the gateway causes NetworkManager to configure a standard default route with the gateway as next hop. This is ignored if "never-default" is set. An alternative is to configure the default route explicitly with a manual route and /0 as prefix length. Note that the gateway usually conflicts with routing that NetworkManager configures for WireGuard interfaces, so usually it should not be set in that case. See "ip4-auto-default-route"." + nmcli-description="The gateway associated with this configuration. This is only meaningful if addresses are also set on the device. Setting the gateway causes NetworkManager to configure a standard default route with the gateway as next hop. This is ignored if "never-default" is set. An alternative is to configure the default route explicitly with a manual route and /0 as prefix length. Note that the gateway usually conflicts with routing that NetworkManager configures for WireGuard interfaces, so usually it should not be set in that case. See "ip4-auto-default-route"." format="IPv6 address" /> <property name="routes" nmcli-description="Array of IP routes." @@ -2331,6 +2338,9 @@ nmcli-description="Like ip4-auto-default-route, but for the IPv6 default route." format="ternary" values="true/yes/on, false/no/off, default/unknown" /> + <property name="peers" + nmcli-description="A comma-separated list of WireGuard peers. Each peer has the following syntax: PUBLIC_KEY [ATTRIBUTE=VALUE [ATTRIBUTE=VALUE]...] The supported attributes are: endpoint, allowed-ips, persistent-keepalive, preshared-key, preshared-key-flags." + format="list of wireguard.peers objects" /> </setting> <setting name="wpan" > <property name="mac-address" diff --git a/src/tests/client/meson.build b/src/tests/client/meson.build index 5686a1c1..570a4a26 100644 --- a/src/tests/client/meson.build +++ b/src/tests/client/meson.build @@ -10,9 +10,6 @@ test( '--', 'TestNmcli', ], - env: [ - 'LIBTOOL=', - ], timeout: 120, ) @@ -27,9 +24,6 @@ if enable_nm_cloud_setup '--', 'TestNmCloudSetup', ], - env: [ - 'LIBTOOL=', - ], timeout: 120, ) endif diff --git a/src/tests/client/test-client.check-on-disk/test_002.expected b/src/tests/client/test-client.check-on-disk/test_002.expected index 11c8bb9c..cc35e4fd 100644 --- a/src/tests/client/test-client.check-on-disk/test_002.expected +++ b/src/tests/client/test-client.check-on-disk/test_002.expected @@ -506,12 +506,12 @@ NAME UUID TYPE DEVICE con-1 5fcfd6d7-1e63-3332-8826-a7eda103792d ethernet -- <<< -size: 1704 +size: 1757 location: src/tests/client/test-client.py:test_002()/23 cmd: $NMCLI c s con-1 lang: C returncode: 0 -stdout: 1576 bytes +stdout: 1629 bytes >>> connection.id: con-1 connection.uuid: 5fcfd6d7-1e63-3332-8826-a7eda103792d @@ -543,17 +543,18 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 <<< -size: 1715 +size: 1768 location: src/tests/client/test-client.py:test_002()/24 cmd: $NMCLI c s con-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 1577 bytes +stdout: 1630 bytes >>> connection.id: con-1 connection.uuid: 5fcfd6d7-1e63-3332-8826-a7eda103792d @@ -585,6 +586,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 diff --git a/src/tests/client/test-client.check-on-disk/test_003.expected b/src/tests/client/test-client.check-on-disk/test_003.expected index 40959fed..809b5579 100644 --- a/src/tests/client/test-client.check-on-disk/test_003.expected +++ b/src/tests/client/test-client.check-on-disk/test_003.expected @@ -182,12 +182,12 @@ id path uuid <<< -size: 6579 +size: 6675 location: src/tests/client/test-client.py:test_003()/14 cmd: $NMCLI con s con-gsm1 lang: C returncode: 0 -stdout: 6446 bytes +stdout: 6542 bytes >>> connection.id: con-gsm1 connection.uuid: UUID-con-gsm1-REPLACED-REPLACED-REPL @@ -219,6 +219,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -324,18 +325,19 @@ gsm.initial-eps-bearer-refuse-pap: no gsm.initial-eps-bearer-refuse-chap: no gsm.initial-eps-bearer-refuse-mschap: no gsm.initial-eps-bearer-refuse-mschapv2: no +gsm.device-uid: -- proxy.method: none proxy.browser-only: no proxy.pac-url: -- proxy.pac-script: -- <<< -size: 6622 +size: 6718 location: src/tests/client/test-client.py:test_003()/15 cmd: $NMCLI con s con-gsm1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6479 bytes +stdout: 6575 bytes >>> connection.id: con-gsm1 connection.uuid: UUID-con-gsm1-REPLACED-REPLACED-REPL @@ -367,6 +369,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -472,48 +475,49 @@ gsm.initial-eps-bearer-refuse-pap: nie gsm.initial-eps-bearer-refuse-chap: nie gsm.initial-eps-bearer-refuse-mschap: nie gsm.initial-eps-bearer-refuse-mschapv2: nie +gsm.device-uid: -- proxy.method: none proxy.browser-only: nie proxy.pac-url: -- proxy.pac-script: -- <<< -size: 584 +size: 588 location: src/tests/client/test-client.py:test_003()/16 cmd: $NMCLI -g all con s con-gsm1 lang: C returncode: 0 -stdout: 445 bytes +stdout: 449 bytes >>> -connection:con-gsm1:UUID-con-gsm1-REPLACED-REPLACED-REPL::gsm::no:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:con-gsm1:UUID-con-gsm1-REPLACED-REPLACED-REPL::gsm::no:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 ipv4:auto::: :0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: serial:5:8:even:1:100 -gsm:no:::<hidden>:0:xyz.con-gsm1::<hidden>:0:no::::auto:no:::<hidden>:0:yes:no:no:no:no:no +gsm:no:::<hidden>:0:xyz.con-gsm1::<hidden>:0:no::::auto:no:::<hidden>:0:yes:no:no:no:no:no: proxy:none:no:: <<< -size: 594 +size: 598 location: src/tests/client/test-client.py:test_003()/17 cmd: $NMCLI -g all con s con-gsm1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 445 bytes +stdout: 449 bytes >>> -connection:con-gsm1:UUID-con-gsm1-REPLACED-REPLACED-REPL::gsm::no:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:con-gsm1:UUID-con-gsm1-REPLACED-REPLACED-REPL::gsm::no:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 ipv4:auto::: :0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: serial:5:8:even:1:100 -gsm:no:::<hidden>:0:xyz.con-gsm1::<hidden>:0:no::::auto:no:::<hidden>:0:yes:no:no:no:no:no +gsm:no:::<hidden>:0:xyz.con-gsm1::<hidden>:0:no::::auto:no:::<hidden>:0:yes:no:no:no:no:no: proxy:none:no:: <<< -size: 6567 +size: 6663 location: src/tests/client/test-client.py:test_003()/18 cmd: $NMCLI con s con-gsm2 lang: C returncode: 0 -stdout: 6434 bytes +stdout: 6530 bytes >>> connection.id: con-gsm2 connection.uuid: UUID-con-gsm2-REPLACED-REPLACED-REPL @@ -545,6 +549,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -650,18 +655,19 @@ gsm.initial-eps-bearer-refuse-pap: no gsm.initial-eps-bearer-refuse-chap: no gsm.initial-eps-bearer-refuse-mschap: no gsm.initial-eps-bearer-refuse-mschapv2: no +gsm.device-uid: -- proxy.method: none proxy.browser-only: no proxy.pac-url: -- proxy.pac-script: -- <<< -size: 6610 +size: 6706 location: src/tests/client/test-client.py:test_003()/19 cmd: $NMCLI con s con-gsm2 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6467 bytes +stdout: 6563 bytes >>> connection.id: con-gsm2 connection.uuid: UUID-con-gsm2-REPLACED-REPLACED-REPL @@ -693,6 +699,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -798,48 +805,49 @@ gsm.initial-eps-bearer-refuse-pap: nie gsm.initial-eps-bearer-refuse-chap: nie gsm.initial-eps-bearer-refuse-mschap: nie gsm.initial-eps-bearer-refuse-mschapv2: nie +gsm.device-uid: -- proxy.method: none proxy.browser-only: nie proxy.pac-url: -- proxy.pac-script: -- <<< -size: 572 +size: 576 location: src/tests/client/test-client.py:test_003()/20 cmd: $NMCLI -g all con s con-gsm2 lang: C returncode: 0 -stdout: 433 bytes +stdout: 437 bytes >>> -connection:con-gsm2:UUID-con-gsm2-REPLACED-REPLACED-REPL::gsm::no:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:con-gsm2:UUID-con-gsm2-REPLACED-REPLACED-REPL::gsm::no:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 ipv4:auto::: :0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: serial:5:8:even:1:100 -gsm:no:::<hidden>:0:::<hidden>:0:no::::auto:no:::<hidden>:0:yes:no:no:no:no:no +gsm:no:::<hidden>:0:::<hidden>:0:no::::auto:no:::<hidden>:0:yes:no:no:no:no:no: proxy:none:no:: <<< -size: 582 +size: 586 location: src/tests/client/test-client.py:test_003()/21 cmd: $NMCLI -g all con s con-gsm2 lang: pl_PL.UTF-8 returncode: 0 -stdout: 433 bytes +stdout: 437 bytes >>> -connection:con-gsm2:UUID-con-gsm2-REPLACED-REPLACED-REPL::gsm::no:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:con-gsm2:UUID-con-gsm2-REPLACED-REPLACED-REPL::gsm::no:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 ipv4:auto::: :0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: serial:5:8:even:1:100 -gsm:no:::<hidden>:0:::<hidden>:0:no::::auto:no:::<hidden>:0:yes:no:no:no:no:no +gsm:no:::<hidden>:0:::<hidden>:0:no::::auto:no:::<hidden>:0:yes:no:no:no:no:no: proxy:none:no:: <<< -size: 6567 +size: 6663 location: src/tests/client/test-client.py:test_003()/22 cmd: $NMCLI con s con-gsm3 lang: C returncode: 0 -stdout: 6434 bytes +stdout: 6530 bytes >>> connection.id: con-gsm3 connection.uuid: UUID-con-gsm3-REPLACED-REPLACED-REPL @@ -871,6 +879,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -976,18 +985,19 @@ gsm.initial-eps-bearer-refuse-pap: no gsm.initial-eps-bearer-refuse-chap: no gsm.initial-eps-bearer-refuse-mschap: no gsm.initial-eps-bearer-refuse-mschapv2: no +gsm.device-uid: -- proxy.method: none proxy.browser-only: no proxy.pac-url: -- proxy.pac-script: -- <<< -size: 6610 +size: 6706 location: src/tests/client/test-client.py:test_003()/23 cmd: $NMCLI con s con-gsm3 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6467 bytes +stdout: 6563 bytes >>> connection.id: con-gsm3 connection.uuid: UUID-con-gsm3-REPLACED-REPLACED-REPL @@ -1019,6 +1029,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -1124,39 +1135,40 @@ gsm.initial-eps-bearer-refuse-pap: nie gsm.initial-eps-bearer-refuse-chap: nie gsm.initial-eps-bearer-refuse-mschap: nie gsm.initial-eps-bearer-refuse-mschapv2: nie +gsm.device-uid: -- proxy.method: none proxy.browser-only: nie proxy.pac-url: -- proxy.pac-script: -- <<< -size: 573 +size: 577 location: src/tests/client/test-client.py:test_003()/24 cmd: $NMCLI -g all con s con-gsm3 lang: C returncode: 0 -stdout: 434 bytes +stdout: 438 bytes >>> -connection:con-gsm3:UUID-con-gsm3-REPLACED-REPLACED-REPL::gsm::no:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:con-gsm3:UUID-con-gsm3-REPLACED-REPLACED-REPL::gsm::no:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 ipv4:auto::: :0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: serial:5:8:even:1:100 -gsm:no:::<hidden>:0: ::<hidden>:0:no::::auto:no:::<hidden>:0:yes:no:no:no:no:no +gsm:no:::<hidden>:0: ::<hidden>:0:no::::auto:no:::<hidden>:0:yes:no:no:no:no:no: proxy:none:no:: <<< -size: 583 +size: 587 location: src/tests/client/test-client.py:test_003()/25 cmd: $NMCLI -g all con s con-gsm3 lang: pl_PL.UTF-8 returncode: 0 -stdout: 434 bytes +stdout: 438 bytes >>> -connection:con-gsm3:UUID-con-gsm3-REPLACED-REPLACED-REPL::gsm::no:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:con-gsm3:UUID-con-gsm3-REPLACED-REPLACED-REPL::gsm::no:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 ipv4:auto::: :0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: serial:5:8:even:1:100 -gsm:no:::<hidden>:0: ::<hidden>:0:no::::auto:no:::<hidden>:0:yes:no:no:no:no:no +gsm:no:::<hidden>:0: ::<hidden>:0:no::::auto:no:::<hidden>:0:yes:no:no:no:no:no: proxy:none:no:: <<< @@ -1300,12 +1312,12 @@ UUID NAME UUID-ethernet-REPLACED-REPLACED-REPL ethernet <<< -size: 5919 +size: 5972 location: src/tests/client/test-client.py:test_003()/37 cmd: $NMCLI -f ALL con s ethernet lang: C returncode: 0 -stdout: 5779 bytes +stdout: 5832 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -1337,6 +1349,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -1433,12 +1446,12 @@ proxy.pac-url: -- proxy.pac-script: -- <<< -size: 5954 +size: 6007 location: src/tests/client/test-client.py:test_003()/38 cmd: $NMCLI -f ALL con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 5804 bytes +stdout: 5857 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -1470,6 +1483,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -1586,12 +1600,12 @@ stdout: 51 bytes GENERAL.STATE: aktywowano <<< -size: 6621 +size: 6674 location: src/tests/client/test-client.py:test_003()/41 cmd: $NMCLI con s ethernet lang: C returncode: 0 -stdout: 6488 bytes +stdout: 6541 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -1623,6 +1637,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -1732,12 +1747,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 6660 +size: 6713 location: src/tests/client/test-client.py:test_003()/42 cmd: $NMCLI con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 6517 bytes +stdout: 6570 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -1769,6 +1784,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -2364,12 +2380,12 @@ UUID NAME UUID-ethernet-REPLACED-REPLACED-REPL ethernet <<< -size: 5919 +size: 5972 location: src/tests/client/test-client.py:test_003()/62 cmd: $NMCLI -f ALL con s ethernet lang: C returncode: 0 -stdout: 5779 bytes +stdout: 5832 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -2401,6 +2417,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -2497,12 +2514,12 @@ proxy.pac-url: -- proxy.pac-script: -- <<< -size: 5954 +size: 6007 location: src/tests/client/test-client.py:test_003()/63 cmd: $NMCLI -f ALL con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 5804 bytes +stdout: 5857 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -2534,6 +2551,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -2654,12 +2672,12 @@ GENERAL.STATE: aktywowano GENERAL.STATE: aktywowano <<< -size: 7331 +size: 7384 location: src/tests/client/test-client.py:test_003()/66 cmd: $NMCLI con s ethernet lang: C returncode: 0 -stdout: 7198 bytes +stdout: 7251 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -2691,6 +2709,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -2814,12 +2833,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 7374 +size: 7427 location: src/tests/client/test-client.py:test_003()/67 cmd: $NMCLI con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 7231 bytes +stdout: 7284 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -2851,6 +2870,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -3482,12 +3502,12 @@ UUID-con-gsm3-REPLACED-REPLACED-REPL gsm UUID-con-xx1-REPLACED-REPLACED-REPLA ethernet <<< -size: 7334 +size: 7387 location: src/tests/client/test-client.py:test_003()/84 cmd: $NMCLI con s ethernet lang: C returncode: 0 -stdout: 7201 bytes +stdout: 7254 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -3519,6 +3539,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -3642,12 +3663,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 7378 +size: 7431 location: src/tests/client/test-client.py:test_003()/85 cmd: $NMCLI con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 7235 bytes +stdout: 7288 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -3679,6 +3700,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -3802,12 +3824,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 6664 +size: 6717 location: src/tests/client/test-client.py:test_003()/86 cmd: $NMCLI c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 6491 bytes +stdout: 6544 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -3839,6 +3861,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -3948,12 +3971,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 6704 +size: 6757 location: src/tests/client/test-client.py:test_003()/87 cmd: $NMCLI c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6521 bytes +stdout: 6574 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -3985,6 +4008,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -4304,12 +4328,12 @@ UUID-con-gsm3-REPLACED-REPLACED-REPL gsm UUID-con-xx1-REPLACED-REPLACED-REPLA ethernet <<< -size: 7346 +size: 7399 location: src/tests/client/test-client.py:test_003()/94 cmd: $NMCLI --color yes con s ethernet lang: C returncode: 0 -stdout: 7201 bytes +stdout: 7254 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -4341,6 +4365,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -4464,12 +4489,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 7390 +size: 7443 location: src/tests/client/test-client.py:test_003()/95 cmd: $NMCLI --color yes con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 7235 bytes +stdout: 7288 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -4501,6 +4526,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -4624,12 +4650,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 6676 +size: 6729 location: src/tests/client/test-client.py:test_003()/96 cmd: $NMCLI --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 6491 bytes +stdout: 6544 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -4661,6 +4687,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -4770,12 +4797,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 6716 +size: 6769 location: src/tests/client/test-client.py:test_003()/97 cmd: $NMCLI --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6521 bytes +stdout: 6574 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -4807,6 +4834,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -5142,12 +5170,12 @@ UUID-con-gsm3-REPLACED-REPLACED-REPL gsm UUID-con-xx1-REPLACED-REPLACED-REPLA ethernet <<< -size: 8587 +size: 8640 location: src/tests/client/test-client.py:test_003()/104 cmd: $NMCLI --pretty con s ethernet lang: C returncode: 0 -stdout: 8444 bytes +stdout: 8497 bytes >>> =============================================================================== Connection profile details (ethernet) @@ -5182,6 +5210,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -5318,12 +5347,12 @@ GENERAL.MASTER-PATH: -- ------------------------------------------------------------------------------- <<< -size: 8652 +size: 8705 location: src/tests/client/test-client.py:test_003()/105 cmd: $NMCLI --pretty con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 8499 bytes +stdout: 8552 bytes >>> =============================================================================== Szczegóły profilu połączenia (ethernet) @@ -5358,6 +5387,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -5494,12 +5524,12 @@ GENERAL.MASTER-PATH: -- ------------------------------------------------------------------------------- <<< -size: 7605 +size: 7658 location: src/tests/client/test-client.py:test_003()/106 cmd: $NMCLI --pretty c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 7422 bytes +stdout: 7475 bytes >>> =============================================================================== Connection profile details (ethernet) @@ -5534,6 +5564,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -5652,12 +5683,12 @@ GENERAL.MASTER-PATH: -- ------------------------------------------------------------------------------- <<< -size: 7658 +size: 7711 location: src/tests/client/test-client.py:test_003()/107 cmd: $NMCLI --pretty c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 7465 bytes +stdout: 7518 bytes >>> =============================================================================== Szczegóły profilu połączenia (ethernet) @@ -5692,6 +5723,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -6060,12 +6092,12 @@ UUID-con-gsm3-REPLACED-REPLACED-REPL gsm UUID-con-xx1-REPLACED-REPLACED-REPLA ethernet <<< -size: 8599 +size: 8652 location: src/tests/client/test-client.py:test_003()/114 cmd: $NMCLI --pretty --color yes con s ethernet lang: C returncode: 0 -stdout: 8444 bytes +stdout: 8497 bytes >>> =============================================================================== Connection profile details (ethernet) @@ -6100,6 +6132,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -6236,12 +6269,12 @@ GENERAL.MASTER-PATH: -- ------------------------------------------------------------------------------- <<< -size: 8664 +size: 8717 location: src/tests/client/test-client.py:test_003()/115 cmd: $NMCLI --pretty --color yes con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 8499 bytes +stdout: 8552 bytes >>> =============================================================================== Szczegóły profilu połączenia (ethernet) @@ -6276,6 +6309,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -6412,12 +6446,12 @@ GENERAL.MASTER-PATH: -- ------------------------------------------------------------------------------- <<< -size: 7617 +size: 7670 location: src/tests/client/test-client.py:test_003()/116 cmd: $NMCLI --pretty --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 7422 bytes +stdout: 7475 bytes >>> =============================================================================== Connection profile details (ethernet) @@ -6452,6 +6486,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -6570,12 +6605,12 @@ GENERAL.MASTER-PATH: -- ------------------------------------------------------------------------------- <<< -size: 7670 +size: 7723 location: src/tests/client/test-client.py:test_003()/117 cmd: $NMCLI --pretty --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 7465 bytes +stdout: 7518 bytes >>> =============================================================================== Szczegóły profilu połączenia (ethernet) @@ -6610,6 +6645,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -6958,12 +6994,12 @@ UUID-con-gsm3-REPLACED-REPLACED-REPL:gsm UUID-con-xx1-REPLACED-REPLACED-REPLA:802-3-ethernet <<< -size: 3938 +size: 3959 location: src/tests/client/test-client.py:test_003()/124 cmd: $NMCLI --terse con s ethernet lang: C returncode: 0 -stdout: 3796 bytes +stdout: 3817 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -6995,6 +7031,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -7118,12 +7155,12 @@ GENERAL.ZONE: GENERAL.MASTER-PATH: <<< -size: 3948 +size: 3969 location: src/tests/client/test-client.py:test_003()/125 cmd: $NMCLI --terse con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 3796 bytes +stdout: 3817 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -7155,6 +7192,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -7278,12 +7316,12 @@ GENERAL.ZONE: GENERAL.MASTER-PATH: <<< -size: 3588 +size: 3609 location: src/tests/client/test-client.py:test_003()/126 cmd: $NMCLI --terse c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 3406 bytes +stdout: 3427 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -7315,6 +7353,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -7424,12 +7463,12 @@ GENERAL.ZONE: GENERAL.MASTER-PATH: <<< -size: 3598 +size: 3619 location: src/tests/client/test-client.py:test_003()/127 cmd: $NMCLI --terse c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 3406 bytes +stdout: 3427 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -7461,6 +7500,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -7776,12 +7816,12 @@ UUID-con-gsm3-REPLACED-REPLACED-REPL:gsm UUID-con-xx1-REPLACED-REPLACED-REPLA:802-3-ethernet <<< -size: 3950 +size: 3971 location: src/tests/client/test-client.py:test_003()/134 cmd: $NMCLI --terse --color yes con s ethernet lang: C returncode: 0 -stdout: 3796 bytes +stdout: 3817 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -7813,6 +7853,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -7936,12 +7977,12 @@ GENERAL.ZONE: GENERAL.MASTER-PATH: <<< -size: 3960 +size: 3981 location: src/tests/client/test-client.py:test_003()/135 cmd: $NMCLI --terse --color yes con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 3796 bytes +stdout: 3817 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -7973,6 +8014,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -8096,12 +8138,12 @@ GENERAL.ZONE: GENERAL.MASTER-PATH: <<< -size: 3600 +size: 3621 location: src/tests/client/test-client.py:test_003()/136 cmd: $NMCLI --terse --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 3406 bytes +stdout: 3427 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -8133,6 +8175,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -8242,12 +8285,12 @@ GENERAL.ZONE: GENERAL.MASTER-PATH: <<< -size: 3610 +size: 3631 location: src/tests/client/test-client.py:test_003()/137 cmd: $NMCLI --terse --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 3406 bytes +stdout: 3427 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -8279,6 +8322,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -8598,15 +8642,15 @@ UUID-con-gsm3-REPLACED-REPLACED-REPL gsm UUID-con-xx1-REPLACED-REPLACED-REPLA ethernet <<< -size: 5055 +size: 5083 location: src/tests/client/test-client.py:test_003()/144 cmd: $NMCLI --mode tabular con s ethernet lang: C returncode: 0 -stdout: 4906 bytes +stdout: 4934 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-denylist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses 802-3-ethernet -- 0 -- no -- -- -- -- auto -- -- -- default -- -1 (default) @@ -8629,15 +8673,15 @@ GENERAL ethernet UUID-ethernet-REPLACED-REPLACED-REPL eth0 eth0 deac <<< -size: 5105 +size: 5133 location: src/tests/client/test-client.py:test_003()/145 cmd: $NMCLI --mode tabular con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 4946 bytes +stdout: 4974 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-denylist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses 802-3-ethernet -- 0 -- nie -- -- -- -- automatyczne -- -- -- default -- -1 (default) @@ -8660,15 +8704,15 @@ GENERAL ethernet UUID-ethernet-REPLACED-REPLACED-REPL eth0 eth0 deza <<< -size: 4593 +size: 4621 location: src/tests/client/test-client.py:test_003()/146 cmd: $NMCLI --mode tabular c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 4404 bytes +stdout: 4432 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-denylist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses 802-3-ethernet -- 0 -- no -- -- -- -- auto -- -- -- default -- -1 (default) @@ -8687,15 +8731,15 @@ GENERAL ethernet UUID-ethernet-REPLACED-REPLACED-REPL eth0 eth0 deac <<< -size: 4641 +size: 4669 location: src/tests/client/test-client.py:test_003()/147 cmd: $NMCLI --mode tabular c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4442 bytes +stdout: 4470 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-denylist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses 802-3-ethernet -- 0 -- nie -- -- -- -- automatyczne -- -- -- default -- -1 (default) @@ -8850,15 +8894,15 @@ UUID-con-gsm3-REPLACED-REPLACED-REPL gsm UUID-con-xx1-REPLACED-REPLACED-REPLA ethernet <<< -size: 5067 +size: 5095 location: src/tests/client/test-client.py:test_003()/154 cmd: $NMCLI --mode tabular --color yes con s ethernet lang: C returncode: 0 -stdout: 4906 bytes +stdout: 4934 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-denylist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses 802-3-ethernet -- 0 -- no -- -- -- -- auto -- -- -- default -- -1 (default) @@ -8881,15 +8925,15 @@ GENERAL ethernet UUID-ethernet-REPLACED-REPLACED-REPL eth0 eth0 deac <<< -size: 5117 +size: 5145 location: src/tests/client/test-client.py:test_003()/155 cmd: $NMCLI --mode tabular --color yes con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 4946 bytes +stdout: 4974 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-denylist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses 802-3-ethernet -- 0 -- nie -- -- -- -- automatyczne -- -- -- default -- -1 (default) @@ -8912,15 +8956,15 @@ GENERAL ethernet UUID-ethernet-REPLACED-REPLACED-REPL eth0 eth0 deza <<< -size: 4605 +size: 4633 location: src/tests/client/test-client.py:test_003()/156 cmd: $NMCLI --mode tabular --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 4404 bytes +stdout: 4432 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-denylist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses 802-3-ethernet -- 0 -- no -- -- -- -- auto -- -- -- default -- -1 (default) @@ -8939,15 +8983,15 @@ GENERAL ethernet UUID-ethernet-REPLACED-REPLACED-REPL eth0 eth0 deac <<< -size: 4653 +size: 4681 location: src/tests/client/test-client.py:test_003()/157 cmd: $NMCLI --mode tabular --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4442 bytes +stdout: 4470 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-denylist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses 802-3-ethernet -- 0 -- nie -- -- -- -- automatyczne -- -- -- default -- -1 (default) @@ -9118,19 +9162,19 @@ UUID-con-gsm3-REPLACED-REPLACED-REPL gsm UUID-con-xx1-REPLACED-REPLACED-REPLA ethernet <<< -size: 8054 +size: 8096 location: src/tests/client/test-client.py:test_003()/164 cmd: $NMCLI --mode tabular --pretty con s ethernet lang: C returncode: 0 -stdout: 7896 bytes +stdout: 7938 bytes >>> ========================================= Connection profile details (ethernet) ========================================= -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-denylist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -9165,19 +9209,19 @@ GENERAL ethernet UUID-ethernet-REPLACED-REPLACED-REPL eth0 eth0 deac <<< -size: 8184 +size: 8226 location: src/tests/client/test-client.py:test_003()/165 cmd: $NMCLI --mode tabular --pretty con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 8016 bytes +stdout: 8058 bytes >>> =========================================== Szczegóły profilu połączenia (ethernet) =========================================== -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-denylist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -9212,19 +9256,19 @@ GENERAL ethernet UUID-ethernet-REPLACED-REPLACED-REPL eth0 eth0 deza <<< -size: 7136 +size: 7178 location: src/tests/client/test-client.py:test_003()/166 cmd: $NMCLI --mode tabular --pretty c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 6938 bytes +stdout: 6980 bytes >>> ========================================= Connection profile details (ethernet) ========================================= -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-denylist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -9251,19 +9295,19 @@ GENERAL ethernet UUID-ethernet-REPLACED-REPLACED-REPL eth0 eth0 deac <<< -size: 7238 +size: 7280 location: src/tests/client/test-client.py:test_003()/167 cmd: $NMCLI --mode tabular --pretty c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 7030 bytes +stdout: 7072 bytes >>> =========================================== Szczegóły profilu połączenia (ethernet) =========================================== -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-denylist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -9466,19 +9510,19 @@ UUID-con-gsm3-REPLACED-REPLACED-REPL gsm UUID-con-xx1-REPLACED-REPLACED-REPLA ethernet <<< -size: 8066 +size: 8108 location: src/tests/client/test-client.py:test_003()/174 cmd: $NMCLI --mode tabular --pretty --color yes con s ethernet lang: C returncode: 0 -stdout: 7896 bytes +stdout: 7938 bytes >>> ========================================= Connection profile details (ethernet) ========================================= -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-denylist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -9513,19 +9557,19 @@ GENERAL ethernet UUID-ethernet-REPLACED-REPLACED-REPL eth0 eth0 deac <<< -size: 8196 +size: 8238 location: src/tests/client/test-client.py:test_003()/175 cmd: $NMCLI --mode tabular --pretty --color yes con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 8016 bytes +stdout: 8058 bytes >>> =========================================== Szczegóły profilu połączenia (ethernet) =========================================== -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-denylist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -9560,19 +9604,19 @@ GENERAL ethernet UUID-ethernet-REPLACED-REPLACED-REPL eth0 eth0 deza <<< -size: 7148 +size: 7190 location: src/tests/client/test-client.py:test_003()/176 cmd: $NMCLI --mode tabular --pretty --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 6938 bytes +stdout: 6980 bytes >>> ========================================= Connection profile details (ethernet) ========================================= -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-denylist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -9599,19 +9643,19 @@ GENERAL ethernet UUID-ethernet-REPLACED-REPLACED-REPL eth0 eth0 deac <<< -size: 7250 +size: 7292 location: src/tests/client/test-client.py:test_003()/177 cmd: $NMCLI --mode tabular --pretty --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 7030 bytes +stdout: 7072 bytes >>> =========================================== Szczegóły profilu połączenia (ethernet) =========================================== -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-denylist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -9794,14 +9838,14 @@ UUID-con-gsm3-REPLACED-REPLACED-REPL:gsm UUID-con-xx1-REPLACED-REPLACED-REPLA:802-3-ethernet <<< -size: 931 +size: 934 location: src/tests/client/test-client.py:test_003()/184 cmd: $NMCLI --mode tabular --terse con s ethernet lang: C returncode: 0 -stdout: 775 bytes +stdout: 778 bytes >>> -connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 802-3-ethernet::0::no:::::auto::::default::-1 ipv4:auto::::0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: @@ -9811,14 +9855,14 @@ GENERAL:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL:eth1:eth1:activated:no:no: GENERAL:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL:eth0:eth0:deactivating:no:no::no:/org/freedesktop/NetworkManager/ActiveConnection/1:/org/freedesktop/NetworkManager/Settings/Connection/6:: <<< -size: 941 +size: 944 location: src/tests/client/test-client.py:test_003()/185 cmd: $NMCLI --mode tabular --terse con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 775 bytes +stdout: 778 bytes >>> -connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 802-3-ethernet::0::no:::::auto::::default::-1 ipv4:auto::::0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: @@ -9828,14 +9872,14 @@ GENERAL:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL:eth1:eth1:activated:no:no: GENERAL:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL:eth0:eth0:deactivating:no:no::no:/org/freedesktop/NetworkManager/ActiveConnection/1:/org/freedesktop/NetworkManager/Settings/Connection/6:: <<< -size: 779 +size: 782 location: src/tests/client/test-client.py:test_003()/186 cmd: $NMCLI --mode tabular --terse c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 583 bytes +stdout: 586 bytes >>> -connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 802-3-ethernet::0::no:::::auto::::default::-1 ipv4:auto::::0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: @@ -9843,14 +9887,14 @@ proxy:none:no:: GENERAL:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL:eth0:eth0:deactivating:no:no::no:/org/freedesktop/NetworkManager/ActiveConnection/1:/org/freedesktop/NetworkManager/Settings/Connection/6:: <<< -size: 789 +size: 792 location: src/tests/client/test-client.py:test_003()/187 cmd: $NMCLI --mode tabular --terse c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 583 bytes +stdout: 586 bytes >>> -connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 802-3-ethernet::0::no:::::auto::::default::-1 ipv4:auto::::0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: @@ -9956,14 +10000,14 @@ UUID-con-gsm3-REPLACED-REPLACED-REPL:gsm UUID-con-xx1-REPLACED-REPLACED-REPLA:802-3-ethernet <<< -size: 943 +size: 946 location: src/tests/client/test-client.py:test_003()/194 cmd: $NMCLI --mode tabular --terse --color yes con s ethernet lang: C returncode: 0 -stdout: 775 bytes +stdout: 778 bytes >>> -connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 802-3-ethernet::0::no:::::auto::::default::-1 ipv4:auto::::0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: @@ -9973,14 +10017,14 @@ GENERAL:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL:eth1:eth1:activated:no:no: GENERAL:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL:eth0:eth0:deactivating:no:no::no:/org/freedesktop/NetworkManager/ActiveConnection/1:/org/freedesktop/NetworkManager/Settings/Connection/6:: <<< -size: 953 +size: 956 location: src/tests/client/test-client.py:test_003()/195 cmd: $NMCLI --mode tabular --terse --color yes con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 775 bytes +stdout: 778 bytes >>> -connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 802-3-ethernet::0::no:::::auto::::default::-1 ipv4:auto::::0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: @@ -9990,14 +10034,14 @@ GENERAL:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL:eth1:eth1:activated:no:no: GENERAL:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL:eth0:eth0:deactivating:no:no::no:/org/freedesktop/NetworkManager/ActiveConnection/1:/org/freedesktop/NetworkManager/Settings/Connection/6:: <<< -size: 791 +size: 794 location: src/tests/client/test-client.py:test_003()/196 cmd: $NMCLI --mode tabular --terse --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 583 bytes +stdout: 586 bytes >>> -connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 802-3-ethernet::0::no:::::auto::::default::-1 ipv4:auto::::0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: @@ -10005,14 +10049,14 @@ proxy:none:no:: GENERAL:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL:eth0:eth0:deactivating:no:no::no:/org/freedesktop/NetworkManager/ActiveConnection/1:/org/freedesktop/NetworkManager/Settings/Connection/6:: <<< -size: 801 +size: 804 location: src/tests/client/test-client.py:test_003()/197 cmd: $NMCLI --mode tabular --terse --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 583 bytes +stdout: 586 bytes >>> -connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 802-3-ethernet::0::no:::::auto::::default::-1 ipv4:auto::::0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: @@ -10326,12 +10370,12 @@ UUID: UUID-con-xx1-REPLACED-REPLACED-REPLA TYPE: ethernet <<< -size: 7352 +size: 7405 location: src/tests/client/test-client.py:test_003()/204 cmd: $NMCLI --mode multiline con s ethernet lang: C returncode: 0 -stdout: 7201 bytes +stdout: 7254 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -10363,6 +10407,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -10486,12 +10531,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 7396 +size: 7449 location: src/tests/client/test-client.py:test_003()/205 cmd: $NMCLI --mode multiline con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 7235 bytes +stdout: 7288 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -10523,6 +10568,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -10646,12 +10692,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 6682 +size: 6735 location: src/tests/client/test-client.py:test_003()/206 cmd: $NMCLI --mode multiline c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 6491 bytes +stdout: 6544 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -10683,6 +10729,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -10792,12 +10839,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 6722 +size: 6775 location: src/tests/client/test-client.py:test_003()/207 cmd: $NMCLI --mode multiline c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6521 bytes +stdout: 6574 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -10829,6 +10876,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -11352,12 +11400,12 @@ UUID: UUID-con-xx1-REPLACED-REPLACED-REPLA TYPE: ethernet <<< -size: 7364 +size: 7417 location: src/tests/client/test-client.py:test_003()/214 cmd: $NMCLI --mode multiline --color yes con s ethernet lang: C returncode: 0 -stdout: 7201 bytes +stdout: 7254 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -11389,6 +11437,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -11512,12 +11561,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 7408 +size: 7461 location: src/tests/client/test-client.py:test_003()/215 cmd: $NMCLI --mode multiline --color yes con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 7235 bytes +stdout: 7288 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -11549,6 +11598,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -11672,12 +11722,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 6694 +size: 6747 location: src/tests/client/test-client.py:test_003()/216 cmd: $NMCLI --mode multiline --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 6491 bytes +stdout: 6544 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -11709,6 +11759,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -11818,12 +11869,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 6734 +size: 6787 location: src/tests/client/test-client.py:test_003()/217 cmd: $NMCLI --mode multiline --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6521 bytes +stdout: 6574 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -11855,6 +11906,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -12416,12 +12468,12 @@ TYPE: ethernet ------------------------------------------------------------------------------- <<< -size: 8604 +size: 8657 location: src/tests/client/test-client.py:test_003()/224 cmd: $NMCLI --mode multiline --pretty con s ethernet lang: C returncode: 0 -stdout: 8444 bytes +stdout: 8497 bytes >>> =============================================================================== Connection profile details (ethernet) @@ -12456,6 +12508,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -12592,12 +12645,12 @@ GENERAL.MASTER-PATH: -- ------------------------------------------------------------------------------- <<< -size: 8669 +size: 8722 location: src/tests/client/test-client.py:test_003()/225 cmd: $NMCLI --mode multiline --pretty con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 8499 bytes +stdout: 8552 bytes >>> =============================================================================== Szczegóły profilu połączenia (ethernet) @@ -12632,6 +12685,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -12768,12 +12822,12 @@ GENERAL.MASTER-PATH: -- ------------------------------------------------------------------------------- <<< -size: 7622 +size: 7675 location: src/tests/client/test-client.py:test_003()/226 cmd: $NMCLI --mode multiline --pretty c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 7422 bytes +stdout: 7475 bytes >>> =============================================================================== Connection profile details (ethernet) @@ -12808,6 +12862,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -12926,12 +12981,12 @@ GENERAL.MASTER-PATH: -- ------------------------------------------------------------------------------- <<< -size: 7675 +size: 7728 location: src/tests/client/test-client.py:test_003()/227 cmd: $NMCLI --mode multiline --pretty c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 7465 bytes +stdout: 7518 bytes >>> =============================================================================== Szczegóły profilu połączenia (ethernet) @@ -12966,6 +13021,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -13560,12 +13616,12 @@ TYPE: ethernet ------------------------------------------------------------------------------- <<< -size: 8616 +size: 8669 location: src/tests/client/test-client.py:test_003()/234 cmd: $NMCLI --mode multiline --pretty --color yes con s ethernet lang: C returncode: 0 -stdout: 8444 bytes +stdout: 8497 bytes >>> =============================================================================== Connection profile details (ethernet) @@ -13600,6 +13656,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -13736,12 +13793,12 @@ GENERAL.MASTER-PATH: -- ------------------------------------------------------------------------------- <<< -size: 8681 +size: 8734 location: src/tests/client/test-client.py:test_003()/235 cmd: $NMCLI --mode multiline --pretty --color yes con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 8499 bytes +stdout: 8552 bytes >>> =============================================================================== Szczegóły profilu połączenia (ethernet) @@ -13776,6 +13833,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -13912,12 +13970,12 @@ GENERAL.MASTER-PATH: -- ------------------------------------------------------------------------------- <<< -size: 7634 +size: 7687 location: src/tests/client/test-client.py:test_003()/236 cmd: $NMCLI --mode multiline --pretty --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 7422 bytes +stdout: 7475 bytes >>> =============================================================================== Connection profile details (ethernet) @@ -13952,6 +14010,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -14070,12 +14129,12 @@ GENERAL.MASTER-PATH: -- ------------------------------------------------------------------------------- <<< -size: 7687 +size: 7740 location: src/tests/client/test-client.py:test_003()/237 cmd: $NMCLI --mode multiline --pretty --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 7465 bytes +stdout: 7518 bytes >>> =============================================================================== Szczegóły profilu połączenia (ethernet) @@ -14110,6 +14169,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -14666,12 +14726,12 @@ UUID:UUID-con-xx1-REPLACED-REPLACED-REPLA TYPE:802-3-ethernet <<< -size: 3955 +size: 3976 location: src/tests/client/test-client.py:test_003()/244 cmd: $NMCLI --mode multiline --terse con s ethernet lang: C returncode: 0 -stdout: 3796 bytes +stdout: 3817 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -14703,6 +14763,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -14826,12 +14887,12 @@ GENERAL.ZONE: GENERAL.MASTER-PATH: <<< -size: 3965 +size: 3986 location: src/tests/client/test-client.py:test_003()/245 cmd: $NMCLI --mode multiline --terse con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 3796 bytes +stdout: 3817 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -14863,6 +14924,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -14986,12 +15048,12 @@ GENERAL.ZONE: GENERAL.MASTER-PATH: <<< -size: 3605 +size: 3626 location: src/tests/client/test-client.py:test_003()/246 cmd: $NMCLI --mode multiline --terse c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 3406 bytes +stdout: 3427 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -15023,6 +15085,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -15132,12 +15195,12 @@ GENERAL.ZONE: GENERAL.MASTER-PATH: <<< -size: 3615 +size: 3636 location: src/tests/client/test-client.py:test_003()/247 cmd: $NMCLI --mode multiline --terse c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 3406 bytes +stdout: 3427 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -15169,6 +15232,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -15692,12 +15756,12 @@ UUID:UUID-con-xx1-REPLACED-REPLACED-REPLA TYPE:802-3-ethernet <<< -size: 3967 +size: 3988 location: src/tests/client/test-client.py:test_003()/254 cmd: $NMCLI --mode multiline --terse --color yes con s ethernet lang: C returncode: 0 -stdout: 3796 bytes +stdout: 3817 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -15729,6 +15793,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -15852,12 +15917,12 @@ GENERAL.ZONE: GENERAL.MASTER-PATH: <<< -size: 3977 +size: 3998 location: src/tests/client/test-client.py:test_003()/255 cmd: $NMCLI --mode multiline --terse --color yes con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 3796 bytes +stdout: 3817 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -15889,6 +15954,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -16012,12 +16078,12 @@ GENERAL.ZONE: GENERAL.MASTER-PATH: <<< -size: 3617 +size: 3638 location: src/tests/client/test-client.py:test_003()/256 cmd: $NMCLI --mode multiline --terse --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 3406 bytes +stdout: 3427 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -16049,6 +16115,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -16158,12 +16225,12 @@ GENERAL.ZONE: GENERAL.MASTER-PATH: <<< -size: 3627 +size: 3648 location: src/tests/client/test-client.py:test_003()/257 cmd: $NMCLI --mode multiline --terse --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 3406 bytes +stdout: 3427 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -16195,6 +16262,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 diff --git a/src/tests/client/test-client.check-on-disk/test_004.expected b/src/tests/client/test-client.check-on-disk/test_004.expected index 09422f10..11ef7556 100644 --- a/src/tests/client/test-client.check-on-disk/test_004.expected +++ b/src/tests/client/test-client.check-on-disk/test_004.expected @@ -58,12 +58,12 @@ location: src/tests/client/test-client.py:test_004()/7 cmd: $NMCLI connection mod con-xx1 ipv4.addresses 192.168.77.5/24 ipv4.routes '2.3.4.5/32 192.168.77.1' ipv6.addresses 1:2:3:4::6/64 ipv6.routes 1:2:3:4:5:6::5/128 lang: C returncode: 0 -size: 6199 +size: 6252 location: src/tests/client/test-client.py:test_004()/8 cmd: $NMCLI con s con-xx1 lang: C returncode: 0 -stdout: 6068 bytes +stdout: 6121 bytes >>> connection.id: con-xx1 connection.uuid: UUID-con-xx1-REPLACED-REPLACED-REPLA @@ -95,6 +95,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -194,12 +195,12 @@ proxy.pac-url: -- proxy.pac-script: -- <<< -size: 6234 +size: 6287 location: src/tests/client/test-client.py:test_004()/9 cmd: $NMCLI con s con-xx1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6093 bytes +stdout: 6146 bytes >>> connection.id: con-xx1 connection.uuid: UUID-con-xx1-REPLACED-REPLACED-REPLA @@ -231,6 +232,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -366,12 +368,12 @@ con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP vpn -- con-xx1 UUID-con-xx1-REPLACED-REPLACED-REPLA wifi -- <<< -size: 5575 +size: 5628 location: src/tests/client/test-client.py:test_004()/13 cmd: $NMCLI con s con-vpn-1 lang: C returncode: 0 -stdout: 5441 bytes +stdout: 5494 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -403,6 +405,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -490,12 +493,12 @@ proxy.pac-url: -- proxy.pac-script: -- <<< -size: 5602 +size: 5655 location: src/tests/client/test-client.py:test_004()/14 cmd: $NMCLI con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5458 bytes +stdout: 5511 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -527,6 +530,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -686,12 +690,12 @@ con-xx1 UUID-con-xx1-REPLACED-REPLACED-REPLA wifi wlan0 con-1 5fcfd6d7-1e63-3332-8826-a7eda103792d ethernet -- <<< -size: 6703 +size: 6756 location: src/tests/client/test-client.py:test_004()/21 cmd: $NMCLI con s con-vpn-1 lang: C returncode: 0 -stdout: 6569 bytes +stdout: 6622 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -723,6 +727,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -831,12 +836,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 6736 +size: 6789 location: src/tests/client/test-client.py:test_004()/22 cmd: $NMCLI con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6592 bytes +stdout: 6645 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -868,6 +873,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -1092,12 +1098,12 @@ con-xx1 UUID-con-xx1-REPLACED-REPLACED-REPLA wifi 0 never con-1 5fcfd6d7-1e63-3332-8826-a7eda103792d ethernet 0 never yes 0 no /org/freedesktop/NetworkManager/Settings/Connection/1 no -- -- -- -- /etc/NetworkManager/system-connections/con-1 <<< -size: 6709 +size: 6762 location: src/tests/client/test-client.py:test_004()/27 cmd: $NMCLI con s con-vpn-1 lang: C returncode: 0 -stdout: 6575 bytes +stdout: 6628 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -1129,6 +1135,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -1237,12 +1244,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 6746 +size: 6799 location: src/tests/client/test-client.py:test_004()/28 cmd: $NMCLI con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6602 bytes +stdout: 6655 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -1274,6 +1281,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -1382,12 +1390,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 6709 +size: 6762 location: src/tests/client/test-client.py:test_004()/29 cmd: $NMCLI con s con-vpn-1 lang: C returncode: 0 -stdout: 6575 bytes +stdout: 6628 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -1419,6 +1427,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -1527,12 +1536,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 6746 +size: 6799 location: src/tests/client/test-client.py:test_004()/30 cmd: $NMCLI con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6602 bytes +stdout: 6655 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -1564,6 +1573,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -1672,12 +1682,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 5582 +size: 5635 location: src/tests/client/test-client.py:test_004()/31 cmd: $NMCLI -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 5441 bytes +stdout: 5494 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -1709,6 +1719,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -1796,12 +1807,12 @@ proxy.pac-url: -- proxy.pac-script: -- <<< -size: 5609 +size: 5662 location: src/tests/client/test-client.py:test_004()/32 cmd: $NMCLI -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5458 bytes +stdout: 5511 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -1833,6 +1844,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -4530,12 +4542,12 @@ connection.type: 802-11-wireless connection.interface-name: -- <<< -size: 6721 +size: 6774 location: src/tests/client/test-client.py:test_004()/77 cmd: $NMCLI --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 6575 bytes +stdout: 6628 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -4567,6 +4579,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -4675,12 +4688,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 6758 +size: 6811 location: src/tests/client/test-client.py:test_004()/78 cmd: $NMCLI --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6602 bytes +stdout: 6655 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -4712,6 +4725,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -4820,12 +4834,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 6721 +size: 6774 location: src/tests/client/test-client.py:test_004()/79 cmd: $NMCLI --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 6575 bytes +stdout: 6628 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -4857,6 +4871,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -4965,12 +4980,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 6758 +size: 6811 location: src/tests/client/test-client.py:test_004()/80 cmd: $NMCLI --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6602 bytes +stdout: 6655 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -5002,6 +5017,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -5110,12 +5126,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 5594 +size: 5647 location: src/tests/client/test-client.py:test_004()/81 cmd: $NMCLI --color yes -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 5441 bytes +stdout: 5494 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -5147,6 +5163,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -5234,12 +5251,12 @@ proxy.pac-url: -- proxy.pac-script: -- <<< -size: 5621 +size: 5674 location: src/tests/client/test-client.py:test_004()/82 cmd: $NMCLI --color yes -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5458 bytes +stdout: 5511 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -5271,6 +5288,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -7968,12 +7986,12 @@ connection.type: 802-11-wireless connection.interface-name: -- <<< -size: 7730 +size: 7783 location: src/tests/client/test-client.py:test_004()/127 cmd: $NMCLI --pretty con s con-vpn-1 lang: C returncode: 0 -stdout: 7586 bytes +stdout: 7639 bytes >>> =============================================================================== Connection profile details (con-vpn-1) @@ -8008,6 +8026,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -8126,12 +8145,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 7780 +size: 7833 location: src/tests/client/test-client.py:test_004()/128 cmd: $NMCLI --pretty con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 7626 bytes +stdout: 7679 bytes >>> =============================================================================== Szczegóły profilu połączenia (con-vpn-1) @@ -8166,6 +8185,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -8284,12 +8304,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 7730 +size: 7783 location: src/tests/client/test-client.py:test_004()/129 cmd: $NMCLI --pretty con s con-vpn-1 lang: C returncode: 0 -stdout: 7586 bytes +stdout: 7639 bytes >>> =============================================================================== Connection profile details (con-vpn-1) @@ -8324,6 +8344,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -8442,12 +8463,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 7780 +size: 7833 location: src/tests/client/test-client.py:test_004()/130 cmd: $NMCLI --pretty con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 7626 bytes +stdout: 7679 bytes >>> =============================================================================== Szczegóły profilu połączenia (con-vpn-1) @@ -8482,6 +8503,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -8600,12 +8622,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 6211 +size: 6264 location: src/tests/client/test-client.py:test_004()/131 cmd: $NMCLI --pretty -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 6060 bytes +stdout: 6113 bytes >>> =============================================================================== Connection profile details (con-vpn-1) @@ -8640,6 +8662,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -8732,12 +8755,12 @@ proxy.pac-script: -- ------------------------------------------------------------------------------- <<< -size: 6243 +size: 6296 location: src/tests/client/test-client.py:test_004()/132 cmd: $NMCLI --pretty -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6082 bytes +stdout: 6135 bytes >>> =============================================================================== Szczegóły profilu połączenia (con-vpn-1) @@ -8772,6 +8795,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -12078,12 +12102,12 @@ connection.interface-name: -- ------------------------------------------------------------------------------- <<< -size: 7742 +size: 7795 location: src/tests/client/test-client.py:test_004()/177 cmd: $NMCLI --pretty --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 7586 bytes +stdout: 7639 bytes >>> =============================================================================== Connection profile details (con-vpn-1) @@ -12118,6 +12142,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -12236,12 +12261,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 7792 +size: 7845 location: src/tests/client/test-client.py:test_004()/178 cmd: $NMCLI --pretty --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 7626 bytes +stdout: 7679 bytes >>> =============================================================================== Szczegóły profilu połączenia (con-vpn-1) @@ -12276,6 +12301,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -12394,12 +12420,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 7742 +size: 7795 location: src/tests/client/test-client.py:test_004()/179 cmd: $NMCLI --pretty --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 7586 bytes +stdout: 7639 bytes >>> =============================================================================== Connection profile details (con-vpn-1) @@ -12434,6 +12460,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -12552,12 +12579,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 7792 +size: 7845 location: src/tests/client/test-client.py:test_004()/180 cmd: $NMCLI --pretty --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 7626 bytes +stdout: 7679 bytes >>> =============================================================================== Szczegóły profilu połączenia (con-vpn-1) @@ -12592,6 +12619,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -12710,12 +12738,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 6223 +size: 6276 location: src/tests/client/test-client.py:test_004()/181 cmd: $NMCLI --pretty --color yes -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 6060 bytes +stdout: 6113 bytes >>> =============================================================================== Connection profile details (con-vpn-1) @@ -12750,6 +12778,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -12842,12 +12871,12 @@ proxy.pac-script: -- ------------------------------------------------------------------------------- <<< -size: 6255 +size: 6308 location: src/tests/client/test-client.py:test_004()/182 cmd: $NMCLI --pretty --color yes -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6082 bytes +stdout: 6135 bytes >>> =============================================================================== Szczegóły profilu połączenia (con-vpn-1) @@ -12882,6 +12911,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -16188,12 +16218,12 @@ connection.interface-name: -- ------------------------------------------------------------------------------- <<< -size: 3428 +size: 3449 location: src/tests/client/test-client.py:test_004()/227 cmd: $NMCLI --terse con s con-vpn-1 lang: C returncode: 0 -stdout: 3285 bytes +stdout: 3306 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -16225,6 +16255,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -16333,12 +16364,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 3438 +size: 3459 location: src/tests/client/test-client.py:test_004()/228 cmd: $NMCLI --terse con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 3285 bytes +stdout: 3306 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -16370,6 +16401,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -16478,12 +16510,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 3428 +size: 3449 location: src/tests/client/test-client.py:test_004()/229 cmd: $NMCLI --terse con s con-vpn-1 lang: C returncode: 0 -stdout: 3285 bytes +stdout: 3306 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -16515,6 +16547,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -16623,12 +16656,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 3438 +size: 3459 location: src/tests/client/test-client.py:test_004()/230 cmd: $NMCLI --terse con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 3285 bytes +stdout: 3306 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -16660,6 +16693,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -16768,12 +16802,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 2853 +size: 2874 location: src/tests/client/test-client.py:test_004()/231 cmd: $NMCLI --terse -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 2703 bytes +stdout: 2724 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -16805,6 +16839,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -16892,12 +16927,12 @@ proxy.pac-url: proxy.pac-script: <<< -size: 2863 +size: 2884 location: src/tests/client/test-client.py:test_004()/232 cmd: $NMCLI --terse -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 2703 bytes +stdout: 2724 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -16929,6 +16964,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -19596,12 +19632,12 @@ connection.type:802-11-wireless connection.interface-name: <<< -size: 3440 +size: 3461 location: src/tests/client/test-client.py:test_004()/277 cmd: $NMCLI --terse --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 3285 bytes +stdout: 3306 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -19633,6 +19669,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -19741,12 +19778,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 3450 +size: 3471 location: src/tests/client/test-client.py:test_004()/278 cmd: $NMCLI --terse --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 3285 bytes +stdout: 3306 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -19778,6 +19815,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -19886,12 +19924,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 3440 +size: 3461 location: src/tests/client/test-client.py:test_004()/279 cmd: $NMCLI --terse --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 3285 bytes +stdout: 3306 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -19923,6 +19961,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -20031,12 +20070,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 3450 +size: 3471 location: src/tests/client/test-client.py:test_004()/280 cmd: $NMCLI --terse --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 3285 bytes +stdout: 3306 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -20068,6 +20107,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -20176,12 +20216,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 2865 +size: 2886 location: src/tests/client/test-client.py:test_004()/281 cmd: $NMCLI --terse --color yes -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 2703 bytes +stdout: 2724 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -20213,6 +20253,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -20300,12 +20341,12 @@ proxy.pac-url: proxy.pac-script: <<< -size: 2875 +size: 2896 location: src/tests/client/test-client.py:test_004()/282 cmd: $NMCLI --terse --color yes -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 2703 bytes +stdout: 2724 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -20337,6 +20378,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -23004,15 +23046,15 @@ connection.type:802-11-wireless connection.interface-name: <<< -size: 4546 +size: 4574 location: src/tests/client/test-client.py:test_004()/327 cmd: $NMCLI --mode tabular con s con-vpn-1 lang: C returncode: 0 -stdout: 4396 bytes +stdout: 4424 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules replace-local-rule dhcp-send-release routed-dns ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-dscp dhcp-timeout dhcp-send-hostname-deprecated dhcp-send-hostname forwarding dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-ipv6-only-preferred link-local dhcp-reject-servers auto-route-ext-gw shared-dhcp-range shared-dhcp-lease-time ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- -1 (default) -1 (default) -1 (default) no no -- -- -- 0 (default) yes -1 (default) -1 (default) -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -1 (default) 0 (default) -- -1 (default) -- 0 (default) @@ -23033,15 +23075,15 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 - VPN connected key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 4585 +size: 4613 location: src/tests/client/test-client.py:test_004()/328 cmd: $NMCLI --mode tabular con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4425 bytes +stdout: 4453 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules replace-local-rule dhcp-send-release routed-dns ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-dscp dhcp-timeout dhcp-send-hostname-deprecated dhcp-send-hostname forwarding dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-ipv6-only-preferred link-local dhcp-reject-servers auto-route-ext-gw shared-dhcp-range shared-dhcp-lease-time ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- -1 (default) -1 (default) -1 (default) nie nie -- -- -- 0 (default) tak -1 (default) -1 (default) -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -1 (default) 0 (default) -- -1 (default) -- 0 (default) @@ -23062,15 +23104,15 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 — Połączono z VPN key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 4546 +size: 4574 location: src/tests/client/test-client.py:test_004()/329 cmd: $NMCLI --mode tabular con s con-vpn-1 lang: C returncode: 0 -stdout: 4396 bytes +stdout: 4424 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules replace-local-rule dhcp-send-release routed-dns ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-dscp dhcp-timeout dhcp-send-hostname-deprecated dhcp-send-hostname forwarding dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-ipv6-only-preferred link-local dhcp-reject-servers auto-route-ext-gw shared-dhcp-range shared-dhcp-lease-time ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- -1 (default) -1 (default) -1 (default) no no -- -- -- 0 (default) yes -1 (default) -1 (default) -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -1 (default) 0 (default) -- -1 (default) -- 0 (default) @@ -23091,15 +23133,15 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 - VPN connected key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 4585 +size: 4613 location: src/tests/client/test-client.py:test_004()/330 cmd: $NMCLI --mode tabular con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4425 bytes +stdout: 4453 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules replace-local-rule dhcp-send-release routed-dns ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-dscp dhcp-timeout dhcp-send-hostname-deprecated dhcp-send-hostname forwarding dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-ipv6-only-preferred link-local dhcp-reject-servers auto-route-ext-gw shared-dhcp-range shared-dhcp-lease-time ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- -1 (default) -1 (default) -1 (default) nie nie -- -- -- 0 (default) tak -1 (default) -1 (default) -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -1 (default) 0 (default) -- -1 (default) -- 0 (default) @@ -23120,15 +23162,15 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 — Połączono z VPN key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 3794 +size: 3822 location: src/tests/client/test-client.py:test_004()/331 cmd: $NMCLI --mode tabular -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 3637 bytes +stdout: 3665 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules replace-local-rule dhcp-send-release routed-dns ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-dscp dhcp-timeout dhcp-send-hostname-deprecated dhcp-send-hostname forwarding dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-ipv6-only-preferred link-local dhcp-reject-servers auto-route-ext-gw shared-dhcp-range shared-dhcp-lease-time ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- -1 (default) -1 (default) -1 (default) no no -- -- -- 0 (default) yes -1 (default) -1 (default) -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -1 (default) 0 (default) -- -1 (default) -- 0 (default) @@ -23144,15 +23186,15 @@ proxy none no -- -- <<< -size: 3822 +size: 3850 location: src/tests/client/test-client.py:test_004()/332 cmd: $NMCLI --mode tabular -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 3655 bytes +stdout: 3683 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules replace-local-rule dhcp-send-release routed-dns ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-dscp dhcp-timeout dhcp-send-hostname-deprecated dhcp-send-hostname forwarding dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-ipv6-only-preferred link-local dhcp-reject-servers auto-route-ext-gw shared-dhcp-range shared-dhcp-lease-time ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- -1 (default) -1 (default) -1 (default) nie nie -- -- -- 0 (default) tak -1 (default) -1 (default) -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -1 (default) 0 (default) -- -1 (default) -- 0 (default) @@ -24658,15 +24700,15 @@ interface-name <<< -size: 4558 +size: 4586 location: src/tests/client/test-client.py:test_004()/377 cmd: $NMCLI --mode tabular --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 4396 bytes +stdout: 4424 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules replace-local-rule dhcp-send-release routed-dns ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-dscp dhcp-timeout dhcp-send-hostname-deprecated dhcp-send-hostname forwarding dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-ipv6-only-preferred link-local dhcp-reject-servers auto-route-ext-gw shared-dhcp-range shared-dhcp-lease-time ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- -1 (default) -1 (default) -1 (default) no no -- -- -- 0 (default) yes -1 (default) -1 (default) -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -1 (default) 0 (default) -- -1 (default) -- 0 (default) @@ -24687,15 +24729,15 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 - VPN connected key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 4597 +size: 4625 location: src/tests/client/test-client.py:test_004()/378 cmd: $NMCLI --mode tabular --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4425 bytes +stdout: 4453 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules replace-local-rule dhcp-send-release routed-dns ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-dscp dhcp-timeout dhcp-send-hostname-deprecated dhcp-send-hostname forwarding dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-ipv6-only-preferred link-local dhcp-reject-servers auto-route-ext-gw shared-dhcp-range shared-dhcp-lease-time ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- -1 (default) -1 (default) -1 (default) nie nie -- -- -- 0 (default) tak -1 (default) -1 (default) -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -1 (default) 0 (default) -- -1 (default) -- 0 (default) @@ -24716,15 +24758,15 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 — Połączono z VPN key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 4558 +size: 4586 location: src/tests/client/test-client.py:test_004()/379 cmd: $NMCLI --mode tabular --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 4396 bytes +stdout: 4424 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules replace-local-rule dhcp-send-release routed-dns ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-dscp dhcp-timeout dhcp-send-hostname-deprecated dhcp-send-hostname forwarding dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-ipv6-only-preferred link-local dhcp-reject-servers auto-route-ext-gw shared-dhcp-range shared-dhcp-lease-time ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- -1 (default) -1 (default) -1 (default) no no -- -- -- 0 (default) yes -1 (default) -1 (default) -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -1 (default) 0 (default) -- -1 (default) -- 0 (default) @@ -24745,15 +24787,15 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 - VPN connected key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 4597 +size: 4625 location: src/tests/client/test-client.py:test_004()/380 cmd: $NMCLI --mode tabular --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4425 bytes +stdout: 4453 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules replace-local-rule dhcp-send-release routed-dns ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-dscp dhcp-timeout dhcp-send-hostname-deprecated dhcp-send-hostname forwarding dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-ipv6-only-preferred link-local dhcp-reject-servers auto-route-ext-gw shared-dhcp-range shared-dhcp-lease-time ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- -1 (default) -1 (default) -1 (default) nie nie -- -- -- 0 (default) tak -1 (default) -1 (default) -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -1 (default) 0 (default) -- -1 (default) -- 0 (default) @@ -24774,15 +24816,15 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 — Połączono z VPN key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 3806 +size: 3834 location: src/tests/client/test-client.py:test_004()/381 cmd: $NMCLI --mode tabular --color yes -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 3637 bytes +stdout: 3665 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules replace-local-rule dhcp-send-release routed-dns ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-dscp dhcp-timeout dhcp-send-hostname-deprecated dhcp-send-hostname forwarding dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-ipv6-only-preferred link-local dhcp-reject-servers auto-route-ext-gw shared-dhcp-range shared-dhcp-lease-time ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- -1 (default) -1 (default) -1 (default) no no -- -- -- 0 (default) yes -1 (default) -1 (default) -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -1 (default) 0 (default) -- -1 (default) -- 0 (default) @@ -24798,15 +24840,15 @@ proxy none no -- -- <<< -size: 3834 +size: 3862 location: src/tests/client/test-client.py:test_004()/382 cmd: $NMCLI --mode tabular --color yes -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 3655 bytes +stdout: 3683 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules replace-local-rule dhcp-send-release routed-dns ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-dscp dhcp-timeout dhcp-send-hostname-deprecated dhcp-send-hostname forwarding dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-ipv6-only-preferred link-local dhcp-reject-servers auto-route-ext-gw shared-dhcp-range shared-dhcp-lease-time ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- -1 (default) -1 (default) -1 (default) nie nie -- -- -- 0 (default) tak -1 (default) -1 (default) -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -1 (default) 0 (default) -- -1 (default) -- 0 (default) @@ -26312,19 +26354,19 @@ interface-name <<< -size: 7089 +size: 7131 location: src/tests/client/test-client.py:test_004()/427 cmd: $NMCLI --mode tabular --pretty con s con-vpn-1 lang: C returncode: 0 -stdout: 6930 bytes +stdout: 6972 bytes >>> ========================================== Connection profile details (con-vpn-1) ========================================== -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules replace-local-rule dhcp-send-release routed-dns ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-dscp dhcp-timeout dhcp-send-hostname-deprecated dhcp-send-hostname forwarding dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-ipv6-only-preferred link-local dhcp-reject-servers auto-route-ext-gw shared-dhcp-range shared-dhcp-lease-time --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -26354,19 +26396,19 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 - VPN connected key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 7175 +size: 7217 location: src/tests/client/test-client.py:test_004()/428 cmd: $NMCLI --mode tabular --pretty con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 7006 bytes +stdout: 7048 bytes >>> ============================================ Szczegóły profilu połączenia (con-vpn-1) ============================================ -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules replace-local-rule dhcp-send-release routed-dns ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-dscp dhcp-timeout dhcp-send-hostname-deprecated dhcp-send-hostname forwarding dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-ipv6-only-preferred link-local dhcp-reject-servers auto-route-ext-gw shared-dhcp-range shared-dhcp-lease-time --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -26396,19 +26438,19 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 — Połączono z VPN key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 7089 +size: 7131 location: src/tests/client/test-client.py:test_004()/429 cmd: $NMCLI --mode tabular --pretty con s con-vpn-1 lang: C returncode: 0 -stdout: 6930 bytes +stdout: 6972 bytes >>> ========================================== Connection profile details (con-vpn-1) ========================================== -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules replace-local-rule dhcp-send-release routed-dns ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-dscp dhcp-timeout dhcp-send-hostname-deprecated dhcp-send-hostname forwarding dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-ipv6-only-preferred link-local dhcp-reject-servers auto-route-ext-gw shared-dhcp-range shared-dhcp-lease-time --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -26438,19 +26480,19 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 - VPN connected key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 7175 +size: 7217 location: src/tests/client/test-client.py:test_004()/430 cmd: $NMCLI --mode tabular --pretty con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 7006 bytes +stdout: 7048 bytes >>> ============================================ Szczegóły profilu połączenia (con-vpn-1) ============================================ -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules replace-local-rule dhcp-send-release routed-dns ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-dscp dhcp-timeout dhcp-send-hostname-deprecated dhcp-send-hostname forwarding dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-ipv6-only-preferred link-local dhcp-reject-servers auto-route-ext-gw shared-dhcp-range shared-dhcp-lease-time --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -26480,19 +26522,19 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 — Połączono z VPN key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 5751 +size: 5793 location: src/tests/client/test-client.py:test_004()/431 cmd: $NMCLI --mode tabular --pretty -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 5585 bytes +stdout: 5627 bytes >>> ========================================== Connection profile details (con-vpn-1) ========================================== -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules replace-local-rule dhcp-send-release routed-dns ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-dscp dhcp-timeout dhcp-send-hostname-deprecated dhcp-send-hostname forwarding dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-ipv6-only-preferred link-local dhcp-reject-servers auto-route-ext-gw shared-dhcp-range shared-dhcp-lease-time --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -26512,19 +26554,19 @@ proxy none no -- -- <<< -size: 5798 +size: 5840 location: src/tests/client/test-client.py:test_004()/432 cmd: $NMCLI --mode tabular --pretty -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5622 bytes +stdout: 5664 bytes >>> ============================================ Szczegóły profilu połączenia (con-vpn-1) ============================================ -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules replace-local-rule dhcp-send-release routed-dns ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-dscp dhcp-timeout dhcp-send-hostname-deprecated dhcp-send-hostname forwarding dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-ipv6-only-preferred link-local dhcp-reject-servers auto-route-ext-gw shared-dhcp-range shared-dhcp-lease-time --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -28620,19 +28662,19 @@ interface-name <<< -size: 7101 +size: 7143 location: src/tests/client/test-client.py:test_004()/477 cmd: $NMCLI --mode tabular --pretty --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 6930 bytes +stdout: 6972 bytes >>> ========================================== Connection profile details (con-vpn-1) ========================================== -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules replace-local-rule dhcp-send-release routed-dns ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-dscp dhcp-timeout dhcp-send-hostname-deprecated dhcp-send-hostname forwarding dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-ipv6-only-preferred link-local dhcp-reject-servers auto-route-ext-gw shared-dhcp-range shared-dhcp-lease-time --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -28662,19 +28704,19 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 - VPN connected key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 7187 +size: 7229 location: src/tests/client/test-client.py:test_004()/478 cmd: $NMCLI --mode tabular --pretty --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 7006 bytes +stdout: 7048 bytes >>> ============================================ Szczegóły profilu połączenia (con-vpn-1) ============================================ -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules replace-local-rule dhcp-send-release routed-dns ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-dscp dhcp-timeout dhcp-send-hostname-deprecated dhcp-send-hostname forwarding dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-ipv6-only-preferred link-local dhcp-reject-servers auto-route-ext-gw shared-dhcp-range shared-dhcp-lease-time --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -28704,19 +28746,19 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 — Połączono z VPN key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 7101 +size: 7143 location: src/tests/client/test-client.py:test_004()/479 cmd: $NMCLI --mode tabular --pretty --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 6930 bytes +stdout: 6972 bytes >>> ========================================== Connection profile details (con-vpn-1) ========================================== -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules replace-local-rule dhcp-send-release routed-dns ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-dscp dhcp-timeout dhcp-send-hostname-deprecated dhcp-send-hostname forwarding dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-ipv6-only-preferred link-local dhcp-reject-servers auto-route-ext-gw shared-dhcp-range shared-dhcp-lease-time --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -28746,19 +28788,19 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 - VPN connected key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 7187 +size: 7229 location: src/tests/client/test-client.py:test_004()/480 cmd: $NMCLI --mode tabular --pretty --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 7006 bytes +stdout: 7048 bytes >>> ============================================ Szczegóły profilu połączenia (con-vpn-1) ============================================ -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules replace-local-rule dhcp-send-release routed-dns ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-dscp dhcp-timeout dhcp-send-hostname-deprecated dhcp-send-hostname forwarding dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-ipv6-only-preferred link-local dhcp-reject-servers auto-route-ext-gw shared-dhcp-range shared-dhcp-lease-time --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -28788,19 +28830,19 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 — Połączono z VPN key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 5763 +size: 5805 location: src/tests/client/test-client.py:test_004()/481 cmd: $NMCLI --mode tabular --pretty --color yes -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 5585 bytes +stdout: 5627 bytes >>> ========================================== Connection profile details (con-vpn-1) ========================================== -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) unknown default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules replace-local-rule dhcp-send-release routed-dns ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-dscp dhcp-timeout dhcp-send-hostname-deprecated dhcp-send-hostname forwarding dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-ipv6-only-preferred link-local dhcp-reject-servers auto-route-ext-gw shared-dhcp-range shared-dhcp-lease-time --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -28820,19 +28862,19 @@ proxy none no -- -- <<< -size: 5810 +size: 5852 location: src/tests/client/test-client.py:test_004()/482 cmd: $NMCLI --mode tabular --pretty --color yes -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5622 bytes +stdout: 5664 bytes >>> ============================================ Szczegóły profilu połączenia (con-vpn-1) ============================================ -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp permissions zone controller master slave-type port-type autoconnect-slaves autoconnect-ports down-on-poweroff secondaries gateway-ping-timeout ip-ping-timeout ip-ping-addresses ip-ping-addresses-require-all metered lldp mdns llmnr dns-over-tls dnssec mptcp-flags wait-device-timeout wait-activation-delay +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 -- -- -- -- -- -- -1 (default) -1 (default) -1 (default) -- 0 0 -- -1 (default) nieznane default -1 (default) -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules replace-local-rule dhcp-send-release routed-dns ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-dscp dhcp-timeout dhcp-send-hostname-deprecated dhcp-send-hostname forwarding dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-ipv6-only-preferred link-local dhcp-reject-servers auto-route-ext-gw shared-dhcp-range shared-dhcp-lease-time --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -30928,14 +30970,14 @@ interface-name <<< -size: 886 +size: 889 location: src/tests/client/test-client.py:test_004()/527 cmd: $NMCLI --mode tabular --terse con s con-vpn-1 lang: C returncode: 0 -stdout: 729 bytes +stdout: 732 bytes >>> -connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 ipv4:auto::::0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: vpn:org.freedesktop.NetworkManager.openvpn::key1 = val1, key2 = val2, key3 = val3:<hidden>:no:0 @@ -30944,14 +30986,14 @@ GENERAL:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP:wlan0:wlan0:activated:no: VPN:openvpn:::*** VPN connection con-vpn-1 ***:5 - VPN connected:key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 896 +size: 899 location: src/tests/client/test-client.py:test_004()/528 cmd: $NMCLI --mode tabular --terse con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 729 bytes +stdout: 732 bytes >>> -connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 ipv4:auto::::0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: vpn:org.freedesktop.NetworkManager.openvpn::key1 = val1, key2 = val2, key3 = val3:<hidden>:no:0 @@ -30960,14 +31002,14 @@ GENERAL:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP:wlan0:wlan0:activated:no: VPN:openvpn:::*** VPN connection con-vpn-1 ***:5 - VPN connected:key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 886 +size: 889 location: src/tests/client/test-client.py:test_004()/529 cmd: $NMCLI --mode tabular --terse con s con-vpn-1 lang: C returncode: 0 -stdout: 729 bytes +stdout: 732 bytes >>> -connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 ipv4:auto::::0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: vpn:org.freedesktop.NetworkManager.openvpn::key1 = val1, key2 = val2, key3 = val3:<hidden>:no:0 @@ -30976,14 +31018,14 @@ GENERAL:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP:wlan0:wlan0:activated:no: VPN:openvpn:::*** VPN connection con-vpn-1 ***:5 - VPN connected:key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 896 +size: 899 location: src/tests/client/test-client.py:test_004()/530 cmd: $NMCLI --mode tabular --terse con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 729 bytes +stdout: 732 bytes >>> -connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 ipv4:auto::::0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: vpn:org.freedesktop.NetworkManager.openvpn::key1 = val1, key2 = val2, key3 = val3:<hidden>:no:0 @@ -30992,28 +31034,28 @@ GENERAL:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP:wlan0:wlan0:activated:no: VPN:openvpn:::*** VPN connection con-vpn-1 ***:5 - VPN connected:key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 593 +size: 596 location: src/tests/client/test-client.py:test_004()/531 cmd: $NMCLI --mode tabular --terse -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 429 bytes +stdout: 432 bytes >>> -connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 ipv4:auto::::0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: vpn:org.freedesktop.NetworkManager.openvpn::key1 = val1, key2 = val2, key3 = val3:<hidden>:no:0 proxy:none:no:: <<< -size: 603 +size: 606 location: src/tests/client/test-client.py:test_004()/532 cmd: $NMCLI --mode tabular --terse -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 429 bytes +stdout: 432 bytes >>> -connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 ipv4:auto::::0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: vpn:org.freedesktop.NetworkManager.openvpn::key1 = val1, key2 = val2, key3 = val3:<hidden>:no:0 @@ -31866,14 +31908,14 @@ UUID-con-xx1-REPLACED-REPLACED-REPLA <<< -size: 898 +size: 901 location: src/tests/client/test-client.py:test_004()/577 cmd: $NMCLI --mode tabular --terse --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 729 bytes +stdout: 732 bytes >>> -connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 ipv4:auto::::0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: vpn:org.freedesktop.NetworkManager.openvpn::key1 = val1, key2 = val2, key3 = val3:<hidden>:no:0 @@ -31882,14 +31924,14 @@ GENERAL:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP:wlan0:wlan0:activated:no: VPN:openvpn:::*** VPN connection con-vpn-1 ***:5 - VPN connected:key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 908 +size: 911 location: src/tests/client/test-client.py:test_004()/578 cmd: $NMCLI --mode tabular --terse --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 729 bytes +stdout: 732 bytes >>> -connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 ipv4:auto::::0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: vpn:org.freedesktop.NetworkManager.openvpn::key1 = val1, key2 = val2, key3 = val3:<hidden>:no:0 @@ -31898,14 +31940,14 @@ GENERAL:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP:wlan0:wlan0:activated:no: VPN:openvpn:::*** VPN connection con-vpn-1 ***:5 - VPN connected:key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 898 +size: 901 location: src/tests/client/test-client.py:test_004()/579 cmd: $NMCLI --mode tabular --terse --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 729 bytes +stdout: 732 bytes >>> -connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 ipv4:auto::::0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: vpn:org.freedesktop.NetworkManager.openvpn::key1 = val1, key2 = val2, key3 = val3:<hidden>:no:0 @@ -31914,14 +31956,14 @@ GENERAL:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP:wlan0:wlan0:activated:no: VPN:openvpn:::*** VPN connection con-vpn-1 ***:5 - VPN connected:key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 908 +size: 911 location: src/tests/client/test-client.py:test_004()/580 cmd: $NMCLI --mode tabular --terse --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 729 bytes +stdout: 732 bytes >>> -connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 ipv4:auto::::0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: vpn:org.freedesktop.NetworkManager.openvpn::key1 = val1, key2 = val2, key3 = val3:<hidden>:no:0 @@ -31930,28 +31972,28 @@ GENERAL:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP:wlan0:wlan0:activated:no: VPN:openvpn:::*** VPN connection con-vpn-1 ***:5 - VPN connected:key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 605 +size: 608 location: src/tests/client/test-client.py:test_004()/581 cmd: $NMCLI --mode tabular --terse --color yes -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 429 bytes +stdout: 432 bytes >>> -connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 ipv4:auto::::0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: vpn:org.freedesktop.NetworkManager.openvpn::key1 = val1, key2 = val2, key3 = val3:<hidden>:no:0 proxy:none:no:: <<< -size: 615 +size: 618 location: src/tests/client/test-client.py:test_004()/582 cmd: $NMCLI --mode tabular --terse --color yes -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 429 bytes +stdout: 432 bytes >>> -connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:0x0:-1:-1 +connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:::::::-1:-1:-1::0:0::-1:unknown:default:-1:-1:-1:-1:0x0:-1:-1 ipv4:auto::::0::::-1:0::-1:-1:-1:no:no::::0:yes:-1:-1:::0x0:no:yes:-1:-1::-1:0::-1::0 ipv6:auto::::0::::-1:0::-1:-1:-1:no:no:no:yes:-1:-1:0:0:default:0:auto::::0:yes:-1::0x0:-1: vpn:org.freedesktop.NetworkManager.openvpn::key1 = val1, key2 = val2, key3 = val3:<hidden>:no:0 @@ -32804,12 +32846,12 @@ UUID-con-xx1-REPLACED-REPLACED-REPLA <<< -size: 6727 +size: 6780 location: src/tests/client/test-client.py:test_004()/627 cmd: $NMCLI --mode multiline con s con-vpn-1 lang: C returncode: 0 -stdout: 6575 bytes +stdout: 6628 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -32841,6 +32883,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -32949,12 +32992,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 6764 +size: 6817 location: src/tests/client/test-client.py:test_004()/628 cmd: $NMCLI --mode multiline con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6602 bytes +stdout: 6655 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -32986,6 +33029,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -33094,12 +33138,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 6727 +size: 6780 location: src/tests/client/test-client.py:test_004()/629 cmd: $NMCLI --mode multiline con s con-vpn-1 lang: C returncode: 0 -stdout: 6575 bytes +stdout: 6628 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -33131,6 +33175,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -33239,12 +33284,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 6764 +size: 6817 location: src/tests/client/test-client.py:test_004()/630 cmd: $NMCLI --mode multiline con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6602 bytes +stdout: 6655 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -33276,6 +33321,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -33384,12 +33430,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 5600 +size: 5653 location: src/tests/client/test-client.py:test_004()/631 cmd: $NMCLI --mode multiline -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 5441 bytes +stdout: 5494 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -33421,6 +33467,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -33508,12 +33555,12 @@ proxy.pac-url: -- proxy.pac-script: -- <<< -size: 5627 +size: 5680 location: src/tests/client/test-client.py:test_004()/632 cmd: $NMCLI --mode multiline -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5458 bytes +stdout: 5511 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -33545,6 +33592,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -36752,12 +36800,12 @@ connection.type: 802-11-wireless connection.interface-name: -- <<< -size: 6739 +size: 6792 location: src/tests/client/test-client.py:test_004()/677 cmd: $NMCLI --mode multiline --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 6575 bytes +stdout: 6628 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -36789,6 +36837,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -36897,12 +36946,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 6776 +size: 6829 location: src/tests/client/test-client.py:test_004()/678 cmd: $NMCLI --mode multiline --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6602 bytes +stdout: 6655 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -36934,6 +36983,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -37042,12 +37092,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 6739 +size: 6792 location: src/tests/client/test-client.py:test_004()/679 cmd: $NMCLI --mode multiline --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 6575 bytes +stdout: 6628 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -37079,6 +37129,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -37187,12 +37238,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 6776 +size: 6829 location: src/tests/client/test-client.py:test_004()/680 cmd: $NMCLI --mode multiline --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6602 bytes +stdout: 6655 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -37224,6 +37275,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -37332,12 +37384,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 5612 +size: 5665 location: src/tests/client/test-client.py:test_004()/681 cmd: $NMCLI --mode multiline --color yes -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 5441 bytes +stdout: 5494 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -37369,6 +37421,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -37456,12 +37509,12 @@ proxy.pac-url: -- proxy.pac-script: -- <<< -size: 5639 +size: 5692 location: src/tests/client/test-client.py:test_004()/682 cmd: $NMCLI --mode multiline --color yes -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5458 bytes +stdout: 5511 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -37493,6 +37546,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -40700,12 +40754,12 @@ connection.type: 802-11-wireless connection.interface-name: -- <<< -size: 7747 +size: 7800 location: src/tests/client/test-client.py:test_004()/727 cmd: $NMCLI --mode multiline --pretty con s con-vpn-1 lang: C returncode: 0 -stdout: 7586 bytes +stdout: 7639 bytes >>> =============================================================================== Connection profile details (con-vpn-1) @@ -40740,6 +40794,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -40858,12 +40913,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 7797 +size: 7850 location: src/tests/client/test-client.py:test_004()/728 cmd: $NMCLI --mode multiline --pretty con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 7626 bytes +stdout: 7679 bytes >>> =============================================================================== Szczegóły profilu połączenia (con-vpn-1) @@ -40898,6 +40953,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -41016,12 +41072,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 7747 +size: 7800 location: src/tests/client/test-client.py:test_004()/729 cmd: $NMCLI --mode multiline --pretty con s con-vpn-1 lang: C returncode: 0 -stdout: 7586 bytes +stdout: 7639 bytes >>> =============================================================================== Connection profile details (con-vpn-1) @@ -41056,6 +41112,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -41174,12 +41231,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 7797 +size: 7850 location: src/tests/client/test-client.py:test_004()/730 cmd: $NMCLI --mode multiline --pretty con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 7626 bytes +stdout: 7679 bytes >>> =============================================================================== Szczegóły profilu połączenia (con-vpn-1) @@ -41214,6 +41271,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -41332,12 +41390,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 6228 +size: 6281 location: src/tests/client/test-client.py:test_004()/731 cmd: $NMCLI --mode multiline --pretty -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 6060 bytes +stdout: 6113 bytes >>> =============================================================================== Connection profile details (con-vpn-1) @@ -41372,6 +41430,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -41464,12 +41523,12 @@ proxy.pac-script: -- ------------------------------------------------------------------------------- <<< -size: 6260 +size: 6313 location: src/tests/client/test-client.py:test_004()/732 cmd: $NMCLI --mode multiline --pretty -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6082 bytes +stdout: 6135 bytes >>> =============================================================================== Szczegóły profilu połączenia (con-vpn-1) @@ -41504,6 +41563,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -45350,12 +45410,12 @@ connection.interface-name: -- ------------------------------------------------------------------------------- <<< -size: 7759 +size: 7812 location: src/tests/client/test-client.py:test_004()/777 cmd: $NMCLI --mode multiline --pretty --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 7586 bytes +stdout: 7639 bytes >>> =============================================================================== Connection profile details (con-vpn-1) @@ -45390,6 +45450,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -45508,12 +45569,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 7809 +size: 7862 location: src/tests/client/test-client.py:test_004()/778 cmd: $NMCLI --mode multiline --pretty --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 7626 bytes +stdout: 7679 bytes >>> =============================================================================== Szczegóły profilu połączenia (con-vpn-1) @@ -45548,6 +45609,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -45666,12 +45728,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 7759 +size: 7812 location: src/tests/client/test-client.py:test_004()/779 cmd: $NMCLI --mode multiline --pretty --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 7586 bytes +stdout: 7639 bytes >>> =============================================================================== Connection profile details (con-vpn-1) @@ -45706,6 +45768,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -45824,12 +45887,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 7809 +size: 7862 location: src/tests/client/test-client.py:test_004()/780 cmd: $NMCLI --mode multiline --pretty --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 7626 bytes +stdout: 7679 bytes >>> =============================================================================== Szczegóły profilu połączenia (con-vpn-1) @@ -45864,6 +45927,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -45982,12 +46046,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 6240 +size: 6293 location: src/tests/client/test-client.py:test_004()/781 cmd: $NMCLI --mode multiline --pretty --color yes -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 6060 bytes +stdout: 6113 bytes >>> =============================================================================== Connection profile details (con-vpn-1) @@ -46022,6 +46086,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -46114,12 +46179,12 @@ proxy.pac-script: -- ------------------------------------------------------------------------------- <<< -size: 6272 +size: 6325 location: src/tests/client/test-client.py:test_004()/782 cmd: $NMCLI --mode multiline --pretty --color yes -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6082 bytes +stdout: 6135 bytes >>> =============================================================================== Szczegóły profilu połączenia (con-vpn-1) @@ -46154,6 +46219,7 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.dnssec: -1 (default) connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 connection.wait-activation-delay: -1 @@ -50000,12 +50066,12 @@ connection.interface-name: -- ------------------------------------------------------------------------------- <<< -size: 3445 +size: 3466 location: src/tests/client/test-client.py:test_004()/827 cmd: $NMCLI --mode multiline --terse con s con-vpn-1 lang: C returncode: 0 -stdout: 3285 bytes +stdout: 3306 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -50037,6 +50103,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -50145,12 +50212,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 3455 +size: 3476 location: src/tests/client/test-client.py:test_004()/828 cmd: $NMCLI --mode multiline --terse con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 3285 bytes +stdout: 3306 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -50182,6 +50249,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -50290,12 +50358,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 3445 +size: 3466 location: src/tests/client/test-client.py:test_004()/829 cmd: $NMCLI --mode multiline --terse con s con-vpn-1 lang: C returncode: 0 -stdout: 3285 bytes +stdout: 3306 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -50327,6 +50395,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -50435,12 +50504,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 3455 +size: 3476 location: src/tests/client/test-client.py:test_004()/830 cmd: $NMCLI --mode multiline --terse con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 3285 bytes +stdout: 3306 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -50472,6 +50541,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -50580,12 +50650,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 2870 +size: 2891 location: src/tests/client/test-client.py:test_004()/831 cmd: $NMCLI --mode multiline --terse -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 2703 bytes +stdout: 2724 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -50617,6 +50687,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -50704,12 +50775,12 @@ proxy.pac-url: proxy.pac-script: <<< -size: 2880 +size: 2901 location: src/tests/client/test-client.py:test_004()/832 cmd: $NMCLI --mode multiline --terse -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 2703 bytes +stdout: 2724 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -50741,6 +50812,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -53948,12 +54020,12 @@ connection.type:802-11-wireless connection.interface-name: <<< -size: 3457 +size: 3478 location: src/tests/client/test-client.py:test_004()/877 cmd: $NMCLI --mode multiline --terse --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 3285 bytes +stdout: 3306 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -53985,6 +54057,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -54093,12 +54166,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 3467 +size: 3488 location: src/tests/client/test-client.py:test_004()/878 cmd: $NMCLI --mode multiline --terse --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 3285 bytes +stdout: 3306 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -54130,6 +54203,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -54238,12 +54312,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 3457 +size: 3478 location: src/tests/client/test-client.py:test_004()/879 cmd: $NMCLI --mode multiline --terse --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 3285 bytes +stdout: 3306 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -54275,6 +54349,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -54383,12 +54458,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 3467 +size: 3488 location: src/tests/client/test-client.py:test_004()/880 cmd: $NMCLI --mode multiline --terse --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 3285 bytes +stdout: 3306 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -54420,6 +54495,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -54528,12 +54604,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 2882 +size: 2903 location: src/tests/client/test-client.py:test_004()/881 cmd: $NMCLI --mode multiline --terse --color yes -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 2703 bytes +stdout: 2724 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -54565,6 +54641,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 @@ -54652,12 +54729,12 @@ proxy.pac-url: proxy.pac-script: <<< -size: 2892 +size: 2913 location: src/tests/client/test-client.py:test_004()/882 cmd: $NMCLI --mode multiline --terse --color yes -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 2703 bytes +stdout: 2724 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -54689,6 +54766,7 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.dnssec:-1 connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 connection.wait-activation-delay:-1 diff --git a/src/tests/client/test-client.py b/src/tests/client/test-client.py index 80080056..6cf1924c 100755 --- a/src/tests/client/test-client.py +++ b/src/tests/client/test-client.py @@ -97,8 +97,6 @@ ENV_NM_TEST_UBSAN_OPTIONS = "NM_TEST_UBSAN_OPTIONS" # Valgrind is always disabled, if NM_TEST_REGENERATE is enabled. ENV_NM_TEST_VALGRIND = "NM_TEST_VALGRIND" -ENV_LIBTOOL = "LIBTOOL" - ############################################################################### import collections @@ -678,9 +676,6 @@ class Util: "--log-file=" + valgrind_log[1], cmd, ] - libtool = conf.get(ENV_LIBTOOL) - if libtool: - argv = list(libtool) + ["--mode=execute"] + argv else: argv = [cmd] @@ -693,7 +688,17 @@ class Util: micro = ver & 0xFF minor = (ver >> 8) & 0xFF major = ver >> 16 - return "%s.%s.%s" % (major, minor, micro) + + # Convert 1.57.1 -> 1.57.1-dev and 1.55.90 -> 1.56-rc1 + if micro >= 90: + minor += 1 + micro = "-rc" + str(micro - 89) + elif minor % 2 == 1: + micro = f".{micro}-dev" + else: + micro = f".{micro}" + + return "%s.%s%s" % (major, minor, micro) ############################################################################### @@ -784,21 +789,6 @@ class Configuration: v = "print_stacktrace=1:halt_on_error=1" else: assert False - elif name == ENV_LIBTOOL: - v = os.environ.get(name, None) - if v is None: - v = os.path.abspath( - os.path.dirname(self.get("ENV_NM_TEST_CLIENT_NMCLI_UNCHECKED_PATH")) - + "/../../libtool" - ) - if not os.path.isfile(v): - v = None - else: - v = [v] - elif not v: - v = None - else: - v = shlex.split(v) else: raise Exception() self._values[name] = v @@ -3284,7 +3274,7 @@ def main(): sys.executable, __file__, "--started-with-dbus-session", - *sys.argv[1:] + *sys.argv[1:], ) except OSError as e: if e.errno != errno.ENOENT: diff --git a/src/tests/client/test-client.sh b/src/tests/client/test-client.sh index dd08e4d8..ac07dd20 100755 --- a/src/tests/client/test-client.sh +++ b/src/tests/client/test-client.sh @@ -72,12 +72,10 @@ fi test -d "$BUILDDIR" || die "BUILDDIR \"$BUILDDIR\" does not exist?" test -d "$SRCDIR" || die "SRCDIR \"$SRCDIR\" does not exist?" -if test -f "$BUILDDIR/src/libnm-client-impl/.libs/libnm.so" ; then - LIBDIR="$BUILDDIR/src/libnm-client-impl/.libs" -elif test -f "$BUILDDIR/src/libnm-client-impl/libnm.so" ; then +if test -f "$BUILDDIR/src/libnm-client-impl/libnm.so" ; then LIBDIR="$BUILDDIR/src/libnm-client-impl" else - die "libnm.so does not exist under expected paths in \"$BUILDDIR/src/libnm-client-impl/{.,.libs}/\"" + die "libnm.so does not exist under expected paths in \"$BUILDDIR/src/libnm-client-impl/\"" fi mkdir -p "$BUILDDIR/src/tests/client/" || die "failure to create build output directory \"$BUILDDIR/src/tests/client/\"" @@ -88,12 +86,6 @@ export GI_TYPELIB_PATH="$BUILDDIR/src/libnm-client-impl${GI_TYPELIB_PATH:+:$GI_T export LD_LIBRARY_PATH="$LIBDIR${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" export NM_TEST_CLIENT_BUILDDIR="$BUILDDIR" -# Run nmcli at least once. With libtool, nmcli is a shell script and with LTO -# this seems to perform some slow setup during the first run. If we do that -# during the test, it will timeout and fail. -"$NM_TEST_CLIENT_NMCLI_PATH" --version &>/dev/null || : -"$NM_TEST_CLIENT_CLOUD_SETUP_PATH" --invalid &>/dev/null || : - # we first collect all the output in "test-client.log" and print it at once # afterwards. The only reason is that when you run with `make -j` that the # test output is grouped together. |