diff options
author | 2025-05-23 20:22:37 +0200 | |
---|---|---|
committer | 2025-05-23 20:26:12 +0200 | |
commit | 780182e37d2b5981171766b8f31bcefd64da7a43 (patch) | |
tree | 304dd71cb13ed50300a6dc9fc60bf5493543bfd9 | |
parent | wg-quick: linux: use smallest mtu, not largest (diff) | |
download | wireguard-tools-780182e37d2b5981171766b8f31bcefd64da7a43.tar.xz wireguard-tools-780182e37d2b5981171766b8f31bcefd64da7a43.zip |
syncconf: account for psks removed from config file
Otherwise removing a psk from a config file wouldn't reflect on the
runtime state.
Note that this could have been implemented more simply, by just setting
WGPEER_HAS_PRESHARED_KEY on all of the file's peers, since the psk slot
is zeroed by calloc in config.c, and this way ones with no set key will
be cleared. The downside is that this means every peer update will take
the handshake lock in the kernel, creating more work and possibly
contention:
if (preshared_key) {
down_write(&peer->handshake.lock);
memcpy(&peer->handshake.preshared_key, preshared_key,
NOISE_SYMMETRIC_KEY_LEN);
up_write(&peer->handshake.lock);
}
Avoid this by only setting it if there's a mismatch between the runtime
and the file. Computationally this shouldn't make much of a difference
because we can do it in the same iteration as the peer removal
detection.
Reported-by: Patrick Havelange <patrick.havelange_ext@softathome.com>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
-rw-r--r-- | src/setconf.c | 43 |
1 files changed, 24 insertions, 19 deletions
diff --git a/src/setconf.c b/src/setconf.c index 1c5b138..4f830a4 100644 --- a/src/setconf.c +++ b/src/setconf.c @@ -13,15 +13,15 @@ #include "ipc.h" #include "subcommands.h" -struct pubkey_origin { - uint8_t *pubkey; +struct peer_origin { + struct wgpeer *peer; bool from_file; }; -static int pubkey_cmp(const void *first, const void *second) +static int peer_cmp(const void *first, const void *second) { - const struct pubkey_origin *a = first, *b = second; - int ret = memcmp(a->pubkey, b->pubkey, WG_KEY_LEN); + const struct peer_origin *a = first, *b = second; + int ret = memcmp(a->peer->public_key, b->peer->public_key, WG_KEY_LEN); if (ret) return ret; return a->from_file - b->from_file; @@ -31,7 +31,7 @@ static bool sync_conf(struct wgdevice *file) { struct wgdevice *runtime; struct wgpeer *peer; - struct pubkey_origin *pubkeys; + struct peer_origin *peers; size_t peer_count = 0, i = 0; if (!file->first_peer) @@ -55,46 +55,51 @@ static bool sync_conf(struct wgdevice *file) for_each_wgpeer(runtime, peer) ++peer_count; - pubkeys = calloc(peer_count, sizeof(*pubkeys)); - if (!pubkeys) { + peers = calloc(peer_count, sizeof(*peers)); + if (!peers) { free_wgdevice(runtime); - perror("Public key allocation"); + perror("Peer list allocation"); return false; } for_each_wgpeer(file, peer) { - pubkeys[i].pubkey = peer->public_key; - pubkeys[i].from_file = true; + peers[i].peer = peer; + peers[i].from_file = true; ++i; } for_each_wgpeer(runtime, peer) { - pubkeys[i].pubkey = peer->public_key; - pubkeys[i].from_file = false; + peers[i].peer = peer; + peers[i].from_file = false; ++i; } - qsort(pubkeys, peer_count, sizeof(*pubkeys), pubkey_cmp); + qsort(peers, peer_count, sizeof(*peers), peer_cmp); for (i = 0; i < peer_count; ++i) { - if (pubkeys[i].from_file) + if (peers[i].from_file) continue; - if (i == peer_count - 1 || !pubkeys[i + 1].from_file || memcmp(pubkeys[i].pubkey, pubkeys[i + 1].pubkey, WG_KEY_LEN)) { + if (i == peer_count - 1 || !peers[i + 1].from_file || memcmp(peers[i].peer->public_key, peers[i + 1].peer->public_key, WG_KEY_LEN)) { peer = calloc(1, sizeof(struct wgpeer)); if (!peer) { free_wgdevice(runtime); - free(pubkeys); + free(peers); perror("Peer allocation"); return false; } peer->flags = WGPEER_REMOVE_ME; - memcpy(peer->public_key, pubkeys[i].pubkey, WG_KEY_LEN); + memcpy(peer->public_key, peers[i].peer->public_key, WG_KEY_LEN); peer->next_peer = file->first_peer; file->first_peer = peer; if (!file->last_peer) file->last_peer = peer; + } else if (i < peer_count - 1 && peers[i + 1].from_file && + (peers[i].peer->flags & WGPEER_HAS_PRESHARED_KEY) && !(peers[i + 1].peer->flags & WGPEER_HAS_PRESHARED_KEY) && + !memcmp(peers[i].peer->public_key, peers[i + 1].peer->public_key, WG_KEY_LEN)) { + memset(peers[i + 1].peer->preshared_key, 0, WG_KEY_LEN); + peers[i + 1].peer->flags |= WGPEER_HAS_PRESHARED_KEY; } } free_wgdevice(runtime); - free(pubkeys); + free(peers); return true; } |