mirror of https://git.zx2c4.com/WireGuard
[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 <aranea@aixah.de>
This commit is contained in:
parent
9a0fc56cdb
commit
f50ef1676f
|
@ -0,0 +1,139 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2019 Luis Ressel <aranea@aixah.de>. All Rights Reserved.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2019 Luis Ressel <aranea@aixah.de>. All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef PEER_NAMES_H
|
||||
#define PEER_NAMES_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
|
@ -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 { <interface> | 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;
|
||||
|
|
Loading…
Reference in New Issue