1 // SPDX-License-Identifier: GPL-2.0 OR MIT
3 * Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
11 #include "containers.h"
14 #include "subcommands.h"
16 struct pubkey_origin {
21 static int pubkey_cmp(const void *first, const void *second)
23 const struct pubkey_origin *a = first, *b = second;
24 int ret = memcmp(a->pubkey, b->pubkey, WG_KEY_LEN);
27 return a->from_file - b->from_file;
30 static bool sync_conf(struct wgdevice *file)
32 struct wgdevice *runtime;
34 struct pubkey_origin *pubkeys;
35 size_t peer_count = 0, i = 0;
37 if (!file->first_peer)
40 for_each_wgpeer(file, peer)
43 if (ipc_get_device(&runtime, file->name) != 0) {
44 perror("Unable to retrieve current interface configuration");
48 if (!runtime->first_peer) {
49 free_wgdevice(runtime);
53 file->flags &= ~WGDEVICE_REPLACE_PEERS;
55 for_each_wgpeer(runtime, peer)
58 pubkeys = calloc(peer_count, sizeof(*pubkeys));
60 free_wgdevice(runtime);
61 perror("Public key allocation");
65 for_each_wgpeer(file, peer) {
66 pubkeys[i].pubkey = peer->public_key;
67 pubkeys[i].from_file = true;
70 for_each_wgpeer(runtime, peer) {
71 pubkeys[i].pubkey = peer->public_key;
72 pubkeys[i].from_file = false;
75 qsort(pubkeys, peer_count, sizeof(*pubkeys), pubkey_cmp);
77 for (i = 0; i < peer_count; ++i) {
78 if (pubkeys[i].from_file)
80 if (i == peer_count - 1 || !pubkeys[i + 1].from_file || memcmp(pubkeys[i].pubkey, pubkeys[i + 1].pubkey, WG_KEY_LEN)) {
81 peer = calloc(1, sizeof(struct wgpeer));
83 free_wgdevice(runtime);
85 perror("Peer allocation");
88 peer->flags = WGPEER_REMOVE_ME;
89 memcpy(peer->public_key, pubkeys[i].pubkey, WG_KEY_LEN);
90 peer->next_peer = file->first_peer;
91 file->first_peer = peer;
93 file->last_peer = peer;
96 free_wgdevice(runtime);
101 int setconf_main(int argc, const char *argv[])
103 struct wgdevice *device = NULL;
104 struct config_ctx ctx;
105 FILE *config_input = NULL;
106 char *config_buffer = NULL;
107 size_t config_buffer_len = 0;
111 fprintf(stderr, "Usage: %s %s <interface> <configuration filename>\n", PROG_NAME, argv[0]);
115 config_input = fopen(argv[2], "r");
120 if (!config_read_init(&ctx, !strcmp(argv[0], "addconf"))) {
121 fclose(config_input);
124 while (getline(&config_buffer, &config_buffer_len, config_input) >= 0) {
125 if (!config_read_line(&ctx, config_buffer)) {
126 fprintf(stderr, "Configuration parsing error\n");
130 device = config_read_finish(&ctx);
132 fprintf(stderr, "Invalid configuration\n");
135 strncpy(device->name, argv[1], IFNAMSIZ - 1);
136 device->name[IFNAMSIZ - 1] = '\0';
138 if (!strcmp(argv[0], "syncconf")) {
139 if (!sync_conf(device))
143 if (ipc_set_device(device) != 0) {
144 perror("Unable to modify interface");
152 fclose(config_input);
154 free_wgdevice(device);