diff options
| author | Michael Biebl <biebl@debian.org> | 2025-02-12 13:46:50 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2025-02-12 13:46:50 +0100 |
| commit | 8bdf070ff046f482f6eb5e2b15ebc216f5d1e3da (patch) | |
| tree | f706478d189d54c6532e8863d4b0d5ff5575af60 /src/core | |
| parent | 818258cf34b83fbc754633295e1052d4752d7b15 (diff) | |
New upstream version 1.51.90 upstream/1.51.90
Diffstat (limited to 'src/core')
136 files changed, 3738 insertions, 1397 deletions
diff --git a/src/core/NetworkManagerUtils.c b/src/core/NetworkManagerUtils.c index 2f447146..6c9e2f3d 100644 --- a/src/core/NetworkManagerUtils.c +++ b/src/core/NetworkManagerUtils.c @@ -250,23 +250,19 @@ nm_utils_ppp_ip_methods_enabled(NMConnection *connection, /*****************************************************************************/ void -_nm_utils_complete_generic_with_params(NMPlatform *platform, - NMConnection *connection, - const char *ctype, - NMConnection *const *existing_connections, - const char *preferred_id, - const char *fallback_id_prefix, - const char *ifname_prefix, - const char *ifname, - ...) +nm_utils_complete_generic(NMPlatform *platform, + NMConnection *connection, + const char *ctype, + NMConnection *const *existing_connections, + const char *preferred_id, + const char *fallback_id_prefix, + const char *ifname_prefix, + const char *ifname) { NMSettingConnection *s_con; char *id; char *generated_ifname; gs_unref_hashtable GHashTable *parameters = NULL; - va_list ap; - const char *p_val; - const char *p_key; g_assert(fallback_id_prefix); g_return_if_fail(ifname_prefix == NULL || ifname == NULL); @@ -301,20 +297,22 @@ _nm_utils_complete_generic_with_params(NMPlatform *platform, g_free(generated_ifname); } - /* Normalize */ - va_start(ap, ifname); - while ((p_key = va_arg(ap, const char *))) { - p_val = va_arg(ap, const char *); - if (!p_val) { - if (parameters) - g_hash_table_remove(parameters, p_key); - continue; - } - if (!parameters) - parameters = g_hash_table_new(nm_str_hash, g_str_equal); - g_hash_table_insert(parameters, (char *) p_key, (char *) p_val); + if (nm_connection_get_setting_adsl(connection) || nm_connection_get_setting_cdma(connection) + || nm_connection_get_setting_olpc_mesh(connection) + || nm_connection_get_setting_pppoe(connection) + || nm_connection_get_setting_vpn(connection)) { + parameters = g_hash_table_new(nm_str_hash, g_str_equal); + g_hash_table_insert(parameters, + NM_CONNECTION_NORMALIZE_PARAM_IP6_CONFIG_METHOD, + NM_SETTING_IP6_CONFIG_METHOD_IGNORE); + } else { + parameters = NULL; } - va_end(ap); + + /* We ignore the result, because the caller validates the connection. + * The only reason we do a normalization attempt here is + * NM_CONNECTION_NORMALIZE_PARAM_IP6_CONFIG_METHOD. + * Could we perhaps, one day, get rid of it? */ nm_connection_normalize(connection, parameters, NULL, NULL); } @@ -967,7 +965,7 @@ nm_match_spec_device_data_init_from_device(struct _NMMatchSpecDeviceData *out_da nm_assert(out_data); if (!device) { - *out_data = (NMMatchSpecDeviceData){}; + *out_data = (NMMatchSpecDeviceData) {}; return out_data; } @@ -983,7 +981,7 @@ nm_match_spec_device_data_init_from_device(struct _NMMatchSpecDeviceData *out_da * * The returned data is only valid, until NMDevice gets modified again. */ - *out_data = (NMMatchSpecDeviceData){ + *out_data = (NMMatchSpecDeviceData) { .interface_name = nm_device_get_iface(device), .device_type = nm_device_get_type_description(device), .driver = nm_device_get_driver(device), @@ -1010,7 +1008,7 @@ nm_match_spec_device_data_init_from_platform(NMMatchSpecDeviceData *out_data, * It's still useful because of specs like "*" and "except:interface-name:eth0", * which match even in that case. */ - *out_data = (NMMatchSpecDeviceData){ + *out_data = (NMMatchSpecDeviceData) { .interface_name = pllink ? pllink->name : NULL, .device_type = match_device_type, .driver = pllink ? pllink->driver : NULL, @@ -1057,7 +1055,7 @@ nm_ip_routing_rule_to_platform(const NMIPRoutingRule *rule, NMPlatformRoutingRul uid_range_has = nm_ip_routing_rule_get_uid_range(rule, &uid_range_start, &uid_range_end); - *out_pl = (NMPlatformRoutingRule){ + *out_pl = (NMPlatformRoutingRule) { .addr_family = nm_ip_routing_rule_get_addr_family(rule), .flags = (nm_ip_routing_rule_get_invert(rule) ? FIB_RULE_INVERT : 0), .priority = nm_ip_routing_rule_get_priority(rule), @@ -1200,7 +1198,7 @@ nm_shutdown_wait_obj_register_full(gpointer watched_obj, * make sure to use the default context. */ handle = g_slice_new(NMShutdownWaitObjHandle); - *handle = (NMShutdownWaitObjHandle){ + *handle = (NMShutdownWaitObjHandle) { /* depending on @free_msg_reason, we take ownership of @msg_reason. * In either case, we just reference the string without cloning * it. */ diff --git a/src/core/NetworkManagerUtils.h b/src/core/NetworkManagerUtils.h index 7d8afe5a..01f5bdb0 100644 --- a/src/core/NetworkManagerUtils.h +++ b/src/core/NetworkManagerUtils.h @@ -23,60 +23,14 @@ void nm_utils_ppp_ip_methods_enabled(NMConnection *connection, gboolean *out_ip4_enabled, gboolean *out_ip6_enabled); -void _nm_utils_complete_generic_with_params(NMPlatform *platform, - NMConnection *connection, - const char *ctype, - NMConnection *const *existing_connections, - const char *preferred_id, - const char *fallback_id_prefix, - const char *ifname_prefix, - const char *ifname, - ...) G_GNUC_NULL_TERMINATED; - -#define nm_utils_complete_generic_with_params(platform, \ - connection, \ - ctype, \ - existing_connections, \ - preferred_id, \ - fallback_id_prefix, \ - ifname_prefix, \ - ifname, \ - ...) \ - _nm_utils_complete_generic_with_params(platform, \ - connection, \ - ctype, \ - existing_connections, \ - preferred_id, \ - fallback_id_prefix, \ - ifname_prefix, \ - ifname, \ - ##__VA_ARGS__, \ - NULL) - -static inline void -nm_utils_complete_generic(NMPlatform *platform, - NMConnection *connection, - const char *ctype, - NMConnection *const *existing_connections, - const char *preferred_id, - const char *fallback_id_prefix, - const char *ifname_prefix, - const char *ifname, - gboolean default_enable_ipv6) -{ - nm_utils_complete_generic_with_params(platform, - connection, - ctype, - existing_connections, - preferred_id, - fallback_id_prefix, - ifname_prefix, - ifname, - NM_CONNECTION_NORMALIZE_PARAM_IP6_CONFIG_METHOD, - default_enable_ipv6 - ? NM_SETTING_IP6_CONFIG_METHOD_AUTO - : NM_SETTING_IP6_CONFIG_METHOD_IGNORE); -} +void nm_utils_complete_generic(NMPlatform *platform, + NMConnection *connection, + const char *ctype, + NMConnection *const *existing_connections, + const char *preferred_id, + const char *fallback_id_prefix, + const char *ifname_prefix, + const char *ifname); typedef gboolean(NMUtilsMatchFilterFunc)(NMConnection *connection, gpointer user_data); diff --git a/src/core/devices/adsl/nm-device-adsl.c b/src/core/devices/adsl/nm-device-adsl.c index ba605077..a6dc6326 100644 --- a/src/core/devices/adsl/nm-device-adsl.c +++ b/src/core/devices/adsl/nm-device-adsl.c @@ -117,8 +117,7 @@ complete_connection(NMDevice *device, NULL, _("ADSL connection"), NULL, - NULL, - FALSE); /* No IPv6 yet by default */ + NULL); return TRUE; } @@ -494,7 +493,7 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) _LOGD(LOGD_ADSL, "starting PPPoA"); } - priv->ppp_mgr = nm_ppp_mgr_start(&((const NMPppMgrConfig){ + priv->ppp_mgr = nm_ppp_mgr_start(&((const NMPppMgrConfig) { .netns = nm_device_get_netns(device), .parent_iface = ppp_iface, .callback = _ppp_mgr_callback, diff --git a/src/core/devices/bluetooth/nm-bluez-manager.c b/src/core/devices/bluetooth/nm-bluez-manager.c index ac26ede8..3088cd6f 100644 --- a/src/core/devices/bluetooth/nm-bluez-manager.c +++ b/src/core/devices/bluetooth/nm-bluez-manager.c @@ -334,7 +334,7 @@ _bz_dbus_obj_new(NMBluezManager *self, const char *object_path) l = strlen(object_path) + 1; bzobj = g_malloc(sizeof(BzDBusObj) + l); - *bzobj = (BzDBusObj){ + *bzobj = (BzDBusObj) { .object_path = bzobj->_object_path_intern, .self = self, .x_network_server.lst = C_LIST_INIT(bzobj->x_network_server.lst), @@ -751,7 +751,7 @@ _conn_data_head_new(NMBluetoothCapabilities bt_type, const char *bdaddr) l = strlen(bdaddr) + 1; cdata_hd = g_malloc(sizeof(ConnDataHead) + l); - *cdata_hd = (ConnDataHead){ + *cdata_hd = (ConnDataHead) { .bdaddr = cdata_hd->bdaddr_data, .lst_head = C_LIST_INIT(cdata_hd->lst_head), .bt_type = bt_type, @@ -1143,7 +1143,7 @@ _network_server_vt_register_bridge(const NMBtVTableNetworkServer *vtable, bzobj->d_adapter.address); r_req_data = g_slice_new(NetworkServerRegisterReqData); - *r_req_data = (NetworkServerRegisterReqData){ + *r_req_data = (NetworkServerRegisterReqData) { .int_cancellable = g_cancellable_new(), .ext_cancellable = g_object_ref(cancellable), .callback = callback, @@ -2749,7 +2749,7 @@ nm_bluez_manager_connect(NMBluezManager *self, } c_req_data = g_slice_new(DeviceConnectReqData); - *c_req_data = (DeviceConnectReqData){ + *c_req_data = (DeviceConnectReqData) { .int_cancellable = g_steal_pointer(&int_cancellable), .ext_cancellable = g_object_ref(cancellable), .callback = callback, @@ -2814,7 +2814,7 @@ nm_bluez_manager_init(NMBluezManager *self) { NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - priv->vtable_network_server = (NMBtVTableNetworkServer){ + priv->vtable_network_server = (NMBtVTableNetworkServer) { .is_available = _network_server_vt_is_available, .register_bridge = _network_server_vt_register_bridge, .unregister_bridge = _network_server_vt_unregister_bridge, diff --git a/src/core/devices/bluetooth/nm-bluez5-dun.c b/src/core/devices/bluetooth/nm-bluez5-dun.c index 426bab0c..08d37c27 100644 --- a/src/core/devices/bluetooth/nm-bluez5-dun.c +++ b/src/core/devices/bluetooth/nm-bluez5-dun.c @@ -683,7 +683,7 @@ nm_bluez5_dun_connect(const char *adapter, dst_l = strlen(remote) + 1; cdat = g_slice_new(ConnectData); - *cdat = (ConnectData){ + *cdat = (ConnectData) { .callback = callback, .callback_user_data = callback_user_data, .cancellable = g_object_ref(cancellable), @@ -691,7 +691,7 @@ nm_bluez5_dun_connect(const char *adapter, }; context = g_malloc(sizeof(NMBluez5DunContext) + src_l + dst_l); - *context = (NMBluez5DunContext){ + *context = (NMBluez5DunContext) { .cdat = cdat, .notify_tty_hangup_cb = notify_tty_hangup_cb, .notify_tty_hangup_user_data = notify_tty_hangup_user_data, diff --git a/src/core/devices/bluetooth/nm-device-bt.c b/src/core/devices/bluetooth/nm-device-bt.c index ce110aa0..4406bcf4 100644 --- a/src/core/devices/bluetooth/nm-device-bt.c +++ b/src/core/devices/bluetooth/nm-device-bt.c @@ -404,8 +404,7 @@ complete_connection(NMDevice *device, preferred, fallback_prefix, NULL, - NULL, - is_dun ? FALSE : TRUE); /* No IPv6 yet for DUN */ + NULL); setting_bdaddr = nm_setting_bluetooth_get_bdaddr(s_bt); if (setting_bdaddr) { diff --git a/src/core/devices/nm-device-6lowpan.c b/src/core/devices/nm-device-6lowpan.c index 78ec634c..3dabcb9b 100644 --- a/src/core/devices/nm-device-6lowpan.c +++ b/src/core/devices/nm-device-6lowpan.c @@ -161,8 +161,7 @@ complete_connection(NMDevice *device, NULL, _("6LOWPAN connection"), NULL, - NULL, - TRUE); + NULL); s_6lowpan = NM_SETTING_6LOWPAN(nm_connection_get_setting(connection, NM_TYPE_SETTING_6LOWPAN)); if (!s_6lowpan) { @@ -276,27 +275,10 @@ get_connection_parent(NMDeviceFactory *factory, NMConnection *connection) g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_6LOWPAN_SETTING_NAME), NULL); s_6lowpan = NM_SETTING_6LOWPAN(nm_connection_get_setting(connection, NM_TYPE_SETTING_6LOWPAN)); - g_assert(s_6lowpan); - - return nm_setting_6lowpan_get_parent(s_6lowpan); -} - -static char * -get_connection_iface(NMDeviceFactory *factory, NMConnection *connection, const char *parent_iface) -{ - NMSetting6Lowpan *s_6lowpan; - const char *ifname; - - g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_6LOWPAN_SETTING_NAME), NULL); - - s_6lowpan = NM_SETTING_6LOWPAN(nm_connection_get_setting(connection, NM_TYPE_SETTING_6LOWPAN)); - g_assert(s_6lowpan); - - if (!parent_iface) + if (s_6lowpan) + return nm_setting_6lowpan_get_parent(s_6lowpan); + else return NULL; - - ifname = nm_connection_get_interface_name(connection); - return g_strdup(ifname); } NM_DEVICE_FACTORY_DEFINE_INTERNAL( @@ -306,5 +288,4 @@ NM_DEVICE_FACTORY_DEFINE_INTERNAL( NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_6LOWPAN) NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_6LOWPAN_SETTING_NAME), factory_class->create_device = create_device; - factory_class->get_connection_parent = get_connection_parent; - factory_class->get_connection_iface = get_connection_iface;); + factory_class->get_connection_parent = get_connection_parent;); diff --git a/src/core/devices/nm-device-bond.c b/src/core/devices/nm-device-bond.c index 3ab17aff..53b32466 100644 --- a/src/core/devices/nm-device-bond.c +++ b/src/core/devices/nm-device-bond.c @@ -94,8 +94,7 @@ complete_connection(NMDevice *device, NULL, _("Bond connection"), "bond", - NULL, - TRUE); + NULL); _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_BOND); @@ -436,7 +435,7 @@ _platform_lnk_bond_init_from_setting(NMSettingBond *s_bond, NMPlatformLnkBond *p #define _v_u32(s_bond, opt) _nm_setting_bond_opt_value_as_u32((s_bond), (opt)) #define _v_intbool(s_bond, opt) _nm_setting_bond_opt_value_as_intbool((s_bond), (opt)) - *props = (NMPlatformLnkBond){ + *props = (NMPlatformLnkBond) { .mode = _v_fcn(_nm_setting_bond_mode_from_string, s_bond, NM_SETTING_BOND_OPTION_MODE), .primary = _setting_bond_primary_opt_as_ifindex(s_bond), .miimon = _v_u32(s_bond, NM_SETTING_BOND_OPTION_MIIMON), @@ -681,7 +680,7 @@ commit_port_options(NMDevice *bond_device, NMDevice *port, NMSettingBondPort *s_ nm_platform_link_change(nm_device_get_platform(port), nm_device_get_ifindex(port), NULL, - &((NMPlatformLinkBondPort){ + &((NMPlatformLinkBondPort) { .queue_id = s_port ? nm_setting_bond_port_get_queue_id(s_port) : NM_BOND_PORT_QUEUE_ID_DEF, .prio = prio_has ? prio : 0, diff --git a/src/core/devices/nm-device-bridge.c b/src/core/devices/nm-device-bridge.c index a237c0b7..7c34fde0 100644 --- a/src/core/devices/nm-device-bridge.c +++ b/src/core/devices/nm-device-bridge.c @@ -164,8 +164,7 @@ complete_connection(NMDevice *device, NULL, _("Bridge connection"), "bridge", - NULL, - TRUE); + NULL); _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_BRIDGE); @@ -439,7 +438,7 @@ setting_vlans_to_platform(GPtrArray *array, guint *out_len) nm_bridge_vlan_get_vid_range(vlan, &vid_start, &vid_end); - arr[i] = (NMPlatformBridgeVlan){ + arr[i] = (NMPlatformBridgeVlan) { .vid_start = vid_start, .vid_end = vid_end, .pvid = nm_bridge_vlan_is_pvid(vlan), @@ -468,7 +467,7 @@ commit_port_options(NMDevice *device, NMSettingBridgePort *setting) nm_device_get_ifindex(device), NULL, NULL, - &((NMPlatformLinkBridgePort){ + &((NMPlatformLinkBridgePort) { .path_cost = path_cost, .priority = priority, .hairpin = nm_setting_bridge_port_get_hairpin_mode(setting), @@ -660,10 +659,10 @@ bridge_set_vlan_options(NMDevice *device, NMSettingBridge *s_bridge, gboolean is nm_platform_link_set_bridge_info( plat, ifindex, - &((NMPlatformLinkSetBridgeInfoData){.vlan_filtering_has = TRUE, - .vlan_filtering_val = FALSE, - .vlan_default_pvid_has = TRUE, - .vlan_default_pvid_val = 1})); + &((NMPlatformLinkSetBridgeInfoData) {.vlan_filtering_has = TRUE, + .vlan_filtering_val = FALSE, + .vlan_default_pvid_has = TRUE, + .vlan_default_pvid_val = 1})); nm_platform_link_set_bridge_vlans(plat, ifindex, FALSE, NULL, 0); return TRUE; } @@ -690,10 +689,10 @@ bridge_set_vlan_options(NMDevice *device, NMSettingBridge *s_bridge, gboolean is nm_platform_link_set_bridge_info( plat, ifindex, - &((NMPlatformLinkSetBridgeInfoData){.vlan_filtering_has = TRUE, - .vlan_filtering_val = FALSE, - .vlan_default_pvid_has = TRUE, - .vlan_default_pvid_val = 0})); + &((NMPlatformLinkSetBridgeInfoData) {.vlan_filtering_has = TRUE, + .vlan_filtering_val = FALSE, + .vlan_default_pvid_has = TRUE, + .vlan_default_pvid_val = 0})); /* Clear all existing VLANs */ if (!nm_platform_link_set_bridge_vlans(plat, ifindex, FALSE, NULL, 0)) @@ -706,8 +705,8 @@ bridge_set_vlan_options(NMDevice *device, NMSettingBridge *s_bridge, gboolean is nm_platform_link_set_bridge_info( plat, ifindex, - &((NMPlatformLinkSetBridgeInfoData){.vlan_default_pvid_has = TRUE, - .vlan_default_pvid_val = pvid})); + &((NMPlatformLinkSetBridgeInfoData) {.vlan_default_pvid_has = TRUE, + .vlan_default_pvid_val = pvid})); } } @@ -721,7 +720,7 @@ bridge_set_vlan_options(NMDevice *device, NMSettingBridge *s_bridge, gboolean is nm_platform_link_set_bridge_info(plat, ifindex, - &((NMPlatformLinkSetBridgeInfoData){ + &((NMPlatformLinkSetBridgeInfoData) { .vlan_filtering_has = TRUE, .vlan_filtering_val = TRUE, })); @@ -757,7 +756,7 @@ merge_bridge_vlan_default_pvid(NMPlatformBridgeVlan *vlans, guint *num_vlans, gu * Set the PVID flag only if the port didn't have one. */ vlans = g_realloc_n(vlans, *num_vlans + 1, sizeof(NMPlatformBridgeVlan)); (*num_vlans)++; - vlans[*num_vlans - 1] = (NMPlatformBridgeVlan){ + vlans[*num_vlans - 1] = (NMPlatformBridgeVlan) { .vid_start = default_pvid, .vid_end = default_pvid, .untagged = TRUE, @@ -847,7 +846,7 @@ nm_device_reapply_bridge_port_vlans(NMDevice *device) static void _platform_lnk_bridge_init_from_setting(NMSettingBridge *s_bridge, NMPlatformLnkBridge *props) { - *props = (NMPlatformLnkBridge){ + *props = (NMPlatformLnkBridge) { .forward_delay = _DEFAULT_IF_ZERO(nm_setting_bridge_get_forward_delay(s_bridge) * 100u, NM_BRIDGE_FORWARD_DELAY_DEF_SYS), .hello_time = _DEFAULT_IF_ZERO(nm_setting_bridge_get_hello_time(s_bridge) * 100u, diff --git a/src/core/devices/nm-device-dummy.c b/src/core/devices/nm-device-dummy.c index b7c4106a..1bc5447f 100644 --- a/src/core/devices/nm-device-dummy.c +++ b/src/core/devices/nm-device-dummy.c @@ -48,14 +48,14 @@ complete_connection(NMDevice *device, NMConnection *const *existing_connections, GError **error) { - nm_utils_complete_generic_with_params(nm_device_get_platform(device), - connection, - NM_SETTING_DUMMY_SETTING_NAME, - existing_connections, - NULL, - _("Dummy connection"), - NULL, - nm_device_get_ip_iface(device)); + nm_utils_complete_generic(nm_device_get_platform(device), + connection, + NM_SETTING_DUMMY_SETTING_NAME, + existing_connections, + NULL, + _("Dummy connection"), + NULL, + nm_device_get_ip_iface(device)); _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_DUMMY); diff --git a/src/core/devices/nm-device-ethernet.c b/src/core/devices/nm-device-ethernet.c index 16992524..4034fdaa 100644 --- a/src/core/devices/nm-device-ethernet.c +++ b/src/core/devices/nm-device-ethernet.c @@ -1451,7 +1451,7 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) g_return_val_if_fail(s_pppoe, NM_ACT_STAGE_RETURN_FAILURE); priv->ppp_data.ppp_mgr = - nm_ppp_mgr_start(&((const NMPppMgrConfig){ + nm_ppp_mgr_start(&((const NMPppMgrConfig) { .netns = nm_device_get_netns(device), .parent_iface = nm_device_get_iface(device), .callback = _ppp_mgr_callback, @@ -1640,8 +1640,7 @@ complete_connection(NMDevice *device, NULL, _("Veth connection"), "veth", - NULL, - TRUE); + NULL); s_veth = _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_VETH); @@ -1698,8 +1697,7 @@ complete_connection(NMDevice *device, NULL, s_pppoe ? _("PPPoE connection") : _("Wired connection"), NULL, - nm_setting_wired_get_mac_address(s_wired) ? NULL : nm_device_get_iface(device), - s_pppoe ? FALSE : TRUE); /* No IPv6 by default yet for PPPoE */ + nm_setting_wired_get_mac_address(s_wired) ? NULL : nm_device_get_iface(device)); return TRUE; } diff --git a/src/core/devices/nm-device-factory.c b/src/core/devices/nm-device-factory.c index 22c8fa5a..15858362 100644 --- a/src/core/devices/nm-device-factory.c +++ b/src/core/devices/nm-device-factory.c @@ -147,7 +147,7 @@ nm_device_factory_get_connection_iface(NMDeviceFactory *factory, g_set_error(error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, - "failed to determine interface name: error determine name for %s", + "failed to determine interface name for a %s", nm_connection_get_connection_type(connection)); return NULL; } @@ -415,6 +415,7 @@ nm_device_factory_manager_load_factories(NMDeviceFactoryManagerFactoryFunc callb _ADD_INTERNAL(nm_hsr_device_factory_get_type); _ADD_INTERNAL(nm_infiniband_device_factory_get_type); _ADD_INTERNAL(nm_ip_tunnel_device_factory_get_type); + _ADD_INTERNAL(nm_ipvlan_device_factory_get_type); _ADD_INTERNAL(nm_loopback_device_factory_get_type); _ADD_INTERNAL(nm_macsec_device_factory_get_type); _ADD_INTERNAL(nm_macvlan_device_factory_get_type); diff --git a/src/core/devices/nm-device-factory.h b/src/core/devices/nm-device-factory.h index 004ae9b1..d4aae75f 100644 --- a/src/core/devices/nm-device-factory.h +++ b/src/core/devices/nm-device-factory.h @@ -69,11 +69,15 @@ typedef struct { /** * get_connection_parent: * @factory: the #NMDeviceFactory - * @connection: the #NMConnection to return the parent name for, if supported + * @connection: the #NMConnection (possibly incomplete) to return the parent name for, if supported * * Given a connection, returns the parent interface name, parent connection * UUID, or parent device permanent hardware address for @connection. * + * Note that @connection is not necessarily a valid connection. + * It might be called during AddAndActivate before the connection is + * completed and normalized. + * * Returns: the parent interface name, parent connection UUID, parent * device permanent hardware address, or %NULL */ @@ -82,12 +86,16 @@ typedef struct { /** * get_connection_iface: * @factory: the #NMDeviceFactory - * @connection: the #NMConnection to return the interface name for + * @connection: the #NMConnection (possibly incomplete) to return the interface name for * @parent_iface: optional parent interface name for virtual devices * * Given a connection, returns the interface name that a device activating * that connection would have. * + * Note that @connection is not necessarily a valid connection. + * It might be called during AddAndActivate before the connection is + * completed and normalized. + * * Returns: the interface name, or %NULL */ char *(*get_connection_iface)(NMDeviceFactory *factory, diff --git a/src/core/devices/nm-device-infiniband.c b/src/core/devices/nm-device-infiniband.c index c974696c..a5a82b94 100644 --- a/src/core/devices/nm-device-infiniband.c +++ b/src/core/devices/nm-device-infiniband.c @@ -159,8 +159,7 @@ complete_connection(NMDevice *device, NULL, _("InfiniBand connection"), NULL, - nm_setting_infiniband_get_mac_address(s_infiniband) ? NULL : nm_device_get_iface(device), - TRUE); + nm_setting_infiniband_get_mac_address(s_infiniband) ? NULL : nm_device_get_iface(device)); if (!nm_setting_infiniband_get_transport_mode(s_infiniband)) g_object_set(G_OBJECT(s_infiniband), @@ -464,9 +463,10 @@ get_connection_parent(NMDeviceFactory *factory, NMConnection *connection) NULL); s_infiniband = nm_connection_get_setting_infiniband(connection); - g_assert(s_infiniband); - - return nm_setting_infiniband_get_parent(s_infiniband); + if (s_infiniband) + return nm_setting_infiniband_get_parent(s_infiniband); + else + return NULL; } static char * @@ -477,17 +477,19 @@ get_connection_iface(NMDeviceFactory *factory, NMConnection *connection, const c g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_INFINIBAND_SETTING_NAME), NULL); - s_infiniband = nm_connection_get_setting_infiniband(connection); - g_assert(s_infiniband); - if (!parent_iface) return NULL; - g_return_val_if_fail(g_strcmp0(parent_iface, nm_setting_infiniband_get_parent(s_infiniband)) - == 0, - NULL); + s_infiniband = nm_connection_get_setting_infiniband(connection); + if (s_infiniband) { + g_return_val_if_fail(g_strcmp0(parent_iface, nm_setting_infiniband_get_parent(s_infiniband)) + == 0, + NULL); - return g_strdup(nm_setting_infiniband_get_virtual_interface_name(s_infiniband)); + return g_strdup(nm_setting_infiniband_get_virtual_interface_name(s_infiniband)); + } else { + return NULL; + } } NM_DEVICE_FACTORY_DEFINE_INTERNAL( diff --git a/src/core/devices/nm-device-ip-tunnel.c b/src/core/devices/nm-device-ip-tunnel.c index cc62180e..2ecfe453 100644 --- a/src/core/devices/nm-device-ip-tunnel.c +++ b/src/core/devices/nm-device-ip-tunnel.c @@ -402,8 +402,7 @@ complete_connection(NMDevice *device, NULL, _("IP tunnel connection"), NULL, - NULL, - TRUE); + NULL); s_ip_tunnel = nm_connection_get_setting_ip_tunnel(connection); if (!s_ip_tunnel) { @@ -1369,29 +1368,10 @@ get_connection_parent(NMDeviceFactory *factory, NMConnection *connection) NULL); s_ip_tunnel = nm_connection_get_setting_ip_tunnel(connection); - g_assert(s_ip_tunnel); - - return nm_setting_ip_tunnel_get_parent(s_ip_tunnel); -} - -static char * -get_connection_iface(NMDeviceFactory *factory, NMConnection *connection, const char *parent_iface) -{ - const char *ifname; - NMSettingIPTunnel *s_ip_tunnel; - - g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_IP_TUNNEL_SETTING_NAME), - NULL); - - s_ip_tunnel = nm_connection_get_setting_ip_tunnel(connection); - g_assert(s_ip_tunnel); - - if (nm_setting_ip_tunnel_get_parent(s_ip_tunnel) && !parent_iface) + if (s_ip_tunnel) + return nm_setting_ip_tunnel_get_parent(s_ip_tunnel); + else return NULL; - - ifname = nm_connection_get_interface_name(connection); - - return g_strdup(ifname); } NM_DEVICE_FACTORY_DEFINE_INTERNAL( @@ -1409,5 +1389,4 @@ NM_DEVICE_FACTORY_DEFINE_INTERNAL( NM_LINK_TYPE_VTI6) NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_IP_TUNNEL_SETTING_NAME), factory_class->create_device = create_device; - factory_class->get_connection_parent = get_connection_parent; - factory_class->get_connection_iface = get_connection_iface;); + factory_class->get_connection_parent = get_connection_parent;); diff --git a/src/core/devices/nm-device-ipvlan.c b/src/core/devices/nm-device-ipvlan.c new file mode 100644 index 00000000..00a1b579 --- /dev/null +++ b/src/core/devices/nm-device-ipvlan.c @@ -0,0 +1,467 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024 Red Hat, Inc. + */ + +#include "src/core/nm-default-daemon.h" + +#include "nm-device-ipvlan.h" + +#include <linux/if_link.h> + +#include "libnm-core-intern/nm-core-internal.h" +#include "nm-device-private.h" +#include "settings/nm-settings.h" +#include "nm-act-request.h" +#include "nm-manager.h" +#include "libnm-core-aux-intern/nm-libnm-core-utils.h" +#include "libnm-platform/nm-platform.h" +#include "nm-device-factory.h" +#include "nm-setting-ipvlan.h" +#include "nm-setting-wired.h" +#include "nm-active-connection.h" +#include "nm-utils.h" + +#define _NMLOG_DEVICE_TYPE NMDeviceIpvlan +#include "nm-device-logging.h" + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceIpvlan, PROP_MODE, PROP_PRIVATE, PROP_VEPA, ); + +typedef struct { + NMPlatformLnkIpvlan props; +} NMDeviceIpvlanPrivate; + +struct _NMDeviceIpvlan { + NMDevice parent; + NMDeviceIpvlanPrivate _priv; +}; + +struct _NMDeviceIpvlanClass { + NMDeviceClass parent; +}; + +G_DEFINE_TYPE(NMDeviceIpvlan, nm_device_ipvlan, NM_TYPE_DEVICE); + +#define NM_DEVICE_IPVLAN_GET_PRIVATE(self) \ + _NM_GET_PRIVATE(self, NMDeviceIpvlan, NM_IS_DEVICE_IPVLAN, NMDevice) + +/*****************************************************************************/ + +static int modes[][2] = { + {NM_SETTING_IPVLAN_MODE_L2, IPVLAN_MODE_L2}, + {NM_SETTING_IPVLAN_MODE_L3, IPVLAN_MODE_L3}, + {NM_SETTING_IPVLAN_MODE_L3S, IPVLAN_MODE_L3S}, +}; + +static int +setting_mode_to_platform(int mode) +{ + guint i; + + for (i = 0; i < G_N_ELEMENTS(modes); i++) { + if (modes[i][0] == mode) + return modes[i][1]; + } + + return -1; +} + +static int +platform_mode_to_setting(int mode) +{ + guint i; + + for (i = 0; i < G_N_ELEMENTS(modes); i++) { + if (modes[i][1] == mode) + return modes[i][0]; + } + + return 0; +} + +static const char * +platform_mode_to_string(guint mode) +{ + switch (mode) { + case IPVLAN_MODE_L2: + return "l2"; + case IPVLAN_MODE_L3: + return "l3"; + case IPVLAN_MODE_L3S: + return "l3s"; + default: + return "unknown"; + } +} + +/*****************************************************************************/ + +static void +update_properties(NMDevice *device) +{ + NMDeviceIpvlan *self = NM_DEVICE_IPVLAN(device); + NMDeviceIpvlanPrivate *priv = NM_DEVICE_IPVLAN_GET_PRIVATE(self); + GObject *object = G_OBJECT(device); + const NMPlatformLnkIpvlan *props; + const NMPlatformLink *plink; + + props = nm_platform_link_get_lnk_ipvlan(nm_device_get_platform(device), + nm_device_get_ifindex(device), + &plink); + + if (!props) { + _LOGW(LOGD_PLATFORM, "could not get IPVLAN properties"); + return; + } + + g_object_freeze_notify(object); + + nm_device_parent_set_ifindex(device, plink->parent); + +#define CHECK_PROPERTY_CHANGED(field, prop) \ + G_STMT_START \ + { \ + if (priv->props.field != props->field) { \ + priv->props.field = props->field; \ + _notify(self, prop); \ + } \ + } \ + G_STMT_END + + CHECK_PROPERTY_CHANGED(mode, PROP_MODE); + CHECK_PROPERTY_CHANGED(private_flag, PROP_PRIVATE); + CHECK_PROPERTY_CHANGED(vepa, PROP_VEPA); + + g_object_thaw_notify(object); +} + +static void +link_changed(NMDevice *device, const NMPlatformLink *pllink) +{ + NM_DEVICE_CLASS(nm_device_ipvlan_parent_class)->link_changed(device, pllink); + update_properties(device); +} + +static gboolean +create_and_realize(NMDevice *device, + NMConnection *connection, + NMDevice *parent, + const NMPlatformLink **out_plink, + GError **error) +{ + const char *iface = nm_device_get_iface(device); + NMSettingIpvlan *s_ipvlan; + NMPlatformLnkIpvlan lnk = {}; + int parent_ifindex; + int r; + + s_ipvlan = _nm_connection_get_setting(connection, NM_TYPE_SETTING_IPVLAN); + nm_assert(s_ipvlan); + + if (!parent) { + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_MISSING_DEPENDENCIES, + "IPVLAN device cannot be created without a parent interface"); + return FALSE; + } + + parent_ifindex = nm_device_get_ifindex(parent); + if (parent_ifindex <= 0) { + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_MISSING_DEPENDENCIES, + "cannot retrieve ifindex of interface %s (%s)", + nm_device_get_iface(parent), + nm_device_get_type_desc(parent)); + return FALSE; + } + + if (setting_mode_to_platform(nm_setting_ipvlan_get_mode(s_ipvlan)) < 0) { + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "unsupported IPVLAN mode %u", + nm_setting_ipvlan_get_mode(s_ipvlan)); + return FALSE; + } + lnk.mode = setting_mode_to_platform(nm_setting_ipvlan_get_mode(s_ipvlan)); + lnk.private_flag = nm_setting_ipvlan_get_private(s_ipvlan); + lnk.vepa = nm_setting_ipvlan_get_vepa(s_ipvlan); + + r = nm_platform_link_ipvlan_add(nm_device_get_platform(device), + iface, + parent_ifindex, + &lnk, + out_plink); + + if (r < 0) { + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create IPVLAN interface '%s' for '%s': %s", + iface, + nm_connection_get_id(connection), + nm_strerror(r)); + return FALSE; + } + + return TRUE; +} + +/*****************************************************************************/ + +static NMDeviceCapabilities +get_generic_capabilities(NMDevice *device) +{ + return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE; +} + +/*****************************************************************************/ + +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, + gboolean check_properties, + GError **error) +{ + NMDeviceIpvlanPrivate *priv = NM_DEVICE_IPVLAN_GET_PRIVATE(device); + NMSettingIpvlan *s_ipvlan; + const char *parent = NULL; + + if (!NM_DEVICE_CLASS(nm_device_ipvlan_parent_class) + ->check_connection_compatible(device, connection, check_properties, error)) + return FALSE; + + s_ipvlan = _nm_connection_get_setting(connection, NM_TYPE_SETTING_IPVLAN); + + if (check_properties && nm_device_is_real(device)) { + if (setting_mode_to_platform(nm_setting_ipvlan_get_mode(s_ipvlan)) != priv->props.mode) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "IPVLAN mode setting differs"); + return FALSE; + } + + if (nm_setting_ipvlan_get_private(s_ipvlan) != priv->props.private_flag) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "IPVLAN private flag setting differs"); + return FALSE; + } + if (nm_setting_ipvlan_get_vepa(s_ipvlan) != priv->props.vepa) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "IPVLAN VEPA flag setting differs"); + return FALSE; + } + + /* Check parent interface; could be an interface name or a UUID */ + parent = nm_setting_ipvlan_get_parent(s_ipvlan); + if (parent) { + if (!nm_device_match_parent(device, parent)) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "IPVLAN parent setting differs"); + return FALSE; + } + } else { + /* Parent could be a MAC address in an NMSettingWired */ + if (!nm_device_match_parent_hwaddr(device, connection, TRUE)) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "IPVLAN parent mac setting differs"); + return FALSE; + } + } + } + return TRUE; +} + +static void +update_connection(NMDevice *device, NMConnection *connection) +{ + NMDeviceIpvlanPrivate *priv = NM_DEVICE_IPVLAN_GET_PRIVATE(device); + NMSettingIpvlan *s_ipvlan = _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_IPVLAN); + + if (priv->props.mode != setting_mode_to_platform(nm_setting_ipvlan_get_mode(s_ipvlan))) + g_object_set(s_ipvlan, + NM_SETTING_IPVLAN_MODE, + platform_mode_to_setting(priv->props.mode), + NULL); + + if (priv->props.private_flag != nm_setting_ipvlan_get_private(s_ipvlan)) + g_object_set(s_ipvlan, NM_SETTING_IPVLAN_PRIVATE, priv->props.private_flag, NULL); + + if (priv->props.vepa != nm_setting_ipvlan_get_vepa(s_ipvlan)) + g_object_set(s_ipvlan, NM_SETTING_IPVLAN_VEPA, priv->props.vepa, NULL); + + g_object_set( + s_ipvlan, + NM_SETTING_IPVLAN_PARENT, + nm_device_parent_find_for_connection(device, nm_setting_ipvlan_get_parent(s_ipvlan)), + NULL); +} + +/*****************************************************************************/ + +static void +get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + NMDeviceIpvlanPrivate *priv = NM_DEVICE_IPVLAN_GET_PRIVATE(object); + + switch (prop_id) { + case PROP_MODE: + g_value_set_string(value, platform_mode_to_string(priv->props.mode)); + break; + case PROP_PRIVATE: + g_value_set_boolean(value, priv->props.private_flag); + break; + case PROP_VEPA: + g_value_set_boolean(value, priv->props.vepa); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +/*****************************************************************************/ + +static void +nm_device_ipvlan_init(NMDeviceIpvlan *self) +{} + +static const NMDBusInterfaceInfoExtended interface_info_device_ipvlan = { + .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( + NM_DBUS_INTERFACE_DEVICE_IPVLAN, + .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Parent", "o", NM_DEVICE_PARENT), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Mode", "s", NM_DEVICE_IPVLAN_MODE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Private", + "b", + NM_DEVICE_IPVLAN_PRIVATE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Vepa", + "b", + NM_DEVICE_IPVLAN_VEPA), ), ), +}; + +static void +nm_device_ipvlan_class_init(NMDeviceIpvlanClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); + NMDeviceClass *device_class = NM_DEVICE_CLASS(klass); + + object_class->get_property = get_property; + + dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_ipvlan); + + device_class->connection_type_supported = NM_SETTING_IPVLAN_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_IPVLAN_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_IPVLAN); + + 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; + + obj_properties[PROP_MODE] = g_param_spec_string(NM_DEVICE_IPVLAN_MODE, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_PRIVATE] = g_param_spec_boolean(NM_DEVICE_IPVLAN_PRIVATE, + "", + "", + TRUE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_VEPA] = g_param_spec_boolean(NM_DEVICE_IPVLAN_VEPA, + "", + "", + TRUE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); +} + +/*****************************************************************************/ + +#define NM_TYPE_IPVLAN_DEVICE_FACTORY (nm_ipvlan_device_factory_get_type()) +#define NM_IPVLAN_DEVICE_FACTORY(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_IPVLAN_DEVICE_FACTORY, NMIpvlanDeviceFactory)) + +static NMDevice * +create_device(NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) +{ + NMSettingIpvlan *s_ipvlan; + + if (connection) { + s_ipvlan = _nm_connection_get_setting(connection, NM_TYPE_SETTING_IPVLAN); + nm_assert(s_ipvlan); + } + + return g_object_new(NM_TYPE_DEVICE_IPVLAN, + NM_DEVICE_IFACE, + iface, + NM_DEVICE_TYPE_DESC, + "Ipvlan", + NM_DEVICE_DEVICE_TYPE, + NM_DEVICE_TYPE_IPVLAN, + NM_DEVICE_LINK_TYPE, + NM_LINK_TYPE_IPVLAN, + NULL); +} + +static const char * +get_connection_parent(NMDeviceFactory *factory, NMConnection *connection) +{ + NMSettingIpvlan *s_ipvlan; + NMSettingWired *s_wired; + const char *parent = NULL; + + g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_IPVLAN_SETTING_NAME), NULL); + + s_ipvlan = _nm_connection_get_setting(connection, NM_TYPE_SETTING_IPVLAN); + if (s_ipvlan) { + parent = nm_setting_ipvlan_get_parent(s_ipvlan); + if (parent) + return parent; + } + + /* Try the hardware address from the IPVLAN connection's hardware setting */ + s_wired = nm_connection_get_setting_wired(connection); + if (s_wired) + return nm_setting_wired_get_mac_address(s_wired); + else + return NULL; +} + +NM_DEVICE_FACTORY_DEFINE_INTERNAL( + IPVLAN, + Ipvlan, + ipvlan, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_IPVLAN) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_IPVLAN_SETTING_NAME), + factory_class->create_device = create_device; + factory_class->get_connection_parent = get_connection_parent;); diff --git a/src/core/devices/nm-device-ipvlan.h b/src/core/devices/nm-device-ipvlan.h new file mode 100644 index 00000000..6a228abe --- /dev/null +++ b/src/core/devices/nm-device-ipvlan.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024 Red Hat, Inc. + */ + +#ifndef __NETWORKMANAGER_DEVICE_IPVLAN_H__ +#define __NETWORKMANAGER_DEVICE_IPVLAN_H__ + +#include "nm-device.h" + +#define NM_TYPE_DEVICE_IPVLAN (nm_device_ipvlan_get_type()) +#define NM_DEVICE_IPVLAN(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_IPVLAN, NMDeviceIpvlan)) +#define NM_DEVICE_IPVLAN_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_IPVLAN, NMDeviceIpvlanClass)) +#define NM_IS_DEVICE_IPVLAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_IPVLAN)) +#define NM_IS_DEVICE_IPVLAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_IPVLAN)) +#define NM_DEVICE_IPVLAN_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_IPVLAN, NMDeviceIpvlanClass)) + +#define NM_DEVICE_IPVLAN_PARENT "parent" +#define NM_DEVICE_IPVLAN_MODE "mode" +#define NM_DEVICE_IPVLAN_PRIVATE "private" +#define NM_DEVICE_IPVLAN_VEPA "vepa" + +typedef struct _NMDeviceIpvlan NMDeviceIpvlan; +typedef struct _NMDeviceIpvlanClass NMDeviceIpvlanClass; + +GType nm_device_ipvlan_get_type(void); + +#endif /* __NETWORKMANAGER_DEVICE_IPVLAN_H__ */ diff --git a/src/core/devices/nm-device-loopback.c b/src/core/devices/nm-device-loopback.c index ec72aa96..268e1fb1 100644 --- a/src/core/devices/nm-device-loopback.c +++ b/src/core/devices/nm-device-loopback.c @@ -59,14 +59,14 @@ complete_connection(NMDevice *device, NMConnection *const *existing_connections, GError **error) { - nm_utils_complete_generic_with_params(nm_device_get_platform(device), - connection, - NM_SETTING_LOOPBACK_SETTING_NAME, - existing_connections, - NULL, - _("Loopback connection"), - NULL, - nm_device_get_ip_iface(device)); + nm_utils_complete_generic(nm_device_get_platform(device), + connection, + NM_SETTING_LOOPBACK_SETTING_NAME, + existing_connections, + NULL, + _("Loopback connection"), + NULL, + nm_device_get_ip_iface(device)); _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_LOOPBACK); diff --git a/src/core/devices/nm-device-macsec.c b/src/core/devices/nm-device-macsec.c index 32fab5be..89a06720 100644 --- a/src/core/devices/nm-device-macsec.c +++ b/src/core/devices/nm-device-macsec.c @@ -1022,36 +1022,18 @@ get_connection_parent(NMDeviceFactory *factory, NMConnection *connection) g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_MACSEC_SETTING_NAME), NULL); s_macsec = nm_connection_get_setting_macsec(connection); - g_assert(s_macsec); - - parent = nm_setting_macsec_get_parent(s_macsec); - if (parent) - return parent; + if (s_macsec) { + parent = nm_setting_macsec_get_parent(s_macsec); + if (parent) + return parent; + } /* Try the hardware address from the MACsec connection's hardware setting */ s_wired = nm_connection_get_setting_wired(connection); if (s_wired) return nm_setting_wired_get_mac_address(s_wired); - - return NULL; -} - -static char * -get_connection_iface(NMDeviceFactory *factory, NMConnection *connection, const char *parent_iface) -{ - NMSettingMacsec *s_macsec; - const char *ifname; - - g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_MACSEC_SETTING_NAME), NULL); - - s_macsec = nm_connection_get_setting_macsec(connection); - g_assert(s_macsec); - - if (!parent_iface) + else return NULL; - - ifname = nm_connection_get_interface_name(connection); - return g_strdup(ifname); } NM_DEVICE_FACTORY_DEFINE_INTERNAL( @@ -1061,5 +1043,4 @@ NM_DEVICE_FACTORY_DEFINE_INTERNAL( NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_MACSEC) NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_MACSEC_SETTING_NAME), factory_class->create_device = create_device; - factory_class->get_connection_parent = get_connection_parent; - factory_class->get_connection_iface = get_connection_iface;) + factory_class->get_connection_parent = get_connection_parent;); diff --git a/src/core/devices/nm-device-macvlan.c b/src/core/devices/nm-device-macvlan.c index 8cdef0cf..9501e8f1 100644 --- a/src/core/devices/nm-device-macvlan.c +++ b/src/core/devices/nm-device-macvlan.c @@ -232,9 +232,8 @@ create_and_realize(NMDevice *device, g_set_error(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, - "unsupported MACVLAN mode %u in connection %s", - nm_setting_macvlan_get_mode(s_macvlan), - nm_connection_get_uuid(connection)); + "unsupported MACVLAN mode %u", + nm_setting_macvlan_get_mode(s_macvlan)); return FALSE; } lnk.no_promisc = !nm_setting_macvlan_get_promiscuous(s_macvlan); @@ -365,8 +364,7 @@ complete_connection(NMDevice *device, NULL, _("MACVLAN connection"), NULL, - NULL, - TRUE); + NULL); s_macvlan = nm_connection_get_setting_macvlan(connection); if (!s_macvlan) { @@ -590,36 +588,18 @@ get_connection_parent(NMDeviceFactory *factory, NMConnection *connection) g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_MACVLAN_SETTING_NAME), NULL); s_macvlan = nm_connection_get_setting_macvlan(connection); - g_assert(s_macvlan); - - parent = nm_setting_macvlan_get_parent(s_macvlan); - if (parent) - return parent; + if (s_macvlan) { + parent = nm_setting_macvlan_get_parent(s_macvlan); + if (parent) + return parent; + } /* Try the hardware address from the MACVLAN connection's hardware setting */ s_wired = nm_connection_get_setting_wired(connection); if (s_wired) return nm_setting_wired_get_mac_address(s_wired); - - return NULL; -} - -static char * -get_connection_iface(NMDeviceFactory *factory, NMConnection *connection, const char *parent_iface) -{ - NMSettingMacvlan *s_macvlan; - const char *ifname; - - g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_MACVLAN_SETTING_NAME), NULL); - - s_macvlan = nm_connection_get_setting_macvlan(connection); - g_assert(s_macvlan); - - if (!parent_iface) + else return NULL; - - ifname = nm_connection_get_interface_name(connection); - return g_strdup(ifname); } NM_DEVICE_FACTORY_DEFINE_INTERNAL( @@ -629,5 +609,4 @@ NM_DEVICE_FACTORY_DEFINE_INTERNAL( NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVTAP) NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_MACVLAN_SETTING_NAME), factory_class->create_device = create_device; - factory_class->get_connection_parent = get_connection_parent; - factory_class->get_connection_iface = get_connection_iface;); + factory_class->get_connection_parent = get_connection_parent;); diff --git a/src/core/devices/nm-device-ppp.c b/src/core/devices/nm-device-ppp.c index 27566607..f44fe2f0 100644 --- a/src/core/devices/nm-device-ppp.c +++ b/src/core/devices/nm-device-ppp.c @@ -188,7 +188,7 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) s_pppoe = nm_device_get_applied_setting(device, NM_TYPE_SETTING_PPPOE); g_return_val_if_fail(s_pppoe, NM_ACT_STAGE_RETURN_FAILURE); - priv->ppp_mgr = nm_ppp_mgr_start(&((const NMPppMgrConfig){ + priv->ppp_mgr = nm_ppp_mgr_start(&((const NMPppMgrConfig) { .netns = nm_device_get_netns(device), .parent_iface = nm_setting_pppoe_get_parent(s_pppoe), .callback = _ppp_mgr_callback, @@ -380,20 +380,10 @@ get_connection_parent(NMDeviceFactory *factory, NMConnection *connection) nm_assert(nm_connection_is_type(connection, NM_SETTING_PPPOE_SETTING_NAME)); s_pppoe = nm_connection_get_setting_pppoe(connection); - nm_assert(s_pppoe); - - return nm_setting_pppoe_get_parent(s_pppoe); -} - -static char * -get_connection_iface(NMDeviceFactory *factory, NMConnection *connection, const char *parent_iface) -{ - nm_assert(nm_connection_is_type(connection, NM_SETTING_PPPOE_SETTING_NAME)); - - if (!parent_iface) + if (s_pppoe) + return nm_setting_pppoe_get_parent(s_pppoe); + else return NULL; - - return g_strdup(nm_connection_get_interface_name(connection)); } NM_DEVICE_FACTORY_DEFINE_INTERNAL( @@ -403,6 +393,5 @@ NM_DEVICE_FACTORY_DEFINE_INTERNAL( NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_PPP) NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_PPPOE_SETTING_NAME), factory_class->get_connection_parent = get_connection_parent; - factory_class->get_connection_iface = get_connection_iface; factory_class->create_device = create_device; factory_class->match_connection = match_connection;); diff --git a/src/core/devices/nm-device-private.h b/src/core/devices/nm-device-private.h index 3bf5925c..2f73a01b 100644 --- a/src/core/devices/nm-device-private.h +++ b/src/core/devices/nm-device-private.h @@ -115,8 +115,8 @@ gboolean nm_device_sysctl_ip_conf_set(NMDevice *self, NML3ConfigData *nm_device_create_l3_config_data(NMDevice *self, NMIPConfigSource source); -const NML3ConfigData *nm_device_create_l3_config_data_from_connection(NMDevice *self, - NMConnection *connection); +NML3ConfigData *nm_device_create_l3_config_data_from_connection(NMDevice *self, + NMConnection *connection); void nm_device_ip_method_dhcp4_start(NMDevice *self); diff --git a/src/core/devices/nm-device-tun.c b/src/core/devices/nm-device-tun.c index 28b03cec..faab86d0 100644 --- a/src/core/devices/nm-device-tun.c +++ b/src/core/devices/nm-device-tun.c @@ -143,8 +143,7 @@ complete_connection(NMDevice *device, NULL, _("TUN connection"), NULL, - NULL, - TRUE); + NULL); s_tun = nm_connection_get_setting_tun(connection); if (!s_tun) { diff --git a/src/core/devices/nm-device-utils.c b/src/core/devices/nm-device-utils.c index ccb6292b..9fd7ac9d 100644 --- a/src/core/devices/nm-device-utils.c +++ b/src/core/devices/nm-device-utils.c @@ -355,7 +355,7 @@ nm_device_resolve_address(int addr_family, NMDnsSystemdResolved *resolved; info = g_new(ResolveAddrInfo, 1); - *info = (ResolveAddrInfo){ + *info = (ResolveAddrInfo) { .task = nm_g_task_new(NULL, cancellable, nm_device_resolve_address, callback, cb_data), .addr_family = addr_family, .address = nm_ip_addr_init(addr_family, address), diff --git a/src/core/devices/nm-device-vlan.c b/src/core/devices/nm-device-vlan.c index d4630999..59a429ca 100644 --- a/src/core/devices/nm-device-vlan.c +++ b/src/core/devices/nm-device-vlan.c @@ -241,7 +241,7 @@ create_and_realize(NMDevice *device, r = nm_platform_link_vlan_add(nm_device_get_platform(device), iface, parent_ifindex, - &((NMPlatformLnkVlan){ + &((NMPlatformLnkVlan) { .id = vlan_id, .flags = nm_setting_vlan_get_flags(s_vlan), .protocol = protocol, @@ -379,8 +379,7 @@ complete_connection(NMDevice *device, NULL, _("VLAN connection"), NULL, - NULL, - TRUE); + NULL); s_vlan = nm_connection_get_setting_vlan(connection); if (!s_vlan) { @@ -618,43 +617,35 @@ get_connection_parent(NMDeviceFactory *factory, NMConnection *connection) g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_VLAN_SETTING_NAME), NULL); s_vlan = nm_connection_get_setting_vlan(connection); - g_assert(s_vlan); - - parent = nm_setting_vlan_get_parent(s_vlan); - if (parent) - return parent; + if (s_vlan) { + parent = nm_setting_vlan_get_parent(s_vlan); + if (parent) + return parent; + } /* Try the hardware address from the VLAN connection's hardware setting */ s_wired = nm_connection_get_setting_wired(connection); if (s_wired) return nm_setting_wired_get_mac_address(s_wired); - - return NULL; + else + return NULL; } static char * get_connection_iface(NMDeviceFactory *factory, NMConnection *connection, const char *parent_iface) { - const char *ifname; NMSettingVlan *s_vlan; g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_VLAN_SETTING_NAME), NULL); - s_vlan = nm_connection_get_setting_vlan(connection); - g_assert(s_vlan); - if (!parent_iface) return NULL; - ifname = nm_connection_get_interface_name(connection); - if (ifname) - return g_strdup(ifname); - - /* If the connection doesn't specify the interface name for the VLAN - * device, we create one for it using the VLAN ID and the parent - * interface's name. - */ - return nmp_utils_new_vlan_name(parent_iface, nm_setting_vlan_get_id(s_vlan)); + s_vlan = nm_connection_get_setting_vlan(connection); + if (s_vlan) + return nmp_utils_new_vlan_name(parent_iface, nm_setting_vlan_get_id(s_vlan)); + else + return NULL; } NM_DEVICE_FACTORY_DEFINE_INTERNAL( diff --git a/src/core/devices/nm-device-vrf.c b/src/core/devices/nm-device-vrf.c index c3d31347..7dfd6504 100644 --- a/src/core/devices/nm-device-vrf.c +++ b/src/core/devices/nm-device-vrf.c @@ -48,7 +48,7 @@ do_update_properties(NMDeviceVrf *self, const NMPlatformLnkVrf *props) NMPlatformLnkVrf props_null; if (!props) { - props_null = (NMPlatformLnkVrf){}; + props_null = (NMPlatformLnkVrf) {}; props = &props_null; } @@ -184,8 +184,7 @@ complete_connection(NMDevice *device, NULL, _("VRF connection"), NULL, - NULL, - TRUE); + NULL); s_vrf = _nm_connection_get_setting(connection, NM_TYPE_SETTING_VRF); if (!s_vrf) { diff --git a/src/core/devices/nm-device-vxlan.c b/src/core/devices/nm-device-vxlan.c index 6a23d51e..4058287c 100644 --- a/src/core/devices/nm-device-vxlan.c +++ b/src/core/devices/nm-device-vxlan.c @@ -384,8 +384,7 @@ complete_connection(NMDevice *device, NULL, _("VXLAN connection"), NULL, - NULL, - TRUE); + NULL); s_vxlan = nm_connection_get_setting_vxlan(connection); if (!s_vxlan) { @@ -777,27 +776,10 @@ get_connection_parent(NMDeviceFactory *factory, NMConnection *connection) g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_VXLAN_SETTING_NAME), NULL); s_vxlan = nm_connection_get_setting_vxlan(connection); - g_assert(s_vxlan); - - return nm_setting_vxlan_get_parent(s_vxlan); -} - -static char * -get_connection_iface(NMDeviceFactory *factory, NMConnection *connection, const char *parent_iface) -{ - const char *ifname; - NMSettingVxlan *s_vxlan; - - g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_VXLAN_SETTING_NAME), NULL); - - s_vxlan = nm_connection_get_setting_vxlan(connection); - g_assert(s_vxlan); - - if (nm_setting_vxlan_get_parent(s_vxlan) && !parent_iface) + if (s_vxlan) + return nm_setting_vxlan_get_parent(s_vxlan); + else return NULL; - - ifname = nm_connection_get_interface_name(connection); - return g_strdup(ifname); } NM_DEVICE_FACTORY_DEFINE_INTERNAL( @@ -807,5 +789,4 @@ NM_DEVICE_FACTORY_DEFINE_INTERNAL( NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_VXLAN) NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_VXLAN_SETTING_NAME), factory_class->create_device = create_device; - factory_class->get_connection_parent = get_connection_parent; - factory_class->get_connection_iface = get_connection_iface;); + factory_class->get_connection_parent = get_connection_parent;); diff --git a/src/core/devices/nm-device-wireguard.c b/src/core/devices/nm-device-wireguard.c index 00a8c718..4a08192e 100644 --- a/src/core/devices/nm-device-wireguard.c +++ b/src/core/devices/nm-device-wireguard.c @@ -430,7 +430,7 @@ get_extra_rules(NMDevice *device) g_ptr_array_add(extra_rules, nmp_object_new(NMP_OBJECT_TYPE_ROUTING_RULE, - &((const NMPlatformRoutingRule){ + &((const NMPlatformRoutingRule) { .priority = priority, .addr_family = addr_family, .action = FR_ACT_TO_TBL, @@ -440,7 +440,7 @@ get_extra_rules(NMDevice *device) g_ptr_array_add(extra_rules, nmp_object_new(NMP_OBJECT_TYPE_ROUTING_RULE, - &((const NMPlatformRoutingRule){ + &((const NMPlatformRoutingRule) { .priority = priority + 1u, .addr_family = addr_family, .action = FR_ACT_TO_TBL, @@ -588,7 +588,7 @@ _peers_add(NMDeviceWireGuard *self, NMWireGuardPeer *peer) nm_assert(!_peers_find(priv, peer)); peer_data = g_slice_new(PeerData); - *peer_data = (PeerData){ + *peer_data = (PeerData) { .self = self, .peer = nm_wireguard_peer_ref(peer), .ep_resolv = @@ -792,7 +792,7 @@ _peers_resolve_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) switch (g_inet_address_get_family(a)) { case G_SOCKET_FAMILY_IPV4: nm_assert(g_inet_address_get_native_size(a) == sizeof(struct in_addr)); - s->in = (struct sockaddr_in){ + s->in = (struct sockaddr_in) { .sin_family = AF_INET, .sin_port = htons(nm_sock_addr_endpoint_get_port( _nm_wireguard_peer_get_endpoint(peer_data->peer))), @@ -801,7 +801,7 @@ _peers_resolve_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) break; case G_SOCKET_FAMILY_IPV6: nm_assert(g_inet_address_get_native_size(a) == sizeof(struct in6_addr)); - s->in6 = (struct sockaddr_in6){ + s->in6 = (struct sockaddr_in6) { .sin6_family = AF_INET6, .sin6_port = htons(nm_sock_addr_endpoint_get_port( _nm_wireguard_peer_get_endpoint(peer_data->peer))), @@ -985,7 +985,7 @@ _peers_update(NMDeviceWireGuard *self, if (nm_clear_g_cancellable(&peer_data->ep_resolv.cancellable)) _peers_resolving_cnt_decrement(self); - peer_data->ep_resolv = (PeerEndpointResolveData){ + peer_data->ep_resolv = (PeerEndpointResolveData) { .sockaddr = sockaddr, .resolv_fail_count = 0, .cancellable = NULL, @@ -1166,7 +1166,7 @@ _peers_get_platform_list(NMDeviceWireGuardPrivate *priv, prefix = addr_family == AF_INET ? 32 : 128; g_array_append_val(allowed_ips, - ((NMPWireGuardAllowedIP){ + ((NMPWireGuardAllowedIP) { .family = addr_family, .mask = prefix, .addr = addrbin, @@ -1486,7 +1486,7 @@ link_config(NMDeviceWireGuard *self, _peers_update_all(self, s_wg, &peers_removed); - wg_lnk = (NMPlatformLnkWireGuard){}; + wg_lnk = (NMPlatformLnkWireGuard) {}; wg_change_flags = NM_PLATFORM_WIREGUARD_CHANGE_FLAG_NONE; @@ -1733,7 +1733,7 @@ _get_dev2_ip_config(NMDeviceWireGuard *self, int addr_family) } if (addr_family == AF_INET) { - rt.r4 = (NMPlatformIP4Route){ + rt.r4 = (NMPlatformIP4Route) { .network = addrbin.addr4, .plen = prefix, .ifindex = ip_ifindex, @@ -1742,7 +1742,7 @@ _get_dev2_ip_config(NMDeviceWireGuard *self, int addr_family) .metric = route_metric, }; } else { - rt.r6 = (NMPlatformIP6Route){ + rt.r6 = (NMPlatformIP6Route) { .network = addrbin.addr6, .plen = prefix, .ifindex = ip_ifindex, diff --git a/src/core/devices/nm-device-wpan.c b/src/core/devices/nm-device-wpan.c index 7885355d..67f845c8 100644 --- a/src/core/devices/nm-device-wpan.c +++ b/src/core/devices/nm-device-wpan.c @@ -53,8 +53,7 @@ complete_connection(NMDevice *device, NULL, _("WPAN connection"), NULL, - NULL, - TRUE); + NULL); s_wpan = NM_SETTING_WPAN(nm_connection_get_setting(connection, NM_TYPE_SETTING_WPAN)); if (!s_wpan) { diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index 6c5a9b5a..e310a9c6 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -283,6 +283,7 @@ typedef struct { NML3IPv4LL *ipv4ll; NML3IPv4LLRegistration *ipv4ll_registation; GSource *timeout_source; + NMSettingIP4LinkLocal mode; } v4; struct { NML3IPv6LL *ipv6ll; @@ -315,6 +316,7 @@ typedef struct { NMEthtoolPauseState *pause; NMEthtoolChannelsState *channels; NMEthtoolEEEState *eee; + uint32_t fec_mode; } EthtoolState; typedef enum { @@ -615,6 +617,9 @@ typedef struct _NMDevicePrivate { NMPacrunnerConfId *pacrunner_conf_id; + const char *ipv4_method; + const char *ipv6_method; + struct { union { const NMDeviceIPState state; @@ -694,16 +699,6 @@ typedef struct _NMDevicePrivate { bool previous_mode_has : 1; } addrgenmode6_data; - struct { - NMLogDomain log_domain; - guint timeout; - guint watch; - GPid pid; - char *binary; - char *address; - guint deadline; - } gw_ping; - /* Firewall */ FirewallState fw_state : 4; NMFirewalldManager *fw_mgr; @@ -781,6 +776,8 @@ typedef struct _NMDevicePrivate { GVariant *ports_variant; /* Array of port devices D-Bus path */ char *prop_ip_iface; /* IP interface D-Bus property */ + GList *ping_operations; + GSource *ping_timeout; } NMDevicePrivate; G_DEFINE_ABSTRACT_TYPE(NMDevice, nm_device, NM_TYPE_DBUS_OBJECT) @@ -837,6 +834,7 @@ static void _set_mtu(NMDevice *self, guint32 mtu); static void _commit_mtu(NMDevice *self); static void _cancel_activation(NMDevice *self); +static void _dev_ipll4_check_fallback(NMDevice *self, const NML3ConfigData *l3cd_new); static void _dev_ipll4_notify_event(NMDevice *self); static void _dev_ip_state_check(NMDevice *self, int addr_family); @@ -1357,6 +1355,42 @@ _prop_get_ipv6_ra_timeout(NMDevice *self) 0); } +static NMSettingIPConfigRoutedDns +_prop_get_ipvx_routed_dns(NMDevice *self, int addr_family) +{ + NMSettingIPConfig *s_ip; + NMSettingIPConfigRoutedDns val; + int IS_IPv4; + const char *dns_mode; + NMSettingIPConfigRoutedDns fallback_value = NM_SETTING_IP_CONFIG_ROUTED_DNS_NO; + + g_return_val_if_fail(NM_IS_DEVICE(self), NM_SETTING_IP_CONFIG_ROUTED_DNS_NO); + IS_IPv4 = NM_IS_IPv4(addr_family); + + s_ip = nm_device_get_applied_setting(self, + IS_IPv4 ? NM_TYPE_SETTING_IP4_CONFIG + : NM_TYPE_SETTING_IP6_CONFIG); + if (!s_ip) + return NM_SETTING_IP_CONFIG_ROUTED_DNS_NO; + + val = nm_setting_ip_config_get_routed_dns(s_ip); + if (val != NM_SETTING_IP_CONFIG_ROUTED_DNS_DEFAULT) + return val; + + dns_mode = nm_config_data_get_dns_mode(nm_config_get_data(nm_config_get())); + if (nm_streq0(dns_mode, "dnsconfd")) { + fallback_value = NM_SETTING_IP_CONFIG_ROUTED_DNS_YES; + } + + return nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, + IS_IPv4 ? NM_CON_DEFAULT("ipv4.routed-dns") + : NM_CON_DEFAULT("ipv6.routed-dns"), + self, + NM_SETTING_IP_CONFIG_ROUTED_DNS_NO, + NM_SETTING_IP_CONFIG_ROUTED_DNS_YES, + fallback_value); +} + static NMSettingConnectionMdns _prop_get_connection_mdns(NMDevice *self) { @@ -1603,6 +1637,7 @@ _prop_get_ipv4_link_local(NMDevice *self) { NMSettingIP4Config *s_ip4; NMSettingIP4LinkLocal link_local; + const char *method; s_ip4 = nm_device_get_applied_setting(self, NM_TYPE_SETTING_IP4_CONFIG); if (!s_ip4) @@ -1611,6 +1646,8 @@ _prop_get_ipv4_link_local(NMDevice *self) if (NM_IS_DEVICE_LOOPBACK(self)) return NM_SETTING_IP4_LL_DISABLED; + method = nm_setting_ip_config_get_method((NMSettingIPConfig *) s_ip4); + link_local = nm_setting_ip4_config_get_link_local(s_ip4); if (link_local == NM_SETTING_IP4_LL_DEFAULT) { @@ -1620,31 +1657,45 @@ _prop_get_ipv4_link_local(NMDevice *self) NM_CON_DEFAULT("ipv4.link-local"), self, NM_SETTING_IP4_LL_AUTO, - NM_SETTING_IP4_LL_ENABLED, + NM_SETTING_IP4_LL_FALLBACK, NM_SETTING_IP4_LL_DEFAULT); if (link_local == NM_SETTING_IP4_LL_DEFAULT) { /* If there is no global configuration for ipv4.link-local assume auto */ link_local = NM_SETTING_IP4_LL_AUTO; - } else if (link_local == NM_SETTING_IP4_LL_ENABLED - && nm_streq(nm_setting_ip_config_get_method((NMSettingIPConfig *) s_ip4), - NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) { - /* ipv4.method=disabled has higher priority than the global ipv4.link-local=enabled */ + } else if (NM_IN_SET(link_local, NM_SETTING_IP4_LL_ENABLED, NM_SETTING_IP4_LL_FALLBACK) + && nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) { + /* ipv4.method=disabled has higher priority than the global + * ipv4.link-local=enabled / ipv4.link-local=fallback */ link_local = NM_SETTING_IP4_LL_DISABLED; } else if (link_local == NM_SETTING_IP4_LL_DISABLED - && nm_streq(nm_setting_ip_config_get_method((NMSettingIPConfig *) s_ip4), - NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) { + && nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) { /* ipv4.method=link-local has higher priority than the global ipv4.link-local=disabled */ link_local = NM_SETTING_IP4_LL_ENABLED; } } if (link_local == NM_SETTING_IP4_LL_AUTO) { - link_local = nm_streq(nm_setting_ip_config_get_method((NMSettingIPConfig *) s_ip4), - NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL) - ? NM_SETTING_IP4_LL_ENABLED - : NM_SETTING_IP4_LL_DISABLED; + /* ipv4.link-local=auto means enabled for ipv4.method=link-local, + * and disabled for anything else */ + if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) { + link_local = NM_SETTING_IP4_LL_ENABLED; + } else { + link_local = NM_SETTING_IP4_LL_DISABLED; + } + } + + if (link_local == NM_SETTING_IP4_LL_FALLBACK + && nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) { + /* ipv4.link-local=fallback with ipv4.method=link-local will + * always be on anyway, simplify logic */ + link_local = NM_SETTING_IP4_LL_ENABLED; } + nm_assert(NM_IN_SET(link_local, + NM_SETTING_IP4_LL_DISABLED, + NM_SETTING_IP4_LL_ENABLED, + NM_SETTING_IP4_LL_FALLBACK)); + return link_local; } @@ -1806,6 +1857,29 @@ _prop_get_ipvx_may_fail_cached(NMDevice *self, int addr_family, NMTernary *cache return _CACHED_BOOL(cache, _prop_get_ipvx_may_fail(self, addr_family)); } +static gboolean +_prop_get_ipv4_dhcp_ipv6_only_preferred(NMDevice *self) +{ + NMSettingIP4Config *s_ip4; + NMSettingIP4DhcpIpv6OnlyPreferred ipv6_only; + + s_ip4 = nm_device_get_applied_setting(self, NM_TYPE_SETTING_IP4_CONFIG); + if (!s_ip4) + return FALSE; + + ipv6_only = nm_setting_ip4_config_get_dhcp_ipv6_only_preferred(s_ip4); + if (ipv6_only != NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_DEFAULT) + return ipv6_only; + + return nm_config_data_get_connection_default_int64( + NM_CONFIG_GET_DATA, + NM_CON_DEFAULT("ipv4.dhcp-ipv6-only-preferred"), + self, + NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_NO, + NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_YES, + NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_NO); +} + /** * _prop_get_ipvx_dhcp_iaid: * @self: the #NMDevice @@ -2005,6 +2079,59 @@ _prop_get_ipvx_dhcp_hostname_flags(NMDevice *self, int addr_family) return NM_DHCP_HOSTNAME_FLAGS_FQDN_DEFAULT_IP6; } +static gboolean +_prop_get_ipvx_dhcp_send_hostname(NMDevice *self, int addr_family) +{ + const int IS_IPv4 = NM_IS_IPv4(addr_family); + NMSettingIPConfig *s_ip = IS_IPv4 + ? nm_device_get_applied_setting(self, NM_TYPE_SETTING_IP4_CONFIG) + : nm_device_get_applied_setting(self, NM_TYPE_SETTING_IP6_CONFIG); + gboolean send_hostname; + gboolean send_hostname_v2; + + g_return_val_if_fail(s_ip, FALSE); + + send_hostname = nm_setting_ip_config_get_dhcp_send_hostname(s_ip); + send_hostname_v2 = nm_setting_ip_config_get_dhcp_send_hostname_v2(s_ip); + + if (send_hostname_v2 == NM_TERNARY_DEFAULT) { + send_hostname_v2 = nm_config_data_get_connection_default_int64( + NM_CONFIG_GET_DATA, + IS_IPv4 ? NM_CON_DEFAULT("ipv4.dhcp-send-hostname") + : NM_CON_DEFAULT("ipv6.dhcp-send-hostname"), + self, + NM_TERNARY_FALSE, + NM_TERNARY_TRUE, + send_hostname ? NM_TERNARY_TRUE : NM_TERNARY_FALSE); + } + + return send_hostname_v2; +} + +static gboolean +_prop_get_connection_ip_ping_addresses_require_all(NMDevice *self, NMSettingConnection *s_con) +{ + NMTernary ip_ping_addresses_require_all; + const char *s; + + ip_ping_addresses_require_all = nm_setting_connection_get_ip_ping_addresses_require_all(s_con); + + if (ip_ping_addresses_require_all != NM_TERNARY_DEFAULT) { + return ip_ping_addresses_require_all; + } else { + s = nm_config_data_get_connection_default( + NM_CONFIG_GET_DATA, + NM_CON_DEFAULT("connection.ip-ping-addresses-require-all"), + self); + + if (s) { + return _nm_utils_ascii_str_to_bool(s, FALSE); + } + } + + return FALSE; +} + static const char * _prop_get_connection_mud_url(NMDevice *self, NMSettingConnection *s_con) { @@ -2564,6 +2691,19 @@ _ethtool_features_reset(NMDevice *self, NMPlatform *platform, EthtoolState *etht } static void +_ethtool_fec_reset(NMDevice *self, NMPlatform *platform, EthtoolState *ethtool_state) +{ + if (ethtool_state->fec_mode) { + if (!nm_platform_ethtool_set_fec_mode(platform, + ethtool_state->ifindex, + ethtool_state->fec_mode)) + _LOGW(LOGD_DEVICE, "ethtool: failure resetting FEC"); + else + _LOGD(LOGD_DEVICE, "ethtool: FEC successfully reset"); + } +} + +static void _ethtool_features_set(NMDevice *self, NMPlatform *platform, EthtoolState *ethtool_state, @@ -2595,6 +2735,55 @@ _ethtool_features_set(NMDevice *self, } static void +_ethtool_fec_set(NMDevice *self, + NMPlatform *platform, + EthtoolState *ethtool_state, + NMSettingEthtool *s_ethtool) +{ + uint32_t old_fec_mode; + uint32_t fec_mode = NM_SETTING_ETHTOOL_FEC_MODE_NONE; + GHashTable *hash; + GHashTableIter iter; + const char *name; + GVariant *variant; + + nm_assert(NM_IS_DEVICE(self)); + nm_assert(NM_IS_PLATFORM(platform)); + nm_assert(NM_IS_SETTING_ETHTOOL(s_ethtool)); + nm_assert(ethtool_state); + nm_assert(!ethtool_state->fec_mode); + + hash = _nm_setting_option_hash(NM_SETTING(s_ethtool), FALSE); + if (!hash) + return; + + 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); + } + + 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_set_fec_mode(platform, ethtool_state->ifindex, fec_mode)) + _LOGW(LOGD_DEVICE, "ethtool: failure setting FEC %d", fec_mode); + else { + _LOGD(LOGD_DEVICE, "ethtool: FEC %d successfully set", fec_mode); + ethtool_state->fec_mode = old_fec_mode; + } +} + +static void _ethtool_coalesce_reset(NMDevice *self, NMPlatform *platform, EthtoolState *ethtool_state) { gs_free NMEthtoolCoalesceState *coalesce = NULL; @@ -3075,6 +3264,7 @@ _ethtool_state_reset(NMDevice *self) _ethtool_pause_reset(self, platform, ethtool_state); _ethtool_channels_reset(self, platform, ethtool_state); _ethtool_eee_reset(self, platform, ethtool_state); + _ethtool_fec_reset(self, platform, ethtool_state); } static void @@ -3111,9 +3301,11 @@ _ethtool_state_set(NMDevice *self) _ethtool_pause_set(self, platform, ethtool_state, s_ethtool); _ethtool_channels_set(self, platform, ethtool_state, s_ethtool); _ethtool_eee_set(self, platform, ethtool_state, s_ethtool); + _ethtool_fec_set(self, platform, ethtool_state, s_ethtool); if (ethtool_state->features || ethtool_state->coalesce || ethtool_state->ring - || ethtool_state->pause || ethtool_state->channels || ethtool_state->eee) + || ethtool_state->pause || ethtool_state->channels || ethtool_state->eee + || ethtool_state->fec_mode != 0) priv->ethtool_state = g_steal_pointer(ðtool_state); } @@ -3124,7 +3316,7 @@ link_properties_fill_from_setting(NMDevice *self, NMPlatformLinkProps *props) NMSettingLink *s_link; gint64 v; - *props = (NMPlatformLinkProps){}; + *props = (NMPlatformLinkProps) {}; s_link = nm_device_get_applied_setting(self, NM_TYPE_SETTING_LINK); if (!s_link) @@ -3336,7 +3528,7 @@ nm_device_create_l3_config_data(NMDevice *self, NMIPConfigSource source) return nm_l3_config_data_new(nm_device_get_multi_index(self), ifindex, source); } -const NML3ConfigData * +NML3ConfigData * nm_device_create_l3_config_data_from_connection(NMDevice *self, NMConnection *connection) { NML3ConfigData *l3cd; @@ -4610,15 +4802,6 @@ _dev_l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, N nm_assert(l3cfg == priv->l3cfg); switch (notify_data->notify_type) { - case NM_L3_CONFIG_NOTIFY_TYPE_L3CD_CHANGED: - if (notify_data->l3cd_changed.commited) { - g_signal_emit(self, - signals[L3CD_CHANGED], - 0, - notify_data->l3cd_changed.l3cd_old, - notify_data->l3cd_changed.l3cd_new); - } - return; case NM_L3_CONFIG_NOTIFY_TYPE_ACD_EVENT: { const NML3AcdAddrInfo *addr_info = ¬ify_data->acd_event.info; @@ -4646,16 +4829,25 @@ _dev_l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, N const NML3ConfigData *l3cd; NMDeviceState state = nm_device_get_state(self); + l3cd = nm_l3cfg_get_combined_l3cd(l3cfg, TRUE); if (state >= NM_DEVICE_STATE_IP_CONFIG && state < NM_DEVICE_STATE_DEACTIVATING) { /* FIXME(l3cfg): MTU handling should be moved to l3cfg. */ - l3cd = nm_l3cfg_get_combined_l3cd(l3cfg, TRUE); if (l3cd) priv->ip6_mtu = nm_l3_config_data_get_ip6_mtu(l3cd); _commit_mtu(self); } + _dev_ipll4_check_fallback(self, l3cd); return; } case NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT: + if (notify_data->commit.l3cd_changed) { + g_signal_emit(self, + signals[L3CD_CHANGED], + 0, + notify_data->commit.l3cd_old, + notify_data->commit.l3cd_new); + } + if (priv->ipshared_data_4.state == NM_DEVICE_IP_STATE_PENDING && !priv->ipshared_data_4.v4.dnsmasq_manager && priv->ipshared_data_4.v4.l3cd) { _dev_ipshared4_spawn_dnsmasq(self); @@ -5635,6 +5827,8 @@ nm_device_get_route_metric_default(NMDeviceType device_type) return 400; case NM_DEVICE_TYPE_MACVLAN: return 410; + case NM_DEVICE_TYPE_IPVLAN: + return 420; case NM_DEVICE_TYPE_BRIDGE: return 425; case NM_DEVICE_TYPE_TUN: @@ -7971,9 +8165,9 @@ sriov_op_queue(NMDevice *self, * grace period we pull the plug and cancel it. */ op = g_slice_new(SriovOp); - *op = (SriovOp){ + *op = (SriovOp) { .sriov_params = - (NMPlatformSriovParams){ + (NMPlatformSriovParams) { .num_vfs = num_vfs, .autoprobe = autoprobe, .eswitch_mode = (_NMSriovEswitchMode) eswitch_mode, @@ -8554,7 +8748,7 @@ port_state_changed(NMDevice *port, /** * nm_device_controller_add_port: * @self: the controller device - * @port: the port device to attach as port + * @port: the port device to attach as port * @configure: pass %TRUE if the port should be configured by the controller, or * %FALSE if it is already configured outside NetworkManager * @@ -10722,6 +10916,25 @@ _dev_ipll4_start(NMDevice *self) nm_l3_ipv4ll_register_new(priv->ipll_data_4.v4.ipv4ll, timeout_msec); } +static void +_dev_ipll4_check_fallback(NMDevice *self, const NML3ConfigData *l3cd_new) +{ + gboolean has_non_ll; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + + if (!l3cd_new || priv->ipll_data_4.v4.mode != NM_SETTING_IP4_LL_FALLBACK) { + return; + } + + has_non_ll = nm_l3_config_data_get_flags(l3cd_new) & NM_L3_CONFIG_DAT_FLAGS_HAS_IPV4_NON_LL; + _LOGT_ipll(AF_INET, "%s fallback", has_non_ll ? "cleanup" : "start"); + if (has_non_ll) { + _dev_ipllx_cleanup(self, AF_INET); + } else { + _dev_ipll4_start(self); + } +} + /*****************************************************************************/ static const char * @@ -10963,8 +11176,8 @@ _dev_ipmanual_check_ready(NMDevice *self) static void _dev_ipmanual_start(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; if (priv->ipmanual_data.state_4 != NM_DEVICE_IP_STATE_NONE || priv->ipmanual_data.state_6 != NM_DEVICE_IP_STATE_NONE) @@ -10974,6 +11187,13 @@ _dev_ipmanual_start(NMDevice *self) l3cd = nm_device_create_l3_config_data_from_connection(self, nm_device_get_applied_connection(self)); + + if (_prop_get_ipvx_routed_dns(self, AF_INET) == NM_SETTING_IP_CONFIG_ROUTED_DNS_YES) { + nm_l3_config_data_set_routed_dns(l3cd, AF_INET, TRUE); + } + if (_prop_get_ipvx_routed_dns(self, AF_INET6) == NM_SETTING_IP_CONFIG_ROUTED_DNS_YES) { + nm_l3_config_data_set_routed_dns(l3cd, AF_INET6, TRUE); + } } if (!l3cd) { @@ -11130,6 +11350,8 @@ _dev_ipdhcpx_notify(NMDhcpClient *client, const NMDhcpClientNotifyData *notify_d const NML3ConfigData *dhcp_l3cd = priv->l3cds[L3_CONFIG_DATA_TYPE_DHCP_X(IS_IPv4)].d; _LOGT_ipdhcp(addr_family, "lease lost"); + _dev_ipdhcpx_set_state(self, addr_family, NM_DEVICE_IP_STATE_PENDING); + _dev_ip_state_check_async(self, addr_family); if (dhcp_l3cd && nm_l3cfg_remove_config( priv->l3cfg, @@ -11273,7 +11495,8 @@ _dev_ipdhcpx_start(NMDevice *self, int addr_family) gboolean hostname_is_fqdn; gboolean send_client_id; guint8 dscp; - gboolean dscp_explicit = FALSE; + gboolean dscp_explicit = FALSE; + gboolean ipv6_only_pref = FALSE; client_id = _prop_get_ipv4_dhcp_client_id(self, connection, hwaddr, &send_client_id); dscp = _prop_get_ipv4_dhcp_dscp(self, &dscp_explicit); @@ -11292,7 +11515,18 @@ _dev_ipdhcpx_start(NMDevice *self, int addr_family) hostname = nm_setting_ip_config_get_dhcp_hostname(s_ip); } - config = (NMDhcpClientConfig){ + if (_prop_get_ipv4_dhcp_ipv6_only_preferred(self)) { + if (nm_streq0(priv->ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) { + _LOGI_ipdhcp( + addr_family, + "not requesting the \"IPv6-only preferred\" option because IPv6 is disabled"); + } else { + _LOGD_ipdhcp(addr_family, "requesting the \"IPv6-only preferred\" option"); + ipv6_only_pref = TRUE; + } + } + + config = (NMDhcpClientConfig) { .addr_family = AF_INET, .l3cfg = nm_device_get_l3cfg(self), .iface = nm_device_get_ip_iface(self), @@ -11300,7 +11534,7 @@ _dev_ipdhcpx_start(NMDevice *self, int addr_family) .uuid = nm_connection_get_uuid(connection), .hwaddr = hwaddr, .bcast_hwaddr = bcast_hwaddr, - .send_hostname = nm_setting_ip_config_get_dhcp_send_hostname(s_ip), + .send_hostname = _prop_get_ipvx_dhcp_send_hostname(self, AF_INET), .hostname = hostname, .hostname_flags = _prop_get_ipvx_dhcp_hostname_flags(self, AF_INET), .client_id = client_id, @@ -11312,11 +11546,12 @@ _dev_ipdhcpx_start(NMDevice *self, int addr_family) .reject_servers = reject_servers, .v4 = { - .request_broadcast = request_broadcast, - .acd_timeout_msec = _prop_get_ipv4_dad_timeout(self), - .send_client_id = send_client_id, - .dscp = dscp, - .dscp_explicit = dscp_explicit, + .request_broadcast = request_broadcast, + .acd_timeout_msec = _prop_get_ipv4_dad_timeout(self), + .send_client_id = send_client_id, + .dscp = dscp, + .dscp_explicit = dscp_explicit, + .ipv6_only_preferred = ipv6_only_pref, }, .previous_lease = priv->l3cds[L3_CONFIG_DATA_TYPE_DHCP_X(IS_IPv4)].d, }; @@ -11333,13 +11568,13 @@ _dev_ipdhcpx_start(NMDevice *self, int addr_family) iaid = _prop_get_ipvx_dhcp_iaid(self, AF_INET6, connection, FALSE, &iaid_explicit); duid = _prop_get_ipv6_dhcp_duid(self, connection, hwaddr, &enforce_duid); - config = (NMDhcpClientConfig){ + config = (NMDhcpClientConfig) { .addr_family = AF_INET6, .l3cfg = nm_device_get_l3cfg(self), .iface = nm_device_get_ip_iface(self), .iface_type_log = nm_device_get_type_desc_for_log(self), .uuid = nm_connection_get_uuid(connection), - .send_hostname = nm_setting_ip_config_get_dhcp_send_hostname(s_ip), + .send_hostname = _prop_get_ipvx_dhcp_send_hostname(self, AF_INET6), .hostname = nm_setting_ip_config_get_dhcp_hostname(s_ip), .hostname_flags = _prop_get_ipvx_dhcp_hostname_flags(self, AF_INET6), .client_id = duid, @@ -12629,6 +12864,9 @@ _dev_sysctl_save_ip6_properties(NMDevice *self) if (!ifname) return; + if (!g_file_test("/proc/sys/net/ipv6", G_FILE_TEST_IS_DIR)) + return; + for (i = 0; i < G_N_ELEMENTS(ip6_properties_to_save); i++) { value = nm_platform_sysctl_ip_conf_get(platform, AF_INET6, ifname, ip6_properties_to_save[i]); @@ -12648,6 +12886,9 @@ _dev_sysctl_restore_ip6_properties(NMDevice *self) gpointer key; gpointer value; + if (!g_file_test("/proc/sys/net/ipv6", G_FILE_TEST_IS_DIR)) + return; + g_hash_table_iter_init(&iter, priv->ip6_saved_properties); while (g_hash_table_iter_next(&iter, &key, &value)) nm_device_sysctl_ip_conf_set(self, AF_INET6, key, value); @@ -12769,7 +13010,7 @@ get_ip_method_auto(NMDevice *self, int addr_family) } static void -activate_stage3_ip_config_for_addr_family(NMDevice *self, int addr_family, const char *method) +activate_stage3_ip_config_for_addr_family(NMDevice *self, int addr_family) { const int IS_IPv4 = NM_IS_IPv4(addr_family); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); @@ -12819,30 +13060,31 @@ activate_stage3_ip_config_for_addr_family(NMDevice *self, int addr_family, const goto out_devip; if (IS_IPv4) { - if (_prop_get_ipv4_link_local(self) == NM_SETTING_IP4_LL_ENABLED) + priv->ipll_data_4.v4.mode = _prop_get_ipv4_link_local(self); + if (priv->ipll_data_4.v4.mode == NM_SETTING_IP4_LL_ENABLED) _dev_ipll4_start(self); - if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) + if (nm_streq(priv->ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) _dev_ipdhcpx_start(self, AF_INET); - else if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) { + else if (nm_streq(priv->ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) { /* pass */ - } else if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) + } else if (nm_streq(priv->ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) _dev_ipshared4_start(self); - else if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) + else if (nm_streq(priv->ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) priv->ip_data_x[IS_IPv4].is_disabled = TRUE; - else if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) { + else if (nm_streq(priv->ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) { /* pass */ } else nm_assert_not_reached(); } if (!IS_IPv4) { - if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) { + if (nm_streq(priv->ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) { if (!priv->ip_data_x[IS_IPv4].is_disabled) { priv->ip_data_x[IS_IPv4].is_disabled = TRUE; nm_device_sysctl_ip_conf_set(self, AF_INET6, "disable_ipv6", "1"); } - } else if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { + } else if (nm_streq(priv->ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { if (!priv->ip_data_x[IS_IPv4].is_ignore) { priv->ip_data_x[IS_IPv4].is_ignore = TRUE; if (priv->controller) { @@ -12875,15 +13117,15 @@ activate_stage3_ip_config_for_addr_family(NMDevice *self, int addr_family, const } else { _dev_ipll6_start(self); - if (NM_IN_STRSET(method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) + if (NM_IN_STRSET(priv->ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) _dev_ipac6_start(self); - else if (NM_IN_STRSET(method, NM_SETTING_IP6_CONFIG_METHOD_SHARED)) + else if (NM_IN_STRSET(priv->ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_SHARED)) _dev_ipshared6_start(self); - else if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) { + else if (nm_streq(priv->ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) { priv->ipdhcp_data_6.v6.mode = NM_NDISC_DHCP_LEVEL_MANAGED; _dev_ipdhcpx_start(self, AF_INET6); } else - nm_assert(NM_IN_STRSET(method, + nm_assert(NM_IN_STRSET(priv->ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)); } @@ -12984,8 +13226,6 @@ activate_stage3_ip_config(NMDevice *self) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); NMDeviceClass *klass = NM_DEVICE_GET_CLASS(self); int ifindex; - const char *ipv4_method; - const char *ipv6_method; /* stage3 is different from stage1+2. * @@ -13035,17 +13275,17 @@ activate_stage3_ip_config(NMDevice *self) } nm_assert(ifindex <= 0 || priv->fw_state == FIREWALL_STATE_INITIALIZED); - ipv4_method = nm_device_get_effective_ip_config_method(self, AF_INET); - if (nm_streq(ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { + priv->ipv4_method = nm_device_get_effective_ip_config_method(self, AF_INET); + if (nm_streq(priv->ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { /* "auto" usually means DHCPv4 or autoconf6, but it doesn't have to be. Subclasses * can overwrite it. For example, you cannot run DHCPv4 on PPP/WireGuard links. */ - ipv4_method = klass->get_ip_method_auto(self, AF_INET); + priv->ipv4_method = klass->get_ip_method_auto(self, AF_INET); } - ipv6_method = nm_device_get_effective_ip_config_method(self, AF_INET6); + priv->ipv6_method = nm_device_get_effective_ip_config_method(self, AF_INET6); if (!g_file_test("/proc/sys/net/ipv6", G_FILE_TEST_IS_DIR)) { _NMLOG_ip((nm_device_managed_type_is_external(self) - || NM_IN_STRSET(ipv6_method, + || NM_IN_STRSET(priv->ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NM_SETTING_IP6_CONFIG_METHOD_DISABLED, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) @@ -13053,9 +13293,9 @@ activate_stage3_ip_config(NMDevice *self) : LOGL_WARN, AF_INET6, "IPv6 not supported by kernel resulting in \"ipv6.method=disabled\""); - ipv6_method = NM_SETTING_IP6_CONFIG_METHOD_DISABLED; - } else if (nm_streq(ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { - ipv6_method = klass->get_ip_method_auto(self, AF_INET6); + priv->ipv6_method = NM_SETTING_IP6_CONFIG_METHOD_DISABLED; + } else if (nm_streq(priv->ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { + priv->ipv6_method = klass->get_ip_method_auto(self, AF_INET6); } if (priv->ip_data_4.do_reapply) { @@ -13064,7 +13304,7 @@ activate_stage3_ip_config(NMDevice *self) _cleanup_ip_pre(self, AF_INET, CLEANUP_TYPE_KEEP_REAPPLY, - nm_streq(ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)); + nm_streq(priv->ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)); } if (priv->ip_data_6.do_reapply) { _LOGD_ip(AF_INET6, "reapply..."); @@ -13072,7 +13312,7 @@ activate_stage3_ip_config(NMDevice *self) _cleanup_ip_pre(self, AF_INET6, CLEANUP_TYPE_KEEP_REAPPLY, - nm_streq(ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)); + nm_streq(priv->ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)); } if (priv->state < NM_DEVICE_STATE_IP_CONFIG) { @@ -13103,7 +13343,7 @@ activate_stage3_ip_config(NMDevice *self) if (!nm_device_managed_type_is_external(self) && (!klass->ready_for_ip_config || klass->ready_for_ip_config(self, TRUE))) { if (priv->ipmanual_data.state_6 == NM_DEVICE_IP_STATE_NONE - && !NM_IN_STRSET(ipv6_method, + && !NM_IN_STRSET(priv->ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_DISABLED, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { /* Ensure the MTU makes sense. If it was below 1280 the kernel would not @@ -13127,8 +13367,8 @@ activate_stage3_ip_config(NMDevice *self) _dev_ipmanual_start(self); } - activate_stage3_ip_config_for_addr_family(self, AF_INET, ipv4_method); - activate_stage3_ip_config_for_addr_family(self, AF_INET6, ipv6_method); + activate_stage3_ip_config_for_addr_family(self, AF_INET); + activate_stage3_ip_config_for_addr_family(self, AF_INET6); } void @@ -13349,6 +13589,9 @@ _dev_ipshared4_spawn_dnsmasq(NMDevice *self) NMConnection *applied; gs_unref_array GArray *conflicts = NULL; gboolean ready; + NMSettingIPConfig *s_ip4 = NULL; + const char *shared_dhcp_range; + int shared_dhcp_lease_time; nm_assert(priv->ipshared_data_4.v4.firewall_config); nm_assert(priv->ipshared_data_4.v4.dnsmasq_state_id == 0); @@ -13394,9 +13637,14 @@ _dev_ipshared4_spawn_dnsmasq(NMDevice *self) break; } + s_ip4 = nm_device_get_applied_setting(self, NM_TYPE_SETTING_IP4_CONFIG); + shared_dhcp_range = nm_setting_ip_config_get_shared_dhcp_range(s_ip4); + shared_dhcp_lease_time = nm_setting_ip_config_get_shared_dhcp_lease_time(s_ip4); priv->ipshared_data_4.v4.dnsmasq_manager = nm_dnsmasq_manager_new(ip_iface); if (!nm_dnsmasq_manager_start(priv->ipshared_data_4.v4.dnsmasq_manager, priv->ipshared_data_4.v4.l3cd, + shared_dhcp_range, + shared_dhcp_lease_time, announce_android_metered, &error)) { _LOGW_ipshared(AF_INET, "could not start dnsmasq: %s", error->message); @@ -13567,8 +13815,11 @@ _cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gbool _dev_ipdhcpx_cleanup(self, addr_family, !preserve_dhcp || !keep_reapply, FALSE); - if (!IS_IPv4) + if (IS_IPv4) { + priv->ipll_data_4.v4.mode = NM_SETTING_IP4_LL_DISABLED; + } else { _dev_ipac6_cleanup(self); + } _dev_ipllx_cleanup(self, addr_family); @@ -14125,7 +14376,7 @@ impl_device_reapply(NMDBusObject *obj, } reapply_data = g_slice_new(ReapplyData); - *reapply_data = (ReapplyData){ + *reapply_data = (ReapplyData) { .connection = connection, .version_id = version_id, .reapply_flags = reapply_flags, @@ -14708,6 +14959,37 @@ _dispatcher_complete_proceed_state(NMDispatcherCallId *call_id, gpointer user_da /*****************************************************************************/ +typedef struct { + NMLogDomain log_domain; + NMDevice *device; + gboolean ping_addresses_require_all; + GSource *watch; + GPid pid; + char *binary; + char *address; + guint deadline; +} PingOperation; + +static PingOperation * +ping_operation_new(NMDevice *self, + NMLogDomain log_domain, + const char *address, + const char *ping_binary, + guint ping_timeout, + gboolean ip_ping_addresses_require_all) +{ + PingOperation *ping_op = g_new0(PingOperation, 1); + + ping_op->device = self; + ping_op->log_domain = log_domain; + ping_op->address = g_strdup(address); + ping_op->binary = g_strdup(ping_binary); + ping_op->deadline = ping_timeout + 10; + ping_op->ping_addresses_require_all = ip_ping_addresses_require_all; + + return ping_op; +} + static void ip_check_pre_up(NMDevice *self) { @@ -14730,49 +15012,50 @@ ip_check_pre_up(NMDevice *self) } static void -ip_check_gw_ping_cleanup(NMDevice *self) +cleanup_ping_operation(PingOperation *ping_op) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - nm_clear_g_source(&priv->gw_ping.watch); - nm_clear_g_source(&priv->gw_ping.timeout); + if (ping_op->watch) { + nm_clear_g_source_inst(&ping_op->watch); + } - if (priv->gw_ping.pid) { - nm_utils_kill_child_async(priv->gw_ping.pid, + if (ping_op->pid) { + nm_utils_kill_child_async(ping_op->pid, SIGTERM, - priv->gw_ping.log_domain, + ping_op->log_domain, "ping", 1000, NULL, NULL); - priv->gw_ping.pid = 0; + ping_op->pid = 0; } - nm_clear_g_free(&priv->gw_ping.binary); - nm_clear_g_free(&priv->gw_ping.address); + nm_clear_g_free(&ping_op->binary); + nm_clear_g_free(&ping_op->address); + + g_free(ping_op); } static gboolean -spawn_ping(NMDevice *self) +spawn_ping_for_operation(NMDevice *self, PingOperation *ping_op) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); gs_free char *str_timeout = NULL; gs_free char *tmp_str = NULL; - const char *args[] = {priv->gw_ping.binary, + const char *args[] = {ping_op->binary, "-I", nm_device_get_ip_iface(self), "-c", "1", "-w", NULL, - priv->gw_ping.address, + ping_op->address, NULL}; gs_free_error GError *error = NULL; gboolean ret; - args[6] = str_timeout = g_strdup_printf("%u", priv->gw_ping.deadline); - tmp_str = g_strjoinv(" ", (char **) args); - _LOGD(priv->gw_ping.log_domain, "ping: running '%s'", tmp_str); + args[6] = str_timeout = g_strdup_printf("%u", ping_op->deadline); + + tmp_str = g_strjoinv(" ", (char **) args); + _LOGD(ping_op->log_domain, "ping: running '%s'", tmp_str); ret = g_spawn_async("/", (char **) args, @@ -14780,14 +15063,13 @@ spawn_ping(NMDevice *self) G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, - &priv->gw_ping.pid, + &ping_op->pid, &error); - if (!ret) { - _LOGW(priv->gw_ping.log_domain, - "ping: could not spawn %s: %s", - priv->gw_ping.binary, - error->message); + if (ret) { + ping_op->watch = nm_g_child_watch_add_source(ping_op->pid, ip_check_ping_watch_cb, ping_op); + } else { + _LOGD(ping_op->log_domain, "ping: could not spawn %s: %s", ping_op->binary, error->message); } return ret; @@ -14796,16 +15078,19 @@ spawn_ping(NMDevice *self) static gboolean respawn_ping_cb(gpointer user_data) { - NMDevice *self = NM_DEVICE(user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + PingOperation *ping_op = (PingOperation *) user_data; + NMDevice *self = ping_op->device; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - priv->gw_ping.watch = 0; + nm_clear_g_source_inst(&ping_op->watch); - if (spawn_ping(self)) { - priv->gw_ping.watch = g_child_watch_add(priv->gw_ping.pid, ip_check_ping_watch_cb, self); - } else { - ip_check_gw_ping_cleanup(self); - ip_check_pre_up(self); + if (!spawn_ping_for_operation(self, ping_op)) { + cleanup_ping_operation(ping_op); + priv->ping_operations = g_list_remove(priv->ping_operations, ping_op); + + if (g_list_length(priv->ping_operations) == 0) { + ip_check_pre_up(self); + } } return FALSE; @@ -14814,34 +15099,64 @@ respawn_ping_cb(gpointer user_data) static void ip_check_ping_watch_cb(GPid pid, int status, gpointer user_data) { - NMDevice *self = NM_DEVICE(user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMLogDomain log_domain = priv->gw_ping.log_domain; - gboolean success = FALSE; + PingOperation *ping_op = (PingOperation *) user_data; + NMDevice *self = ping_op->device; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gboolean success = FALSE; - if (!priv->gw_ping.watch) + if (!ping_op->watch) return; - priv->gw_ping.watch = 0; - priv->gw_ping.pid = 0; + + nm_clear_g_source_inst(&ping_op->watch); + ping_op->pid = 0; if (WIFEXITED(status)) { if (WEXITSTATUS(status) == 0) { - _LOGD(log_domain, "ping: gateway ping succeeded"); + _LOGD(ping_op->log_domain, "ping: ping succeeded on %s", ping_op->address); success = TRUE; } else { - _LOGW(log_domain, "ping: gateway ping failed with error code %d", WEXITSTATUS(status)); + _LOGD(ping_op->log_domain, + "ping: ping failed with error code %d on %s", + WEXITSTATUS(status), + ping_op->address); } - } else - _LOGW(log_domain, "ping: stopped unexpectedly with status %d", status); + } else { + _LOGD(ping_op->log_domain, + "ping: stopped unexpectedly with status %d on %s", + status, + ping_op->address); + } if (success) { - /* We've got connectivity, proceed to pre_up */ - ip_check_gw_ping_cleanup(self); - ip_check_pre_up(self); + 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, + "ping: ip-ping-addresses requires all, all ping checks on ip-ping-addresses " + "succeeded"); + if (priv->ping_timeout) + nm_clear_g_source_inst(&priv->ping_timeout); + ip_check_pre_up(self); + } + } else { + nm_assert(priv->ping_operations); + + g_list_free_full(priv->ping_operations, (GDestroyNotify) cleanup_ping_operation); + priv->ping_operations = NULL; + + if (priv->ping_timeout) + nm_clear_g_source_inst(&priv->ping_timeout); + + _LOGD(ping_op->log_domain, + "ping: ip-ping-addresses requires any, one ping check on ip-ping-addresses " + "succeeded"); + ip_check_pre_up(self); + } } else { /* If ping exited with an error it may have returned early, * wait 1 second and restart it */ - priv->gw_ping.watch = g_timeout_add_seconds(1, respawn_ping_cb, self); + ping_op->watch = nm_g_timeout_add_seconds_source(1, respawn_ping_cb, ping_op); } } @@ -14851,39 +15166,31 @@ ip_check_ping_timeout_cb(gpointer user_data) NMDevice *self = NM_DEVICE(user_data); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - priv->gw_ping.timeout = 0; + _LOGW(LOGD_DEVICE, "ping timeout: unreachable gateway or ip-ping-addresses"); - _LOGW(priv->gw_ping.log_domain, "ping: gateway ping timed out"); + if (priv->ping_operations) { + g_list_free_full(priv->ping_operations, (GDestroyNotify) cleanup_ping_operation); + priv->ping_operations = NULL; + } - ip_check_gw_ping_cleanup(self); + if (priv->ping_timeout) + nm_clear_g_source_inst(&priv->ping_timeout); ip_check_pre_up(self); + return FALSE; } static gboolean -start_ping(NMDevice *self, - NMLogDomain log_domain, - const char *binary, - const char *address, - guint timeout) +start_ping(NMDevice *self, PingOperation *ping_op) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - g_return_val_if_fail(priv->gw_ping.watch == 0, FALSE); - g_return_val_if_fail(priv->gw_ping.timeout == 0, FALSE); - - priv->gw_ping.log_domain = log_domain; - priv->gw_ping.address = g_strdup(address); - priv->gw_ping.binary = g_strdup(binary); - priv->gw_ping.deadline = timeout + 10; /* the proper termination is enforced by a timer */ - - if (spawn_ping(self)) { - priv->gw_ping.watch = g_child_watch_add(priv->gw_ping.pid, ip_check_ping_watch_cb, self); - priv->gw_ping.timeout = g_timeout_add_seconds(timeout, ip_check_ping_timeout_cb, self); + if (spawn_ping_for_operation(self, ping_op)) { + priv->ping_operations = g_list_append(priv->ping_operations, ping_op); return TRUE; } - ip_check_gw_ping_cleanup(self); + cleanup_ping_operation(ping_op); return FALSE; } @@ -14893,18 +15200,19 @@ nm_device_start_ip_check(NMDevice *self) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); NMConnection *connection; NMSettingConnection *s_con; - guint timeout = 0; - const char *ping_binary = NULL; + guint gw_ping_timeout = 0; + guint ip_ping_timeout = 0; + const char *ping_binary = NULL; char buf[NM_INET_ADDRSTRLEN]; NMLogDomain log_domain = LOGD_IP4; + gboolean ip_ping_addresses_require_all; + gboolean ping_started = FALSE; /* Shouldn't be any active ping here, since IP_CHECK happens after the * first IP method completes. Any subsequently completing IP method doesn't * get checked. */ - g_return_if_fail(!priv->gw_ping.watch); - g_return_if_fail(!priv->gw_ping.timeout); - g_return_if_fail(!priv->gw_ping.pid); + g_return_if_fail(priv->ping_operations == NULL); g_return_if_fail(priv->ip_data_4.state == NM_DEVICE_IP_STATE_READY || priv->ip_data_6.state == NM_DEVICE_IP_STATE_READY); @@ -14913,13 +15221,17 @@ nm_device_start_ip_check(NMDevice *self) s_con = nm_connection_get_setting_connection(connection); g_assert(s_con); - timeout = nm_setting_connection_get_gateway_ping_timeout(s_con); + gw_ping_timeout = nm_setting_connection_get_gateway_ping_timeout(s_con); + ip_ping_addresses_require_all = _prop_get_connection_ip_ping_addresses_require_all(self, s_con); + ip_ping_timeout = nm_setting_connection_get_ip_ping_timeout(s_con); buf[0] = '\0'; - if (timeout) { + if (gw_ping_timeout != 0 && ip_ping_timeout == 0) { const NMPObject *gw; const NML3ConfigData *l3cd; + _LOGD(LOGD_DEVICE, "starting ping gateway..."); + l3cd = priv->l3cfg ? nm_l3cfg_get_combined_l3cd(priv->l3cfg, TRUE) : NULL; if (!l3cd) { /* pass */ @@ -14940,11 +15252,68 @@ nm_device_start_ip_check(NMDevice *self) } } - if (buf[0]) - start_ping(self, log_domain, ping_binary, buf, timeout); + if (buf[0]) { + PingOperation *ping_op = ping_operation_new(self, + log_domain, + buf, + ping_binary, + gw_ping_timeout, + ip_ping_addresses_require_all); - /* If no ping was started, just advance to pre_up */ - if (!priv->gw_ping.pid) + if (start_ping(self, ping_op)) + ping_started = TRUE; + } + + if (gw_ping_timeout == 0 && ip_ping_timeout != 0) { + const NML3ConfigData *l3cd; + guint i; + GArray *ip_ping_addresses = _nm_setting_connection_get_ip_ping_addresses(s_con); + const char *const *strv = nm_strvarray_get_strv_notempty(ip_ping_addresses, NULL); + + _LOGD(LOGD_DEVICE, "starting ping ip addresses..."); + + l3cd = priv->l3cfg ? nm_l3cfg_get_combined_l3cd(priv->l3cfg, TRUE) : NULL; + + if (l3cd) { + for (i = 0; strv[i]; i++) { + const char *s = strv[i]; + struct in_addr ipv4_addr; + struct in6_addr ipv6_addr; + + if (priv->ip_data_4.state == NM_DEVICE_IP_STATE_READY + && inet_pton(AF_INET, (const char *) s, &ipv4_addr)) { + ping_binary = nm_utils_find_helper("ping", "/usr/bin/ping", NULL); + log_domain = LOGD_IP4; + } else if (priv->ip_data_6.state == NM_DEVICE_IP_STATE_READY + && inet_pton(AF_INET6, (const char *) s, &ipv6_addr)) { + ping_binary = nm_utils_find_helper("ping6", "/usr/bin/ping6", NULL); + log_domain = LOGD_IP6; + } else + continue; + + if (s[0]) { + PingOperation *ping_op = ping_operation_new(self, + log_domain, + s, + ping_binary, + ip_ping_timeout, + ip_ping_addresses_require_all); + + if (start_ping(self, ping_op)) + ping_started = TRUE; + } + } + } + } + + if (ping_started) { + priv->ping_timeout = + nm_g_timeout_add_seconds_source(gw_ping_timeout ? gw_ping_timeout : ip_ping_timeout, + ip_check_ping_timeout_cb, + self); + } + /* If no ping was started, just advance to pre_up. */ + else ip_check_pre_up(self); } @@ -16403,7 +16772,14 @@ _cancel_activation(NMDevice *self) } _dispatcher_cleanup(self); - ip_check_gw_ping_cleanup(self); + + if (priv->ping_operations) { + g_list_free_full(priv->ping_operations, (GDestroyNotify) cleanup_ping_operation); + priv->ping_operations = NULL; + } + + if (priv->ping_timeout) + nm_clear_g_source_inst(&priv->ping_timeout); _dev_ip_state_cleanup(self, AF_INET, FALSE); _dev_ip_state_cleanup(self, AF_INET6, FALSE); @@ -16629,6 +17005,9 @@ nm_device_cleanup(NMDevice *self, NMDeviceStateReason reason, CleanupType cleanu priv->promisc_reset = NM_OPTION_BOOL_DEFAULT; } + priv->ipv4_method = NULL; + priv->ipv6_method = NULL; + _cleanup_generic_post(self, reason, cleanup_type); } @@ -16643,6 +17022,9 @@ deactivate_reset_hw_addr(NMDevice *self) static void ip6_managed_setup(NMDevice *self) { + if (!g_file_test("/proc/sys/net/ipv6", G_FILE_TEST_IS_DIR)) + return; + _dev_addrgenmode6_set(self, NM_IN6_ADDR_GEN_MODE_NONE); _dev_sysctl_set_disable_ipv6(self, FALSE); nm_device_sysctl_ip_conf_set(self, AF_INET6, "accept_ra", "0"); @@ -17138,7 +17520,12 @@ _set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason, break; } case NM_DEVICE_STATE_SECONDARIES: - ip_check_gw_ping_cleanup(self); + if (priv->ping_operations) { + g_list_free_full(priv->ping_operations, (GDestroyNotify) cleanup_ping_operation); + priv->ping_operations = NULL; + } + if (priv->ping_timeout) + nm_clear_g_source_inst(&priv->ping_timeout); _LOGD(LOGD_DEVICE, "device entered SECONDARIES state"); break; default: @@ -18382,7 +18769,7 @@ nm_device_get_hostname_from_dns_lookup(NMDevice *self, int addr_family, gboolean resolver = priv->hostname_resolver_x[IS_IPv4]; if (!resolver) { resolver = g_slice_new(HostnameResolver); - *resolver = (HostnameResolver){ + *resolver = (HostnameResolver) { .device = self, .addr_family = addr_family, .state = RESOLVER_WAIT_ADDRESS, @@ -18737,7 +19124,7 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps nm_assert(priv->type == NM_DEVICE_TYPE_UNKNOWN); priv->type = g_value_get_uint(value); nm_assert(priv->type > NM_DEVICE_TYPE_UNKNOWN); - nm_assert(priv->type <= NM_DEVICE_TYPE_HSR); + nm_assert(priv->type <= NM_DEVICE_TYPE_IPVLAN); break; case PROP_LINK_TYPE: /* construct-only */ @@ -19525,6 +19912,9 @@ nm_device_class_init(NMDeviceClass *klass) G_TYPE_BOOLEAN, 0); + /* Signal "l3cd-changed" indicates that the combined layer-3 configuration + * on the device has changed. It is invoked after the new configuration has + * been committed to kernel. */ signals[L3CD_CHANGED] = g_signal_new(NM_DEVICE_L3CD_CHANGED, G_OBJECT_CLASS_TYPE(object_class), G_SIGNAL_RUN_FIRST, diff --git a/src/core/devices/nm-lldp-listener.c b/src/core/devices/nm-lldp-listener.c index 59c8f54c..e08b379a 100644 --- a/src/core/devices/nm-lldp-listener.c +++ b/src/core/devices/nm-lldp-listener.c @@ -397,7 +397,7 @@ lldp_neighbor_new(NMLldpNeighbor *neighbor_nm) } neigh = g_slice_new(LldpNeighbor); - *neigh = (LldpNeighbor){ + *neigh = (LldpNeighbor) { .neighbor_nm = nm_lldp_neighbor_ref(neighbor_nm), .chassis_id_type = chassis_id_type, .chassis_id = g_steal_pointer(&s_chassis_id), @@ -522,7 +522,7 @@ lldp_neighbor_to_variant(LldpNeighbor *neigh) if (len <= 6) continue; - /* skip over leading TLV, OUI and subtype */ + /* skip over leading TLV, OUI and subtype */ #if NM_MORE_ASSERTS > 5 { guint8 check_hdr[] = {0xfe | (((len - 2) >> 8) & 0x01), @@ -721,7 +721,7 @@ nmtst_lldp_parse_from_raw(const guint8 *raw_data, gsize raw_len) g_assert(raw_data); g_assert(raw_len > 0); - lldp_rx = nm_lldp_rx_new(&((NMLldpRXConfig){ + lldp_rx = nm_lldp_rx_new(&((NMLldpRXConfig) { .ifindex = 1, .neighbors_max = MAX_NEIGHBORS, .callback = nmtst_lldp_event_handler, @@ -889,7 +889,7 @@ nm_lldp_listener_new(int ifindex, g_return_val_if_fail(notify_callback, FALSE); self = g_slice_new(NMLldpListener); - *self = (NMLldpListener){ + *self = (NMLldpListener) { .ifindex = ifindex, .notify_callback = notify_callback, .notify_user_data = notify_user_data, @@ -897,7 +897,7 @@ nm_lldp_listener_new(int ifindex, nm_assert(nm_g_main_context_is_thread_default(g_main_context_default())); - lldp_rx = nm_lldp_rx_new(&((NMLldpRXConfig){ + lldp_rx = nm_lldp_rx_new(&((NMLldpRXConfig) { .ifindex = ifindex, .neighbors_max = MAX_NEIGHBORS, .callback = lldp_event_handler, diff --git a/src/core/devices/ovs/nm-device-ovs-interface.c b/src/core/devices/ovs/nm-device-ovs-interface.c index 8aeb8718..06a1da15 100644 --- a/src/core/devices/ovs/nm-device-ovs-interface.c +++ b/src/core/devices/ovs/nm-device-ovs-interface.c @@ -603,7 +603,7 @@ deactivate_async(NMDevice *device, * with a timeout. */ data = g_slice_new(DeactivateData); - *data = (DeactivateData){ + *data = (DeactivateData) { .self = g_object_ref(self), .cancellable = g_object_ref(cancellable), .callback = callback, diff --git a/src/core/devices/ovs/nm-device-ovs-port.c b/src/core/devices/ovs/nm-device-ovs-port.c index 2e8ab717..7eacedb8 100644 --- a/src/core/devices/ovs/nm-device-ovs-port.c +++ b/src/core/devices/ovs/nm-device-ovs-port.c @@ -175,7 +175,7 @@ attach_port(NMDevice *device, } data = g_slice_new(AttachPortData); - *data = (AttachPortData){ + *data = (AttachPortData) { .device = g_object_ref(device), .port = g_object_ref(port), .cancellable = g_object_ref(cancellable), @@ -233,7 +233,7 @@ detach_port(NMDevice *device, AttachPortData *data; data = g_slice_new(AttachPortData); - *data = (AttachPortData){ + *data = (AttachPortData) { .device = g_object_ref(device), .port = g_object_ref(port), .cancellable = nm_g_object_ref(cancellable), diff --git a/src/core/devices/ovs/nm-ovsdb.c b/src/core/devices/ovs/nm-ovsdb.c index 8e32cff5..528d44d8 100644 --- a/src/core/devices/ovs/nm-ovsdb.c +++ b/src/core/devices/ovs/nm-ovsdb.c @@ -205,7 +205,7 @@ static void cleanup_check_ready(NMOvsdb *self); /*****************************************************************************/ #define OVSDB_METHOD_PAYLOAD_MONITOR() \ - (&((const OvsdbMethodPayload){ \ + (&((const OvsdbMethodPayload) { \ .monitor = {}, \ })) @@ -214,7 +214,7 @@ static void cleanup_check_ready(NMOvsdb *self); xinterface, \ xbridge_device, \ xinterface_device) \ - (&((const OvsdbMethodPayload){ \ + (&((const OvsdbMethodPayload) { \ .add_interface = \ { \ .bridge = (xbridge), \ @@ -226,7 +226,7 @@ static void cleanup_check_ready(NMOvsdb *self); })) #define OVSDB_METHOD_PAYLOAD_DEL_INTERFACE(xifname) \ - (&((const OvsdbMethodPayload){ \ + (&((const OvsdbMethodPayload) { \ .del_interface = \ { \ .ifname = (char *) NM_CONSTCAST(char, (xifname)), \ @@ -234,7 +234,7 @@ static void cleanup_check_ready(NMOvsdb *self); })) #define OVSDB_METHOD_PAYLOAD_SET_INTERFACE_MTU(xifname, xmtu) \ - (&((const OvsdbMethodPayload){ \ + (&((const OvsdbMethodPayload) { \ .set_interface_mtu = \ { \ .ifname = (char *) NM_CONSTCAST(char, (xifname)), \ @@ -249,7 +249,7 @@ static void cleanup_check_ready(NMOvsdb *self); xexternal_ids_new, \ xother_config_old, \ xother_config_new) \ - (&((const OvsdbMethodPayload){ \ + (&((const OvsdbMethodPayload) { \ .set_reapply = \ { \ .device_type = xdevice_type, \ @@ -420,7 +420,7 @@ ovsdb_call_method(NMOvsdb *self, ovsdb_try_connect(self); call = g_slice_new(OvsdbMethodCall); - *call = (OvsdbMethodCall){ + *call = (OvsdbMethodCall) { .self = self, .call_id = CALL_ID_UNSPEC, .command = command, @@ -1682,7 +1682,7 @@ _strdict_extract(json_t *strdict, GArray **out_array) } v = nm_g_array_append_new(*out_array, NMUtilsNamedValue); - *v = (NMUtilsNamedValue){ + *v = (NMUtilsNamedValue) { .name = g_strdup(key), .value_str = g_strdup(val), }; @@ -1909,7 +1909,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) gs_free char *strtmp2 = NULL; ovs_interface = g_slice_new(OpenvswitchInterface); - *ovs_interface = (OpenvswitchInterface){ + *ovs_interface = (OpenvswitchInterface) { .interface_uuid = g_strdup(key), .name = g_strdup(name), .type = g_strdup(type), @@ -2040,7 +2040,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) gs_free char *strtmp2 = NULL; ovs_port = g_slice_new(OpenvswitchPort); - *ovs_port = (OpenvswitchPort){ + *ovs_port = (OpenvswitchPort) { .port_uuid = g_strdup(key), .name = g_strdup(name), .connection_uuid = g_strdup(connection_uuid), @@ -2161,7 +2161,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) gs_free char *strtmp2 = NULL; ovs_bridge = g_slice_new(OpenvswitchBridge); - *ovs_bridge = (OpenvswitchBridge){ + *ovs_bridge = (OpenvswitchBridge) { .bridge_uuid = g_strdup(key), .name = g_strdup(name), .connection_uuid = g_strdup(connection_uuid), @@ -2905,7 +2905,7 @@ ovsdb_call_new(NMOvsdbCallback callback, gpointer user_data) OvsdbCall *call; call = g_slice_new(OvsdbCall); - *call = (OvsdbCall){ + *call = (OvsdbCall) { .callback = callback, .user_data = user_data, }; diff --git a/src/core/devices/team/nm-device-team.c b/src/core/devices/team/nm-device-team.c index a4c77f7f..40779c89 100644 --- a/src/core/devices/team/nm-device-team.c +++ b/src/core/devices/team/nm-device-team.c @@ -130,8 +130,7 @@ complete_connection(NMDevice *device, NULL, _("Team connection"), "team", - NULL, - TRUE); + NULL); _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_TEAM); diff --git a/src/core/devices/wifi/nm-device-iwd-p2p.c b/src/core/devices/wifi/nm-device-iwd-p2p.c index fadc6722..184c8ec5 100644 --- a/src/core/devices/wifi/nm-device-iwd-p2p.c +++ b/src/core/devices/wifi/nm-device-iwd-p2p.c @@ -301,8 +301,7 @@ complete_connection(NMDevice *device, setting_name, setting_name, NULL, - NULL, - TRUE); + NULL); return TRUE; } diff --git a/src/core/devices/wifi/nm-device-iwd.c b/src/core/devices/wifi/nm-device-iwd.c index d6e3ed08..fa6e2f9d 100644 --- a/src/core/devices/wifi/nm-device-iwd.c +++ b/src/core/devices/wifi/nm-device-iwd.c @@ -275,7 +275,7 @@ ap_from_network(NMDeviceIwd *self, ssid = g_bytes_new(name, NM_MIN(32u, strlen(name))); - bss_info = (NMSupplicantBssInfo){ + bss_info = (NMSupplicantBssInfo) { .bss_path = bss_path, .last_seen_msec = last_seen_msec, .bssid_valid = TRUE, @@ -1074,8 +1074,7 @@ complete_connection(NMDevice *device, ssid_utf8, ssid_utf8, NULL, - NULL, - TRUE); + NULL); if (hidden) g_object_set(s_wifi, NM_SETTING_WIRELESS_HIDDEN, TRUE, NULL); @@ -3602,7 +3601,7 @@ nm_device_iwd_parse_netconfig(NMDeviceIwd *self, int addr_family, GVariantIter * preferred_lifetime = valid_lifetime; if (addr_family == AF_INET) { - a.a4 = (NMPlatformIP4Address){ + a.a4 = (NMPlatformIP4Address) { .address = addr_bin.addr4, .peer_address = addr_bin.addr4, .plen = plen, @@ -3614,7 +3613,7 @@ nm_device_iwd_parse_netconfig(NMDeviceIwd *self, int addr_family, GVariantIter * .broadcast_address = bcast_bin.addr4, }; } else { - a.a6 = (NMPlatformIP6Address){ + a.a6 = (NMPlatformIP6Address) { .address = addr_bin.addr6, .plen = 128, .timestamp = (valid_lifetime != NM_PLATFORM_LIFETIME_PERMANENT) ? timestamp : 0, @@ -3703,7 +3702,7 @@ nm_device_iwd_parse_netconfig(NMDeviceIwd *self, int addr_family, GVariantIter * } if (addr_family == AF_INET) { - r.r4 = (NMPlatformIP4Route){ + r.r4 = (NMPlatformIP4Route) { .network = dst_addr_str ? dst_addr_bin.addr4 : 0, .plen = dst_addr_str ? dst_plen : 0, .gateway = router_str ? router_bin.addr4 : 0, @@ -3712,7 +3711,7 @@ nm_device_iwd_parse_netconfig(NMDeviceIwd *self, int addr_family, GVariantIter * nm_platform_route_scope_inv(router_str ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK), }; } else { - r.r6 = (NMPlatformIP6Route){ + r.r6 = (NMPlatformIP6Route) { .network = dst_addr_str ? dst_addr_bin.addr6 : nm_ip_addr_zero.addr6, .plen = dst_addr_str ? dst_plen : 0, .gateway = router_str ? router_bin.addr6 : nm_ip_addr_zero.addr6, @@ -3739,7 +3738,7 @@ nm_device_iwd_parse_netconfig(NMDeviceIwd *self, int addr_family, GVariantIter * if (inet_pton(addr_family, str_value, &dns_bin) != 1) goto param_error; - nm_l3_config_data_add_nameserver_detail(l3cd, addr_family, &dns_bin, NULL); + nm_l3_config_data_add_nameserver_addr(l3cd, addr_family, &dns_bin); nm_l3_config_data_set_dns_priority(l3cd, addr_family, NM_DNS_PRIORITY_DEFAULT_NORMAL); } } diff --git a/src/core/devices/wifi/nm-device-olpc-mesh.c b/src/core/devices/wifi/nm-device-olpc-mesh.c index 8e1e779b..b62dc311 100644 --- a/src/core/devices/wifi/nm-device-olpc-mesh.c +++ b/src/core/devices/wifi/nm-device-olpc-mesh.c @@ -111,8 +111,7 @@ complete_connection(NMDevice *device, NULL, _("Mesh"), NULL, - NULL, - FALSE); /* No IPv6 by default */ + NULL); return TRUE; } diff --git a/src/core/devices/wifi/nm-device-wifi-p2p.c b/src/core/devices/wifi/nm-device-wifi-p2p.c index f06383b1..957a2df6 100644 --- a/src/core/devices/wifi/nm-device-wifi-p2p.c +++ b/src/core/devices/wifi/nm-device-wifi-p2p.c @@ -319,8 +319,7 @@ complete_connection(NMDevice *device, setting_name, setting_name, NULL, - NULL, - TRUE); + NULL); return TRUE; } diff --git a/src/core/devices/wifi/nm-device-wifi.c b/src/core/devices/wifi/nm-device-wifi.c index ea65499e..06eee142 100644 --- a/src/core/devices/wifi/nm-device-wifi.c +++ b/src/core/devices/wifi/nm-device-wifi.c @@ -340,7 +340,7 @@ _scan_request_ssids_track(NMDeviceWifiPrivate *priv, const GPtrArray *ssids) d = g_hash_table_lookup(priv->scan_request_ssids_hash, &ssid); if (!d) { d = g_slice_new(ScanRequestSsidData); - *d = (ScanRequestSsidData){ + *d = (ScanRequestSsidData) { .lst = C_LIST_INIT(d->lst), .timestamp_msec = now_msec, .ssid = g_bytes_ref(ssid), @@ -1296,8 +1296,7 @@ complete_connection(NMDevice *device, ssid_utf8, ssid_utf8, NULL, - nm_setting_wireless_get_mac_address(s_wifi) ? NULL : nm_device_get_iface(device), - TRUE); + nm_setting_wireless_get_mac_address(s_wifi) ? NULL : nm_device_get_iface(device)); if (hidden) g_object_set(s_wifi, NM_SETTING_WIRELESS_HIDDEN, TRUE, NULL); diff --git a/src/core/devices/wifi/nm-wifi-utils.c b/src/core/devices/wifi/nm-wifi-utils.c index 8a8d062f..332352ab 100644 --- a/src/core/devices/wifi/nm-wifi-utils.c +++ b/src/core/devices/wifi/nm-wifi-utils.c @@ -1577,19 +1577,17 @@ ip_config_to_iwd_config(int addr_family, GKeyFile *file, NMSettingIPConfig *s_ip if (num) { nm_str_buf_reset(&strbuf); for (i = 0; i < num; i++) { - char sbuf[NM_INET_ADDRSTRLEN]; - NMIPAddr a; - - if (!nm_utils_dnsname_parse_assert(addr_family, - nm_setting_ip_config_get_dns(s_ip, i), - NULL, - &a, - NULL)) + char addrstr[NM_INET_ADDRSTRLEN]; + + if (!nm_dns_uri_parse_plain(addr_family, + nm_setting_ip_config_get_dns(s_ip, i), + addrstr, + NULL)) continue; if (strbuf.len > 0) nm_str_buf_append_c(&strbuf, ' '); - nm_str_buf_append(&strbuf, nm_inet_ntop(addr_family, &a, sbuf)); + nm_str_buf_append(&strbuf, addrstr); } /* It doesn't matter whether we add the DNS under [IPv4] or [IPv6] * except that with method=auto the list will override the diff --git a/src/core/devices/wwan/nm-modem-broadband.c b/src/core/devices/wwan/nm-modem-broadband.c index c03446b9..018e5306 100644 --- a/src/core/devices/wwan/nm-modem-broadband.c +++ b/src/core/devices/wwan/nm-modem-broadband.c @@ -668,6 +668,8 @@ connect_context_step(NMModemBroadband *self) NMSettingGsm *s_gsm = nm_connection_get_setting_gsm(ctx->connection); const char *apn = nm_setting_gsm_get_initial_eps_apn(s_gsm); gboolean do_config = nm_setting_gsm_get_initial_eps_config(s_gsm); + const char *username = nm_setting_gsm_get_initial_eps_username(s_gsm); + const char *password = nm_setting_gsm_get_initial_eps_password(s_gsm); /* assume do_config is true if an APN is set */ if (apn || do_config) { @@ -690,9 +692,28 @@ connect_context_step(NMModemBroadband *self) /* do nothing */ break; } - if (apn) - mm_bearer_properties_set_apn(config, apn); + if (apn) { + MMBearerAllowedAuth allowed_auth = MM_BEARER_ALLOWED_AUTH_UNKNOWN; + mm_bearer_properties_set_apn(config, apn); + mm_bearer_properties_set_user(config, username); + mm_bearer_properties_set_password(config, password); + + if (nm_setting_gsm_get_initial_eps_noauth(s_gsm)) + allowed_auth |= MM_BEARER_ALLOWED_AUTH_NONE; + if (!nm_setting_gsm_get_initial_eps_refuse_pap(s_gsm)) + allowed_auth |= MM_BEARER_ALLOWED_AUTH_PAP; + if (!nm_setting_gsm_get_initial_eps_refuse_chap(s_gsm)) + allowed_auth |= MM_BEARER_ALLOWED_AUTH_CHAP; + if (!nm_setting_gsm_get_initial_eps_refuse_mschap(s_gsm)) + allowed_auth |= MM_BEARER_ALLOWED_AUTH_MSCHAP; + if (!nm_setting_gsm_get_initial_eps_refuse_mschapv2(s_gsm)) + allowed_auth |= MM_BEARER_ALLOWED_AUTH_MSCHAPV2; + if (!nm_setting_gsm_get_initial_eps_refuse_eap(s_gsm)) + allowed_auth |= MM_BEARER_ALLOWED_AUTH_EAP; + + mm_bearer_properties_set_allowed_auth(config, allowed_auth); + } /* * Setting the initial EPS bearer settings is a no-op in * ModemManager if the desired configuration is already active. @@ -896,8 +917,7 @@ complete_connection(NMModem *modem, NULL, _("GSM connection"), NULL, - NULL, - FALSE); /* No IPv6 yet by default */ + NULL); return TRUE; } @@ -917,8 +937,7 @@ complete_connection(NMModem *modem, NULL, _("CDMA connection"), NULL, - iface, - FALSE); /* No IPv6 yet by default */ + iface); return TRUE; } @@ -1116,7 +1135,7 @@ stage3_ip_config_start(NMModem *modem, int addr_family, NMModemIPMethod ip_metho ifindex, NM_IP_CONFIG_SOURCE_WWAN); - address = (NMPlatformIP4Address){ + address = (NMPlatformIP4Address) { .address = address_network, .peer_address = address_network, .plen = mm_bearer_ip_config_get_prefix(self->_priv.ipv4_config), @@ -1127,7 +1146,7 @@ stage3_ip_config_start(NMModem *modem, int addr_family, NMModemIPMethod ip_metho _LOGI(" address %s", nm_platform_ip4_address_to_string(&address, sbuf, sizeof(sbuf))); - route = (NMPlatformIP4Route){ + route = (NMPlatformIP4Route) { .rt_source = NM_IP_CONFIG_SOURCE_WWAN, .gateway = gw, .table_any = TRUE, @@ -1141,7 +1160,7 @@ stage3_ip_config_start(NMModem *modem, int addr_family, NMModemIPMethod ip_metho dns = mm_bearer_ip_config_get_dns(self->_priv.ipv4_config); for (i = 0; dns && dns[i]; i++) { if (nm_inet_parse_bin(AF_INET, dns[i], NULL, &address_network) && address_network > 0) { - nm_l3_config_data_add_nameserver_detail(l3cd, AF_INET, &address_network, NULL); + nm_l3_config_data_add_nameserver_addr(l3cd, AF_INET, &address_network); _LOGI(" DNS %s", dns[i]); } } @@ -1193,7 +1212,7 @@ stage3_ip_config_start(NMModem *modem, int addr_family, NMModemIPMethod ip_metho do_auto = TRUE; if (address_string) { - address = (NMPlatformIP6Address){}; + address = (NMPlatformIP6Address) {}; if (!inet_pton(AF_INET6, address_string, &address.address)) { g_set_error(&error, @@ -1260,7 +1279,7 @@ stage3_ip_config_start(NMModem *modem, int addr_family, NMModemIPMethod ip_metho struct in6_addr addr; if (inet_pton(AF_INET6, dns[i], &addr)) { - nm_l3_config_data_add_nameserver_detail(l3cd, AF_INET6, &addr, NULL); + nm_l3_config_data_add_nameserver_addr(l3cd, AF_INET6, &addr); _LOGI(" DNS %s", dns[i]); } } diff --git a/src/core/devices/wwan/nm-modem-ofono.c b/src/core/devices/wwan/nm-modem-ofono.c index 3e0bbd48..80f966f1 100644 --- a/src/core/devices/wwan/nm-modem-ofono.c +++ b/src/core/devices/wwan/nm-modem-ofono.c @@ -1256,7 +1256,7 @@ handle_settings(NMModemOfono *self, GVariant *v_dict) goto out; } - address = (NMPlatformIP4Address){ + address = (NMPlatformIP4Address) { .ifindex = ifindex, .address = address_network, .addr_source = NM_IP_CONFIG_SOURCE_WWAN, @@ -1315,7 +1315,7 @@ handle_settings(NMModemOfono *self, GVariant *v_dict) } any_good = TRUE; _LOGI("DNS: %s", array[i]); - nm_l3_config_data_add_nameserver_detail(priv->l3cd_4, AF_INET, &address_network, NULL); + nm_l3_config_data_add_nameserver_addr(priv->l3cd_4, AF_INET, &address_network); } if (!any_good) { _LOGW("Settings: 'DomainNameServers': none specified"); diff --git a/src/core/devices/wwan/nm-modem.c b/src/core/devices/wwan/nm-modem.c index 23e7de4a..c4852ea2 100644 --- a/src/core/devices/wwan/nm-modem.c +++ b/src/core/devices/wwan/nm-modem.c @@ -1064,7 +1064,7 @@ nm_modem_act_stage2_config(NMModem *self, NMDevice *device, NMDeviceStateReason else baud_override = 0; - priv->ppp_mgr = nm_ppp_mgr_start(&((const NMPppMgrConfig){ + priv->ppp_mgr = nm_ppp_mgr_start(&((const NMPppMgrConfig) { .netns = nm_device_get_netns(device), .parent_iface = priv->data_port, .callback = _ppp_mgr_callback, diff --git a/src/core/dhcp/nm-dhcp-client.c b/src/core/dhcp/nm-dhcp-client.c index cd6e67e2..18ad4024 100644 --- a/src/core/dhcp/nm-dhcp-client.c +++ b/src/core/dhcp/nm-dhcp-client.c @@ -91,6 +91,11 @@ typedef struct _NMDhcpClientPrivate { union { struct { + /* Timer for restarting DHCP after the IPv6-only timeout */ + GSource *ipv6_only_restart_source; + /* Minimum value accepted for the IPv6-only option. For test/debug only.*/ + guint ipv6_only_min_wait; + struct { NML3CfgCommitTypeHandle *l3cfg_commit_handle; GSource *done_source; @@ -336,7 +341,7 @@ _emit_notify_data(NMDhcpClient *self, const NMDhcpClientNotifyData *notify_data) #define _emit_notify(self, _notify_type, ...) \ _emit_notify_data( \ (self), \ - &((const NMDhcpClientNotifyData){.notify_type = (_notify_type), __VA_ARGS__})) + &((const NMDhcpClientNotifyData) {.notify_type = (_notify_type), __VA_ARGS__})) /*****************************************************************************/ @@ -684,7 +689,7 @@ _acd_check_lease(NMDhcpClient *self, NMOptionBool *out_acd_state) now_msec = nm_utils_get_monotonic_timestamp_msec(); g_array_append_val(priv->v4.acd.reglist, - ((AcdRegListData){ + ((AcdRegListData) { .l3cd = nm_l3_config_data_ref(priv->l3cd_next), .addr = addr, .expiry_msec = now_msec + ACD_REGLIST_GRACE_PERIOD_MSEC, @@ -1375,6 +1380,8 @@ nm_dhcp_client_start(NMDhcpClient *self, GError **error) g_return_val_if_fail(priv->config.uuid, FALSE); nm_assert(!priv->effective_client_id); + priv->is_stopped = FALSE; + IS_IPv4 = NM_IS_IPv4(priv->config.addr_family); if (!IS_IPv4) { @@ -1416,6 +1423,51 @@ nm_dhcp_client_start(NMDhcpClient *self, GError **error) /*****************************************************************************/ +static gboolean +ipv6_only_restart_timeout_cb(gpointer user_data) +{ + NMDhcpClient *self = user_data; + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + gs_free_error GError *error = NULL; + + nm_assert(priv->config.addr_family == AF_INET); + + nm_clear_g_source_inst(&priv->v4.ipv6_only_restart_source); + if (!nm_dhcp_client_start(self, &error)) { + _LOGW("failed to restart the DHCP client after the IPv6-only timeout: %s", error->message); + _emit_notify(self, + NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD, + .it_looks_bad.reason = error->message); + } + + return G_SOURCE_CONTINUE; +} + +/** + * nm_dhcp_client_schedule_ipv6_only_restart(): + * @self: the client + * @timeout: the raw value from the DHCP option + * + * Stops the DHCPv4 client and restarts it after the timeout announced + * by the "IPv6-Only preferred" option. + */ +void +nm_dhcp_client_schedule_ipv6_only_restart(NMDhcpClient *self, guint timeout) +{ + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + nm_assert(priv->config.addr_family == AF_INET); + nm_assert(!priv->is_stopped); + + timeout = NM_MAX(priv->v4.ipv6_only_min_wait, timeout); + _LOGI("received option \"ipv6-only-preferred\": stopping DHCPv4 for %u seconds", timeout); + + nm_dhcp_client_stop(self, FALSE); + nm_clear_g_source_inst(&priv->no_lease_timeout_source); + priv->v4.ipv6_only_restart_source = + nm_g_timeout_add_seconds_source(timeout, ipv6_only_restart_timeout_cb, self); +} + void nm_dhcp_client_stop_existing(const char *pid_file, const char *binary_name) { @@ -1488,7 +1540,10 @@ nm_dhcp_client_stop(NMDhcpClient *self, gboolean release) if (priv->is_stopped) return; + nm_clear_pointer(&priv->effective_client_id, g_bytes_unref); nm_clear_g_source_inst(&priv->previous_lease_timeout_source); + if (priv->config.addr_family == AF_INET) + nm_clear_g_source_inst(&priv->v4.ipv6_only_restart_source); priv->is_stopped = TRUE; @@ -1934,6 +1989,8 @@ static void set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(object); + const char *str; + guint min_wait; switch (prop_id) { case PROP_CONFIG: @@ -1943,7 +2000,8 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps /* I know, this is technically not necessary. It just feels nicer to * explicitly initialize the respective union member. */ if (NM_IS_IPv4(priv->config.addr_family)) { - priv->v4 = (typeof(priv->v4)){ + priv->v4 = (typeof(priv->v4)) { + .ipv6_only_min_wait = NM_DHCP_MIN_V6ONLY_WAIT_DEFAULT, .acd = { .addr = INADDR_ANY, @@ -1952,8 +2010,16 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps .done_source = NULL, }, }; + + str = g_getenv("NM_TEST_IPV6_ONLY_MIN_WAIT"); + if (str) { + min_wait = _nm_utils_ascii_str_to_int64(str, 10, 1, G_MAXUINT, 0); + if (min_wait != 0) { + priv->v4.ipv6_only_min_wait = min_wait; + } + } } else { - priv->v6 = (typeof(priv->v6)){ + priv->v6 = (typeof(priv->v6)) { .lladdr_timeout_source = NULL, }; } @@ -1990,13 +2056,13 @@ dispose(GObject *object) nm_clear_g_source_inst(&priv->previous_lease_timeout_source); nm_clear_g_source_inst(&priv->no_lease_timeout_source); - if (!NM_IS_IPv4(priv->config.addr_family)) { + if (priv->config.addr_family == AF_INET) { + nm_clear_g_source_inst(&priv->v4.ipv6_only_restart_source); + } else { nm_clear_g_source_inst(&priv->v6.lladdr_timeout_source); nm_clear_g_source_inst(&priv->v6.dad_timeout_source); } - nm_clear_pointer(&priv->effective_client_id, g_bytes_unref); - nm_assert(!priv->watch_source); nm_assert(!priv->l3cd_next); nm_assert(!priv->l3cd_curr); diff --git a/src/core/dhcp/nm-dhcp-client.h b/src/core/dhcp/nm-dhcp-client.h index 8c685faf..a7b6ae98 100644 --- a/src/core/dhcp/nm-dhcp-client.h +++ b/src/core/dhcp/nm-dhcp-client.h @@ -27,6 +27,8 @@ #define NM_DHCP_CLIENT_NOTIFY "dhcp-notify" +#define NM_DHCP_MIN_V6ONLY_WAIT_DEFAULT 300u /* (seconds). RFC 8925, section 3.4 */ + typedef enum { NM_DHCP_CLIENT_EVENT_TYPE_UNSPECIFIED, @@ -172,6 +174,8 @@ typedef struct { /* Whether to send or not the client identifier */ bool send_client_id : 1; + /* Request and honor the "IPv6-only Preferred" option (RFC 8925).*/ + bool ipv6_only_preferred : 1; } v4; struct { /* If set, the DUID from the connection is used; otherwise @@ -246,6 +250,8 @@ const NML3ConfigData *nm_dhcp_client_get_lease(NMDhcpClient *self, gboolean igno void nm_dhcp_client_stop(NMDhcpClient *self, gboolean release); +void nm_dhcp_client_schedule_ipv6_only_restart(NMDhcpClient *self, guint timeout); + /* Backend helpers for subclasses */ void nm_dhcp_client_stop_existing(const char *pid_file, const char *binary_name); @@ -305,7 +311,6 @@ typedef struct { GType nm_dhcp_nettools_get_type(void); -extern const NMDhcpClientFactory _nm_dhcp_client_factory_dhcpcanon; extern const NMDhcpClientFactory _nm_dhcp_client_factory_dhclient; extern const NMDhcpClientFactory _nm_dhcp_client_factory_dhcpcd; extern const NMDhcpClientFactory _nm_dhcp_client_factory_internal; diff --git a/src/core/dhcp/nm-dhcp-dhclient.c b/src/core/dhcp/nm-dhcp-dhclient.c index 043c2264..7e00599c 100644 --- a/src/core/dhcp/nm-dhcp-dhclient.c +++ b/src/core/dhcp/nm-dhcp-dhclient.c @@ -462,6 +462,11 @@ dhclient_start(NMDhcpClient *client, "to LOWDELAY (0x10)."); } + if (client_config->v4.ipv6_only_preferred) { + _LOGW("the dhclient backend does not support the \"IPv6-Only Preferred\" option; ignoring " + "it"); + } + /* Usually the system bus address is well-known; but if it's supposed * to be something else, we need to push it to dhclient, since dhclient * sanitizes the environment it gives the action scripts. diff --git a/src/core/dhcp/nm-dhcp-dhcpcanon.c b/src/core/dhcp/nm-dhcp-dhcpcanon.c deleted file mode 100644 index cd42b692..00000000 --- a/src/core/dhcp/nm-dhcp-dhcpcanon.c +++ /dev/null @@ -1,239 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2017 juga <juga at riseup dot net> - */ - -#include "src/core/nm-default-daemon.h" - -#if WITH_DHCPCANON - -#include <stdlib.h> -#include <unistd.h> - -#include "nm-utils.h" -#include "nm-dhcp-manager.h" -#include "NetworkManagerUtils.h" -#include "nm-dhcp-listener.h" -#include "nm-dhcp-client-logging.h" - -#define NM_TYPE_DHCP_DHCPCANON (nm_dhcp_dhcpcanon_get_type()) -#define NM_DHCP_DHCPCANON(obj) \ - (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_DHCPCANON, NMDhcpDhcpcanon)) -#define NM_DHCP_DHCPCANON_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DHCP_DHCPCANON, NMDhcpDhcpcanonClass)) -#define NM_IS_DHCP_DHCPCANON(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DHCP_DHCPCANON)) -#define NM_IS_DHCP_DHCPCANON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DHCP_DHCPCANON)) -#define NM_DHCP_DHCPCANON_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DHCP_DHCPCANON, NMDhcpDhcpcanonClass)) - -typedef struct _NMDhcpDhcpcanon NMDhcpDhcpcanon; -typedef struct _NMDhcpDhcpcanonClass NMDhcpDhcpcanonClass; - -static GType nm_dhcp_dhcpcanon_get_type(void); - -/*****************************************************************************/ - -typedef struct { - char *conf_file; - const char *def_leasefile; - char *lease_file; - char *pid_file; - NMDhcpListener *dhcp_listener; -} NMDhcpDhcpcanonPrivate; - -struct _NMDhcpDhcpcanon { - NMDhcpClient parent; - NMDhcpDhcpcanonPrivate _priv; -}; - -struct _NMDhcpDhcpcanonClass { - NMDhcpClientClass parent; -}; - -G_DEFINE_TYPE(NMDhcpDhcpcanon, nm_dhcp_dhcpcanon, NM_TYPE_DHCP_CLIENT) - -#define NM_DHCP_DHCPCANON_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDhcpDhcpcanon, NM_IS_DHCP_DHCPCANON) - -/*****************************************************************************/ - -static const char * -nm_dhcp_dhcpcanon_get_path(void) -{ - return nm_utils_find_helper("dhcpcanon", DHCPCANON_PATH, NULL); -} - -static gboolean -dhcpcanon_start(NMDhcpClient *client, - const char *mode_opt, - GBytes *duid, - gboolean release, - pid_t *out_pid, - guint needed_prefixes, - GError **error) -{ - NMDhcpDhcpcanon *self = NM_DHCP_DHCPCANON(client); - NMDhcpDhcpcanonPrivate *priv = NM_DHCP_DHCPCANON_GET_PRIVATE(self); - gs_unref_ptrarray GPtrArray *argv = NULL; - pid_t pid; - gs_free_error GError *local = NULL; - const char *iface; - const char *system_bus_address; - const char *dhcpcanon_path; - gs_free char *binary_name = NULL; - gs_free char *pid_file = NULL; - gs_free char *system_bus_address_env = NULL; - int addr_family; - - g_return_val_if_fail(!priv->pid_file, FALSE); - - iface = nm_dhcp_client_get_iface(client); - - addr_family = nm_dhcp_client_get_addr_family(client); - - dhcpcanon_path = nm_dhcp_dhcpcanon_get_path(); - if (!dhcpcanon_path) { - nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "dhcpcanon binary not found"); - return FALSE; - } - - _LOGD("dhcpcanon_path: %s", dhcpcanon_path); - - pid_file = g_strdup_printf(RUNSTATEDIR "/dhcpcanon%c-%s.pid", - nm_utils_addr_family_to_char(addr_family), - iface); - _LOGD("pid_file: %s", pid_file); - - /* Kill any existing dhcpcanon from the pidfile */ - binary_name = g_path_get_basename(dhcpcanon_path); - nm_dhcp_client_stop_existing(pid_file, binary_name); - - argv = g_ptr_array_new(); - g_ptr_array_add(argv, (gpointer) dhcpcanon_path); - - g_ptr_array_add(argv, (gpointer) "-sf"); /* Set script file */ - g_ptr_array_add(argv, (gpointer) nm_dhcp_helper_path); - - g_ptr_array_add(argv, (gpointer) "-pf"); /* Set pid file */ - g_ptr_array_add(argv, (gpointer) pid_file); - - if (priv->conf_file) { - g_ptr_array_add(argv, (gpointer) "-cf"); /* Set interface config file */ - g_ptr_array_add(argv, (gpointer) priv->conf_file); - } - - /* Usually the system bus address is well-known; but if it's supposed - * to be something else, we need to push it to dhcpcanon, since dhcpcanon - * sanitizes the environment it gives the action scripts. - */ - system_bus_address = getenv("DBUS_SYSTEM_BUS_ADDRESS"); - if (system_bus_address) { - system_bus_address_env = g_strdup_printf("DBUS_SYSTEM_BUS_ADDRESS=%s", system_bus_address); - g_ptr_array_add(argv, (gpointer) "-e"); - g_ptr_array_add(argv, (gpointer) system_bus_address_env); - } - - g_ptr_array_add(argv, (gpointer) iface); - g_ptr_array_add(argv, NULL); - - if (!g_spawn_async(NULL, - (char **) argv->pdata, - NULL, - G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_STDOUT_TO_DEV_NULL - | G_SPAWN_STDERR_TO_DEV_NULL, - nm_utils_setpgid, - NULL, - &pid, - &local)) { - nm_utils_error_set(error, - NM_UTILS_ERROR_UNKNOWN, - "dhcpcanon failed to start: %s", - local->message); - return FALSE; - } - - nm_assert(pid > 0); - _LOGI("dhcpcanon started with pid %d", pid); - nm_dhcp_client_watch_child(client, pid); - priv->pid_file = g_steal_pointer(&pid_file); - return TRUE; -} - -static gboolean -ip4_start(NMDhcpClient *client, GError **error) -{ - return dhcpcanon_start(client, NULL, NULL, FALSE, NULL, 0, error); -} - -static void -stop(NMDhcpClient *client, gboolean release) -{ - NMDhcpDhcpcanon *self = NM_DHCP_DHCPCANON(client); - NMDhcpDhcpcanonPrivate *priv = NM_DHCP_DHCPCANON_GET_PRIVATE(self); - int errsv; - - NM_DHCP_CLIENT_CLASS(nm_dhcp_dhcpcanon_parent_class)->stop(client, release); - - if (priv->pid_file) { - if (remove(priv->pid_file) == -1) { - errsv = errno; - _LOGD("could not remove dhcp pid file \"%s\": %d (%s)", - priv->pid_file, - errsv, - nm_strerror_native(errsv)); - } - g_free(priv->pid_file); - priv->pid_file = NULL; - } -} - -/*****************************************************************************/ - -static void -nm_dhcp_dhcpcanon_init(NMDhcpDhcpcanon *self) -{ - NMDhcpDhcpcanonPrivate *priv = NM_DHCP_DHCPCANON_GET_PRIVATE(self); - - priv->dhcp_listener = g_object_ref(nm_dhcp_listener_get()); - g_signal_connect(priv->dhcp_listener, - NM_DHCP_LISTENER_EVENT, - G_CALLBACK(nm_dhcp_client_handle_event), - self); -} - -static void -dispose(GObject *object) -{ - NMDhcpDhcpcanonPrivate *priv = NM_DHCP_DHCPCANON_GET_PRIVATE(object); - - if (priv->dhcp_listener) { - g_signal_handlers_disconnect_by_func(priv->dhcp_listener, - G_CALLBACK(nm_dhcp_client_handle_event), - NM_DHCP_DHCPCANON(object)); - g_clear_object(&priv->dhcp_listener); - } - - nm_clear_g_free(&priv->pid_file); - - G_OBJECT_CLASS(nm_dhcp_dhcpcanon_parent_class)->dispose(object); -} - -static void -nm_dhcp_dhcpcanon_class_init(NMDhcpDhcpcanonClass *dhcpcanon_class) -{ - NMDhcpClientClass *client_class = NM_DHCP_CLIENT_CLASS(dhcpcanon_class); - GObjectClass *object_class = G_OBJECT_CLASS(dhcpcanon_class); - - object_class->dispose = dispose; - - client_class->ip4_start = ip4_start; - client_class->stop = stop; -} - -const NMDhcpClientFactory _nm_dhcp_client_factory_dhcpcanon = { - .name = "dhcpcanon", - .get_type_4 = nm_dhcp_dhcpcanon_get_type, - .get_path = nm_dhcp_dhcpcanon_get_path, -}; - -#endif /* WITH_DHCPCANON */ diff --git a/src/core/dhcp/nm-dhcp-listener.c b/src/core/dhcp/nm-dhcp-listener.c index 05e428f8..095131cc 100644 --- a/src/core/dhcp/nm-dhcp-listener.c +++ b/src/core/dhcp/nm-dhcp-listener.c @@ -31,9 +31,6 @@ const NMDhcpClientFactory *const _nm_dhcp_manager_factories[6] = { * the first available plugin. */ &_nm_dhcp_client_factory_internal, -#if WITH_DHCPCANON - &_nm_dhcp_client_factory_dhcpcanon, -#endif #if WITH_DHCPCD &_nm_dhcp_client_factory_dhcpcd, #endif diff --git a/src/core/dhcp/nm-dhcp-nettools.c b/src/core/dhcp/nm-dhcp-nettools.c index f4f244c6..27bb136b 100644 --- a/src/core/dhcp/nm-dhcp-nettools.c +++ b/src/core/dhcp/nm-dhcp-nettools.c @@ -169,6 +169,27 @@ lease_option_consume_route(const uint8_t **datap, /*****************************************************************************/ static gboolean +lease_get_ipv6_only_wait_time(NDhcp4ClientLease *lease, guint32 *out_val, const char *iface) +{ + const uint8_t *data; + size_t len; + int r; + + r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_IPV6_ONLY_PREFERRED, &data, &len); + if (r == 0 + && nm_dhcp_lease_data_parse_u32(data, + len, + out_val, + iface, + AF_INET, + NM_DHCP_OPTION_DHCP4_IPV6_ONLY_PREFERRED)) { + return TRUE; + } + + return FALSE; +} + +static gboolean lease_parse_address(NMDhcpNettools *self /* for logging context only */, NDhcp4ClientLease *lease, NML3ConfigData *l3cd, @@ -305,7 +326,7 @@ lease_parse_address(NMDhcpNettools *self /* for logging context only */, } nm_l3_config_data_add_address_4(l3cd, - &((const NMPlatformIP4Address){ + &((const NMPlatformIP4Address) { .address = a_address.s_addr, .peer_address = a_address.s_addr, .plen = a_plen, @@ -366,7 +387,7 @@ lease_parse_address_list(NDhcp4ClientLease *lease, nm_inet4_ntop(addr, addr_str)); continue; } - nm_l3_config_data_add_nameserver_detail(l3cd, AF_INET, &addr, NULL); + nm_l3_config_data_add_nameserver_addr(l3cd, AF_INET, &addr); break; case NM_DHCP_OPTION_DHCP4_NIS_SERVERS: nm_l3_config_data_add_nis_server(l3cd, addr); @@ -445,7 +466,7 @@ lease_parse_routes(NDhcp4ClientLease *lease, m = 0; nm_l3_config_data_add_route_4(l3cd, - &((const NMPlatformIP4Route){ + &((const NMPlatformIP4Route) { .rt_source = NM_IP_CONFIG_SOURCE_DHCP, .network = dest, .plen = plen, @@ -489,7 +510,7 @@ lease_parse_routes(NDhcp4ClientLease *lease, } nm_l3_config_data_add_route_4(l3cd, - &((const NMPlatformIP4Route){ + &((const NMPlatformIP4Route) { .rt_source = NM_IP_CONFIG_SOURCE_DHCP, .network = dest, .plen = plen, @@ -533,7 +554,7 @@ lease_parse_routes(NDhcp4ClientLease *lease, m = default_route_metric_offset++; nm_l3_config_data_add_route_4(l3cd, - &((const NMPlatformIP4Route){ + &((const NMPlatformIP4Route) { .rt_source = NM_IP_CONFIG_SOURCE_DHCP, .gateway = gateway, .pref_src = lease_address, @@ -929,6 +950,22 @@ bound4_handle(NMDhcpNettools *self, guint event, NDhcp4ClientLease *lease) l3cd); } +static gboolean +dhcp4_handle_ipv6_only(NMDhcpNettools *self, NDhcp4ClientEvent *event) +{ + NMDhcpClient *client = NM_DHCP_CLIENT(self); + guint32 val; + + if (nm_dhcp_client_get_config(client)->v4.ipv6_only_preferred + && lease_get_ipv6_only_wait_time(event->offer.lease, + &val, + nm_dhcp_client_get_iface(client))) { + nm_dhcp_client_schedule_ipv6_only_restart(client, val); + return TRUE; + } + return FALSE; +} + static void dhcp4_event_handle(NMDhcpNettools *self, NDhcp4ClientEvent *event) { @@ -962,18 +999,23 @@ dhcp4_event_handle(NMDhcpNettools *self, NDhcp4ClientEvent *event) return; } - n_dhcp4_client_lease_get_yiaddr(event->offer.lease, &yiaddr); - if (yiaddr.s_addr == INADDR_ANY) { - _LOGD("selecting lease failed: no yiaddr address"); - return; - } - if (nm_dhcp_client_server_id_is_rejected(NM_DHCP_CLIENT(self), &server_id)) { _LOGD("server-id %s is in the reject-list, ignoring", nm_inet_ntop(AF_INET, &server_id, addr_str)); return; } + if (dhcp4_handle_ipv6_only(self, event)) + return; + + /* Check yiaddr only after evaluating the ipv6-only-preferred option, because if + * the option is present yiaddr can be zero. */ + n_dhcp4_client_lease_get_yiaddr(event->offer.lease, &yiaddr); + if (yiaddr.s_addr == INADDR_ANY) { + _LOGD("selecting lease failed: no yiaddr address"); + return; + } + if (!_nm_dhcp_client_accept_offer(NM_DHCP_CLIENT(self), &yiaddr.s_addr)) { /* We don't log about this, the parent class is expected to notify about the reasons. */ return; @@ -1001,6 +1043,17 @@ dhcp4_event_handle(NMDhcpNettools *self, NDhcp4ClientEvent *event) _nm_dhcp_client_notify(NM_DHCP_CLIENT(self), NM_DHCP_CLIENT_EVENT_TYPE_FAIL, NULL); return; case N_DHCP4_CLIENT_EVENT_GRANTED: + if (dhcp4_handle_ipv6_only(self, event)) { + /* RFC 8925 says that when the client receives a DHCPACK, it should + * stop the client; but only in the INIT-REBOOT (actually, REBOOTING) + * state, otherwise it should continue to use the address. + * The GRANTED event is emitted both in the REBOOTING and REQUESTING + * state; however if we got the IPv6-only option in the OFFER we have + * already stopped the client. Therefore this point can be reached + * only in the REBOOTING state. + */ + return; + } bound4_handle(self, event->event, event->granted.lease); return; case N_DHCP4_CLIENT_EVENT_EXTENDED: @@ -1323,7 +1376,7 @@ ip4_start(NMDhcpClient *client, GError **error) g_return_val_if_fail(!priv->probe, FALSE); g_return_val_if_fail(client_config, FALSE); - if (!nettools_create(self, &effective_client_id, error)) + if (!priv->client && !nettools_create(self, &effective_client_id, error)) return FALSE; r = n_dhcp4_client_probe_config_new(&config); @@ -1377,6 +1430,11 @@ ip4_start(NMDhcpClient *client, GError **error) } } + if (client_config->v4.ipv6_only_preferred) { + n_dhcp4_client_probe_config_request_option(config, + NM_DHCP_OPTION_DHCP4_IPV6_ONLY_PREFERRED); + } + if (client_config->mud_url) { r = n_dhcp4_client_probe_config_append_option(config, NM_DHCP_OPTION_DHCP4_MUD_URL, diff --git a/src/core/dhcp/nm-dhcp-options.c b/src/core/dhcp/nm-dhcp-options.c index f89237c5..ce03c607 100644 --- a/src/core/dhcp/nm-dhcp-options.c +++ b/src/core/dhcp/nm-dhcp-options.c @@ -113,6 +113,7 @@ const NMDhcpOption _nm_dhcp_option_dhcp4_options[] = { REQ(NM_DHCP_OPTION_DHCP4_PXE_CLIENT_ID, "pxe_client_id", FALSE), REQ(NM_DHCP_OPTION_DHCP4_UAP_SERVERS, "uap_servers", FALSE), REQ(NM_DHCP_OPTION_DHCP4_GEOCONF_CIVIC, "geoconf_civic", FALSE), + REQ(NM_DHCP_OPTION_DHCP4_IPV6_ONLY_PREFERRED, "ipv6_only_preferred", FALSE), REQ(NM_DHCP_OPTION_DHCP4_NETINFO_SERVER_ADDRESS, "netinfo_server_address", FALSE), REQ(NM_DHCP_OPTION_DHCP4_NETINFO_SERVER_TAG, "netinfo_server_tag", FALSE), REQ(NM_DHCP_OPTION_DHCP4_DEFAULT_URL, "default_url", FALSE), @@ -183,11 +184,11 @@ static const NMDhcpOption *const _sorted_options_4[G_N_ELEMENTS(_nm_dhcp_option_ A(13), A(53), A(54), A(55), A(57), A(58), A(59), A(60), A(61), A(62), A(63), A(64), A(65), A(66), A(67), A(68), A(69), A(70), A(71), A(72), A(73), A(74), A(75), A(76), A(77), A(78), A(79), A(80), A(81), A(82), A(83), A(84), A(85), A(86), A(87), A(56), - A(88), A(89), A(90), A(91), A(92), A(93), A(14), A(7), A(94), A(95), A(96), A(97), + A(88), A(89), A(90), A(91), A(92), A(93), A(94), A(14), A(7), A(95), A(96), A(97), A(98), A(99), A(100), A(101), A(102), A(103), A(104), A(105), A(106), A(107), A(108), A(109), A(110), A(111), A(112), A(113), A(114), A(115), A(116), A(117), A(118), A(119), A(120), A(121), A(122), A(123), A(124), A(125), A(126), A(127), A(128), A(129), A(130), A(131), A(132), A(133), - A(134), A(15), A(135), A(136), A(16), A(137), A(138), A(139), A(140), A(141), A(142), + A(134), A(135), A(15), A(136), A(137), A(16), A(138), A(139), A(140), A(141), A(142), A(143), #undef A }; diff --git a/src/core/dhcp/nm-dhcp-options.h b/src/core/dhcp/nm-dhcp-options.h index 1c61c74d..c8ab1dae 100644 --- a/src/core/dhcp/nm-dhcp-options.h +++ b/src/core/dhcp/nm-dhcp-options.h @@ -93,6 +93,7 @@ typedef enum { NM_DHCP_OPTION_DHCP4_UAP_SERVERS = 98, NM_DHCP_OPTION_DHCP4_GEOCONF_CIVIC = 99, NM_DHCP_OPTION_DHCP4_NEW_TZDB_TIMEZONE = 101, + NM_DHCP_OPTION_DHCP4_IPV6_ONLY_PREFERRED = 108, NM_DHCP_OPTION_DHCP4_NETINFO_SERVER_ADDRESS = 112, NM_DHCP_OPTION_DHCP4_NETINFO_SERVER_TAG = 113, NM_DHCP_OPTION_DHCP4_DEFAULT_URL = 114, @@ -188,7 +189,7 @@ typedef struct { bool include; } NMDhcpOption; -extern const NMDhcpOption _nm_dhcp_option_dhcp4_options[143]; +extern const NMDhcpOption _nm_dhcp_option_dhcp4_options[144]; extern const NMDhcpOption _nm_dhcp_option_dhcp6_options[18]; static inline const char * diff --git a/src/core/dhcp/nm-dhcp-systemd.c b/src/core/dhcp/nm-dhcp-systemd.c index 5ede0df9..e1761523 100644 --- a/src/core/dhcp/nm-dhcp-systemd.c +++ b/src/core/dhcp/nm-dhcp-systemd.c @@ -157,7 +157,7 @@ lease_to_ip6_config(NMDhcpSystemd *self, sd_dhcp6_lease *lease, gint32 ts, GErro for (i = 0; i < num; i++) { nm_inet6_ntop(&dns[i], addr_str); g_string_append(nm_gstring_add_space_delimiter(str), addr_str); - nm_l3_config_data_add_nameserver_detail(l3cd, AF_INET6, &dns[i], NULL); + nm_l3_config_data_add_nameserver_addr(l3cd, AF_INET6, &dns[i]); } nm_dhcp_option_add_option(options, TRUE, diff --git a/src/core/dhcp/nm-dhcp-utils.c b/src/core/dhcp/nm-dhcp-utils.c index ca1c0482..15293fa3 100644 --- a/src/core/dhcp/nm-dhcp-utils.c +++ b/src/core/dhcp/nm-dhcp-utils.c @@ -92,7 +92,7 @@ ip4_process_dhcpcd_rfc3442_routes(const char *iface, nm_l3_config_data_add_route_4( l3cd, - &((const NMPlatformIP4Route){ + &((const NMPlatformIP4Route) { .rt_source = NM_IP_CONFIG_SOURCE_DHCP, .network = nm_ip4_addr_clear_host_address(rt_addr, rt_cidr), .plen = rt_cidr, @@ -147,7 +147,7 @@ process_dhclient_rfc3442_route(const char *const **p_octets, NMPlatformIP4Route if (inet_pton(AF_INET, next_hop, &tmp_addr) <= 0) return FALSE; - *route = (NMPlatformIP4Route){ + *route = (NMPlatformIP4Route) { .network = v_network, .plen = v_plen, .gateway = tmp_addr, @@ -316,7 +316,7 @@ process_classful_routes(const char *iface, // FIXME: ensure the IP address and route are sane - route = (NMPlatformIP4Route){ + route = (NMPlatformIP4Route) { .network = rt_addr, }; @@ -409,7 +409,7 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, now = nm_utils_get_monotonic_timestamp_sec(); - address = (NMPlatformIP4Address){ + address = (NMPlatformIP4Address) { .timestamp = now, }; @@ -499,7 +499,7 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, for (s = dns; dns && *s; s++) { if (inet_pton(AF_INET, *s, &tmp_addr) > 0) { if (tmp_addr) { - nm_l3_config_data_add_nameserver_detail(l3cd, AF_INET, &tmp_addr, NULL); + nm_l3_config_data_add_nameserver_addr(l3cd, AF_INET, &tmp_addr); _LOG2I(LOGD_DHCP4, iface, " nameserver '%s'", *s); } } else @@ -655,7 +655,7 @@ nm_dhcp_utils_ip6_config_from_options(NMDedupMultiIndex *multi_idx, now = nm_utils_get_monotonic_timestamp_sec(); - address = (NMPlatformIP6Address){ + address = (NMPlatformIP6Address) { .plen = 128, .timestamp = now, }; @@ -704,7 +704,7 @@ nm_dhcp_utils_ip6_config_from_options(NMDedupMultiIndex *multi_idx, for (s = dns; dns && *s; s++) { if (inet_pton(AF_INET6, *s, &tmp_addr) > 0) { if (!IN6_IS_ADDR_UNSPECIFIED(&tmp_addr)) { - nm_l3_config_data_add_nameserver_detail(l3cd, AF_INET6, &tmp_addr, NULL); + nm_l3_config_data_add_nameserver_addr(l3cd, AF_INET6, &tmp_addr); _LOG2I(LOGD_DHCP6, iface, " nameserver '%s'", *s); } } else @@ -935,6 +935,27 @@ nm_dhcp_lease_data_parse_u16(const guint8 *data, } gboolean +nm_dhcp_lease_data_parse_u32(const guint8 *data, + gsize n_data, + uint32_t *out_val, + const char *iface, + int addr_family, + guint option) +{ + if (n_data != 4) { + nm_dhcp_lease_log_invalid_option(iface, + addr_family, + option, + "invalid option length %lu", + (unsigned long) n_data); + return FALSE; + } + + *out_val = unaligned_read_be32(data); + return TRUE; +} + +gboolean nm_dhcp_lease_data_parse_mtu(const guint8 *data, gsize n_data, uint16_t *out_val, diff --git a/src/core/dhcp/nm-dhcp-utils.h b/src/core/dhcp/nm-dhcp-utils.h index 00199b02..99898524 100644 --- a/src/core/dhcp/nm-dhcp-utils.h +++ b/src/core/dhcp/nm-dhcp-utils.h @@ -74,6 +74,12 @@ gboolean nm_dhcp_lease_data_parse_u16(const guint8 *data, const char *iface, int addr_family, guint option); +gboolean nm_dhcp_lease_data_parse_u32(const guint8 *data, + gsize n_data, + uint32_t *out_val, + const char *iface, + int addr_family, + guint option); gboolean nm_dhcp_lease_data_parse_mtu(const guint8 *data, gsize n_data, guint16 *out_val, diff --git a/src/core/dhcp/tests/test-dhcp-dhclient.c b/src/core/dhcp/tests/test-dhcp-dhclient.c index 0edcc296..6a7b7185 100644 --- a/src/core/dhcp/tests/test-dhcp-dhclient.c +++ b/src/core/dhcp/tests/test-dhcp-dhclient.c @@ -1023,7 +1023,7 @@ _check_duid_impl(const guint8 *duid_bin, g_assert_cmpint(contents_len, ==, strlen(contents)); } -#define _DUID(...) ((const guint8[]){__VA_ARGS__}) +#define _DUID(...) ((const guint8[]) {__VA_ARGS__}) #define _check_duid(duid, enforce_duid, old_content, new_content) \ _check_duid_impl((duid), sizeof(duid), (enforce_duid), (old_content), (new_content)) diff --git a/src/core/dhcp/tests/test-dhcp-utils.c b/src/core/dhcp/tests/test-dhcp-utils.c index 1c6d6302..b81523e1 100644 --- a/src/core/dhcp/tests/test-dhcp-utils.c +++ b/src/core/dhcp/tests/test-dhcp-utils.c @@ -194,16 +194,16 @@ test_parse_search_list(void) guint8 *data; char **domains; - data = (guint8[]){0x05, 'l', 'o', 'c', 'a', 'l', 0x00}; + data = (guint8[]) {0x05, 'l', 'o', 'c', 'a', 'l', 0x00}; domains = nm_dhcp_lease_data_parse_search_list(data, 7, NULL, 0, 0); g_assert(domains); g_assert_cmpint(g_strv_length(domains), ==, 1); g_assert_cmpstr(domains[0], ==, "local"); g_strfreev(domains); - data = (guint8[]){0x04, 't', 'e', 's', 't', 0x07, 'e', 'x', 'a', 'm', 'p', 'l', - 'e', 0x03, 'c', 'o', 'm', 0x00, 0xc0, 0x05, 0x03, 'a', 'b', 'c', - 0xc0, 0x0d, 0x06, 'f', 'o', 'o', 'b', 'a', 'r', 0x00}; + data = (guint8[]) {0x04, 't', 'e', 's', 't', 0x07, 'e', 'x', 'a', 'm', 'p', 'l', + 'e', 0x03, 'c', 'o', 'm', 0x00, 0xc0, 0x05, 0x03, 'a', 'b', 'c', + 0xc0, 0x0d, 0x06, 'f', 'o', 'o', 'b', 'a', 'r', 0x00}; domains = nm_dhcp_lease_data_parse_search_list(data, 34, NULL, 0, 0); g_assert(domains); g_assert_cmpint(g_strv_length(domains), ==, 4); @@ -213,7 +213,7 @@ test_parse_search_list(void) g_assert_cmpstr(domains[3], ==, "foobar"); g_strfreev(domains); - data = (guint8[]){ + data = (guint8[]) { 0x40, 'b', 'a', @@ -222,7 +222,7 @@ test_parse_search_list(void) domains = nm_dhcp_lease_data_parse_search_list(data, 4, NULL, 0, 0); g_assert(!domains); - data = (guint8[]){ + data = (guint8[]) { 0x04, 'o', 'k', diff --git a/src/core/dns/nm-dns-dnsconfd.c b/src/core/dns/nm-dns-dnsconfd.c new file mode 100644 index 00000000..b356c2f9 --- /dev/null +++ b/src/core/dns/nm-dns-dnsconfd.c @@ -0,0 +1,802 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024 Red Hat, Inc. + */ + +#include "src/core/nm-default-daemon.h" + +#include "nm-dns-dnsconfd.h" + +#include "libnm-glib-aux/nm-dbus-aux.h" +#include "libnm-core-intern/nm-core-internal.h" +#include "libnm-platform/nm-platform.h" +#include "nm-utils.h" +#include "nm-dbus-manager.h" +#include "NetworkManagerUtils.h" +#include "nm-l3-config-data.h" +#include "nm-manager.h" +#include "devices/nm-device.h" +#include "nm-active-connection.h" +#include "nm-l3cfg.h" + +typedef enum { + DNSCONFD_PLUGIN_IDLE = 0, + DNSCONFD_PLUGIN_WAIT_CONNECT = 1, + DNSCONFD_PLUGIN_WAIT_UPDATE_DONE = 2, + DNSCONFD_PLUGIN_WAIT_SERIAL = 3 +} DnsconfdPluginState; + +typedef struct { + GDBusConnection *dbus_connection; + GCancellable *update_cancellable; + char *name_owner; + guint name_owner_changed_id; + GCancellable *name_owner_cancellable; + GVariant *latest_update_args; + + guint awaited_configuration_serial; + guint present_configuration_serial; + guint properties_changed_id; + GCancellable *serial_cancellable; + + DnsconfdPluginState plugin_state; +} NMDnsDnsconfdPrivate; + +struct _NMDnsDnsconfd { + NMDnsPlugin parent; + NMDnsDnsconfdPrivate _priv; +}; + +struct _NMDnsDnsconfdClass { + NMDnsPluginClass parent; +}; + +G_DEFINE_TYPE(NMDnsDnsconfd, nm_dns_dnsconfd, NM_TYPE_DNS_PLUGIN) + +#define NM_DNS_DNSCONFD_GET_PRIVATE(self) \ + _NM_GET_PRIVATE(self, NMDnsDnsconfd, NM_IS_DNS_DNSCONFD, NMDnsPlugin) + +#define _NMLOG_DOMAIN LOGD_DNS +#define _NMLOG(level, ...) __NMLOG_DEFAULT(level, _NMLOG_DOMAIN, "dnsconfd", __VA_ARGS__) + +#define DNSCONFD_DBUS_SERVICE "com.redhat.dnsconfd" + +typedef enum { CONNECTION_FAIL, CONNECTION_SUCCESS, CONNECTION_WAIT } ConnectionState; + +/*****************************************************************************/ + +static void +dnsconfd_serial_changed(NMDnsDnsconfd *self, guint new_serial) +{ + NMDnsDnsconfdPrivate *priv = NM_DNS_DNSCONFD_GET_PRIVATE(self); + 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; + /* Update finished, serials match */ + _LOGT("serials match, update finished"); + } + + _nm_dns_plugin_update_pending_maybe_changed(NM_DNS_PLUGIN(self)); +} + +static void +dnsconfd_properties_changed(GDBusConnection *connection, + const char *sender_name, + const char *object_path, + const char *interface_name, + const char *signal_name, + GVariant *parameters, + gpointer user_data) +{ + NMDnsDnsconfd *self = user_data; + gs_unref_variant GVariant *updated_properties = NULL; + guint new_serial; + + if (!g_variant_is_of_type(parameters, G_VARIANT_TYPE("(sa{sv}as)"))) { + _LOGW("received properties changed signal but the type is wrong"); + return; + } + + g_variant_get(parameters, "(&s@a{sv}as)", NULL, &updated_properties, NULL); + + if (!g_variant_lookup(updated_properties, "configuration_serial", "u", &new_serial)) { + _LOGT("properties changed but they do not contain new serial"); + return; + } + _LOGT("properties changed and contain new serial %u", new_serial); + + dnsconfd_serial_changed(self, new_serial); +} + +static void +dnsconfd_serial_retrieval_done(GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + NMDnsDnsconfd *self; + NMDnsDnsconfdPrivate *priv; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *response = NULL; + gs_unref_variant GVariant *new_serial_variant = NULL; + guint new_serial; + + response = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source_object), res, &error); + if (nm_utils_error_is_cancelled(error)) + return; + + self = user_data; + priv = NM_DNS_DNSCONFD_GET_PRIVATE(self); + + nm_clear_g_cancellable(&priv->serial_cancellable); + + g_variant_get(response, "(v)", &new_serial_variant); + + g_variant_get(new_serial_variant, "u", &new_serial); + + _LOGT("serial retrieval done %u", new_serial); + + dnsconfd_serial_changed(self, new_serial); +} + +static gboolean +subscribe_serial(NMDnsDnsconfd *self) +{ + NMDnsDnsconfdPrivate *priv = NM_DNS_DNSCONFD_GET_PRIVATE(self); + + priv->properties_changed_id = + g_dbus_connection_signal_subscribe(priv->dbus_connection, + priv->name_owner, + "org.freedesktop.DBus.Properties", + "PropertiesChanged", + "/com/redhat/dnsconfd", + "com.redhat.dnsconfd.Manager", + G_DBUS_SIGNAL_FLAGS_NONE, + dnsconfd_properties_changed, + self, + NULL); + if (!priv->properties_changed_id) { + return FALSE; + } + + nm_clear_g_cancellable(&priv->serial_cancellable); + + g_dbus_connection_call( + priv->dbus_connection, + priv->name_owner, + "/com/redhat/dnsconfd", + "org.freedesktop.DBus.Properties", + "Get", + g_variant_new("(ss)", "com.redhat.dnsconfd.Manager", "configuration_serial"), + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->serial_cancellable, + dnsconfd_serial_retrieval_done, + self); + return TRUE; +} + +static void +dnsconfd_update_done(GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + NMDnsDnsconfd *self; + NMDnsDnsconfdPrivate *priv; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *response = NULL; + guint awaited_serial; + char *dnsconfd_message; + + response = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source_object), res, &error); + + if (nm_utils_error_is_cancelled(error)) + return; + + self = user_data; + priv = NM_DNS_DNSCONFD_GET_PRIVATE(self); + + nm_clear_g_cancellable(&priv->update_cancellable); + + if (!response) + _LOGW("dnsconfd update failed: %s", error->message); + + /* By using &s we will get pointer to char data contained + * in variant and thus no freing of dnsconfd_message is required */ + g_variant_get(response, "(u&s)", &awaited_serial, &dnsconfd_message); + + 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)); + return; + } + + priv->awaited_configuration_serial = awaited_serial; + _LOGT("dnsconfd accepted update, awaited serial is %u", awaited_serial); + + if (priv->awaited_configuration_serial == priv->present_configuration_serial) { + /* Serials match, update finished */ + priv->plugin_state = DNSCONFD_PLUGIN_IDLE; + _LOGT("after update serials match"); + } else { + priv->plugin_state = 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 +is_default_interface_explicit(const CList *ip_data_lst_head) +{ + guint n_domains; + const char *const *strv_domains; + NMDnsConfigIPData *ip_data; + gboolean is_routing; + + /* If there is "~." specified in any connection's active ipvX.search setting then default + * interface is explicit */ + + c_list_for_each_entry (ip_data, ip_data_lst_head, ip_data_lst) { + strv_domains = + nm_l3_config_data_get_searches(ip_data->l3cd, ip_data->addr_family, &n_domains); + for (guint i = 0; i < n_domains; i++) { + if (nm_streq(nm_utils_parse_dns_domain(strv_domains[i], &is_routing), ".")) { + return TRUE; + } + } + } + /* AFAIK it should not be passible to pass "." through DHCP and thus we will check only + * searches */ + return FALSE; +} + +static void +gather_interface_domains(NMDnsConfigIPData *ip_data, + gboolean is_default_explicit, + const char ***routing_domains, + const char ***search_domains) +{ + guint n_domains; + const char *const *strv_domains; + gboolean is_routing; + const char *cur_domain; + GPtrArray *routing_ptr_array = g_ptr_array_sized_new(5); + GPtrArray *search_ptr_array = g_ptr_array_sized_new(5); + + /* Searches have higher priority than domains (dynamically retrieved) */ + strv_domains = nm_l3_config_data_get_searches(ip_data->l3cd, ip_data->addr_family, &n_domains); + if (!n_domains) { + strv_domains = + nm_l3_config_data_get_domains(ip_data->l3cd, ip_data->addr_family, &n_domains); + } + + for (int i = 0; i < n_domains; i++) { + cur_domain = nm_utils_parse_dns_domain(strv_domains[i], &is_routing); + g_ptr_array_add(routing_ptr_array, (char *) cur_domain); + if (!is_routing) { + g_ptr_array_add(search_ptr_array, (char *) cur_domain); + } + } + + /* If there has been specified search like "~." then we will not be adding "." and respect + * users wishes */ + if (!is_default_explicit + && nm_l3_config_data_get_best_default_route(ip_data->l3cd, ip_data->addr_family)) { + g_ptr_array_add(routing_ptr_array, "."); + } + g_ptr_array_add(routing_ptr_array, NULL); + g_ptr_array_add(search_ptr_array, NULL); + + /* When array would be empty we will simply return NULL */ + *routing_domains = + (const char **) g_ptr_array_free(routing_ptr_array, (routing_ptr_array->len == 1)); + *search_domains = + (const char **) g_ptr_array_free(search_ptr_array, (search_ptr_array->len == 1)); +} + +static void +get_networks(NMDnsConfigIPData *ip_data, char ***networks) +{ + NMDedupMultiIter ipconf_iter; + const NMPObject *obj; + char s_address[INET6_ADDRSTRLEN]; + /* +4 because INET6_ADDRSTRLEN already contains byte for end of string and we need 4 bytes + * to store max 3 characters of mask and slash (/128 for example) */ + char network_buffer[INET6_ADDRSTRLEN + 4]; + const NMPlatformIPRoute *route; + GPtrArray *ptr_array = g_ptr_array_sized_new(5); + int addr_family = ip_data->addr_family; + guint IS_IPv4 = NM_IS_IPv4(addr_family); + + nm_l3_config_data_iter_obj_for_each (&ipconf_iter, + ip_data->l3cd, + &obj, + NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4)) { + route = NMP_OBJECT_CAST_IP_ROUTE(obj); + if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(route) + || route->table_coerced == NM_DNS_ROUTES_FWMARK_TABLE_PRIO) { + continue; + } + nm_inet_ntop(addr_family, route->network_ptr, s_address); + nm_sprintf_buf(network_buffer, "%s/%u", s_address, route->plen); + g_ptr_array_add(ptr_array, g_strdup(network_buffer)); + } + + g_ptr_array_add(ptr_array, NULL); + /* If array would be empty then return NULL */ + *networks = (char **) g_ptr_array_free(ptr_array, ptr_array->len == 1); +} + +static void +server_builder_append_interface_info(GVariantBuilder *argument_builder, + const char *interface, + char **networks, + const char *connection_id, + const char *connection_uuid, + const char *dbus_path) +{ + if (connection_id) { + g_variant_builder_add(argument_builder, + "{sv}", + "connection-id", + g_variant_new("s", connection_id)); + } + if (connection_uuid) { + g_variant_builder_add(argument_builder, + "{sv}", + "connection-uuid", + g_variant_new("s", connection_uuid)); + } + if (dbus_path) { + g_variant_builder_add(argument_builder, + "{sv}", + "connection-object", + g_variant_new("s", dbus_path)); + } + if (interface) { + g_variant_builder_add(argument_builder, "{sv}", "interface", g_variant_new("s", interface)); + } + if (networks) { + g_variant_builder_add(argument_builder, + "{sv}", + "networks", + g_variant_new_strv((const char *const *) networks, -1)); + } + g_variant_builder_close(argument_builder); +} + +static gboolean +server_builder_append_base(GVariantBuilder *argument_builder, + int address_family, + const char *address_string, + const char *const *routing_domains, + const char *const *search_domains, + const char *ca) +{ + NMDnsServer dns_server; + gsize addr_size; + + if (!nm_dns_uri_parse(address_family, address_string, &dns_server)) + return FALSE; + addr_size = nm_utils_addr_family_to_size(dns_server.addr_family); + + g_variant_builder_open(argument_builder, G_VARIANT_TYPE("a{sv}")); + + /* No freeing needed in this section as builder takes ownership of all data */ + + g_variant_builder_add(argument_builder, + "{sv}", + "address", + nm_g_variant_new_ay((gconstpointer) &dns_server.addr, addr_size)); + if (dns_server.scheme == NM_DNS_URI_SCHEME_TLS) + g_variant_builder_add(argument_builder, "{sv}", "protocol", g_variant_new("s", "dns+tls")); + if (dns_server.servername) + g_variant_builder_add(argument_builder, + "{sv}", + "name", + g_variant_new("s", dns_server.servername)); + if (routing_domains) { + g_variant_builder_add(argument_builder, + "{sv}", + "routing_domains", + g_variant_new_strv(routing_domains, -1)); + } + if (search_domains) { + g_variant_builder_add(argument_builder, + "{sv}", + "search_domains", + g_variant_new_strv(search_domains, -1)); + } + if (ca) { + g_variant_builder_add(argument_builder, "{sv}", "ca", g_variant_new("s", ca)); + } + return TRUE; +} + +static void +parse_global_config(const NMGlobalDnsConfig *global_config, + GVariantBuilder *argument_builder, + guint *resolve_mode, + const char **ca) +{ + NMGlobalDnsDomain *domain; + const char *const *servers; + const char *name; + const char *routing_domains[2] = {0}; + const char *const *searches = nm_global_dns_config_get_searches(global_config); + guint num_domains = nm_global_dns_config_get_num_domains(global_config); + /* CA can be specified only in global config, but if it is, then we must set it for + * all servers the same, because we do not support multiple certification authorities + * (backend limitation) */ + *ca = nm_global_dns_config_get_certification_authority(global_config); + *resolve_mode = nm_global_dns_config_get_resolve_mode(global_config); + + for (guint i = 0; i < num_domains; i++) { + domain = nm_global_dns_config_get_domain(global_config, i); + servers = nm_global_dns_domain_get_servers(domain); + if (!servers) { + continue; + } + name = nm_global_dns_domain_get_name(domain); + routing_domains[0] = nm_streq(name, "*") ? "." : name; + + for (gsize j = 0; servers[j]; j++) { + if (server_builder_append_base(argument_builder, + AF_UNSPEC, + servers[j], + routing_domains, + searches, + *ca)) { + g_variant_builder_close(argument_builder); + } + } + } +} + +static void +send_dnsconfd_update(NMDnsDnsconfd *self) +{ + NMDnsDnsconfdPrivate *priv = NM_DNS_DNSCONFD_GET_PRIVATE(self); + + nm_clear_g_cancellable(&priv->update_cancellable); + priv->update_cancellable = g_cancellable_new(); + + g_dbus_connection_call(priv->dbus_connection, + priv->name_owner, + "/com/redhat/dnsconfd", + "com.redhat.dnsconfd.Manager", + "Update", + priv->latest_update_args, + NULL, + G_DBUS_CALL_FLAGS_NONE, + 20000, + priv->update_cancellable, + dnsconfd_update_done, + self); +} + +static void +name_owner_changed(NMDnsDnsconfd *self, const char *name_owner) +{ + NMDnsDnsconfdPrivate *priv = NM_DNS_DNSCONFD_GET_PRIVATE(self); + + name_owner = nm_str_not_empty(name_owner); + + if (nm_streq0(priv->name_owner, name_owner)) + return; + + g_free(priv->name_owner); + priv->name_owner = g_strdup(name_owner); + + if (!name_owner) { + _LOGD("D-Bus name for dnsconfd disappeared"); + if (priv->plugin_state == DNSCONFD_PLUGIN_WAIT_UPDATE_DONE + || 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)); + } + return; + } + + _LOGT("D-Bus name for dnsconfd got owner %s", 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; + _LOGT("subscription failed, waiting to connect"); + } else { + priv->plugin_state = 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 +name_owner_changed_cb(GDBusConnection *connection, + const char *sender_name, + const char *object_path, + const char *interface_name, + const char *signal_name, + GVariant *parameters, + gpointer user_data) +{ + NMDnsDnsconfd *self = user_data; + const char *new_owner; + + if (!g_variant_is_of_type(parameters, G_VARIANT_TYPE("(sss)"))) + return; + + g_variant_get(parameters, "(&s&s&s)", NULL, NULL, &new_owner); + + name_owner_changed(self, new_owner); +} + +static void +get_name_owner_cb(const char *name_owner, GError *error, gpointer user_data) +{ + if (nm_utils_error_is_cancelled(error)) + return; + + name_owner_changed(user_data, name_owner); +} + +static ConnectionState +ensure_all_connected(NMDnsDnsconfd *self) +{ + NMDnsDnsconfdPrivate *priv = NM_DNS_DNSCONFD_GET_PRIVATE(self); + + if (!priv->dbus_connection) { + priv->dbus_connection = nm_g_object_ref(NM_MAIN_DBUS_CONNECTION_GET); + if (!priv->dbus_connection) { + return CONNECTION_FAIL; + } + } + + if (priv->name_owner) { + return CONNECTION_SUCCESS; + } + + if (!priv->name_owner_changed_id) { + priv->name_owner_changed_id = + nm_dbus_connection_signal_subscribe_name_owner_changed(priv->dbus_connection, + DNSCONFD_DBUS_SERVICE, + name_owner_changed_cb, + self, + NULL); + } + + if (!priv->name_owner_cancellable) { + nm_clear_g_cancellable(&priv->name_owner_cancellable); + priv->name_owner_cancellable = g_cancellable_new(); + + nm_dbus_connection_call_get_name_owner(priv->dbus_connection, + DNSCONFD_DBUS_SERVICE, + -1, + priv->name_owner_cancellable, + get_name_owner_cb, + self); + } + + return CONNECTION_WAIT; +} + +static void +parse_all_interface_config(GVariantBuilder *argument_builder, + const CList *ip_data_lst_head, + const char *ca) +{ + NMDnsConfigIPData *ip_data; + const char *const *dns_server_strings; + guint nameserver_count; + const char *ifname; + NMDevice *device; + NMActiveConnection *active_connection; + NMSettingsConnection *settings_connection; + NMActRequest *act_request; + const char *connection_id; + const char *connection_uuid; + const char *dbus_path; + gboolean explicit_default = is_default_interface_explicit(ip_data_lst_head); + + c_list_for_each_entry (ip_data, ip_data_lst_head, ip_data_lst) { + /* No need to free insides of routing and search domains, as they point to data + * owned elsewhere on the other hand networks are created by us and thus we need to also + * free the data */ + gs_free const char **routing_domains = NULL; + gs_free const char **search_domains = NULL; + gs_strfreev char **networks = NULL; + + dns_server_strings = nm_l3_config_data_get_nameservers(ip_data->l3cd, + ip_data->addr_family, + &nameserver_count); + if (!nameserver_count) + continue; + ifname = nm_platform_link_get_name(NM_PLATFORM_GET, ip_data->data->ifindex); + device = nm_manager_get_device_by_ifindex(NM_MANAGER_GET, ip_data->data->ifindex); + act_request = nm_device_get_act_request(device); + active_connection = NM_ACTIVE_CONNECTION(act_request); + + /* Presume that when we have server of this interface then the interface has to have + * an active connection */ + nm_assert(active_connection); + + settings_connection = nm_active_connection_get_settings_connection(active_connection); + connection_id = nm_settings_connection_get_id(settings_connection); + connection_uuid = nm_settings_connection_get_uuid(settings_connection); + dbus_path = nm_dbus_object_get_path_still_exported(NM_DBUS_OBJECT(act_request)); + + /* dbus_path also should be set, because if we are parsing this connection then we + * expect it to be active and exported on dbus */ + nm_assert(dbus_path && dbus_path[0] != 0); + + gather_interface_domains(ip_data, explicit_default, &routing_domains, &search_domains); + get_networks(ip_data, &networks); + + for (guint i = 0; i < nameserver_count; i++) { + if (server_builder_append_base(argument_builder, + ip_data->addr_family, + dns_server_strings[i], + routing_domains, + search_domains, + ca)) { + server_builder_append_interface_info(argument_builder, + ifname, + networks, + connection_id, + connection_uuid, + dbus_path); + } + } + } +} + +static gboolean +update(NMDnsPlugin *plugin, + const NMGlobalDnsConfig *global_config, + const CList *ip_data_lst_head, + const char *hostdomain, + GError **error) +{ + NMDnsDnsconfd *self = NM_DNS_DNSCONFD(plugin); + NMDnsDnsconfdPrivate *priv = NM_DNS_DNSCONFD_GET_PRIVATE(self); + GVariantBuilder argument_builder; + GVariant *args; + + ConnectionState all_connected; + const char *ca = NULL; + guint resolve_mode = 0; + gs_free char *debug_string = NULL; + + g_variant_builder_init(&argument_builder, G_VARIANT_TYPE("(aa{sv}u)")); + g_variant_builder_open(&argument_builder, G_VARIANT_TYPE("aa{sv}")); + + if (global_config) { + _LOGT("parsing global configuration"); + parse_global_config(global_config, &argument_builder, &resolve_mode, &ca); + } + _LOGT("parsing configuration of interfaces"); + parse_all_interface_config(&argument_builder, ip_data_lst_head, ca); + + g_variant_builder_close(&argument_builder); + g_variant_builder_add(&argument_builder, "u", resolve_mode); + + args = g_variant_builder_end(&argument_builder); + + /* Knowing how the update looks will be immensely helpful during debugging */ + _LOGT("arguments variant is composed like: %s", (debug_string = g_variant_print(args, TRUE))); + + nm_clear_pointer(&priv->latest_update_args, g_variant_unref); + priv->latest_update_args = g_variant_ref_sink(args); + + all_connected = ensure_all_connected(self); + + /* We need to consider only whether we are connected, because newer update call + * overrides the old one */ + if (all_connected != CONNECTION_SUCCESS) { + priv->plugin_state = DNSCONFD_PLUGIN_WAIT_CONNECT; + _LOGT("not connected, waiting to connect"); + } else { + priv->plugin_state = DNSCONFD_PLUGIN_WAIT_UPDATE_DONE; + _LOGT("connected, waiting for update to finish"); + } + + if (all_connected == CONNECTION_FAIL) { + nm_utils_error_set(error, + NM_UTILS_ERROR_UNKNOWN, + "no D-Bus connection available to talk to dnsconfd"); + /* Not connected to dbus, can do nothing here */ + return FALSE; + } else if (all_connected == CONNECTION_WAIT) { + /* We do not have name owner yet, and have to wait */ + return TRUE; + } + + send_dnsconfd_update(self); + + _nm_dns_plugin_update_pending_maybe_changed(NM_DNS_PLUGIN(self)); + + return TRUE; +} + +static void +stop(NMDnsPlugin *plugin) +{ + NMDnsDnsconfd *self = NM_DNS_DNSCONFD(plugin); + NMDnsDnsconfdPrivate *priv = NM_DNS_DNSCONFD_GET_PRIVATE(self); + + nm_clear_g_cancellable(&priv->update_cancellable); + nm_clear_g_cancellable(&priv->name_owner_cancellable); + nm_clear_g_cancellable(&priv->serial_cancellable); + nm_clear_g_dbus_connection_signal(priv->dbus_connection, &priv->name_owner_changed_id); + nm_clear_g_dbus_connection_signal(priv->dbus_connection, &priv->properties_changed_id); +} + +static gboolean +_update_pending_detect(NMDnsDnsconfd *self) +{ + NMDnsDnsconfdPrivate *priv = NM_DNS_DNSCONFD_GET_PRIVATE(self); + + if (priv->plugin_state == DNSCONFD_PLUGIN_IDLE) { + /* We are waiting for nothing */ + return FALSE; + } + + /* Update in progress */ + return TRUE; +} + +static gboolean +get_update_pending(NMDnsPlugin *plugin) +{ + NMDnsDnsconfd *self = NM_DNS_DNSCONFD(plugin); + return _update_pending_detect(self); +} + +static void +nm_dns_dnsconfd_init(NMDnsDnsconfd *self) +{} + +NMDnsPlugin * +nm_dns_dnsconfd_new(void) +{ + return g_object_new(NM_TYPE_DNS_DNSCONFD, NULL); +} + +static void +dispose(GObject *object) +{ + NMDnsDnsconfdPrivate *priv = NM_DNS_DNSCONFD_GET_PRIVATE(NM_DNS_DNSCONFD(object)); + + _LOGT("disposing of Dnsconfd plugin"); + + stop(NM_DNS_PLUGIN(object)); + if (priv->name_owner) { + nm_clear_g_free(&priv->name_owner); + } + if (priv->latest_update_args) { + nm_clear_pointer(&priv->latest_update_args, g_variant_unref); + } + + G_OBJECT_CLASS(nm_dns_dnsconfd_parent_class)->dispose(object); + + g_clear_object(&priv->dbus_connection); +} + +static void +nm_dns_dnsconfd_class_init(NMDnsDnsconfdClass *dns_class) +{ + NMDnsPluginClass *plugin_class = NM_DNS_PLUGIN_CLASS(dns_class); + GObjectClass *object_class = G_OBJECT_CLASS(dns_class); + + object_class->dispose = dispose; + + plugin_class->plugin_name = "dnsconfd"; + plugin_class->is_caching = TRUE; + plugin_class->stop = stop; + plugin_class->update = update; + plugin_class->get_update_pending = get_update_pending; +} diff --git a/src/core/dns/nm-dns-dnsconfd.h b/src/core/dns/nm-dns-dnsconfd.h new file mode 100644 index 00000000..1f71b507 --- /dev/null +++ b/src/core/dns/nm-dns-dnsconfd.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024 Red Hat, Inc. + */ + +#ifndef __NETWORKMANAGER_DNS_DNSCONFD_H__ +#define __NETWORKMANAGER_DNS_DNSCONFD_H__ + +#include "nm-dns-plugin.h" +#include "nm-dns-manager.h" + +#define NM_TYPE_DNS_DNSCONFD (nm_dns_dnsconfd_get_type()) +#define NM_DNS_DNSCONFD(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DNS_DNSCONFD, NMDnsDnsconfd)) +#define NM_DNS_DNSCONFD_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DNS_DNSCONFD, NMDnsDnsconfdClass)) +#define NM_IS_DNS_DNSCONFD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DNS_DNSCONFD)) +#define NM_IS_DNS_DNSCONFD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DNS_DNSCONFD)) +#define NM_DNS_DNSCONFD_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DNS_DNSCONFD, NMDnsDnsconfdClass)) + +typedef struct _NMDnsDnsconfd NMDnsDnsconfd; +typedef struct _NMDnsDnsconfdClass NMDnsDnsconfdClass; + +GType nm_dns_dnsconfd_get_type(void); + +NMDnsPlugin *nm_dns_dnsconfd_new(void); + +#endif /* __NETWORKMANAGER_DNS_DNSCONFD_H__ */ diff --git a/src/core/dns/nm-dns-dnsmasq.c b/src/core/dns/nm-dns-dnsmasq.c index 53e40f59..8e3c10c9 100644 --- a/src/core/dns/nm-dns-dnsmasq.c +++ b/src/core/dns/nm-dns-dnsmasq.c @@ -263,7 +263,7 @@ handle_kill: PIDFILE); gl_pid.kill_external_data = g_slice_new(GlPidKillExternalData); - *gl_pid.kill_external_data = (GlPidKillExternalData){ + *gl_pid.kill_external_data = (GlPidKillExternalData) { .shutdown_wait_handle = nm_shutdown_wait_obj_register_handle_full( g_strdup_printf("kill-external-dnsmasq-process-%" G_PID_FORMAT, pid), TRUE), @@ -623,7 +623,7 @@ _gl_pid_spawn(const char *dm_binary, nm_assert(notify); nm_assert(G_IS_CANCELLABLE(cancellable)); gl_pid.spawn_data = g_slice_new(GlPidSpawnAsyncData); - *gl_pid.spawn_data = (GlPidSpawnAsyncData){ + *gl_pid.spawn_data = (GlPidSpawnAsyncData) { .dm_binary = dm_binary, .notify = notify, .notify_user_data = notify_user_data, @@ -853,13 +853,16 @@ add_global_config(NMDnsDnsmasq *self, const char *const *servers = nm_global_dns_domain_get_servers(domain); const char *name = nm_global_dns_domain_get_name(domain); - g_return_if_fail(name); + nm_assert(name); for (j = 0; servers && servers[j]; j++) { - if (!strcmp(name, "*")) - add_dnsmasq_nameserver(self, dnsmasq_servers, servers[j], NULL); - else - add_dnsmasq_nameserver(self, dnsmasq_servers, servers[j], name); + char str[NM_INET_ADDRSTRLEN]; + + /* TODO: support IPv6 link-local addresses with scope id */ + if (!nm_dns_uri_parse_plain(AF_UNSPEC, servers[j], str, NULL)) + continue; + + add_dnsmasq_nameserver(self, dnsmasq_servers, str, nm_streq(name, "*") ? NULL : name); } } } @@ -881,7 +884,7 @@ add_ip_config(NMDnsDnsmasq *self, GVariantBuilder *servers, const NMDnsConfigIPD for (i = 0; i < num; i++) { NMIPAddr a; - if (!nm_utils_dnsname_parse_assert(ip_data->addr_family, strarr[i], NULL, &a, NULL)) + if (!nm_dns_uri_parse_plain(ip_data->addr_family, strarr[i], NULL, &a)) continue; ip_addr_to_string(ip_data->addr_family, &a, iface, ip_addr_to_string_buf); diff --git a/src/core/dns/nm-dns-manager.c b/src/core/dns/nm-dns-manager.c index 8f87fec1..d47590dc 100644 --- a/src/core/dns/nm-dns-manager.c +++ b/src/core/dns/nm-dns-manager.c @@ -32,6 +32,7 @@ #include "nm-config.h" #include "nm-dbus-object.h" #include "nm-dns-dnsmasq.h" +#include "nm-dns-dnsconfd.h" #include "nm-dns-plugin.h" #include "nm-dns-systemd-resolved.h" #include "nm-ip-config.h" @@ -401,7 +402,7 @@ _dns_config_ip_data_new(NMDnsConfigData *data, nm_assert(ip_config_type != NM_DNS_IP_CONFIG_TYPE_REMOVED); ip_data = g_slice_new(NMDnsConfigIPData); - *ip_data = (NMDnsConfigIPData){ + *ip_data = (NMDnsConfigIPData) { .data = data, .source_tag = source_tag, .l3cd = nm_l3_config_data_ref_and_seal(l3cd), @@ -600,7 +601,7 @@ merge_one_l3cd(NMResolvConfData *rc, int addr_family, int ifindex, const NML3Con for (i = 0; i < num_nameservers; i++) { NMIPAddr a; - if (!nm_utils_dnsname_parse_assert(addr_family, strarr[i], NULL, &a, NULL)) + if (!nm_dns_uri_parse_plain(addr_family, strarr[i], NULL, &a)) continue; if (addr_family == AF_INET) @@ -1291,8 +1292,15 @@ merge_global_dns_config(NMResolvConfData *rc, NMGlobalDnsConfig *global_conf) if (!servers) return TRUE; - for (i = 0; servers[i]; i++) - add_string_item(rc->nameservers, servers[i], TRUE); + for (i = 0; servers[i]; i++) { + char addrstr[NM_INET_ADDRSTRLEN]; + + /* TODO: support IPv6 link-local addresses with scope id */ + if (!nm_dns_uri_parse_plain(AF_UNSPEC, servers[i], addrstr, NULL)) + continue; + + add_string_item(rc->nameservers, addrstr, TRUE); + } return TRUE; } @@ -1300,7 +1308,6 @@ merge_global_dns_config(NMResolvConfData *rc, NMGlobalDnsConfig *global_conf) static const char * get_nameserver_list(int addr_family, const NML3ConfigData *l3cd, NMStrBuf *tmp_strbuf) { - char buf[NM_INET_ADDRSTRLEN]; guint num; guint i; const char *const *strarr; @@ -1309,15 +1316,9 @@ get_nameserver_list(int addr_family, const NML3ConfigData *l3cd, NMStrBuf *tmp_s strarr = nm_l3_config_data_get_nameservers(l3cd, addr_family, &num); for (i = 0; i < num; i++) { - NMIPAddr a; - - if (!nm_utils_dnsname_parse_assert(addr_family, strarr[i], NULL, &a, NULL)) - continue; - - nm_inet_ntop(addr_family, &a, buf); if (i > 0) nm_str_buf_append_c(tmp_strbuf, ' '); - nm_str_buf_append(tmp_strbuf, buf); + nm_str_buf_append(tmp_strbuf, strarr[i]); } nm_str_buf_maybe_expand(tmp_strbuf, 1, FALSE); @@ -2108,7 +2109,7 @@ nm_dns_manager_set_ip_config(NMDnsManager *self, if (!data) { data = g_slice_new(NMDnsConfigData); - *data = (NMDnsConfigData){ + *data = (NMDnsConfigData) { .ifindex = ifindex, .self = self, .data_lst_head = C_LIST_INIT(data->data_lst_head), @@ -2525,6 +2526,12 @@ again: priv->plugin = nm_dns_dnsmasq_new(); plugin_changed = TRUE; } + } else if (nm_streq0(mode, "dnsconfd")) { + if (force_reload_plugin || !NM_IS_DNS_DNSCONFD(priv->plugin)) { + _clear_plugin(self); + priv->plugin = nm_dns_dnsconfd_new(); + plugin_changed = TRUE; + } } else { if (!NM_IN_STRSET(mode, "none", "default")) { if (mode) { @@ -2541,7 +2548,7 @@ again: if (rc_manager == NM_DNS_MANAGER_RESOLV_CONF_MAN_AUTO) { rc_manager_was_auto = TRUE; - if (nm_streq(mode, "systemd-resolved")) + if (nm_streq(mode, "systemd-resolved") || nm_streq(mode, "dnsconfd")) rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED; else if (HAS_RESOLVCONF && g_file_test(RESOLVCONF_PATH, G_FILE_TEST_IS_EXECUTABLE)) { /* We detect /sbin/resolvconf only at this stage. That means, if you install @@ -2730,7 +2737,6 @@ _get_config_variant(NMDnsManager *self) guint num_domains; guint num_searches; guint i; - char buf[NM_INET_ADDRSTRLEN]; const char *ifname; const char *const *strarr; @@ -2742,12 +2748,7 @@ _get_config_variant(NMDnsManager *self) g_variant_builder_init(&strv_builder, G_VARIANT_TYPE("as")); for (i = 0; i < num; i++) { - NMIPAddr a; - - if (!nm_utils_dnsname_parse_assert(ip_data->addr_family, strarr[i], NULL, &a, NULL)) - continue; - - g_variant_builder_add(&strv_builder, "s", nm_inet_ntop(ip_data->addr_family, &a, buf)); + g_variant_builder_add(&strv_builder, "s", strarr[i]); } g_variant_builder_add(&entry_builder, "{sv}", diff --git a/src/core/dns/nm-dns-systemd-resolved.c b/src/core/dns/nm-dns-systemd-resolved.c index 24c7c774..0701a1dc 100644 --- a/src/core/dns/nm-dns-systemd-resolved.c +++ b/src/core/dns/nm-dns-systemd-resolved.c @@ -248,7 +248,7 @@ _request_item_append(NMDnsSystemdResolved *self, RequestItem *request_item; request_item = g_slice_new(RequestItem); - *request_item = (RequestItem){ + *request_item = (RequestItem) { .ref_count = 1, .operation = operation, .argument = g_variant_ref_sink(argument), @@ -396,13 +396,24 @@ update_add_ip_config(NMDnsSystemdResolved *self, strarr = nm_l3_config_data_get_nameservers(ip_data->l3cd, ip_data->addr_family, &n); for (i = 0; i < n; i++) { - const char *server_name; - NMIPAddr a; + NMDnsServer dns_server; - if (!nm_utils_dnsname_parse_assert(ip_data->addr_family, strarr[i], NULL, &a, &server_name)) + if (!nm_dns_uri_parse(ip_data->addr_family, strarr[i], &dns_server)) continue; - if (server_name) { + if (!NM_IN_SET(dns_server.scheme, + NM_DNS_URI_SCHEME_TLS, + NM_DNS_URI_SCHEME_NONE, + NM_DNS_URI_SCHEME_UDP)) { + /* In systemd-resolved, the use of DNS-over-TLS can't be controlled + * for each name server; it is controlled via a per-link knob. + * Therefore, we pass all the addresses we know about and then let + * systemd-resolved decide whether to use DoT, based on the + * "connection.dns-over-tls" property. */ + continue; + } + + if (dns_server.servername) { NM_SET_OUT(out_require_dns_ex, TRUE); if (priv->has_set_link_dns_ex == FALSE) { /* The caller won't care about this result anymore. We can skip setting it. */ @@ -413,15 +424,19 @@ update_add_ip_config(NMDnsSystemdResolved *self, if (dns_ex) { g_variant_builder_open(dns_ex, G_VARIANT_TYPE("(iayqs)")); g_variant_builder_add(dns_ex, "i", ip_data->addr_family); - g_variant_builder_add_value(dns_ex, nm_g_variant_new_ay((gconstpointer) &a, addr_size)); + g_variant_builder_add_value( + dns_ex, + nm_g_variant_new_ay((gconstpointer) &dns_server.addr, addr_size)); g_variant_builder_add(dns_ex, "q", 0); - g_variant_builder_add(dns_ex, "s", server_name ?: ""); + g_variant_builder_add(dns_ex, "s", dns_server.servername ?: ""); g_variant_builder_close(dns_ex); } if (dns) { g_variant_builder_open(dns, G_VARIANT_TYPE("(iay)")); g_variant_builder_add(dns, "i", ip_data->addr_family); - g_variant_builder_add_value(dns, nm_g_variant_new_ay((gconstpointer) &a, addr_size)); + g_variant_builder_add_value( + dns, + nm_g_variant_new_ay((gconstpointer) &dns_server.addr, addr_size)); g_variant_builder_close(dns); } has_config = TRUE; @@ -803,7 +818,7 @@ update(NMDnsPlugin *plugin, ic = g_hash_table_lookup(interfaces, GINT_TO_POINTER(ifindex)); if (!ic) { ic = g_slice_new(InterfaceConfig); - *ic = (InterfaceConfig){ + *ic = (InterfaceConfig) { .ifindex = ifindex, .ip_data_list = g_ptr_array_sized_new(4), }; @@ -855,7 +870,7 @@ update(NMDnsPlugin *plugin, InterfaceConfig ic; _LOGT("clear previously configured ifindex %d", ifindex); - ic = (InterfaceConfig){ + ic = (InterfaceConfig) { .ifindex = ifindex, .ip_data_list = NULL, }; @@ -1053,7 +1068,7 @@ _resolve_handle_call_cb(GObject *source, GAsyncResult *result, gpointer user_dat NMDnsSystemdResolvedAddressResult *n; n = nm_g_array_append_new(v_names, NMDnsSystemdResolvedAddressResult); - *n = (NMDnsSystemdResolvedAddressResult){ + *n = (NMDnsSystemdResolvedAddressResult) { .name = g_steal_pointer(&v_name), .ifindex = v_ifindex, }; @@ -1167,7 +1182,7 @@ nm_dns_systemd_resolved_resolve_address(NMDnsSystemdResolved nm_assert(callback); handle = g_slice_new(NMDnsSystemdResolvedResolveHandle); - *handle = (NMDnsSystemdResolvedResolveHandle){ + *handle = (NMDnsSystemdResolvedResolveHandle) { .self = self, .timeout_msec = timeout_msec, .callback_user_data = user_data, diff --git a/src/core/dnsmasq/nm-dnsmasq-manager.c b/src/core/dnsmasq/nm-dnsmasq-manager.c index d245d5d3..030a8e28 100644 --- a/src/core/dnsmasq/nm-dnsmasq-manager.c +++ b/src/core/dnsmasq/nm-dnsmasq-manager.c @@ -92,6 +92,8 @@ static GPtrArray * create_dm_cmd_line(const char *iface, const NML3ConfigData *l3cd, const char *pidfile, + const char *shared_dhcp_range, + int shared_dhcp_lease_time, gboolean announce_android_metered, GError **error) { @@ -100,7 +102,6 @@ create_dm_cmd_line(const char *iface, char first[INET_ADDRSTRLEN]; char last[INET_ADDRSTRLEN]; char listen_address_s[INET_ADDRSTRLEN]; - char sbuf_addr[INET_ADDRSTRLEN]; gs_free char *error_desc = NULL; const char *dm_binary; const NMPlatformIP4Address *listen_address; @@ -108,6 +109,10 @@ create_dm_cmd_line(const char *iface, guint n; guint i; + nm_assert((shared_dhcp_lease_time == 0) || (shared_dhcp_lease_time == G_MAXINT32) + || ((NM_MIN_FINITE_LEASE_TIME <= shared_dhcp_lease_time) + && (shared_dhcp_lease_time <= NM_MAX_FINITE_LEASE_TIME))); + listen_address = NMP_OBJECT_CAST_IP4_ADDRESS( nm_l3_config_data_get_first_obj(l3cd, NMP_OBJECT_TYPE_IP4_ADDRESS, NULL)); @@ -150,14 +155,32 @@ create_dm_cmd_line(const char *iface, nm_strv_ptrarray_add_string_concat(cmd, "--listen-address=", listen_address_s); - if (!nm_dnsmasq_utils_get_range(listen_address, first, last, &error_desc)) { + shared_dhcp_lease_time = (shared_dhcp_lease_time != 0) ? shared_dhcp_lease_time : 3600; + if (shared_dhcp_range && *shared_dhcp_range) { + if (shared_dhcp_lease_time < G_MAXINT32) { + nm_strv_ptrarray_add_string_printf(cmd, + "--dhcp-range=%s,%d", + shared_dhcp_range, + shared_dhcp_lease_time); + } else { + nm_strv_ptrarray_add_string_printf(cmd, "--dhcp-range=%s,infinite", shared_dhcp_range); + } + } else if (nm_dnsmasq_utils_get_range(listen_address, first, last, &error_desc)) { + if (shared_dhcp_lease_time < G_MAXINT32) { + nm_strv_ptrarray_add_string_printf(cmd, + "--dhcp-range=%s,%s,%d", + first, + last, + shared_dhcp_lease_time); + } else { + nm_strv_ptrarray_add_string_printf(cmd, "--dhcp-range=%s,%s,infinite", first, last); + } + } else { g_set_error_literal(error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, error_desc); _LOGW("failed to find DHCP address ranges: %s", error_desc); return NULL; } - nm_strv_ptrarray_add_string_printf(cmd, "--dhcp-range=%s,%s,60m", first, last); - if (nm_l3_config_data_get_best_default_route(l3cd, AF_INET)) { nm_strv_ptrarray_add_string_concat(cmd, "--dhcp-option=option:router,", listen_address_s); } @@ -167,13 +190,13 @@ create_dm_cmd_line(const char *iface, nm_gstring_prepare(&s); g_string_append(s, "--dhcp-option=option:dns-server"); for (i = 0; i < n; i++) { - in_addr_t a; + char addrstr[NM_INET_ADDRSTRLEN]; - if (!nm_utils_dnsname_parse_assert(AF_INET, strarr[i], NULL, &a, NULL)) + if (!nm_dns_uri_parse_plain(AF_INET, strarr[i], addrstr, NULL)) continue; g_string_append_c(s, ','); - g_string_append(s, nm_inet4_ntop(a, sbuf_addr)); + g_string_append(s, addrstr); } nm_strv_ptrarray_take_gstring(cmd, &s); } @@ -249,6 +272,8 @@ out: gboolean nm_dnsmasq_manager_start(NMDnsMasqManager *manager, const NML3ConfigData *l3cd, + const char *shared_dhcp_range, + int shared_dhcp_lease_time, gboolean announce_android_metered, GError **error) { @@ -265,7 +290,13 @@ nm_dnsmasq_manager_start(NMDnsMasqManager *manager, kill_existing_by_pidfile(priv->pidfile); - dm_cmd = create_dm_cmd_line(priv->iface, l3cd, priv->pidfile, announce_android_metered, error); + dm_cmd = create_dm_cmd_line(priv->iface, + l3cd, + priv->pidfile, + shared_dhcp_range, + shared_dhcp_lease_time, + announce_android_metered, + error); if (!dm_cmd) return FALSE; diff --git a/src/core/dnsmasq/nm-dnsmasq-manager.h b/src/core/dnsmasq/nm-dnsmasq-manager.h index 2f10a9e8..a393807d 100644 --- a/src/core/dnsmasq/nm-dnsmasq-manager.h +++ b/src/core/dnsmasq/nm-dnsmasq-manager.h @@ -35,6 +35,8 @@ NMDnsMasqManager *nm_dnsmasq_manager_new(const char *iface); gboolean nm_dnsmasq_manager_start(NMDnsMasqManager *manager, const NML3ConfigData *l3cd, + const char *shared_dhcp_range, + int shared_dhcp_lease_time, gboolean announce_android_metered, GError **error); diff --git a/src/core/meson.build b/src/core/meson.build index 4419ff62..6cf891ee 100644 --- a/src/core/meson.build +++ b/src/core/meson.build @@ -105,6 +105,7 @@ libNetworkManager = static_library( 'devices/nm-device-hsr.c', 'devices/nm-device-infiniband.c', 'devices/nm-device-ip-tunnel.c', + 'devices/nm-device-ipvlan.c', 'devices/nm-device-loopback.c', 'devices/nm-device-macsec.c', 'devices/nm-device-macvlan.c', @@ -119,10 +120,10 @@ libNetworkManager = static_library( 'devices/nm-lldp-listener.c', 'dhcp/nm-dhcp-dhclient.c', 'dhcp/nm-dhcp-dhclient-utils.c', - 'dhcp/nm-dhcp-dhcpcanon.c', 'dhcp/nm-dhcp-dhcpcd.c', 'dhcp/nm-dhcp-listener.c', 'dns/nm-dns-dnsmasq.c', + 'dns/nm-dns-dnsconfd.c', 'dns/nm-dns-manager.c', 'dns/nm-dns-plugin.c', 'dns/nm-dns-systemd-resolved.c', diff --git a/src/core/ndisc/nm-fake-ndisc.c b/src/core/ndisc/nm-fake-ndisc.c index f0b6dcf6..b2858848 100644 --- a/src/core/ndisc/nm-fake-ndisc.c +++ b/src/core/ndisc/nm-fake-ndisc.c @@ -161,7 +161,7 @@ nm_fake_ndisc_add_prefix(NMFakeNDisc *self, g_assert(ra); prefix = nm_g_array_append_new(ra->prefixes, FakePrefix); - *prefix = (FakePrefix){ + *prefix = (FakePrefix) { .plen = plen, .expiry_msec = expiry_msec, .expiry_preferred_msec = expiry_preferred_msec, diff --git a/src/core/ndisc/nm-lndp-ndisc.c b/src/core/ndisc/nm-lndp-ndisc.c index eea79373..33e9ebf3 100644 --- a/src/core/ndisc/nm-lndp-ndisc.c +++ b/src/core/ndisc/nm-lndp-ndisc.c @@ -181,7 +181,7 @@ receive_ra(struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) * SHOULD NOT appear on the default router list. * * We handle that by tracking a gateway that expires right now. */ - gateway = (NMNDiscGateway){ + gateway = (NMNDiscGateway) { .address = gateway_addr, .expiry_msec = _nm_ndisc_lifetime_to_expiry(now_msec, ndp_msgra_router_lifetime(msgra)), .preference = _route_preference_coerce(ndp_msgra_route_preference(msgra)), diff --git a/src/core/ndisc/nm-ndisc.c b/src/core/ndisc/nm-ndisc.c index 86b7da6e..ad2edd8d 100644 --- a/src/core/ndisc/nm-ndisc.c +++ b/src/core/ndisc/nm-ndisc.c @@ -130,7 +130,7 @@ nm_ndisc_data_to_l3cd(NMDedupMultiIndex *multi_idx, const NMNDiscAddress *ndisc_addr = &rdata->addresses[i]; NMPlatformIP6Address a; - a = (NMPlatformIP6Address){ + a = (NMPlatformIP6Address) { .ifindex = ifindex, .address = ndisc_addr->address, .plen = 64, @@ -151,7 +151,7 @@ nm_ndisc_data_to_l3cd(NMDedupMultiIndex *multi_idx, const NMNDiscRoute *ndisc_route = &rdata->routes[i]; NMPlatformIP6Route r; - r = (NMPlatformIP6Route){ + r = (NMPlatformIP6Route) { .ifindex = ifindex, .network = ndisc_route->network, .plen = ndisc_route->plen, @@ -205,10 +205,7 @@ nm_ndisc_data_to_l3cd(NMDedupMultiIndex *multi_idx, } for (i = 0; i < rdata->dns_servers_n; i++) { - nm_l3_config_data_add_nameserver_detail(l3cd, - AF_INET6, - &rdata->dns_servers[i].address, - NULL); + nm_l3_config_data_add_nameserver_addr(l3cd, AF_INET6, &rdata->dns_servers[i].address); } for (i = 0; i < rdata->dns_domains_n; i++) @@ -836,7 +833,7 @@ nm_ndisc_add_dns_domain(NMNDisc *ndisc, const NMNDiscDNSDomain *new_item, gint64 return FALSE; item = nm_g_array_append_new(rdata->dns_domains, NMNDiscDNSDomain); - *item = (NMNDiscDNSDomain){ + *item = (NMNDiscDNSDomain) { .domain = g_strdup(new_item->domain), .expiry_msec = new_item->expiry_msec, }; @@ -991,9 +988,8 @@ announce_router(NMNDisc *ndisc) /* Schedule next initial announcement retransmit. */ priv->send_ra_id = - g_timeout_add_seconds(nm_random_u64_range_full(NM_NDISC_ROUTER_ADVERT_DELAY, - NM_NDISC_ROUTER_ADVERT_INITIAL_INTERVAL, - FALSE), + g_timeout_add_seconds(nm_random_u64_range(NM_NDISC_ROUTER_ADVERT_DELAY, + NM_NDISC_ROUTER_ADVERT_INITIAL_INTERVAL), (GSourceFunc) announce_router, ndisc); } else { @@ -1027,9 +1023,10 @@ announce_router_initial(NMNDisc *ndisc) /* Schedule the initial send rather early. Clamp the delay by minimal * delay and not the initial advert internal so that we start fast. */ if (G_LIKELY(!priv->send_ra_id)) { - priv->send_ra_id = g_timeout_add_seconds(nm_random_u64_range(NM_NDISC_ROUTER_ADVERT_DELAY), - (GSourceFunc) announce_router, - ndisc); + priv->send_ra_id = + g_timeout_add_seconds(nm_random_u64_range(0, NM_NDISC_ROUTER_ADVERT_DELAY), + (GSourceFunc) announce_router, + ndisc); } } @@ -1045,7 +1042,7 @@ announce_router_solicited(NMNDisc *ndisc) nm_clear_g_source(&priv->send_ra_id); if (!priv->send_ra_id) { - priv->send_ra_id = g_timeout_add(nm_random_u64_range(NM_NDISC_ROUTER_ADVERT_DELAY_MS), + priv->send_ra_id = g_timeout_add(nm_random_u64_range(0, NM_NDISC_ROUTER_ADVERT_DELAY_MS), (GSourceFunc) announce_router, ndisc); } @@ -1090,7 +1087,7 @@ nm_ndisc_set_config(NMNDisc *ndisc, const NML3ConfigData *l3cd) if (!lifetime) continue; - a = (NMNDiscAddress){ + a = (NMNDiscAddress) { .address = addr->address, .expiry_msec = _nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, lifetime), .expiry_preferred_msec = @@ -1106,14 +1103,14 @@ nm_ndisc_set_config(NMNDisc *ndisc, const NML3ConfigData *l3cd) if (l3cd) strvarr = nm_l3_config_data_get_nameservers(l3cd, AF_INET6, &len); for (i = 0; i < len; i++) { - struct in6_addr a; + NMIPAddr a; NMNDiscDNSServer n; - if (!nm_utils_dnsname_parse_assert(AF_INET6, strvarr[i], NULL, &a, NULL)) + if (!nm_dns_uri_parse_plain(AF_INET6, strvarr[i], NULL, &a)) continue; - n = (NMNDiscDNSServer){ - .address = a, + n = (NMNDiscDNSServer) { + .address = a.addr6, .expiry_msec = _nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, NM_NDISC_ROUTER_LIFETIME), }; @@ -1128,7 +1125,7 @@ nm_ndisc_set_config(NMNDisc *ndisc, const NML3ConfigData *l3cd) for (i = 0; i < len; i++) { NMNDiscDNSDomain n; - n = (NMNDiscDNSDomain){ + n = (NMNDiscDNSDomain) { .domain = (char *) strvarr[i], .expiry_msec = _nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, NM_NDISC_ROUTER_LIFETIME), diff --git a/src/core/ndisc/nm-ndisc.h b/src/core/ndisc/nm-ndisc.h index b8f8b06e..8f1a12a2 100644 --- a/src/core/ndisc/nm-ndisc.h +++ b/src/core/ndisc/nm-ndisc.h @@ -40,7 +40,7 @@ typedef enum { const char *nm_ndisc_dhcp_level_to_string(NMNDiscDHCPLevel level); -#define NM_NDISC_INFINITY_U32 ((uint32_t) - 1) +#define NM_NDISC_INFINITY_U32 ((uint32_t) -1) /* It's important that this is G_MAXINT64, so that we can meaningfully do * MIN(e1, e2) to find the minimum expiry time (and properly handle if any diff --git a/src/core/ndisc/tests/test-ndisc-linux.c b/src/core/ndisc/tests/test-ndisc-linux.c index 66c7e157..e4184184 100644 --- a/src/core/ndisc/tests/test-ndisc-linux.c +++ b/src/core/ndisc/tests/test-ndisc-linux.c @@ -62,7 +62,7 @@ main(int argc, char **argv) l3cfg = nm_netns_l3cfg_acquire(NM_NETNS_GET, ifindex); - config = (NMNDiscConfig){ + config = (NMNDiscConfig) { .l3cfg = l3cfg, .ifname = nm_l3cfg_get_ifname(l3cfg, TRUE), .stable_type = NM_UTILS_STABLE_TYPE_UUID, diff --git a/src/core/nm-audit-manager.c b/src/core/nm-audit-manager.c index 7cf52946..70d5d88b 100644 --- a/src/core/nm-audit-manager.c +++ b/src/core/nm-audit-manager.c @@ -90,7 +90,7 @@ _audit_field_init_string(AuditField *field, gboolean need_encoding, AuditBackend backends) { - *field = (AuditField){ + *field = (AuditField) { .name = name, .need_encoding = need_encoding, .backends = backends, @@ -102,7 +102,7 @@ _audit_field_init_string(AuditField *field, static void _audit_field_init_uint64(AuditField *field, const char *name, guint64 val, AuditBackend backends) { - *field = (AuditField){ + *field = (AuditField) { .name = name, .backends = backends, .value_type = NM_VALUE_TYPE_UINT64, diff --git a/src/core/nm-auth-manager.c b/src/core/nm-auth-manager.c index 242f0055..65357a9f 100644 --- a/src/core/nm-auth-manager.c +++ b/src/core/nm-auth-manager.c @@ -327,7 +327,7 @@ nm_auth_manager_check_authorization(NMAuthManager *self : POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE; call_id = g_slice_new(NMAuthManagerCallId); - *call_id = (NMAuthManagerCallId){ + *call_id = (NMAuthManagerCallId) { .self = g_object_ref(self), .callback = callback, .user_data = user_data, diff --git a/src/core/nm-auth-utils.c b/src/core/nm-auth-utils.c index aa2547b3..389004aa 100644 --- a/src/core/nm-auth-utils.c +++ b/src/core/nm-auth-utils.c @@ -293,7 +293,7 @@ nm_auth_chain_set_data_unsafe(NMAuthChain *self, } chain_data = &self->data_arr[self->data_len++]; - *chain_data = (ChainData){ + *chain_data = (ChainData) { .tag = tag, .data = data, .destroy = data_destroy, @@ -445,7 +445,7 @@ nm_auth_chain_add_call_unsafe(NMAuthChain *self, const char *permission, gboolea } call = g_slice_new(AuthCall); - *call = (AuthCall){ + *call = (AuthCall) { .chain = self, .call_id = NULL, .result = NM_AUTH_CALL_RESULT_UNKNOWN, @@ -520,7 +520,7 @@ nm_auth_chain_new_subject(NMAuthSubject *subject, nm_assert(done_func); self = g_slice_new(NMAuthChain); - *self = (NMAuthChain){ + *self = (NMAuthChain) { .done_func = done_func, .user_data = user_data, .context = nm_g_object_ref(context), diff --git a/src/core/nm-bond-manager.c b/src/core/nm-bond-manager.c index f24c8163..2f7fe36c 100644 --- a/src/core/nm-bond-manager.c +++ b/src/core/nm-bond-manager.c @@ -994,7 +994,7 @@ nm_bond_manager_new(struct _NMPlatform *platform, nm_assert(ifindex > 0); self = g_slice_new(NMBondManager); - *self = (NMBondManager){ + *self = (NMBondManager) { .platform = g_object_ref(platform), .ifindex = ifindex, .reg_state = REGISTRATION_STATE_NONE, diff --git a/src/core/nm-config-data.c b/src/core/nm-config-data.c index 0a73695a..5a84a2c8 100644 --- a/src/core/nm-config-data.c +++ b/src/core/nm-config-data.c @@ -46,11 +46,13 @@ struct _NMGlobalDnsDomain { }; struct _NMGlobalDnsConfig { - char **searches; - char **options; - GHashTable *domains; - const char **domain_list; - gboolean internal; + char **searches; + char **options; + GHashTable *domains; + const char **domain_list; + gboolean internal; + char *cert_authority; + NMDnsResolveMode resolve_mode; }; /*****************************************************************************/ @@ -399,7 +401,7 @@ nm_config_data_get_ignore_carrier_for_port(const NMConfigData *self, if (!nm_utils_ifname_valid_kernel(controller, NULL)) goto out_default; - match_data = (NMMatchSpecDeviceData){ + match_data = (NMMatchSpecDeviceData) { .interface_name = controller, .device_type = port_type, }; @@ -955,6 +957,22 @@ nm_global_dns_config_get_options(const NMGlobalDnsConfig *dns_config) return (const char *const *) dns_config->options; } +const char * +nm_global_dns_config_get_certification_authority(const NMGlobalDnsConfig *dns_config) +{ + g_return_val_if_fail(dns_config, NULL); + + return (const char *) dns_config->cert_authority; +} + +guint +nm_global_dns_config_get_resolve_mode(const NMGlobalDnsConfig *dns_config) +{ + g_return_val_if_fail(dns_config, 0); + + return dns_config->resolve_mode; +} + guint nm_global_dns_config_get_num_domains(const NMGlobalDnsConfig *dns_config) { @@ -1155,6 +1173,9 @@ nm_global_dns_config_free(NMGlobalDnsConfig *dns_config) g_free(dns_config->domain_list); if (dns_config->domains) g_hash_table_unref(dns_config->domains); + if (dns_config->cert_authority) { + g_free(dns_config->cert_authority); + } g_free(dns_config); } } @@ -1180,6 +1201,29 @@ global_dns_config_seal_domains(NMGlobalDnsConfig *dns_config) dns_config->domain_list = nm_strdict_get_keys(dns_config->domains, TRUE, NULL); } +static const char * +nm_dns_resolve_mode_to_string(const NMDnsResolveMode mode) +{ + const char *to_string[3] = {"backup", "prefer", "exclusive"}; + + nm_assert(mode < _NM_NUM_DNS_RESOLVE_MODES); + + return to_string[mode]; +} + +static NMDnsResolveMode +nm_dns_resolve_mode_from_string(const char *string) +{ + if (nm_streq0(string, "backup")) { + return NM_DNS_RESOLVE_MODE_BACKUP; + } else if (nm_streq0(string, "prefer")) { + return NM_DNS_RESOLVE_MODE_PREFER; + } else if (nm_streq0(string, "exclusive")) { + return NM_DNS_RESOLVE_MODE_EXCLUSIVE; + } + return _NM_NUM_DNS_RESOLVE_MODES; +} + static NMGlobalDnsConfig * load_global_dns(GKeyFile *keyfile, gboolean internal) { @@ -1189,6 +1233,9 @@ load_global_dns(GKeyFile *keyfile, gboolean internal) int g, i, j, domain_prefix_len; gboolean default_found = FALSE; char **strv; + gs_free char *cert_authority = NULL; + gs_free char *resolve_mode = NULL; + NMDnsResolveMode parsed_resolve_mode; if (internal) { group = NM_CONFIG_KEYFILE_GROUP_INTERN_GLOBAL_DNS; @@ -1202,7 +1249,31 @@ load_global_dns(GKeyFile *keyfile, gboolean internal) if (!nm_config_keyfile_has_global_dns_config(keyfile, internal)) return NULL; - dns_config = g_malloc0(sizeof(NMGlobalDnsConfig)); + dns_config = g_malloc0(sizeof(NMGlobalDnsConfig)); + + cert_authority = g_key_file_get_string(keyfile, + group, + NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_CERTIFICATION_AUTHORITY, + NULL); + if (cert_authority) { + dns_config->cert_authority = g_steal_pointer(&cert_authority); + } + + resolve_mode = + g_key_file_get_string(keyfile, group, NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_RESOLVE_MODE, NULL); + + if (resolve_mode) { + parsed_resolve_mode = nm_dns_resolve_mode_from_string(resolve_mode); + if (parsed_resolve_mode == _NM_NUM_DNS_RESOLVE_MODES) { + nm_log_dbg(LOGD_CORE, + "%s global DNS configuration has invalid value '%s', assuming backup", + internal ? "internal" : "user", + NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_RESOLVE_MODE); + } else { + dns_config->resolve_mode = parsed_resolve_mode; + } + } + dns_config->domains = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, @@ -1259,10 +1330,19 @@ load_global_dns(GKeyFile *keyfile, gboolean internal) if (strv) { nm_strv_cleanup(strv, TRUE, TRUE, TRUE); for (i = 0, j = 0; strv[i]; i++) { - if (nm_inet_is_valid(AF_INET, strv[i]) || nm_inet_is_valid(AF_INET6, strv[i])) - strv[j++] = strv[i]; - else + gs_free char *to_free = NULL; + + if (nm_dns_uri_normalize(AF_UNSPEC, strv[i], &to_free)) { + if (to_free) { + g_free(strv[i]); + strv[j++] = g_steal_pointer(&to_free); + } else { + strv[j++] = strv[i]; + } + } else { + nm_log_dbg(LOGD_CORE, "invalid global name server \"%s\"", strv[i]); g_free(strv[i]); + } } if (j == 0) g_free(strv); @@ -1335,6 +1415,21 @@ nm_global_dns_config_to_dbus(const NMGlobalDnsConfig *dns_config, GValue *value) g_variant_new_strv((const char *const *) dns_config->options, -1)); } + if (dns_config->cert_authority) { + g_variant_builder_add(&conf_builder, + "{sv}", + "certification-authority", + g_variant_new("s", dns_config->cert_authority)); + } + + if (dns_config->resolve_mode) { + g_variant_builder_add( + &conf_builder, + "{sv}", + "resolve-mode", + g_variant_new("s", nm_dns_resolve_mode_to_string(dns_config->resolve_mode))); + } + g_variant_builder_init(&domains_builder, G_VARIANT_TYPE("a{sv}")); if (dns_config->domain_list) { for (i = 0; dns_config->domain_list[i]; i++) { @@ -1435,6 +1530,7 @@ nm_global_dns_config_from_dbus(const GValue *value, GError **error) GVariantIter iter; char **strv, *key; int i, j; + gs_free char *resolve_mode_buffer = NULL; if (!G_VALUE_HOLDS_VARIANT(value)) { g_set_error(error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, "invalid value type"); @@ -1490,7 +1586,23 @@ nm_global_dns_config_from_dbus(const GValue *value, GError **error) } g_variant_unref(v); } + } else if (nm_streq0(key, "resolve-mode") + && g_variant_is_of_type(val, G_VARIANT_TYPE("s"))) { + g_variant_get(val, "s", &resolve_mode_buffer); + dns_config->resolve_mode = nm_dns_resolve_mode_from_string(resolve_mode_buffer); + if (dns_config->resolve_mode == _NM_NUM_DNS_RESOLVE_MODES) { + g_set_error_literal(error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_FAILED, + "Global DNS configuration contains invalid resolve-mode"); + nm_global_dns_config_free(dns_config); + return NULL; + } + } else if (nm_streq0(key, "certification-authority") + && g_variant_is_of_type(val, G_VARIANT_TYPE("s"))) { + g_variant_get(val, "s", &dns_config->cert_authority); } + g_variant_unref(val); } @@ -1879,7 +1991,7 @@ _match_section_info_init(MatchSectionInfo *connection_info, if (!value) continue; - vals[j++] = (NMUtilsNamedValue){ + vals[j++] = (NMUtilsNamedValue) { .name = g_steal_pointer(&key), .value_str = value, }; diff --git a/src/core/nm-config-data.h b/src/core/nm-config-data.h index 1ea0ccf2..d764a7c4 100644 --- a/src/core/nm-config-data.h +++ b/src/core/nm-config-data.h @@ -120,6 +120,13 @@ typedef enum { } NMConfigChangeFlags; +typedef enum { + NM_DNS_RESOLVE_MODE_BACKUP = 0, + NM_DNS_RESOLVE_MODE_PREFER = 1, + NM_DNS_RESOLVE_MODE_EXCLUSIVE = 2, + _NM_NUM_DNS_RESOLVE_MODES = 3 +} NMDnsResolveMode; + typedef struct _NMConfigDataClass NMConfigDataClass; typedef struct _NMGlobalDnsConfig NMGlobalDnsConfig; @@ -269,6 +276,9 @@ GKeyFile *nm_config_data_clone_keyfile_intern(const NMConfigData *self); const char *const *nm_global_dns_config_get_searches(const NMGlobalDnsConfig *dns_config); const char *const *nm_global_dns_config_get_options(const NMGlobalDnsConfig *dns_config); +const char *nm_global_dns_config_get_certification_authority(const NMGlobalDnsConfig *dns_config); +guint nm_global_dns_config_get_resolve_mode(const NMGlobalDnsConfig *dns_config); + guint nm_global_dns_config_get_num_domains(const NMGlobalDnsConfig *dns_config); NMGlobalDnsDomain *nm_global_dns_config_get_domain(const NMGlobalDnsConfig *dns_config, guint i); NMGlobalDnsDomain *nm_global_dns_config_lookup_domain(const NMGlobalDnsConfig *dns_config, diff --git a/src/core/nm-config.c b/src/core/nm-config.c index cc3d1135..a55d2d13 100644 --- a/src/core/nm-config.c +++ b/src/core/nm-config.c @@ -905,7 +905,9 @@ static const ConfigGroup config_groups[] = { { .group = NM_CONFIG_KEYFILE_GROUP_GLOBAL_DNS, .keys = NM_MAKE_STRV(NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_OPTIONS, - NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_SEARCHES, ), + NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_SEARCHES, + NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_CERTIFICATION_AUTHORITY, + NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_RESOLVE_MODE, ), }, { .group = NM_CONFIG_KEYFILE_GROUPPREFIX_GLOBAL_DNS_DOMAIN, @@ -1284,19 +1286,23 @@ _get_config_dir_files(const char *config_dir) static void _confs_to_description(GString *str, const GPtrArray *confs, const char *name) { - guint i; + guint i; + gboolean need_braces; if (!confs->len) return; + need_braces = confs->len > 1; + for (i = 0; i < confs->len; i++) { if (i == 0) - g_string_append_printf(str, " (%s: ", name); + g_string_append_printf(str, ", %s/%s", name, need_braces ? "{" : ""); else - g_string_append(str, ", "); + g_string_append(str, ","); g_string_append(str, confs->pdata[i]); } - g_string_append(str, ")"); + if (need_braces) + g_string_append(str, "}"); } static GKeyFile * @@ -1427,9 +1433,9 @@ read_entire_config(const NMConfigCmdLineOptions *cli, GString *str; str = g_string_new(o_config_main_file); - _confs_to_description(str, system_confs, "lib"); - _confs_to_description(str, run_confs, "run"); - _confs_to_description(str, confs, "etc"); + _confs_to_description(str, system_confs, system_config_dir); + _confs_to_description(str, run_confs, run_config_dir); + _confs_to_description(str, confs, config_dir); *out_config_description = g_string_free(str, FALSE); } NM_SET_OUT(out_config_main_file, g_steal_pointer(&o_config_main_file)); @@ -2815,12 +2821,12 @@ nm_config_reload(NMConfig *self, NMConfigChangeFlags reload_flags, gboolean emit NMConfigPrivate *priv; GError *error = NULL; GKeyFile *keyfile, *keyfile_intern; - NMConfigData *new_data = NULL; - char *config_main_file = NULL; - char *config_description = NULL; - gs_strfreev char **no_auto_default = NULL; - gboolean intern_config_needs_rewrite; - gs_unref_ptrarray GPtrArray *warnings = NULL; + NMConfigData *new_data = NULL; + char *config_main_file = NULL; + char *config_description = NULL; + gs_strfreev char **no_auto_default = NULL; + gboolean intern_config_needs_rewrite = FALSE; + gs_unref_ptrarray GPtrArray *warnings = NULL; guint i; g_return_if_fail(NM_IS_CONFIG(self)); @@ -2871,6 +2877,13 @@ nm_config_reload(NMConfig *self, NMConfigChangeFlags reload_flags, gboolean emit NULL); } + if (keyfile_intern) { + gs_free char *desc = config_description; + + config_description = + g_strdup_printf("%s, %s", config_description, priv->intern_config_file); + } + new_data = nm_config_data_new(config_main_file, config_description, (const char *const *) no_auto_default, @@ -3042,16 +3055,16 @@ nm_config_kernel_command_line_nm_debug(void) static gboolean init_sync(GInitable *initable, GCancellable *cancellable, GError **error) { - NMConfig *self = NM_CONFIG(initable); - NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE(self); - nm_auto_unref_keyfile GKeyFile *keyfile = NULL; - nm_auto_unref_keyfile GKeyFile *keyfile_intern = NULL; - gs_free char *config_main_file = NULL; - gs_free char *config_description = NULL; - gs_strfreev char **no_auto_default = NULL; - gs_unref_ptrarray GPtrArray *warnings = NULL; - gs_free char *configure_and_quit = NULL; - gboolean intern_config_needs_rewrite; + NMConfig *self = NM_CONFIG(initable); + NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE(self); + nm_auto_unref_keyfile GKeyFile *keyfile = NULL; + nm_auto_unref_keyfile GKeyFile *keyfile_intern = NULL; + gs_free char *config_main_file = NULL; + gs_free char *config_description = NULL; + gs_strfreev char **no_auto_default = NULL; + gs_unref_ptrarray GPtrArray *warnings = NULL; + gs_free char *configure_and_quit = NULL; + gboolean intern_config_needs_rewrite = FALSE; const char *s; if (priv->config_dir) { @@ -3126,6 +3139,13 @@ init_sync(GInitable *initable, GCancellable *cancellable, GError **error) NULL); } + if (keyfile_intern) { + gs_free char *desc = config_description; + + config_description = + g_strdup_printf("%s, %s", config_description, priv->intern_config_file); + } + priv->config_data_orig = nm_config_data_new(config_main_file, config_description, (const char *const *) no_auto_default, diff --git a/src/core/nm-connectivity.c b/src/core/nm-connectivity.c index 65eec36d..22e6c0d5 100644 --- a/src/core/nm-connectivity.c +++ b/src/core/nm-connectivity.c @@ -497,7 +497,7 @@ multi_socket_cb(CURL *e_handle, curl_socket_t fd, int what, void *userdata, void if (!fdp) { fdp = g_slice_new(ConCurlSockData); - *fdp = (ConCurlSockData){ + *fdp = (ConCurlSockData) { .cb_data = cb_data, }; curl_multi_assign(cb_data->concheck.curl_mhandle, fd, fdp); @@ -1291,7 +1291,7 @@ update_config(NMConnectivity *self, NMConfigData *config_data) } _con_config_unref(priv->con_config); priv->con_config = g_slice_new(ConConfig); - *priv->con_config = (ConConfig){ + *priv->con_config = (ConConfig) { .ref_count = 1, .uri = g_strdup(new_uri), .response = g_strdup(new_response), diff --git a/src/core/nm-core-utils.c b/src/core/nm-core-utils.c index 6aa38be2..895a9917 100644 --- a/src/core/nm-core-utils.c +++ b/src/core/nm-core-utils.c @@ -1434,7 +1434,7 @@ nm_match_spec_device(const GSList *specs, const NMMatchSpecDeviceData *data) if (!specs) return NM_MATCH_SPEC_NO_MATCH; - match_data = (MatchSpecDeviceData){ + match_data = (MatchSpecDeviceData) { .data = data, .device_type = nm_str_not_empty(data->device_type), .driver = nm_str_not_empty(data->driver), @@ -2834,10 +2834,7 @@ _host_id_read(guint8 **out_host_id, gsize *out_host_id_len) int base64_save = 0; gsize len; - if (nm_random_get_crypto_bytes(rnd_buf, sizeof(rnd_buf)) < 0) - nm_random_get_bytes_full(rnd_buf, sizeof(rnd_buf), &success); - else - success = TRUE; + nm_random_get_bytes(rnd_buf, sizeof(rnd_buf)); /* Our key is really binary data. But since we anyway generate a random seed * (with 32 random bytes), don't write it in binary, but instead create @@ -2858,12 +2855,9 @@ _host_id_read(guint8 **out_host_id, gsize *out_host_id_len) secret_arr = _host_id_hash_v2(new_content, len, sha256_digest); secret_len = NM_UTILS_CHECKSUM_LENGTH_SHA256; + success = TRUE; - if (!success) - nm_log_warn(LOGD_CORE, - "secret-key: failure to generate good random data for secret-key (use " - "non-persistent key)"); - else if (nm_utils_get_testing()) { + if (nm_utils_get_testing()) { /* for test code, we don't write the generated secret-key to disk. */ } else if (!nm_utils_file_set_contents(SECRET_KEY_FILE, (const char *) new_content, @@ -3011,7 +3005,7 @@ nmtst_utils_host_id_push(const guint8 *host_id, h = nm_g_array_append_new(nmtst_host_id_stack, HostIdData); - *h = (HostIdData){ + *h = (HostIdData) { .host_id = nm_memdup(host_id, host_id_len), .host_id_len = host_id_len, .timestamp_nsec = p_timestamp_nsec ? *p_timestamp_nsec : 0, @@ -3585,11 +3579,11 @@ _is_reserved_ipv6_iid(const guint8 *iid) /* 0200:5EFF:FE00:0000 - 0200:5EFF:FE00:5212 (Reserved IPv6 Interface Identifiers corresponding to the IANA Ethernet Block [RFC4291]) * 0200:5EFF:FE00:5213 (Proxy Mobile IPv6 [RFC6543]) * 0200:5EFF:FE00:5214 - 0200:5EFF:FEFF:FFFF (Reserved IPv6 Interface Identifiers corresponding to the IANA Ethernet Block [RFC4291]) */ - if (memcmp(iid, (const guint8[]){0x02, 0x00, 0x5E, 0xFF, 0xFE}, 5) == 0) + if (memcmp(iid, (const guint8[]) {0x02, 0x00, 0x5E, 0xFF, 0xFE}, 5) == 0) return TRUE; /* FDFF:FFFF:FFFF:FF80 - FDFF:FFFF:FFFF:FFFF (Reserved Subnet Anycast Addresses [RFC2526]) */ - if (memcmp(iid, (const guint8[]){0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 7) == 0) { + if (memcmp(iid, (const guint8[]) {0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 7) == 0) { if (iid[7] & 0x80) return TRUE; } @@ -3738,7 +3732,7 @@ _hw_addr_eth_complete(struct ether_addr *addr, nm_assert((ouis == NULL) ^ (ouis_len != 0)); if (ouis) { - oui = ouis[nm_random_u64_range(ouis_len)]; + oui = ouis[nm_random_u64_range(0, ouis_len)]; g_free(ouis); } else { if (!nm_utils_hwaddr_aton(current_mac_address, &oui, ETH_ALEN)) @@ -5255,7 +5249,7 @@ nm_utils_spawn_helper(const char *const *args, nm_assert(args && args[0]); info = g_new(HelperInfo, 1); - *info = (HelperInfo){ + *info = (HelperInfo) { .task = nm_g_task_new(NULL, cancellable, nm_utils_spawn_helper, callback, cb_data), }; diff --git a/src/core/nm-dbus-manager.c b/src/core/nm-dbus-manager.c index 7e6757f0..a89c7040 100644 --- a/src/core/nm-dbus-manager.c +++ b/src/core/nm-dbus-manager.c @@ -549,7 +549,7 @@ _get_caller_info_ensure(NMDBusManager *self, gsize l = strlen(sender) + 1; caller_info = g_malloc(sizeof(CallerInfo) + l); - *caller_info = (CallerInfo){ + *caller_info = (CallerInfo) { .uid_checked_at = -CALLER_INFO_MAX_AGE, .pid_checked_at = -CALLER_INFO_MAX_AGE, }; diff --git a/src/core/nm-dbus-object.h b/src/core/nm-dbus-object.h index 2a0ff0ee..f9427f24 100644 --- a/src/core/nm-dbus-object.h +++ b/src/core/nm-dbus-object.h @@ -29,7 +29,7 @@ typedef struct { #define NM_DBUS_EXPORT_PATH_STATIC(basepath) \ ({ \ - ((NMDBusExportPath){ \ + ((NMDBusExportPath) { \ .path = "" basepath "", \ }); \ }) @@ -37,7 +37,7 @@ typedef struct { #define NM_DBUS_EXPORT_PATH_NUMBERED(basepath) \ ({ \ static long long unsigned _int_counter = 0; \ - ((NMDBusExportPath){ \ + ((NMDBusExportPath) { \ .path = "" basepath "/%llu", \ .int_counter = &_int_counter, \ }); \ @@ -81,7 +81,7 @@ struct _NMDBusObject { }; #define NM_DEFINE_DBUS_INTERFACE_INFO(...) \ - ((NMDBusInterfaceInfo *) (&((const NMDBusInterfaceInfo){__VA_ARGS__}))) + ((NMDBusInterfaceInfo *) (&((const NMDBusInterfaceInfo) {__VA_ARGS__}))) typedef struct { GObjectClass parent; diff --git a/src/core/nm-dbus-utils.h b/src/core/nm-dbus-utils.h index 237b37d8..015ebb1e 100644 --- a/src/core/nm-dbus-utils.h +++ b/src/core/nm-dbus-utils.h @@ -50,10 +50,10 @@ extern const GDBusAnnotationInfo _nm_gdbus_annotation_info_deprecated; #define NM_GDBUS_ANNOTATION_INFO_DEPRECATED() \ ((GDBusAnnotationInfo *) &_nm_gdbus_annotation_info_deprecated) -#define NM_DEFINE_DBUS_ANNOTATION_INFO(a_key, a_value) \ - ((GDBusAnnotationInfo *) &((const GDBusAnnotationInfo){ \ - .key = (a_key), \ - .value = (a_value), \ +#define NM_DEFINE_DBUS_ANNOTATION_INFO(a_key, a_value) \ + ((GDBusAnnotationInfo *) &((const GDBusAnnotationInfo) { \ + .key = (a_key), \ + .value = (a_value), \ })) extern const GDBusAnnotationInfo *const _nm_gdbus_annotation_info_list_deprecated[]; @@ -67,10 +67,10 @@ extern const GDBusAnnotationInfo *const _nm_gdbus_annotation_info_list_deprecate ((GDBusAnnotationInfo **) _nm_gdbus_annotation_info_list_deprecated) #define NM_DEFINE_DBUS_ANNOTATION_INFOS(...) \ - ((GDBusAnnotationInfo **) ((const GDBusAnnotationInfo *const[]){__VA_ARGS__, NULL})) + ((GDBusAnnotationInfo **) ((const GDBusAnnotationInfo *const[]) {__VA_ARGS__, NULL})) #define NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE(m_name, m_signature, m_property_name, ...) \ - ((GDBusPropertyInfo *) &((const struct _NMDBusPropertyInfoExtendedBase){ \ + ((GDBusPropertyInfo *) &((const struct _NMDBusPropertyInfoExtendedBase) { \ ._parent = {.ref_count = -1, \ .name = m_name, \ .signature = m_signature, \ @@ -79,25 +79,25 @@ extern const GDBusAnnotationInfo *const _nm_gdbus_annotation_info_list_deprecate .property_name = m_property_name, \ })) -#define NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE(m_name, \ - m_signature, \ - m_property_name, \ - m_permission, \ - m_audit_op, \ - ...) \ - ((GDBusPropertyInfo *) &((const struct _NMDBusPropertyInfoExtendedReadWritable){ \ - ._base = \ - { \ - ._parent = {.ref_count = -1, \ - .name = m_name, \ - .signature = m_signature, \ - .flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE \ - | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE, \ - __VA_ARGS__}, \ - .property_name = m_property_name, \ - }, \ - .permission = m_permission, \ - .audit_op = m_audit_op, \ +#define NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE(m_name, \ + m_signature, \ + m_property_name, \ + m_permission, \ + m_audit_op, \ + ...) \ + ((GDBusPropertyInfo *) &((const struct _NMDBusPropertyInfoExtendedReadWritable) { \ + ._base = \ + { \ + ._parent = {.ref_count = -1, \ + .name = m_name, \ + .signature = m_signature, \ + .flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE \ + | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE, \ + __VA_ARGS__}, \ + .property_name = m_property_name, \ + }, \ + .permission = m_permission, \ + .audit_op = m_audit_op, \ })) typedef struct _NMDBusMethodInfoExtended { @@ -113,7 +113,7 @@ typedef struct _NMDBusMethodInfoExtended { } NMDBusMethodInfoExtended; #define NM_DEFINE_DBUS_METHOD_INFO_EXTENDED(parent_, ...) \ - ((GDBusMethodInfo *) (&((const NMDBusMethodInfoExtended){.parent = parent_, __VA_ARGS__}))) + ((GDBusMethodInfo *) (&((const NMDBusMethodInfoExtended) {.parent = parent_, __VA_ARGS__}))) typedef struct _NMDBusInterfaceInfoExtended { GDBusInterfaceInfo parent; diff --git a/src/core/nm-dispatcher.c b/src/core/nm-dispatcher.c index 4f442c68..16fb7e96 100644 --- a/src/core/nm-dispatcher.c +++ b/src/core/nm-dispatcher.c @@ -247,6 +247,20 @@ dump_ip_to_props(const NML3ConfigData *l3cd, int addr_family, GVariantBuilder *b } g_variant_builder_add(builder, "{sv}", "addresses", g_variant_builder_end(&int_builder)); + /* We used to send name servers as a entry with key "nameservers" and binary + * value. That no longer works because name servers can be URIs. Send the + * value as an array of strings. + * To avoid problems when the NM and NM-dispatcher version don't match (right + * after an upgrade or downgrade), still send the old key in the old format, + * and introduce a new key for the new format. */ + g_variant_builder_init(&int_builder, G_VARIANT_TYPE("as")); + strarr = nm_l3_config_data_get_nameservers(l3cd, addr_family, &n); + for (i = 0; i < n; i++) + g_variant_builder_add(&int_builder, "s", strarr[i]); + g_variant_builder_add(builder, "{sv}", "nameservers-full", g_variant_builder_end(&int_builder)); + + /* Old format for nameservers. This can be removed in the future when it's + * expected that both NM and NM-dispatcher support the new format.*/ if (IS_IPv4) g_variant_builder_init(&int_builder, G_VARIANT_TYPE("au")); else @@ -255,7 +269,7 @@ dump_ip_to_props(const NML3ConfigData *l3cd, int addr_family, GVariantBuilder *b for (i = 0; i < n; i++) { NMIPAddr a; - if (!nm_utils_dnsname_parse_assert(addr_family, strarr[i], NULL, &a, NULL)) + if (!nm_dns_uri_parse_plain(addr_family, strarr[i], NULL, &a)) continue; if (IS_IPv4) diff --git a/src/core/nm-firewall-utils.c b/src/core/nm-firewall-utils.c index a88c6f1a..b4960612 100644 --- a/src/core/nm-firewall-utils.c +++ b/src/core/nm-firewall-utils.c @@ -566,7 +566,7 @@ nm_firewall_nft_call(GBytes *stdin_buf, gs_free char *ss1 = NULL; call_data = g_slice_new(FwNftCallData); - *call_data = (FwNftCallData){ + *call_data = (FwNftCallData) { .task = nm_g_task_new(NULL, cancellable, nm_firewall_nft_call, callback, callback_user_data), .subprocess = NULL, @@ -661,7 +661,7 @@ _fw_nft_call_sync(GBytes *stdin_buf, GError **error) nm_auto_pop_and_unref_gmaincontext GMainContext *main_context = nm_g_main_context_push_thread_default(g_main_context_new()); nm_auto_unref_gmainloop GMainLoop *main_loop = g_main_loop_new(main_context, FALSE); - FwNftCallSyncData data = (FwNftCallSyncData){ + FwNftCallSyncData data = (FwNftCallSyncData) { .loop = main_loop, .error = error, }; @@ -1027,7 +1027,7 @@ nm_firewall_config_new_shared(const char *ip_iface, in_addr_t addr, guint8 plen) nm_assert(plen <= 32); self = g_slice_new(NMFirewallConfig); - *self = (NMFirewallConfig){ + *self = (NMFirewallConfig) { .ip_iface = g_strdup(ip_iface), .addr = addr, .plen = plen, diff --git a/src/core/nm-ip-config.c b/src/core/nm-ip-config.c index c4dc04da..eb0ec9aa 100644 --- a/src/core/nm-ip-config.c +++ b/src/core/nm-ip-config.c @@ -142,9 +142,9 @@ static void _l3cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMIPConfig *self) { switch (notify_data->notify_type) { - case NM_L3_CONFIG_NOTIFY_TYPE_L3CD_CHANGED: - if (notify_data->l3cd_changed.commited) - _handle_l3cd_changed(self, notify_data->l3cd_changed.l3cd_new); + case NM_L3_CONFIG_NOTIFY_TYPE_PRE_COMMIT: + if (notify_data->commit.l3cd_changed) + _handle_l3cd_changed(self, notify_data->commit.l3cd_new); break; case NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE: _notify_platform(self, notify_data->platform_change_on_idle.obj_type_flags); @@ -162,6 +162,7 @@ get_property_ip(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec NMIPConfig *self = NM_IP_CONFIG(object); NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self); const int addr_family = nm_ip_config_get_addr_family(self); + char **to_free = NULL; char sbuf_addr[NM_INET_ADDRSTRLEN]; const char *const *strv; guint len; @@ -193,7 +194,20 @@ get_property_ip(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec break; case PROP_IP_SEARCHES: strv = nm_l3_config_data_get_searches(priv->l3cd, addr_family, &len); + if (strv) { + strv = nm_utils_buf_utf8safe_escape_strv( + strv, + len, + NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL + | NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII, + &to_free); + } + _value_set_variant_as(value, strv, len); + + if (to_free) { + g_strfreev(to_free); + } break; case PROP_IP_DNS_PRIORITY: v_i = nm_l3_config_data_get_dns_priority_or_default(priv->l3cd, addr_family); @@ -435,22 +449,27 @@ get_property_ip4(GObject *object, guint prop_id, GValue *value, GParamSpec *pspe else g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}")); for (i = 0; i < len; i++) { - in_addr_t a; - - if (!nm_utils_dnsname_parse_assert(AF_INET, strarr[i], NULL, &a, NULL)) - continue; + NMIPAddr a; - if (prop_id == PROP_IP4_NAMESERVERS) + if (prop_id == PROP_IP4_NAMESERVERS) { + if (!nm_dns_uri_parse_plain(AF_INET, strarr[i], NULL, &a)) + continue; g_variant_builder_add(&builder, "u", a); - else { + } else { GVariantBuilder nested_builder; + char addrstr[NM_INET_ADDRSTRLEN]; - nm_inet4_ntop(a, addr_str); g_variant_builder_init(&nested_builder, G_VARIANT_TYPE("a{sv}")); + if (nm_dns_uri_parse_plain(AF_INET, strarr[i], addrstr, NULL)) { + g_variant_builder_add(&nested_builder, + "{sv}", + "address", + g_variant_new_string(addrstr)); + } g_variant_builder_add(&nested_builder, "{sv}", - "address", - g_variant_new_string(addr_str)); + "uri", + g_variant_new_string(strarr[i])); g_variant_builder_add(&builder, "a{sv}", &nested_builder); } } @@ -678,12 +697,13 @@ get_property_ip6(GObject *object, guint prop_id, GValue *value, GParamSpec *pspe else { g_variant_builder_init(&builder, G_VARIANT_TYPE("aay")); for (i = 0; i < len; i++) { - struct in6_addr a; + NMIPAddr a; - if (!nm_utils_dnsname_parse_assert(AF_INET6, strarr[i], NULL, &a, NULL)) + /* TODO: expose the full URI as well */ + if (!nm_dns_uri_parse_plain(AF_INET6, strarr[i], NULL, &a)) continue; - g_variant_builder_add(&builder, "@ay", nm_g_variant_new_ay_in6addr(&a)); + g_variant_builder_add(&builder, "@ay", nm_g_variant_new_ay_in6addr(&a.addr6)); } g_value_take_variant(value, g_variant_builder_end(&builder)); } diff --git a/src/core/nm-l3-config-data.c b/src/core/nm-l3-config-data.c index 6d98e46d..70867ff7 100644 --- a/src/core/nm-l3-config-data.c +++ b/src/core/nm-l3-config-data.c @@ -163,6 +163,9 @@ struct _NML3ConfigData { bool ndisc_hop_limit_set : 1; bool ndisc_reachable_time_msec_set : 1; bool ndisc_retrans_timer_msec_set : 1; + + bool routed_dns_4 : 1; + bool routed_dns_6 : 1; }; /*****************************************************************************/ @@ -370,7 +373,8 @@ nm_l3_config_data_log(const NML3ConfigData *self, nm_assert(!NM_FLAGS_ANY(self->flags, ~(NM_L3_CONFIG_DAT_FLAGS_IGNORE_MERGE_NO_DEFAULT_ROUTES | NM_L3_CONFIG_DAT_FLAGS_HAS_DNS_PRIORITY_4 - | NM_L3_CONFIG_DAT_FLAGS_HAS_DNS_PRIORITY_6))); + | NM_L3_CONFIG_DAT_FLAGS_HAS_DNS_PRIORITY_6 + | NM_L3_CONFIG_DAT_FLAGS_HAS_IPV4_NON_LL))); _L("l3cd %s%s%s(" NM_HASH_OBFUSCATE_PTR_FMT ", ifindex=%d%s%s%s%s)", NM_PRINT_FMT_QUOTED(title, "\"", title, "\" ", ""), @@ -602,6 +606,12 @@ nm_l3_config_data_log(const NML3ConfigData *self, if (self->proxy_pac_script) _L("proxy-pac-script: %s", self->proxy_pac_script->str); + + if (self->routed_dns_4) + _L("routed-dns4: yes"); + if (self->routed_dns_6) + _L("routed-dns6: yes"); + #undef _L } @@ -677,7 +687,7 @@ nm_l3_config_data_new(NMDedupMultiIndex *multi_idx, int ifindex, NMIPConfigSourc || (source >= NM_IP_CONFIG_SOURCE_KERNEL && source <= NM_IP_CONFIG_SOURCE_USER)); self = g_slice_new(NML3ConfigData); - *self = (NML3ConfigData){ + *self = (NML3ConfigData) { .ref_count = 1, .ifindex = ifindex, .multi_idx = nm_dedup_multi_index_ref(multi_idx), @@ -1287,15 +1297,26 @@ nm_l3_config_data_add_address_full(NML3ConfigData *self, const NMPObject **out_obj_new) { const NMPObject *new; - gboolean changed; + gboolean changed; + const int IS_IPv4 = NM_IS_IPv4(addr_family); nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); nm_assert_addr_family(addr_family); nm_assert((!pl_new) != (!obj_new)); nm_assert(!obj_new || NMP_OBJECT_GET_ADDR_FAMILY(obj_new) == addr_family); + if (IS_IPv4 && !NM_FLAGS_HAS(self->flags, NM_L3_CONFIG_DAT_FLAGS_HAS_IPV4_NON_LL)) { + const NMPlatformIP4Address *addr; + addr = obj_new ? NMP_OBJECT_CAST_IP4_ADDRESS(obj_new) + : (const NMPlatformIP4Address *) (pl_new); + + if (!nm_platform_ip4_address_is_link_local(addr)) { + self->flags |= NM_L3_CONFIG_DAT_FLAGS_HAS_IPV4_NON_LL; + } + } + changed = _l3_config_data_add_obj(self->multi_idx, - &self->idx_addresses_x[NM_IS_IPv4(addr_family)], + &self->idx_addresses_x[IS_IPv4], self->ifindex, obj_new, (const NMPlatformObject *) pl_new, @@ -1439,8 +1460,7 @@ nm_l3_config_data_add_nameserver(NML3ConfigData *self, int addr_family, const ch if (NM_MORE_ASSERTS > 5) { gs_free char *s_free = NULL; - nm_assert( - nm_streq0(nm_utils_dnsname_normalize(addr_family, nameserver, &s_free), nameserver)); + nm_assert(nm_streq0(nm_dns_uri_normalize(addr_family, nameserver, &s_free), nameserver)); } p_arr = &self->nameservers_x[NM_IS_IPv4(addr_family)]; @@ -1453,27 +1473,16 @@ nm_l3_config_data_add_nameserver(NML3ConfigData *self, int addr_family, const ch } gboolean -nm_l3_config_data_add_nameserver_detail(NML3ConfigData *self, - int addr_family, - gconstpointer addr_bin, - const char *server_name) +nm_l3_config_data_add_nameserver_addr(NML3ConfigData *self, int addr_family, gconstpointer addr_bin) { - gs_free char *s_free = NULL; - char *s; - gsize l; + char addrstr[NM_INET_ADDRSTRLEN]; nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); nm_assert_addr_family(addr_family); nm_assert(addr_bin); - l = (NM_INET_ADDRSTRLEN + 2u) + (server_name ? strlen(server_name) : 0u); - - s = nm_malloc_maybe_a(300, l, &s_free); - - if (!nm_utils_dnsname_construct(addr_family, addr_bin, server_name, s, l)) - nm_assert_not_reached(); - - return nm_l3_config_data_add_nameserver(self, addr_family, s); + nm_inet_ntop(addr_family, addr_bin, addrstr); + return nm_l3_config_data_add_nameserver(self, addr_family, addrstr); } gboolean @@ -1965,6 +1974,32 @@ nm_l3_config_data_set_allow_routes_without_address(NML3ConfigData *self, } } +gboolean +nm_l3_config_data_get_routed_dns(const NML3ConfigData *self, int addr_family) +{ + const int IS_IPv4 = NM_IS_IPv4(addr_family); + + nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); + if (IS_IPv4) { + return self->routed_dns_4; + } else { + return self->routed_dns_6; + } +} + +void +nm_l3_config_data_set_routed_dns(NML3ConfigData *self, int addr_family, gboolean value) +{ + const int IS_IPv4 = NM_IS_IPv4(addr_family); + + nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); + if (IS_IPv4) { + self->routed_dns_4 = value; + } else { + self->routed_dns_6 = value; + } +} + NMProxyConfigMethod nm_l3_config_data_get_proxy_method(const NML3ConfigData *self) { @@ -2435,6 +2470,9 @@ nm_l3_config_data_cmp_full(const NML3ConfigData *a, if (a->ndisc_retrans_timer_msec_set) NM_CMP_DIRECT(a->ndisc_retrans_timer_msec_val, b->ndisc_retrans_timer_msec_val); + NM_CMP_DIRECT_UNSAFE(a->routed_dns_4, b->routed_dns_4); + NM_CMP_DIRECT_UNSAFE(a->routed_dns_6, b->routed_dns_6); + NM_CMP_FIELD(a, b, source); } @@ -2543,7 +2581,7 @@ nm_l3_config_data_get_blacklisted_ip4_routes(const NML3ConfigData *self, gboolea continue; } - rx.r4 = (NMPlatformIP4Route){ + rx.r4 = (NMPlatformIP4Route) { .ifindex = self->ifindex, .rt_source = NM_IP_CONFIG_SOURCE_KERNEL, .network = network_4, @@ -2725,7 +2763,7 @@ nm_l3_config_data_add_dependent_device_routes(NML3ConfigData *self, plen = addr_src->a6.plen; } - rx.r6 = (NMPlatformIP6Route){ + rx.r6 = (NMPlatformIP6Route) { .ifindex = self->ifindex, .rt_source = NM_IP_CONFIG_SOURCE_KERNEL, .table_coerced = nm_platform_route_table_coerce(route_table), @@ -2798,14 +2836,14 @@ _init_from_connection_ip(NML3ConfigData *self, int addr_family, NMConnection *co NMPlatformIPXRoute r; if (IS_IPv4) { - r.r4 = (NMPlatformIP4Route){ + r.r4 = (NMPlatformIP4Route) { .rt_source = NM_IP_CONFIG_SOURCE_USER, .gateway = gateway_bin.addr4, .table_any = TRUE, .metric_any = TRUE, }; } else { - r.r6 = (NMPlatformIP6Route){ + r.r6 = (NMPlatformIP6Route) { .rt_source = NM_IP_CONFIG_SOURCE_USER, .gateway = gateway_bin.addr6, .table_any = TRUE, @@ -2828,7 +2866,7 @@ _init_from_connection_ip(NML3ConfigData *self, int addr_family, NMConnection *co nm_ip_address_get_address_binary(s_addr, &addr_bin); if (IS_IPv4) { - a.a4 = (NMPlatformIP4Address){ + a.a4 = (NMPlatformIP4Address) { .address = addr_bin.addr4, .peer_address = addr_bin.addr4, .plen = nm_ip_address_get_prefix(s_addr), @@ -2842,7 +2880,7 @@ _init_from_connection_ip(NML3ConfigData *self, int addr_family, NMConnection *co nm_assert(a.a4.plen <= 32); } else { - a.a6 = (NMPlatformIP6Address){ + a.a6 = (NMPlatformIP6Address) { .address = addr_bin.addr6, .plen = nm_ip_address_get_prefix(s_addr), .lifetime = NM_PLATFORM_LIFETIME_PERMANENT, @@ -2887,7 +2925,7 @@ _init_from_connection_ip(NML3ConfigData *self, int addr_family, NMConnection *co nm_ip_addr_clear_host_address(addr_family, &network_bin, &network_bin, plen); if (IS_IPv4) { - r.r4 = (NMPlatformIP4Route){ + r.r4 = (NMPlatformIP4Route) { .network = network_bin.addr4, .plen = plen, .gateway = next_hop_bin.addr4, @@ -2897,7 +2935,7 @@ _init_from_connection_ip(NML3ConfigData *self, int addr_family, NMConnection *co }; nm_assert(r.r4.plen <= 32); } else { - r.r6 = (NMPlatformIP6Route){ + r.r6 = (NMPlatformIP6Route) { .network = network_bin.addr6, .plen = plen, .gateway = next_hop_bin.addr6, @@ -3045,14 +3083,12 @@ _init_from_platform(NML3ConfigData *self, else self->has_routes_with_type_local_6_set = FALSE; nmp_cache_iter_for_each (&iter, head_entry, &plobj) { - if (!_l3_config_data_add_obj(self->multi_idx, - &self->idx_addresses_x[IS_IPv4], - self->ifindex, - plobj, - NULL, - NM_L3_CONFIG_ADD_FLAGS_APPEND_FORCE, - NULL, - NULL)) + if (!nm_l3_config_data_add_address_full(self, + addr_family, + plobj, + NULL, + NM_L3_CONFIG_ADD_FLAGS_APPEND_FORCE, + NULL)) nm_assert_not_reached(); } head_entry = nm_l3_config_data_lookup_addresses(self, addr_family); @@ -3478,6 +3514,11 @@ nm_l3_config_data_merge(NML3ConfigData *self, if (!src->allow_routes_without_address_6) self->allow_routes_without_address_6 = FALSE; + + if (src->routed_dns_4) + self->routed_dns_4 = TRUE; + if (src->routed_dns_6) + self->routed_dns_6 = TRUE; } NML3ConfigData * diff --git a/src/core/nm-l3-config-data.h b/src/core/nm-l3-config-data.h index faf4f0bf..bcb6af67 100644 --- a/src/core/nm-l3-config-data.h +++ b/src/core/nm-l3-config-data.h @@ -28,6 +28,7 @@ typedef enum { ((is_ipv4) ? NM_L3_CONFIG_DAT_FLAGS_HAS_DNS_PRIORITY_4 \ : NM_L3_CONFIG_DAT_FLAGS_HAS_DNS_PRIORITY_6) + NM_L3_CONFIG_DAT_FLAGS_HAS_IPV4_NON_LL = (1ull << 3), } NML3ConfigDatFlags; typedef enum { @@ -499,10 +500,9 @@ nm_l3_config_data_get_nameservers(const NML3ConfigData *self, int addr_family, g gboolean nm_l3_config_data_add_nameserver(NML3ConfigData *self, int addr_family, const char *nameserver); -gboolean nm_l3_config_data_add_nameserver_detail(NML3ConfigData *self, - int addr_family, - gconstpointer addr_bin, - const char *server_name); +gboolean nm_l3_config_data_add_nameserver_addr(NML3ConfigData *self, + int addr_family, + gconstpointer addr_bin); gboolean nm_l3_config_data_clear_nameservers(NML3ConfigData *self, int addr_family); @@ -561,6 +561,9 @@ void nm_l3_config_data_set_allow_routes_without_address(NML3ConfigData *self, int addr_family, gboolean value); +gboolean nm_l3_config_data_get_routed_dns(const NML3ConfigData *self, int addr_family); +void nm_l3_config_data_set_routed_dns(NML3ConfigData *self, int addr_family, gboolean value); + NMProxyConfigMethod nm_l3_config_data_get_proxy_method(const NML3ConfigData *self); gboolean nm_l3_config_data_set_proxy_method(NML3ConfigData *self, NMProxyConfigMethod value); diff --git a/src/core/nm-l3-ipv4ll.c b/src/core/nm-l3-ipv4ll.c index 551a90fe..3c003c29 100644 --- a/src/core/nm-l3-ipv4ll.c +++ b/src/core/nm-l3-ipv4ll.c @@ -10,8 +10,6 @@ #include "n-acd/src/n-acd.h" #include "nm-core-utils.h" -#define ADDR_IPV4LL_PREFIX_LEN 16 - #define TIMED_OUT_TIME_FACTOR 5u /*****************************************************************************/ @@ -193,7 +191,7 @@ _ipv4ll_emit_signal_notify(NML3IPv4LL *self) self->notify_on_idle = FALSE; notify_data.notify_type = NM_L3_CONFIG_NOTIFY_TYPE_IPV4LL_EVENT; - notify_data.ipv4ll_event = (typeof(notify_data.ipv4ll_event)){ + notify_data.ipv4ll_event = (typeof(notify_data.ipv4ll_event)) { .ipv4ll = self, }; _nm_l3cfg_emit_signal_notify(self->l3cfg, ¬ify_data); @@ -233,7 +231,7 @@ _registration_update(NML3IPv4LL *self, if (!reg) { reg = g_slice_new(NML3IPv4LLRegistration); - *reg = (NML3IPv4LLRegistration){ + *reg = (NML3IPv4LLRegistration) { .self = self, .timeout_msec = timeout_msec, }; @@ -286,15 +284,6 @@ nm_l3_ipv4ll_register_remove(NML3IPv4LLRegistration *reg) /*****************************************************************************/ static gboolean -_ip4_address_is_link_local(const NMPlatformIP4Address *a) -{ - nm_assert(a); - - return nm_ip4_addr_is_link_local(a->address) && a->plen == ADDR_IPV4LL_PREFIX_LEN - && a->address == a->peer_address; -} - -static gboolean _acd_info_is_good(const NML3AcdAddrInfo *acd_info) { if (!acd_info) @@ -333,7 +322,7 @@ _l3cd_config_create(int ifindex, in_addr_t addr, NMDedupMultiIndex *multi_idx) NM_PLATFORM_IP4_ADDRESS_INIT(.ifindex = ifindex, .address = addr, .peer_address = addr, - .plen = ADDR_IPV4LL_PREFIX_LEN, + .plen = NM_IPV4LL_PREFIXLEN, .addr_source = NM_IP_CONFIG_SOURCE_IP4LL)); nm_l3_config_data_add_route_4(l3cd, @@ -359,7 +348,7 @@ _l3cd_config_get_addr(const NML3ConfigData *l3cd) nm_l3_config_data_iter_ip4_address_for_each (&iter, l3cd, &pladdr) { const in_addr_t addr = pladdr->address; - nm_assert(_ip4_address_is_link_local(pladdr)); + nm_assert(nm_platform_ip4_address_is_link_local(pladdr)); #if NM_MORE_ASSERTS > 10 { nm_auto_unref_l3cd const NML3ConfigData *l3cd2 = NULL; @@ -644,11 +633,11 @@ _ipv4ll_platform_ip4_address_lookup(NML3IPv4LL *self, in_addr_t addr) pladdr = nm_platform_ip4_address_get(nm_l3_ipv4ll_get_platform(self), nm_l3_ipv4ll_get_ifindex(self), addr, - ADDR_IPV4LL_PREFIX_LEN, + NM_IPV4LL_PREFIXLEN, addr); nm_assert(!pladdr || pladdr->address == addr); - nm_assert(!pladdr || _ip4_address_is_link_local(pladdr)); + nm_assert(!pladdr || nm_platform_ip4_address_is_link_local(pladdr)); return pladdr; } @@ -677,7 +666,7 @@ _ipv4ll_platform_find_addr(NML3IPv4LL *self, const NML3AcdAddrInfo **out_acd_inf nm_l3_ipv4ll_get_ifindex(self)); nm_platform_iter_obj_for_each (&iter, nm_l3_ipv4ll_get_platform(self), &lookup, &obj) { addr = NMP_OBJECT_CAST_IP4_ADDRESS(obj); - if (!_ip4_address_is_link_local(addr)) + if (!nm_platform_ip4_address_is_link_local(addr)) continue; acd_info = _ipv4ll_l3cfg_get_acd_addr_info(self, addr->address); @@ -962,7 +951,7 @@ nm_l3_ipv4ll_new(NML3Cfg *l3cfg) g_return_val_if_fail(NM_IS_L3CFG(l3cfg), NULL); self = g_slice_new(NML3IPv4LL); - *self = (NML3IPv4LL){ + *self = (NML3IPv4LL) { .l3cfg = g_object_ref(l3cfg), .ref_count = 1, .reg_lst_head = C_LIST_INIT(self->reg_lst_head), diff --git a/src/core/nm-l3-ipv6ll.c b/src/core/nm-l3-ipv6ll.c index 38aa98fc..e5f3b85e 100644 --- a/src/core/nm-l3-ipv6ll.c +++ b/src/core/nm-l3-ipv6ll.c @@ -646,7 +646,7 @@ _nm_l3_ipv6ll_new(NML3Cfg *l3cfg, NULL); self = g_slice_new(NML3IPv6LL); - *self = (NML3IPv6LL){ + *self = (NML3IPv6LL) { .l3cfg = g_object_ref(l3cfg), .notify_fcn = notify_fcn, .user_data = user_data, diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c index a7189d3e..fb48b860 100644 --- a/src/core/nm-l3cfg.c +++ b/src/core/nm-l3cfg.c @@ -10,7 +10,9 @@ #include "nm-compat-headers/linux/if_addr.h" #include <linux/if_ether.h> #include <linux/rtnetlink.h> +#include <linux/fib_rules.h> +#include "libnm-core-aux-intern/nm-libnm-core-utils.h" #include "libnm-glib-aux/nm-prioq.h" #include "libnm-glib-aux/nm-time-utils.h" #include "libnm-platform/nm-platform.h" @@ -436,7 +438,6 @@ static NM_UTILS_ENUM2STR_DEFINE( NML3ConfigNotifyType, NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_ACD_EVENT, "acd-event"), NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_IPV4LL_EVENT, "ipv4ll-event"), - NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_L3CD_CHANGED, "l3cd-changed"), NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE, "platform-change"), NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE, "platform-change-on-idle"), NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_PRE_COMMIT, "pre-commit"), @@ -591,16 +592,17 @@ _l3_config_notify_data_to_string(const NML3ConfigNotifyData *notify_data, nm_strbuf_seek_end(&s, &l); switch (notify_data->notify_type) { - case NM_L3_CONFIG_NOTIFY_TYPE_L3CD_CHANGED: + case NM_L3_CONFIG_NOTIFY_TYPE_PRE_COMMIT: + case NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT: nm_strbuf_append(&s, &l, ", l3cd-old=%s", - NM_HASH_OBFUSCATE_PTR_STR(notify_data->l3cd_changed.l3cd_old, sbufobf)); + NM_HASH_OBFUSCATE_PTR_STR(notify_data->commit.l3cd_old, sbufobf)); nm_strbuf_append(&s, &l, ", l3cd-new=%s", - NM_HASH_OBFUSCATE_PTR_STR(notify_data->l3cd_changed.l3cd_new, sbufobf)); - nm_strbuf_append(&s, &l, ", commited=%d", notify_data->l3cd_changed.commited); + NM_HASH_OBFUSCATE_PTR_STR(notify_data->commit.l3cd_new, sbufobf)); + nm_strbuf_append(&s, &l, ", l3cd-changed=%d", notify_data->commit.l3cd_changed); break; case NM_L3_CONFIG_NOTIFY_TYPE_ACD_EVENT: nm_strbuf_append(&s, @@ -659,27 +661,22 @@ _nm_l3cfg_emit_signal_notify(NML3Cfg *self, const NML3ConfigNotifyData *notify_d } static void -_nm_l3cfg_emit_signal_notify_simple(NML3Cfg *self, NML3ConfigNotifyType notify_type) +_nm_l3cfg_emit_signal_notify_commit(NML3Cfg *self, + NML3ConfigNotifyType type, + const NML3ConfigData *l3cd_old, + const NML3ConfigData *l3cd_new, + gboolean l3cd_changed) { NML3ConfigNotifyData notify_data; - notify_data.notify_type = notify_type; - _nm_l3cfg_emit_signal_notify(self, ¬ify_data); -} - -static void -_nm_l3cfg_emit_signal_notify_l3cd_changed(NML3Cfg *self, - const NML3ConfigData *l3cd_old, - const NML3ConfigData *l3cd_new, - gboolean commited) -{ - NML3ConfigNotifyData notify_data; + nm_assert( + NM_IN_SET(type, NM_L3_CONFIG_NOTIFY_TYPE_PRE_COMMIT, NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT)); - notify_data.notify_type = NM_L3_CONFIG_NOTIFY_TYPE_L3CD_CHANGED; - notify_data.l3cd_changed = (typeof(notify_data.l3cd_changed)){ - .l3cd_old = l3cd_old, - .l3cd_new = l3cd_new, - .commited = commited, + notify_data.notify_type = type; + notify_data.commit = (typeof(notify_data.commit)) { + .l3cd_old = l3cd_old, + .l3cd_new = l3cd_new, + .l3cd_changed = l3cd_changed, }; _nm_l3cfg_emit_signal_notify(self, ¬ify_data); } @@ -770,7 +767,7 @@ _nm_n_acd_data_probe_new(NML3Cfg *self, in_addr_t addr, guint32 timeout_msec, gp if (r) return NULL; - n_acd_probe_config_set_ip(probe_config, (struct in_addr){addr}); + n_acd_probe_config_set_ip(probe_config, (struct in_addr) {addr}); n_acd_probe_config_set_timeout(probe_config, timeout_msec); r = n_acd_probe(self->priv.p->nacd, &probe, probe_config); @@ -855,7 +852,7 @@ _obj_state_data_new(const NMPObject *obj, const NMPObject *plobj) ObjStateData *obj_state; obj_state = g_slice_new(ObjStateData); - *obj_state = (ObjStateData){ + *obj_state = (ObjStateData) { .obj = nmp_object_ref(obj), .os_plobj = nmp_object_ref(plobj), .os_was_in_platform = !!plobj, @@ -1581,7 +1578,7 @@ _nm_l3cfg_notify_platform_change_on_idle(NML3Cfg *self, guint32 obj_type_flags) _load_link(self, FALSE); notify_data.notify_type = NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE; - notify_data.platform_change_on_idle = (typeof(notify_data.platform_change_on_idle)){ + notify_data.platform_change_on_idle = (typeof(notify_data.platform_change_on_idle)) { .obj_type_flags = obj_type_flags, }; _nm_l3cfg_emit_signal_notify(self, ¬ify_data); @@ -1625,7 +1622,7 @@ _nm_l3cfg_notify_platform_change(NML3Cfg *self, } notify_data.notify_type = NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE; - notify_data.platform_change = (typeof(notify_data.platform_change)){ + notify_data.platform_change = (typeof(notify_data.platform_change)) { .obj = obj, .change_type = change_type, }; @@ -2161,7 +2158,7 @@ _l3_acd_data_add(NML3Cfg *self, } acd_data = g_slice_new(AcdData); - *acd_data = (AcdData){ + *acd_data = (AcdData) { .info = { .l3cfg = self, @@ -2193,7 +2190,7 @@ _l3_acd_data_add(NML3Cfg *self, } acd_track = (NML3AcdAddrTrackInfo *) &acd_data->info.track_infos[acd_data->info.n_track_infos++]; - *acd_track = (NML3AcdAddrTrackInfo){ + *acd_track = (NML3AcdAddrTrackInfo) { .l3cd = nm_l3_config_data_ref(l3cd), .obj = nmp_object_ref(obj), .tag = tag, @@ -2348,7 +2345,7 @@ _nm_l3cfg_emit_signal_notify_acd_event(NML3Cfg *self, AcdData *acd_data) nm_assert(acd_data->info.n_track_infos > 0); notify_data.notify_type = NM_L3_CONFIG_NOTIFY_TYPE_ACD_EVENT; - notify_data.acd_event = (typeof(notify_data.acd_event)){ + notify_data.acd_event = (typeof(notify_data.acd_event)) { .info = acd_data->info, }; @@ -3610,7 +3607,7 @@ nm_l3cfg_add_config(NML3Cfg *self, if (idx < 0) { l3_config_data = nm_g_array_append_new(self->priv.p->l3_config_datas, L3ConfigData); - *l3_config_data = (L3ConfigData){ + *l3_config_data = (L3ConfigData) { .tag_confdata = tag, .l3cd = nm_l3_config_data_ref_and_seal(l3cd), .config_flags = config_flags, @@ -3900,6 +3897,215 @@ out_ip4_address: } } +/*****************************************************************************/ + +static gboolean +_l3cfg_routed_dns_equal(GPtrArray *routes_old, GPtrArray *routes_new) +{ + guint i; + + if (nm_g_ptr_array_len(routes_old) != nm_g_ptr_array_len(routes_new)) + return FALSE; + + if (routes_old) { + nm_platform_route_objs_sort(routes_old, NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY); + } + + if (routes_new) { + nm_platform_route_objs_sort(routes_new, NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY); + } + + for (i = 0; i < nm_g_ptr_array_len(routes_old); i++) { + if (nmp_object_cmp(routes_old->pdata[i], routes_new->pdata[i]) != 0) + return FALSE; + } + + return TRUE; +} + +static GPtrArray * +_l3cfg_routed_dns_get_existing_routes(NML3Cfg *self, int addr_family) +{ + GPtrArray *routes = NULL; + NMPLookup lookup; + const NMDedupMultiHeadEntry *head_entry; + CList *iter; + + nmp_lookup_init_object_by_ifindex(&lookup, + NMP_OBJECT_TYPE_IP_ROUTE(NM_IS_IPv4(addr_family)), + self->priv.ifindex); + + head_entry = nm_platform_lookup(self->priv.platform, &lookup); + if (!head_entry) + return NULL; + + c_list_for_each (iter, &head_entry->lst_entries_head) { + const NMPObject *obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj; + + if (nm_platform_route_table_uncoerce(obj->ipx_route.rx.table_coerced, FALSE) + != NM_DNS_ROUTES_FWMARK_TABLE_PRIO) + continue; + + if (!routes) + routes = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref); + g_ptr_array_add(routes, (gpointer) nmp_object_ref(obj)); + } + + return routes; +} + +static void +_l3cfg_routed_dns_apply(NML3Cfg *self, const NML3ConfigData *l3cd) +{ + if (!l3cd) + return; + + for (int IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) { + const char *const *nameservers; + guint i; + guint len; + int addr_family; + nm_auto_unref_ptrarray GPtrArray *old_routes = NULL; + nm_auto_unref_ptrarray GPtrArray *new_routes = NULL; + + addr_family = IS_IPv4 ? AF_INET : AF_INET6; + + if (!nm_l3_config_data_get_routed_dns(l3cd, addr_family)) + goto update_routes; + + _LOGT("configuring IPv%c DNS routes", nm_utils_addr_family_to_char(addr_family)); + + new_routes = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref); + + nameservers = nm_l3_config_data_get_nameservers(l3cd, addr_family, &len); + for (i = 0; i < len; i++) { + nm_auto_nmpobj NMPObject *obj = NULL; + NMPObject *obj_new; + const NMPlatformIPXRoute *route; + NMPlatformIPXRoute route_new; + char addr_buf[INET6_ADDRSTRLEN]; + char route_buf[128]; + NMDnsServer dns; + int r; + + if (!nm_dns_uri_parse(addr_family, nameservers[i], &dns)) + continue; + + /* Find the gateway to the DNS over the current interface. When + * doing the lookup, we want to ignore existing DNS routes added + * before: use policy routing with a special fwmark that skips + * the table containing DNS routes. */ + r = nm_platform_ip_route_get(self->priv.platform, + addr_family, + &dns.addr, + NM_DNS_ROUTES_FWMARK_TABLE_PRIO, + self->priv.ifindex, + &obj); + if (r < 0) { + _LOGD("could not get route to DNS server %s", + nm_inet_ntop(addr_family, dns.addr.addr_ptr, addr_buf)); + continue; + } + + route = NMP_OBJECT_CAST_IPX_ROUTE(obj); + + if (IS_IPv4) { + route_new.r4 = (NMPlatformIP4Route) { + .ifindex = self->priv.ifindex, + .network = dns.addr.addr4, + .plen = 32, + .table_any = FALSE, + .metric_any = TRUE, + .table_coerced = + nm_platform_route_table_coerce(NM_DNS_ROUTES_FWMARK_TABLE_PRIO), + .gateway = route->r4.gateway, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + }; + + nm_platform_ip_route_normalize(addr_family, &route_new.rx); + + _LOGT("route to DNS server %s: %s", + nm_inet4_ntop(dns.addr.addr4, addr_buf), + nm_platform_ip4_route_to_string(&route_new.r4, route_buf, sizeof(route_buf))); + + obj_new = nmp_object_new(NMP_OBJECT_TYPE_IP4_ROUTE, &route_new); + g_ptr_array_add(new_routes, obj_new); + } else { + route_new.r6 = (NMPlatformIP6Route) { + .ifindex = self->priv.ifindex, + .network = dns.addr.addr6, + .plen = 128, + .table_any = FALSE, + .metric_any = TRUE, + .table_coerced = + nm_platform_route_table_coerce(NM_DNS_ROUTES_FWMARK_TABLE_PRIO), + .gateway = route->r6.gateway, + .rt_source = NM_IP_CONFIG_SOURCE_USER, + }; + + nm_platform_ip_route_normalize(addr_family, &route_new.rx); + + _LOGT("route to DNS server %s: %s", + nm_inet6_ntop(&dns.addr.addr6, addr_buf), + nm_platform_ip6_route_to_string(&route_new.r6, route_buf, sizeof(route_buf))); + + obj_new = nmp_object_new(NMP_OBJECT_TYPE_IP6_ROUTE, &route_new); + g_ptr_array_add(new_routes, obj_new); + } + } + + if (new_routes->len > 0) { + NMPlatformRoutingRule rule; + NMPObject rule_obj; + + /* Add a routing rule that selects the table when not using the + * special fwmark. Note that the rule is shared between all + * devices that use DNS routes. There is no cleanup mechanism: + * once added the rule stays forever. */ + rule = ((NMPlatformRoutingRule) { + .addr_family = addr_family, + .flags = FIB_RULE_INVERT, + .priority = NM_DNS_ROUTES_FWMARK_TABLE_PRIO, + .table = NM_DNS_ROUTES_FWMARK_TABLE_PRIO, + .fwmark = NM_DNS_ROUTES_FWMARK_TABLE_PRIO, + .fwmask = 0xffffffff, + .action = FR_ACT_TO_TBL, + .protocol = RTPROT_STATIC, + }); + + nmp_object_stackinit(&rule_obj, NMP_OBJECT_TYPE_ROUTING_RULE, &rule); + + if (!nm_platform_lookup_obj(self->priv.platform, + NMP_CACHE_ID_TYPE_OBJECT_TYPE, + &rule_obj)) { + _LOGT("adding rule to DNS routing table"); + nm_platform_routing_rule_add(self->priv.platform, NMP_NLM_FLAG_ADD, &rule); + } + } + +update_routes: + old_routes = _l3cfg_routed_dns_get_existing_routes(self, addr_family); + + if (!_l3cfg_routed_dns_equal(old_routes, new_routes)) { + if (old_routes) { + _LOGT("deleting old DNS routes"); + for (i = 0; i < old_routes->len; i++) { + nm_platform_object_delete(self->priv.platform, old_routes->pdata[i]); + } + } + if (new_routes) { + _LOGT("adding new DNS routes"); + for (i = 0; i < new_routes->len; i++) { + nm_platform_ip_route_add(self->priv.platform, + NMP_NLM_FLAG_REPLACE, + new_routes->pdata[i], + NULL); + } + } + } + } +} + static void _l3cfg_update_combined_config(NML3Cfg *self, gboolean to_commit, @@ -4030,7 +4236,7 @@ _l3cfg_update_combined_config(NML3Cfg *self, nm_platform_ip6_address_init_loopback(&ax.a6)); } - rx.r4 = (NMPlatformIP4Route){ + rx.r4 = (NMPlatformIP4Route) { .ifindex = NM_LOOPBACK_IFINDEX, .rt_source = NM_IP_CONFIG_SOURCE_KERNEL, .network = NM_IPV4LO_ADDR1, @@ -4077,11 +4283,6 @@ _l3cfg_update_combined_config(NML3Cfg *self, self->priv.p->combined_l3cd_merged = nm_l3_config_data_seal(g_steal_pointer(&l3cd)); merged_changed = TRUE; - _nm_l3cfg_emit_signal_notify_l3cd_changed(self, - l3cd_old, - self->priv.p->combined_l3cd_merged, - FALSE); - if (!to_commit) { NM_SET_OUT(out_old, g_steal_pointer(&l3cd_old)); NM_SET_OUT(out_changed_combined_l3cd, TRUE); @@ -4096,11 +4297,6 @@ out: _obj_states_update_all(self); - _nm_l3cfg_emit_signal_notify_l3cd_changed(self, - l3cd_commited_old, - self->priv.p->combined_l3cd_commited, - TRUE); - NM_SET_OUT(out_old, g_steal_pointer(&l3cd_commited_old)); NM_SET_OUT(out_changed_combined_l3cd, TRUE); } @@ -4957,7 +5153,6 @@ static void _l3_commit_one(NML3Cfg *self, int addr_family, NML3CfgCommitType commit_type, - gboolean changed_combined_l3cd, const NML3ConfigData *l3cd_old) { const int IS_IPv4 = NM_IS_IPv4(addr_family); @@ -5192,10 +5387,16 @@ _l3_commit(NML3Cfg *self, NML3CfgCommitType commit_type, gboolean is_idle) &l3cd_old, &changed_combined_l3cd); - _nm_l3cfg_emit_signal_notify_simple(self, NM_L3_CONFIG_NOTIFY_TYPE_PRE_COMMIT); + _nm_l3cfg_emit_signal_notify_commit(self, + NM_L3_CONFIG_NOTIFY_TYPE_PRE_COMMIT, + l3cd_old, + self->priv.p->combined_l3cd_commited, + changed_combined_l3cd); + + _l3_commit_one(self, AF_INET, commit_type, l3cd_old); + _l3_commit_one(self, AF_INET6, commit_type, l3cd_old); - _l3_commit_one(self, AF_INET, commit_type, changed_combined_l3cd, l3cd_old); - _l3_commit_one(self, AF_INET6, commit_type, changed_combined_l3cd, l3cd_old); + _l3cfg_routed_dns_apply(self, self->priv.p->combined_l3cd_commited); _failedobj_reschedule(self, 0); @@ -5206,7 +5407,11 @@ _l3_commit(NML3Cfg *self, NML3CfgCommitType commit_type, gboolean is_idle) nm_assert(self->priv.p->commit_reentrant_count == 1); self->priv.p->commit_reentrant_count--; - _nm_l3cfg_emit_signal_notify_simple(self, NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT); + _nm_l3cfg_emit_signal_notify_commit(self, + NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT, + l3cd_old, + self->priv.p->combined_l3cd_commited, + changed_combined_l3cd); } NML3CfgBlockHandle * diff --git a/src/core/nm-l3cfg.h b/src/core/nm-l3cfg.h index 4d3537a0..5f0721da 100644 --- a/src/core/nm-l3cfg.h +++ b/src/core/nm-l3cfg.h @@ -24,6 +24,8 @@ #define NM_L3CFG_SIGNAL_NOTIFY "l3cfg-notify" +#define NM_DNS_ROUTES_FWMARK_TABLE_PRIO 20053 + typedef enum _nm_packed { _NM_L3_ACD_DEFEND_TYPE_NONE, NM_L3_ACD_DEFEND_TYPE_NEVER, @@ -123,22 +125,17 @@ nm_l3_acd_addr_info_find_track_info(const NML3AcdAddrInfo *addr_info, } typedef enum { - /* emitted when the merged/commited NML3ConfigData instance changes. + NM_L3_CONFIG_NOTIFY_TYPE_ACD_EVENT, + + /* Emitted before the merged l3cd is committed to platform. * Note that this gets emitted "under unsafe circumstances". That means, * you should not perform complex operations inside this callback, * and neither should you call into NML3Cfg again (reentrancy). */ - NM_L3_CONFIG_NOTIFY_TYPE_L3CD_CHANGED, - - NM_L3_CONFIG_NOTIFY_TYPE_ACD_EVENT, - - /* emitted before the merged l3cd is committed to platform. - * - * This event also gets emitted "under unsafe circumstances". - * See NM_L3_CONFIG_NOTIFY_TYPE_L3CD_CHANGED. */ NM_L3_CONFIG_NOTIFY_TYPE_PRE_COMMIT, /* emitted at the end of nm_l3cfg_platform_commit(). This signals also that - * nm_l3cfg_is_ready() might have switched to TRUE. */ + * nm_l3cfg_is_ready() might have switched to TRUE. Also emitted + * "under unsafe circumstances". */ NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT, /* NML3Cfg hooks to the NMPlatform signals for link, addresses and routes. @@ -168,8 +165,8 @@ typedef struct { struct { const NML3ConfigData *l3cd_old; const NML3ConfigData *l3cd_new; - bool commited; - } l3cd_changed; + bool l3cd_changed; + } commit; struct { NML3AcdAddrInfo info; diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c index b96a9053..c9bcbd12 100644 --- a/src/core/nm-manager.c +++ b/src/core/nm-manager.c @@ -1638,7 +1638,7 @@ _devcon_lookup_data(NMManager *self, return NULL; data = g_slice_new(DevConData); - *data = (DevConData){ + *data = (DevConData) { .device = device, .sett_conn = sett_conn, .autoconnect = @@ -2522,7 +2522,7 @@ return_ifname_fom_connection: g_set_error(error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, - "failed to determine interface name: error determine name for %s", + "failed to determine interface name for a %s", nm_connection_get_connection_type(connection)); } return iface; @@ -3455,7 +3455,7 @@ get_existing_connection(NMManager *self, NMDevice *device, gboolean *out_generat if (connection) { NMConnection *con = nm_settings_connection_get_connection(connection_checked); - if (nm_utils_match_connection((NMConnection *[]){con, NULL}, + if (nm_utils_match_connection((NMConnection *[]) {con, NULL}, connection, TRUE, nm_device_has_carrier(device), @@ -4536,7 +4536,7 @@ nm_manager_get_best_device_for_connection(NMManager *self, NMSettingsConnection *sett_conn, NMConnection *connection, gboolean for_user_request, - GHashTable *unavailable_devices, + GHashTable *exclude_devices, GError **error) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self); @@ -4619,7 +4619,7 @@ nm_manager_get_best_device_for_connection(NMManager *self, ac_device = nm_active_connection_get_device(ac); if (ac_device - && ((unavailable_devices && g_hash_table_contains(unavailable_devices, ac_device)) + && (nm_g_hash_table_contains(exclude_devices, ac_device) || !nm_device_check_connection_available(ac_device, connection, flags, NULL, NULL))) ac_device = NULL; @@ -4635,9 +4635,7 @@ nm_manager_get_best_device_for_connection(NMManager *self, NMDevice *ac_device2 = nm_active_connection_get_device(ac2); NMActiveConnectionState ac_state2; - if (!ac_device2 - || (unavailable_devices - && g_hash_table_contains(unavailable_devices, ac_device2)) + if (!ac_device2 || nm_g_hash_table_contains(exclude_devices, ac_device2) || !nm_device_check_connection_available(ac_device2, connection, flags, @@ -4698,7 +4696,13 @@ found_better: GError *local = NULL; DeviceActivationPrio prio; - if (unavailable_devices && g_hash_table_contains(unavailable_devices, device)) + if (nm_g_hash_table_contains(exclude_devices, device)) + continue; + + if (!nm_device_is_available(device, + for_user_request + ? NM_DEVICE_CHECK_DEV_AVAILABLE_FOR_USER_REQUEST + : NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) continue; /* determine the priority of this device. Currently, this priority is independent @@ -5347,7 +5351,7 @@ find_ports(NMManager *manager, } nm_assert(n_ports < n_all_connections); - ports[n_ports++] = (PortConnectionInfo){ + ports[n_ports++] = (PortConnectionInfo) { .connection = candidate, .device = port_device, }; @@ -6403,17 +6407,11 @@ nm_manager_activate_connection(NMManager *self, * @sett_conn: the #NMSettingsConnection to be activated, or %NULL if there * is only a partial activation. * @connection: the partial #NMConnection to be activated (if @sett_conn is unspecified) - * @device_path: the object path of the device to be activated, or NULL - * @out_device: on successful return, the #NMDevice to be activated with @connection - * The caller may pass in a device which shortcuts the lookup by path. - * In this case, the passed in device must have the matching @device_path - * already. - * @out_is_vpn: on successful return, %TRUE if @connection is a VPN connection * @error: location to store an error on failure * - * Performs basic validation on an activation request, including ensuring that - * the requestor is a valid Unix process, is not disallowed in @connection - * permissions, and that a device exists that can activate @connection. + * Performs basic permission validation on an activation request: Ensures that + * the requestor is a valid Unix process and is not disallowed in @connection + * permissions. * * Returns: on success, the #NMAuthSubject representing the requestor, or * %NULL on error @@ -6423,13 +6421,8 @@ validate_activation_request(NMManager *self, GDBusMethodInvocation *context, NMSettingsConnection *sett_conn, NMConnection *connection, - const char *device_path, - NMDevice **out_device, - gboolean *out_is_vpn, GError **error) { - NMDevice *device = NULL; - gboolean is_vpn = FALSE; gs_unref_object NMAuthSubject *subject = NULL; nm_assert(!sett_conn || NM_IS_SETTINGS_CONNECTION(sett_conn)); @@ -6437,8 +6430,6 @@ validate_activation_request(NMManager *self, nm_assert(sett_conn || connection); nm_assert(!connection || !sett_conn || connection == nm_settings_connection_get_connection(sett_conn)); - nm_assert(out_device); - nm_assert(out_is_vpn); if (!connection) connection = nm_settings_connection_get_connection(sett_conn); @@ -6459,6 +6450,51 @@ validate_activation_request(NMManager *self, NM_MANAGER_ERROR_PERMISSION_DENIED, error)) return NULL; + return g_steal_pointer(&subject); +} + +/** + * find_device_for_activation: + * @self: the #NMManager + * @sett_conn: the #NMSettingsConnection to be activated, or %NULL if there + * is only a partial activation. + * @connection: the partial #NMConnection to be activated (if @sett_conn is unspecified) + * @device_path: the object path of the device to be activated, or NULL + * @out_device: on successful return, the #NMDevice to be activated with @connection + * The caller may pass in a device which shortcuts the lookup by path. + * In this case, the passed in device must have the matching @device_path + * already. + * @out_is_vpn: on successful return, %TRUE if @connection is a VPN connection + * @error: location to store an error on failure + * + * Looks up a device that can activate @connection, or indicates the + * connection is a VPN connection that does not require a device. + * + * Returns: %TRUE if the device could be find or connection doesn't + * need one, %FALSE otherwise + */ +static gboolean +find_device_for_activation(NMManager *self, + NMSettingsConnection *sett_conn, + NMConnection *connection, + const char *device_path, + NMDevice **out_device, + gboolean *out_is_vpn, + GError **error) +{ + gboolean is_vpn = FALSE; + NMDevice *device = NULL; + + nm_assert(!sett_conn || NM_IS_SETTINGS_CONNECTION(sett_conn)); + nm_assert(!connection || NM_IS_CONNECTION(connection)); + nm_assert(sett_conn || connection); + nm_assert(!connection || !sett_conn + || connection == nm_settings_connection_get_connection(sett_conn)); + nm_assert(out_device); + nm_assert(out_is_vpn); + + if (!connection) + connection = nm_settings_connection_get_connection(sett_conn); is_vpn = _connection_is_vpn(connection); @@ -6475,7 +6511,7 @@ validate_activation_request(NMManager *self, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, "Device not found"); - return NULL; + return FALSE; } } else if (!is_vpn) { gs_free_error GError *local = NULL; @@ -6497,13 +6533,13 @@ validate_activation_request(NMManager *self, NM_MANAGER_ERROR_UNKNOWN_DEVICE, "No suitable device found for this connection (%s).", local->message); - return NULL; + return FALSE; } /* Look for an existing device with the connection's interface name */ iface = nm_manager_get_connection_iface(self, connection, NULL, NULL, error); if (!iface) - return NULL; + return FALSE; device = find_device_by_iface(self, iface, connection, NULL, NULL); if (!device) { @@ -6511,7 +6547,7 @@ validate_activation_request(NMManager *self, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, "Failed to find a compatible device for this connection"); - return NULL; + return FALSE; } } } @@ -6520,7 +6556,8 @@ validate_activation_request(NMManager *self, *out_device = device; *out_is_vpn = is_vpn; - return g_steal_pointer(&subject); + + return TRUE; } /*****************************************************************************/ @@ -6637,17 +6674,14 @@ impl_manager_activate_connection(NMDBusObject *obj, goto error; } - subject = validate_activation_request(self, - invocation, - sett_conn, - NULL, - device_path, - &device, - &is_vpn, - &error); + subject = validate_activation_request(self, invocation, sett_conn, NULL, &error); if (!subject) goto error; + if (!find_device_for_activation(self, sett_conn, NULL, device_path, &device, &is_vpn, &error)) { + goto error; + } + active = _new_active_connection(self, is_vpn, sett_conn, @@ -6920,17 +6954,20 @@ impl_manager_add_and_activate_connection(NMDBusObject *obj, NM_SETTING_PARSE_FLAGS_STRICT, NULL); - subject = validate_activation_request(self, - invocation, - NULL, - incompl_conn, - device_path, - &device, - &is_vpn, - &error); + subject = validate_activation_request(self, invocation, NULL, incompl_conn, &error); if (!subject) goto error; + if (!find_device_for_activation(self, + NULL, + incompl_conn, + device_path, + &device, + &is_vpn, + &error)) { + goto error; + } + if (is_vpn) { /* Try to fill the VPN's connection setting and name at least */ if (!nm_connection_get_setting_vpn(incompl_conn)) { @@ -6952,8 +6989,7 @@ impl_manager_add_and_activate_connection(NMDBusObject *obj, NULL, _("VPN connection"), NULL, - NULL, - FALSE); /* No IPv6 by default for now */ + NULL); } else { conns = nm_settings_connections_array_to_connections( nm_settings_get_connections(priv->settings, NULL), @@ -8931,12 +8967,12 @@ nm_manager_init(NMManager *self) priv->capabilities = g_array_new(FALSE, FALSE, sizeof(guint32)); - priv->radio_states[NM_RFKILL_TYPE_WLAN] = (RfkillRadioState){ + priv->radio_states[NM_RFKILL_TYPE_WLAN] = (RfkillRadioState) { .user_enabled = TRUE, .sw_enabled = FALSE, .hw_enabled = TRUE, }; - priv->radio_states[NM_RFKILL_TYPE_WWAN] = (RfkillRadioState){ + priv->radio_states[NM_RFKILL_TYPE_WWAN] = (RfkillRadioState) { .user_enabled = TRUE, .sw_enabled = FALSE, .hw_enabled = TRUE, diff --git a/src/core/nm-netns.c b/src/core/nm-netns.c index ed33d336..420d01e4 100644 --- a/src/core/nm-netns.c +++ b/src/core/nm-netns.c @@ -274,7 +274,7 @@ _ecmp_track_init_merged_obj(EcmpTrackEcmpid *track_ecmpid, const NMPObject **out const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE(track_obj->obj); NMPlatformIP4RtNextHop *nh = (gpointer) &obj_new->_ip4_route.extra_nexthops[i - 1]; - *nh = (NMPlatformIP4RtNextHop){ + *nh = (NMPlatformIP4RtNextHop) { .ifindex = r->ifindex, .gateway = r->gateway, .weight = r->weight, @@ -620,7 +620,7 @@ nm_netns_shared_ip_reserve(NMNetns *self) } handle = g_slice_new(NMNetnsSharedIPHandle); - *handle = (NMNetnsSharedIPHandle){ + *handle = (NMNetnsSharedIPHandle) { .addr = addr, ._ref_count = 1, ._self = self, @@ -717,7 +717,7 @@ nm_netns_ip_route_ecmp_register(NMNetns *self, NML3Cfg *l3cfg, const NMPObject * track_ecmpid = g_hash_table_lookup(priv->ecmp_track_by_ecmpid, &obj); if (!track_ecmpid) { track_ecmpid = g_slice_new(EcmpTrackEcmpid); - *track_ecmpid = (EcmpTrackEcmpid){ + *track_ecmpid = (EcmpTrackEcmpid) { .representative_obj = nmp_object_ref(obj), .merged_obj = NULL, .ecmpid_lst_head = C_LIST_INIT(track_ecmpid->ecmpid_lst_head), @@ -728,7 +728,7 @@ nm_netns_ip_route_ecmp_register(NMNetns *self, NML3Cfg *l3cfg, const NMPObject * track_ecmpid->needs_update = TRUE; track_obj = g_slice_new(EcmpTrackObj); - *track_obj = (EcmpTrackObj){ + *track_obj = (EcmpTrackObj) { .obj = nmp_object_ref(obj), .l3cfg = l3cfg, .parent_track_ecmpid = track_ecmpid, @@ -1031,7 +1031,7 @@ _watcher_handle_init(NMNetnsWatcherHandle *handle, nm_assert(handle); nm_assert(NM_NETNS_WATCHER_TYPE_VALID(watcher_type)); - *handle = (NMNetnsWatcherHandle){ + *handle = (NMNetnsWatcherHandle) { .watcher_type = watcher_type, .tag = tag, .watcher_tag_lst = C_LIST_INIT(handle->watcher_tag_lst), @@ -1194,7 +1194,7 @@ _watcher_register_handle(NMNetns *self, NMNetnsWatcherHandle *handle) data = _watcher_ip_data_lookup_addr(self, &handle->watcher_data.ip_addr.addr); if (!data) { data = g_slice_new(WatcherDataIPAddr); - *data = (WatcherDataIPAddr){ + *data = (WatcherDataIPAddr) { .addr = handle->watcher_data.ip_addr.addr, .watcher_ip_addr_lst_head = C_LIST_INIT(data->watcher_ip_addr_lst_head), }; @@ -1288,7 +1288,7 @@ nm_netns_watcher_add(NMNetns *self, if (!watcher_by_tag) { watcher_by_tag = g_slice_new(WatcherByTag); - *watcher_by_tag = (WatcherByTag){ + *watcher_by_tag = (WatcherByTag) { .tag = tag, .watcher_by_tag_lst_head = C_LIST_INIT(watcher_by_tag->watcher_by_tag_lst_head), }; diff --git a/src/core/nm-pacrunner-manager.c b/src/core/nm-pacrunner-manager.c index 80db755f..12c3c9a1 100644 --- a/src/core/nm-pacrunner-manager.c +++ b/src/core/nm-pacrunner-manager.c @@ -365,7 +365,7 @@ nm_pacrunner_manager_add(NMPacrunnerManager *self, const char *iface, const NML3 priv = NM_PACRUNNER_MANAGER_GET_PRIVATE(self); conf_id = g_slice_new(NMPacrunnerConfId); - *conf_id = (NMPacrunnerConfId){ + *conf_id = (NMPacrunnerConfId) { .log_id = ++priv->log_id_counter, .refcount = 1, .self = g_object_ref(self), diff --git a/src/core/nm-policy.c b/src/core/nm-policy.c index 05d4d006..f86d8115 100644 --- a/src/core/nm-policy.c +++ b/src/core/nm-policy.c @@ -824,7 +824,7 @@ build_device_hostname_infos(NMPolicy *self) array = g_array_sized_new(FALSE, FALSE, sizeof(DeviceHostnameInfo), 4); info = nm_g_array_append_new(array, DeviceHostnameInfo); - *info = (DeviceHostnameInfo){ + *info = (DeviceHostnameInfo) { .device = device, .priority = device_get_hostname_priority(device), .from_dhcp = @@ -2448,6 +2448,10 @@ device_l3cd_changed(NMDevice *device, */ state = nm_device_get_state(device); if (l3cd_new && state >= NM_DEVICE_STATE_IP_CONFIG && state < NM_DEVICE_STATE_DEACTIVATING) { + /* Since the device L3CD_CHANGED signal is emitted *after* the commit of + * configuration, addresses and routes are already set in kernel when we + * write the configuration to resolv.conf or send it to the DNS plugin. + * This prevents "leaks" of DNS queries via the wrong routes.*/ nm_dns_manager_set_ip_config(priv->dns_manager, AF_UNSPEC, device, diff --git a/src/core/nm-rfkill-manager.c b/src/core/nm-rfkill-manager.c index aea5df11..c8efc376 100644 --- a/src/core/nm-rfkill-manager.c +++ b/src/core/nm-rfkill-manager.c @@ -146,7 +146,7 @@ killswitch_new(struct udev_device *device, NMRfkillType rtype) platform = TRUE; ks = g_slice_new(Killswitch); - *ks = (Killswitch){ + *ks = (Killswitch) { .name = g_strdup(udev_device_get_sysname(device)), .seqnum = udev_device_get_seqnum(device), .path = g_strdup(udev_device_get_syspath(device)), diff --git a/src/core/platform/nm-fake-platform.c b/src/core/platform/nm-fake-platform.c index 6a64746e..10c69f63 100644 --- a/src/core/platform/nm-fake-platform.c +++ b/src/core/platform/nm-fake-platform.c @@ -1000,7 +1000,7 @@ ip4_address_add(NMPlatform *platform, { NMPlatformIP4Address address; - address = (NMPlatformIP4Address){ + address = (NMPlatformIP4Address) { .addr_source = NM_IP_CONFIG_SOURCE_KERNEL, .ifindex = ifindex, .address = addr, diff --git a/src/core/platform/tests/test-common.c b/src/core/platform/tests/test-common.c index 99b8bc45..26f8b26b 100644 --- a/src/core/platform/tests/test-common.c +++ b/src/core/platform/tests/test-common.c @@ -224,7 +224,7 @@ _nmtstp_platform_ip_addresses_assert(const char *filename, else g_error("%s:%d: invalid IP address in argument: %s", filename, lineno, addrstr); - addrs_bin[i] = (IPAddressesAssertData){ + addrs_bin[i] = (IPAddressesAssertData) { .addr_family = addr_family, .addr = a, .found = FALSE, @@ -1117,7 +1117,7 @@ again: link = nmtstp_link_gre_add(NULL, EX, test_ifname, - &((const NMPlatformLnkGre){ + &((const NMPlatformLnkGre) { .local = nmtst_inet4_from_string("192.168.233.204"), .remote = nmtst_inet4_from_string("172.168.10.25"), .parent_ifindex = 0, @@ -1129,7 +1129,7 @@ again: link = nmtstp_link_ipip_add(NULL, EX, test_ifname, - &((const NMPlatformLnkIpIp){ + &((const NMPlatformLnkIpIp) { .local = nmtst_inet4_from_string("1.2.3.4"), .remote = nmtst_inet4_from_string("5.6.7.8"), .parent_ifindex = 0, @@ -1140,7 +1140,7 @@ again: link = nmtstp_link_ip6tnl_add(NULL, EX, test_ifname, - &((const NMPlatformLnkIp6Tnl){ + &((const NMPlatformLnkIp6Tnl) { .local = nmtst_inet6_from_string("fd01::15"), .remote = nmtst_inet6_from_string("fd01::16"), .tclass = 20, @@ -1152,7 +1152,7 @@ again: link = nmtstp_link_ip6gre_add(NULL, EX, test_ifname, - &((const NMPlatformLnkIp6Tnl){ + &((const NMPlatformLnkIp6Tnl) { .local = nmtst_inet6_from_string("fd01::42"), .remote = nmtst_inet6_from_string("fd01::aaaa"), .tclass = 21, @@ -1163,7 +1163,7 @@ again: link = nmtstp_link_sit_add(NULL, EX, test_ifname, - &((const NMPlatformLnkSit){ + &((const NMPlatformLnkSit) { .local = nmtst_inet4_from_string("192.168.200.1"), .remote = nmtst_inet4_from_string("172.25.100.14"), .ttl = 0, @@ -1174,7 +1174,7 @@ again: link = nmtstp_link_vti_add(NULL, EX, test_ifname, - &((const NMPlatformLnkVti){ + &((const NMPlatformLnkVti) { .local = nmtst_inet4_from_string("192.168.212.204"), .remote = nmtst_inet4_from_string("172.168.11.25"), .ikey = 12, @@ -1184,7 +1184,7 @@ again: link = nmtstp_link_vti6_add(NULL, EX, test_ifname, - &((const NMPlatformLnkVti6){ + &((const NMPlatformLnkVti6) { .local = nmtst_inet6_from_string("fd01::1"), .remote = nmtst_inet6_from_string("fd02::2"), .ikey = 13, @@ -1891,11 +1891,11 @@ nmtstp_ip4_address_add(NMPlatform *platform, external_command, TRUE, ifindex, - &((NMIPAddr){ + &((NMIPAddr) { .addr4 = address, }), plen, - &((NMIPAddr){ + &((NMIPAddr) { .addr4 = peer_address, }), lifetime, @@ -3592,7 +3592,7 @@ nmtstp_acd_defender_new(int ifindex, in_addr_t ip_addr, const NMEtherAddr *mac_a g_assert_cmpint(r, ==, 0); g_assert(probe_config); - n_acd_probe_config_set_ip(probe_config, (struct in_addr){ip_addr}); + n_acd_probe_config_set_ip(probe_config, (struct in_addr) {ip_addr}); n_acd_probe_config_set_timeout(probe_config, 0); r = n_acd_probe(nacd, &probe, probe_config); @@ -3600,7 +3600,7 @@ nmtstp_acd_defender_new(int ifindex, in_addr_t ip_addr, const NMEtherAddr *mac_a g_assert(probe); defender = g_slice_new(NMTstpAcdDefender); - *defender = (NMTstpAcdDefender){ + *defender = (NMTstpAcdDefender) { .ifindex = ifindex, .ip_addr = ip_addr, .nacd = g_steal_pointer(&nacd), diff --git a/src/core/platform/tests/test-common.h b/src/core/platform/tests/test-common.h index 12d6e7ce..85ed7961 100644 --- a/src/core/platform/tests/test-common.h +++ b/src/core/platform/tests/test-common.h @@ -372,21 +372,21 @@ void _nmtstp_platform_ip_addresses_assert(const char *filename, guint addrs_len, const char *const *addrs); -#define nmtstp_platform_ip_addresses_assert(self, \ - ifindex, \ - force_exact_4, \ - force_exact_6, \ - ignore_ll6, \ - ...) \ - _nmtstp_platform_ip_addresses_assert(__FILE__, \ - __LINE__, \ - (self), \ - (ifindex), \ - (force_exact_4), \ - (force_exact_6), \ - (ignore_ll6), \ - NM_NARG(__VA_ARGS__), \ - ((const char *const[]){"dummy", ##__VA_ARGS__, NULL}) \ +#define nmtstp_platform_ip_addresses_assert(self, \ + ifindex, \ + force_exact_4, \ + force_exact_6, \ + ignore_ll6, \ + ...) \ + _nmtstp_platform_ip_addresses_assert(__FILE__, \ + __LINE__, \ + (self), \ + (ifindex), \ + (force_exact_4), \ + (force_exact_6), \ + (ignore_ll6), \ + NM_NARG(__VA_ARGS__), \ + ((const char *const[]) {"dummy", ##__VA_ARGS__, NULL}) \ + 1) /*****************************************************************************/ @@ -540,7 +540,7 @@ gboolean nmtstp_ensure_module(const char *module_name); /*****************************************************************************/ #define nmtst_object_new_mptcp_addr(...) \ - nmp_object_new(NMP_OBJECT_TYPE_MPTCP_ADDR, &((const NMPlatformMptcpAddr){__VA_ARGS__})) + nmp_object_new(NMP_OBJECT_TYPE_MPTCP_ADDR, &((const NMPlatformMptcpAddr) {__VA_ARGS__})) /*****************************************************************************/ diff --git a/src/core/platform/tests/test-link.c b/src/core/platform/tests/test-link.c index bcb135d3..4cadfe4d 100644 --- a/src/core/platform/tests/test-link.c +++ b/src/core/platform/tests/test-link.c @@ -174,7 +174,7 @@ software_add(NMLinkType link_type, const char *name) return NMTST_NM_ERR_SUCCESS(nm_platform_link_vlan_add(NM_PLATFORM_GET, name, parent_ifindex, - &((NMPlatformLnkVlan){ + &((NMPlatformLnkVlan) { .id = VLAN_ID, .protocol = ETH_P_8021Q, }), @@ -289,7 +289,7 @@ test_port(int controller, int port_type, SignalData *controller_changed) prio_supported = (lnk->mode == 1); prio_has = nmtst_get_rand_bool() && prio_supported; - bond_port = (NMPlatformLinkBondPort){ + bond_port = (NMPlatformLinkBondPort) { .queue_id = 5, .prio_has = prio_has, .prio = prio_has ? 6 : 0, @@ -315,7 +315,7 @@ test_port(int controller, int port_type, SignalData *controller_changed) lnk = nm_platform_link_get_lnk_bridge(NM_PLATFORM_GET, controller, NULL); g_assert(lnk); - bridge_port = (NMPlatformLinkBridgePort){ + bridge_port = (NMPlatformLinkBridgePort) { .path_cost = 100, .priority = 614, .hairpin = 0, @@ -724,7 +724,7 @@ test_bridge_addr(void) g_assert_cmpint(plink->l_address.len, ==, sizeof(addr)); g_assert(!memcmp(plink->l_address.data, addr, sizeof(addr))); - info_data = (const NMPlatformLinkSetBridgeInfoData){ + info_data = (const NMPlatformLinkSetBridgeInfoData) { .vlan_default_pvid_val = nmtst_rand_select(0, 5, 42, 1048), .vlan_default_pvid_has = nmtst_get_rand_bool(), .vlan_filtering_val = nmtst_get_rand_bool(), @@ -743,7 +743,7 @@ test_bridge_addr(void) "/sys/class/net/" DEVICE_NAME "/bridge/vlan_filtering", info_data.vlan_filtering_val && info_data.vlan_filtering_has ? "1" : "0"); - info_data = (const NMPlatformLinkSetBridgeInfoData){ + info_data = (const NMPlatformLinkSetBridgeInfoData) { .vlan_default_pvid_val = 55, .vlan_default_pvid_has = TRUE, .vlan_filtering_val = !info_data.vlan_filtering_val, @@ -1275,7 +1275,7 @@ _test_wireguard_change(NMPlatform *platform, int ifindex, int test_mode) peers = g_array_new(FALSE, TRUE, sizeof(NMPWireGuardPeer)); - lnk_wireguard = (NMPlatformLnkWireGuard){ + lnk_wireguard = (NMPlatformLnkWireGuard) { .listen_port = 50754, .fwmark = 0x1102, }; @@ -1295,7 +1295,7 @@ _test_wireguard_change(NMPlatform *platform, int ifindex, int test_mode) NMPWireGuardAllowedIP *allowed_ips; if ((i % 2) == 1) { - endpoint = (NMSockAddrUnion){ + endpoint = (NMSockAddrUnion) { .in = { .sin_family = AF_INET, @@ -1305,7 +1305,7 @@ _test_wireguard_change(NMPlatform *platform, int ifindex, int test_mode) }, }; } else { - endpoint = (NMSockAddrUnion){ + endpoint = (NMSockAddrUnion) { .in6 = { .sin6_family = AF_INET6, @@ -1337,7 +1337,7 @@ _test_wireguard_change(NMPlatform *platform, int ifindex, int test_mode) } } - peer = (NMPWireGuardPeer){ + peer = (NMPWireGuardPeer) { .persistent_keepalive_interval = 60 + i, .endpoint = endpoint, .allowed_ips = n_allowed_ips > 0 ? allowed_ips : NULL, @@ -1803,7 +1803,7 @@ test_software_detect(gconstpointer user_data) switch (test_data->test_mode) { case 0: - lnk_tun = (NMPlatformLnkTun){ + lnk_tun = (NMPlatformLnkTun) { .type = nmtst_get_rand_bool() ? IFF_TUN : IFF_TAP, .owner = owner_valid ? getuid() : 0, .owner_valid = owner_valid, @@ -2702,7 +2702,7 @@ test_link_set_properties(void) NMPlatformLinkChangeFlags flags; int ifindex; - props = (NMPlatformLinkProps){ + props = (NMPlatformLinkProps) { .tx_queue_length = 599, .gso_max_size = 10001, .gso_max_segments = 512, @@ -3814,7 +3814,7 @@ test_sysctl_set_async(void) cancellable = g_cancellable_new(); proc_writable = access(PATH, W_OK) == 0; - data = (SetAsyncData){ + data = (SetAsyncData) { .loop = loop, .path = PATH, .expected_success = proc_writable, @@ -3823,7 +3823,7 @@ test_sysctl_set_async(void) nm_platform_sysctl_set_async(PL, NMP_SYSCTL_PATHID_ABSOLUTE(PATH), - (const char *[]){"2", NULL}, + (const char *[]) {"2", NULL}, sysctl_set_async_cb, &data, cancellable); @@ -3831,7 +3831,7 @@ test_sysctl_set_async(void) if (!nmtst_main_loop_run(loop, 1000)) g_assert_not_reached(); - data = (SetAsyncData){ + data = (SetAsyncData) { .loop = loop, .path = PATH, .expected_success = proc_writable, @@ -3840,7 +3840,7 @@ test_sysctl_set_async(void) nm_platform_sysctl_set_async(PL, NMP_SYSCTL_PATHID_ABSOLUTE(PATH), - (const char *[]){"2", "0", "1", "0", "1", NULL}, + (const char *[]) {"2", "0", "1", "0", "1", NULL}, sysctl_set_async_cb, &data, cancellable); @@ -3867,7 +3867,7 @@ test_sysctl_set_async_fail(void) loop = g_main_loop_new(NULL, FALSE); cancellable = g_cancellable_new(); - data = (SetAsyncData){ + data = (SetAsyncData) { .loop = loop, .path = PATH, .expected_success = FALSE, @@ -3875,7 +3875,7 @@ test_sysctl_set_async_fail(void) nm_platform_sysctl_set_async(PL, NMP_SYSCTL_PATHID_ABSOLUTE(PATH), - (const char *[]){"2", NULL}, + (const char *[]) {"2", NULL}, sysctl_set_async_cb, &data, cancellable); diff --git a/src/core/platform/tests/test-route.c b/src/core/platform/tests/test-route.c index 9aa21a9a..a05362f2 100644 --- a/src/core/platform/tests/test-route.c +++ b/src/core/platform/tests/test-route.c @@ -574,6 +574,7 @@ test_ip4_route_get(void) result = nm_platform_ip_route_get(NM_PLATFORM_GET, AF_INET, &a, + 0, nmtst_get_rand_uint32() % 2 ? 0 : ifindex, &route); @@ -638,7 +639,7 @@ test_ip4_route_options(gconstpointer test_data) switch (TEST_IDX) { case 1: - rts_add[rts_n++] = ((NMPlatformIP4Route){ + rts_add[rts_n++] = ((NMPlatformIP4Route) { .ifindex = IFINDEX, .rt_source = NM_IP_CONFIG_SOURCE_USER, .network = nmtst_inet4_from_string("172.16.1.0"), @@ -658,7 +659,7 @@ test_ip4_route_options(gconstpointer test_data) }); break; case 2: - addr[addr_n++] = ((NMPlatformIP4Address){ + addr[addr_n++] = ((NMPlatformIP4Address) { .ifindex = IFINDEX, .address = nmtst_inet4_from_string("172.16.1.5"), .peer_address = nmtst_inet4_from_string("172.16.1.5"), @@ -667,7 +668,7 @@ test_ip4_route_options(gconstpointer test_data) .preferred = NM_PLATFORM_LIFETIME_PERMANENT, .n_ifa_flags = 0, }); - rts_add[rts_n++] = ((NMPlatformIP4Route){ + rts_add[rts_n++] = ((NMPlatformIP4Route) { .ifindex = IFINDEX, .rt_source = NM_IP_CONFIG_SOURCE_USER, .network = nmtst_inet4_from_string("172.17.1.0"), @@ -676,7 +677,7 @@ test_ip4_route_options(gconstpointer test_data) .metric = 20, .n_nexthops = 1, }); - rts_add[rts_n++] = ((NMPlatformIP4Route){ + rts_add[rts_n++] = ((NMPlatformIP4Route) { .ifindex = IFINDEX, .rt_source = NM_IP_CONFIG_SOURCE_USER, .network = nmtst_inet4_from_string("172.19.1.0"), @@ -766,6 +767,7 @@ test_ip6_route_get(void) result = nm_platform_ip_route_get(NM_PLATFORM_GET, AF_INET6, a, + 0, nmtst_get_rand_uint32() % 2 ? 0 : ifindex, &route); @@ -801,7 +803,7 @@ test_ip6_route_options(gconstpointer test_data) switch (TEST_IDX) { case 1: - rts_add[rts_n++] = ((NMPlatformIP6Route){ + rts_add[rts_n++] = ((NMPlatformIP6Route) { .ifindex = IFINDEX, .rt_source = NM_IP_CONFIG_SOURCE_USER, .network = nmtst_inet6_from_string("2001:db8:a:b:0:0:0:0"), @@ -817,7 +819,7 @@ test_ip6_route_options(gconstpointer test_data) }); break; case 2: - addr[addr_n++] = ((NMPlatformIP6Address){ + addr[addr_n++] = ((NMPlatformIP6Address) { .ifindex = IFINDEX, .address = nmtst_inet6_from_string("2000::2"), .plen = 128, @@ -826,7 +828,7 @@ test_ip6_route_options(gconstpointer test_data) .preferred = NM_PLATFORM_LIFETIME_PERMANENT, .n_ifa_flags = 0, }); - rts_add[rts_n++] = ((NMPlatformIP6Route){ + rts_add[rts_n++] = ((NMPlatformIP6Route) { .ifindex = IFINDEX, .rt_source = NM_IP_CONFIG_SOURCE_USER, .network = nmtst_inet6_from_string("1010::1"), @@ -837,7 +839,7 @@ test_ip6_route_options(gconstpointer test_data) }); break; case 3: - addr[addr_n++] = ((NMPlatformIP6Address){ + addr[addr_n++] = ((NMPlatformIP6Address) { .ifindex = IFINDEX, .address = nmtst_inet6_from_string("2001:db8:8086::5"), .plen = 128, @@ -846,7 +848,7 @@ test_ip6_route_options(gconstpointer test_data) .preferred = NM_PLATFORM_LIFETIME_PERMANENT, .n_ifa_flags = 0, }); - rts_add[rts_n++] = ((NMPlatformIP6Route){ + rts_add[rts_n++] = ((NMPlatformIP6Route) { .ifindex = IFINDEX, .rt_source = nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER), .network = nmtst_inet6_from_string("2001:db8:8086::"), @@ -854,7 +856,7 @@ test_ip6_route_options(gconstpointer test_data) .metric = 10021, .mss = 0, }); - rts_add[rts_n++] = ((NMPlatformIP6Route){ + rts_add[rts_n++] = ((NMPlatformIP6Route) { .ifindex = IFINDEX, .rt_source = nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER), .network = nmtst_inet6_from_string("2001:db8:abad:c0de::"), @@ -1595,7 +1597,7 @@ test_rule(gconstpointer test_data) #define RR(...) \ nmp_object_new(NMP_OBJECT_TYPE_ROUTING_RULE, \ - (const NMPlatformObject *) &((NMPlatformRoutingRule){__VA_ARGS__})) + (const NMPlatformObject *) &((NMPlatformRoutingRule) {__VA_ARGS__})) objs = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref); @@ -1926,11 +1928,11 @@ test_blackhole(gconstpointer test_data) rtn_type = nmtst_rand_select(RTN_BLACKHOLE, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_THROW); if (IS_IPv4) { - rr.r4 = (const NMPlatformIP4Route){ + rr.r4 = (const NMPlatformIP4Route) { .type_coerced = nm_platform_route_type_coerce(rtn_type), }; } else { - rr.r6 = (const NMPlatformIP6Route){ + rr.r6 = (const NMPlatformIP6Route) { .type_coerced = nm_platform_route_type_coerce(rtn_type), .metric = 1000, }; @@ -1987,7 +1989,7 @@ again: if (p == -1) { static gsize lock; - const NMPlatformMptcpAddr mptcp_addr = (NMPlatformMptcpAddr){ + const NMPlatformMptcpAddr mptcp_addr = (NMPlatformMptcpAddr) { .id = 1, .addr_family = AF_INET, .addr.addr4 = nmtst_inet4_from_string("1.2.3.4"), diff --git a/src/core/platform/tests/test-tc.c b/src/core/platform/tests/test-tc.c index 832fbea6..dc4dafc0 100644 --- a/src/core/platform/tests/test-tc.c +++ b/src/core/platform/tests/test-tc.c @@ -16,7 +16,7 @@ qdisc_new(int ifindex, const char *kind, guint32 parent) NMPObject *obj; obj = nmp_object_new(NMP_OBJECT_TYPE_QDISC, NULL); - obj->qdisc = (NMPlatformQdisc){ + obj->qdisc = (NMPlatformQdisc) { .ifindex = ifindex, .kind = kind, .parent = parent, diff --git a/src/core/ppp/nm-ppp-manager.c b/src/core/ppp/nm-ppp-manager.c index fbc5d075..2eebd17d 100644 --- a/src/core/ppp/nm-ppp-manager.c +++ b/src/core/ppp/nm-ppp-manager.c @@ -547,7 +547,7 @@ impl_ppp_manager_set_ip4_config(NMDBusObject *obj, nm_l3_config_data_set_mtu(l3cd, mtu); - address = (NMPlatformIP4Address){ + address = (NMPlatformIP4Address) { .plen = 32, }; @@ -583,7 +583,7 @@ impl_ppp_manager_set_ip4_config(NMDBusObject *obj, if (g_variant_lookup(config_dict, NM_PPP_IP4_CONFIG_DNS, "au", &iter)) { while (g_variant_iter_next(iter, "u", &u32)) - nm_l3_config_data_add_nameserver_detail(l3cd, AF_INET, &u32, NULL); + nm_l3_config_data_add_nameserver_addr(l3cd, AF_INET, &u32); g_variant_iter_free(iter); } @@ -662,7 +662,7 @@ impl_ppp_manager_set_ip6_config(NMDBusObject *obj, nm_l3_config_data_set_mtu(l3cd, mtu); - address = (NMPlatformIP6Address){ + address = (NMPlatformIP6Address) { .plen = 64, .addr_source = NM_IP_CONFIG_SOURCE_PPP, }; diff --git a/src/core/ppp/nm-ppp-mgr.c b/src/core/ppp/nm-ppp-mgr.c index 91d9a021..9f6e8835 100644 --- a/src/core/ppp/nm-ppp-mgr.c +++ b/src/core/ppp/nm-ppp-mgr.c @@ -208,11 +208,11 @@ _set_state_failed(NMPppMgr *self, NMPppMgrState state, NMPppMgrState *out_old_st self->ifindex = 0; nm_clear_l3cd(&self->ip_data_4.l3cd); nm_clear_l3cd(&self->ip_data_6.l3cd); - self->ip_data_4 = (NMPppMgrIPData){ + self->ip_data_4 = (NMPppMgrIPData) { .ip_received = FALSE, .ip_enabled = FALSE, }; - self->ip_data_6 = (NMPppMgrIPData){ + self->ip_data_6 = (NMPppMgrIPData) { .ip_received = FALSE, .ip_enabled = FALSE, }; @@ -563,7 +563,7 @@ nm_ppp_mgr_start(const NMPppMgrConfig *config, GError **error) self = g_slice_new(NMPppMgr); - *self = (NMPppMgr){ + *self = (NMPppMgr) { .config = *config, .ppp_manager = ppp_manager, .idle_start = nm_g_idle_add_source(_idle_start_cb, self), diff --git a/src/core/ppp/nm-pppd-compat.c b/src/core/ppp/nm-pppd-compat.c index 04e26f22..c1416023 100644 --- a/src/core/ppp/nm-pppd-compat.c +++ b/src/core/ppp/nm-pppd-compat.c @@ -164,14 +164,14 @@ nm_pppd_compat_get_ipcp_options(NMPppdCompatIPCPOptions *out_got, NMPppdCompatIP nm_assert(out_got); nm_assert(out_his); - *out_got = (NMPppdCompatIPCPOptions){ + *out_got = (NMPppdCompatIPCPOptions) { .ouraddr = got->ouraddr, .hisaddr = got->hisaddr, .dnsaddr = {got->dnsaddr[0], got->dnsaddr[1]}, .winsaddr = {got->winsaddr[0], got->winsaddr[1]}, }; - *out_his = (NMPppdCompatIPCPOptions){ + *out_his = (NMPppdCompatIPCPOptions) { .ouraddr = his->ouraddr, .hisaddr = his->hisaddr, .dnsaddr = {his->dnsaddr[0], his->dnsaddr[1]}, @@ -191,11 +191,11 @@ nm_pppd_compat_get_ipv6cp_options(NMPppdCompatIPV6CPOptions *out_got, nm_assert(out_got); nm_assert(out_his); - *out_got = (NMPppdCompatIPV6CPOptions){}; + *out_got = (NMPppdCompatIPV6CPOptions) {}; memcpy(&out_got->ourid, &got->ourid, sizeof(guint64)); memcpy(&out_got->hisid, &got->hisid, sizeof(guint64)); - *out_his = (NMPppdCompatIPV6CPOptions){}; + *out_his = (NMPppdCompatIPV6CPOptions) {}; memcpy(&out_his->ourid, &his->ourid, sizeof(guint64)); memcpy(&out_his->hisid, &his->hisid, sizeof(guint64)); } diff --git a/src/core/settings/nm-secret-agent.c b/src/core/settings/nm-secret-agent.c index bb300345..6448ec57 100644 --- a/src/core/settings/nm-secret-agent.c +++ b/src/core/settings/nm-secret-agent.c @@ -142,7 +142,7 @@ _call_id_new(NMSecretAgent *self, NMSecretAgentCallId *call_id; call_id = g_slice_new(NMSecretAgentCallId); - *call_id = (NMSecretAgentCallId){ + *call_id = (NMSecretAgentCallId) { .self = g_object_ref(self), .path = g_strdup(path), .setting_name = g_strdup(setting_name), diff --git a/src/core/settings/nm-settings-connection.c b/src/core/settings/nm-settings-connection.c index 459c60ad..d5611e76 100644 --- a/src/core/settings/nm-settings-connection.c +++ b/src/core/settings/nm-settings-connection.c @@ -1721,7 +1721,7 @@ settings_connection_update(NMSettingsConnection *self, goto error; info = g_slice_new(UpdateInfo); - *info = (UpdateInfo){ + *info = (UpdateInfo) { .is_update2 = is_update2, .context = context, .agent_mgr = g_object_ref(priv->agent_mgr), diff --git a/src/core/settings/nm-settings-plugin.c b/src/core/settings/nm-settings-plugin.c index 60181759..5dae482f 100644 --- a/src/core/settings/nm-settings-plugin.c +++ b/src/core/settings/nm-settings-plugin.c @@ -110,7 +110,7 @@ nm_settings_plugin_create_connection_load_entries(const char *const *filenames, entries = g_new(NMSettingsPluginConnectionLoadEntry, len); for (i = 0; i < len; i++) { - entries[i] = (NMSettingsPluginConnectionLoadEntry){ + entries[i] = (NMSettingsPluginConnectionLoadEntry) { .filename = filenames[i], .error = NULL, .handled = FALSE, diff --git a/src/core/settings/nm-settings-utils.c b/src/core/settings/nm-settings-utils.c index 4343a376..820d4fbd 100644 --- a/src/core/settings/nm-settings-utils.c +++ b/src/core/settings/nm-settings-utils.c @@ -37,14 +37,14 @@ nm_sett_util_stat_mtime(const char *filename, gboolean do_lstat, struct timespec } if (gettimeofday(&now_tv, NULL) == 0) { - *out_val = (struct timespec){ + *out_val = (struct timespec) { .tv_sec = now_tv.tv_sec, .tv_nsec = now_tv.tv_usec * 1000u, }; return out_val; } - *out_val = (struct timespec){}; + *out_val = (struct timespec) {}; return out_val; } diff --git a/src/core/settings/nm-settings-utils.h b/src/core/settings/nm-settings-utils.h index d3f50ddf..949963e2 100644 --- a/src/core/settings/nm-settings-utils.h +++ b/src/core/settings/nm-settings-utils.h @@ -81,7 +81,7 @@ typedef struct { } NMSettUtilAllowFilenameData; #define NM_SETT_UTIL_ALLOW_FILENAME_DATA(_storages, _allowed_filename) \ - (&((NMSettUtilAllowFilenameData){ \ + (&((NMSettUtilAllowFilenameData) { \ .idx_by_filename = (_storages)->idx_by_filename, \ .allowed_filename = (_allowed_filename), \ })) diff --git a/src/core/settings/nm-settings.c b/src/core/settings/nm-settings.c index 80b1f4b2..50d98ece 100644 --- a/src/core/settings/nm-settings.c +++ b/src/core/settings/nm-settings.c @@ -703,7 +703,7 @@ _startup_complete_notify_connection(NMSettings *self, if (timeout_msec == 0) return; scd = g_slice_new(StartupCompleteData); - *scd = (StartupCompleteData){ + *scd = (StartupCompleteData) { .sett_conn = g_object_ref(sett_conn), .timeout_msec = timeout_msec, }; 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 81964de6..d64052cb 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,9 +2056,8 @@ make_ip4_setting(shvarFile *ifcfg, * Pick up just IPv4 addresses (IPv6 addresses are taken by make_ip6_setting()) */ for (i = 1; i < 10000; i++) { - int af; - NMIPAddr ip; - char tag[256]; + NMDnsServer dns; + char tag[256]; numbered_tag(tag, "DNS", i); nm_clear_g_free(&value); @@ -2066,14 +2065,16 @@ make_ip4_setting(shvarFile *ifcfg, if (!v) break; - if (!nm_utils_dnsname_parse(AF_UNSPEC, v, &af, &ip, NULL)) { + if (!nm_dns_uri_parse(AF_UNSPEC, v, &dns)) { g_set_error(error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Invalid DNS server address '%s'", v); return NULL; - } else if (af == AF_INET) { + } + + if (dns.addr_family == AF_INET) { if (!nm_setting_ip_config_add_dns(s_ip4, v)) PARSE_WARNING("duplicate DNS server %s", tag); } else { @@ -2606,9 +2607,8 @@ 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++) { - int af; - NMIPAddr ip; - char tag[256]; + NMDnsServer dns; + char tag[256]; numbered_tag(tag, "DNS", i); nm_clear_g_free(&value); @@ -2616,7 +2616,7 @@ make_ip6_setting(shvarFile *ifcfg, shvarFile *network_ifcfg, gboolean routes_rea if (!v) break; - if (!nm_utils_dnsname_parse(AF_UNSPEC, v, &af, &ip, NULL)) { + if (!nm_dns_uri_parse(AF_UNSPEC, v, &dns)) { if (is_disabled) continue; g_set_error(error, @@ -2625,7 +2625,8 @@ make_ip6_setting(shvarFile *ifcfg, shvarFile *network_ifcfg, gboolean routes_rea "Invalid DNS server address '%s'", v); return NULL; - } else if (af == AF_INET6) { + } + if (dns.addr_family == AF_INET6) { if (is_disabled) { PARSE_WARNING("ignore DNS server addresses with method disabled/ignore"); break; 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 21f31d8b..6e0411c6 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 @@ -1454,6 +1454,15 @@ write_ethtool_setting(NMConnection *connection, shvarFile *ifcfg, GError **error return FALSE; } } + if (ethtool_id == NM_ETHTOOL_ID_FEC_MODE) { + if (nm_setting_option_get_uint32(NM_SETTING(s_ethtool), + nm_ethtool_data[ethtool_id]->optname, + &u32)) { + nm_sprintf_buf(prop_name, "ethtool.%s", nm_ethtool_data[ethtool_id]->optname); + set_error_unsupported(error, connection, prop_name, FALSE); + return FALSE; + } + } if (!any_option) { /* Write an empty dummy "-A" option without arguments. This is to @@ -3588,13 +3597,24 @@ do_write_construct(NMConnection *connection, } else route_ignore = FALSE; - if ((s_ip4 = nm_connection_get_setting_ip4_config(connection)) - && nm_setting_ip_config_get_dhcp_dscp(s_ip4)) { - set_error_unsupported(error, - connection, - NM_SETTING_IP4_CONFIG_SETTING_NAME "." NM_SETTING_IP_CONFIG_DHCP_DSCP, - FALSE); - return FALSE; + if ((s_ip4 = nm_connection_get_setting_ip4_config(connection))) { + if (nm_setting_ip_config_get_dhcp_dscp(s_ip4)) { + set_error_unsupported(error, + connection, + NM_SETTING_IP4_CONFIG_SETTING_NAME + "." NM_SETTING_IP_CONFIG_DHCP_DSCP, + FALSE); + return FALSE; + } + if (nm_setting_ip4_config_get_dhcp_ipv6_only_preferred(NM_SETTING_IP4_CONFIG(s_ip4)) + != NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_DEFAULT) { + set_error_unsupported(error, + connection, + NM_SETTING_IP4_CONFIG_SETTING_NAME + "." NM_SETTING_IP4_CONFIG_DHCP_IPV6_ONLY_PREFERRED, + FALSE); + return FALSE; + } } write_ip4_setting(connection, diff --git a/src/core/settings/plugins/ifcfg-rh/shvar.c b/src/core/settings/plugins/ifcfg-rh/shvar.c index 1ca2ea60..565e20f7 100644 --- a/src/core/settings/plugins/ifcfg-rh/shvar.c +++ b/src/core/settings/plugins/ifcfg-rh/shvar.c @@ -722,7 +722,7 @@ svFile_new(const char *name, int fd, const char *content) nm_assert(fd >= -1); s = g_slice_new(shvarFile); - *s = (shvarFile){ + *s = (shvarFile) { .fileName = g_strdup(name), .fd = fd, .lst_head = C_LIST_INIT(s->lst_head), @@ -796,7 +796,7 @@ line_new_parse(const char *value, gsize len) nm_assert(value); line = g_slice_new(shvarLine); - *line = (shvarLine){ + *line = (shvarLine) { .lst = C_LIST_INIT(line->lst), .dirty = TRUE, }; @@ -836,7 +836,7 @@ line_new_build(const char *key, const char *value) value = svEscape(value, &value_escaped); line = g_slice_new(shvarLine); - new_key = g_strdup(key), *line = (shvarLine){ + new_key = g_strdup(key), *line = (shvarLine) { .lst = C_LIST_INIT(line->lst), .line = value_escaped ?: g_strdup(value), .key_with_prefix = new_key, diff --git a/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 334662c3..ea978a98 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -3623,7 +3623,8 @@ test_roundtrip_ethtool(void) optname = nm_ethtool_data[ethtool_id]->optname; vtype = nm_ethtool_id_get_variant_type(ethtool_id); - if (nm_ethtool_optname_is_channels(optname) || nm_ethtool_optname_is_eee(optname)) { + if (nm_ethtool_optname_is_channels(optname) || nm_ethtool_optname_is_eee(optname) + || nm_ethtool_optname_is_fec(optname)) { /* Not supported */ continue; } @@ -9520,18 +9521,24 @@ do_svUnescape_combine_ansi(GString *str_val, static void test_svUnescape(void) { -#define V0(v_value, v_expected) \ - { \ - .val = "" v_value "", .exp = v_expected, .can_concat = FALSE, \ +#define V0(v_value, v_expected) \ + { \ + .val = "" v_value "", \ + .exp = v_expected, \ + .can_concat = FALSE, \ } -#define V1(v_value, v_expected) \ - { \ - .val = "" v_value "", .exp = v_expected, .can_concat = !!v_expected, \ +#define V1(v_value, v_expected) \ + { \ + .val = "" v_value "", \ + .exp = v_expected, \ + .can_concat = !!v_expected, \ } -#define V2(v_value, v_expected) \ - { \ - .val = "" v_value "", .exp = v_expected, .can_concat = TRUE, \ - .needs_ascii_separator = TRUE, \ +#define V2(v_value, v_expected) \ + { \ + .val = "" v_value "", \ + .exp = v_expected, \ + .can_concat = TRUE, \ + .needs_ascii_separator = TRUE, \ } const UnescapeTestData data_full[] = { V1("", ""), diff --git a/src/core/settings/plugins/ifupdown/nms-ifupdown-plugin.c b/src/core/settings/plugins/ifupdown/nms-ifupdown-plugin.c index 14c82c55..1b03ce2a 100644 --- a/src/core/settings/plugins/ifupdown/nms-ifupdown-plugin.c +++ b/src/core/settings/plugins/ifupdown/nms-ifupdown-plugin.c @@ -330,7 +330,7 @@ load_eni_ifaces(NMSIfupdownPlugin *self) storage = nm_settings_storage_new(NM_SETTINGS_PLUGIN(self), uuid, NULL); sd = g_slice_new(StorageData); - *sd = (StorageData){ + *sd = (StorageData) { .connection = g_steal_pointer(&connection), .storage = g_steal_pointer(&storage), }; diff --git a/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Duplicate_Gateways b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Duplicate_Gateways new file mode 100644 index 00000000..0b081761 --- /dev/null +++ b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Duplicate_Gateways @@ -0,0 +1,17 @@ +[connection] +id=Test Duplicate Gateways +uuid=5e2a7b1e-e4c8-4964-88c4-ca7255471aa1 +type=802-3-ethernet +autoconnect=true +timestamp=6654332 + +[ipv4] +method=manual +address1=192.168.0.5/24;192.168.0.254 +address2=192.0.2.1/16 +gateway=192.168.0.253 + +[ipv6] +method=manual +gateway=fd01::bbbb +address1=fd01::1/64;fd01::aaaa diff --git a/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Bluetooth_DUN b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Bluetooth_DUN new file mode 100644 index 00000000..80de393e --- /dev/null +++ b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Bluetooth_DUN @@ -0,0 +1,24 @@ +[connection] +id=T-Mobile Funkadelic +uuid=76c59c25-c27c-57a4-8357-1409491cea45 +type=bluetooth +autoconnect=false +timestamp=305415219 + +[gsm] +apn=internet2.voicestream.com +password=parliament +username=george.clinton + +[bluetooth] +bdaddr=AA:B9:A1:74:55:44 +type=dun + +[ipv4] +method=auto + +[ipv6] +addr-gen-mode=default +method=auto + +[proxy] diff --git a/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Bridge_Component b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Bridge_Component new file mode 100644 index 00000000..81e1ba80 --- /dev/null +++ b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Bridge_Component @@ -0,0 +1,14 @@ +[connection] +id=Test Write Bridge Component +uuid=7c4e34eb-419f-531c-b6ca-486f51a08d1d +type=ethernet +controller=br0 +port-type=bridge + +[ethernet] +mac-address=99:88:77:66:55:44 +mtu=1300 + +[bridge-port] +path-cost=99 +priority=3 diff --git a/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Bridge_Main b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Bridge_Main new file mode 100644 index 00000000..03182b43 --- /dev/null +++ b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Bridge_Main @@ -0,0 +1,20 @@ +[connection] +id=Test Write Bridge Main +uuid=b23c15e0-815b-5e6e-a5f9-aea49237aa35 +type=bridge +interface-name=br0 + +[ethernet] + +[bridge] + +[ipv4] +address1=1.2.3.4/24 +gateway=1.1.1.1 +method=manual + +[ipv6] +addr-gen-mode=default +method=auto + +[proxy] diff --git a/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Enum b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Enum new file mode 100644 index 00000000..3ebd6657 --- /dev/null +++ b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Enum @@ -0,0 +1,16 @@ +[connection] +id=Test Write Enum Property +uuid=7e4cb57c-33ff-51fc-ae49-4ee414ef0b63 +type=ethernet + +[ethernet] + +[ipv4] +method=auto + +[ipv6] +addr-gen-mode=default +ip6-privacy=2 +method=auto + +[proxy] diff --git a/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Flags b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Flags new file mode 100644 index 00000000..403a3fd2 --- /dev/null +++ b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Flags @@ -0,0 +1,18 @@ +[connection] +id=Test Write Flags Property +uuid=19febe12-db48-5661-94cc-16529548d772 +type=gsm + +[gsm] +apn=myapn +password-flags=6 +username=adfasdfasdf + +[ipv4] +method=auto + +[ipv6] +addr-gen-mode=default +method=auto + +[proxy] diff --git a/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_GSM b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_GSM new file mode 100644 index 00000000..2f6dc26c --- /dev/null +++ b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_GSM @@ -0,0 +1,26 @@ +[connection] +id=T-Mobile Funkadelic 2 +uuid=952d369e-52c7-5686-ad8c-37ca7e47f8b2 +type=gsm +autoconnect=false +timestamp=305415219 + +[gsm] +apn=internet2.voicestream.com +device-id=da812de91eec16620b06cd0ca5cbc7ea25245222 +home-only=true +network-id=254098 +password=parliament2 +pin=123456 +sim-id=89148000000060671234 +sim-operator-id=310260 +username=george.clinton.again + +[ipv4] +method=auto + +[ipv6] +addr-gen-mode=default +method=auto + +[proxy] diff --git a/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Infiniband b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Infiniband new file mode 100644 index 00000000..f72b669e --- /dev/null +++ b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Infiniband @@ -0,0 +1,19 @@ +[connection] +id=Work InfiniBand +uuid=c27325f5-9eff-517a-9d96-d7897785fa5b +type=infiniband +autoconnect=false + +[infiniband] +mac-address=99:88:77:66:55:44:AB:BC:CD:DE:EF:F0:0A:1B:2C:3D:4E:5F:6F:BA +mtu=900 +transport-mode=datagram + +[ipv4] +method=auto + +[ipv6] +addr-gen-mode=default +method=auto + +[proxy] diff --git a/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_TC b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_TC new file mode 100644 index 00000000..496e7bd9 --- /dev/null +++ b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_TC @@ -0,0 +1,21 @@ +[connection] +id=Test TC +uuid=ed1cb963-ff64-5129-99ca-e05ab3195ce4 +type=ethernet + +[ethernet] + +[ipv4] +method=auto + +[ipv6] +addr-gen-mode=default +method=auto + +[proxy] + +[tc] +qdisc.root=handle 1234: fq_codel +qdisc.ffff:fff1=ingress +tfilter.1234:=matchall action drop +tfilter.ffff:=matchall action simple sdata Hello diff --git a/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Wired b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Wired new file mode 100644 index 00000000..69ca9a6d --- /dev/null +++ b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Wired @@ -0,0 +1,36 @@ +[connection] +id=Work Wired +uuid=9342d47a-1bab-5709-9869-c840b2eac501 +type=ethernet +autoconnect=false +timestamp=305419896 + +[ethernet] +mac-address=99:88:77:66:55:44 +mtu=900 + +[ipv4] +address1=192.168.0.5/24 +address2=1.2.3.4/8 +dns=4.2.2.1;4.2.2.2; +gateway=192.168.0.1 +method=manual +route1=10.10.10.2/24,10.10.10.1,3 +route2=1.1.1.1/8,1.2.1.1,1 +route3=2.2.2.2/7 +route4=3.3.3.3/6,0.0.0.0,4 +route4_options=cwnd=10,mtu=1492,src=1.2.3.4,weight=5 + +[ipv6] +addr-gen-mode=default +address1=abcd::beef/64 +address2=dcba::beef/56 +dns=1::cafe;2::cafe; +dns-search=wallaceandgromit.com; +method=manual +route1=1:2:3:4:5:6:7:8/64,8:7:6:5:4:3:2:1,3 +route2=2001::1000/56,2001::1111,1 +route3=4:5:6:7:8:9:0:1/63,::,5 +route4=5:6:7:8:9:0:1:2/62 + +[proxy] diff --git a/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Wired_IP6 b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Wired_IP6 new file mode 100644 index 00000000..cc379ec6 --- /dev/null +++ b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Wired_IP6 @@ -0,0 +1,20 @@ +[connection] +id=Work Wired IP6 +uuid=0bef2d09-50a3-56b9-912a-5dc941284e3e +type=ethernet +autoconnect=false + +[ethernet] + +[ipv4] +method=disabled + +[ipv6] +addr-gen-mode=default +address1=abcd::beef/64 +dns=1::cafe; +dns-search=wallaceandgromit.com; +gateway=dcba::beef +method=manual + +[proxy] diff --git a/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Wireless b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Wireless new file mode 100644 index 00000000..2fc15098 --- /dev/null +++ b/src/core/settings/plugins/keyfile/tests/keyfiles/Test_Write_Wireless @@ -0,0 +1,20 @@ +[connection] +id=Work Wireless +uuid=e9b337d3-6aa0-552a-822c-4b71c8ddec2e +type=wifi +autoconnect=false +timestamp=305415219 + +[wifi] +bssid=AA:B9:A1:74:55:44 +mtu=1000 +ssid=1337 + +[ipv4] +method=auto + +[ipv6] +addr-gen-mode=default +method=auto + +[proxy] 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 f999105a..6b6913c5 100644 --- a/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c +++ b/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c @@ -163,13 +163,48 @@ write_test_connection(NMConnection *connection, char **testfile) } static void -write_test_connection_and_reread(NMConnection *connection, gboolean normalize_connection) +write_test_connection_and_reread(NMConnection *connection, + gboolean normalize_connection, + const char *reference) { gs_free char *testfile = NULL; g_assert(NM_IS_CONNECTION(connection)); write_test_connection(connection, &testfile); + + if (reference) { + gs_free char *data1 = NULL; + gs_free char *data2 = NULL; + gsize len1; + gsize len2; + gs_free_error GError *error = NULL; + gboolean success; + + success = g_file_get_contents(testfile, &data1, &len1, &error); + nmtst_assert_success(success, error); + + if (nm_streq0(g_getenv("NM_TEST_REGENERATE"), "1")) { + success = g_file_set_contents(reference, data1, len1, &error); + nmtst_assert_success(success, error); + } else { + success = g_file_get_contents(reference, &data2, &len2, &error); + nmtst_assert_success(success, error); + + if (len1 != len2 || !nm_streq0(data1, data2)) { + g_error("The content of \"%s\" (%zu) differs from \"%s\" (%zu). Set " + "NM_TEST_REGENERATE=1 to update the files " + "in place\n\n>>>%s<<<\n\n>>>%s<<<\n", + testfile, + len1, + reference, + len2, + data1, + data2); + } + } + } + assert_reread_and_unlink(connection, normalize_connection, testfile); } @@ -369,6 +404,34 @@ test_read_valid_wired_connection(void) } static void +test_read_duplicate_gateways(void) +{ + gs_unref_object NMConnection *connection = NULL; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + + NMTST_EXPECT_NM_WARN( + "*ipv4* ignoring gateway * from \"address*\" keys because the \"gateway\" key is set*"); + NMTST_EXPECT_NM_WARN( + "*ipv6* ignoring gateway * from \"address*\" keys because the \"gateway\" key is set*"); + connection = keyfile_read_connection_from_file(TEST_KEYFILES_DIR "/Test_Duplicate_Gateways"); + g_test_assert_expected_messages(); + + s_ip4 = nm_connection_get_setting_ip4_config(connection); + g_assert(s_ip4); + g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 2); + check_ip_address(s_ip4, 0, "192.168.0.5", 24); + check_ip_address(s_ip4, 1, "192.0.2.1", 16); + g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, "192.168.0.253"); + + s_ip6 = nm_connection_get_setting_ip6_config(connection); + g_assert(s_ip6); + g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip6), ==, 1); + check_ip_address(s_ip6, 0, "fd01::1", 64); + g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip6), ==, "fd01::bbbb"); +} + +static void add_one_ip_address(NMSettingIPConfig *s_ip, const char *addr, guint32 prefix) { NMIPAddress *ip_addr; @@ -408,13 +471,13 @@ add_one_ip_route(NMSettingIPConfig *s_ip, static void test_write_wired_connection(void) { - NMTST_UUID_INIT(uuid); gs_unref_object NMConnection *connection = NULL; NMSettingConnection *s_con; NMSettingWired *s_wired; NMSettingIPConfig *s_ip4; NMSettingIPConfig *s_ip6; NMIPRoute *rt; + const char *uuid = "9342d47a-1bab-5709-9869-c840b2eac501"; const char *mac = "99:88:77:66:55:44"; const char *dns1 = "4.2.2.1"; const char *dns2 = "4.2.2.2"; @@ -529,7 +592,7 @@ test_write_wired_connection(void) /* DNS searches */ nm_setting_ip_config_add_dns_search(s_ip6, "wallaceandgromit.com"); - write_test_connection_and_reread(connection, FALSE); + write_test_connection_and_reread(connection, FALSE, TEST_KEYFILES_DIR "/Test_Write_Wired"); } static void @@ -573,12 +636,12 @@ test_read_ip6_wired_connection(void) static void test_write_ip6_wired_connection(void) { - NMTST_UUID_INIT(uuid); gs_unref_object NMConnection *connection = NULL; NMSettingConnection *s_con; NMSettingWired *s_wired; NMSettingIPConfig *s_ip4; NMSettingIPConfig *s_ip6; + const char *uuid = "0bef2d09-50a3-56b9-912a-5dc941284e3e"; const char *dns = "1::cafe"; const char *address = "abcd::beef"; const char *gw = "dcba::beef"; @@ -634,7 +697,7 @@ test_write_ip6_wired_connection(void) /* DNS searches */ nm_setting_ip_config_add_dns_search(s_ip6, "wallaceandgromit.com"); - write_test_connection_and_reread(connection, FALSE); + write_test_connection_and_reread(connection, FALSE, TEST_KEYFILES_DIR "/Test_Write_Wired_IP6"); } static void @@ -746,12 +809,12 @@ test_read_valid_wireless_connection(void) static void test_write_wireless_connection(void) { - NMTST_UUID_INIT(uuid); gs_unref_object NMConnection *connection = NULL; NMSettingConnection *s_con; NMSettingWireless *s_wireless; NMSettingIPConfig *s_ip4; NMSettingIPConfig *s_ip6; + const char *uuid = "e9b337d3-6aa0-552a-822c-4b71c8ddec2e"; const char *bssid = "aa:b9:a1:74:55:44"; GBytes *ssid; unsigned char tmpssid[] = {0x31, 0x33, 0x33, 0x37}; @@ -809,7 +872,7 @@ test_write_wireless_connection(void) g_object_set(s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL); - write_test_connection_and_reread(connection, FALSE); + write_test_connection_and_reread(connection, FALSE, TEST_KEYFILES_DIR "/Test_Write_Wireless"); } static void @@ -1181,12 +1244,12 @@ test_read_bt_dun_connection(void) static void test_write_bt_dun_connection(void) { - NMTST_UUID_INIT(uuid); gs_unref_object NMConnection *connection = NULL; NMSettingConnection *s_con; NMSettingBluetooth *s_bt; NMSettingIPConfig *s_ip4; NMSettingGsm *s_gsm; + const char *uuid = "76c59c25-c27c-57a4-8357-1409491cea45"; const char *bdaddr = "aa:b9:a1:74:55:44"; guint64 timestamp = 0x12344433L; @@ -1242,7 +1305,9 @@ test_write_bt_dun_connection(void) "parliament", NULL); - write_test_connection_and_reread(connection, TRUE); + write_test_connection_and_reread(connection, + TRUE, + TEST_KEYFILES_DIR "/Test_Write_Bluetooth_DUN"); } static void @@ -1286,12 +1351,12 @@ test_read_gsm_connection(void) static void test_write_gsm_connection(void) { - NMTST_UUID_INIT(uuid); gs_unref_object NMConnection *connection = NULL; NMSettingConnection *s_con; NMSettingIPConfig *s_ip4; NMSettingGsm *s_gsm; guint64 timestamp = 0x12344433L; + const char *uuid = "952d369e-52c7-5686-ad8c-37ca7e47f8b2"; connection = nm_simple_connection_new(); @@ -1345,7 +1410,7 @@ test_write_gsm_connection(void) "310260", NULL); - write_test_connection_and_reread(connection, TRUE); + write_test_connection_and_reread(connection, TRUE, TEST_KEYFILES_DIR "/Test_Write_GSM"); } static void @@ -1830,12 +1895,12 @@ test_read_infiniband_connection(void) static void test_write_infiniband_connection(void) { - NMTST_UUID_INIT(uuid); gs_unref_object NMConnection *connection = NULL; NMSettingConnection *s_con; NMSettingInfiniband *s_ib; NMSettingIPConfig *s_ip4; NMSettingIPConfig *s_ip6; + const char *uuid = "c27325f5-9eff-517a-9d96-d7897785fa5b"; const char *mac = "99:88:77:66:55:44:ab:bc:cd:de:ef:f0:0a:1b:2c:3d:4e:5f:6f:ba"; connection = nm_simple_connection_new(); @@ -1883,7 +1948,7 @@ test_write_infiniband_connection(void) nm_connection_add_setting(connection, NM_SETTING(s_ip6)); g_object_set(s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL); - write_test_connection_and_reread(connection, FALSE); + write_test_connection_and_reread(connection, FALSE, TEST_KEYFILES_DIR "/Test_Write_Infiniband"); } static void @@ -1922,13 +1987,13 @@ test_read_bridge_main(void) static void test_write_bridge_main(void) { - NMTST_UUID_INIT(uuid); gs_unref_object NMConnection *connection = NULL; NMSettingConnection *s_con; NMSettingBridge *s_bridge; NMSettingWired *s_wired; NMSettingIPConfig *s_ip4; NMSettingIPConfig *s_ip6; + const char *uuid = "b23c15e0-815b-5e6e-a5f9-aea49237aa35"; connection = nm_simple_connection_new(); g_assert(connection); @@ -1982,7 +2047,9 @@ test_write_bridge_main(void) nm_connection_add_setting(connection, NM_SETTING(s_ip6)); g_object_set(s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL); - write_test_connection_and_reread(connection, FALSE); + write_test_connection_and_reread(connection, + FALSE, + TEST_KEYFILES_DIR "/Test_Write_Bridge_Main"); } static void @@ -2022,12 +2089,12 @@ test_read_bridge_component(void) static void test_write_bridge_component(void) { - NMTST_UUID_INIT(uuid); gs_unref_object NMConnection *connection = NULL; NMSettingConnection *s_con; NMSettingBridgePort *s_port; NMSettingWired *s_wired; - const char *mac = "99:88:77:66:55:44"; + const char *mac = "99:88:77:66:55:44"; + const char *uuid = "7c4e34eb-419f-531c-b6ca-486f51a08d1d"; connection = nm_simple_connection_new(); g_assert(connection); @@ -2071,7 +2138,9 @@ test_write_bridge_component(void) 99, NULL); - write_test_connection_and_reread(connection, FALSE); + write_test_connection_and_reread(connection, + FALSE, + TEST_KEYFILES_DIR "/Test_Write_Bridge_Component"); } static void @@ -2423,11 +2492,11 @@ test_read_enum_property(void) static void test_write_enum_property(void) { - NMTST_UUID_INIT(uuid); gs_unref_object NMConnection *connection = NULL; NMSettingConnection *s_con; NMSettingWired *s_wired; NMSettingIPConfig *s_ip6; + const char *uuid = "7e4cb57c-33ff-51fc-ae49-4ee414ef0b63"; connection = nm_simple_connection_new(); @@ -2461,7 +2530,7 @@ test_write_enum_property(void) nmtst_connection_normalize(connection); - write_test_connection_and_reread(connection, FALSE); + write_test_connection_and_reread(connection, FALSE, TEST_KEYFILES_DIR "/Test_Write_Enum"); } static void @@ -2482,10 +2551,10 @@ test_read_flags_property(void) static void test_write_flags_property(void) { - NMTST_UUID_INIT(uuid); gs_unref_object NMConnection *connection = NULL; NMSettingConnection *s_con; NMSetting *s_gsm; + const char *uuid = "19febe12-db48-5661-94cc-16529548d772"; connection = nm_simple_connection_new(); @@ -2517,7 +2586,7 @@ test_write_flags_property(void) nmtst_connection_normalize(connection); - write_test_connection_and_reread(connection, FALSE); + write_test_connection_and_reread(connection, FALSE, TEST_KEYFILES_DIR "/Test_Write_Flags"); } /*****************************************************************************/ @@ -2586,9 +2655,11 @@ test_write_tc_config(void) NMTCAction *action; GError *error = NULL; - connection = - nmtst_create_minimal_connection("Test TC", NULL, NM_SETTING_WIRED_SETTING_NAME, NULL); - s_tc = nm_setting_tc_config_new(); + connection = nmtst_create_minimal_connection("Test TC", + "ed1cb963-ff64-5129-99ca-e05ab3195ce4", + NM_SETTING_WIRED_SETTING_NAME, + NULL); + s_tc = nm_setting_tc_config_new(); qdisc1 = nm_tc_qdisc_new("fq_codel", TC_H_ROOT, &error); nmtst_assert_success(qdisc1, error); @@ -2622,7 +2693,7 @@ test_write_tc_config(void) nm_connection_add_setting(connection, s_tc); nmtst_connection_normalize(connection); - write_test_connection_and_reread(connection, FALSE); + write_test_connection_and_reread(connection, FALSE, TEST_KEYFILES_DIR "/Test_Write_TC"); nm_tc_qdisc_unref(qdisc1); nm_tc_qdisc_unref(qdisc2); @@ -2856,6 +2927,8 @@ main(int argc, char **argv) g_test_add_func("/keyfile/test_read_valid_wired_connection", test_read_valid_wired_connection); g_test_add_func("/keyfile/test_write_wired_connection", test_write_wired_connection); + g_test_add_func("/keyfile/test_read_duplicate_gateways", test_read_duplicate_gateways); + g_test_add_func("/keyfile/test_read_ip6_wired_connection", test_read_ip6_wired_connection); g_test_add_func("/keyfile/test_write_ip6_wired_connection", test_write_ip6_wired_connection); diff --git a/src/core/supplicant/nm-supplicant-config.c b/src/core/supplicant/nm-supplicant-config.c index 4433e809..9e066395 100644 --- a/src/core/supplicant/nm-supplicant-config.c +++ b/src/core/supplicant/nm-supplicant-config.c @@ -154,7 +154,7 @@ nm_supplicant_config_add_option_with_type(NMSupplicantConfig *self, } opt = g_slice_new(ConfigOption); - *opt = (ConfigOption){ + *opt = (ConfigOption) { .value = nm_memdup_nul(value, len), .len = len, .type = type, diff --git a/src/core/supplicant/nm-supplicant-interface.c b/src/core/supplicant/nm-supplicant-interface.c index eb7a40a5..d5f56dcd 100644 --- a/src/core/supplicant/nm-supplicant-interface.c +++ b/src/core/supplicant/nm-supplicant-interface.c @@ -714,7 +714,7 @@ _bss_info_properties_changed(NMSupplicantInterface *self, if (v_v) { arr_data = g_variant_get_fixed_array(v_v, &arr_len, 1); if (arr_len == ETH_ALEN && memcmp(arr_data, &nm_ether_addr_zero, ETH_ALEN) != 0 - && memcmp(arr_data, (char[ETH_ALEN]){0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, ETH_ALEN) + && memcmp(arr_data, (char[ETH_ALEN]) {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, ETH_ALEN) != 0) { /* pass */ } else @@ -839,7 +839,7 @@ _bss_info_add(NMSupplicantInterface *self, const char *object_path) } bss_info = g_slice_new(NMSupplicantBssInfo); - *bss_info = (NMSupplicantBssInfo){ + *bss_info = (NMSupplicantBssInfo) { ._self = self, .bss_path = g_steal_pointer(&bss_path), ._init_cancellable = g_cancellable_new(), @@ -953,7 +953,7 @@ _peer_info_properties_changed(NMSupplicantInterface *self, if (v_v) { arr_data = g_variant_get_fixed_array(v_v, &arr_len, 1); if (arr_len == ETH_ALEN && memcmp(arr_data, &nm_ether_addr_zero, ETH_ALEN) != 0 - && memcmp(arr_data, (char[ETH_ALEN]){0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, ETH_ALEN) + && memcmp(arr_data, (char[ETH_ALEN]) {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, ETH_ALEN) != 0) { /* pass */ } else @@ -1037,7 +1037,7 @@ _peer_info_add(NMSupplicantInterface *self, const char *object_path) } peer_info = g_slice_new(NMSupplicantPeerInfo); - *peer_info = (NMSupplicantPeerInfo){ + *peer_info = (NMSupplicantPeerInfo) { ._self = self, .peer_path = g_steal_pointer(&peer_path), ._init_cancellable = g_cancellable_new(), @@ -1831,7 +1831,7 @@ _wps_start(NMSupplicantInterface *self, const char *type, const char *bssid, con } wps_data = g_slice_new(WpsData); - *wps_data = (WpsData){ + *wps_data = (WpsData) { .self = self, .type = g_strdup(type), .bssid = g_strdup(bssid), @@ -2381,7 +2381,7 @@ add_network(NMSupplicantInterface *self) * For that we also have a shutdown_wait_obj so that on exit we still wait * to handle the response. */ add_network_data = g_slice_new(AddNetworkData); - *add_network_data = (AddNetworkData){ + *add_network_data = (AddNetworkData) { .assoc_data = priv->assoc_data, .name_owner = nm_ref_string_ref(priv->name_owner), .object_path = nm_ref_string_ref(priv->object_path), @@ -2534,7 +2534,7 @@ nm_supplicant_interface_assoc(NMSupplicantInterface *self, nm_supplicant_interface_disconnect(self); assoc_data = g_slice_new(AssocData); - *assoc_data = (AssocData){ + *assoc_data = (AssocData) { .self = self, .cfg = g_object_ref(cfg), .callback = callback, @@ -2707,7 +2707,7 @@ nm_supplicant_interface_request_scan(NMSupplicantInterface *se } data = g_slice_new(ScanRequestData); - *data = (ScanRequestData){ + *data = (ScanRequestData) { .self = self, .callback = callback, .user_data = user_data, diff --git a/src/core/supplicant/nm-supplicant-manager.c b/src/core/supplicant/nm-supplicant-manager.c index 3b805693..ea8d0865 100644 --- a/src/core/supplicant/nm-supplicant-manager.c +++ b/src/core/supplicant/nm-supplicant-manager.c @@ -693,7 +693,7 @@ nm_supplicant_manager_create_interface(NMSupplicantManager *self priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE(self); handle = g_slice_new(NMSupplMgrCreateIfaceHandle); - *handle = (NMSupplMgrCreateIfaceHandle){ + *handle = (NMSupplMgrCreateIfaceHandle) { .self = g_object_ref(self), .callback = callback, .callback_user_data = user_data, diff --git a/src/core/tests/config/test-config.c b/src/core/tests/config/test-config.c index 8365fc82..2980cda7 100644 --- a/src/core/tests/config/test-config.c +++ b/src/core/tests/config/test-config.c @@ -965,7 +965,8 @@ _set_values_user_atomic_section_1_set(NMConfig *config, g_key_file_set_string(keyfile, "atomic-prefix-1.section-b", "key1", "user-value1"); g_key_file_set_string(keyfile, "non-atomic-prefix-1.section-a", "nap1-key1", "user-value1"); g_key_file_set_string(keyfile, "non-atomic-prefix-1.section-a", "nap1-key2", "user-value2"); - *out_expected_changes = NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_USER; + *out_expected_changes = + NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_USER | NM_CONFIG_CHANGE_CONFIG_FILES; } static void @@ -976,7 +977,9 @@ _set_values_user_atomic_section_1_check(NMConfig *config, NMConfigData *old_data) { if (is_change_event) - g_assert(changes == (NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_USER)); + g_assert(changes + == (NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_USER + | NM_CONFIG_CHANGE_CONFIG_FILES)); assert_config_value(config_data, "atomic-prefix-1.section-a", "key1", "user-value1"); assert_config_value(config_data, "atomic-prefix-1.section-a", "key2", "user-value2"); assert_config_value(config_data, "atomic-prefix-1.section-b", "key1", "user-value1"); diff --git a/src/core/tests/test-core.c b/src/core/tests/test-core.c index 71a3d878..2ff41f00 100644 --- a/src/core/tests/test-core.c +++ b/src/core/tests/test-core.c @@ -1027,7 +1027,7 @@ test_connection_match_ip6_routes(void) } #define do_test_wildcard_match_eval(str, ...) \ - nm_wildcard_match_check(str, (const char *const[]){__VA_ARGS__}, NM_NARG(__VA_ARGS__)) + nm_wildcard_match_check(str, (const char *const[]) {__VA_ARGS__}, NM_NARG(__VA_ARGS__)) #define do_test_wildcard_match(str, result, ...) \ g_assert(do_test_wildcard_match_eval(str, __VA_ARGS__) == result) @@ -1244,7 +1244,7 @@ _test_match_spec_device(const GSList *specs, const char *match_str) { if (match_str && g_str_has_prefix(match_str, MATCH_S390)) return nm_match_spec_device(specs, - &((const NMMatchSpecDeviceData){ + &((const NMMatchSpecDeviceData) { .s390_subchannels = &match_str[NM_STRLEN(MATCH_S390)], })); if (match_str && g_str_has_prefix(match_str, MATCH_DRIVER)) { @@ -1257,13 +1257,13 @@ _test_match_spec_device(const GSList *specs, const char *match_str) t++; } return nm_match_spec_device(specs, - &((const NMMatchSpecDeviceData){ + &((const NMMatchSpecDeviceData) { .driver = s, .driver_version = t, })); } return nm_match_spec_device(specs, - &((const NMMatchSpecDeviceData){ + &((const NMMatchSpecDeviceData) { .interface_name = match_str, })); } @@ -1789,28 +1789,28 @@ test_nm_utils_strbuf_append(void) } \ G_STMT_END -#define _strbuf_append_c(buf, len, ch) \ - G_STMT_START \ - { \ - char **_buf = (buf); \ - gsize *_len = (len); \ - char _ch = (ch); \ - \ - switch (nmtst_get_rand_uint32() % 4) { \ - case 0: \ - nm_strbuf_append(_buf, _len, "%c", _ch); \ - break; \ - case 1: \ - nm_strbuf_append_str(_buf, _len, ((char[2]){_ch, 0})); \ - break; \ - case 2: \ - nm_strbuf_append_bin(_buf, _len, &_ch, 1); \ - break; \ - case 3: \ - nm_strbuf_append_c(_buf, _len, _ch); \ - break; \ - } \ - } \ +#define _strbuf_append_c(buf, len, ch) \ + G_STMT_START \ + { \ + char **_buf = (buf); \ + gsize *_len = (len); \ + char _ch = (ch); \ + \ + switch (nmtst_get_rand_uint32() % 4) { \ + case 0: \ + nm_strbuf_append(_buf, _len, "%c", _ch); \ + break; \ + case 1: \ + nm_strbuf_append_str(_buf, _len, ((char[2]) {_ch, 0})); \ + break; \ + case 2: \ + nm_strbuf_append_bin(_buf, _len, &_ch, 1); \ + break; \ + case 3: \ + nm_strbuf_append_c(_buf, _len, _ch); \ + break; \ + } \ + } \ G_STMT_END for (buf_len = 0; buf_len < 10; buf_len++) { diff --git a/src/core/tests/test-l3cfg.c b/src/core/tests/test-l3cfg.c index 6b82fe43..6e11ca51 100644 --- a/src/core/tests/test-l3cfg.c +++ b/src/core/tests/test-l3cfg.c @@ -111,7 +111,7 @@ _test_fixture_1_teardown(TestFixture1 *f) g_object_unref(f->platform); nm_dedup_multi_index_unref(f->multiidx); - *f = (TestFixture1){ + *f = (TestFixture1) { .test_idx = 0, }; } @@ -192,11 +192,13 @@ _test_l3cfg_signal_notify(NML3Cfg *l3cfg, nm_assert(NM_IS_L3_CONFIG_DATA(ti->l3cd)); nm_assert(ti->tag); } - } else if (notify_data->notify_type == NM_L3_CONFIG_NOTIFY_TYPE_L3CD_CHANGED) { - g_assert(!notify_data->l3cd_changed.l3cd_old - || NM_IS_L3_CONFIG_DATA(notify_data->l3cd_changed.l3cd_old)); - g_assert(!notify_data->l3cd_changed.l3cd_new - || NM_IS_L3_CONFIG_DATA(notify_data->l3cd_changed.l3cd_new)); + } else if (NM_IN_SET(notify_data->notify_type, + NM_L3_CONFIG_NOTIFY_TYPE_PRE_COMMIT, + NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT)) { + g_assert(!notify_data->commit.l3cd_old + || NM_IS_L3_CONFIG_DATA(notify_data->commit.l3cd_old)); + g_assert(!notify_data->commit.l3cd_new + || NM_IS_L3_CONFIG_DATA(notify_data->commit.l3cd_new)); return; } diff --git a/src/core/vpn/nm-vpn-connection.c b/src/core/vpn/nm-vpn-connection.c index c14682b8..d0607160 100644 --- a/src/core/vpn/nm-vpn-connection.c +++ b/src/core/vpn/nm-vpn-connection.c @@ -1206,6 +1206,7 @@ _parent_device_l3cd_add_gateway_route(NML3ConfigData *l3cd, r = nm_platform_ip_route_get(platform, addr_family, vpn_gw, + 0, ifindex, (NMPObject **) &route_resolved); if (r >= 0) { @@ -1238,7 +1239,7 @@ _parent_device_l3cd_add_gateway_route(NML3ConfigData *l3cd, return FALSE; if (IS_IPv4) { - route.r4 = (NMPlatformIP4Route){ + route.r4 = (NMPlatformIP4Route) { .ifindex = ifindex, .network = vpn_gw->addr4, .plen = 32, @@ -1248,7 +1249,7 @@ _parent_device_l3cd_add_gateway_route(NML3ConfigData *l3cd, .table_any = TRUE, }; } else { - route.r6 = (NMPlatformIP6Route){ + route.r6 = (NMPlatformIP6Route) { .ifindex = ifindex, .network = vpn_gw->addr6, .plen = 128, @@ -1267,7 +1268,7 @@ _parent_device_l3cd_add_gateway_route(NML3ConfigData *l3cd, * the parent device's gateway would get routed through the VPN and fail. */ if (IS_IPv4) { - route.r4 = (NMPlatformIP4Route){ + route.r4 = (NMPlatformIP4Route) { .network = parent_gw.addr4, .plen = 32, .rt_source = NM_IP_CONFIG_SOURCE_VPN, @@ -1275,7 +1276,7 @@ _parent_device_l3cd_add_gateway_route(NML3ConfigData *l3cd, .table_any = TRUE, }; } else { - route.r6 = (NMPlatformIP6Route){ + route.r6 = (NMPlatformIP6Route) { .network = parent_gw.addr6, .plen = 128, .rt_source = NM_IP_CONFIG_SOURCE_VPN, @@ -2006,11 +2007,11 @@ _dbus_signal_ip_config_cb(NMVpnConnection *self, int addr_family, GVariant *dict &priv->ip_data_x[IS_IPv4].gw_internal); if (IS_IPv4) { - address.a4 = (NMPlatformIP4Address){ + address.a4 = (NMPlatformIP4Address) { .plen = 24, }; } else { - address.a6 = (NMPlatformIP6Address){ + address.a6 = (NMPlatformIP6Address) { .plen = 128, }; } @@ -2059,14 +2060,14 @@ _dbus_signal_ip_config_cb(NMVpnConnection *self, int addr_family, GVariant *dict if (IS_IPv4) { if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP4_CONFIG_DNS, "au", &var_iter)) { while (g_variant_iter_next(var_iter, "u", &u32)) - nm_l3_config_data_add_nameserver_detail(l3cd, addr_family, &u32, NULL); + nm_l3_config_data_add_nameserver_addr(l3cd, addr_family, &u32); g_variant_iter_free(var_iter); } } else { if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP6_CONFIG_DNS, "aay", &var_iter)) { while (g_variant_iter_next(var_iter, "@ay", &v)) { if (nm_ip_addr_set_from_variant(AF_INET6, &v_addr, v, NULL)) - nm_l3_config_data_add_nameserver_detail(l3cd, addr_family, &v_addr, NULL); + nm_l3_config_data_add_nameserver_addr(l3cd, addr_family, &v_addr); g_variant_unref(v); } g_variant_iter_free(var_iter); @@ -2212,7 +2213,7 @@ _dbus_signal_ip_config_cb(NMVpnConnection *self, int addr_family, GVariant *dict if (prefix > 128) continue; - route.r6 = (NMPlatformIP6Route){ + route.r6 = (NMPlatformIP6Route) { .plen = prefix, .table_any = TRUE, .metric_any = TRUE, @@ -2258,7 +2259,7 @@ _dbus_signal_ip_config_cb(NMVpnConnection *self, int addr_family, GVariant *dict NMPlatformIPXRoute route; if (IS_IPv4) { - route.r4 = (NMPlatformIP4Route){ + route.r4 = (NMPlatformIP4Route) { .ifindex = ip_ifindex, .rt_source = NM_IP_CONFIG_SOURCE_VPN, .gateway = priv->ip_data_4.gw_internal.addr4, @@ -2267,7 +2268,7 @@ _dbus_signal_ip_config_cb(NMVpnConnection *self, int addr_family, GVariant *dict .mss = mss, }; } else { - route.r6 = (NMPlatformIP6Route){ + route.r6 = (NMPlatformIP6Route) { .ifindex = ip_ifindex, .rt_source = NM_IP_CONFIG_SOURCE_VPN, .gateway = priv->ip_data_6.gw_internal.addr6, |