]> git.ipfire.org Git - thirdparty/wireguard-tools.git/commitdiff
wg: support text-based ipc
authorJason A. Donenfeld <Jason@zx2c4.com>
Mon, 15 May 2017 21:24:48 +0000 (23:24 +0200)
committerJason A. Donenfeld <Jason@zx2c4.com>
Wed, 17 May 2017 16:13:14 +0000 (18:13 +0200)
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
src/config.c
src/encoding.c [moved from src/base64.c with 53% similarity]
src/encoding.h [moved from src/base64.h with 62% similarity]
src/genkey.c
src/ipc.c
src/pubkey.c
src/show.c
src/showconf.c

index 7007b880d76d91edaa036adbc3c634c760a67ff5..f57fa8278072724b0dbd863d3f3f1378c2d24c58 100644 (file)
@@ -15,7 +15,7 @@
 
 #include "config.h"
 #include "ipc.h"
-#include "base64.h"
+#include "encoding.h"
 
 #define COMMENT_CHAR '#'
 
@@ -171,14 +171,12 @@ static inline bool parse_endpoint(struct sockaddr *endpoint, const char *value)
                        fprintf(stderr, "Unable to find matching brace of endpoint: `%s`\n", value);
                        return false;
                }
-               *end = '\0';
-               ++end;
-               if (*end != ':' || !*(end + 1)) {
+               *end++ = '\0';
+               if (*end++ != ':' || !*end) {
                        free(mutable);
                        fprintf(stderr, "Unable to find port of endpoint: `%s`\n", value);
                        return false;
                }
-               ++end;
        } else {
                begin = mutable;
                end = strrchr(mutable, ':');
@@ -187,8 +185,7 @@ static inline bool parse_endpoint(struct sockaddr *endpoint, const char *value)
                        fprintf(stderr, "Unable to find port of endpoint: `%s`\n", value);
                        return false;
                }
-               *end = '\0';
-               ++end;
+               *end++ = '\0';
        }
 
        for (unsigned int timeout = 1000000; timeout < 90000000; timeout = timeout * 3 / 2) {
similarity index 53%
rename from src/base64.c
rename to src/encoding.c
index 48ac1be66c1c2398d192d8c58a125321b60e6dcd..389bbf70d8a91d56d0ba44301fe9772561eaddc6 100644 (file)
@@ -1,12 +1,12 @@
 /* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
  *
- * This is a specialized constant-time base64 implementation that resists side-channel attacks.
+ * This is a specialized constant-time base64/hex implementation that resists side-channel attacks.
  */
 
 #include <string.h>
-#include "base64.h"
+#include "encoding.h"
 
-static inline void encode(char dest[4], const uint8_t src[3])
+static inline void encode_base64(char dest[4], const uint8_t src[3])
 {
        const uint8_t input[] = { (src[0] >> 2) & 63, ((src[0] << 4) | (src[1] >> 4)) & 63, ((src[1] << 2) | (src[2] >> 6)) & 63, src[2] & 63 };
        for (unsigned int i = 0; i < 4; ++i)
@@ -22,13 +22,13 @@ void key_to_base64(char base64[static WG_KEY_LEN_BASE64], const uint8_t key[stat
 {
        unsigned int i;
        for (i = 0; i < WG_KEY_LEN / 3; ++i)
-               encode(&base64[i * 4], &key[i * 3]);
-       encode(&base64[i * 4], (const uint8_t[]){ key[i * 3 + 0], key[i * 3 + 1], 0 });
+               encode_base64(&base64[i * 4], &key[i * 3]);
+       encode_base64(&base64[i * 4], (const uint8_t[]){ key[i * 3 + 0], key[i * 3 + 1], 0 });
        base64[WG_KEY_LEN_BASE64 - 2] = '=';
        base64[WG_KEY_LEN_BASE64 - 1] = '\0';
 }
 
-static inline int decode(const char src[4])
+static inline int decode_base64(const char src[4])
 {
        int val = 0;
        for (unsigned int i = 0; i < 4; ++i)
@@ -50,17 +50,52 @@ bool key_from_base64(uint8_t key[static WG_KEY_LEN], const char *base64)
                return false;
 
        for (i = 0; i < WG_KEY_LEN / 3; ++i) {
-               val = decode(&base64[i * 4]);
+               val = decode_base64(&base64[i * 4]);
                if (val < 0)
                        return false;
                key[i * 3 + 0] = (val >> 16) & 0xff;
                key[i * 3 + 1] = (val >> 8) & 0xff;
                key[i * 3 + 2] = val & 0xff;
        }
-       val = decode((const char[]){ base64[i * 4 + 0], base64[i * 4 + 1], base64[i * 4 + 2], 'A' });
+       val = decode_base64((const char[]){ base64[i * 4 + 0], base64[i * 4 + 1], base64[i * 4 + 2], 'A' });
        if (val < 0 || val & 0xff)
                return false;
        key[i * 3 + 0] = (val >> 16) & 0xff;
        key[i * 3 + 1] = (val >> 8) & 0xff;
        return true;
 }
+
+void key_to_hex(char hex[static WG_KEY_LEN_HEX], const uint8_t key[static WG_KEY_LEN])
+{
+       unsigned int i;
+       for (i = 0; i < WG_KEY_LEN; ++i) {
+               hex[i * 2] = 87U + (key[i] >> 4) + ((((key[i] >> 4) - 10U) >> 8) & ~38U);
+               hex[i * 2 + 1] = 87U + (key[i] & 0xf) + ((((key[i] & 0xf) - 10U) >> 8) & ~38U);
+       }
+       hex[i * 2] = '\0';
+}
+
+bool key_from_hex(uint8_t key[static WG_KEY_LEN], const char *hex)
+{
+       uint8_t i, c, c_acc = 0, c_alpha0, c_alpha, c_num0, c_num, c_val, state = 0;
+
+       if (strlen(hex) != WG_KEY_LEN_HEX - 1)
+               return false;
+
+       for (i = 0; i < WG_KEY_LEN_HEX - 1; ++i) {
+               c = (uint8_t)hex[i];
+               c_num = c ^ 48U;
+               c_num0 = (c_num - 10U) >> 8;
+               c_alpha = (c & ~32U) - 55U;
+               c_alpha0 = ((c_alpha - 10U) ^ (c_alpha - 16U)) >> 8;
+               if (!(c_num0 | c_alpha0))
+                       return false;
+               c_val = (c_num0 & c_num) | (c_alpha0 & c_alpha);
+               if (!state)
+                       c_acc = c_val * 16U;
+               else
+                       key[i / 2] = c_acc | c_val;
+               state = ~state;
+       }
+       return true;
+}
similarity index 62%
rename from src/base64.h
rename to src/encoding.h
index 37cf1b9c3edc5200775baa0431400f286645056c..f4fe51e5b107044f1e29cf82786d91f8759d7e66 100644 (file)
@@ -1,15 +1,19 @@
 /* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
 
-#ifndef BASE64_H
-#define BASE64_H
+#ifndef ENCODING_H
+#define ENCODING_H
 
 #include <stdbool.h>
 #include <stdint.h>
 #include "../uapi.h"
 
 #define WG_KEY_LEN_BASE64 ((((WG_KEY_LEN) + 2) / 3) * 4 + 1)
+#define WG_KEY_LEN_HEX (WG_KEY_LEN * 2 + 1)
 
 void key_to_base64(char base64[static WG_KEY_LEN_BASE64], const uint8_t key[static WG_KEY_LEN]);
 bool key_from_base64(uint8_t key[static WG_KEY_LEN], const char *base64);
 
+void key_to_hex(char hex[static WG_KEY_LEN_HEX], const uint8_t key[static WG_KEY_LEN]);
+bool key_from_hex(uint8_t key[static WG_KEY_LEN], const char *hex);
+
 #endif
index 9c8da42eac927f3627e68c1047a7f69c87332ce4..52aeef5ab7f071a45a4024312a74138d0eb22d01 100644 (file)
@@ -12,7 +12,7 @@
 #endif
 
 #include "curve25519.h"
-#include "base64.h"
+#include "encoding.h"
 #include "subcommands.h"
 
 static inline ssize_t get_random_bytes(uint8_t *out, size_t len)
index 1c13e17c1c9c12d2c505edce82a3bd655a52a4a7..529099601ded7bb919fd6fac781dd50a94fa3140 100644 (file)
--- a/src/ipc.c
+++ b/src/ipc.c
 #include <time.h>
 #include <dirent.h>
 #include <signal.h>
+#include <netdb.h>
+#include <limits.h>
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/un.h>
+#include <arpa/inet.h>
 
 #include "ipc.h"
+#include "encoding.h"
+#include "curve25519.h"
 #include "../uapi.h"
 
 #define SOCK_PATH RUNSTATEDIR "/wireguard/"
@@ -42,16 +47,6 @@ struct inflatable_buffer {
 
 #define max(a, b) ((a) > (b) ? (a) : (b))
 
-static int check_version_magic(struct wgdevice *device, int ret)
-{
-       if (ret == -EPROTO || (!ret && device->version_magic != WG_API_VERSION_MAGIC)) {
-               fprintf(stderr, "This program was built for a different version of WireGuard than\nwhat is currently running. Either this version of wg(8) is out\nof date, or the currently loaded WireGuard module is out of date.\nIf you have just updated your WireGuard installation, you may have\nforgotten to unload the previous running WireGuard module. Try\nrunning `rmmod wireguard` as root, and then try re-adding the interface\nand trying again.\n\n");
-               errno = EPROTO;
-               return -EPROTO;
-       }
-       return ret;
-}
-
 static int add_next_to_inflatable_buffer(struct inflatable_buffer *buffer)
 {
        size_t len, expand_to;
@@ -90,11 +85,12 @@ static int add_next_to_inflatable_buffer(struct inflatable_buffer *buffer)
        return 0;
 }
 
-static int userspace_interface_fd(const char *interface)
+static FILE *userspace_interface_file(const char *interface)
 {
        struct stat sbuf;
        struct sockaddr_un addr = { .sun_family = AF_UNIX };
        int fd = -1, ret;
+       FILE *f;
 
        ret = -EINVAL;
        if (strchr(interface, '/'))
@@ -119,20 +115,25 @@ static int userspace_interface_fd(const char *interface)
                        unlink(addr.sun_path);
                goto out;
        }
+       f = fdopen(fd, "r+");
+       if (!f)
+               ret = -errno;
 out:
        if (ret && fd >= 0)
                close(fd);
-       if (!ret)
-               ret = fd;
-       return ret;
+       if (ret) {
+               errno = -ret;
+               return NULL;
+       }
+       return f;
 }
 
 static bool userspace_has_wireguard_interface(const char *interface)
 {
-       int fd = userspace_interface_fd(interface);
-       if (fd < 0)
+       FILE *f = userspace_interface_file(interface);
+       if (!f)
                return false;
-       close(fd);
+       fclose(f);
        return true;
 }
 
@@ -170,110 +171,261 @@ out:
 
 static int userspace_set_device(struct wgdevice *dev)
 {
+       static const uint8_t zero[WG_KEY_LEN] = { 0 };
+       char hex[WG_KEY_LEN_HEX], ip[INET6_ADDRSTRLEN], host[4096 + 1], service[512 + 1];
        struct wgpeer *peer;
-       size_t len;
-       ssize_t ret;
-       int ret_code;
-       int fd = userspace_interface_fd(dev->interface);
-       if (fd < 0)
-               return fd;
-       for_each_wgpeer(dev, peer, len);
-       len = (uint8_t *)peer - (uint8_t *)dev;
-       ret = -EBADMSG;
-       if (!len)
-               goto out;
-       dev->version_magic = WG_API_VERSION_MAGIC;
-       ret = write(fd, dev, len);
-       if (ret < 0)
-               goto out;
-       ret = read(fd, &ret_code, sizeof(ret_code));
-       if (ret < 0)
-               goto out;
-       if (ret != sizeof(ret_code)) {
-               ret = -EBADMSG;
-               goto out;
+       struct wgipmask *ipmask;
+       FILE *f;
+       int ret;
+       size_t i, j;
+       socklen_t addr_len;
+
+       f = userspace_interface_file(dev->interface);
+       if (!f)
+               return -errno;
+       fprintf(f, "set=1\n");
+
+       if (dev->flags & WGDEVICE_REMOVE_PRIVATE_KEY)
+               fprintf(f, "private_key=\n");
+       else if (memcmp(dev->private_key, zero, WG_KEY_LEN)) {
+               key_to_hex(hex, dev->private_key);
+               fprintf(f, "private_key=%s\n", hex);
        }
-       ret = ret_code;
-out:
-       close(fd);
+       if (dev->port)
+               fprintf(f, "listen_port=%u\n", dev->port);
+       if (dev->flags & WGDEVICE_REMOVE_FWMARK)
+               fprintf(f, "fwmark=\n");
+       else if (dev->fwmark)
+               fprintf(f, "fwmark=%u\n", dev->fwmark);
+       if (dev->flags & WGDEVICE_REPLACE_PEERS)
+               fprintf(f, "replace_peers=true\n");
+
+       for_each_wgpeer(dev, peer, i) {
+               key_to_hex(hex, peer->public_key);
+               fprintf(f, "public_key=%s\n", hex);
+               if (peer->flags & WGPEER_REMOVE_ME) {
+                       fprintf(f, "remove=true\n");
+                       continue;
+               }
+               if (peer->flags & WGPEER_REMOVE_PRESHARED_KEY)
+                       fprintf(f, "preshared_key=\n");
+               else if (memcmp(peer->preshared_key, zero, WG_KEY_LEN)) {
+                       key_to_hex(hex, peer->preshared_key);
+                       fprintf(f, "preshared_key=%s\n", hex);
+               }
+               if (peer->endpoint.addr.sa_family == AF_INET || peer->endpoint.addr.sa_family == AF_INET6) {
+                       addr_len = 0;
+                       if (peer->endpoint.addr.sa_family == AF_INET)
+                               addr_len = sizeof(struct sockaddr_in);
+                       else if (peer->endpoint.addr.sa_family == AF_INET6)
+                               addr_len = sizeof(struct sockaddr_in6);
+                       if (!getnameinfo(&peer->endpoint.addr, addr_len, host, sizeof(host), service, sizeof(service), NI_DGRAM | NI_NUMERICSERV | NI_NUMERICHOST)) {
+                               if (peer->endpoint.addr.sa_family == AF_INET6 && strchr(host, ':'))
+                                       fprintf(f, "endpoint=[%s]:%s\n", host, service);
+                               else
+                                       fprintf(f, "endpoint=%s:%s\n", host, service);
+                       }
+               }
+               if (peer->persistent_keepalive_interval != (uint16_t)-1)
+                       fprintf(f, "persistent_keepalive_interval=%u\n", peer->persistent_keepalive_interval);
+               if (peer->flags & WGPEER_REPLACE_IPMASKS)
+                       fprintf(f, "replace_allowed_ips=true\n");
+               for_each_wgipmask(peer, ipmask, j) {
+                       if (ipmask->family == AF_INET) {
+                               if (!inet_ntop(AF_INET, &ipmask->ip4, ip, INET6_ADDRSTRLEN))
+                                       continue;
+                       } else if (ipmask->family == AF_INET6) {
+                               if (!inet_ntop(AF_INET6, &ipmask->ip6, ip, INET6_ADDRSTRLEN))
+                                       continue;
+                       } else
+                               continue;
+                       fprintf(f, "allowed_ip=%s/%d\n", ip, ipmask->cidr);
+               }
+       }
+       fprintf(f, "\n");
+       fflush(f);
+
+       if (fscanf(f, "errno=%d\n\n", &ret) != 1)
+               ret = errno ? -errno : -EPROTO;
+       fclose(f);
        errno = -ret;
-       return check_version_magic(dev, ret);
+       return ret;
 }
 
-#define READ_BYTES(bytes) ({ \
-       void *__p; \
-       size_t __bytes = (bytes); \
-       if (bytes_left < __bytes) { \
-               offset = p - buffer; \
-               bytes_left += buffer_size; \
-               buffer_size *= 2; \
-               ret = -ENOMEM; \
-               p = realloc(buffer, buffer_size); \
-               if (!p) \
-                       goto out; \
-               buffer = p; \
-               p += offset; \
-       } \
-       bytes_left -= __bytes; \
-       ret = read(fd, p, __bytes); \
-       if (ret < 0) \
-               goto out; \
-       if ((size_t)ret != __bytes) { \
-               ret = -EBADMSG; \
-               goto out; \
+#define ADD(bytes) ({ \
+       if (buffer_len - buffer_end < bytes) { \
+               ptrdiff_t peer_offset = (void *)peer - (void *)*out; \
+               buffer_len = buffer_len * 2 + bytes; \
+               *out = realloc(*out, buffer_len); \
+               if (!*out) { \
+                       ret = -errno; \
+                       goto err; \
+               } \
+               memset((void *)*out + buffer_end, 0, buffer_len - buffer_end); \
+               if (peer) \
+                       peer = (void *)*out + peer_offset; \
+               dev = *out; \
        } \
-       __p = p; \
-       p += __bytes; \
-       __p; \
+       buffer_end += bytes; \
+       (void *)*out + buffer_end - bytes; \
 })
-static int userspace_get_device(struct wgdevice **dev, const char *interface)
-{
-       unsigned int len = 0, i;
-       size_t buffer_size, bytes_left;
-       ssize_t ret;
-       ptrdiff_t offset;
-       uint8_t *buffer = NULL, *p, byte = 0;
-
-       int fd = userspace_interface_fd(interface);
-       if (fd < 0)
-               return fd;
 
-       ret = write(fd, &byte, sizeof(byte));
-       if (ret < 0)
-               goto out;
-       if (ret != sizeof(byte)) {
-               ret = -EBADMSG;
-               goto out;
-       }
-
-       ioctl(fd, FIONREAD, &len);
-       bytes_left = buffer_size = max(len, sizeof(struct wgdevice) + sizeof(struct wgpeer) + sizeof(struct wgipmask));
-       p = buffer = malloc(buffer_size);
-       ret = -ENOMEM;
-       if (!buffer)
-               goto out;
+#define NUM(max) ({ \
+       unsigned long long num; \
+       char *end; \
+       if (!strlen(value)) \
+               break; \
+       num = strtoull(value, &end, 10); \
+       if (*end || num > max) \
+               break; \
+       num; \
+})
 
-       len = ((struct wgdevice *)READ_BYTES(sizeof(struct wgdevice)))->num_peers;
-       ret = check_version_magic((struct wgdevice *)buffer, ret);
-       if (ret)
-               goto out;
-       for (i = 0; i < len; ++i)
-               READ_BYTES(sizeof(struct wgipmask) * ((struct wgpeer *)READ_BYTES(sizeof(struct wgpeer)))->num_ipmasks);
-       ret = 0;
-out:
-       if (buffer && ret) {
-               free(buffer);
-               buffer = NULL;
+static int userspace_get_device(struct wgdevice **out, const char *interface)
+{
+       struct wgdevice *dev;
+       struct wgpeer *peer = NULL;
+       size_t buffer_len = 0, buffer_end = 0, line_buffer_len = 0, line_len;
+       char *key = NULL, *value;
+       FILE *f;
+       int ret = -EPROTO;
+
+       f = userspace_interface_file(interface);
+       if (!f)
+               return -errno;
+
+       fprintf(f, "get=1\n\n");
+       fflush(f);
+
+       *out = NULL;
+       dev = ADD(sizeof(struct wgdevice));
+       dev->version_magic = WG_API_VERSION_MAGIC;
+       strncpy(dev->interface, interface, IFNAMSIZ - 1);
+       dev->interface[IFNAMSIZ - 1] = '\0';
+
+       while (getline(&key, &line_buffer_len, f) > 0) {
+               line_len = strlen(key);
+               if (line_len == 1 && key[0] == '\n') {
+                       free(key);
+                       fclose(f);
+                       return ret;
+               }
+               value = strchr(key, '=');
+               if (!value || line_len == 0 || key[line_len - 1] != '\n')
+                       break;
+               *value++ = key[--line_len] = '\0';
+
+               if (!strcmp(key, "private_key")) {
+                       if (!key_from_hex(dev->private_key, value))
+                               break;
+                       curve25519_generate_public(dev->public_key, dev->private_key);
+               } else if (!strcmp(key, "listen_port"))
+                       dev->port = NUM(0xffffU);
+               else if (!strcmp(key, "fwmark"))
+                       dev->fwmark = NUM(0xffffffffU);
+               else if (!strcmp(key, "public_key")) {
+                       peer = ADD(sizeof(struct wgpeer));
+                       if (!key_from_hex(peer->public_key, value))
+                               break;
+                       ++dev->num_peers;
+               } else if (peer && !strcmp(key, "preshared_key")) {
+                       if (!key_from_hex(peer->preshared_key, value))
+                               break;
+               } else if (peer && !strcmp(key, "endpoint")) {
+                       char *begin, *end;
+                       struct addrinfo *resolved;
+                       struct addrinfo hints = {
+                               .ai_family = AF_UNSPEC,
+                               .ai_socktype = SOCK_DGRAM,
+                               .ai_protocol = IPPROTO_UDP
+                       };
+                       if (!strlen(value))
+                               break;
+                       if (value[0] == '[') {
+                               begin = &value[1];
+                               end = strchr(value, ']');
+                               if (!end)
+                                       break;
+                               *end++ = '\0';
+                               if (*end++ != ':' || !*end)
+                                       break;
+                       } else {
+                               begin = value;
+                               end = strrchr(value, ':');
+                               if (!end || !*(end + 1))
+                                       break;
+                               *end++ = '\0';
+                       }
+                       if (getaddrinfo(begin, end, &hints, &resolved) != 0) {
+                               errno = ENETUNREACH;
+                               goto err;
+                       }
+                       if ((resolved->ai_family == AF_INET && resolved->ai_addrlen == sizeof(struct sockaddr_in)) ||
+                           (resolved->ai_family == AF_INET6 && resolved->ai_addrlen == sizeof(struct sockaddr_in6)))
+                               memcpy(&peer->endpoint.addr, resolved->ai_addr, resolved->ai_addrlen);
+                       else  {
+                               freeaddrinfo(resolved);
+                               break;
+                       }
+                       freeaddrinfo(resolved);
+               } else if (peer && !strcmp(key, "persistent_keepalive_interval"))
+                       peer->persistent_keepalive_interval = NUM(65535U);
+               else if (peer && !strcmp(key, "allowed_ip")) {
+                       struct wgipmask *ipmask = ADD(sizeof(struct wgipmask));
+                       char *end, *cidr = strchr(value, '/');
+                       if (!cidr || strlen(cidr) <= 1)
+                               break;
+                       *cidr++ = '\0';
+                       ipmask->family = AF_UNSPEC;
+                       if (strchr(value, ':')) {
+                               if (inet_pton(AF_INET6, value, &ipmask->ip6) == 1)
+                                       ipmask->family = AF_INET6;
+                       } else {
+                               if (inet_pton(AF_INET, value, &ipmask->ip4) == 1)
+                                       ipmask->family = AF_INET;
+                       }
+                       ipmask->cidr = strtoul(cidr, &end, 10);
+                       if (*end || ipmask->family == AF_UNSPEC || (ipmask->family == AF_INET6 && ipmask->cidr > 128) || (ipmask->family == AF_INET && ipmask->cidr > 32))
+                               break;
+                       ++peer->num_ipmasks;
+               } else if (peer && !strcmp(key, "last_handshake_time_sec"))
+                       peer->last_handshake_time.tv_sec = NUM(0xffffffffffffffffULL);
+               else if (peer && !strcmp(key, "last_handshake_time_nsec"))
+                       peer->last_handshake_time.tv_usec = NUM(0xffffffffffffffffULL) / 1000;
+               else if (peer && !strcmp(key, "rx_bytes"))
+                       peer->rx_bytes = NUM(0xffffffffffffffffULL);
+               else if (peer && !strcmp(key, "tx_bytes"))
+                       peer->tx_bytes = NUM(0xffffffffffffffffULL);
+               else if (!strcmp(key, "errno"))
+                       ret = -NUM(0x7fffffffU);
+               else
+                       break;
        }
-       *dev = (struct wgdevice *)buffer;
-       close(fd);
+       ret = -EPROTO;
+err:
+       free(key);
+       free(*out);
+       *out = NULL;
+       fclose(f);
        errno = -ret;
        return ret;
 
 }
-#undef READ_BYTES
+#undef ADD
+#undef NUM
+#undef KEY
 
 #ifdef __linux__
+static int check_version_magic(struct wgdevice *device, int ret)
+{
+       if (ret == -EPROTO || (!ret && device->version_magic != WG_API_VERSION_MAGIC)) {
+               fprintf(stderr, "This program was built for a different version of WireGuard than\nwhat is currently running. Either this version of wg(8) is out\nof date, or the currently loaded WireGuard module is out of date.\nIf you have just updated your WireGuard installation, you may have\nforgotten to unload the previous running WireGuard module. Try\nrunning `rmmod wireguard` as root, and then try re-adding the interface\nand trying again.\n\n");
+               errno = EPROTO;
+               return -EPROTO;
+       }
+       return ret;
+}
+
 static int parse_linkinfo(const struct nlattr *attr, void *data)
 {
        struct inflatable_buffer *buffer = data;
@@ -295,9 +447,11 @@ static int parse_infomsg(const struct nlattr *attr, void *data)
 static int read_devices_cb(const struct nlmsghdr *nlh, void *data)
 {
        struct inflatable_buffer *buffer = data;
+       int ret;
+
        buffer->good = false;
        buffer->next = NULL;
-       int ret = mnl_attr_parse(nlh, sizeof(struct ifinfomsg), parse_infomsg, data);
+       ret = mnl_attr_parse(nlh, sizeof(struct ifinfomsg), parse_infomsg, data);
        if (ret != MNL_CB_OK)
                return ret;
        ret = add_next_to_inflatable_buffer(buffer);
index 009cd15366df8baeea4ecea9afddfaf5dbd740fd..6cced491ae0cc3bfa590fe299b7b98964990f3eb 100644 (file)
@@ -5,7 +5,7 @@
 #include <ctype.h>
 
 #include "curve25519.h"
-#include "base64.h"
+#include "encoding.h"
 #include "subcommands.h"
 
 int pubkey_main(int argc, char *argv[])
index 7f67dbaac70652987e4431e59d43bf58d656a95d..4eb096ff6d8678254b2fdab833c60a13cd1163ae 100644 (file)
@@ -16,7 +16,7 @@
 #include "ipc.h"
 #include "subcommands.h"
 #include "terminal.h"
-#include "base64.h"
+#include "encoding.h"
 #include "../uapi.h"
 
 static int peer_cmp(const void *first, const void *second)
index 039abeedf1b4f46c7f179c25c0420a26b88adf82..2453c86074b8c4c5cffcb3d5b4abd018cc32349f 100644 (file)
@@ -10,7 +10,7 @@
 #include <netdb.h>
 
 #include "subcommands.h"
-#include "base64.h"
+#include "encoding.h"
 #include "ipc.h"
 #include "../uapi.h"
 
@@ -79,16 +79,16 @@ int showconf_main(int argc, char *argv[])
                if (peer->endpoint.addr.sa_family == AF_INET || peer->endpoint.addr.sa_family == AF_INET6) {
                        char host[4096 + 1];
                        char service[512 + 1];
-                       static char buf[sizeof(host) + sizeof(service) + 4];
                        socklen_t addr_len = 0;
-                       memset(buf, 0, sizeof(buf));
                        if (peer->endpoint.addr.sa_family == AF_INET)
                                addr_len = sizeof(struct sockaddr_in);
                        else if (peer->endpoint.addr.sa_family == AF_INET6)
                                addr_len = sizeof(struct sockaddr_in6);
                        if (!getnameinfo(&peer->endpoint.addr, addr_len, host, sizeof(host), service, sizeof(service), NI_DGRAM | NI_NUMERICSERV | NI_NUMERICHOST)) {
-                               snprintf(buf, sizeof(buf) - 1, (peer->endpoint.addr.sa_family == AF_INET6 && strchr(host, ':')) ? "[%s]:%s" : "%s:%s", host, service);
-                               printf("Endpoint = %s\n", buf);
+                               if (peer->endpoint.addr.sa_family == AF_INET6 && strchr(host, ':'))
+                                       printf("Endpoint = [%s]:%s\n", host, service);
+                               else
+                                       printf("Endpoint = %s:%s\n", host, service);
                        }
                }