aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2019-09-28 20:04:17 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2019-10-11 12:34:54 +0200
commit54db1977b2501680eb0e407efbf0350c103ca7a0 (patch)
tree0c094a992e9e6d7c22341242cf23d0e7b0eb3c95
parentnetns: add test for failing 5.3 FIB changes (diff)
downloadWireGuard-54db1977b2501680eb0e407efbf0350c103ca7a0.tar.xz
WireGuard-54db1977b2501680eb0e407efbf0350c103ca7a0.zip
netlink: allow preventing creation of new peers when updating
This enables race-free updates for wg-dynamic and similar tools. Suggested-by: Thomas Gschwantner <tharre3@gmail.com>
-rw-r--r--src/netlink.c7
-rw-r--r--src/uapi/wireguard.h14
2 files changed, 12 insertions, 9 deletions
diff --git a/src/netlink.c b/src/netlink.c
index 0805a26..190e405 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -389,10 +389,10 @@ static int set_peer(struct wg_device *wg, struct nlattr **attrs)
peer = wg_pubkey_hashtable_lookup(wg->peer_hashtable,
nla_data(attrs[WGPEER_A_PUBLIC_KEY]));
+ ret = 0;
if (!peer) { /* Peer doesn't exist yet. Add a new one. */
- ret = -ENODEV;
- if (flags & WGPEER_F_REMOVE_ME)
- goto out; /* Tried to remove a non-existing peer. */
+ if (flags & (WGPEER_F_REMOVE_ME | WGPEER_F_UPDATE_ONLY))
+ goto out;
/* The peer is new, so there aren't allowed IPs to remove. */
flags &= ~WGPEER_F_REPLACE_ALLOWEDIPS;
@@ -429,7 +429,6 @@ static int set_peer(struct wg_device *wg, struct nlattr **attrs)
wg_peer_get(peer);
}
- ret = 0;
if (flags & WGPEER_F_REMOVE_ME) {
wg_peer_remove(peer);
goto out;
diff --git a/src/uapi/wireguard.h b/src/uapi/wireguard.h
index 5a3e5a7..dd8a47c 100644
--- a/src/uapi/wireguard.h
+++ b/src/uapi/wireguard.h
@@ -87,10 +87,12 @@
* 0: NLA_NESTED
* WGPEER_A_PUBLIC_KEY: len WG_KEY_LEN
* WGPEER_A_FLAGS: NLA_U32, 0 and/or WGPEER_F_REMOVE_ME if the
- * specified peer should be removed rather than
- * added/updated and/or WGPEER_F_REPLACE_ALLOWEDIPS
- * if all current allowed IPs of this peer should be
- * removed prior to adding the list below.
+ * specified peer should not exist at the end of the
+ * operation, rather than added/updated and/or
+ * WGPEER_F_REPLACE_ALLOWEDIPS if all current allowed
+ * IPs of this peer should be removed prior to adding
+ * the list below and/or WGPEER_F_UPDATE_ONLY if the
+ * peer should only be set if it already exists.
* WGPEER_A_PRESHARED_KEY: len WG_KEY_LEN, all zeros to remove
* WGPEER_A_ENDPOINT: struct sockaddr_in or struct sockaddr_in6
* WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL: NLA_U16, 0 to disable
@@ -162,7 +164,9 @@ enum wgdevice_attribute {
enum wgpeer_flag {
WGPEER_F_REMOVE_ME = 1U << 0,
WGPEER_F_REPLACE_ALLOWEDIPS = 1U << 1,
- __WGPEER_F_ALL = WGPEER_F_REMOVE_ME | WGPEER_F_REPLACE_ALLOWEDIPS
+ WGPEER_F_UPDATE_ONLY = 1U << 2,
+ __WGPEER_F_ALL = WGPEER_F_REMOVE_ME | WGPEER_F_REPLACE_ALLOWEDIPS |
+ WGPEER_F_UPDATE_ONLY
};
enum wgpeer_attribute {
WGPEER_A_UNSPEC,