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
	
	Block a user