UDP-WG Implementation
Loading...
Searching...
No Matches
shared.h
1#pragma once
2
3#include <arpa/inet.h>
4#include <iostream>
5#include <random>
6#include <sys/ioctl.h>
7#include <fstream>
8#include <atomic>
9#include <thread>
10#include <sstream>
11
12#include "crypto.h"
13
19namespace shared {
20
21 // To make it more obvious what we're using these for.
22 using port_t = uint16_t;
23 using address_t = uint32_t;
24 using fd_t = int32_t;
25 using con_t = uint64_t;
26
27
28 // WireGuard uses the first byte of each Packet to define what it's for.
29 // We borrow this for our own internal packets.
30 using tag = uint8_t;
31 tag NONE = 0x0, WG_HANDSHAKE = 0x1, SYS = 0x2, WG_COOKIE = 0x3, WG_TRANSPORT = 0x4;
32
33
34 // A connection contains both an address, and a port.
35 // For hash maps, we want a single value, but when
36 // constructing packets we want an address and port.
37 // We can be clever about this, by simply making it
38 // a union, one member being a 64 bit struct with the a,p,
39 // and another being a 64 bit number. C will automatically
40 // break the 64 bit value up for the former, or just leave
41 // it as-is. Unions are really cool, and I sincerely regret
42 // not implementing the AES State in AES-DH as an array of 4 unions,
43 // with one element being a uin32_t to get the entire value, and
44 // the other a series of 4 uint8_t's.
45 typedef union {
46 struct {
47 address_t a = 0;
48 port_t p = 0;
49 } pair;
50 con_t num = 0;
51 } connection;
52
53
58 std::string connection_string(const connection& c) {
59 return std::to_string(c.pair.a) + ":" + std::to_string(c.pair.p);
60 }
61
62
73
74 // Get the time.
75 crypto::string time = 12;
76 timespec ts;
77 clock_gettime(CLOCK_REALTIME, &ts);
78 uint64_t seconds = ts.tv_sec; uint32_t nano = ts.tv_nsec;
79
80 // Copy to the right sections.
81 memcpy(time.bytes(), reinterpret_cast<char*>(&seconds), sizeof(uint64_t));
82 memcpy(time.bytes() + 8, reinterpret_cast<char*>(&nano), sizeof(uint32_t));
83
84 return time;
85 }
86
87
95
96 // Get the seconds, compare them
97 const uint64_t
98 sec_a = *reinterpret_cast<const uint64_t*>(a.bytes()),
99 sec_b = *reinterpret_cast<const uint64_t*>(b.bytes());
100 if (sec_a > sec_b) return true;
101 if (sec_a < sec_b) return false;
102
103 // If the seconds are the same, match the nanoseconds.
104 const uint32_t
105 nan_a = *reinterpret_cast<const uint32_t*>(a.bytes() + 8),
106 nan_b = *reinterpret_cast<const uint32_t*>(b.bytes() + 8);
107
108 // If the seconds+nano are equal, we return true.
109 if (nan_a >= nan_b) return true;
110 return false;
111 }
112
113
121 size_t TimestampDiff(const crypto::string& a, const crypto::string& b = Timestamp()) {
122 uint64_t as = *reinterpret_cast<const uint64_t*>(a.bytes()), bs = *reinterpret_cast<const uint64_t*>(b.bytes());
123 return as < bs ? bs - as : as - bs;
124 }
125
126
131 uint64_t TimeSeconds() {
132 timespec ts;
133 clock_gettime(CLOCK_REALTIME, &ts);
134 uint64_t seconds = ts.tv_sec; uint32_t nano = ts.tv_nsec;
135 return seconds;
136 }
137
138
139 // These are our default source port/address. The user can change them
140 // using command line arguments.
141 connection self = {.pair {.a = inet_addr("127.0.0.1"), .p = 5000}};
142
143
159 typedef struct sys_packet {
160 uint8_t tag = SYS;
161 unsigned char pub[32] = {0};
162 connection source = {};
163 bool rekey = false;
165
166
170 typedef enum {DEAD, INIT, READY, TERMINATE} status;
171
172 // Flags shared by the main+network threads.
173 std::atomic<status> stat = DEAD; // Terminate all threads
174 std::atomic<bool> verbose = false; // Display verbose information.
175 std::atomic<bool> log = false; // Log information to a file
176 std::string logfile = "main.log"; // Where to log information.
177
178 // RNG
179 std::random_device dev;
180 std::mt19937 rng(dev());
181
182 // A lock to ensure the main/network don't conflict in output.
183 std::mutex io_lock;
184
185 // Color coded messages for output.
186 typedef enum {STANDARD, INFO, WARN, ERROR, SUCCESS} message_type;
187 constexpr char
188 END[] = "\e[0m", RED[] = "\e[31m", YELLOW[] = "\e[1;33m",
189 GREEN[] = "\e[32m", BLUE[] = "\e[34m", VIOLET[] = "\e[35m";
190
191
198 void sleep(const size_t& milliseconds=100) {std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));}
199
200
208 void output(const std::string& message, const std::string& thread="SYS", const message_type& t=STANDARD) {
209 std::lock_guard<std::mutex> guard(io_lock);
210
211 // If logging, log non-standard output.
212 if (log && t != STANDARD) {
213 auto outfile = std::ofstream(logfile, std::ios_base::app);
214 outfile << TimeSeconds() << ": ";
215 outfile << thread << ": " << message << std::endl;
216 outfile.close();
217 }
218
219 // Handle our cases.
220 if (t == STANDARD) std::cout << message << std::endl;
221 else if (t == ERROR) std::cerr << RED << thread << "! " << message << END << std::endl;
222 else if (t == SUCCESS) std::cerr << GREEN << thread << ": " << message << END << std::endl;
223
224 // Only display INFO and WARN if verbose logging.
225 else if (verbose) {
226 if (t == INFO) std::cout << thread << ": " << message << std::endl;
227 else if (t == WARN) std::cout << YELLOW << thread << ": " << message << END << std::endl;
228 }
229 }
230
231
232 // A macro to prompt, then return from a function.
233 #define prompt_return(msg) {prompt(msg); return;}
234 // A macro to prompt, then break from a loop/switch
235 #define prompt_break(msg) {prompt(msg); break;}
236 // A macro to promptly, then continue from a loop
237 #define prompt_continue(msg) {prompt(msg); continue;}
238
239
244 inline void clear() {output("\033[2J\033[1;1H");}
245
246
257 template <typename T = bool> inline T input(const std::string& title, const T& error_ret = T()) {
258 T ret;
259
260 // Print the title, get the input.
261 output(title);
262 std::cin >> ret;
263
264 // If it failed, clear the buffer and set the error return.
265 auto f = std::cin.fail();
266 if (f) {
267 std::cin.clear();
268 ret = error_ret;
269 }
270
271 // Skip past whatever garbage the user may have added.
272 std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
273
274 // Return.
275 return ret;
276 }
277
278
284 inline void prompt(const std::string& message) {
285 output(message);
286 output("Press Enter to Continue");
287 getchar();
288 }
289
290
291 // If we're going to have a dynamically updating main menu, we might as well have some fun with it ;)
292 std::vector<std::vector<std::string>> titles = {
293 {
294 "UDP-WG",
295 },
296 {
297 " __ ______ ____ _ ________",
298 " / / / / __ \\/ __ \\ | | / / ____/",
299 " / / / / / / / /_/ /____| | /| / / / __",
300 "/ /_/ / /_/ / ____/_____/ |/ |/ / /_/ /",
301 "\\____/_____/_/ |__/|__/\\____/"
302 },
303 {
304 "__/\\\\\\________/\\\\\\__/\\\\\\\\\\\\\\\\\\\\\\\\_____/\\\\\\\\\\\\\\\\\\\\\\\\\\__________________/\\\\\\______________/\\\\\\_____/\\\\\\\\\\\\\\\\\\\\\\\\_ ",
305 " _\\/\\\\\\_______\\/\\\\\\_\\/\\\\\\////////\\\\\\__\\/\\\\\\/////////\\\\\\_______________\\/\\\\\\_____________\\/\\\\\\___/\\\\\\//////////__ ",
306 " _\\/\\\\\\_______\\/\\\\\\_\\/\\\\\\______\\//\\\\\\_\\/\\\\\\_______\\/\\\\\\_______________\\/\\\\\\_____________\\/\\\\\\__/\\\\\\_____________ ",
307 " _\\/\\\\\\_______\\/\\\\\\_\\/\\\\\\_______\\/\\\\\\_\\/\\\\\\\\\\\\\\\\\\\\\\\\\\/___/\\\\\\\\\\\\\\\\\\\\\\_\\//\\\\\\____/\\\\\\____/\\\\\\__\\/\\\\\\____/\\\\\\\\\\\\\\_ ",
308 " _\\/\\\\\\_______\\/\\\\\\_\\/\\\\\\_______\\/\\\\\\_\\/\\\\\\/////////____\\///////////___\\//\\\\\\__/\\\\\\\\\\__/\\\\\\___\\/\\\\\\___\\/////\\\\\\_ ",
309 " _\\/\\\\\\_______\\/\\\\\\_\\/\\\\\\_______\\/\\\\\\_\\/\\\\\\_____________________________\\//\\\\\\/\\\\\\/\\\\\\/\\\\\\____\\/\\\\\\_______\\/\\\\\\_ ",
310 " _\\//\\\\\\______/\\\\\\__\\/\\\\\\_______/\\\\\\__\\/\\\\\\______________________________\\//\\\\\\\\\\\\//\\\\\\\\\\_____\\/\\\\\\_______\\/\\\\\\_ ",
311 " __\\///\\\\\\\\\\\\\\\\\\/___\\/\\\\\\\\\\\\\\\\\\\\\\\\/___\\/\\\\\\_______________________________\\//\\\\\\__\\//\\\\\\______\\//\\\\\\\\\\\\\\\\\\\\\\\\/__ ",
312 " ____\\/////////_____\\////////////_____\\///_________________________________\\///____\\///________\\////////////____",
313 },
314 {
315 "$$\\ $$\\ $$$$$$$\\ $$$$$$$\\ $$\\ $$\\ $$$$$$\\ ",
316 "$$ | $$ |$$ __$$\\ $$ __$$\\ $$ | $\\ $$ |$$ __$$\\ ",
317 "$$ | $$ |$$ | $$ |$$ | $$ | $$ |$$$\\ $$ |$$ / \\__|",
318 "$$ | $$ |$$ | $$ |$$$$$$$ |$$$$$$\\ $$ $$ $$\\$$ |$$ |$$$$\\",
319 "$$ | $$ |$$ | $$ |$$ ____/ \\______|$$$$ _$$$$ |$$ |\\_$$ |",
320 "$$ | $$ |$$ | $$ |$$ | $$$ / \\$$$ |$$ | $$ |",
321 "\\$$$$$$ |$$$$$$$ |$$ | $$ / \\$$ |\\$$$$$$ |",
322 " \\______/ \\_______/ \\__| \\__/ \\__| \\______/",
323 },
324 {
325 "888 888 8888888b. 8888888b. 888 888 .d8888b.",
326 "888 888 888 \"Y88b 888 Y88b 888 o 888 d88P Y88b",
327 "888 888 888 888 888 888 888 d8b 888 888 888",
328 "888 888 888 888 888 d88P 888 d888b 888 888",
329 "888 888 888 888 8888888P\" 888d88888b888 888 88888",
330 "888 888 888 888 888 888888 88888P Y88888 888 888",
331 "Y88b. .d88P 888 .d88P 888 8888P Y8888 Y88b d88P",
332 " \"Y88888P\" 8888888P\" 888 888P Y888 \"Y8888P88",
333 },
334 };
335
336 size_t title = 0, mode = 0;
337
338 // Pick a color cycle.
339 void pick_mode() {
340 auto old = mode;
341 do {
342
343 // Once we have a connection, you don't get boring anymore.
344 std::uniform_int_distribution<std::mt19937::result_type> mode_dist(1,6);
345 mode = mode_dist(rng);
346 } while (mode == old);
347 }
348
349 // Pick a title.
350 void pick_title() {
351 // Otherwise randomly choose one that will fit in the current terminal, but make sure we
352 // don't choose the one we already have!
353 auto old = title;
354 size_t retry = 0;
355
356 struct winsize w;
357 ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
358 auto width = w.ws_col;
359
360 do {
361 if (retry == 100) title = 0;
362 std::uniform_int_distribution<std::mt19937::result_type> title_dist(0,titles.size() - 1);
363 title = title_dist(rng);
364 ++retry;
365 } while (titles[title][0].length() > width || title == old);
366 }
367
368 // Print the title.
369 std::string print_title(const uint64_t& cycle) {
370 std::stringstream ret;
371 std::vector<std::string> lookup = {RED, YELLOW, GREEN, BLUE, VIOLET};
372
373 for (size_t x = 0; x < titles[title].size(); ++x) {
374 for (size_t y = 0; y < titles[title][x].length(); ++y) {
375 size_t h = titles[title][x].length(), v = titles[title].size();
376 switch (mode) {
377 case 0: break;
378 case 1: ret << lookup[(x + y + cycle) % 5]; break;
379 case 2: ret << lookup[(x + cycle) % 5]; break;
380 case 3: ret << lookup[(y + cycle) % 5]; break;
381 case 4: ret << lookup[((v - x) + (h - y) + cycle) % 5]; break;
382 case 5: ret << lookup[((v - x) + cycle) % 5]; break;
383 case 6: ret << lookup[((h - y) + cycle) % 5]; break;
384 default: break;
385 }
386 ret << titles[title][x][y];
387 }
388 ret << END << '\n';
389 }
390 return ret.str();
391 }
392}
A cryptographically secure string.
Definition crypto.h:63
unsigned char * bytes()
Return a mutable byte array that can be directly manipulated.
Definition crypto.h:220
The shared namespace.
Definition shared.h:19
void sleep(const size_t &milliseconds=100)
Sleep.
Definition shared.h:198
size_t TimestampDiff(const crypto::string &a, const crypto::string &b=Timestamp())
Return the time between each timestamp in seconds.
Definition shared.h:121
bool TimestampGreater(const crypto::string &a, const crypto::string &b)
Compares two timestamps.
Definition shared.h:94
T input(const std::string &title, const T &error_ret=T())
std::cin can be a little difficult to use, particularly handling bad input. This sanitized it.
Definition shared.h:257
void output(const std::string &message, const std::string &thread="SYS", const message_type &t=STANDARD)
Output to STDOUT, thread safe.
Definition shared.h:208
struct shared::sys_packet sys_packet
A system packet.
std::string connection_string(const connection &c)
Get a string representation of the connection.
Definition shared.h:58
crypto::string Timestamp()
Get the current TAI64N timestamp.
Definition shared.h:72
uint64_t TimeSeconds()
Get the current UNIX timestamp.
Definition shared.h:131
void prompt(const std::string &message)
Prompt the user and wait until they have confirmed it.
Definition shared.h:284
status
Status used to communicate between Main and Network Threads.
Definition shared.h:170
void clear()
Clear the screen.
Definition shared.h:244
A system packet.
Definition shared.h:159
Definition shared.h:45