From f50ef1676fe5861c9071910d2caf64593a28d837 Mon Sep 17 00:00:00 2001 From: Luis Ressel Date: Mon, 25 Mar 2019 14:53:09 +0100 Subject: [WIP] wg: Support human-readable peer names TODO: * Refactor the inflatable_buffer code from ipc.c and use it for both the wgpeer_name array and the names. * ugly_print, dumb_print * Make wgpeer_names part of wgdevice? * Check for dupes? * Test! Signed-off-by: Luis Ressel --- src/tools/peer_names.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++ src/tools/peer_names.h | 29 +++++++++++ src/tools/show.c | 21 ++++++-- 3 files changed, 185 insertions(+), 4 deletions(-) create mode 100644 src/tools/peer_names.c create mode 100644 src/tools/peer_names.h diff --git a/src/tools/peer_names.c b/src/tools/peer_names.c new file mode 100644 index 0000000..37e122d --- /dev/null +++ b/src/tools/peer_names.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Luis Ressel . All Rights Reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "containers.h" +#include "encoding.h" +#include "peer_names.h" + +static bool parse_peer_name(char *line, struct wgpeer_name *slot) +{ + char *name; + size_t len; + + name = strpbrk(line, " \t"); + if (!name) + return false; + *name = '\0'; + + if (!key_from_base64(slot->public_key, line)) + return false; + + len = strlen(++name); + if (name[len - 1] == '\n') + name[len - 1] = '\0'; + slot->name = strdup(name); + return !!slot->name; +} + +static int peer_name_cmp(const void *a, const void *b) +{ + const struct wgpeer_name *x = a, *y = b; + return memcmp(x->public_key, y->public_key, WG_KEY_LEN); +} + +bool peer_names_open(struct wgpeer_names *names, struct wgdevice *device) +{ + size_t max_peers = 1, peers = 0, buf_len = 0, path_len; + struct wgpeer_name *arr, *arr2; + char *buf = NULL, *path; + FILE *f; + + path = getenv("WG_PEER_NAMES"); + if (!path || !path[0]) { + errno = 0; + return false; + } + + path_len = strlen(path); + if (path[path_len - 1] == '/') { + size_t dev_len = strlen(device->name); + char *path2 = malloc(path_len + dev_len + 1); + + if (!path2) + return false; + memcpy(path2, path, path_len); + memcpy(path2 + path_len, device->name, dev_len + 1); + f = fopen(path2, "r"); + free(path2); + } else + f = fopen(path, "r"); + if (!f) + return false; + + arr = malloc(sizeof(struct wgpeer_name)); + if (!arr) + return false; + + while (getline(&buf, &buf_len, f) >= 0) { + if (parse_peer_name(buf, &arr[peers]) && (++peers == max_peers)) { + // TODO: Pulled this overflow check out of my ass, gotta revisit it later + if (SIZE_MAX / (2 * sizeof(struct wgpeer_name)) < max_peers) { + errno = ENOMEM; + return false; + } + max_peers *= 2; + + arr2 = realloc(arr, max_peers * sizeof(struct wgpeer_name)); + if (!arr2) { + free(arr); + return false; + } + arr = arr2; + } + } + free(buf); + + if (!peers) + free(arr); + if ((arr2 = realloc(arr, peers * sizeof(struct wgpeer_name)))) + arr = arr2; + + qsort(arr, peers, sizeof(struct wgpeer_name), peer_name_cmp); + names->len = peers; + names->arr = arr; + return true; +} + +void peer_names_free(struct wgpeer_names *names) +{ + if (!names) + return; + + for (size_t i = 0; i < names->len; ++i) + free(names->arr[i].name); + if (names->len) + free(names->arr); +} + +char *peer_names_get(struct wgpeer_names *names, uint8_t key[static WG_KEY_LEN]) +{ + size_t r, l = 0; + + if (!names || !names->len) + return NULL; + r = names->len - 1; + + while (l <= r) { + size_t m = l + (r - l) / 2; + int cmp = memcmp(key, names->arr[m].public_key, WG_KEY_LEN); + if (!cmp) + return names->arr[m].name; + else if (cmp > 0) + l = m + 1; + else if (!m) + break; + else + r = m - 1; + } + return NULL; +} diff --git a/src/tools/peer_names.h b/src/tools/peer_names.h new file mode 100644 index 0000000..5ba73fe --- /dev/null +++ b/src/tools/peer_names.h @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Luis Ressel . All Rights Reserved. + */ + +#ifndef PEER_NAMES_H +#define PEER_NAMES_H + +#include +#include +#include + +#include "containers.h" + +struct wgpeer_name { + char *name; + uint8_t public_key[WG_KEY_LEN]; +}; + +struct wgpeer_names { + size_t len; + struct wgpeer_name *arr; +}; + +bool peer_names_open(struct wgpeer_names *names, struct wgdevice *device); +void peer_names_free(struct wgpeer_names *names); +char *peer_names_get(struct wgpeer_names *names, uint8_t key[static WG_KEY_LEN]); + +#endif // PEER_NAMES_H diff --git a/src/tools/show.c b/src/tools/show.c index ff0897d..ca26cc6 100644 --- a/src/tools/show.c +++ b/src/tools/show.c @@ -22,6 +22,7 @@ #include "ipc.h" #include "terminal.h" #include "encoding.h" +#include "peer_names.h" #include "subcommands.h" static int peer_cmp(const void *first, const void *second) @@ -205,8 +206,9 @@ static void show_usage(void) fprintf(stderr, "Usage: %s %s { | all | interfaces } [public-key | private-key | listen-port | fwmark | peers | preshared-keys | endpoints | allowed-ips | latest-handshakes | transfer | persistent-keepalive | dump]\n", PROG_NAME, COMMAND_NAME); } -static void pretty_print(struct wgdevice *device) +static void pretty_print(struct wgdevice *device, struct wgpeer_names *names) { + char *name; struct wgpeer *peer; struct wgallowedip *allowedip; @@ -226,6 +228,8 @@ static void pretty_print(struct wgdevice *device) } for_each_wgpeer(device, peer) { terminal_printf(TERMINAL_FG_YELLOW TERMINAL_BOLD "peer" TERMINAL_RESET ": " TERMINAL_FG_YELLOW "%s" TERMINAL_RESET "\n", key(peer->public_key)); + if ((name = peer_names_get(names, peer->public_key))) + terminal_printf(" " TERMINAL_BOLD "name" TERMINAL_RESET ": %s\n", name); if (peer->flags & WGPEER_HAS_PRESHARED_KEY) terminal_printf(" " TERMINAL_BOLD "preshared key" TERMINAL_RESET ": %s\n", masked_key(peer->preshared_key)); if (peer->endpoint.addr.sa_family == AF_INET || peer->endpoint.addr.sa_family == AF_INET6) @@ -398,6 +402,7 @@ int show_main(int argc, char *argv[]) interface = interfaces; for (size_t len = 0; (len = strlen(interface)); interface += len + 1) { struct wgdevice *device = NULL; + struct wgpeer_names names; if (ipc_get_device(&device, interface) < 0) { fprintf(stderr, "Unable to access interface %s: %s\n", interface, strerror(errno)); @@ -410,9 +415,12 @@ int show_main(int argc, char *argv[]) break; } } else { - pretty_print(device); + if (!peer_names_open(&names, device) && errno) + perror("peer_names_open"); + pretty_print(device, &names); if (strlen(interface + len + 1)) printf("\n"); + peer_names_free(&names); } free_wgdevice(device); ret = 0; @@ -438,6 +446,7 @@ int show_main(int argc, char *argv[]) show_usage(); else { struct wgdevice *device = NULL; + struct wgpeer_names names; if (ipc_get_device(&device, argv[1]) < 0) { perror("Unable to access interface"); @@ -446,8 +455,12 @@ int show_main(int argc, char *argv[]) if (argc == 3) { if (!ugly_print(device, argv[2], false)) ret = 1; - } else - pretty_print(device); + } else { + if (!peer_names_open(&names, device) && errno) + perror("peer_names_open"); + pretty_print(device, &names); + peer_names_free(&names); + } free_wgdevice(device); } return ret; -- cgit v1.2.3-59-g8ed1b