/* Copyright (C) 2015-2016 Jason A. Donenfeld . All Rights Reserved. */ #include #include #include #include #include #include #include #include #include #include "config.h" static int fd; static void open_kmem(void) { fd = open("/dev/kmem", O_RDONLY); if (fd < 0) { perror("open(/dev/kmem)"); exit(errno); } } static void read_kmem(void *buffer, size_t len, unsigned long addr) { if (lseek(fd, addr, SEEK_SET) == (off_t)-1) { perror("lseek"); exit(errno); } if (read(fd, buffer, len) != len) { perror("read"); exit(errno); } } static inline unsigned int read_int(unsigned long addr) { unsigned int ret; read_kmem(&ret, sizeof(ret), addr); return ret; } static inline unsigned long read_long(unsigned long addr) { unsigned long ret; read_kmem(&ret, sizeof(ret), addr); return ret; } static unsigned long find_interface(const char *interface) { FILE *f = fopen("/proc/net/udp", "r"); char line[256], *ptr; unsigned long addr = 0; char name[IFNAMSIZ + 1] = { 0 }; if (!f) { perror("fopen(/proc/net/udp)"); exit(errno); } if (!fgets(line, 256, f)) goto out; while (fgets(line, 256, f)) { ptr = line + strlen(line) - 1; while (*--ptr == ' '); while (*--ptr != ' '); while (*(--ptr - 1) != ' '); addr = strtoul(ptr, NULL, 16); if (!addr) continue; addr = read_long(addr + SOCK_DEVICE_OFFSET); if (!addr) continue; read_kmem(name, IFNAMSIZ, addr + DEVICE_NAME_OFFSET); if (!strcmp(name, interface)) goto out; } addr = 0; out: fclose(f); return addr; } static bool print_key(unsigned long key) { unsigned char sending[32], receiving[32]; char sending_b64[45], receiving_b64[45]; unsigned int local_index, remote_index; if (!key) return false; local_index = le32toh(read_int(key + KEY_LOCALID_OFFSET)); remote_index = le32toh(read_int(key + KEY_REMOTEID_OFFSET)); read_kmem(sending, 32, key + KEY_SENDING_OFFSET); read_kmem(receiving, 32, key + KEY_RECEIVING_OFFSET); b64_ntop(sending, 32, sending_b64, 45); b64_ntop(receiving, 32, receiving_b64, 45); printf("0x%08x %s\n", local_index, receiving_b64); printf("0x%08x %s\n", remote_index, sending_b64); return true; } static bool walk_peers(unsigned long peer_head) { unsigned long peer, peer_entry; bool found = false; for (peer_entry = read_long(peer_head); peer_entry != peer_head; peer_entry = read_long(peer_entry)) { peer = peer_entry + PEERS_PEER_OFFSET; if (print_key(read_long(peer + PEER_CURRENTKEY_OFFSET))) found = true; if (print_key(read_long(peer + PEER_PREVIOUSKEY_OFFSET))) found = true; if (print_key(read_long(peer + PEER_NEXTKEY_OFFSET))) found = true; } return found; } int main(int argc, char *argv[]) { unsigned long wireguard_device; if (argc < 2) { fprintf(stderr, "Usage: %s WIREGUARD_INTERFACE\n", argv[0]); return EINVAL; } open_kmem(); wireguard_device = find_interface(argv[1]); if (!wireguard_device) { fprintf(stderr, "Could not find interface %s\n", argv[1]); return EBADSLT; } if (!walk_peers(wireguard_device + DEVICE_PEERS_OFFSET)) { fprintf(stderr, "No active sessions\n"); return ENOKEY; } return 0; }