summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/devices/nm-device-wireguard.c109
1 files changed, 88 insertions, 21 deletions
diff --git a/src/devices/nm-device-wireguard.c b/src/devices/nm-device-wireguard.c
index 0c467dfe73..1b109969ee 100644
--- a/src/devices/nm-device-wireguard.c
+++ b/src/devices/nm-device-wireguard.c
@@ -118,6 +118,9 @@ typedef struct {
CList lst_peers_head;
GHashTable *peers;
+ /* counts the numbers of peers that are currently resolving. */
+ guint peers_resolving_cnt;
+
gint64 resolve_next_try_at;
gint64 link_config_last_at;
@@ -506,9 +509,52 @@ _peers_find(NMDeviceWireGuardPrivate *priv, NMWireGuardPeer *peer)
return g_hash_table_lookup(priv->peers, &peer);
}
+static guint
+_peers_resolving_cnt(NMDeviceWireGuardPrivate *priv)
+{
+ nm_assert(priv);
+#if NM_MORE_ASSERTS > 3
+ {
+ PeerData *peer_data;
+ guint cnt = 0;
+
+ c_list_for_each_entry (peer_data, &priv->lst_peers_head, lst_peers) {
+ if (peer_data->ep_resolv.cancellable)
+ cnt++;
+ }
+ nm_assert(cnt == priv->peers_resolving_cnt);
+ }
+#endif
+
+ return priv->peers_resolving_cnt;
+}
+
+static void
+_peers_resolving_cnt_decrement(NMDeviceWireGuard *self)
+{
+ NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self);
+
+ nm_assert(priv);
+ nm_assert(priv->peers_resolving_cnt > 0);
+
+ priv->peers_resolving_cnt--;
+
+ nm_assert(_peers_resolving_cnt(priv) == priv->peers_resolving_cnt);
+
+ if (priv->peers_resolving_cnt == 0) {
+ if (nm_device_get_state(NM_DEVICE(self)) == NM_DEVICE_STATE_CONFIG) {
+ _LOGT(LOGD_DEVICE,
+ "activation delayed to resolve DNS names of peers: completed, proceed now");
+ nm_device_activate_schedule_stage2_device_config(NM_DEVICE(self), FALSE);
+ }
+ }
+}
+
static void
-_peers_remove(NMDeviceWireGuardPrivate *priv, PeerData *peer_data)
+_peers_remove(NMDeviceWireGuard *self, PeerData *peer_data)
{
+ NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self);
+
nm_assert(peer_data);
nm_assert(g_hash_table_lookup(priv->peers, peer_data) == peer_data);
@@ -517,13 +563,16 @@ _peers_remove(NMDeviceWireGuardPrivate *priv, PeerData *peer_data)
c_list_unlink_stale(&peer_data->lst_peers);
nm_wireguard_peer_unref(peer_data->peer);
- nm_clear_g_cancellable(&peer_data->ep_resolv.cancellable);
+ if (nm_clear_g_cancellable(&peer_data->ep_resolv.cancellable))
+ _peers_resolving_cnt_decrement(self);
g_slice_free(PeerData, peer_data);
if (c_list_is_empty(&priv->lst_peers_head)) {
nm_clear_g_source(&priv->resolve_next_try_id);
nm_clear_g_source(&priv->link_config_delayed_id);
}
+
+ nm_assert(_peers_resolving_cnt(priv) == priv->peers_resolving_cnt);
}
static PeerData *
@@ -675,8 +724,9 @@ _peers_retry_in_msec(PeerData *peer_data, gboolean after_failure)
static void
_peers_resolve_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- NMDeviceWireGuard *self;
- PeerData * peer_data;
+ NMDeviceWireGuard * self;
+ NMDeviceWireGuardPrivate *priv;
+ PeerData * peer_data;
gs_free_error GError *resolv_error = NULL;
GList * list;
gboolean changed = FALSE;
@@ -692,10 +742,13 @@ _peers_resolve_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
peer_data = user_data;
self = peer_data->self;
+ priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self);
- g_clear_object(&peer_data->ep_resolv.cancellable);
+ if (nm_clear_g_object(&peer_data->ep_resolv.cancellable))
+ _peers_resolving_cnt_decrement(self);
nm_assert((!resolv_error) != (!list));
+ nm_assert(_peers_resolving_cnt(priv) == priv->peers_resolving_cnt);
#define _retry_in_msec_to_string(retry_in_msec, s_retry) \
({ \
@@ -797,8 +850,6 @@ _peers_resolve_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
_peers_resolve_retry_reschedule_for_peer(self, peer_data, retry_in_msec);
if (changed) {
- NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self);
-
/* schedule the job in the background, to give multiple resolve events time
* to complete. */
nm_clear_g_source(&priv->link_config_delayed_id);
@@ -812,6 +863,7 @@ _peers_resolve_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
static void
_peers_resolve_start(NMDeviceWireGuard *self, PeerData *peer_data)
{
+ NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self);
gs_unref_object GResolver *resolver = NULL;
const char * host;
@@ -820,6 +872,7 @@ _peers_resolve_start(NMDeviceWireGuard *self, PeerData *peer_data)
nm_assert(!peer_data->ep_resolv.cancellable);
peer_data->ep_resolv.cancellable = g_cancellable_new();
+ priv->peers_resolving_cnt++;
/* set a special next-try timestamp. It is positive, and indicates
* that we are in the process of trying.
@@ -841,6 +894,8 @@ _peers_resolve_start(NMDeviceWireGuard *self, PeerData *peer_data)
nm_wireguard_peer_get_public_key(peer_data->peer),
host,
nm_wireguard_peer_get_endpoint(peer_data->peer));
+
+ nm_assert(_peers_resolving_cnt(priv) == priv->peers_resolving_cnt);
}
static void
@@ -915,7 +970,8 @@ _peers_update(NMDeviceWireGuard *self,
if (nm_sock_addr_union_cmp(&peer_data->ep_resolv.sockaddr, &sockaddr) != 0)
changed = TRUE;
- nm_clear_g_cancellable(&peer_data->ep_resolv.cancellable);
+ if (nm_clear_g_cancellable(&peer_data->ep_resolv.cancellable))
+ _peers_resolving_cnt_decrement(self);
peer_data->ep_resolv = (PeerEndpointResolveData){
.sockaddr = sockaddr,
@@ -948,12 +1004,13 @@ _peers_update(NMDeviceWireGuard *self,
}
static void
-_peers_remove_all(NMDeviceWireGuardPrivate *priv)
+_peers_remove_all(NMDeviceWireGuard *self)
{
- PeerData *peer_data;
+ NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self);
+ PeerData * peer_data;
while ((peer_data = c_list_first_entry(&priv->lst_peers_head, PeerData, lst_peers)))
- _peers_remove(priv, peer_data);
+ _peers_remove(self, peer_data);
}
static void
@@ -984,7 +1041,7 @@ _peers_update_all(NMDeviceWireGuard *self, NMSettingWireGuard *s_wg, gboolean *o
c_list_for_each_entry_safe (peer_data, peer_data_safe, &priv->lst_peers_head, lst_peers) {
if (peer_data->dirty_update_all) {
- _peers_remove(priv, peer_data);
+ _peers_remove(self, peer_data);
peers_removed = TRUE;
}
}
@@ -1515,9 +1572,11 @@ link_config_delayed_resolver_cb(gpointer user_data)
static NMActStageReturn
act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason)
{
- NMDeviceSysIfaceState sys_iface_state;
- NMDeviceStateReason failure_reason;
- NMActStageReturn ret;
+ NMDeviceWireGuard * self = NM_DEVICE_WIREGUARD(device);
+ NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self);
+ NMDeviceSysIfaceState sys_iface_state;
+ NMDeviceStateReason failure_reason;
+ NMActStageReturn ret;
sys_iface_state = nm_device_sys_iface_state_get(device);
@@ -1533,17 +1592,25 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason)
: LINK_CONFIG_MODE_FULL,
&failure_reason);
- if (sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_ASSUME) {
- /* this never fails. */
- return NM_ACT_STAGE_RETURN_SUCCESS;
- }
-
if (ret == NM_ACT_STAGE_RETURN_FAILURE) {
+ if (sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_ASSUME) {
+ /* this never fails. */
+ return NM_ACT_STAGE_RETURN_SUCCESS;
+ }
+
nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, failure_reason);
NM_SET_OUT(out_failure_reason, failure_reason);
return NM_ACT_STAGE_RETURN_FAILURE;
}
+ nm_assert(NM_IN_SET(ret, NM_ACT_STAGE_RETURN_SUCCESS, NM_ACT_STAGE_RETURN_POSTPONE));
+
+ if (ret == NM_ACT_STAGE_RETURN_SUCCESS && _peers_resolving_cnt(priv) > 0u) {
+ _LOGT(LOGD_DEVICE,
+ "activation delayed to resolve DNS names of peers: resolving and waiting...");
+ return NM_ACT_STAGE_RETURN_POSTPONE;
+ }
+
return ret;
}
@@ -1732,7 +1799,7 @@ _device_cleanup(NMDeviceWireGuard *self)
{
NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self);
- _peers_remove_all(priv);
+ _peers_remove_all(self);
_secrets_cancel(self);