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,
|
||||
to the current configuration of \fI<interface>\fP.
|
||||
.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
|
||||
Generates a random \fIprivate\fP key in base64 and prints it to
|
||||
standard output.
|
||||
|
|
|
@ -13,6 +13,89 @@
|
|||
#include "ipc.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[])
|
||||
{
|
||||
struct wgdevice *device = NULL;
|
||||
|
@ -50,6 +133,11 @@ int setconf_main(int argc, char *argv[])
|
|||
strncpy(device->name, argv[1], IFNAMSIZ - 1);
|
||||
device->name[IFNAMSIZ - 1] = '\0';
|
||||
|
||||
if (!strcmp(argv[0], "syncconf")) {
|
||||
if (!sync_conf(device))
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (ipc_set_device(device) != 0) {
|
||||
perror("Unable to modify interface");
|
||||
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" },
|
||||
{ "setconf", setconf_main, "Applies 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" },
|
||||
{ "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" }
|
||||
|
|
Reference in New Issue