git diff debian/1.52.0-6..debian/1.52.1-1 | filterdiff -x "*/src/tests/*" -x "*/contrib/fedora/*" -x "*src/nm-cloud-setup/*" -x "*/src/core/devices/ovs/*"
diff --git a/NEWS b/NEWS index 1e50ee0cf2..b47b76b865 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,14 @@ +============================================= +NetworkManager-1.52.1 +Overview of changes since NetworkManager-1.52 +============================================= +* Fail early if we cannot get current FEC + (Forward Error Correction) value. +* Allow reapplying ovs-bridge and ovs-port properties. +* When activating a WireGuard connection to an IPv6 endpoint, now + NetworkManager creates firewall rules to ensure that the incoming + packets are not dropped by kernel reverse path filtering. + ============================================= NetworkManager-1.52 Overview of changes since NetworkManager-1.50 diff --git a/config.h.meson b/config.h.meson index e59160dec5..9ae88b26bf 100644 --- a/config.h.meson +++ b/config.h.meson @@ -67,6 +67,9 @@ /* Define to path of iptables binary */ #mesondefine IPTABLES_PATH +/* Define to path of ip6tables binary */ +#mesondefine IP6TABLES_PATH + /* Define to path of nft binary */ #mesondefine NFT_PATH diff --git a/debian/changelog b/debian/changelog index 78613a2474..cbd4bc3e60 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +network-manager (1.52.1-1) unstable; urgency=medium + + * New upstream version 1.52.1 + * Explicitly specify the path for ip6tables + + -- Michael Biebl <bi...@debian.org> Tue, 15 Jul 2025 12:21:02 +0200 + network-manager (1.52.0-6) unstable; urgency=medium [ Lukas Märdian ] diff --git a/debian/rules b/debian/rules index f222c09b28..1279622896 100755 --- a/debian/rules +++ b/debian/rules @@ -22,6 +22,7 @@ override_dh_auto_configure: -Dmodprobe=/usr/sbin/modprobe \ -Ddhcpcd=false \ -Diptables=/usr/sbin/iptables \ + -Dip6tables=/usr/sbin/ip6tables \ -Dnft=/usr/sbin/nft \ -Ddnsmasq=/usr/sbin/dnsmasq \ -Dpolkit_agent_helper_1=/usr/lib/policykit-1/polkit-agent-helper-1 \ diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml index 4652887905..eb8f18e76a 100644 --- a/man/NetworkManager.conf.xml +++ b/man/NetworkManager.conf.xml @@ -1933,7 +1933,7 @@ interface-name:vboxnet*,except:interface-name:vboxnet2 <literal>"uuid:83037490-1d17-4986-a397-01f1db3a7fc2"</literal></para></listitem> </varlistentry> <varlistentry> - <term>id=ID</term> + <term>id:ID</term> <listitem><para>Match the connection by name.</para></listitem> </varlistentry> <varlistentry> diff --git a/meson.build b/meson.build index 52bd072b0c..847f72b556 100644 --- a/meson.build +++ b/meson.build @@ -5,7 +5,7 @@ project( # NOTE: When incrementing version also add corresponding # NM_VERSION_x_y_z macros in # "src/libnm-core-public/nm-version-macros.h.in" - version: '1.52.0', + version: '1.52.1', license: 'GPL2+', default_options: [ 'buildtype=debugoptimized', @@ -723,6 +723,7 @@ default_paths = ['/sbin', '/usr/sbin'] # 0: cmdline option, 1: paths, 2: fallback progs = [['iptables', default_paths, '/usr/sbin/iptables'], + ['ip6tables', default_paths, '/usr/sbin/ip6tables'], ['nft', default_paths, '/usr/sbin/nft'], ['dnsmasq', default_paths, ''], ['modprobe', default_paths, '/sbin/modprobe'] @@ -1125,6 +1126,7 @@ endif output += '\n' output += ' jansson: ' + jansson_msg + '\n' output += ' iptables: ' + config_h.get('IPTABLES_PATH') + '\n' +output += ' ip6tables: ' + config_h.get('IP6TABLES_PATH') + '\n' output += ' nft: ' + config_h.get('NFT_PATH') + '\n' output += ' modprobe: ' + config_h.get('MODPROBE_PATH') + '\n' output += ' modemmanager-1: ' + enable_modem_manager.to_string() + '\n' diff --git a/meson_options.txt b/meson_options.txt index 4bc11aa08b..fe696aaf16 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -6,6 +6,7 @@ option('dbus_conf_dir', type: 'string', value: '', description: 'where D-Bus sys option('kernel_firmware_dir', type: 'string', value: '/lib/firmware', description: 'where kernel firmware directory is (default is /lib/firmware)') option('runtime_dir', type: 'string', value: '', description: 'Directory for transient runtime state [default: LOCALSTATEDIR/run or /run]') option('iptables', type: 'string', value: '', description: 'path to iptables') +option('ip6tables', type: 'string', value: '', description: 'path to ip6tables') option('nft', type: 'string', value: '', description: 'path to nft') option('dnsmasq', type: 'string', value: '', description: 'path to dnsmasq') option('modprobe', type: 'string', value: '', description: 'path to modprobe') diff --git a/src/core/devices/nm-device-6lowpan.c b/src/core/devices/nm-device-6lowpan.c index 3dabcb9bdc..61b1e4eee8 100644 --- a/src/core/devices/nm-device-6lowpan.c +++ b/src/core/devices/nm-device-6lowpan.c @@ -137,14 +137,6 @@ link_changed(NMDevice *device, const NMPlatformLink *pllink) nm_device_parent_set_ifindex(device, parent); } -static gboolean -is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) -{ - if (!nm_device_parent_get_device(device)) - return FALSE; - return NM_DEVICE_CLASS(nm_device_6lowpan_parent_class)->is_available(device, flags); -} - static gboolean complete_connection(NMDevice *device, NMConnection *connection, @@ -237,7 +229,6 @@ nm_device_6lowpan_class_init(NMDevice6LowpanClass *klass) device_class->get_generic_capabilities = get_generic_capabilities; device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; device_class->link_changed = link_changed; - device_class->is_available = is_available; device_class->parent_changed_notify = parent_changed_notify; device_class->update_connection = update_connection; } diff --git a/src/core/devices/nm-device-ipvlan.c b/src/core/devices/nm-device-ipvlan.c index 00a1b57937..abeb82f794 100644 --- a/src/core/devices/nm-device-ipvlan.c +++ b/src/core/devices/nm-device-ipvlan.c @@ -221,16 +221,6 @@ get_generic_capabilities(NMDevice *device) /*****************************************************************************/ -static gboolean -is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) -{ - if (!nm_device_parent_get_device(device)) - return FALSE; - return NM_DEVICE_CLASS(nm_device_ipvlan_parent_class)->is_available(device, flags); -} - -/*****************************************************************************/ - static gboolean check_connection_compatible(NMDevice *device, NMConnection *connection, @@ -376,7 +366,6 @@ nm_device_ipvlan_class_init(NMDeviceIpvlanClass *klass) device_class->check_connection_compatible = check_connection_compatible; device_class->create_and_realize = create_and_realize; device_class->get_generic_capabilities = get_generic_capabilities; - device_class->is_available = is_available; device_class->link_changed = link_changed; device_class->update_connection = update_connection; diff --git a/src/core/devices/nm-device-macsec.c b/src/core/devices/nm-device-macsec.c index 89a0672097..2ff1eeb30a 100644 --- a/src/core/devices/nm-device-macsec.c +++ b/src/core/devices/nm-device-macsec.c @@ -683,14 +683,6 @@ get_generic_capabilities(NMDevice *dev) /******************************************************************/ -static gboolean -is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) -{ - if (!nm_device_parent_get_device(device)) - return FALSE; - return NM_DEVICE_CLASS(nm_device_macsec_parent_class)->is_available(device, flags); -} - static gboolean create_and_realize(NMDevice *device, NMConnection *connection, @@ -903,7 +895,6 @@ nm_device_macsec_class_init(NMDeviceMacsecClass *klass) device_class->deactivate = deactivate; device_class->get_generic_capabilities = get_generic_capabilities; device_class->link_changed = link_changed; - device_class->is_available = is_available; device_class->parent_changed_notify = parent_changed_notify; device_class->state_changed = device_state_changed; device_class->get_configured_mtu = nm_device_get_configured_mtu_wired_parent; diff --git a/src/core/devices/nm-device-macvlan.c b/src/core/devices/nm-device-macvlan.c index 9501e8f15c..c5bcc91ad1 100644 --- a/src/core/devices/nm-device-macvlan.c +++ b/src/core/devices/nm-device-macvlan.c @@ -270,16 +270,6 @@ get_generic_capabilities(NMDevice *device) /*****************************************************************************/ -static gboolean -is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) -{ - if (!nm_device_parent_get_device(device)) - return FALSE; - return NM_DEVICE_CLASS(nm_device_macvlan_parent_class)->is_available(device, flags); -} - -/*****************************************************************************/ - static gboolean check_connection_compatible(NMDevice *device, NMConnection *connection, @@ -508,7 +498,6 @@ nm_device_macvlan_class_init(NMDeviceMacvlanClass *klass) device_class->create_and_realize = create_and_realize; device_class->get_generic_capabilities = get_generic_capabilities; device_class->get_configured_mtu = nm_device_get_configured_mtu_wired_parent; - device_class->is_available = is_available; device_class->link_changed = link_changed; device_class->parent_changed_notify = parent_changed_notify; device_class->update_connection = update_connection; diff --git a/src/core/devices/nm-device-vlan.c b/src/core/devices/nm-device-vlan.c index 59a429ca7f..9d03e33704 100644 --- a/src/core/devices/nm-device-vlan.c +++ b/src/core/devices/nm-device-vlan.c @@ -292,16 +292,6 @@ get_generic_capabilities(NMDevice *device) /*****************************************************************************/ -static gboolean -is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) -{ - if (!nm_device_parent_get_device(device)) - return FALSE; - return NM_DEVICE_CLASS(nm_device_vlan_parent_class)->is_available(device, flags); -} - -/*****************************************************************************/ - static gboolean check_connection_compatible(NMDevice *device, NMConnection *connection, @@ -561,7 +551,6 @@ nm_device_vlan_class_init(NMDeviceVlanClass *klass) device_class->act_stage1_prepare_set_hwaddr_ethernet = TRUE; device_class->act_stage1_prepare = act_stage1_prepare; device_class->get_configured_mtu = nm_device_get_configured_mtu_wired_parent; - device_class->is_available = is_available; device_class->parent_changed_notify = parent_changed_notify; device_class->check_connection_compatible = check_connection_compatible; diff --git a/src/core/devices/nm-device-wireguard.c b/src/core/devices/nm-device-wireguard.c index 4a08192e03..299e3b30e8 100644 --- a/src/core/devices/nm-device-wireguard.c +++ b/src/core/devices/nm-device-wireguard.c @@ -23,6 +23,7 @@ #include "nm-active-connection.h" #include "nm-act-request.h" #include "dns/nm-dns-manager.h" +#include "nm-firewall-utils.h" #define _NMLOG_DEVICE_TYPE NMDeviceWireGuard #include "nm-device-logging.h" @@ -1207,6 +1208,40 @@ skip: *out_allowed_ips_data = g_steal_pointer(&allowed_ips); } +static void +_configure_firewall(NMDeviceWireGuard *self, NMConnection *connection, int addr_family, gboolean up) +{ + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); + const char *ip_iface; + NMSettingIPConfig *ip_config; + + ip_iface = nm_device_get_ip_iface(NM_DEVICE(self)); + + nm_assert(ip_iface); + + switch (addr_family) { + case AF_INET: + if (!priv->auto_default_route_enabled_4) + return; + + ip_config = nm_connection_get_setting_ip4_config(connection); + break; + case AF_INET6: + if (!priv->auto_default_route_enabled_6) + return; + + ip_config = nm_connection_get_setting_ip6_config(connection); + break; + default: + nm_assert_not_reached(); + } + + nm_assert(ip_config); + nm_assert(priv->auto_default_route_fwmark); + + nm_firewall_config_set_wg_rule(ip_iface, ip_config, priv->auto_default_route_fwmark, up); +} + /*****************************************************************************/ static void @@ -1300,6 +1335,18 @@ create_and_realize(NMDevice *device, return TRUE; } +static void +deactivate(NMDevice *device) +{ + NMDeviceWireGuard *self = NM_DEVICE_WIREGUARD(device); + NMConnection *connection = nm_device_get_applied_connection(NM_DEVICE(self)); + + if (connection) { + _configure_firewall(self, connection, AF_INET, FALSE); + _configure_firewall(self, connection, AF_INET6, FALSE); + } +} + /*****************************************************************************/ static void @@ -1768,6 +1815,10 @@ act_stage3_ip_config(NMDevice *device, int addr_family) nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; l3cd = _get_dev2_ip_config(NM_DEVICE_WIREGUARD(device), addr_family); + _configure_firewall(NM_DEVICE_WIREGUARD(device), + nm_device_get_applied_connection(device), + addr_family, + TRUE); nm_device_devip_set_state(device, addr_family, NM_DEVICE_IP_STATE_READY, l3cd); } @@ -1866,6 +1917,10 @@ reapply_connection(NMDevice *device, NMConnection *con_old, NMConnection *con_ne if (state >= NM_DEVICE_STATE_CONFIG) { priv->auto_default_route_refresh = TRUE; + + _configure_firewall(self, con_old, AF_INET, FALSE); + _configure_firewall(self, con_old, AF_INET6, FALSE); + link_config(NM_DEVICE_WIREGUARD(device), "reapply", LINK_CONFIG_MODE_REAPPLY, NULL); } @@ -2018,6 +2073,7 @@ nm_device_wireguard_class_init(NMDeviceWireGuardClass *klass) device_class->state_changed = device_state_changed; device_class->create_and_realize = create_and_realize; + device_class->deactivate = deactivate; device_class->act_stage2_config = act_stage2_config; device_class->act_stage2_config_also_for_external_or_assume = TRUE; device_class->act_stage3_ip_config = act_stage3_ip_config; diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index e310a9c680..2f2f25a5b8 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -603,6 +603,7 @@ typedef struct _NMDevicePrivate { bool is_attached : 1; + bool device_link_carrier_changed_down : 1; bool device_link_changed_down : 1; bool concheck_rp_filter_checked : 1; @@ -2759,22 +2760,23 @@ _ethtool_fec_set(NMDevice *self, g_hash_table_iter_init(&iter, hash); while (g_hash_table_iter_next(&iter, (gpointer *) &name, (gpointer *) &variant)) { - NMEthtoolID ethtool_id = nm_ethtool_id_get_by_name(name); - - if (!nm_ethtool_id_is_fec(ethtool_id)) - continue; - - nm_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_UINT32)); - fec_mode = g_variant_get_uint32(variant); + if (nm_ethtool_id_is_fec(nm_ethtool_id_get_by_name(name))) { + nm_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_UINT32)); + fec_mode = g_variant_get_uint32(variant); + break; + } } - nm_platform_ethtool_get_fec_mode(platform, ethtool_state->ifindex, &old_fec_mode); - /* The NM_SETTING_ETHTOOL_FEC_MODE_NONE is query only value, hence do nothing. */ if (!fec_mode || fec_mode == NM_SETTING_ETHTOOL_FEC_MODE_NONE) { return; } + if (!nm_platform_ethtool_get_fec_mode(platform, ethtool_state->ifindex, &old_fec_mode)) { + _LOGW(LOGD_DEVICE, "ethtool: failure setting FEC %d: cannot get current value", fec_mode); + return; + } + if (!nm_platform_ethtool_set_fec_mode(platform, ethtool_state->ifindex, fec_mode)) _LOGW(LOGD_DEVICE, "ethtool: failure setting FEC %d", fec_mode); else { @@ -7123,6 +7125,9 @@ nm_device_controller_release_port(NMDevice *self, NM_UNMANAGED_IS_PORT, NM_UNMAN_FLAG_OP_FORGET, NM_DEVICE_STATE_REASON_REMOVED); + + /* Once the port is detached, unmanaged-external-down might change */ + _dev_unmanaged_check_external_down(self, FALSE, FALSE); } /*****************************************************************************/ @@ -7558,10 +7563,12 @@ device_link_changed(gpointer user_data) gboolean carrier_was_up; gboolean update_unmanaged_specs = FALSE; gboolean got_hw_addr = FALSE, had_hw_addr; + gboolean carrier_seen_down = priv->device_link_carrier_changed_down; gboolean seen_down = priv->device_link_changed_down; - priv->device_link_changed_id = 0; - priv->device_link_changed_down = FALSE; + priv->device_link_changed_id = 0; + priv->device_link_changed_down = FALSE; + priv->device_link_carrier_changed_down = FALSE; ifindex = nm_device_get_ifindex(self); if (ifindex <= 0) @@ -7712,7 +7719,8 @@ device_link_changed(gpointer user_data) if (priv->state >= NM_DEVICE_STATE_IP_CONFIG && priv->state <= NM_DEVICE_STATE_ACTIVATED && !nm_device_managed_type_is_external(self)) nm_device_l3cfg_commit(self, NM_L3_CFG_COMMIT_TYPE_REAPPLY, FALSE); - + } + if (priv->carrier && (!carrier_was_up || carrier_seen_down)) { /* If the device is active without a carrier (probably because it is * tagged for carrier ignore) ensure that when the carrier appears we * renew DHCP leases and such. @@ -7803,6 +7811,8 @@ link_changed_cb(NMPlatform *platform, priv = NM_DEVICE_GET_PRIVATE(self); if (ifindex == nm_device_get_ifindex(self)) { + if (!(pllink->n_ifi_flags & IFF_LOWER_UP)) + priv->device_link_carrier_changed_down = TRUE; if (!(pllink->n_ifi_flags & IFF_UP)) priv->device_link_changed_down = TRUE; if (!priv->device_link_changed_id) { @@ -8814,6 +8824,9 @@ nm_device_controller_add_port(NMDevice *self, NMDevice *port, gboolean configure } else g_return_val_if_fail(port_priv->controller == self, FALSE); + /* Once the port is attached, unmanaged-external-down might change */ + _dev_unmanaged_check_external_down(self, TRUE, FALSE); + nm_device_queue_recheck_assume(self); nm_device_queue_recheck_assume(port); @@ -13417,6 +13430,8 @@ _dev_ipsharedx_cleanup(NMDevice *self, int addr_family) nm_clear_l3cd(&priv->ipshared_data_4.v4.l3cd); _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_SHARED_4, NULL, FALSE); + } else { + _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_PD_6, NULL, FALSE); } _dev_ipsharedx_set_state(self, addr_family, NM_DEVICE_IP_STATE_NONE); @@ -15085,8 +15100,8 @@ respawn_ping_cb(gpointer user_data) nm_clear_g_source_inst(&ping_op->watch); if (!spawn_ping_for_operation(self, ping_op)) { - cleanup_ping_operation(ping_op); priv->ping_operations = g_list_remove(priv->ping_operations, ping_op); + cleanup_ping_operation(ping_op); if (g_list_length(priv->ping_operations) == 0) { ip_check_pre_up(self); @@ -15129,7 +15144,6 @@ ip_check_ping_watch_cb(GPid pid, int status, gpointer user_data) if (success) { if (ping_op->ping_addresses_require_all) { - cleanup_ping_operation(ping_op); priv->ping_operations = g_list_remove(priv->ping_operations, ping_op); if (g_list_length(priv->ping_operations) == 0) { _LOGD(ping_op->log_domain, @@ -15139,6 +15153,7 @@ ip_check_ping_watch_cb(GPid pid, int status, gpointer user_data) nm_clear_g_source_inst(&priv->ping_timeout); ip_check_pre_up(self); } + cleanup_ping_operation(ping_op); } else { nm_assert(priv->ping_operations); diff --git a/src/core/dns/nm-dns-dnsconfd.c b/src/core/dns/nm-dns-dnsconfd.c index 63b3060f3d..c17fb9cf44 100644 --- a/src/core/dns/nm-dns-dnsconfd.c +++ b/src/core/dns/nm-dns-dnsconfd.c @@ -71,6 +71,15 @@ typedef enum { /*****************************************************************************/ +static void +dnsconfd_change_plugin_state(NMDnsDnsconfd *self, DnsconfdPluginState new_state) +{ + NMDnsDnsconfdPrivate *priv = NM_DNS_DNSCONFD_GET_PRIVATE(self); + + priv->plugin_state = new_state; + _nm_dns_plugin_update_pending_maybe_changed(NM_DNS_PLUGIN(self)); +} + static void dnsconfd_serial_changed(NMDnsDnsconfd *self, guint new_serial) { @@ -78,12 +87,10 @@ dnsconfd_serial_changed(NMDnsDnsconfd *self, guint new_serial) priv->present_configuration_serial = new_serial; if (priv->plugin_state == DNSCONFD_PLUGIN_WAIT_SERIAL && priv->awaited_configuration_serial == new_serial) { - priv->plugin_state = DNSCONFD_PLUGIN_IDLE; + dnsconfd_change_plugin_state(self, DNSCONFD_PLUGIN_IDLE); /* Update finished, serials match */ _LOGT("serials match, update finished"); } - - _nm_dns_plugin_update_pending_maybe_changed(NM_DNS_PLUGIN(self)); } static void @@ -132,6 +139,12 @@ dnsconfd_serial_retrieval_done(GObject *source_object, GAsyncResult *res, gpoint self = user_data; priv = NM_DNS_DNSCONFD_GET_PRIVATE(self); + if (!response) { + _LOGW("dnsconfd serial retrieval failed: %s", error->message); + dnsconfd_change_plugin_state(self, DNSCONFD_PLUGIN_IDLE); + return; + } + nm_clear_g_cancellable(&priv->serial_cancellable); g_variant_get(response, "(v)", &new_serial_variant); @@ -201,8 +214,11 @@ dnsconfd_update_done(GObject *source_object, GAsyncResult *res, gpointer user_da nm_clear_g_cancellable(&priv->update_cancellable); - if (!response) + if (!response) { _LOGW("dnsconfd update failed: %s", error->message); + dnsconfd_change_plugin_state(self, DNSCONFD_PLUGIN_IDLE); + return; + } /* By using &s we will get pointer to char data contained * in variant and thus no freing of dnsconfd_message is required */ @@ -210,8 +226,7 @@ dnsconfd_update_done(GObject *source_object, GAsyncResult *res, gpointer user_da if (!awaited_serial) { _LOGW("dnsconfd refused update: %s", dnsconfd_message); - priv->plugin_state = DNSCONFD_PLUGIN_IDLE; - _nm_dns_plugin_update_pending_maybe_changed(NM_DNS_PLUGIN(self)); + dnsconfd_change_plugin_state(self, DNSCONFD_PLUGIN_IDLE); return; } @@ -220,14 +235,12 @@ dnsconfd_update_done(GObject *source_object, GAsyncResult *res, gpointer user_da if (priv->awaited_configuration_serial == priv->present_configuration_serial) { /* Serials match, update finished */ - priv->plugin_state = DNSCONFD_PLUGIN_IDLE; + dnsconfd_change_plugin_state(self, DNSCONFD_PLUGIN_IDLE); _LOGT("after update serials match"); } else { - priv->plugin_state = DNSCONFD_PLUGIN_WAIT_SERIAL; + dnsconfd_change_plugin_state(self, DNSCONFD_PLUGIN_WAIT_SERIAL); _LOGT("after update serials don't match, waiting"); } - - _nm_dns_plugin_update_pending_maybe_changed(NM_DNS_PLUGIN(self)); } static gboolean @@ -478,8 +491,7 @@ name_owner_changed(NMDnsDnsconfd *self, const char *name_owner) || priv->plugin_state == DNSCONFD_PLUGIN_WAIT_SERIAL) { /* We were waiting for either serial or confirmation of update and name * disappeared, thus we need to retransmit */ - priv->plugin_state = DNSCONFD_PLUGIN_WAIT_CONNECT; - _nm_dns_plugin_update_pending_maybe_changed(NM_DNS_PLUGIN(self)); + dnsconfd_change_plugin_state(self, DNSCONFD_PLUGIN_WAIT_CONNECT); } return; } @@ -490,15 +502,13 @@ name_owner_changed(NMDnsDnsconfd *self, const char *name_owner) if (!subscribe_serial(self)) { /* This means that in time between new name and subscribe serial call * we lost the name again thus wait again */ - priv->plugin_state = DNSCONFD_PLUGIN_WAIT_CONNECT; + dnsconfd_change_plugin_state(self, DNSCONFD_PLUGIN_WAIT_CONNECT); _LOGT("subscription failed, waiting to connect"); } else { - priv->plugin_state = DNSCONFD_PLUGIN_WAIT_UPDATE_DONE; + dnsconfd_change_plugin_state(self, DNSCONFD_PLUGIN_WAIT_UPDATE_DONE); _LOGT("sending update and waiting for its finish"); send_dnsconfd_update(self); } - - _nm_dns_plugin_update_pending_maybe_changed(NM_DNS_PLUGIN(self)); } static void @@ -695,18 +705,16 @@ update(NMDnsPlugin *plugin, /* We need to consider only whether we are connected, because newer update call * overrides the old one */ if (all_connected == CONNECTION_FAIL) { - priv->plugin_state = DNSCONFD_PLUGIN_IDLE; + dnsconfd_change_plugin_state(self, DNSCONFD_PLUGIN_IDLE); _LOGT("failed to connect"); } else if (all_connected == CONNECTION_WAIT) { - priv->plugin_state = DNSCONFD_PLUGIN_WAIT_CONNECT; + dnsconfd_change_plugin_state(self, DNSCONFD_PLUGIN_WAIT_CONNECT); _LOGT("not connected, waiting to connect"); } else { - priv->plugin_state = DNSCONFD_PLUGIN_WAIT_UPDATE_DONE; + dnsconfd_change_plugin_state(self, DNSCONFD_PLUGIN_WAIT_UPDATE_DONE); _LOGT("connected, waiting for update to finish"); } - _nm_dns_plugin_update_pending_maybe_changed(plugin); - if (all_connected == CONNECTION_FAIL) { nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, diff --git a/src/core/nm-bond-manager.c b/src/core/nm-bond-manager.c index 2f7fe36c16..116cb73744 100644 --- a/src/core/nm-bond-manager.c +++ b/src/core/nm-bond-manager.c @@ -882,7 +882,7 @@ nm_bond_manager_send_arp(int bond_ifindex, .sll_protocol = htons(ETH_P_ARP), .sll_ifindex = bond_ifindex, }; - ARPPacket data; + ARPPacket data = {0}; const guint8 *hwaddr; gsize hwaddrlen = 0; nm_auto_close int sockfd = -1; @@ -940,6 +940,7 @@ nm_bond_manager_send_arp(int bond_ifindex, data.op = htons(ARP_OP_GARP); memcpy(data.s_addr, hwaddr, hwaddrlen); memcpy(data.s_hw_addr, hwaddr, hwaddrlen); + memset(data.d_hw_addr, 0xff, ETH_ALEN); for (int i = 0; i < addrs_len; i++) { const in_addr_t tmp_addr = addrs_array[i]; diff --git a/src/core/nm-connectivity.c b/src/core/nm-connectivity.c index 22e6c0d5eb..2aa22331ea 100644 --- a/src/core/nm-connectivity.c +++ b/src/core/nm-connectivity.c @@ -25,6 +25,8 @@ #define HEADER_STATUS_ONLINE "X-NetworkManager-Status: online\r\n" +#define SD_RESOLVED_DNS ((guint64) (1LL << 0)) + /*****************************************************************************/ static NM_UTILS_LOOKUP_STR_DEFINE(_state_to_string, @@ -950,9 +952,6 @@ systemd_resolved_resolve_cb(GObject *object, GAsyncResult *res, gpointer user_da do_curl_request(cb_data, nm_str_buf_get_str(&strbuf_hosts)); } -#endif - -#define SD_RESOLVED_DNS ((guint64) (1LL << 0)) static NMConnectivityState check_platform_config(NMConnectivity *self, @@ -1013,6 +1012,7 @@ check_platform_config(NMConnectivity *self, NM_SET_OUT(reason, NULL); return NM_CONNECTIVITY_UNKNOWN; } +#endif NMConnectivityCheckHandle * nm_connectivity_check_start(NMConnectivity *self, diff --git a/src/core/nm-firewall-utils.c b/src/core/nm-firewall-utils.c index b496061247..60f40228db 100644 --- a/src/core/nm-firewall-utils.c +++ b/src/core/nm-firewall-utils.c @@ -8,6 +8,7 @@ #include "nm-firewall-utils.h" +#include "libnm-core-aux-intern/nm-libnm-core-utils.h" #include "libnm-glib-aux/nm-str-buf.h" #include "libnm-glib-aux/nm-io-utils.h" #include "libnm-platform/nm-platform.h" @@ -127,7 +128,7 @@ _share_iptables_subnet_to_str(char buf[static _SHARE_IPTABLES_SUBNET_TO_STR } static char * -_share_iptables_get_name(gboolean is_iptables_chain, const char *prefix, const char *ip_iface) +_iptables_get_name(gboolean is_iptables_chain, const char *prefix, const char *ip_iface) { NMStrBuf strbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_40, FALSE); gsize ip_iface_len; @@ -179,13 +180,13 @@ _share_iptables_get_name(gboolean is_iptables_chain, const char *prefix, const c /*****************************************************************************/ static gboolean -_share_iptables_call_v(const char *const *argv) +_iptables_call_v(const char *const *argv) { gs_free_error GError *error = NULL; gs_free char *argv_str = NULL; int status; - nm_log_dbg(LOGD_SHARING, "iptables: %s", (argv_str = g_strjoinv(" ", (char **) argv))); + nm_log_dbg(LOGD_FIREWALL, "iptables: %s", (argv_str = g_strjoinv(" ", (char **) argv))); if (!g_spawn_sync("/", (char **) argv, @@ -197,7 +198,7 @@ _share_iptables_call_v(const char *const *argv) NULL, &status, &error)) { - nm_log_warn(LOGD_SHARING, + nm_log_warn(LOGD_FIREWALL, "iptables: error executing command %s: %s", argv[0], error->message); @@ -205,20 +206,24 @@ _share_iptables_call_v(const char *const *argv) } if (!g_spawn_check_exit_status(status, &error)) { - nm_log_warn(LOGD_SHARING, "iptables: command %s failed: %s", argv[0], error->message); + nm_log_warn(LOGD_FIREWALL, "iptables: command %s failed: %s", argv[0], error->message); return FALSE; } return TRUE; } -#define _share_iptables_call(...) \ - _share_iptables_call_v(NM_MAKE_STRV("" IPTABLES_PATH "", "--wait", "2", __VA_ARGS__)) +#define _ipxtables_call(family, ...) \ + _iptables_call_v( \ + NM_MAKE_STRV((family == AF_INET ? "" IPTABLES_PATH "" : "" IP6TABLES_PATH ""), \ + "--wait", \ + "2", \ + __VA_ARGS__)) static gboolean _share_iptables_chain_op(const char *table, const char *chain, const char *op) { - return _share_iptables_call("--table", table, op, chain); + return _ipxtables_call(AF_INET, "--table", table, op, chain); } static gboolean @@ -244,24 +249,25 @@ _share_iptables_set_masquerade_sync(gboolean up, const char *ip_iface, in_addr_t char str_subnet[_SHARE_IPTABLES_SUBNET_TO_STR_LEN]; gs_free char *comment_name = NULL; - comment_name = _share_iptables_get_name(FALSE, "nm-shared", ip_iface); + comment_name = _iptables_get_name(FALSE, "nm-shared", ip_iface); _share_iptables_subnet_to_str(str_subnet, addr, plen); - _share_iptables_call("--table", - "nat", - up ? "--insert" : "--delete", - "POSTROUTING", - "--source", - str_subnet, - "!", - "--destination", - str_subnet, - "--jump", - "MASQUERADE", - "-m", - "comment", - "--comment", - comment_name); + _ipxtables_call(AF_INET, + "--table", + "nat", + up ? "--insert" : "--delete", + "POSTROUTING", + "--source", + str_subnet, + "!", + "--destination", + str_subnet, + "--jump", + "MASQUERADE", + "-m", + "comment", + "--comment", + comment_name); } static void @@ -297,70 +303,76 @@ _share_iptables_set_shared_chains_add(const char *chain_input, _share_iptables_chain_add("filter", chain_input); for (i = 0; i < (int) G_N_ELEMENTS(input_params); i++) { - _share_iptables_call("--table", - "filter", - "--append", - chain_input, - "--protocol", - input_params[i][0], - "--destination-port", - input_params[i][1], - "--jump", - "ACCEPT"); + _ipxtables_call(AF_INET, + "--table", + "filter", + "--append", + chain_input, + "--protocol", + input_params[i][0], + "--destination-port", + input_params[i][1], + "--jump", + "ACCEPT"); } _share_iptables_chain_add("filter", chain_forward); - _share_iptables_call("--table", - "filter", - "--append", - chain_forward, - "--destination", - str_subnet, - "--out-interface", - ip_iface, - "--match", - "state", - "--state", - "ESTABLISHED,RELATED", - "--jump", - "ACCEPT"); - _share_iptables_call("--table", - "filter", - "--append", - chain_forward, - "--source", - str_subnet, - "--in-interface", - ip_iface, - "--jump", - "ACCEPT"); - _share_iptables_call("--table", - "filter", - "--append", - chain_forward, - "--in-interface", - ip_iface, - "--out-interface", - ip_iface, - "--jump", - "ACCEPT"); - _share_iptables_call("--table", - "filter", - "--append", - chain_forward, - "--out-interface", - ip_iface, - "--jump", - "REJECT"); - _share_iptables_call("--table", - "filter", - "--append", - chain_forward, - "--in-interface", - ip_iface, - "--jump", - "REJECT"); + _ipxtables_call(AF_INET, + "--table", + "filter", + "--append", + chain_forward, + "--destination", + str_subnet, + "--out-interface", + ip_iface, + "--match", + "state", + "--state", + "ESTABLISHED,RELATED", + "--jump", + "ACCEPT"); + _ipxtables_call(AF_INET, + "--table", + "filter", + "--append", + chain_forward, + "--source", + str_subnet, + "--in-interface", + ip_iface, + "--jump", + "ACCEPT"); + _ipxtables_call(AF_INET, + "--table", + "filter", + "--append", + chain_forward, + "--in-interface", + ip_iface, + "--out-interface", + ip_iface, + "--jump", + "ACCEPT"); + _ipxtables_call(AF_INET, + "--table", + "filter", + "--append", + chain_forward, + "--out-interface", + ip_iface, + "--jump", + "REJECT"); + _ipxtables_call(AF_INET, + "--table", + "filter", + "--append", + chain_forward, + "--in-interface", + ip_iface, + "--jump", + "REJECT"); } static void @@ -377,36 +389,38 @@ _share_iptables_set_shared_sync(gboolean up, const char *ip_iface, in_addr_t add gs_free char *chain_input = NULL; gs_free char *chain_forward = NULL; - comment_name = _share_iptables_get_name(FALSE, "nm-shared", ip_iface); - chain_input = _share_iptables_get_name(TRUE, "nm-sh-in", ip_iface); - chain_forward = _share_iptables_get_name(TRUE, "nm-sh-fw", ip_iface); + comment_name = _iptables_get_name(FALSE, "nm-shared", ip_iface); + chain_input = _iptables_get_name(TRUE, "nm-sh-in", ip_iface); + chain_forward = _iptables_get_name(TRUE, "nm-sh-fw", ip_iface); if (up) _share_iptables_set_shared_chains_add(chain_input, chain_forward, ip_iface, addr, plen); - _share_iptables_call("--table", - "filter", - up ? "--insert" : "--delete", - "INPUT", - "--in-interface", - ip_iface, - "--jump", - chain_input, - "-m", - "comment", - "--comment", - comment_name); - - _share_iptables_call("--table", - "filter", - up ? "--insert" : "--delete", - "FORWARD", - "--jump", - chain_forward, - "-m", - "comment", - "--comment", - comment_name); + _ipxtables_call(AF_INET, + "--table", + "filter", + up ? "--insert" : "--delete", + "INPUT", + "--in-interface", + ip_iface, + "--jump", + chain_input, + "-m", + "comment", + "--comment", + comment_name); + + _ipxtables_call(AF_INET, + "--table", + "filter", + up ? "--insert" : "--delete", + "FORWARD", + "--jump", + chain_forward, + "-m", + "comment", + "--comment", + comment_name); if (!up) _share_iptables_set_shared_chains_delete(chain_input, chain_forward); @@ -460,19 +474,19 @@ _fw_nft_call_communicate_cb(GObject *source, GAsyncResult *result, gpointer user /* on any error, the process might still be running. We need to abort it in * the background... */ if (!nm_utils_error_is_cancelled(error)) { - nm_log_dbg(LOGD_SHARING, + nm_log_dbg(LOGD_FIREWALL, "firewall: nft[%s]: communication failed: %s. Kill process", call_data->identifier, error->message); } else if (!call_data->timeout_source) { - nm_log_dbg(LOGD_SHARING, - "firewall: ntf[%s]: communication timed out. Kill process", + nm_log_dbg(LOGD_FIREWALL, + "firewall: nft[%s]: communication timed out. Kill process", call_data->identifier); nm_clear_error(&error); nm_utils_error_set(&error, NM_UTILS_ERROR_UNKNOWN, "timeout communicating with nft"); } else { - nm_log_dbg(LOGD_SHARING, - "firewall: ntf[%s]: communication cancelled. Kill process", + nm_log_dbg(LOGD_FIREWALL, + "firewall: nft[%s]: communication cancelled. Kill process", call_data->identifier); } @@ -485,7 +499,7 @@ _fw_nft_call_communicate_cb(GObject *source, GAsyncResult *result, gpointer user nm_g_subprocess_terminate_in_background(call_data->subprocess, 200); } } else if (g_subprocess_get_successful(call_data->subprocess)) { - nm_log_dbg(LOGD_SHARING, "firewall: nft[%s]: command successful", call_data->identifier); + nm_log_dbg(LOGD_FIREWALL, "firewall: nft[%s]: command successful", call_data->identifier); } else { char buf[NM_UTILS_GET_PROCESS_EXIT_STATUS_BUF_LEN]; gs_free char *ss_stdout = NULL; @@ -498,7 +512,7 @@ _fw_nft_call_communicate_cb(GObject *source, GAsyncResult *result, gpointer user nm_utils_get_process_exit_status_desc_buf(status, buf, sizeof(buf)); - nm_log_warn(LOGD_SHARING, + nm_log_warn(LOGD_FIREWALL, "firewall: nft[%s]: command %s:%s%s%s%s%s%s%s", call_data->identifier, buf, @@ -534,7 +548,7 @@ _fw_nft_call_cancelled_cb(GCancellable *cancellable, gpointer user_data) if (call_data->cancellable_id == 0) return; - nm_log_dbg(LOGD_SHARING, "firewall: nft[%s]: operation cancelled", call_data->identifier); + nm_log_dbg(LOGD_FIREWALL, "firewall: nft[%s]: operation cancelled", call_data->identifier); nm_clear_g_signal_handler(g_task_get_cancellable(call_data->task), &call_data->cancellable_id); nm_clear_g_cancellable(&call_data->intern_cancellable); @@ -546,7 +560,7 @@ _fw_nft_call_timeout_cb(gpointer user_data) FwNftCallData *call_data = user_data; nm_clear_g_source_inst(&call_data->timeout_source); - nm_log_dbg(LOGD_SHARING, + nm_log_dbg(LOGD_FIREWALL, "firewall: nft[%s]: cancel operation after timeout", call_data->identifier); @@ -573,7 +587,7 @@ nm_firewall_nft_call(GBytes *stdin_buf, .timeout_source = NULL, }; - nm_log_trace(LOGD_SHARING, + nm_log_trace(LOGD_FIREWALL, "firewall: nft: call command: [ '%s' ]", nm_utils_buf_utf8safe_escape_bytes(stdin_buf, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, @@ -585,7 +599,7 @@ nm_firewall_nft_call(GBytes *stdin_buf, call_data, NULL); if (call_data->cancellable_id == 0) { - nm_log_dbg(LOGD_SHARING, "firewall: nft: already cancelled"); + nm_log_dbg(LOGD_FIREWALL, "firewall: nft: already cancelled"); nm_utils_error_set_cancelled(&error, FALSE, NULL); _fw_nft_call_data_free(call_data, g_steal_pointer(&error)); return; @@ -602,14 +616,14 @@ nm_firewall_nft_call(GBytes *stdin_buf, &error); if (!call_data->subprocess) { - nm_log_dbg(LOGD_SHARING, "firewall: nft: spawning nft failed: %s", error->message); + nm_log_dbg(LOGD_FIREWALL, "firewall: nft: spawning nft failed: %s", error->message); _fw_nft_call_data_free(call_data, g_steal_pointer(&error)); return; } call_data->identifier = g_strdup(g_subprocess_get_identifier(call_data->subprocess)); - nm_log_dbg(LOGD_SHARING, "firewall: nft[%s]: communicate with nft", call_data->identifier); + nm_log_dbg(LOGD_FIREWALL, "firewall: nft[%s]: communicate with nft", call_data->identifier); nm_shutdown_wait_obj_register_object(call_data->task, "nft-call"); @@ -691,7 +705,7 @@ _fw_nft_set_shared_construct(gboolean up, const char *ip_iface, in_addr_t addr, gs_free char *table_name = NULL; char str_subnet[_SHARE_IPTABLES_SUBNET_TO_STR_LEN]; - table_name = _share_iptables_get_name(FALSE, "nm-shared", ip_iface); + table_name = _iptables_get_name(FALSE, "nm-shared", ip_iface); _share_iptables_subnet_to_str(str_subnet, addr, plen); @@ -756,6 +770,141 @@ _fw_nft_set_shared_construct(gboolean up, const char *ip_iface, in_addr_t addr, return nm_str_buf_finalize_to_gbytes(&strbuf); } +static GBytes * +_fw_nft_wg_default_construct(const char *ip_iface, + NMSettingIPConfig *ip_config, + int fwmark, + gboolean up) +{ + nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE); + gs_free char *table_name = NULL; + const char *family_str; + + table_name = _iptables_get_name(FALSE, "nm-wg", ip_iface); + family_str = nm_setting_ip_config_get_addr_family(ip_config) == AF_INET ? "ip" : "ip6"; + + _fw_nft_append_cmd_table(&strbuf, family_str, table_name, up); + + if (up) { + guint n_addresses = nm_setting_ip_config_get_num_addresses(ip_config); + + if (n_addresses) { + _append(&strbuf, "add chain %s %s preraw {", family_str, table_name); + + for (guint i = 0; i < n_addresses; i++) { + NMIPAddress *addr = nm_setting_ip_config_get_address(ip_config, i); + + _append(&strbuf, + " iifname != \"%s\" " + " %s daddr %s " + " fib saddr type != local " + "drop;", + ip_iface, + family_str, + nm_ip_address_get_address(addr)); + } + + _append(&strbuf, "};"); + } + + _append(&strbuf, + "add chain %s %s premangle {" + " type filter hook prerouting priority mangle; policy accept; " + " meta l4proto udp meta mark set ct mark; " + "};", + family_str, + table_name); + + _append(&strbuf, + "add chain %s %s postmangle {" + " type filter hook postrouting priority mangle; policy accept; " + " meta l4proto udp mark 0x%08x ct mark set meta mark; " + "};", + family_str, + table_name, + fwmark); + } + + return nm_str_buf_finalize_to_gbytes(&strbuf); +} + +static void +_fw_iptables_wg_configure(const char *ip_iface, + NMSettingIPConfig *ip_config, + int fwmark, + gboolean up) +{ + gs_free char *comment_name = NULL; + char fwmark_str[11]; + int family = nm_setting_ip_config_get_addr_family(ip_config); + guint n_addresses = nm_setting_ip_config_get_num_addresses(ip_config); + + comment_name = _iptables_get_name(FALSE, "nm-wg", ip_iface); + g_snprintf(fwmark_str, sizeof(fwmark_str), "%" G_GUINT32_FORMAT, fwmark); + + nm_assert(strlen(fwmark_str) > 0); + + for (guint i = 0; i < n_addresses; i++) { + NMIPAddress *addr = nm_setting_ip_config_get_address(ip_config, i); + + _ipxtables_call(family, + "--table", + "raw", + up ? "--insert" : "--delete", + "PREROUTING", + "!", + "--in-interface", + ip_iface, + "--destination", + nm_ip_address_get_address(addr), + "--match", + "addrtype", + "!", + "--src-type", + "LOCAL", + "-j", + "DROP", + "-m", + "comment", + "--comment", + comment_name); + } + + _ipxtables_call(family, + "--table", + "mangle", + up ? "--insert" : "--delete", + "POSTROUTING", + "--match", + "mark", + "--mark", + fwmark_str, + "--protocol", + "udp", + "--jump", + "CONNMARK", + "--save-mark", + "-m", + "comment", + "--comment", + comment_name); + + _ipxtables_call(family, + "--table", + "mangle", + up ? "--insert" : "--delete", + "PREROUTING", + "--protocol", + "udp", + "--jump", + "CONNMARK", + "--restore-mark", + "-m", + "comment", + "--comment", + comment_name); +} + /*****************************************************************************/ GBytes * @@ -1046,6 +1195,31 @@ nm_firewall_config_free(NMFirewallConfig *self) } /*****************************************************************************/ +void +nm_firewall_config_set_wg_rule(const char *ifname, + NMSettingIPConfig *ip_config, + int fwmark, + gboolean up) +{ + switch (nm_firewall_utils_get_backend()) { + case NM_FIREWALL_BACKEND_NFTABLES: + { + gs_unref_bytes GBytes *stdin_buf = NULL; + + stdin_buf = _fw_nft_wg_default_construct(ifname, ip_config, fwmark, up); + _fw_nft_call_sync(stdin_buf, NULL); + break; + } + case NM_FIREWALL_BACKEND_IPTABLES: + _fw_iptables_wg_configure(ifname, ip_config, fwmark, up); + break; + case NM_FIREWALL_BACKEND_NONE: + break; + default: + nm_assert_not_reached(); + break; + } +} void nm_firewall_config_apply_sync(NMFirewallConfig *self, gboolean up) @@ -1124,7 +1298,7 @@ again: if (!g_atomic_int_compare_and_exchange(&backend, NM_FIREWALL_BACKEND_UNKNOWN, b)) goto again; - nm_log_dbg(LOGD_SHARING, + nm_log_dbg(LOGD_FIREWALL, "firewall: use %s backend%s%s%s%s%s%s%s", FirewallBackends[b - 1].name, NM_PRINT_FMT_QUOTED(FirewallBackends[b - 1].path, diff --git a/src/core/nm-firewall-utils.h b/src/core/nm-firewall-utils.h index 9f13a5127e..4df33d11db 100644 --- a/src/core/nm-firewall-utils.h +++ b/src/core/nm-firewall-utils.h @@ -24,6 +24,11 @@ NMFirewallConfig *nm_firewall_config_new_shared(const char *ip_iface, in_addr_t void nm_firewall_config_free(NMFirewallConfig *self); +void nm_firewall_config_set_wg_rule(const char *ifname, + NMSettingIPConfig *ip_config, + int fwmark, + gboolean up); + void nm_firewall_config_apply_sync(NMFirewallConfig *self, gboolean up); /*****************************************************************************/ diff --git a/src/core/nm-ip-config.c b/src/core/nm-ip-config.c index eb0ec9aa03..975ae20d45 100644 --- a/src/core/nm-ip-config.c +++ b/src/core/nm-ip-config.c @@ -826,7 +826,7 @@ _handle_l3cd_changed(NMIPConfig *self, const NML3ConfigData *l3cd) if (v_i != v_i_old) changed_params[n_changed_params++] = obj_properties_ip[PROP_IP_DNS_PRIORITY]; - strarr_old = nm_l3_config_data_get_dns_options(l3cd_old, addr_family, &len); + strarr_old = nm_l3_config_data_get_dns_options(l3cd_old, addr_family, &len_old); strarr = nm_l3_config_data_get_dns_options(priv->l3cd, addr_family, &len); if (!nm_strv_equal_n(strarr, len, strarr_old, len_old)) changed_params[n_changed_params++] = obj_properties_ip[PROP_IP_DNS_OPTIONS]; diff --git a/src/core/tests/test-core.c b/src/core/tests/test-core.c index 2ff41f0067..e08296c20f 100644 --- a/src/core/tests/test-core.c +++ b/src/core/tests/test-core.c @@ -36,6 +36,7 @@ test_config_h(void) G_STMT_END ABSOLUTE_PATH(IPTABLES_PATH); + ABSOLUTE_PATH(IP6TABLES_PATH); ABSOLUTE_PATH(NFT_PATH); } diff --git a/src/core/vpn/nm-vpn-connection.c b/src/core/vpn/nm-vpn-connection.c index d0607160cd..22364ef9dc 100644 --- a/src/core/vpn/nm-vpn-connection.c +++ b/src/core/vpn/nm-vpn-connection.c @@ -1899,7 +1899,7 @@ _dbus_signal_config_cb(NMVpnConnection *self, GVariant *dict) _LOGD("config: reply received (IPv4:%s(%s), IPv6:%s(%s))", priv->ip_data_4.enabled ? "on" : "off", priv->ip_data_4.method_auto ? "auto" : "disabled", - priv->ip_data_4.enabled ? "on" : "off", + priv->ip_data_6.enabled ? "on" : "off", priv->ip_data_6.method_auto ? "auto" : "disabled"); if (!priv->ip_data_4.method_auto) diff --git a/src/libnm-client-impl/nm-ip-config.c b/src/libnm-client-impl/nm-ip-config.c index ad5f08f814..ef3dcca1a5 100644 --- a/src/libnm-client-impl/nm-ip-config.c +++ b/src/libnm-client-impl/nm-ip-config.c @@ -180,6 +180,7 @@ _notify_update_prop_nameservers(NMClient *client, goto next; nameserver = g_steal_pointer(&val_str); } else if (nm_streq(key, "uri")) { + g_free(nameserver); nameserver = g_variant_dup_string(val, NULL); } next: diff --git a/src/libnm-client-public/nm-secret-agent-old.h b/src/libnm-client-public/nm-secret-agent-old.h index ca7bfa4cc9..6cf94a6d51 100644 --- a/src/libnm-client-public/nm-secret-agent-old.h +++ b/src/libnm-client-public/nm-secret-agent-old.h @@ -39,13 +39,13 @@ typedef struct { * note that this object will be unrefed after the callback has returned, use * g_object_ref()/g_object_unref() if you want to use this object after the callback * has returned - * @secrets: the #GVariant of type %NM_VARIANT_TYPE_CONNECTION containing the requested + * @secrets: (nullable): the #GVariant of type %NM_VARIANT_TYPE_CONNECTION containing the requested * secrets (as created by nm_connection_to_dbus() for example). Each key in @secrets * should be the name of a #NMSetting object (like "802-11-wireless-security") * and each value should be an %NM_VARIANT_TYPE_SETTING variant. The sub-dicts * map string:value, where the string is the setting property name (like "psk") * and the value is the secret - * @error: if the secrets request failed, give a descriptive error here + * @error: (nullable): if the secrets request failed, give a descriptive error here * @user_data: caller-specific data to be passed to the function * * Called as a result of a request by NM to retrieve secrets. When the @@ -90,7 +90,7 @@ typedef void (*NMSecretAgentOldGetSecretsFunc)(NMSecretAgentOld *agent, * note that this object will be unrefed after the callback has returned, use * g_object_ref()/g_object_unref() if you want to use this object after the callback * has returned - * @error: if the saving secrets failed, give a descriptive error here + * @error: (nullable): if the saving secrets failed, give a descriptive error here * @user_data: caller-specific data to be passed to the function * * Called as a result of a request by NM to save secrets. When the @@ -109,7 +109,7 @@ typedef void (*NMSecretAgentOldSaveSecretsFunc)(NMSecretAgentOld *agent, * note that this object will be unrefed after the callback has returned, use * g_object_ref()/g_object_unref() if you want to use this object after the callback * has returned - * @error: if the deleting secrets failed, give a descriptive error here + * @error: (nullable): if the deleting secrets failed, give a descriptive error here * @user_data: caller-specific data to be passed to the function * * Called as a result of a request by NM to delete secrets. When the diff --git a/src/libnm-core-impl/nm-meta-setting-base-impl.c b/src/libnm-core-impl/nm-meta-setting-base-impl.c index 37cb61f176..b9dcf34f61 100644 --- a/src/libnm-core-impl/nm-meta-setting-base-impl.c +++ b/src/libnm-core-impl/nm-meta-setting-base-impl.c @@ -431,7 +431,7 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = { [NM_META_SETTING_TYPE_OVS_DPDK] = { .meta_type = NM_META_SETTING_TYPE_OVS_DPDK, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_priority = NM_SETTING_PRIORITY_AUX, .setting_name = NM_SETTING_OVS_DPDK_SETTING_NAME, .get_setting_gtype = nm_setting_ovs_dpdk_get_type, }, @@ -459,7 +459,7 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = { [NM_META_SETTING_TYPE_OVS_PATCH] = { .meta_type = NM_META_SETTING_TYPE_OVS_PATCH, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_priority = NM_SETTING_PRIORITY_AUX, .setting_name = NM_SETTING_OVS_PATCH_SETTING_NAME, .get_setting_gtype = nm_setting_ovs_patch_get_type, }, @@ -656,9 +656,7 @@ const NMMetaSettingType nm_meta_setting_types_by_priority[] = { NM_META_SETTING_TYPE_MACSEC, NM_META_SETTING_TYPE_MACVLAN, NM_META_SETTING_TYPE_OVS_BRIDGE, - NM_META_SETTING_TYPE_OVS_DPDK, NM_META_SETTING_TYPE_OVS_INTERFACE, - NM_META_SETTING_TYPE_OVS_PATCH, NM_META_SETTING_TYPE_OVS_PORT, NM_META_SETTING_TYPE_TEAM, NM_META_SETTING_TYPE_TUN, @@ -688,8 +686,10 @@ const NMMetaSettingType nm_meta_setting_types_by_priority[] = { NM_META_SETTING_TYPE_ETHTOOL, NM_META_SETTING_TYPE_LINK, NM_META_SETTING_TYPE_MATCH, + NM_META_SETTING_TYPE_OVS_DPDK, NM_META_SETTING_TYPE_OVS_EXTERNAL_IDS, NM_META_SETTING_TYPE_OVS_OTHER_CONFIG, + NM_META_SETTING_TYPE_OVS_PATCH, NM_META_SETTING_TYPE_PPP, NM_META_SETTING_TYPE_PPPOE, NM_META_SETTING_TYPE_TEAM_PORT, diff --git a/src/libnm-core-impl/nm-setting-macvlan.c b/src/libnm-core-impl/nm-setting-macvlan.c index 2adecdfe6c..41d41a539a 100644 --- a/src/libnm-core-impl/nm-setting-macvlan.c +++ b/src/libnm-core-impl/nm-setting-macvlan.c @@ -251,7 +251,7 @@ nm_setting_macvlan_class_init(NMSettingMacvlanClass *klass) /** * NMSettingMacvlan:promiscuous: * - * Whether the interface should be put in promiscuous mode. + * Whether the parent interface should be put in promiscuous mode (true by default). * * Since: 1.2 **/ diff --git a/src/libnmc-setting/nm-meta-setting-base-impl.c b/src/libnmc-setting/nm-meta-setting-base-impl.c index 37cb61f176..b9dcf34f61 100644 --- a/src/libnmc-setting/nm-meta-setting-base-impl.c +++ b/src/libnmc-setting/nm-meta-setting-base-impl.c @@ -431,7 +431,7 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = { [NM_META_SETTING_TYPE_OVS_DPDK] = { .meta_type = NM_META_SETTING_TYPE_OVS_DPDK, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_priority = NM_SETTING_PRIORITY_AUX, .setting_name = NM_SETTING_OVS_DPDK_SETTING_NAME, .get_setting_gtype = nm_setting_ovs_dpdk_get_type, }, @@ -459,7 +459,7 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = { [NM_META_SETTING_TYPE_OVS_PATCH] = { .meta_type = NM_META_SETTING_TYPE_OVS_PATCH, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_priority = NM_SETTING_PRIORITY_AUX, .setting_name = NM_SETTING_OVS_PATCH_SETTING_NAME, .get_setting_gtype = nm_setting_ovs_patch_get_type, }, @@ -656,9 +656,7 @@ const NMMetaSettingType nm_meta_setting_types_by_priority[] = { NM_META_SETTING_TYPE_MACSEC, NM_META_SETTING_TYPE_MACVLAN, NM_META_SETTING_TYPE_OVS_BRIDGE, - NM_META_SETTING_TYPE_OVS_DPDK, NM_META_SETTING_TYPE_OVS_INTERFACE, - NM_META_SETTING_TYPE_OVS_PATCH, NM_META_SETTING_TYPE_OVS_PORT, NM_META_SETTING_TYPE_TEAM, NM_META_SETTING_TYPE_TUN, @@ -688,8 +686,10 @@ const NMMetaSettingType nm_meta_setting_types_by_priority[] = { NM_META_SETTING_TYPE_ETHTOOL, NM_META_SETTING_TYPE_LINK, NM_META_SETTING_TYPE_MATCH, + NM_META_SETTING_TYPE_OVS_DPDK, NM_META_SETTING_TYPE_OVS_EXTERNAL_IDS, NM_META_SETTING_TYPE_OVS_OTHER_CONFIG, + NM_META_SETTING_TYPE_OVS_PATCH, NM_META_SETTING_TYPE_PPP, NM_META_SETTING_TYPE_PPPOE, NM_META_SETTING_TYPE_TEAM_PORT, diff --git a/src/libnmc-setting/nm-meta-setting-desc.c b/src/libnmc-setting/nm-meta-setting-desc.c index e35db06eca..fcb2d041d2 100644 --- a/src/libnmc-setting/nm-meta-setting-desc.c +++ b/src/libnmc-setting/nm-meta-setting-desc.c @@ -9133,12 +9133,7 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = { NM_META_SETTING_VALID_PART_ITEM (WIRED, FALSE), ), ), - SETTING_INFO (OVS_DPDK, - .valid_parts = NM_META_SETTING_VALID_PARTS ( - NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), - NM_META_SETTING_VALID_PART_ITEM (OVS_DPDK, TRUE), - ), - ), + SETTING_INFO (OVS_DPDK), SETTING_INFO_EMPTY (OVS_OTHER_CONFIG), SETTING_INFO_EMPTY (OVS_EXTERNAL_IDS), SETTING_INFO (OVS_INTERFACE, @@ -9153,12 +9148,7 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = { NM_META_SETTING_VALID_PART_ITEM (ETHTOOL, FALSE), ), ), - SETTING_INFO (OVS_PATCH, - .valid_parts = NM_META_SETTING_VALID_PARTS ( - NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), - NM_META_SETTING_VALID_PART_ITEM (OVS_PATCH, TRUE), - ), - ), + SETTING_INFO (OVS_PATCH), SETTING_INFO (OVS_PORT, .valid_parts = NM_META_SETTING_VALID_PARTS ( NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), diff --git a/src/libnmc-setting/settings-docs.h.in b/src/libnmc-setting/settings-docs.h.in index dd719afad6..3bae49b8b5 100644 --- a/src/libnmc-setting/settings-docs.h.in +++ b/src/libnmc-setting/settings-docs.h.in @@ -286,7 +286,7 @@ #define DESCRIBE_DOC_NM_SETTING_MACSEC_VALIDATION N_("Specifies the validation mode for incoming frames.") #define DESCRIBE_DOC_NM_SETTING_MACVLAN_MODE N_("The macvlan mode, which specifies the communication mechanism between multiple macvlans on the same lower device.") #define DESCRIBE_DOC_NM_SETTING_MACVLAN_PARENT N_("If given, specifies the parent interface name or parent connection UUID from which this MAC-VLAN interface should be created. If this property is not specified, the connection must contain an \"802-3-ethernet\" setting with a \"mac-address\" property.") -#define DESCRIBE_DOC_NM_SETTING_MACVLAN_PROMISCUOUS N_("Whether the interface should be put in promiscuous mode.") +#define DESCRIBE_DOC_NM_SETTING_MACVLAN_PROMISCUOUS N_("Whether the parent interface should be put in promiscuous mode (true by default).") #define DESCRIBE_DOC_NM_SETTING_MACVLAN_TAP N_("Whether the interface should be a MACVTAP.") #define DESCRIBE_DOC_NM_SETTING_MATCH_DRIVER N_("A list of driver names to match. Each element is a shell wildcard pattern. See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the pattern.") #define DESCRIBE_DOC_NM_SETTING_MATCH_INTERFACE_NAME N_("A list of interface names to match. Each element is a shell wildcard pattern. An element can be prefixed with a pipe symbol (|) or an ampersand (&). The former means that the element is optional and the latter means that it is mandatory. If there are any optional elements, than the match evaluates to true if at least one of the optional element matches (logical OR). If there are any mandatory elements, then they all must match (logical AND). By default, an element is optional. This means that an element \"foo\" behaves the same as \"|foo\". An element can also be inverted with exclamation mark (!) between the pipe symbol (or the ampersand) and before the pattern. Note that \"!foo\" is a shortcut for the mandatory match \"&!foo\". Finally, a backslash can be used at the beginning of the element (after the optional special characters) to escape the start of the pattern. For example, \"&\\!a\" is an mandatory match for literally \"!a\".") diff --git a/src/n-dhcp4/src/n-dhcp4-c-probe.c b/src/n-dhcp4/src/n-dhcp4-c-probe.c index 7a6def340c..58d61e72ba 100644 --- a/src/n-dhcp4/src/n-dhcp4-c-probe.c +++ b/src/n-dhcp4/src/n-dhcp4-c-probe.c @@ -1140,8 +1140,6 @@ int n_dhcp4_client_probe_transition_decline(NDhcp4ClientProbe *probe, NDhcp4Inco r = n_dhcp4_c_connection_send_request(&probe->connection, request, ns_now); if (r) return r; - else - request = NULL; /* consumed */ n_dhcp4_client_lease_unlink(probe->current_lease); probe->current_lease = n_dhcp4_client_lease_unref(probe->current_lease); @@ -1346,7 +1344,6 @@ int n_dhcp4_client_probe_release(NDhcp4ClientProbe *probe) { probe->state = N_DHCP4_CLIENT_PROBE_STATE_INIT; n_dhcp4_client_lease_unlink(probe->current_lease); - request_out = NULL; return 0; } diff --git a/src/nm-initrd-generator/nmi-cmdline-reader.c b/src/nm-initrd-generator/nmi-cmdline-reader.c index d6dc1fcb7c..5389748d82 100644 --- a/src/nm-initrd-generator/nmi-cmdline-reader.c +++ b/src/nm-initrd-generator/nmi-cmdline-reader.c @@ -299,33 +299,44 @@ get_word(char **argument, const char separator) { char *word; int nest = 0; + char *last_ch; + char *first_close = NULL; if (*argument == NULL) return NULL; - if (**argument == '[') { - nest++; - (*argument)++; - } - - word = *argument; + word = last_ch = *argument; while (**argument != '\0') { - if (nest && **argument == ']') { - **argument = '\0'; - (*argument)++; - nest--; - continue; - } - if (nest == 0 && **argument == separator) { **argument = '\0'; (*argument)++; break; } + if (**argument == '[') { + nest++; + } else if (nest && **argument == ']') { + nest--; + if (!first_close && nest == 0) + first_close = *argument; + } + + last_ch = *argument; (*argument)++; } + /* If the word is surrounded with the nesting symbols [], strip them so we return + * the inner content only. + * If there were nesting symbols but embracing only part of the inner content, don't + * remove them. Example: + * Remove [] in get_word("[fc08::1]:other_token", ":") + * Don't remove [] in get_word("ip6=[fc08::1]:other_token", ":") + */ + if (*word == '[' && *last_ch == ']' && last_ch == first_close) { + word++; + *last_ch = '\0'; + } + return *word ? word : NULL; } @@ -533,7 +544,7 @@ reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument) NMSettingConnection *s_con; NMSettingIPConfig *s_ip4 = NULL, *s_ip6 = NULL; gs_unref_hashtable GHashTable *ibft = NULL; - const char *tmp; + char *tmp; const char *tmp2; const char *tmp3; const char *kind; @@ -578,15 +589,25 @@ reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument) kind = tmp3; } else { /* <client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<kind> */ - client_ip = tmp; + + /* note: split here address and prefix to normalize IPs defined as + * [dead::beef]/64. Latter parsing would fail due to the '[]'. */ + client_ip = get_word(&tmp, '/'); + if (client_ip) { - client_ip_family = get_ip_address_family(client_ip, TRUE); + client_ip_family = get_ip_address_family(client_ip, FALSE); if (client_ip_family == AF_UNSPEC) { _LOGW(LOGD_CORE, "Invalid IP address '%s'.", client_ip); return; } } + if (!nm_str_is_empty(tmp)) { + gboolean is_ipv4 = client_ip_family == AF_INET; + + client_ip_prefix = _nm_utils_ascii_str_to_int64(tmp, 10, 0, is_ipv4 ? 32 : 128, -1); + } + peer = tmp2; gateway_ip = get_word(&argument, ':'); netmask = get_word(&argument, ':'); @@ -661,11 +682,7 @@ reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument) NMIPAddress *address = NULL; NMIPAddr addr; - if (nm_inet_parse_with_prefix_bin(client_ip_family, - client_ip, - NULL, - &addr, - client_ip_prefix == -1 ? &client_ip_prefix : NULL)) { + if (nm_inet_parse_bin(client_ip_family, client_ip, NULL, &addr)) { if (client_ip_prefix == -1) { switch (client_ip_family) { case AF_INET: @@ -905,14 +922,25 @@ reader_parse_controller(Reader *reader, opts = get_word(&argument, ':'); while (opts && *opts) { - gs_free_error GError *error = NULL; - char *opt; - const char *opt_name; - + gs_free_error GError *error = NULL; + char *tmp; + const char *opt_name; + char *opt; + const char *opt_value; + nm_auto_unref_ptrarray GPtrArray *opt_values = g_ptr_array_new(); + gs_free char *opt_normalized = NULL; + + opt_name = get_word(&opts, '='); opt = get_word(&opts, ','); - opt_name = get_word(&opt, '='); - if (!_nm_setting_bond_validate_option(opt_name, opt, &error)) { + /* Normalize: convert ';' to ',' and remove '[]' from IPv6 addresses */ + tmp = opt; + while ((opt_value = get_word(&tmp, ';'))) + g_ptr_array_add(opt_values, (gpointer) opt_value); + g_ptr_array_add(opt_values, NULL); + opt_normalized = g_strjoinv(",", (char **) opt_values->pdata); + + if (!_nm_setting_bond_validate_option(opt_name, opt_normalized, &error)) { _LOGW(LOGD_CORE, "Ignoring invalid bond option: %s%s%s = %s%s%s: %s", NM_PRINT_FMT_QUOTE_STRING(opt_name), @@ -920,7 +948,7 @@ reader_parse_controller(Reader *reader, error->message); continue; } - nm_setting_bond_add_option(s_bond, opt_name, opt); + nm_setting_bond_add_option(s_bond, opt_name, opt_normalized); } mtu = get_word(&argument, ':'); diff --git a/src/nm-initrd-generator/tests/test-cmdline-reader.c b/src/nm-initrd-generator/tests/test-cmdline-reader.c index a0100764ca..cd7b1069b6 100644 --- a/src/nm-initrd-generator/tests/test-cmdline-reader.c +++ b/src/nm-initrd-generator/tests/test-cmdline-reader.c @@ -597,7 +597,7 @@ static void test_if_ip6_manual(void) { gs_unref_hashtable GHashTable *connections = NULL; - const char *const *ARGV = NM_MAKE_STRV("ip=[2001:0db8::02]/64::[2001:0db8::01]::" + const char *const *ARGV = NM_MAKE_STRV("ip=[2001:0db8::02]/56::[2001:0db8::01]::" "hostname0.example.com:eth4::[2001:0db8::53]"); NMConnection *connection; NMSettingIPConfig *s_ip4; @@ -633,7 +633,7 @@ test_if_ip6_manual(void) ip_addr = nm_setting_ip_config_get_address(s_ip6, 0); g_assert(ip_addr); g_assert_cmpstr(nm_ip_address_get_address(ip_addr), ==, "2001:db8::2"); - g_assert_cmpint(nm_ip_address_get_prefix(ip_addr), ==, 64); + g_assert_cmpint(nm_ip_address_get_prefix(ip_addr), ==, 56); g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip6), ==, "2001:db8::1"); g_assert_cmpstr(nm_setting_ip_config_get_dhcp_hostname(s_ip6), ==, NULL); } @@ -975,8 +975,8 @@ static void test_bond(void) { gs_unref_hashtable GHashTable *connections = NULL; - const char *const *ARGV = NM_MAKE_STRV("rd.route=192.0.2.53::bong0", - "bond=bong0:eth0,eth1:mode=balance-rr:9000", + const char *const *ARGV = NM_MAKE_STRV("rd.route=192.0.2.53::bond0", + "bond=bond0:eth0,eth1:mode=balance-rr:9000", "nameserver=203.0.113.53"); NMConnection *connection; NMSettingConnection *s_con; @@ -990,12 +990,12 @@ test_bond(void) connections = _parse_cons(ARGV); g_assert_cmpint(g_hash_table_size(connections), ==, 3); - connection = g_hash_table_lookup(connections, "bong0"); + connection = g_hash_table_lookup(connections, "bond0"); nmtst_assert_connection_verifies_without_normalization(connection); g_assert_cmpstr(nm_connection_get_connection_type(connection), ==, NM_SETTING_BOND_SETTING_NAME); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "bong0"); + g_assert_cmpstr(nm_connection_get_id(connection), ==, "bond0"); controller_uuid = nm_connection_get_uuid(connection); g_assert(controller_uuid); @@ -1162,6 +1162,118 @@ test_bond_ip(void) NM_CONNECTION_MULTI_CONNECT_SINGLE); } +static void +test_bond_ip6_option(void) +{ + /* Test that IPv6 addresses within [] are parsed fine in different positions */ + + gs_unref_hashtable GHashTable *connections = NULL; + const char *const *ARGV = + NM_MAKE_STRV("bond=bond0:eth0,eth1:arp_interval=100,ns_ip6_target=[fc08::1]", + "bond=bond1:eth2,eth3:arp_interval=100,ns_ip6_target=[fc08::1]:9000", + "bond=bond2:eth4,eth5:ns_ip6_target=[fc08::1],arp_interval=100"); + NMConnection *connection; + NMSettingBond *s_bond; + + connections = _parse_cons(ARGV); + g_assert_cmpint(g_hash_table_size(connections), ==, 9); + + connection = g_hash_table_lookup(connections, "bond0"); + nmtst_assert_connection_verifies_without_normalization(connection); + s_bond = nm_connection_get_setting_bond(connection); + g_assert(s_bond); + g_assert_cmpint(nm_setting_bond_get_num_options(s_bond), ==, 3); + g_assert_cmpstr(nm_setting_bond_get_option_by_name(s_bond, "ns_ip6_target"), ==, "fc08::1"); + + connection = g_hash_table_lookup(connections, "bond1"); + nmtst_assert_connection_verifies_without_normalization(connection); + s_bond = nm_connection_get_setting_bond(connection); + g_assert(s_bond); + g_assert_cmpint(nm_setting_bond_get_num_options(s_bond), ==, 3); + g_assert_cmpstr(nm_setting_bond_get_option_by_name(s_bond, "ns_ip6_target"), ==, "fc08::1"); + + connection = g_hash_table_lookup(connections, "bond2"); + nmtst_assert_connection_verifies_without_normalization(connection); + s_bond = nm_connection_get_setting_bond(connection); + g_assert(s_bond); + g_assert_cmpint(nm_setting_bond_get_num_options(s_bond), ==, 3); + g_assert_cmpstr(nm_setting_bond_get_option_by_name(s_bond, "ns_ip6_target"), ==, "fc08::1"); +} + +static void +test_bond_multi_values_option(void) +{ + /* Test that semicolon-separated multi-valued options are parsed fine in different positions */ + + gs_unref_hashtable GHashTable *connections = NULL; + const char *const *ARGV = + NM_MAKE_STRV("bond=bond0:eth0,eth1:arp_interval=100,ns_ip6_target=[fc08::1];[fc08::2]", + "bond=bond1:eth2,eth3:arp_interval=100,ns_ip6_target=[fc08::1];[fc08::2]:9000", + "bond=bond2:eth4,eth5:ns_ip6_target=[fc08::1];[fc08::2],arp_interval=100", + "bond=bond3:eth6,eth7:arp_interval=100,arp_ip_target=10.0.0.1;10.0.0.2", + "bond=bond4:eth8,eth9:arp_interval=100,arp_ip_target=10.0.0.1;10.0.0.2:9000", + "bond=bond5:eth10,eth11:arp_ip_target=10.0.0.1;10.0.0.2,arp_interval=100"); + NMConnection *connection; + NMSettingBond *s_bond; + + connections = _parse_cons(ARGV); + g_assert_cmpint(g_hash_table_size(connections), ==, 18); + + connection = g_hash_table_lookup(connections, "bond0"); + nmtst_assert_connection_verifies_without_normalization(connection); + s_bond = nm_connection_get_setting_bond(connection); + g_assert(s_bond); + g_assert_cmpint(nm_setting_bond_get_num_options(s_bond), ==, 3); + g_assert_cmpstr(nm_setting_bond_get_option_by_name(s_bond, "ns_ip6_target"), + ==, + "fc08::1,fc08::2"); + + connection = g_hash_table_lookup(connections, "bond1"); + nmtst_assert_connection_verifies_without_normalization(connection); + s_bond = nm_connection_get_setting_bond(connection); + g_assert(s_bond); + g_assert_cmpint(nm_setting_bond_get_num_options(s_bond), ==, 3); + g_assert_cmpstr(nm_setting_bond_get_option_by_name(s_bond, "ns_ip6_target"), + ==, + "fc08::1,fc08::2"); + + connection = g_hash_table_lookup(connections, "bond2"); + nmtst_assert_connection_verifies_without_normalization(connection); + s_bond = nm_connection_get_setting_bond(connection); + g_assert(s_bond); + g_assert_cmpint(nm_setting_bond_get_num_options(s_bond), ==, 3); + g_assert_cmpstr(nm_setting_bond_get_option_by_name(s_bond, "ns_ip6_target"), + ==, + "fc08::1,fc08::2"); + + connection = g_hash_table_lookup(connections, "bond3"); + nmtst_assert_connection_verifies_without_normalization(connection); + s_bond = nm_connection_get_setting_bond(connection); + g_assert(s_bond); + g_assert_cmpint(nm_setting_bond_get_num_options(s_bond), ==, 3); + g_assert_cmpstr(nm_setting_bond_get_option_by_name(s_bond, "arp_ip_target"), + ==, + "10.0.0.1,10.0.0.2"); + + connection = g_hash_table_lookup(connections, "bond4"); + nmtst_assert_connection_verifies_without_normalization(connection); + s_bond = nm_connection_get_setting_bond(connection); + g_assert(s_bond); + g_assert_cmpint(nm_setting_bond_get_num_options(s_bond), ==, 3); + g_assert_cmpstr(nm_setting_bond_get_option_by_name(s_bond, "arp_ip_target"), + ==, + "10.0.0.1,10.0.0.2"); + + connection = g_hash_table_lookup(connections, "bond5"); + nmtst_assert_connection_verifies_without_normalization(connection); + s_bond = nm_connection_get_setting_bond(connection); + g_assert(s_bond); + g_assert_cmpint(nm_setting_bond_get_num_options(s_bond), ==, 3); + g_assert_cmpstr(nm_setting_bond_get_option_by_name(s_bond, "arp_ip_target"), + ==, + "10.0.0.1,10.0.0.2"); +} + static void test_bond_default(void) { @@ -2701,6 +2813,8 @@ main(int argc, char **argv) g_test_add_func("/initrd/cmdline/bootdev", test_bootdev); g_test_add_func("/initrd/cmdline/bond", test_bond); g_test_add_func("/initrd/cmdline/bond/ip", test_bond_ip); + g_test_add_func("/initrd/cmdline/bond/ip6-option", test_bond_ip6_option); + g_test_add_func("/initrd/cmdline/bond/multi-values-option", test_bond_multi_values_option); g_test_add_func("/initrd/cmdline/bond/default", test_bond_default); g_test_add_func("/initrd/cmdline/team", test_team); g_test_add_func("/initrd/cmdline/vlan", test_vlan); diff --git a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in index 9aa1751e7e..77e6c4278a 100644 --- a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in +++ b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in @@ -629,7 +629,7 @@ alias="type" nmcli-description="Base type of the connection. For hardware-dependent connections, should contain the setting name of the hardware-type specific setting (ie, "802-3-ethernet" or "802-11-wireless" or "bluetooth", etc), and for non-hardware dependent connections like VPN or otherwise, should contain the setting name of that setting type (ie, "vpn" or "bridge", etc)." format="string" - values="6lowpan, 802-11-olpc-mesh, 802-11-wireless, 802-3-ethernet, adsl, bluetooth, bond, bridge, cdma, dummy, generic, gsm, hsr, infiniband, ip-tunnel, ipvlan, loopback, macsec, macvlan, ovs-bridge, ovs-dpdk, ovs-interface, ovs-patch, ovs-port, pppoe, team, tun, veth, vlan, vpn, vrf, vxlan, wifi-p2p, wimax, wireguard, wpan" /> + values="6lowpan, 802-11-olpc-mesh, 802-11-wireless, 802-3-ethernet, adsl, bluetooth, bond, bridge, cdma, dummy, generic, gsm, hsr, infiniband, ip-tunnel, ipvlan, loopback, macsec, macvlan, ovs-bridge, ovs-interface, ovs-port, pppoe, team, tun, veth, vlan, vpn, vrf, vxlan, wifi-p2p, wimax, wireguard, wpan" /> <property name="interface-name" alias="ifname" nmcli-description="The name of the network interface this connection is bound to. If not set, then the connection can be attached to any interface of the appropriate type (subject to restrictions imposed by other settings). For software devices this specifies the name of the created device. For connection types where interface names cannot easily be made persistent (e.g. mobile broadband or USB Ethernet), this property should not be used. Setting this property restricts the interfaces a connection can be used with, and if interface names change or are reordered the connection may be applied to the wrong interface." @@ -1698,7 +1698,7 @@ format="choice (NMSettingMacvlanMode)" values="vepa (1), bridge (2), private (3), passthru (4), source (5)" /> <property name="promiscuous" - nmcli-description="Whether the interface should be put in promiscuous mode." + nmcli-description="Whether the parent interface should be put in promiscuous mode (true by default)." format="boolean" values="true/yes/on, false/no/off" /> <property name="tap" diff --git a/tools/test-networkmanager-service.py b/tools/test-networkmanager-service.py index 8a42633204..8d39aef78e 100755 --- a/tools/test-networkmanager-service.py +++ b/tools/test-networkmanager-service.py @@ -868,7 +868,7 @@ class Device(ExportedObj): self.activation_state_change_delay_ms = 50 self.hwaddr = hwaddr is None if "" else hwaddr - self.prp_state = NM.DeviceState.UNAVAILABLE + self.prp_state = NM.DeviceState.DISCONNECTED if devtype == NM.DeviceType.MODEM: udi = "/org/freedesktop/ModemManager1/Modem/0"
OpenPGP_signature.asc
Description: OpenPGP digital signature