wg: add syncconf command
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
parent
34ea0caf1f
commit
ae374129ab
|
@ -94,6 +94,14 @@ Appends the contents of \fI<configuration-filename>\fP, which must
|
||||||
be in the format described by \fICONFIGURATION FILE FORMAT\fP below,
|
be in the format described by \fICONFIGURATION FILE FORMAT\fP below,
|
||||||
to the current configuration of \fI<interface>\fP.
|
to the current configuration of \fI<interface>\fP.
|
||||||
.TP
|
.TP
|
||||||
|
\fBsyncconf\fP \fI<interface>\fP \fI<configuration-filename>\fP
|
||||||
|
Like \fBsetconf\fP, but reads back the existing configuration first
|
||||||
|
and only makes changes that are explicitly different between the configuration
|
||||||
|
file and the interface. This is much less efficient than \fBsetconf\fP,
|
||||||
|
but has the benefit of not disrupting current peer sessions. The contents of
|
||||||
|
\fI<configuration-filename>\fP must be in the format described by
|
||||||
|
\fICONFIGURATION FILE FORMAT\fP below.
|
||||||
|
.TP
|
||||||
\fBgenkey\fP
|
\fBgenkey\fP
|
||||||
Generates a random \fIprivate\fP key in base64 and prints it to
|
Generates a random \fIprivate\fP key in base64 and prints it to
|
||||||
standard output.
|
standard output.
|
||||||
|
|
|
@ -13,6 +13,89 @@
|
||||||
#include "ipc.h"
|
#include "ipc.h"
|
||||||
#include "subcommands.h"
|
#include "subcommands.h"
|
||||||
|
|
||||||
|
struct pubkey_origin {
|
||||||
|
uint8_t *pubkey;
|
||||||
|
bool from_file;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int pubkey_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);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
return a->from_file - b->from_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool sync_conf(struct wgdevice *file)
|
||||||
|
{
|
||||||
|
struct wgdevice *runtime;
|
||||||
|
struct wgpeer *peer;
|
||||||
|
struct pubkey_origin *pubkeys;
|
||||||
|
size_t peer_count = 0, i = 0;
|
||||||
|
|
||||||
|
if (!file->first_peer)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for_each_wgpeer(file, peer)
|
||||||
|
++peer_count;
|
||||||
|
|
||||||
|
if (ipc_get_device(&runtime, file->name) != 0) {
|
||||||
|
perror("Unable to retrieve current interface configuration");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!runtime->first_peer)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
file->flags &= ~WGDEVICE_REPLACE_PEERS;
|
||||||
|
|
||||||
|
for_each_wgpeer(runtime, peer)
|
||||||
|
++peer_count;
|
||||||
|
|
||||||
|
pubkeys = calloc(peer_count, sizeof(*pubkeys));
|
||||||
|
if (!pubkeys) {
|
||||||
|
free_wgdevice(runtime);
|
||||||
|
perror("Public key allocation");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_wgpeer(file, peer) {
|
||||||
|
pubkeys[i].pubkey = peer->public_key;
|
||||||
|
pubkeys[i].from_file = true;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
for_each_wgpeer(runtime, peer) {
|
||||||
|
pubkeys[i].pubkey = peer->public_key;
|
||||||
|
pubkeys[i].from_file = false;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
qsort(pubkeys, peer_count, sizeof(*pubkeys), pubkey_cmp);
|
||||||
|
|
||||||
|
for (i = 0; i < peer_count; ++i) {
|
||||||
|
if (pubkeys[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)) {
|
||||||
|
peer = calloc(1, sizeof(struct wgpeer));
|
||||||
|
if (!peer) {
|
||||||
|
free_wgdevice(runtime);
|
||||||
|
free(pubkeys);
|
||||||
|
perror("Peer allocation");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
peer->flags = WGPEER_REMOVE_ME;
|
||||||
|
memcpy(peer->public_key, pubkeys[i].pubkey, WG_KEY_LEN);
|
||||||
|
peer->next_peer = file->first_peer;
|
||||||
|
file->first_peer = peer;
|
||||||
|
if (!file->last_peer)
|
||||||
|
file->last_peer = peer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free_wgdevice(runtime);
|
||||||
|
free(pubkeys);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int setconf_main(int argc, char *argv[])
|
int setconf_main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct wgdevice *device = NULL;
|
struct wgdevice *device = NULL;
|
||||||
|
@ -50,6 +133,11 @@ int setconf_main(int argc, char *argv[])
|
||||||
strncpy(device->name, argv[1], IFNAMSIZ - 1);
|
strncpy(device->name, argv[1], IFNAMSIZ - 1);
|
||||||
device->name[IFNAMSIZ - 1] = '\0';
|
device->name[IFNAMSIZ - 1] = '\0';
|
||||||
|
|
||||||
|
if (!strcmp(argv[0], "syncconf")) {
|
||||||
|
if (!sync_conf(device))
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
if (ipc_set_device(device) != 0) {
|
if (ipc_set_device(device) != 0) {
|
||||||
perror("Unable to modify interface");
|
perror("Unable to modify interface");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
1
src/wg.c
1
src/wg.c
|
@ -21,6 +21,7 @@ static const struct {
|
||||||
{ "set", set_main, "Change the current configuration, add peers, remove peers, or change peers" },
|
{ "set", set_main, "Change the current configuration, add peers, remove peers, or change peers" },
|
||||||
{ "setconf", setconf_main, "Applies a configuration file to a WireGuard interface" },
|
{ "setconf", setconf_main, "Applies a configuration file to a WireGuard interface" },
|
||||||
{ "addconf", setconf_main, "Appends a configuration file to a WireGuard interface" },
|
{ "addconf", setconf_main, "Appends a configuration file to a WireGuard interface" },
|
||||||
|
{ "syncconf", setconf_main, "Synchronizes a configuration file to a WireGuard interface" },
|
||||||
{ "genkey", genkey_main, "Generates a new private key and writes it to stdout" },
|
{ "genkey", genkey_main, "Generates a new private key and writes it to stdout" },
|
||||||
{ "genpsk", genkey_main, "Generates a new preshared key and writes it to stdout" },
|
{ "genpsk", genkey_main, "Generates a new preshared key and writes it to stdout" },
|
||||||
{ "pubkey", pubkey_main, "Reads a private key from stdin and writes a public key to stdout" }
|
{ "pubkey", pubkey_main, "Reads a private key from stdin and writes a public key to stdout" }
|
||||||
|
|
Reference in New Issue