1adf37648SKyle Evans // SPDX-License-Identifier: GPL-2.0 OR MIT 2adf37648SKyle Evans /* 3adf37648SKyle Evans * Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. 4adf37648SKyle Evans */ 5adf37648SKyle Evans 6adf37648SKyle Evans #include <arpa/inet.h> 7adf37648SKyle Evans #include <inttypes.h> 8adf37648SKyle Evans #include <netinet/in.h> 9adf37648SKyle Evans #include <sys/socket.h> 10adf37648SKyle Evans #include <net/if.h> 11adf37648SKyle Evans #include <stdbool.h> 12adf37648SKyle Evans #include <stddef.h> 13adf37648SKyle Evans #include <stdint.h> 14adf37648SKyle Evans #include <stdlib.h> 15adf37648SKyle Evans #include <stdio.h> 16adf37648SKyle Evans #include <string.h> 17adf37648SKyle Evans #include <errno.h> 18adf37648SKyle Evans #include <time.h> 19adf37648SKyle Evans #include <netdb.h> 20adf37648SKyle Evans 21adf37648SKyle Evans #include "containers.h" 22adf37648SKyle Evans #include "ipc.h" 23adf37648SKyle Evans #include "terminal.h" 24adf37648SKyle Evans #include "encoding.h" 25adf37648SKyle Evans #include "subcommands.h" 26adf37648SKyle Evans 27adf37648SKyle Evans static int peer_cmp(const void *first, const void *second) 28adf37648SKyle Evans { 29adf37648SKyle Evans time_t diff; 30*2cb43631SKyle Evans const struct wgpeer *a = *(void *const *)first, *b = *(void *const *)second; 31adf37648SKyle Evans 32adf37648SKyle Evans if (!a->last_handshake_time.tv_sec && !a->last_handshake_time.tv_nsec && (b->last_handshake_time.tv_sec || b->last_handshake_time.tv_nsec)) 33adf37648SKyle Evans return 1; 34adf37648SKyle Evans if (!b->last_handshake_time.tv_sec && !b->last_handshake_time.tv_nsec && (a->last_handshake_time.tv_sec || a->last_handshake_time.tv_nsec)) 35adf37648SKyle Evans return -1; 36adf37648SKyle Evans diff = a->last_handshake_time.tv_sec - b->last_handshake_time.tv_sec; 37adf37648SKyle Evans if (!diff) 38adf37648SKyle Evans diff = a->last_handshake_time.tv_nsec - b->last_handshake_time.tv_nsec; 39adf37648SKyle Evans if (diff < 0) 40adf37648SKyle Evans return 1; 41adf37648SKyle Evans if (diff > 0) 42adf37648SKyle Evans return -1; 43adf37648SKyle Evans return 0; 44adf37648SKyle Evans } 45adf37648SKyle Evans 46adf37648SKyle Evans /* This, hilariously, is not the right way to sort a linked list... */ 47adf37648SKyle Evans static void sort_peers(struct wgdevice *device) 48adf37648SKyle Evans { 49adf37648SKyle Evans size_t peer_count = 0, i = 0; 50adf37648SKyle Evans struct wgpeer *peer, **peers; 51adf37648SKyle Evans 52adf37648SKyle Evans for_each_wgpeer(device, peer) 53adf37648SKyle Evans ++peer_count; 54adf37648SKyle Evans if (!peer_count) 55adf37648SKyle Evans return; 56adf37648SKyle Evans peers = calloc(peer_count, sizeof(*peers)); 57adf37648SKyle Evans if (!peers) 58adf37648SKyle Evans return; 59adf37648SKyle Evans for_each_wgpeer(device, peer) 60adf37648SKyle Evans peers[i++] = peer; 61adf37648SKyle Evans qsort(peers, peer_count, sizeof(*peers), peer_cmp); 62adf37648SKyle Evans device->first_peer = peers[0]; 63adf37648SKyle Evans for (i = 1; i < peer_count; ++i) { 64adf37648SKyle Evans peers[i - 1]->next_peer = peers[i]; 65adf37648SKyle Evans } 66adf37648SKyle Evans peers[peer_count - 1]->next_peer = NULL; 67adf37648SKyle Evans free(peers); 68adf37648SKyle Evans } 69adf37648SKyle Evans 70adf37648SKyle Evans static char *key(const uint8_t key[static WG_KEY_LEN]) 71adf37648SKyle Evans { 72adf37648SKyle Evans static char base64[WG_KEY_LEN_BASE64]; 73adf37648SKyle Evans 74adf37648SKyle Evans key_to_base64(base64, key); 75adf37648SKyle Evans return base64; 76adf37648SKyle Evans } 77adf37648SKyle Evans 78adf37648SKyle Evans static const char *maybe_key(const uint8_t maybe_key[static WG_KEY_LEN], bool have_it) 79adf37648SKyle Evans { 80adf37648SKyle Evans if (!have_it) 81adf37648SKyle Evans return "(none)"; 82adf37648SKyle Evans return key(maybe_key); 83adf37648SKyle Evans } 84adf37648SKyle Evans 85adf37648SKyle Evans static const char *masked_key(const uint8_t masked_key[static WG_KEY_LEN]) 86adf37648SKyle Evans { 87adf37648SKyle Evans const char *var = getenv("WG_HIDE_KEYS"); 88adf37648SKyle Evans 89adf37648SKyle Evans if (var && !strcmp(var, "never")) 90adf37648SKyle Evans return key(masked_key); 91adf37648SKyle Evans return "(hidden)"; 92adf37648SKyle Evans } 93adf37648SKyle Evans 94adf37648SKyle Evans static char *ip(const struct wgallowedip *ip) 95adf37648SKyle Evans { 96adf37648SKyle Evans static char buf[INET6_ADDRSTRLEN + 1]; 97adf37648SKyle Evans 98adf37648SKyle Evans memset(buf, 0, INET6_ADDRSTRLEN + 1); 99adf37648SKyle Evans if (ip->family == AF_INET) 100adf37648SKyle Evans inet_ntop(AF_INET, &ip->ip4, buf, INET6_ADDRSTRLEN); 101adf37648SKyle Evans else if (ip->family == AF_INET6) 102adf37648SKyle Evans inet_ntop(AF_INET6, &ip->ip6, buf, INET6_ADDRSTRLEN); 103adf37648SKyle Evans return buf; 104adf37648SKyle Evans } 105adf37648SKyle Evans 106adf37648SKyle Evans static char *endpoint(const struct sockaddr *addr) 107adf37648SKyle Evans { 108adf37648SKyle Evans char host[4096 + 1]; 109adf37648SKyle Evans char service[512 + 1]; 110adf37648SKyle Evans static char buf[sizeof(host) + sizeof(service) + 4]; 111adf37648SKyle Evans int ret; 112adf37648SKyle Evans socklen_t addr_len = 0; 113adf37648SKyle Evans 114adf37648SKyle Evans memset(buf, 0, sizeof(buf)); 115adf37648SKyle Evans if (addr->sa_family == AF_INET) 116adf37648SKyle Evans addr_len = sizeof(struct sockaddr_in); 117adf37648SKyle Evans else if (addr->sa_family == AF_INET6) 118adf37648SKyle Evans addr_len = sizeof(struct sockaddr_in6); 119adf37648SKyle Evans 120adf37648SKyle Evans ret = getnameinfo(addr, addr_len, host, sizeof(host), service, sizeof(service), NI_DGRAM | NI_NUMERICSERV | NI_NUMERICHOST); 121adf37648SKyle Evans if (ret) { 122adf37648SKyle Evans strncpy(buf, gai_strerror(ret), sizeof(buf) - 1); 123adf37648SKyle Evans buf[sizeof(buf) - 1] = '\0'; 124adf37648SKyle Evans } else 125adf37648SKyle Evans snprintf(buf, sizeof(buf), (addr->sa_family == AF_INET6 && strchr(host, ':')) ? "[%s]:%s" : "%s:%s", host, service); 126adf37648SKyle Evans return buf; 127adf37648SKyle Evans } 128adf37648SKyle Evans 129adf37648SKyle Evans static size_t pretty_time(char *buf, const size_t len, unsigned long long left) 130adf37648SKyle Evans { 131adf37648SKyle Evans size_t offset = 0; 132adf37648SKyle Evans unsigned long long years, days, hours, minutes, seconds; 133adf37648SKyle Evans 134adf37648SKyle Evans years = left / (365 * 24 * 60 * 60); 135adf37648SKyle Evans left = left % (365 * 24 * 60 * 60); 136adf37648SKyle Evans days = left / (24 * 60 * 60); 137adf37648SKyle Evans left = left % (24 * 60 * 60); 138adf37648SKyle Evans hours = left / (60 * 60); 139adf37648SKyle Evans left = left % (60 * 60); 140adf37648SKyle Evans minutes = left / 60; 141adf37648SKyle Evans seconds = left % 60; 142adf37648SKyle Evans 143adf37648SKyle Evans if (years) 144adf37648SKyle Evans offset += snprintf(buf + offset, len - offset, "%s%llu " TERMINAL_FG_CYAN "year%s" TERMINAL_RESET, offset ? ", " : "", years, years == 1 ? "" : "s"); 145adf37648SKyle Evans if (days) 146adf37648SKyle Evans offset += snprintf(buf + offset, len - offset, "%s%llu " TERMINAL_FG_CYAN "day%s" TERMINAL_RESET, offset ? ", " : "", days, days == 1 ? "" : "s"); 147adf37648SKyle Evans if (hours) 148adf37648SKyle Evans offset += snprintf(buf + offset, len - offset, "%s%llu " TERMINAL_FG_CYAN "hour%s" TERMINAL_RESET, offset ? ", " : "", hours, hours == 1 ? "" : "s"); 149adf37648SKyle Evans if (minutes) 150adf37648SKyle Evans offset += snprintf(buf + offset, len - offset, "%s%llu " TERMINAL_FG_CYAN "minute%s" TERMINAL_RESET, offset ? ", " : "", minutes, minutes == 1 ? "" : "s"); 151adf37648SKyle Evans if (seconds) 152adf37648SKyle Evans offset += snprintf(buf + offset, len - offset, "%s%llu " TERMINAL_FG_CYAN "second%s" TERMINAL_RESET, offset ? ", " : "", seconds, seconds == 1 ? "" : "s"); 153adf37648SKyle Evans 154adf37648SKyle Evans return offset; 155adf37648SKyle Evans } 156adf37648SKyle Evans 157adf37648SKyle Evans static char *ago(const struct timespec64 *t) 158adf37648SKyle Evans { 159adf37648SKyle Evans static char buf[1024]; 160adf37648SKyle Evans size_t offset; 161adf37648SKyle Evans time_t now = time(NULL); 162adf37648SKyle Evans 163adf37648SKyle Evans if (now == t->tv_sec) 164adf37648SKyle Evans strncpy(buf, "Now", sizeof(buf) - 1); 165adf37648SKyle Evans else if (now < t->tv_sec) 166adf37648SKyle Evans strncpy(buf, "(" TERMINAL_FG_RED "System clock wound backward; connection problems may ensue." TERMINAL_RESET ")", sizeof(buf) - 1); 167adf37648SKyle Evans else { 168adf37648SKyle Evans offset = pretty_time(buf, sizeof(buf), now - t->tv_sec); 169adf37648SKyle Evans strncpy(buf + offset, " ago", sizeof(buf) - offset - 1); 170adf37648SKyle Evans } 171adf37648SKyle Evans buf[sizeof(buf) - 1] = '\0'; 172adf37648SKyle Evans 173adf37648SKyle Evans return buf; 174adf37648SKyle Evans } 175adf37648SKyle Evans 176adf37648SKyle Evans static char *every(uint16_t seconds) 177adf37648SKyle Evans { 178adf37648SKyle Evans static char buf[1024] = "every "; 179adf37648SKyle Evans 180adf37648SKyle Evans pretty_time(buf + strlen("every "), sizeof(buf) - strlen("every ") - 1, seconds); 181adf37648SKyle Evans return buf; 182adf37648SKyle Evans } 183adf37648SKyle Evans 184adf37648SKyle Evans static char *bytes(uint64_t b) 185adf37648SKyle Evans { 186adf37648SKyle Evans static char buf[1024]; 187adf37648SKyle Evans 188adf37648SKyle Evans if (b < 1024ULL) 189adf37648SKyle Evans snprintf(buf, sizeof(buf), "%u " TERMINAL_FG_CYAN "B" TERMINAL_RESET, (unsigned int)b); 190adf37648SKyle Evans else if (b < 1024ULL * 1024ULL) 191adf37648SKyle Evans snprintf(buf, sizeof(buf), "%.2f " TERMINAL_FG_CYAN "KiB" TERMINAL_RESET, (double)b / 1024); 192adf37648SKyle Evans else if (b < 1024ULL * 1024ULL * 1024ULL) 193adf37648SKyle Evans snprintf(buf, sizeof(buf), "%.2f " TERMINAL_FG_CYAN "MiB" TERMINAL_RESET, (double)b / (1024 * 1024)); 194adf37648SKyle Evans else if (b < 1024ULL * 1024ULL * 1024ULL * 1024ULL) 195adf37648SKyle Evans snprintf(buf, sizeof(buf), "%.2f " TERMINAL_FG_CYAN "GiB" TERMINAL_RESET, (double)b / (1024 * 1024 * 1024)); 196adf37648SKyle Evans else 197adf37648SKyle Evans snprintf(buf, sizeof(buf), "%.2f " TERMINAL_FG_CYAN "TiB" TERMINAL_RESET, (double)b / (1024 * 1024 * 1024) / 1024); 198adf37648SKyle Evans 199adf37648SKyle Evans return buf; 200adf37648SKyle Evans } 201adf37648SKyle Evans 202adf37648SKyle Evans static const char *COMMAND_NAME; 203adf37648SKyle Evans static void show_usage(void) 204adf37648SKyle Evans { 205adf37648SKyle Evans 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); 206adf37648SKyle Evans } 207adf37648SKyle Evans 208adf37648SKyle Evans static void pretty_print(struct wgdevice *device) 209adf37648SKyle Evans { 210adf37648SKyle Evans struct wgpeer *peer; 211adf37648SKyle Evans struct wgallowedip *allowedip; 212adf37648SKyle Evans 213adf37648SKyle Evans terminal_printf(TERMINAL_RESET); 214adf37648SKyle Evans terminal_printf(TERMINAL_FG_GREEN TERMINAL_BOLD "interface" TERMINAL_RESET ": " TERMINAL_FG_GREEN "%s" TERMINAL_RESET "\n", device->name); 215adf37648SKyle Evans if (device->flags & WGDEVICE_HAS_PUBLIC_KEY) 216adf37648SKyle Evans terminal_printf(" " TERMINAL_BOLD "public key" TERMINAL_RESET ": %s\n", key(device->public_key)); 217adf37648SKyle Evans if (device->flags & WGDEVICE_HAS_PRIVATE_KEY) 218adf37648SKyle Evans terminal_printf(" " TERMINAL_BOLD "private key" TERMINAL_RESET ": %s\n", masked_key(device->private_key)); 219adf37648SKyle Evans if (device->listen_port) 220adf37648SKyle Evans terminal_printf(" " TERMINAL_BOLD "listening port" TERMINAL_RESET ": %u\n", device->listen_port); 221adf37648SKyle Evans if (device->fwmark) 222adf37648SKyle Evans terminal_printf(" " TERMINAL_BOLD "fwmark" TERMINAL_RESET ": 0x%x\n", device->fwmark); 223adf37648SKyle Evans if (device->first_peer) { 224adf37648SKyle Evans sort_peers(device); 225adf37648SKyle Evans terminal_printf("\n"); 226adf37648SKyle Evans } 227adf37648SKyle Evans for_each_wgpeer(device, peer) { 228adf37648SKyle Evans terminal_printf(TERMINAL_FG_YELLOW TERMINAL_BOLD "peer" TERMINAL_RESET ": " TERMINAL_FG_YELLOW "%s" TERMINAL_RESET "\n", key(peer->public_key)); 229adf37648SKyle Evans if (peer->flags & WGPEER_HAS_PRESHARED_KEY) 230adf37648SKyle Evans terminal_printf(" " TERMINAL_BOLD "preshared key" TERMINAL_RESET ": %s\n", masked_key(peer->preshared_key)); 231adf37648SKyle Evans if (peer->endpoint.addr.sa_family == AF_INET || peer->endpoint.addr.sa_family == AF_INET6) 232adf37648SKyle Evans terminal_printf(" " TERMINAL_BOLD "endpoint" TERMINAL_RESET ": %s\n", endpoint(&peer->endpoint.addr)); 233adf37648SKyle Evans terminal_printf(" " TERMINAL_BOLD "allowed ips" TERMINAL_RESET ": "); 234adf37648SKyle Evans if (peer->first_allowedip) { 235adf37648SKyle Evans for_each_wgallowedip(peer, allowedip) 236adf37648SKyle Evans terminal_printf("%s" TERMINAL_FG_CYAN "/" TERMINAL_RESET "%u%s", ip(allowedip), allowedip->cidr, allowedip->next_allowedip ? ", " : "\n"); 237adf37648SKyle Evans } else 238adf37648SKyle Evans terminal_printf("(none)\n"); 239adf37648SKyle Evans if (peer->last_handshake_time.tv_sec) 240adf37648SKyle Evans terminal_printf(" " TERMINAL_BOLD "latest handshake" TERMINAL_RESET ": %s\n", ago(&peer->last_handshake_time)); 241adf37648SKyle Evans if (peer->rx_bytes || peer->tx_bytes) { 242adf37648SKyle Evans terminal_printf(" " TERMINAL_BOLD "transfer" TERMINAL_RESET ": "); 243adf37648SKyle Evans terminal_printf("%s received, ", bytes(peer->rx_bytes)); 244adf37648SKyle Evans terminal_printf("%s sent\n", bytes(peer->tx_bytes)); 245adf37648SKyle Evans } 246adf37648SKyle Evans if (peer->persistent_keepalive_interval) 247adf37648SKyle Evans terminal_printf(" " TERMINAL_BOLD "persistent keepalive" TERMINAL_RESET ": %s\n", every(peer->persistent_keepalive_interval)); 248adf37648SKyle Evans if (peer->next_peer) 249adf37648SKyle Evans terminal_printf("\n"); 250adf37648SKyle Evans } 251adf37648SKyle Evans } 252adf37648SKyle Evans 253adf37648SKyle Evans static void dump_print(struct wgdevice *device, bool with_interface) 254adf37648SKyle Evans { 255adf37648SKyle Evans struct wgpeer *peer; 256adf37648SKyle Evans struct wgallowedip *allowedip; 257adf37648SKyle Evans 258adf37648SKyle Evans if (with_interface) 259adf37648SKyle Evans printf("%s\t", device->name); 260adf37648SKyle Evans printf("%s\t", maybe_key(device->private_key, device->flags & WGDEVICE_HAS_PRIVATE_KEY)); 261adf37648SKyle Evans printf("%s\t", maybe_key(device->public_key, device->flags & WGDEVICE_HAS_PUBLIC_KEY)); 262adf37648SKyle Evans printf("%u\t", device->listen_port); 263adf37648SKyle Evans if (device->fwmark) 264adf37648SKyle Evans printf("0x%x\n", device->fwmark); 265adf37648SKyle Evans else 266adf37648SKyle Evans printf("off\n"); 267adf37648SKyle Evans for_each_wgpeer(device, peer) { 268adf37648SKyle Evans if (with_interface) 269adf37648SKyle Evans printf("%s\t", device->name); 270adf37648SKyle Evans printf("%s\t", key(peer->public_key)); 271adf37648SKyle Evans printf("%s\t", maybe_key(peer->preshared_key, peer->flags & WGPEER_HAS_PRESHARED_KEY)); 272adf37648SKyle Evans if (peer->endpoint.addr.sa_family == AF_INET || peer->endpoint.addr.sa_family == AF_INET6) 273adf37648SKyle Evans printf("%s\t", endpoint(&peer->endpoint.addr)); 274adf37648SKyle Evans else 275adf37648SKyle Evans printf("(none)\t"); 276adf37648SKyle Evans if (peer->first_allowedip) { 277adf37648SKyle Evans for_each_wgallowedip(peer, allowedip) 278adf37648SKyle Evans printf("%s/%u%c", ip(allowedip), allowedip->cidr, allowedip->next_allowedip ? ',' : '\t'); 279adf37648SKyle Evans } else 280adf37648SKyle Evans printf("(none)\t"); 281adf37648SKyle Evans printf("%llu\t", (unsigned long long)peer->last_handshake_time.tv_sec); 282adf37648SKyle Evans printf("%" PRIu64 "\t%" PRIu64 "\t", (uint64_t)peer->rx_bytes, (uint64_t)peer->tx_bytes); 283adf37648SKyle Evans if (peer->persistent_keepalive_interval) 284adf37648SKyle Evans printf("%u\n", peer->persistent_keepalive_interval); 285adf37648SKyle Evans else 286adf37648SKyle Evans printf("off\n"); 287adf37648SKyle Evans } 288adf37648SKyle Evans } 289adf37648SKyle Evans 290adf37648SKyle Evans static bool ugly_print(struct wgdevice *device, const char *param, bool with_interface) 291adf37648SKyle Evans { 292adf37648SKyle Evans struct wgpeer *peer; 293adf37648SKyle Evans struct wgallowedip *allowedip; 294adf37648SKyle Evans 295adf37648SKyle Evans if (!strcmp(param, "public-key")) { 296adf37648SKyle Evans if (with_interface) 297adf37648SKyle Evans printf("%s\t", device->name); 298adf37648SKyle Evans printf("%s\n", maybe_key(device->public_key, device->flags & WGDEVICE_HAS_PUBLIC_KEY)); 299adf37648SKyle Evans } else if (!strcmp(param, "private-key")) { 300adf37648SKyle Evans if (with_interface) 301adf37648SKyle Evans printf("%s\t", device->name); 302adf37648SKyle Evans printf("%s\n", maybe_key(device->private_key, device->flags & WGDEVICE_HAS_PRIVATE_KEY)); 303adf37648SKyle Evans } else if (!strcmp(param, "listen-port")) { 304adf37648SKyle Evans if (with_interface) 305adf37648SKyle Evans printf("%s\t", device->name); 306adf37648SKyle Evans printf("%u\n", device->listen_port); 307adf37648SKyle Evans } else if (!strcmp(param, "fwmark")) { 308adf37648SKyle Evans if (with_interface) 309adf37648SKyle Evans printf("%s\t", device->name); 310adf37648SKyle Evans if (device->fwmark) 311adf37648SKyle Evans printf("0x%x\n", device->fwmark); 312adf37648SKyle Evans else 313adf37648SKyle Evans printf("off\n"); 314adf37648SKyle Evans } else if (!strcmp(param, "endpoints")) { 315adf37648SKyle Evans if (with_interface) 316adf37648SKyle Evans printf("%s\t", device->name); 317adf37648SKyle Evans for_each_wgpeer(device, peer) { 318adf37648SKyle Evans printf("%s\t", key(peer->public_key)); 319adf37648SKyle Evans if (peer->endpoint.addr.sa_family == AF_INET || peer->endpoint.addr.sa_family == AF_INET6) 320adf37648SKyle Evans printf("%s\n", endpoint(&peer->endpoint.addr)); 321adf37648SKyle Evans else 322adf37648SKyle Evans printf("(none)\n"); 323adf37648SKyle Evans } 324adf37648SKyle Evans } else if (!strcmp(param, "allowed-ips")) { 325adf37648SKyle Evans for_each_wgpeer(device, peer) { 326adf37648SKyle Evans if (with_interface) 327adf37648SKyle Evans printf("%s\t", device->name); 328adf37648SKyle Evans printf("%s\t", key(peer->public_key)); 329adf37648SKyle Evans if (peer->first_allowedip) { 330adf37648SKyle Evans for_each_wgallowedip(peer, allowedip) 331adf37648SKyle Evans printf("%s/%u%c", ip(allowedip), allowedip->cidr, allowedip->next_allowedip ? ' ' : '\n'); 332adf37648SKyle Evans } else 333adf37648SKyle Evans printf("(none)\n"); 334adf37648SKyle Evans } 335adf37648SKyle Evans } else if (!strcmp(param, "latest-handshakes")) { 336adf37648SKyle Evans for_each_wgpeer(device, peer) { 337adf37648SKyle Evans if (with_interface) 338adf37648SKyle Evans printf("%s\t", device->name); 339adf37648SKyle Evans printf("%s\t%llu\n", key(peer->public_key), (unsigned long long)peer->last_handshake_time.tv_sec); 340adf37648SKyle Evans } 341adf37648SKyle Evans } else if (!strcmp(param, "transfer")) { 342adf37648SKyle Evans for_each_wgpeer(device, peer) { 343adf37648SKyle Evans if (with_interface) 344adf37648SKyle Evans printf("%s\t", device->name); 345adf37648SKyle Evans printf("%s\t%" PRIu64 "\t%" PRIu64 "\n", key(peer->public_key), (uint64_t)peer->rx_bytes, (uint64_t)peer->tx_bytes); 346adf37648SKyle Evans } 347adf37648SKyle Evans } else if (!strcmp(param, "persistent-keepalive")) { 348adf37648SKyle Evans for_each_wgpeer(device, peer) { 349adf37648SKyle Evans if (with_interface) 350adf37648SKyle Evans printf("%s\t", device->name); 351adf37648SKyle Evans if (peer->persistent_keepalive_interval) 352adf37648SKyle Evans printf("%s\t%u\n", key(peer->public_key), peer->persistent_keepalive_interval); 353adf37648SKyle Evans else 354adf37648SKyle Evans printf("%s\toff\n", key(peer->public_key)); 355adf37648SKyle Evans } 356adf37648SKyle Evans } else if (!strcmp(param, "preshared-keys")) { 357adf37648SKyle Evans for_each_wgpeer(device, peer) { 358adf37648SKyle Evans if (with_interface) 359adf37648SKyle Evans printf("%s\t", device->name); 360adf37648SKyle Evans printf("%s\t", key(peer->public_key)); 361adf37648SKyle Evans printf("%s\n", maybe_key(peer->preshared_key, peer->flags & WGPEER_HAS_PRESHARED_KEY)); 362adf37648SKyle Evans } 363adf37648SKyle Evans } else if (!strcmp(param, "peers")) { 364adf37648SKyle Evans for_each_wgpeer(device, peer) { 365adf37648SKyle Evans if (with_interface) 366adf37648SKyle Evans printf("%s\t", device->name); 367adf37648SKyle Evans printf("%s\n", key(peer->public_key)); 368adf37648SKyle Evans } 369adf37648SKyle Evans } else if (!strcmp(param, "dump")) 370adf37648SKyle Evans dump_print(device, with_interface); 371adf37648SKyle Evans else { 372adf37648SKyle Evans fprintf(stderr, "Invalid parameter: `%s'\n", param); 373adf37648SKyle Evans show_usage(); 374adf37648SKyle Evans return false; 375adf37648SKyle Evans } 376adf37648SKyle Evans return true; 377adf37648SKyle Evans } 378adf37648SKyle Evans 379adf37648SKyle Evans int show_main(int argc, const char *argv[]) 380adf37648SKyle Evans { 381adf37648SKyle Evans int ret = 0; 382adf37648SKyle Evans 383adf37648SKyle Evans COMMAND_NAME = argv[0]; 384adf37648SKyle Evans 385adf37648SKyle Evans if (argc > 3) { 386adf37648SKyle Evans show_usage(); 387adf37648SKyle Evans return 1; 388adf37648SKyle Evans } 389adf37648SKyle Evans 390adf37648SKyle Evans if (argc == 1 || !strcmp(argv[1], "all")) { 391adf37648SKyle Evans char *interfaces = ipc_list_devices(), *interface; 392adf37648SKyle Evans 393adf37648SKyle Evans if (!interfaces) { 394adf37648SKyle Evans perror("Unable to list interfaces"); 395adf37648SKyle Evans return 1; 396adf37648SKyle Evans } 397adf37648SKyle Evans ret = !!*interfaces; 398adf37648SKyle Evans interface = interfaces; 399adf37648SKyle Evans for (size_t len = 0; (len = strlen(interface)); interface += len + 1) { 400adf37648SKyle Evans struct wgdevice *device = NULL; 401adf37648SKyle Evans 402adf37648SKyle Evans if (ipc_get_device(&device, interface) < 0) { 403adf37648SKyle Evans fprintf(stderr, "Unable to access interface %s: %s\n", interface, strerror(errno)); 404adf37648SKyle Evans continue; 405adf37648SKyle Evans } 406adf37648SKyle Evans if (argc == 3) { 407adf37648SKyle Evans if (!ugly_print(device, argv[2], true)) { 408adf37648SKyle Evans ret = 1; 409adf37648SKyle Evans free_wgdevice(device); 410adf37648SKyle Evans break; 411adf37648SKyle Evans } 412adf37648SKyle Evans } else { 413adf37648SKyle Evans pretty_print(device); 414adf37648SKyle Evans if (strlen(interface + len + 1)) 415adf37648SKyle Evans printf("\n"); 416adf37648SKyle Evans } 417adf37648SKyle Evans free_wgdevice(device); 418adf37648SKyle Evans ret = 0; 419adf37648SKyle Evans } 420adf37648SKyle Evans free(interfaces); 421adf37648SKyle Evans } else if (!strcmp(argv[1], "interfaces")) { 422adf37648SKyle Evans char *interfaces, *interface; 423adf37648SKyle Evans 424adf37648SKyle Evans if (argc > 2) { 425adf37648SKyle Evans show_usage(); 426adf37648SKyle Evans return 1; 427adf37648SKyle Evans } 428adf37648SKyle Evans interfaces = ipc_list_devices(); 429adf37648SKyle Evans if (!interfaces) { 430adf37648SKyle Evans perror("Unable to list interfaces"); 431adf37648SKyle Evans return 1; 432adf37648SKyle Evans } 433adf37648SKyle Evans interface = interfaces; 434adf37648SKyle Evans for (size_t len = 0; (len = strlen(interface)); interface += len + 1) 435adf37648SKyle Evans printf("%s%c", interface, strlen(interface + len + 1) ? ' ' : '\n'); 436adf37648SKyle Evans free(interfaces); 437adf37648SKyle Evans } else if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help") || !strcmp(argv[1], "help"))) 438adf37648SKyle Evans show_usage(); 439adf37648SKyle Evans else { 440adf37648SKyle Evans struct wgdevice *device = NULL; 441adf37648SKyle Evans 442adf37648SKyle Evans if (ipc_get_device(&device, argv[1]) < 0) { 443adf37648SKyle Evans perror("Unable to access interface"); 444adf37648SKyle Evans return 1; 445adf37648SKyle Evans } 446adf37648SKyle Evans if (argc == 3) { 447adf37648SKyle Evans if (!ugly_print(device, argv[2], false)) 448adf37648SKyle Evans ret = 1; 449adf37648SKyle Evans } else 450adf37648SKyle Evans pretty_print(device); 451adf37648SKyle Evans free_wgdevice(device); 452adf37648SKyle Evans } 453adf37648SKyle Evans return ret; 454adf37648SKyle Evans } 455