Initial commit
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
debug
|
||||||
|
release
|
||||||
47
Makefile
Normal file
47
Makefile
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
debug_builddir = $(CURDIR)/debug
|
||||||
|
debug_target = $(debug_builddir)/wg_quicker
|
||||||
|
|
||||||
|
release_builddir = $(CURDIR)/release
|
||||||
|
release_target = $(release_builddir)/wg_quicker
|
||||||
|
|
||||||
|
CFLAGS = -g
|
||||||
|
|
||||||
|
ALL_CFLAGS += -std=c11
|
||||||
|
ALL_CFLAGS += -Wall
|
||||||
|
ALL_CFLAGS += -DLOG_LEVEL_DEBUG
|
||||||
|
ALL_CFLAGS += $(CFLAGS)
|
||||||
|
|
||||||
|
|
||||||
|
source += wg_quicker.c
|
||||||
|
source += lstring.c
|
||||||
|
source += wireguard.c
|
||||||
|
|
||||||
|
include += log.h
|
||||||
|
include += types.h
|
||||||
|
include += lstring.h
|
||||||
|
include += wireguard.h
|
||||||
|
|
||||||
|
|
||||||
|
all: debug
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@rm -Rf $(debug_builddir)
|
||||||
|
@rm -Rf $(release_builddir)
|
||||||
|
|
||||||
|
debug: $(debug_target)
|
||||||
|
|
||||||
|
release: $(release_target)
|
||||||
|
|
||||||
|
.PHONY: all clean run release debug
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$(debug_target): $(source) $(include) Makefile
|
||||||
|
@echo Modified files: $?
|
||||||
|
@mkdir -p $(debug_builddir)
|
||||||
|
@$(CC) -o $@ $(ALL_CFLAGS) $(source)
|
||||||
|
|
||||||
|
$(release_target): $(source) $(include) Makefile
|
||||||
|
@echo Modified files: $?
|
||||||
|
@mkdir -p $(release_builddir)
|
||||||
|
@$(CC) -o $@ -DRELEASE $(ALL_CFLAGS) $(source)
|
||||||
5
README.md
Normal file
5
README.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Wireguard utility programs
|
||||||
|
Utility programs to work with Wireguard VPNs.
|
||||||
|
|
||||||
|
## wg-quicker
|
||||||
|
Utility to create and update wg-quick configuration files.
|
||||||
61
log.h
Normal file
61
log.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
// LCZ libraries v0.1b
|
||||||
|
|
||||||
|
#ifndef _LCZ_LOG_H_
|
||||||
|
#define _LCZ_LOG_H_
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define LOG_COLOR_RESET "\033[0m"
|
||||||
|
#define LOG_COLOR_DEBUG "\033[1;92m"
|
||||||
|
#define LOG_COLOR_INFO "\033[1;96m"
|
||||||
|
#define LOG_COLOR_WARNING "\033[1;93m"
|
||||||
|
#define LOG_COLOR_ERROR "\033[1;91m"
|
||||||
|
|
||||||
|
#define LOG_PREFIX_DEBUG LOG_COLOR_DEBUG "DEBUG" LOG_COLOR_RESET
|
||||||
|
#define LOG_PREFIX_INFO LOG_COLOR_INFO "INFO" LOG_COLOR_RESET
|
||||||
|
#define LOG_PREFIX_WARNING LOG_COLOR_WARNING "WARNING" LOG_COLOR_RESET
|
||||||
|
#define LOG_PREFIX_ERROR LOG_COLOR_ERROR "ERROR" LOG_COLOR_RESET
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef LOG_LEVEL_DEBUG
|
||||||
|
#define LOG_LEVEL_INFO 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LOG_LEVEL_INFO
|
||||||
|
#define LOG_LEVEL_WARN 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LOG_LEVEL_WARN
|
||||||
|
#define LOG_LEVEL_ERROR 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef LOG_LEVEL_DEBUG
|
||||||
|
#define LogDebug(FORMAT_STR, ...) fprintf(stderr, LOG_PREFIX_DEBUG " %s:%d: " FORMAT_STR "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define LogDebug(...) ((void)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LOG_LEVEL_INFO
|
||||||
|
#define LogInfo(FORMAT_STR, ...) fprintf(stderr, LOG_PREFIX_INFO " %s:%d: " FORMAT_STR "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define LogInfo(...) ((void)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LOG_LEVEL_WARN
|
||||||
|
#define LogWarning(FORMAT_STR, ...) fprintf(stderr, LOG_PREFIX_WARNING " %s:%d: " FORMAT_STR "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define LogWarning(...) ((void)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LOG_LEVEL_ERROR
|
||||||
|
#define LogError(FORMAT_STR, ...) fprintf(stderr, LOG_PREFIX_ERROR " %s:%d: " FORMAT_STR "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define LogError(...) ((void)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
301
lstring.c
Normal file
301
lstring.c
Normal file
@@ -0,0 +1,301 @@
|
|||||||
|
// LCZ libraries v0.1b
|
||||||
|
|
||||||
|
#include "lstring.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
// String building / constructors
|
||||||
|
String string_take(char *src)
|
||||||
|
{
|
||||||
|
String res;
|
||||||
|
res.text = src;
|
||||||
|
res.length = rstring_length(src);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
DString dstring_take(char *src)
|
||||||
|
{
|
||||||
|
DString res;
|
||||||
|
res.text = src;
|
||||||
|
res.length = rstring_length(src);
|
||||||
|
res.capacity = res.length;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
String string_copy(const char *src, u64 length)
|
||||||
|
{
|
||||||
|
String res;
|
||||||
|
res.text = malloc(length + 1);
|
||||||
|
assert(res.text != NULL);
|
||||||
|
|
||||||
|
memcpy(res.text, src, length);
|
||||||
|
res.text[length] = '\0';
|
||||||
|
res.length = length;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
DString dstring_copy(const char *src, u64 length)
|
||||||
|
{
|
||||||
|
DString res;
|
||||||
|
res.text = malloc(length + 1);
|
||||||
|
assert(res.text != NULL);
|
||||||
|
|
||||||
|
memcpy(res.text, src, length);
|
||||||
|
res.text[length] = '\0';
|
||||||
|
res.length = length;
|
||||||
|
res.capacity = length;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
DString dstring_new(u64 capacity)
|
||||||
|
{
|
||||||
|
DString res;
|
||||||
|
res.text = malloc(capacity + 1);
|
||||||
|
assert(res.text != NULL);
|
||||||
|
res.text[0] = '\0';
|
||||||
|
res.length = 0;
|
||||||
|
res.capacity = capacity;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// n = number of strings, ... = , const char *src1, u64 length1, ...
|
||||||
|
String string_concat(u32 n, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, n);
|
||||||
|
|
||||||
|
const char *strings[n];
|
||||||
|
u64 sizes[n];
|
||||||
|
u64 tot_len = 0;
|
||||||
|
for (u32 i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
strings[i] = va_arg(ap, const char *);
|
||||||
|
sizes[i] = va_arg(ap, u64);
|
||||||
|
tot_len += sizes[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
String res;
|
||||||
|
res.text = malloc(tot_len + 1);
|
||||||
|
assert(res.text != NULL);
|
||||||
|
res.length = tot_len;
|
||||||
|
char *cursor = res.text;
|
||||||
|
for (u32 i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
memcpy(cursor, strings[i], sizes[i]);
|
||||||
|
cursor += sizes[i];
|
||||||
|
}
|
||||||
|
*cursor = '\0';
|
||||||
|
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
// n = number of strings, ... = , const char *src1, u64 length1, ...
|
||||||
|
DString dstring_concat(u32 n, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
const char *strings[n];
|
||||||
|
u64 sizes[n];
|
||||||
|
u64 tot_len = 0;
|
||||||
|
|
||||||
|
va_start(ap, n);
|
||||||
|
for (u32 i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
strings[i] = va_arg(ap, const char *);
|
||||||
|
sizes[i] = va_arg(ap, u64);
|
||||||
|
tot_len += sizes[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
DString res;
|
||||||
|
res.text = malloc(tot_len + 1);
|
||||||
|
assert(res.text != NULL);
|
||||||
|
res.length = tot_len;
|
||||||
|
res.capacity = tot_len;
|
||||||
|
char *cursor = res.text;
|
||||||
|
for (u32 i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
memcpy(cursor, strings[i], sizes[i]);
|
||||||
|
cursor += sizes[i];
|
||||||
|
}
|
||||||
|
*cursor = '\0';
|
||||||
|
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Compute string length, excluding zero-terminator
|
||||||
|
u64 rstring_length(const char *src)
|
||||||
|
{
|
||||||
|
u64 length = 0;
|
||||||
|
while(*(src++) != '\0')
|
||||||
|
length++;
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Comparison
|
||||||
|
int rstring_compare(const char* left, const char *right)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (*left < *right)
|
||||||
|
return -1;
|
||||||
|
if (*left > *right)
|
||||||
|
return +1;
|
||||||
|
right++;
|
||||||
|
} while (*(left++));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool string_equal(String left, String right)
|
||||||
|
{
|
||||||
|
if (left.length != right.length)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
char *l = left.text;
|
||||||
|
char *r = right.text;
|
||||||
|
char *l_end = l + left.length;
|
||||||
|
|
||||||
|
while (l != l_end)
|
||||||
|
{
|
||||||
|
if (*l != *r)
|
||||||
|
return false;
|
||||||
|
l++; r++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool string_find(String str, u64 start_index, String to_find, u64 *found_index)
|
||||||
|
{
|
||||||
|
// @TODO: Replace with better algorithm (Knuth-Morris-Pratt?)
|
||||||
|
char *end = str.text + str.length;
|
||||||
|
char *last_valid_start = end - to_find.length;
|
||||||
|
|
||||||
|
for (char *curr = str.text + start_index; curr <= last_valid_start; curr++)
|
||||||
|
{
|
||||||
|
bool found = true;
|
||||||
|
for (u64 i = 0; i < to_find.length; i++)
|
||||||
|
{
|
||||||
|
if (curr[i] != to_find.text[i])
|
||||||
|
{
|
||||||
|
found = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found)
|
||||||
|
{
|
||||||
|
*found_index = curr - str.text;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String string_substring(String *str, u64 start, u64 end)
|
||||||
|
{
|
||||||
|
String res;
|
||||||
|
res.text = &str->text[start];
|
||||||
|
end = (end < str->length ? end : str->length);
|
||||||
|
end = (start < end ? end : start);
|
||||||
|
res.length = end - start;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
String string_trim(String *str)
|
||||||
|
{
|
||||||
|
u64 start = 0;
|
||||||
|
u64 end = str->length;
|
||||||
|
|
||||||
|
while(start < str->length && isspace(str->text[start]))
|
||||||
|
start++;
|
||||||
|
while(end > start && isspace(str->text[end-1]))
|
||||||
|
end--;
|
||||||
|
|
||||||
|
return string_substring(str, start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// DString specific operations
|
||||||
|
void dstring_reserve(DString *dstr, u64 new_length)
|
||||||
|
{
|
||||||
|
if (dstr->length < new_length)
|
||||||
|
dstr->text = realloc(dstr->text, new_length + 1); // + 1 --> reserve space for '\0'
|
||||||
|
assert(dstr->text != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dstring_append(DString *dstr, const char *to_append, u64 count)
|
||||||
|
{
|
||||||
|
u64 len;
|
||||||
|
|
||||||
|
// Make sure we have enought space
|
||||||
|
len = dstr->length + count;
|
||||||
|
dstring_reserve(dstr, len);
|
||||||
|
|
||||||
|
// Copy bytes
|
||||||
|
memcpy(dstr->text + dstr->length, to_append, count);
|
||||||
|
|
||||||
|
dstr->text[len] = '\0';
|
||||||
|
dstr->length = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dstring_insert(DString *dstr, u64 index, const char *to_insert, u64 count)
|
||||||
|
{
|
||||||
|
u64 len;
|
||||||
|
char *insert_start;
|
||||||
|
char *insert_end;
|
||||||
|
|
||||||
|
// Make sure we have enought space
|
||||||
|
len = dstr->length + count;
|
||||||
|
dstring_reserve(dstr, len);
|
||||||
|
|
||||||
|
// Move content to make space for the data we have to insert
|
||||||
|
insert_start = dstr->text + index;
|
||||||
|
insert_end = insert_start + count;
|
||||||
|
|
||||||
|
memmove(insert_end, insert_start, dstr->length - index + 1);
|
||||||
|
|
||||||
|
// Insert
|
||||||
|
memcpy(insert_start, to_insert, count);
|
||||||
|
dstr->length = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dstring_erase(DString *dstr, u64 index, u64 count)
|
||||||
|
{
|
||||||
|
if (index + count > dstr->length)
|
||||||
|
count = dstr->length - index;
|
||||||
|
|
||||||
|
char *start = dstr->text + index;
|
||||||
|
char *end = start + count;
|
||||||
|
u64 to_move_from_end = dstr->length - index - count + 1; // Remember to move terminating zero
|
||||||
|
memmove(start, end, to_move_from_end);
|
||||||
|
dstr->length -= count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dstring_replace(DString *dstr, u64 index, u64 rem_count, const char *to_insert, u64 ins_count)
|
||||||
|
{
|
||||||
|
if (index + rem_count > dstr->length)
|
||||||
|
rem_count = dstr->length - index;
|
||||||
|
|
||||||
|
u64 len = dstr->length - rem_count + ins_count;
|
||||||
|
dstring_reserve(dstr, len);
|
||||||
|
|
||||||
|
char *start = dstr->text + index;
|
||||||
|
char *rem_end = start + rem_count;
|
||||||
|
char *ins_end = start + ins_count;
|
||||||
|
u64 to_move_from_end = dstr->length - index - rem_count + 1;
|
||||||
|
memmove(ins_end, rem_end, to_move_from_end);
|
||||||
|
memcpy(start, to_insert, ins_count);
|
||||||
|
dstr->length = len;
|
||||||
|
}
|
||||||
94
lstring.h
Normal file
94
lstring.h
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
// LCZ libraries v0.1b
|
||||||
|
|
||||||
|
#ifndef _LCZ_STRING_H_
|
||||||
|
#define _LCZ_STRING_H_
|
||||||
|
|
||||||
|
#ifndef _LCZ_TYPES_H_
|
||||||
|
#include "types.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* String: constant length string.
|
||||||
|
* DString: dynamic length string.
|
||||||
|
* RString: raw c-style string. Not an actual type.
|
||||||
|
*
|
||||||
|
* USAGE INTERFACE:
|
||||||
|
* Length does not include '\0', but most strings should still be zero-terminated.
|
||||||
|
*
|
||||||
|
* DString is purposefully made to have the same memory layout as String,
|
||||||
|
* so you can use DString everywhere you can use String (but not vice-versa) by converting it with TO_STRING(dstr).
|
||||||
|
*
|
||||||
|
* Advanced: Actually String is not constant length. It's just unknown how much space has been allocated for it.
|
||||||
|
* Make sure you have enough space before modifying the lenght.
|
||||||
|
* DStrings change their size automatically if you use the functions in this library.
|
||||||
|
*
|
||||||
|
* IMPLEMENTER INTERFACE
|
||||||
|
* The "text" pointer should always be valid, unless you are building the String objects yourself.
|
||||||
|
* "capacity" and "length" do not include the zero terminator of the string. Make sure you malloc 1 more byte to fit it.
|
||||||
|
*
|
||||||
|
|
||||||
|
|
||||||
|
* String and DString are small containers, so they are not expensive to copy around.
|
||||||
|
* (It's PROBABLY more expensive to dereference a pointer than to copy a String container. Did not profile though.)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* @TODO: Add allocator function to parameters?
|
||||||
|
* @TODO: Use String type instead of passing text + length everywhere?
|
||||||
|
*
|
||||||
|
* @Note: I considered adding a SString (Static string, immutable), but it would be so inconvenient to use
|
||||||
|
* that I decided to leave it out (it's just like the "const" keyword)
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct String
|
||||||
|
{
|
||||||
|
char *text;
|
||||||
|
u64 length;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DString
|
||||||
|
{
|
||||||
|
char *text;
|
||||||
|
u64 length;
|
||||||
|
u64 capacity;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct String String;
|
||||||
|
typedef struct DString DString;
|
||||||
|
|
||||||
|
|
||||||
|
#define TO_STRING(dstr) (*((String*)&dstr))
|
||||||
|
|
||||||
|
// String building / constructors
|
||||||
|
String string_take(char *src);
|
||||||
|
DString dstring_take(char *src);
|
||||||
|
String string_copy(const char *src, u64 length);
|
||||||
|
DString dstring_copy(const char *src, u64 length);
|
||||||
|
DString dstring_new(u64 capacity);
|
||||||
|
// n = number of strings, ... = , const char *src1, u64 length1, ...
|
||||||
|
String string_concat(u32 n, ...);
|
||||||
|
// n = number of strings, ... = , const char *src1, u64 length1, ...
|
||||||
|
DString dstring_concat(u32 n, ...);
|
||||||
|
|
||||||
|
// Compute string length, excluding zero-terminator
|
||||||
|
u64 rstring_length(const char *src);
|
||||||
|
|
||||||
|
// Comparison
|
||||||
|
int rstring_compare(const char *left, const char *right);
|
||||||
|
bool string_equal(String left, String right);
|
||||||
|
bool string_find(String str, u64 start_index, String to_find, u64 *found_index);
|
||||||
|
|
||||||
|
// String specific operations
|
||||||
|
// Warning: You have to make sure the space pointed by str is big enough to fit to_append.
|
||||||
|
void string_append(String *str, const char *to_append, u64 count);
|
||||||
|
String string_substring(String *str, u64 start, u64 end);
|
||||||
|
String string_trim(String *str);
|
||||||
|
|
||||||
|
// DString specific operations
|
||||||
|
void dstring_reserve(DString *dstr, u64 new_length);
|
||||||
|
void dstring_append(DString *dstr, const char *to_append, u64 count);
|
||||||
|
void dstring_insert(DString *dstr, u64 index, const char *to_insert, u64 count);
|
||||||
|
void dstring_erase(DString *dstr, u64 index, u64 count);
|
||||||
|
void dstring_replace(DString *dstr, u64 index, u64 rem_count, const char *to_insert, u64 ins_count);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
31
types.h
Normal file
31
types.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// LCZ libraries v0.1b
|
||||||
|
|
||||||
|
#ifndef _LCZ_TYPES_H_
|
||||||
|
#define _LCZ_TYPES_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
// Standard types with better names
|
||||||
|
typedef int8_t s8;
|
||||||
|
typedef int16_t s16;
|
||||||
|
typedef int32_t s32;
|
||||||
|
typedef int64_t s64;
|
||||||
|
|
||||||
|
typedef uint8_t u8;
|
||||||
|
typedef uint16_t u16;
|
||||||
|
typedef uint32_t u32;
|
||||||
|
typedef uint64_t u64;
|
||||||
|
|
||||||
|
typedef float f32;
|
||||||
|
typedef double f64;
|
||||||
|
|
||||||
|
|
||||||
|
// Status code for error managemet
|
||||||
|
enum StatusCode {
|
||||||
|
STATUS_ERR = 0,
|
||||||
|
STATUS_OK = 1
|
||||||
|
};
|
||||||
|
typedef enum StatusCode StatusCode;
|
||||||
|
|
||||||
|
#endif
|
||||||
424
wg_quicker.c
Normal file
424
wg_quicker.c
Normal file
@@ -0,0 +1,424 @@
|
|||||||
|
#include "types.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "lstring.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "wireguard.h"
|
||||||
|
|
||||||
|
|
||||||
|
const char *program_name = "wg_quicker";
|
||||||
|
|
||||||
|
struct IP4
|
||||||
|
{
|
||||||
|
u8 a;
|
||||||
|
u8 b;
|
||||||
|
u8 c;
|
||||||
|
u8 d;
|
||||||
|
};
|
||||||
|
typedef struct IP4 IP4;
|
||||||
|
|
||||||
|
struct VPN_Data
|
||||||
|
{
|
||||||
|
String name;
|
||||||
|
IP4 network;
|
||||||
|
String server_host;
|
||||||
|
String server_port;
|
||||||
|
String pre_shared_key;
|
||||||
|
String server_public_key;
|
||||||
|
IP4 last_ip;
|
||||||
|
};
|
||||||
|
typedef struct VPN_Data VPN_Data;
|
||||||
|
|
||||||
|
bool IP4_from_String(String *str, IP4 *ip)
|
||||||
|
{
|
||||||
|
IP4 res;
|
||||||
|
// Warning: str might not be zero terminated
|
||||||
|
int read = sscanf(str->text, "%hhu.%hhu.%hhu.%hhu", &res.a, &res.b, &res.c, &res.d);
|
||||||
|
// TODO: Check for parsing errors
|
||||||
|
*ip = res;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void String_split(String *str, char divider, String **result_arr, u64 *result_count)
|
||||||
|
{
|
||||||
|
u64 capacity = 8;
|
||||||
|
String *res = malloc(sizeof(String) * capacity);
|
||||||
|
u64 count = 0;
|
||||||
|
|
||||||
|
u64 start = 0;
|
||||||
|
for(u64 i = 0; i < str->length; i++)
|
||||||
|
{
|
||||||
|
if(str->text[i] == divider)
|
||||||
|
{
|
||||||
|
// Resize backing storage if not big enought
|
||||||
|
if(count >= capacity)
|
||||||
|
{
|
||||||
|
capacity *= 1.5;
|
||||||
|
res = realloc(res, sizeof(String) * capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add line substring to array
|
||||||
|
res[count++] = string_substring(str, start, i);
|
||||||
|
start = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*result_arr = res;
|
||||||
|
*result_count = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VPN_Data_from_String(String *str, VPN_Data *vpn)
|
||||||
|
{
|
||||||
|
String *lines;
|
||||||
|
u64 lines_count;
|
||||||
|
String_split(str, '\n', &lines, &lines_count);
|
||||||
|
|
||||||
|
if(lines_count != 7)
|
||||||
|
{
|
||||||
|
LogError("Error parsing data file,");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VPN_Data res;
|
||||||
|
|
||||||
|
res.name = string_trim(&lines[0]);
|
||||||
|
if(! IP4_from_String(&lines[1], &res.network))
|
||||||
|
{
|
||||||
|
LogError("Error parsing network address.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
res.server_host = string_trim(&lines[2]);
|
||||||
|
res.server_port = string_trim(&lines[3]);
|
||||||
|
res.pre_shared_key = string_trim(&lines[4]);
|
||||||
|
res.server_public_key = string_trim(&lines[5]);
|
||||||
|
if(! IP4_from_String(&lines[6], &res.last_ip))
|
||||||
|
{
|
||||||
|
LogError("Error parsing last IP address.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(lines);
|
||||||
|
*vpn = res;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
String VPN_Data_to_String(VPN_Data *vpn)
|
||||||
|
{
|
||||||
|
DString res = dstring_new(2048);
|
||||||
|
|
||||||
|
res.length += snprintf(res.text, res.capacity,
|
||||||
|
"%.*s\n"
|
||||||
|
"%hhu.%hhu.%hhu.%hhu\n"
|
||||||
|
"%.*s\n"
|
||||||
|
"%.*s\n"
|
||||||
|
"%.*s\n"
|
||||||
|
"%.*s\n"
|
||||||
|
"%hhu.%hhu.%hhu.%hhu\n",
|
||||||
|
vpn->name.length, vpn->name.text,
|
||||||
|
vpn->network.a, vpn->network.b, vpn->network.c, vpn->network.d,
|
||||||
|
vpn->server_host.length, vpn->server_host.text,
|
||||||
|
vpn->server_port.length, vpn->server_port.text,
|
||||||
|
vpn->pre_shared_key.length, vpn->pre_shared_key.text,
|
||||||
|
vpn->server_public_key.length, vpn->server_public_key.text,
|
||||||
|
vpn->last_ip.a, vpn->last_ip.b, vpn->last_ip.c, vpn->last_ip.d
|
||||||
|
);
|
||||||
|
|
||||||
|
return TO_STRING(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
String Stream_ReadAll(FILE *file, bool zero_terminated)
|
||||||
|
{
|
||||||
|
u64 end, start;
|
||||||
|
u64 fsize;
|
||||||
|
u64 read;
|
||||||
|
String res;
|
||||||
|
|
||||||
|
// Get file size
|
||||||
|
fseek(file, 0, SEEK_END);
|
||||||
|
end = ftell(file);
|
||||||
|
|
||||||
|
fseek(file, 0, SEEK_SET);
|
||||||
|
start = ftell(file);
|
||||||
|
|
||||||
|
fsize = end - start;
|
||||||
|
LogDebug("File size is %lu", fsize);
|
||||||
|
|
||||||
|
// Reserve memory for str
|
||||||
|
res.length = fsize;
|
||||||
|
if (zero_terminated)
|
||||||
|
res.length++;
|
||||||
|
res.text = malloc(res.length);
|
||||||
|
assert(res.text != NULL);
|
||||||
|
|
||||||
|
// Actually read data from file
|
||||||
|
read = fread(res.text, 1, fsize, file);
|
||||||
|
assert(read == fsize);
|
||||||
|
if (zero_terminated)
|
||||||
|
res.text[res.length] = '\0';
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Print_ErrorAndUsage(const char *error_msg)
|
||||||
|
{
|
||||||
|
LogError(
|
||||||
|
"%s\n"
|
||||||
|
"Usage: %s <command> ...\n"
|
||||||
|
"Commands:\n"
|
||||||
|
" new_vpn <vpn_name> <vpn_net_addr> <server_host_addr> <server_port>\n"
|
||||||
|
" add_client <vpn_name> <client_name>\n"
|
||||||
|
, error_msg, program_name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
// Get program name from args
|
||||||
|
if(argc < 1)
|
||||||
|
{
|
||||||
|
LogError("Internal error (missing program name from args. This should never happen. There is a bug.)");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
program_name = argv[0];
|
||||||
|
|
||||||
|
// Get command name from args
|
||||||
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
Print_ErrorAndUsage("Missing command.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
String command = string_take(argv[1]);
|
||||||
|
|
||||||
|
if(string_equal(command, string_take("new_vpn")))
|
||||||
|
{
|
||||||
|
if(argc < 6)
|
||||||
|
{
|
||||||
|
Print_ErrorAndUsage("Missing argument.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
String arg_vpn_name = string_take(argv[2]);
|
||||||
|
String arg_vpn_net_addr = string_take(argv[3]);
|
||||||
|
String arg_server_host_addr = string_take(argv[4]);
|
||||||
|
String arg_server_port = string_take(argv[5]);
|
||||||
|
|
||||||
|
VPN_Data vpn;
|
||||||
|
|
||||||
|
vpn.name = arg_vpn_name;
|
||||||
|
if(! IP4_from_String(&arg_vpn_net_addr, &vpn.network))
|
||||||
|
{
|
||||||
|
LogError("Error parsing argument: network address.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
vpn.server_host = arg_server_host_addr;
|
||||||
|
vpn.server_port = arg_server_port;
|
||||||
|
|
||||||
|
if(vpn.network.d != 0)
|
||||||
|
{
|
||||||
|
LogError("Address %hhu.%hhu.%hhu.%hhu is not a valid /24 network address.", vpn.network.a, vpn.network.b, vpn.network.c, vpn.network.d);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate private/public key for server and pre shared key
|
||||||
|
wg_key_b64_string priv_b64, publ_b64, pre_shared_b64;
|
||||||
|
{
|
||||||
|
wg_key priv, publ, pre_shared;
|
||||||
|
wg_generate_private_key(priv);
|
||||||
|
wg_generate_public_key(publ, priv);
|
||||||
|
wg_generate_preshared_key(pre_shared);
|
||||||
|
wg_key_to_base64(priv_b64, priv);
|
||||||
|
wg_key_to_base64(publ_b64, publ);
|
||||||
|
wg_key_to_base64(pre_shared_b64, pre_shared);
|
||||||
|
}
|
||||||
|
|
||||||
|
vpn.pre_shared_key = string_take(pre_shared_b64);
|
||||||
|
vpn.server_public_key = string_take(publ_b64);
|
||||||
|
|
||||||
|
vpn.last_ip = vpn.network;
|
||||||
|
vpn.last_ip.d = 1;
|
||||||
|
|
||||||
|
// Save config data
|
||||||
|
String vpn_str = VPN_Data_to_String(&vpn);
|
||||||
|
|
||||||
|
String data_filename = string_concat(
|
||||||
|
2,
|
||||||
|
vpn.name.text, vpn.name.length,
|
||||||
|
".txt", rstring_length(".txt")
|
||||||
|
);
|
||||||
|
if(access(data_filename.text, F_OK) == 0)
|
||||||
|
{
|
||||||
|
LogError("File \"%s\" already exists.", data_filename.text);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
FILE *data_f = fopen(data_filename.text, "w");
|
||||||
|
if (! data_f)
|
||||||
|
{
|
||||||
|
LogError("Cannot open \"%s\"", data_filename.text);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(data_f, "%.*s", vpn_str.length, vpn_str.text);
|
||||||
|
|
||||||
|
fclose(data_f);
|
||||||
|
free(data_filename.text);
|
||||||
|
free(vpn_str.text);
|
||||||
|
|
||||||
|
// Create wg-quick configuration file
|
||||||
|
String wg_config_filename = string_concat(
|
||||||
|
3,
|
||||||
|
"/etc/wireguard/", rstring_length("/etc/wireguard/"),
|
||||||
|
vpn.name.text, vpn.name.length,
|
||||||
|
".conf", rstring_length(".conf")
|
||||||
|
);
|
||||||
|
if(access(wg_config_filename.text, F_OK) == 0)
|
||||||
|
{
|
||||||
|
LogError("File \"%s\" already exists.", wg_config_filename.text);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
FILE *wg_config_f = fopen(wg_config_filename.text, "w");
|
||||||
|
if (! wg_config_f)
|
||||||
|
{
|
||||||
|
LogError("Cannot open \"%s\"", wg_config_filename.text);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(wg_config_f, "[Interface]\n");
|
||||||
|
fprintf(wg_config_f, "Address = %hhu.%hhu.%hhu.%hhu/24\n", vpn.last_ip.a, vpn.last_ip.b, vpn.last_ip.c, vpn.last_ip.d);
|
||||||
|
fprintf(wg_config_f, "PrivateKey = %s\n", priv_b64);
|
||||||
|
fprintf(wg_config_f, "PostUp = firewall-cmd --zone=public --add-port=%.*s/udp\n", vpn.server_port.length, vpn.server_port.text);
|
||||||
|
fprintf(wg_config_f, "PostUp = firewall-cmd --zone=public --remove-port=%.*s/udp\n", vpn.server_port.length, vpn.server_port.text);
|
||||||
|
fprintf(wg_config_f, "ListenPort = %.*s\n", vpn.server_port.length, vpn.server_port.text);
|
||||||
|
|
||||||
|
fclose(wg_config_f);
|
||||||
|
free(wg_config_filename.text);
|
||||||
|
|
||||||
|
printf("You can now activate the Wireguard service with the command \"systemctl start wg-quick@%.*s\"\n", vpn.name.length, vpn.name.text);
|
||||||
|
}
|
||||||
|
else if(string_equal(command, string_take("add_client")))
|
||||||
|
{
|
||||||
|
if(argc < 4)
|
||||||
|
{
|
||||||
|
Print_ErrorAndUsage("Missing argument.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
String vpn_name = string_take(argv[2]);
|
||||||
|
String client_name = string_take(argv[3]);
|
||||||
|
|
||||||
|
// Read data file
|
||||||
|
String data_filename = string_concat(
|
||||||
|
2,
|
||||||
|
vpn_name.text, vpn_name.length,
|
||||||
|
".txt", rstring_length(".txt")
|
||||||
|
);
|
||||||
|
FILE *data_f = fopen(data_filename.text, "r+");
|
||||||
|
if (! data_f)
|
||||||
|
{
|
||||||
|
LogError("Cannot open \"%s\"", data_filename.text);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
String vpn_str = Stream_ReadAll(data_f, true);
|
||||||
|
|
||||||
|
VPN_Data vpn;
|
||||||
|
if(! VPN_Data_from_String(&vpn_str, &vpn))
|
||||||
|
{
|
||||||
|
LogError("Cannot parse data file.");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vpn.last_ip.d >= 254)
|
||||||
|
{
|
||||||
|
LogError("Address space full. (You already generated configs for 253 clients)");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
vpn.last_ip.d += 1;
|
||||||
|
|
||||||
|
// Generate client private and public keys
|
||||||
|
wg_key_b64_string priv_b64, publ_b64;
|
||||||
|
{
|
||||||
|
wg_key priv, publ;
|
||||||
|
wg_generate_private_key(priv);
|
||||||
|
wg_key_to_base64(priv_b64, priv);
|
||||||
|
wg_generate_public_key(publ, priv);
|
||||||
|
wg_key_to_base64(publ_b64, publ);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update server config file
|
||||||
|
String wg_config_filename = string_concat(
|
||||||
|
3,
|
||||||
|
"/etc/wireguard/", rstring_length("/etc/wireguard/"),
|
||||||
|
vpn.name.text, vpn.name.length,
|
||||||
|
".conf", rstring_length(".conf")
|
||||||
|
);
|
||||||
|
FILE *wg_config_f = fopen(wg_config_filename.text, "a");
|
||||||
|
if(access(wg_config_filename.text, F_OK) != 0)
|
||||||
|
{
|
||||||
|
LogError("File \"%s\" does not exist.", wg_config_filename.text);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
if (! wg_config_f)
|
||||||
|
{
|
||||||
|
LogError("Cannot open \"%s\"", wg_config_filename.text);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(wg_config_f, "\n");
|
||||||
|
fprintf(wg_config_f, "[Peer]\n");
|
||||||
|
fprintf(wg_config_f, "# User: %.*s\n", client_name.length, client_name.text);
|
||||||
|
fprintf(wg_config_f, "PublicKey = %s\n", publ_b64);
|
||||||
|
fprintf(wg_config_f, "PresharedKey = %.*s\n", vpn.pre_shared_key.length, vpn.pre_shared_key.text);
|
||||||
|
fprintf(wg_config_f, "AllowedIPs = %hhu.%hhu.%hhu.%hhu/32\n", vpn.last_ip.a, vpn.last_ip.b, vpn.last_ip.c, vpn.last_ip.d);
|
||||||
|
|
||||||
|
fclose(wg_config_f);
|
||||||
|
free(wg_config_filename.text);
|
||||||
|
|
||||||
|
// Create client config file
|
||||||
|
String client_conf_path = string_concat(
|
||||||
|
2,
|
||||||
|
client_name.text, client_name.length,
|
||||||
|
".conf", rstring_length(".conf")
|
||||||
|
);
|
||||||
|
FILE *client_conf_f = fopen(client_conf_path.text, "w");
|
||||||
|
if (!client_conf_f)
|
||||||
|
{
|
||||||
|
LogError("Cannot open \"%s\"", client_conf_path.text);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(client_conf_f, "[Interface]\n");
|
||||||
|
fprintf(client_conf_f, "Address = %hhu.%hhu.%hhu.%hhu/32\n", vpn.last_ip.a, vpn.last_ip.b, vpn.last_ip.c, vpn.last_ip.d);
|
||||||
|
fprintf(client_conf_f, "PrivateKey = %s\n", priv_b64);
|
||||||
|
fprintf(client_conf_f, "\n");
|
||||||
|
fprintf(client_conf_f, "[Peer]\n");
|
||||||
|
fprintf(client_conf_f, "PublicKey = %.*s\n", vpn.server_public_key.length, vpn.server_public_key.text);
|
||||||
|
fprintf(client_conf_f, "PresharedKey = %.*s\n", vpn.pre_shared_key.length, vpn.pre_shared_key.text);
|
||||||
|
fprintf(client_conf_f, "AllowedIPs = %hhu.%hhu.%hhu.%hhu/24\n", vpn.network.a, vpn.network.b, vpn.network.c, vpn.network.d);
|
||||||
|
fprintf(client_conf_f, "\n");
|
||||||
|
fprintf(client_conf_f, "Endpoint = %.*s:%.*s\n", vpn.server_host.length, vpn.server_host.text, vpn.server_port.length, vpn.server_port.text);
|
||||||
|
fprintf(client_conf_f, "PersistentKeepalive = 30\n");
|
||||||
|
|
||||||
|
fclose(client_conf_f);
|
||||||
|
|
||||||
|
// Save config data (last ip changed)
|
||||||
|
String vpn_str_bis = VPN_Data_to_String(&vpn);
|
||||||
|
fseek(data_f, 0, SEEK_SET);
|
||||||
|
fprintf(data_f, "%.*s", vpn_str_bis.length, vpn_str_bis.text);
|
||||||
|
|
||||||
|
printf("Client config file created: \"%.*s\".\n", client_conf_path.length, client_conf_path.text);
|
||||||
|
printf("Remember to restart the Wireguard service with the command \"systemctl restart wg-quick@%.*s\" to apply the changes.\n", vpn.name.length, vpn.name.text);
|
||||||
|
|
||||||
|
free(client_conf_path.text);
|
||||||
|
free(vpn_str_bis.text);
|
||||||
|
free(vpn_str.text);
|
||||||
|
fclose(data_f);
|
||||||
|
free(data_filename.text);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Print_ErrorAndUsage("Unrecognized command.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
1755
wireguard.c
Normal file
1755
wireguard.c
Normal file
File diff suppressed because it is too large
Load Diff
103
wireguard.h
Normal file
103
wireguard.h
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WIREGUARD_H
|
||||||
|
#define WIREGUARD_H
|
||||||
|
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
typedef uint8_t wg_key[32];
|
||||||
|
typedef char wg_key_b64_string[((sizeof(wg_key) + 2) / 3) * 4 + 1];
|
||||||
|
|
||||||
|
/* Cross platform __kernel_timespec */
|
||||||
|
struct timespec64 {
|
||||||
|
int64_t tv_sec;
|
||||||
|
int64_t tv_nsec;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct wg_allowedip {
|
||||||
|
uint16_t family;
|
||||||
|
union {
|
||||||
|
struct in_addr ip4;
|
||||||
|
struct in6_addr ip6;
|
||||||
|
};
|
||||||
|
uint8_t cidr;
|
||||||
|
struct wg_allowedip *next_allowedip;
|
||||||
|
} wg_allowedip;
|
||||||
|
|
||||||
|
enum wg_peer_flags {
|
||||||
|
WGPEER_REMOVE_ME = 1U << 0,
|
||||||
|
WGPEER_REPLACE_ALLOWEDIPS = 1U << 1,
|
||||||
|
WGPEER_HAS_PUBLIC_KEY = 1U << 2,
|
||||||
|
WGPEER_HAS_PRESHARED_KEY = 1U << 3,
|
||||||
|
WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL = 1U << 4
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct wg_peer {
|
||||||
|
enum wg_peer_flags flags;
|
||||||
|
|
||||||
|
wg_key public_key;
|
||||||
|
wg_key preshared_key;
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct sockaddr addr;
|
||||||
|
struct sockaddr_in addr4;
|
||||||
|
struct sockaddr_in6 addr6;
|
||||||
|
} endpoint;
|
||||||
|
|
||||||
|
struct timespec64 last_handshake_time;
|
||||||
|
uint64_t rx_bytes, tx_bytes;
|
||||||
|
uint16_t persistent_keepalive_interval;
|
||||||
|
|
||||||
|
struct wg_allowedip *first_allowedip, *last_allowedip;
|
||||||
|
struct wg_peer *next_peer;
|
||||||
|
} wg_peer;
|
||||||
|
|
||||||
|
enum wg_device_flags {
|
||||||
|
WGDEVICE_REPLACE_PEERS = 1U << 0,
|
||||||
|
WGDEVICE_HAS_PRIVATE_KEY = 1U << 1,
|
||||||
|
WGDEVICE_HAS_PUBLIC_KEY = 1U << 2,
|
||||||
|
WGDEVICE_HAS_LISTEN_PORT = 1U << 3,
|
||||||
|
WGDEVICE_HAS_FWMARK = 1U << 4
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct wg_device {
|
||||||
|
char name[IF_NAMESIZE];
|
||||||
|
uint32_t ifindex;
|
||||||
|
|
||||||
|
enum wg_device_flags flags;
|
||||||
|
|
||||||
|
wg_key public_key;
|
||||||
|
wg_key private_key;
|
||||||
|
|
||||||
|
uint32_t fwmark;
|
||||||
|
uint16_t listen_port;
|
||||||
|
|
||||||
|
struct wg_peer *first_peer, *last_peer;
|
||||||
|
} wg_device;
|
||||||
|
|
||||||
|
#define wg_for_each_device_name(__names, __name, __len) for ((__name) = (__names), (__len) = 0; ((__len) = strlen(__name)); (__name) += (__len) + 1)
|
||||||
|
#define wg_for_each_peer(__dev, __peer) for ((__peer) = (__dev)->first_peer; (__peer); (__peer) = (__peer)->next_peer)
|
||||||
|
#define wg_for_each_allowedip(__peer, __allowedip) for ((__allowedip) = (__peer)->first_allowedip; (__allowedip); (__allowedip) = (__allowedip)->next_allowedip)
|
||||||
|
|
||||||
|
int wg_set_device(wg_device *dev);
|
||||||
|
int wg_get_device(wg_device **dev, const char *device_name);
|
||||||
|
int wg_add_device(const char *device_name);
|
||||||
|
int wg_del_device(const char *device_name);
|
||||||
|
void wg_free_device(wg_device *dev);
|
||||||
|
char *wg_list_device_names(void); /* first\0second\0third\0forth\0last\0\0 */
|
||||||
|
void wg_key_to_base64(wg_key_b64_string base64, const wg_key key);
|
||||||
|
int wg_key_from_base64(wg_key key, const wg_key_b64_string base64);
|
||||||
|
bool wg_key_is_zero(const wg_key key);
|
||||||
|
void wg_generate_public_key(wg_key public_key, const wg_key private_key);
|
||||||
|
void wg_generate_private_key(wg_key private_key);
|
||||||
|
void wg_generate_preshared_key(wg_key preshared_key);
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user