diff options
author | Thomas Haller <thaller@redhat.com> | 2019-07-29 20:45:58 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2019-07-29 20:45:58 +0200 |
commit | 3b3596bb03b1c48d7c4dd3efeacaa36807858713 (patch) | |
tree | 8ea8d917a15681e2730f64a7624d67e25f08441a | |
parent | ccd4be4014f9f4cfdd0d298ff387ee7558d5f3a5 (diff) | |
parent | 1a9f8a20a24c26732a659645367f9902e329ead5 (diff) | |
download | NetworkManager-3b3596bb03b1c48d7c4dd3efeacaa36807858713.tar.gz |
wireguard: merge branch 'th/wireguard-routing'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/214
-rw-r--r-- | NEWS | 7 | ||||
-rw-r--r-- | clients/common/nm-meta-setting-desc.c | 6 | ||||
-rw-r--r-- | clients/common/settings-docs.h.in | 4 | ||||
-rw-r--r-- | libnm-core/nm-core-internal.h | 7 | ||||
-rw-r--r-- | libnm-core/nm-setting-sriov.c | 2 | ||||
-rw-r--r-- | libnm-core/nm-setting-wireguard.c | 94 | ||||
-rw-r--r-- | libnm-core/nm-setting-wireguard.h | 8 | ||||
-rw-r--r-- | libnm/libnm.ver | 2 | ||||
-rw-r--r-- | src/devices/nm-device-wireguard.c | 467 | ||||
-rw-r--r-- | src/devices/nm-device.c | 69 | ||||
-rw-r--r-- | src/devices/nm-device.h | 13 | ||||
-rw-r--r-- | src/platform/nmp-object.c | 7 | ||||
-rw-r--r-- | src/platform/nmp-object.h | 108 |
13 files changed, 670 insertions, 124 deletions
@@ -26,6 +26,13 @@ USE AT YOUR OWN RISK. NOT RECOMMENDED FOR PRODUCTION USE! * Drop ibft settings plugin. This functionality is now covered by using nm-initrd-generator from initrd to pre-generate in-memory profiles. * Support "suppress_prefixlength" attribute for policy routing rules. + This is what wg-quick uses for the "Improved Rule-based Routing" solution, + and the user can now manually configure such policy routing rules. +* Support "wireguard.ip4-auto-default-route" and "wireguard.ip6-auto-default-route". + This automatically implements the "Improved Rule-based Routing" of wg-quick + to help with routing loops. Note that this is now enabled by default, so + there is a change in behavior if your WireGuard connection profiles had the + default-route (0.0.0.0/0 or ::/0) in allowed-ips. * Rework implementation of settings plugins and how profiles are presisted to disk. * In-memory profiles are now only handled by keyfile plugin and will also be diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index 0260fa828e..c1a5c2a7fe 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -7137,6 +7137,12 @@ static const NMMetaPropertyInfo *const property_infos_WIREGUARD[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_WIREGUARD_MTU, .property_type = &_pt_gobject_mtu, ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_WIREGUARD_IP4_AUTO_DEFAULT_ROUTE, + .property_type = &_pt_gobject_enum, + ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_WIREGUARD_IP6_AUTO_DEFAULT_ROUTE, + .property_type = &_pt_gobject_enum, + ), NULL }; diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in index 8053b01973..789083059c 100644 --- a/clients/common/settings-docs.h.in +++ b/clients/common/settings-docs.h.in @@ -369,7 +369,9 @@ #define DESCRIBE_DOC_NM_SETTING_WIFI_P2P_WPS_METHOD N_("Flags indicating which mode of WPS is to be used. There's little point in changing the default setting as NetworkManager will automatically determine the best method to use.") #define DESCRIBE_DOC_NM_SETTING_WIMAX_MAC_ADDRESS N_("If specified, this connection will only apply to the WiMAX device whose MAC address matches. This property does not change the MAC address of the device (known as MAC spoofing). Deprecated: 1") #define DESCRIBE_DOC_NM_SETTING_WIMAX_NETWORK_NAME N_("Network Service Provider (NSP) name of the WiMAX network this connection should use. Deprecated: 1") -#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_FWMARK N_("The use of fwmark is optional and is by default off. Setting it to 0 disables it. Otherwise it is a 32-bit fwmark for outgoing packets.") +#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_FWMARK N_("The use of fwmark is optional and is by default off. Setting it to 0 disables it. Otherwise it is a 32-bit fwmark for outgoing packets. Note that \"ip4-auto-default-route\" or \"ip6-auto-default-route\" enabled, implies to automatically choose a fwmark.") +#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_IP4_AUTO_DEFAULT_ROUTE N_("Whether to enable special handling of the IPv4 default route. If enabled, the IPv4 default route will be placed to a dedicated routing-table and two policy routing rules will be added. The fwmark number is also used as routing-table for the default-route, and if fwmark is zero, a unused fwmark/table is chosen automatically. This corresponds to what wg-quick does with Table=auto. Leaving this at the default will enable this option automatically if ipv4.never-default is not set and there are any peers that use a default-route as allowed-ips.") +#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_IP6_AUTO_DEFAULT_ROUTE N_("Like ip4-auto-default-route, but for the IPv6 default route.") #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_LISTEN_PORT N_("The listen-port. If listen-port is not specified, the port will be chosen randomly when the interface comes up.") #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple fragments. If zero a default MTU is used. Note that contrary to wg-quick's MTU setting, this does not take into account the current routes at the time of activation.") #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_PEER_ROUTES N_("Whether to automatically add routes for the AllowedIPs ranges of the peers. If TRUE (the default), NetworkManager will automatically add routes in the routing tables according to ipv4.route-table and ipv6.route-table. If FALSE, no such routes are added automatically. In this case, the user may want to configure static routes in ipv4.routes and ipv6.routes, respectively.") diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index d263900d1a..868f731214 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -476,6 +476,13 @@ gboolean _nm_utils_generate_mac_address_mask_parse (const char *value, /*****************************************************************************/ +static inline gpointer +_nm_connection_get_setting (NMConnection *connection, + GType type) +{ + return (gpointer) nm_connection_get_setting (connection, type); +} + NMSettingIPConfig *nm_connection_get_setting_ip_config (NMConnection *connection, int addr_family); diff --git a/libnm-core/nm-setting-sriov.c b/libnm-core/nm-setting-sriov.c index 94583b09fc..90ac44abb8 100644 --- a/libnm-core/nm-setting-sriov.c +++ b/libnm-core/nm-setting-sriov.c @@ -1370,7 +1370,7 @@ nm_setting_sriov_class_init (NMSettingSriovClass *klass) */ obj_properties[PROP_AUTOPROBE_DRIVERS] = g_param_spec_enum (NM_SETTING_SRIOV_AUTOPROBE_DRIVERS, "", "", - nm_ternary_get_type (), + NM_TYPE_TERNARY, NM_TERNARY_DEFAULT, NM_SETTING_PARAM_FUZZY_IGNORE | G_PARAM_READWRITE | diff --git a/libnm-core/nm-setting-wireguard.c b/libnm-core/nm-setting-wireguard.c index 9e67454d0d..07a841f4a7 100644 --- a/libnm-core/nm-setting-wireguard.c +++ b/libnm-core/nm-setting-wireguard.c @@ -907,6 +907,8 @@ typedef struct { NM_GOBJECT_PROPERTIES_DEFINE_BASE ( PROP_FWMARK, + PROP_IP4_AUTO_DEFAULT_ROUTE, + PROP_IP6_AUTO_DEFAULT_ROUTE, PROP_LISTEN_PORT, PROP_MTU, PROP_PEER_ROUTES, @@ -919,6 +921,8 @@ typedef struct { GPtrArray *peers_arr; GHashTable *peers_hash; NMSettingSecretFlags private_key_flags; + NMTernary ip4_auto_default_route; + NMTernary ip6_auto_default_route; guint32 fwmark; guint32 mtu; guint16 listen_port; @@ -929,7 +933,7 @@ typedef struct { /** * NMSettingWireGuard: * - * WireGuard Ethernet Settings + * WireGuard Settings * * Since: 1.16 */ @@ -1070,6 +1074,38 @@ nm_setting_wireguard_get_mtu (NMSettingWireGuard *self) return NM_SETTING_WIREGUARD_GET_PRIVATE (self)->mtu; } +/** + * nm_setting_wireguard_get_ip4_auto_default_route: + * @self: the #NMSettingWireGuard setting. + * + * Returns: the "ip4-auto-default-route" property of the setting. + * + * Since: 1.20 + */ +NMTernary +nm_setting_wireguard_get_ip4_auto_default_route (NMSettingWireGuard *self) +{ + g_return_val_if_fail (NM_IS_SETTING_WIREGUARD (self), NM_TERNARY_DEFAULT); + + return NM_SETTING_WIREGUARD_GET_PRIVATE (self)->ip4_auto_default_route; +} + +/** + * nm_setting_wireguard_get_ip6_auto_default_route: + * @self: the #NMSettingWireGuard setting. + * + * Returns: the "ip6-auto-default-route" property of the setting. + * + * Since: 1.20 + */ +NMTernary +nm_setting_wireguard_get_ip6_auto_default_route (NMSettingWireGuard *self) +{ + g_return_val_if_fail (NM_IS_SETTING_WIREGUARD (self), NM_TERNARY_DEFAULT); + + return NM_SETTING_WIREGUARD_GET_PRIVATE (self)->ip6_auto_default_route; +} + /*****************************************************************************/ static void @@ -2260,6 +2296,12 @@ get_property (GObject *object, guint prop_id, case PROP_FWMARK: g_value_set_uint (value, priv->fwmark); break; + case PROP_IP4_AUTO_DEFAULT_ROUTE: + g_value_set_enum (value, priv->ip4_auto_default_route); + break; + case PROP_IP6_AUTO_DEFAULT_ROUTE: + g_value_set_enum (value, priv->ip6_auto_default_route); + break; case PROP_LISTEN_PORT: g_value_set_uint (value, priv->listen_port); break; @@ -2292,6 +2334,12 @@ set_property (GObject *object, guint prop_id, case PROP_FWMARK: priv->fwmark = g_value_get_uint (value); break; + case PROP_IP4_AUTO_DEFAULT_ROUTE: + priv->ip4_auto_default_route = g_value_get_enum (value); + break; + case PROP_IP6_AUTO_DEFAULT_ROUTE: + priv->ip6_auto_default_route = g_value_get_enum (value); + break; case PROP_LISTEN_PORT: priv->listen_port = g_value_get_uint (value); break; @@ -2334,6 +2382,8 @@ nm_setting_wireguard_init (NMSettingWireGuard *setting) priv->peers_arr = g_ptr_array_new (); priv->peers_hash = g_hash_table_new (nm_pstr_hash, nm_pstr_equal); priv->peer_routes = TRUE; + priv->ip4_auto_default_route = NM_TERNARY_DEFAULT; + priv->ip6_auto_default_route = NM_TERNARY_DEFAULT; } /** @@ -2424,6 +2474,9 @@ nm_setting_wireguard_class_init (NMSettingWireGuardClass *klass) * The use of fwmark is optional and is by default off. Setting it to 0 * disables it. Otherwise it is a 32-bit fwmark for outgoing packets. * + * Note that "ip4-auto-default-route" or "ip6-auto-default-route" enabled, + * implies to automatically choose a fwmark. + * * Since: 1.16 **/ obj_properties[PROP_FWMARK] = @@ -2487,6 +2540,45 @@ nm_setting_wireguard_class_init (NMSettingWireGuardClass *klass) | NM_SETTING_PARAM_INFERRABLE | G_PARAM_STATIC_STRINGS); + /** + * NMSettingWireGuard:ip4-auto-default-route: + * + * Whether to enable special handling of the IPv4 default route. + * If enabled, the IPv4 default route will be placed to a dedicated + * routing-table and two policy routing rules will be added. + * The fwmark number is also used as routing-table for the default-route, + * and if fwmark is zero, a unused fwmark/table is chosen automatically. + * This corresponds to what wg-quick does with Table=auto. + * + * Leaving this at the default will enable this option automatically + * if ipv4.never-default is not set and there are any peers that use + * a default-route as allowed-ips. + * + * Since: 1.20 + **/ + obj_properties[PROP_IP4_AUTO_DEFAULT_ROUTE] = + g_param_spec_enum (NM_SETTING_WIREGUARD_IP4_AUTO_DEFAULT_ROUTE, "", "", + NM_TYPE_TERNARY, + NM_TERNARY_DEFAULT, + NM_SETTING_PARAM_FUZZY_IGNORE | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + + /** + * NMSettingWireGuard:ip6-auto-default-route: + * + * Like ip4-auto-default-route, but for the IPv6 default route. + * + * Since: 1.20 + **/ + obj_properties[PROP_IP6_AUTO_DEFAULT_ROUTE] = + g_param_spec_enum (NM_SETTING_WIREGUARD_IP6_AUTO_DEFAULT_ROUTE, "", "", + NM_TYPE_TERNARY, + NM_TERNARY_DEFAULT, + NM_SETTING_PARAM_FUZZY_IGNORE | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + /* ---dbus--- * property: peers * format: array of 'a{sv}' diff --git a/libnm-core/nm-setting-wireguard.h b/libnm-core/nm-setting-wireguard.h index 017eb1f6d3..1f81422fb1 100644 --- a/libnm-core/nm-setting-wireguard.h +++ b/libnm-core/nm-setting-wireguard.h @@ -138,6 +138,8 @@ int nm_wireguard_peer_cmp (const NMWireGuardPeer *a, #define NM_SETTING_WIREGUARD_MTU "mtu" #define NM_SETTING_WIREGUARD_PEER_ROUTES "peer-routes" +#define NM_SETTING_WIREGUARD_IP4_AUTO_DEFAULT_ROUTE "ip4-auto-default-route" +#define NM_SETTING_WIREGUARD_IP6_AUTO_DEFAULT_ROUTE "ip6-auto-default-route" #define NM_WIREGUARD_PEER_ATTR_ALLOWED_IPS "allowed-ips" #define NM_WIREGUARD_PEER_ATTR_ENDPOINT "endpoint" @@ -206,6 +208,12 @@ gboolean nm_setting_wireguard_get_peer_routes (NMSettingWireGuard *self); NM_AVAILABLE_IN_1_16 guint32 nm_setting_wireguard_get_mtu (NMSettingWireGuard *self); +NM_AVAILABLE_IN_1_20 +NMTernary nm_setting_wireguard_get_ip4_auto_default_route (NMSettingWireGuard *self); + +NM_AVAILABLE_IN_1_20 +NMTernary nm_setting_wireguard_get_ip6_auto_default_route (NMSettingWireGuard *self); + /*****************************************************************************/ G_END_DECLS diff --git a/libnm/libnm.ver b/libnm/libnm.ver index fb5c06b6e6..51e0d87241 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1624,5 +1624,7 @@ global: nm_setting_ovs_dpdk_get_devargs; nm_setting_ovs_dpdk_get_type; nm_setting_ovs_dpdk_new; + nm_setting_wireguard_get_ip4_auto_default_route; + nm_setting_wireguard_get_ip6_auto_default_route; nm_settings_add_connection2_flags_get_type; } libnm_1_18_0; diff --git a/src/devices/nm-device-wireguard.c b/src/devices/nm-device-wireguard.c index 169775146c..d36573cf25 100644 --- a/src/devices/nm-device-wireguard.c +++ b/src/devices/nm-device-wireguard.c @@ -21,12 +21,16 @@ #include "nm-device-wireguard.h" +#include <linux/rtnetlink.h> +#include <linux/fib_rules.h> + #include "nm-setting-wireguard.h" #include "nm-core-internal.h" #include "nm-glib-aux/nm-secret-utils.h" #include "nm-device-private.h" #include "platform/nm-platform.h" #include "platform/nmp-object.h" +#include "platform/nmp-rules-manager.h" #include "nm-device-factory.h" #include "nm-active-connection.h" #include "nm-act-request.h" @@ -134,10 +138,21 @@ typedef struct { GHashTable *peers; gint64 resolve_next_try_at; - guint resolve_next_try_id; - gint64 link_config_last_at; + + guint resolve_next_try_id; guint link_config_delayed_id; + + guint32 auto_default_route_fwmark; + + guint32 auto_default_route_priority; + + bool auto_default_route_enabled_4:1; + bool auto_default_route_enabled_6:1; + bool auto_default_route_initialized:1; + bool auto_default_route_refresh:1; + bool auto_default_route_priority_initialized:1; + } NMDeviceWireGuardPrivate; struct _NMDeviceWireGuard { @@ -177,6 +192,394 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_link_config_mode_to_string, LinkConfigMode, /*****************************************************************************/ +static void +_auto_default_route_get_enabled (NMSettingWireGuard *s_wg, + NMConnection *connection, + gboolean *out_enabled_v4, + gboolean *out_enabled_v6) +{ + NMTernary enabled_v4; + NMTernary enabled_v6; + + enabled_v4 = nm_setting_wireguard_get_ip4_auto_default_route (s_wg); + enabled_v6 = nm_setting_wireguard_get_ip6_auto_default_route (s_wg); + + if (enabled_v4 == NM_TERNARY_DEFAULT) { + if (nm_setting_ip_config_get_never_default (nm_connection_get_setting_ip_config (connection, AF_INET))) + enabled_v4 = FALSE; + } + if (enabled_v6 == NM_TERNARY_DEFAULT) { + if (nm_setting_ip_config_get_never_default (nm_connection_get_setting_ip_config (connection, AF_INET6))) + enabled_v6 = FALSE; + } + + if ( enabled_v4 == NM_TERNARY_DEFAULT + || enabled_v6 == NM_TERNARY_DEFAULT) { + guint i, n_peers; + + n_peers = nm_setting_wireguard_get_peers_len (s_wg); + for (i = 0; i < n_peers; i++) { + NMWireGuardPeer *peer = nm_setting_wireguard_get_peer (s_wg, i); + guint n_aips; + guint j; + + n_aips = nm_wireguard_peer_get_allowed_ips_len (peer); + for (j = 0; j < n_aips; j++) { + const char *aip; + gboolean valid; + int prefix; + int addr_family; + + aip = nm_wireguard_peer_get_allowed_ip (peer, j, &valid); + if (!valid) + continue; + if (!nm_utils_parse_inaddr_prefix_bin (AF_UNSPEC, + aip, + &addr_family, + NULL, + &prefix)) + continue; + if (prefix != 0) + continue; + + if (addr_family == AF_INET) { + if (enabled_v4 == NM_TERNARY_DEFAULT) { + enabled_v4 = TRUE; + if (enabled_v6 != NM_TERNARY_DEFAULT) + goto done; + } + } else { + if (enabled_v6 == NM_TERNARY_DEFAULT) { + enabled_v6 = TRUE; + if (enabled_v4 != NM_TERNARY_DEFAULT) + goto done; + } + } + } + } +done: + ; + } + + *out_enabled_v4 = (enabled_v4 == TRUE); + *out_enabled_v6 = (enabled_v6 == TRUE); +} + +static guint32 +_auto_default_route_find_unused_table (NMPlatform *platform) +{ + guint32 table; + int is_ipv4; + + for (table = 51820; TRUE; table++) { + const NMDedupMultiHeadEntry *head_entry; + const guint32 table_coerced = nm_platform_route_table_coerce (table); + NMDedupMultiIter iter; + const NMPObject *plobj; + + /* find a table/fwmark that is not yet in use. */ + + for (is_ipv4 = 0; is_ipv4 < 2; is_ipv4++) { + head_entry = nm_platform_lookup_object (platform, + is_ipv4 + ? NMP_OBJECT_TYPE_IP4_ROUTE + : NMP_OBJECT_TYPE_IP6_ROUTE, + -1); + nmp_cache_iter_for_each (&iter, head_entry, &plobj) { + if (NMP_OBJECT_CAST_IP_ROUTE (plobj)->table_coerced == table_coerced) + goto try_next_table; + } + } + + head_entry = nm_platform_lookup_object_by_addr_family (platform, + NMP_OBJECT_TYPE_ROUTING_RULE, + AF_UNSPEC); + nmp_cache_iter_for_each (&iter, head_entry, &plobj) { + const NMPlatformRoutingRule *rr = NMP_OBJECT_CAST_ROUTING_RULE (plobj); + + if (rr->fwmark == table) + goto try_next_table; + } + + head_entry = nm_platform_lookup_obj_type (platform, NMP_OBJECT_TYPE_LINK); + nmp_cache_iter_for_each (&iter, head_entry, &plobj) { + const NMPObject *lnk_wg; + + if (plobj->link.type != NM_LINK_TYPE_WIREGUARD) + continue; + + lnk_wg = plobj->_link.netlink.lnk; + + if (!lnk_wg) + continue; + + if (NMP_OBJECT_GET_TYPE (lnk_wg) != NMP_OBJECT_TYPE_LNK_WIREGUARD) + continue; + + if (NMP_OBJECT_CAST_LNK_WIREGUARD (lnk_wg)->fwmark == table) + goto try_next_table; + } + + return table; +try_next_table: + ; + } +} + +#define PRIO_WIDTH ((guint32) 2) + +static gboolean +_auto_default_route_find_priority_exists (const NMDedupMultiHeadEntry *head_entry, + guint32 priority) +{ + NMDedupMultiIter iter; + const NMPObject *plobj; + + nmp_cache_iter_for_each (&iter, head_entry, &plobj) { + const NMPlatformRoutingRule *rr = NMP_OBJECT_CAST_ROUTING_RULE (plobj); + + /* we don't differenciate between IPv4 vs. IPv6. There should be no + * conflicting rules with the same priority. */ + if ( rr->priority >= priority + && rr->priority < priority + PRIO_WIDTH) + return TRUE; + } + + return FALSE; +} + +static guint32 +_auto_default_route_find_priority (NMPlatform *platform, + const char *uuid) +{ + const NMDedupMultiHeadEntry *head_entry; + guint64 rnd_seed; + const guint32 PRIME_NUMBER = 1111567573u; + const guint32 RANGE_TOP = ((32766u - 2u * PRIO_WIDTH) / PRIO_WIDTH); + const guint32 RANGE_LEN1 = 200u; + const guint32 RANGE_LEN2 = (RANGE_TOP - 100u) - RANGE_LEN1; + guint32 range_len; + guint32 range_top; + guint32 prio_candidate = 0; + guint32 i_step; + guint32 i; + + /* For the auto-default-route policy routing rule we add 4 rules (2 Ipv4 and 2 IPv6). + * Hence, we choose a priority for the first (of the two rules) and the second + * rule gets priority + 1. + * We want a priority that is + * - unused so far. + * - smaller than 32766u (which is the priority of the default rules for IPv4 and IPv6) + * - stable for each connection but different between connections (we hash the UUID + * as a "random" seed) + * - if possible, close to 32766u (RANGE_LEN1). Only otherwise fallback to the entire + * range (RANGE_LEN2). + */ + + rnd_seed = c_siphash_hash ((const guint8 [16]) { 0xb9, 0x39, 0x8e, 0xed, 0x15, 0xb3, 0xd1, 0xc4, 0x5f, 0x45, 0x00, 0x4f, 0xec, 0xc2, 0x2b, 0x7e }, + (const guint8 *) uuid, + uuid ? strlen (uuid) + 1u : 0u); + + head_entry = nm_platform_lookup_object_by_addr_family (platform, + NMP_OBJECT_TYPE_ROUTING_RULE, + AF_UNSPEC); + + range_len = RANGE_LEN1; + range_top = RANGE_TOP; + +again: + i_step = ((guint32) rnd_seed) % range_len; + for (i = 0; i < range_len; i++) { + + /* we sample the range in a stable, but somewhat arbitrary order to + * find an unused priority. */ + i_step = (i_step + PRIME_NUMBER) % range_len; + + nm_assert (i_step < range_top); + + prio_candidate = (range_top - i_step) * PRIO_WIDTH; + + nm_assert (prio_candidate < 32766u); + + if (!_auto_default_route_find_priority_exists (head_entry, prio_candidate)) + return prio_candidate; + } + + if (range_len == RANGE_LEN1) { + /* within the narrow range close to RANGE_TOP we couldn't find any unused + * priority. Retry with the entire range... */ + range_len = RANGE_LEN2; + range_top -= RANGE_LEN1; + goto again; + } + + /* Couldn't find an unused one? Very odd, this really should not happen unless there + * are thousands of rules already. Just pick the last one we sampled. */ + return prio_candidate; +} + +static void +_auto_default_route_init (NMDeviceWireGuard *self) +{ + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); + NMConnection *connection; + NMSettingWireGuard *s_wg; + gboolean enabled_v4; + gboolean enabled_v6; + gboolean refreshing_only; + guint32 old_fwmark; + char sbuf1[100]; + + if (G_LIKELY ( priv->auto_default_route_initialized + && !priv->auto_default_route_refresh)) + return; + + refreshing_only = priv->auto_default_route_initialized + && priv->auto_default_route_refresh; + priv->auto_default_route_refresh = FALSE; + + connection = nm_device_get_applied_connection (NM_DEVICE (self)); + + s_wg = _nm_connection_get_setting (connection, NM_TYPE_SETTING_WIREGUARD); + + old_fwmark = priv->auto_default_route_fwmark; + + priv->auto_default_route_fwmark = nm_setting_wireguard_get_fwmark (s_wg); + + _auto_default_route_get_enabled (s_wg, + connection, + &enabled_v4, + &enabled_v6); + priv->auto_default_route_enabled_4 = enabled_v4; + priv->auto_default_route_enabled_6 = enabled_v6; + priv->auto_default_route_initialized = TRUE; + + if ( ( priv->auto_default_route_enabled_4 + || priv->auto_default_route_enabled_6) + && priv->auto_default_route_fwmark == 0u) { + if (refreshing_only) + priv->auto_default_route_fwmark = old_fwmark; + else + priv->auto_default_route_fwmark = _auto_default_route_find_unused_table (nm_device_get_platform (NM_DEVICE (self))); + } + + _LOGT (LOGD_DEVICE, + "auto-default-route is %s for IPv4 and %s for IPv6%s", + priv->auto_default_route_enabled_4 ? "enabled" : "disabled", + priv->auto_default_route_enabled_6 ? "enabled" : "disabled", + priv->auto_default_route_enabled_4 || priv->auto_default_route_enabled_6 + ? nm_sprintf_buf (sbuf1, " (fwmark 0x%x)", priv->auto_default_route_fwmark) + : ""); +} + +static GPtrArray * +get_extra_rules (NMDevice *device) +{ + NMDeviceWireGuard *self = NM_DEVICE_WIREGUARD (device); + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); + gs_unref_ptrarray GPtrArray *extra_rules = NULL; + guint32 priority = 0; + int is_ipv4; + NMConnection *connection; + + _auto_default_route_init (self); + + connection = nm_device_get_applied_connection (device); + if (!connection) + return NULL; + + for (is_ipv4 = 0; is_ipv4 < 2; is_ipv4++) { + NMSettingIPConfig *s_ip; + int addr_family = is_ipv4 ? AF_INET : AF_INET6; + guint32 table_main; + guint32 fwmark; + + if (is_ipv4) { + if (!priv->auto_default_route_enabled_4) + continue; + } else { + if (!priv->auto_default_route_enabled_6) + continue; + } + + if (!extra_rules) { + if (priv->auto_default_route_priority_initialized) + priority = priv->auto_default_route_priority; + else { + priority = _auto_default_route_find_priority (nm_device_get_platform (device), + nm_connection_get_uuid (connection)); + priv->auto_default_route_priority = priority; + priv->auto_default_route_priority_initialized = TRUE; + } + extra_rules = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref); + } + + s_ip = nm_connection_get_setting_ip_config (connection, addr_family); + table_main = nm_setting_ip_config_get_route_table (s_ip); + if (table_main == 0) + table_main = RT_TABLE_MAIN; + + fwmark = priv->auto_default_route_fwmark; + + G_STATIC_ASSERT_EXPR (PRIO_WIDTH == 2); + + g_ptr_array_add (extra_rules, + nmp_object_new (NMP_OBJECT_TYPE_ROUTING_RULE, + &((const NMPlatformRoutingRule) { + .priority = priority, + .addr_family = addr_family, + .action = FR_ACT_TO_TBL, + .table = table_main, + .suppress_prefixlen_inverse = ~((guint32) 0u), + }))); + + g_ptr_array_add (extra_rules, + nmp_object_new (NMP_OBJECT_TYPE_ROUTING_RULE, + &((const NMPlatformRoutingRule) { + .priority = priority + 1u, + .addr_family = addr_family, + .action = FR_ACT_TO_TBL, + .table = fwmark, + .flags = FIB_RULE_INVERT, + .fwmark = fwmark, + .fwmask = 0xFFFFFFFFu, + }))); + } + + return g_steal_pointer (&extra_rules); +} + +static guint32 +coerce_route_table (NMDevice *device, + int addr_family, + guint32 route_table, + gboolean is_user_config) +{ + NMDeviceWireGuard *self = NM_DEVICE_WIREGUARD (device); + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); + gboolean auto_default_route_enabled; + + if (route_table != 0u) + return route_table; + + _auto_default_route_init (self); + + auto_default_route_enabled = (addr_family == AF_INET) + ? priv->auto_default_route_enabled_4 + : priv->auto_default_route_enabled_6; + + if (auto_default_route_enabled) { + /* we need to enable full-sync mode of all routing tables. */ + _LOGT (LOGD_DEVICE, "coerce ipv%c.route-table setting to \"main\" (table 254) as we enable auto-default-route handling", + nm_utils_addr_family_to_char (addr_family)); + return RT_TABLE_MAIN; + } + + return 0; +} + +/*****************************************************************************/ + static gboolean _peer_data_equal (gconstpointer ptr_a, gconstpointer ptr_b) { @@ -1084,6 +1487,8 @@ link_config (NMDeviceWireGuard *self, _LOGT (LOGD_DEVICE, "wireguard link config (%s, %s)...", reason, _link_config_mode_to_string (config_mode)); + _auto_default_route_init (self); + if (!priv->dns_manager) { priv->dns_manager = g_object_ref (nm_dns_manager_get ()); g_signal_connect (priv->dns_manager, NM_DNS_MANAGER_CONFIG_CHANGED, G_CALLBACK (_dns_config_changed), self); @@ -1130,7 +1535,7 @@ link_config (NMDeviceWireGuard *self, wg_lnk.listen_port = nm_setting_wireguard_get_listen_port (s_wg); wg_change_flags |= NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_LISTEN_PORT; - wg_lnk.fwmark = nm_setting_wireguard_get_fwmark (s_wg); + wg_lnk.fwmark = priv->auto_default_route_fwmark; wg_change_flags |= NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_FWMARK; if (nm_utils_base64secret_decode (nm_setting_wireguard_get_private_key (s_wg), @@ -1256,6 +1661,7 @@ static NMIPConfig * _get_dev2_ip_config (NMDeviceWireGuard *self, int addr_family) { + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); gs_unref_object NMIPConfig *ip_config = NULL; NMConnection *connection; NMSettingWireGuard *s_wg; @@ -1264,6 +1670,9 @@ _get_dev2_ip_config (NMDeviceWireGuard *self, int ip_ifindex; guint32 route_metric; guint32 route_table_coerced; + gboolean auto_default_route_enabled; + + _auto_default_route_init (self); connection = nm_device_get_applied_connection (NM_DEVICE (self)); @@ -1303,6 +1712,10 @@ _get_dev2_ip_config (NMDeviceWireGuard *self, route_table_coerced = nm_platform_route_table_coerce (nm_device_get_route_table (NM_DEVICE (self), addr_family)); + auto_default_route_enabled = (addr_family == AF_INET) + ? priv->auto_default_route_enabled_4 + : priv->auto_default_route_enabled_6; + n_peers = nm_setting_wireguard_get_peers_len (s_wg); for (i = 0; i < n_peers; i++) { NMWireGuardPeer *peer = nm_setting_wireguard_get_peer (s_wg, i); @@ -1316,6 +1729,7 @@ _get_dev2_ip_config (NMDeviceWireGuard *self, const char *aip; gboolean valid; int prefix; + guint32 rtable_coerced; aip = nm_wireguard_peer_get_allowed_ip (peer, j, &valid); @@ -1335,13 +1749,24 @@ _get_dev2_ip_config (NMDeviceWireGuard *self, nm_utils_ipx_address_clear_host_address (addr_family, &addrbin, NULL, prefix); + rtable_coerced = route_table_coerced; + + if ( prefix == 0 + && auto_default_route_enabled) { + /* In auto-default-route mode, we place the default route in a table that + * has the same number as the fwmark. wg-quick does that too. If you don't + * like that, configure the rules and the default-route explicitly in the + * connection profile. */ + rtable_coerced = nm_platform_route_table_coerce (priv->auto_default_route_fwmark); + } + if (addr_family == AF_INET) { rt.r4 = (NMPlatformIP4Route) { .network = addrbin.addr4, .plen = prefix, .ifindex = ip_ifindex, .rt_source = NM_IP_CONFIG_SOURCE_USER, - .table_coerced = route_table_coerced, + .table_coerced = rtable_coerced, .metric = route_metric, }; } else { @@ -1350,7 +1775,7 @@ _get_dev2_ip_config (NMDeviceWireGuard *self, .plen = prefix, .ifindex = ip_ifindex, .rt_source = NM_IP_CONFIG_SOURCE_USER, - .table_coerced = route_table_coerced, + .table_coerced = rtable_coerced, .metric = route_metric, }; } @@ -1406,20 +1831,28 @@ get_configured_mtu (NMDevice *device, NMDeviceMtuSource *out_source) } static void +_device_cleanup (NMDeviceWireGuard *self) +{ + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); + + _peers_remove_all (priv); + + _secrets_cancel (self); + + priv->auto_default_route_initialized = FALSE; + priv->auto_default_route_priority_initialized = FALSE; +} + +static void device_state_changed (NMDevice *device, NMDeviceState new_state, NMDeviceState old_state, NMDeviceStateReason reason) { - NMDeviceWireGuardPrivate *priv; - if (new_state <= NM_DEVICE_STATE_ACTIVATED) return; - priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (device); - - _peers_remove_all (priv); - _secrets_cancel (NM_DEVICE_WIREGUARD (device)); + _device_cleanup (NM_DEVICE_WIREGUARD (device)); } /*****************************************************************************/ @@ -1440,6 +1873,8 @@ can_reapply_change (NMDevice *device, NM_SETTING_WIREGUARD_SETTING_NAME, error, NM_SETTING_WIREGUARD_FWMARK, + NM_SETTING_WIREGUARD_IP4_AUTO_DEFAULT_ROUTE, + NM_SETTING_WIREGUARD_IP6_AUTO_DEFAULT_ROUTE, NM_SETTING_WIREGUARD_LISTEN_PORT, NM_SETTING_WIREGUARD_PEERS, NM_SETTING_WIREGUARD_PEER_ROUTES, @@ -1461,9 +1896,12 @@ reapply_connection (NMDevice *device, NMConnection *con_new) { NMDeviceWireGuard *self = NM_DEVICE_WIREGUARD (device); + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); gs_unref_object NMIPConfig *ip4_config = NULL; gs_unref_object NMIPConfig *ip6_config = NULL; + priv->auto_default_route_refresh = TRUE; + ip4_config = _get_dev2_ip_config (self, AF_INET); ip6_config = _get_dev2_ip_config (self, AF_INET6); @@ -1567,11 +2005,8 @@ static void dispose (GObject *object) { NMDeviceWireGuard *self = NM_DEVICE_WIREGUARD (object); - NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE (self); - _secrets_cancel (self); - - _peers_remove_all (priv); + _device_cleanup (self); G_OBJECT_CLASS (nm_device_wireguard_parent_class)->dispose (object); } @@ -1633,6 +2068,8 @@ nm_device_wireguard_class_init (NMDeviceWireGuardClass *klass) device_class->can_reapply_change = can_reapply_change; device_class->reapply_connection = reapply_connection; device_class->get_configured_mtu = get_configured_mtu; + device_class->get_extra_rules = get_extra_rules; + device_class->coerce_route_table = coerce_route_table; obj_properties[PROP_PUBLIC_KEY] = g_param_spec_variant (NM_DEVICE_WIREGUARD_PUBLIC_KEY, diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index da34602427..feb5110d30 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -2265,9 +2265,11 @@ _get_route_table (NMDevice *self, int addr_family) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDeviceClass *klass; NMConnection *connection; NMSettingIPConfig *s_ip; guint32 route_table = 0; + gboolean is_user_config = TRUE; nm_assert_addr_family (addr_family); @@ -2288,16 +2290,26 @@ _get_route_table (NMDevice *self, route_table = nm_setting_ip_config_get_route_table (s_ip); } if (route_table == 0u) { - route_table = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - addr_family == AF_INET - ? NM_CON_DEFAULT ("ipv4.route-table") - : NM_CON_DEFAULT ("ipv6.route-table"), - self, - 0, - G_MAXUINT32, - 0); + gint64 v; + + v = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + addr_family == AF_INET + ? NM_CON_DEFAULT ("ipv4.route-table") + : NM_CON_DEFAULT ("ipv6.route-table"), + self, + 0, + G_MAXUINT32, + -1); + if (v != -1) { + route_table = v; + is_user_config = FALSE; + } } + klass = NM_DEVICE_GET_CLASS (self); + if (klass->coerce_route_table) + route_table = klass->coerce_route_table (self, addr_family, route_table, is_user_config); + if (addr_family == AF_INET) { priv->v4_route_table_initialized = TRUE; priv->v4_route_table = route_table; @@ -6587,11 +6599,15 @@ _routing_rules_sync (NMDevice *self, { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMPRulesManager *rules_manager = nm_netns_get_rules_manager (nm_device_get_netns (self)); + NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self); gboolean untrack_only_dirty = FALSE; gboolean keep_deleted_rules; - gpointer user_tag; + gpointer user_tag_1; + gpointer user_tag_2; - user_tag = priv; + /* take two arbitrary user-tag pointers that belong to @self. */ + user_tag_1 = &priv->v4_route_table; + user_tag_2 = &priv->v6_route_table; if (set_mode == NM_TERNARY_TRUE) { NMConnection *applied_connection; @@ -6600,7 +6616,9 @@ _routing_rules_sync (NMDevice *self, int is_ipv4; untrack_only_dirty = TRUE; - nmp_rules_manager_set_dirty (rules_manager, user_tag); + nmp_rules_manager_set_dirty (rules_manager, user_tag_1); + if (klass->get_extra_rules) + nmp_rules_manager_set_dirty (rules_manager, user_tag_2); applied_connection = nm_device_get_applied_connection (self); @@ -6625,13 +6643,30 @@ _routing_rules_sync (NMDevice *self, nmp_rules_manager_track (rules_manager, &plrule, 10, - user_tag, + user_tag_1, NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG); } } + + if (klass->get_extra_rules) { + gs_unref_ptrarray GPtrArray *extra_rules = NULL; + + extra_rules = klass->get_extra_rules (self); + if (extra_rules) { + for (i = 0; i < extra_rules->len; i++) { + nmp_rules_manager_track (rules_manager, + NMP_OBJECT_CAST_ROUTING_RULE (extra_rules->pdata[i]), + 10, + user_tag_2, + NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG); + } + } + } } - nmp_rules_manager_untrack_all (rules_manager, user_tag, !untrack_only_dirty); + nmp_rules_manager_untrack_all (rules_manager, user_tag_1, !untrack_only_dirty); + if (klass->get_extra_rules) + nmp_rules_manager_untrack_all (rules_manager, user_tag_2, !untrack_only_dirty); keep_deleted_rules = FALSE; if (set_mode == NM_TERNARY_DEFAULT) { @@ -11532,6 +11567,12 @@ check_and_reapply_connection (NMDevice *self, /************************************************************************** * Reapply changes + * + * Note that reapply_connection() is called as very first. This is for example + * important for NMDeviceWireGuard, which implements coerce_route_table() + * and get_extra_rules(). + * That is because NMDeviceWireGuard caches settings, so during reapply that + * cache must be updated *first*. *************************************************************************/ klass->reapply_connection (self, con_old, con_new); @@ -11550,6 +11591,8 @@ check_and_reapply_connection (NMDevice *self, nm_device_reactivate_ip4_config (self, s_ip4_old, s_ip4_new); nm_device_reactivate_ip6_config (self, s_ip6_old, s_ip6_new); + _routing_rules_sync (self, NM_TERNARY_TRUE); + reactivate_proxy_config (self); return TRUE; diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index 2108b134e9..ae6aab392a 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -320,6 +320,12 @@ typedef struct _NMDeviceClass { void (* set_enabled) (NMDevice *self, gboolean enabled); + /* let the subclass return additional NMPlatformRoutingRule (in form of NMPObject + * pointers) that shall be added to the rules provided by this device. + * The returned GPtrArray will be g_ptr_array_unref()'ed. The subclass may or + * may not keep an additional reference and return this array again and again. */ + GPtrArray *(*get_extra_rules) (NMDevice *self); + /* allow derived classes to override the result of nm_device_autoconnect_allowed(). * If the value changes, the class should call nm_device_emit_recheck_auto_activate(), * which emits NM_DEVICE_RECHECK_AUTO_ACTIVATE signal. */ @@ -331,6 +337,13 @@ typedef struct _NMDeviceClass { guint32 (*get_configured_mtu) (NMDevice *self, NMDeviceMtuSource *out_source); + /* allow the subclass to overwrite the routing table. This is mainly useful + * to change from partial mode (route-table=0) to full-sync mode (route-table=254). */ + guint32 (*coerce_route_table) (NMDevice *self, + int addr_family, + guint32 route_table, + gboolean is_user_config); + const char *(*get_auto_ip_config_method) (NMDevice *self, int addr_family); /* Checks whether the connection is compatible with the device using diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index fc5cffab2e..5cbf9428f8 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -786,7 +786,7 @@ _nmp_object_new_from_class (const NMPClass *klass) } NMPObject * -nmp_object_new (NMPObjectType obj_type, const NMPlatformObject *plobj) +nmp_object_new (NMPObjectType obj_type, gconstpointer plobj) { const NMPClass *klass = nmp_class_from_type (obj_type); NMPObject *obj; @@ -2146,9 +2146,12 @@ nmp_lookup_init_object_by_addr_family (NMPLookup *lookup, NMPObject *o; nm_assert (lookup); - nm_assert_addr_family (addr_family); nm_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_ROUTING_RULE)); + if (addr_family == AF_UNSPEC) + return nmp_lookup_init_obj_type (lookup, obj_type); + + nm_assert_addr_family (addr_family); o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type); NMP_OBJECT_CAST_ROUTING_RULE (o)->addr_family = addr_family; lookup->cache_id_type = NMP_CACHE_ID_TYPE_OBJECT_BY_ADDR_FAMILY; diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index fc844aaf86..cea5f95810 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -534,101 +534,27 @@ _NMP_OBJECT_TYPE_IS_OBJ_WITH_IFINDEX (NMPObjectType obj_type) _obj ? &NM_CONSTCAST (NMPObject, _obj)->obj_with_ifindex : NULL; \ }) -#define NMP_OBJECT_CAST_LINK(obj) \ +#define _NMP_OBJECT_CAST(obj, field, ...) \ ({ \ typeof (obj) _obj = (obj); \ \ - nm_assert (!_obj || NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_LINK); \ - _obj ? &NM_CONSTCAST (NMPObject, _obj)->link : NULL; \ + nm_assert (!_obj || NM_IN_SET (NMP_OBJECT_GET_TYPE (_obj), __VA_ARGS__)); \ + _obj ? &NM_CONSTCAST (NMPObject, _obj)->field : NULL; \ }) -#define NMP_OBJECT_CAST_IP_ADDRESS(obj) \ - ({ \ - typeof (obj) _obj = (obj); \ - \ - nm_assert (!_obj || NM_IN_SET (NMP_OBJECT_GET_TYPE (_obj), NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS)); \ - _obj ? &NM_CONSTCAST (NMPObject, _obj)->ip_address : NULL; \ - }) - -#define NMP_OBJECT_CAST_IPX_ADDRESS(obj) \ - ({ \ - typeof (obj) _obj = (obj); \ - \ - nm_assert (!_obj || NM_IN_SET (NMP_OBJECT_GET_TYPE (_obj), NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS)); \ - _obj ? &NM_CONSTCAST (NMPObject, _obj)->ipx_address : NULL; \ - }) - -#define NMP_OBJECT_CAST_IP4_ADDRESS(obj) \ - ({ \ - typeof (obj) _obj = (obj); \ - \ - nm_assert (!_obj || NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_IP4_ADDRESS); \ - _obj ? &NM_CONSTCAST (NMPObject, _obj)->ip4_address : NULL; \ - }) - -#define NMP_OBJECT_CAST_IP6_ADDRESS(obj) \ - ({ \ - typeof (obj) _obj = (obj); \ - \ - nm_assert (!_obj || NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_IP6_ADDRESS); \ - _obj ? &NM_CONSTCAST (NMPObject, _obj)->ip6_address : NULL; \ - }) - -#define NMP_OBJECT_CAST_IPX_ROUTE(obj) \ - ({ \ - typeof (obj) _obj = (obj); \ - \ - nm_assert (!_obj || NM_IN_SET (NMP_OBJECT_GET_TYPE (_obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); \ - _obj ? &NM_CONSTCAST (NMPObject, _obj)->ipx_route : NULL; \ - }) - -#define NMP_OBJECT_CAST_IP_ROUTE(obj) \ - ({ \ - typeof (obj) _obj = (obj); \ - \ - nm_assert (!_obj || NM_IN_SET (NMP_OBJECT_GET_TYPE (_obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); \ - _obj ? &NM_CONSTCAST (NMPObject, _obj)->ip_route : NULL; \ - }) - -#define NMP_OBJECT_CAST_IP4_ROUTE(obj) \ - ({ \ - typeof (obj) _obj = (obj); \ - \ - nm_assert (!_obj || NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_IP4_ROUTE); \ - _obj ? &NM_CONSTCAST (NMPObject, _obj)->ip4_route : NULL; \ - }) - -#define NMP_OBJECT_CAST_IP6_ROUTE(obj) \ - ({ \ - typeof (obj) _obj = (obj); \ - \ - nm_assert (!_obj || NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_IP6_ROUTE); \ - _obj ? &NM_CONSTCAST (NMPObject, _obj)->ip6_route : NULL; \ - }) - -#define NMP_OBJECT_CAST_ROUTING_RULE(obj) \ - ({ \ - typeof (obj) _obj = (obj); \ - \ - nm_assert (!_obj || NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_ROUTING_RULE); \ - _obj ? &NM_CONSTCAST (NMPObject, _obj)->routing_rule : NULL; \ - }) - -#define NMP_OBJECT_CAST_QDISC(obj) \ - ({ \ - typeof (obj) _obj = (obj); \ - \ - nm_assert (!_obj || NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_QDISC); \ - _obj ? &NM_CONSTCAST (NMPObject, _obj)->qdisc : NULL; \ - }) - -#define NMP_OBJECT_CAST_TFILTER(obj) \ - ({ \ - typeof (obj) _obj = (obj); \ - \ - nm_assert (!_obj || NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_TFILTER); \ - _obj ? &NM_CONSTCAST (NMPObject, _obj)->tfilter : NULL; \ - }) +#define NMP_OBJECT_CAST_LINK(obj) _NMP_OBJECT_CAST (obj, link, NMP_OBJECT_TYPE_LINK) +#define NMP_OBJECT_CAST_IP_ADDRESS(obj) _NMP_OBJECT_CAST (obj, ip_address, NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS) +#define NMP_OBJECT_CAST_IPX_ADDRESS(obj) _NMP_OBJECT_CAST (obj, ipx_address, NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS) +#define NMP_OBJECT_CAST_IP4_ADDRESS(obj) _NMP_OBJECT_CAST (obj, ip4_address, NMP_OBJECT_TYPE_IP4_ADDRESS) +#define NMP_OBJECT_CAST_IP6_ADDRESS(obj) _NMP_OBJECT_CAST (obj, ip6_address, NMP_OBJECT_TYPE_IP6_ADDRESS) +#define NMP_OBJECT_CAST_IP_ROUTE(obj) _NMP_OBJECT_CAST (obj, ip_route, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE) +#define NMP_OBJECT_CAST_IPX_ROUTE(obj) _NMP_OBJECT_CAST (obj, ipx_route, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE) +#define NMP_OBJECT_CAST_IP4_ROUTE(obj) _NMP_OBJECT_CAST (obj, ip4_route, NMP_OBJECT_TYPE_IP4_ROUTE) +#define NMP_OBJECT_CAST_IP6_ROUTE(obj) _NMP_OBJECT_CAST (obj, ip6_route, NMP_OBJECT_TYPE_IP6_ROUTE) +#define NMP_OBJECT_CAST_ROUTING_RULE(obj) _NMP_OBJECT_CAST (obj, routing_rule, NMP_OBJECT_TYPE_ROUTING_RULE) +#define NMP_OBJECT_CAST_QDISC(obj) _NMP_OBJECT_CAST (obj, qdisc, NMP_OBJECT_TYPE_QDISC) +#define NMP_OBJECT_CAST_TFILTER(obj) _NMP_OBJECT_CAST (obj, tfilter, NMP_OBJECT_TYPE_TFILTER) +#define NMP_OBJECT_CAST_LNK_WIREGUARD(obj) _NMP_OBJECT_CAST (obj, lnk_wireguard, NMP_OBJECT_TYPE_LNK_WIREGUARD) static inline const NMPObject * nmp_object_ref (const NMPObject *obj) @@ -673,7 +599,7 @@ nmp_object_unref (const NMPObject *obj) _changed; \ }) -NMPObject *nmp_object_new (NMPObjectType obj_type, const NMPlatformObject *plob); +NMPObject *nmp_object_new (NMPObjectType obj_type, gconstpointer plobj); NMPObject *nmp_object_new_link (int ifindex); const NMPObject *nmp_object_stackinit (NMPObject *obj, NMPObjectType obj_type, gconstpointer plobj); |