Compare commits

..

48 Commits

Author SHA1 Message Date
Adrien Gallouët
42faaf816f Update mud: losslimit per path
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-03-07 16:19:06 +00:00
Adrien Gallouët
eee6a22ccd Use strip -x
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-02-29 10:06:50 +00:00
Adrien Gallouët
ee2d7a2e07 Update mud
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-02-29 09:57:46 +00:00
Adrien Gallouët
e5949b409f Handle cross stripped binary
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-02-29 09:34:58 +00:00
Adrien Gallouët
13703fb15f Allow to setup beat without [back]up
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-02-21 16:40:22 +00:00
Adrien Gallouët
7f30cdc5ee Update mud
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-02-05 14:01:13 +00:00
Adrien Gallouët
b2077f5cd4 Use mud_set_conf()
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-01-16 17:48:02 +00:00
Adrien Gallouët
a9408e799d Show beat
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-01-11 15:04:55 +00:00
Adrien Gallouët
61c7b48e3f Add beat option in path command
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-01-11 09:55:17 +00:00
Adrien Gallouët
4db90b42b6 Use mud based keepalive
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-01-11 09:12:47 +00:00
Adrien Gallouët
3df542b6d7 Update mud
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-01-09 22:25:42 +00:00
Adrien Gallouët
4a0027e640 Update mud
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-01-09 17:39:58 +00:00
Adrien Gallouët
296d80782a Update mud
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-01-08 14:38:28 +00:00
Adrien Gallouët
1c38034265 Code cleanup
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-01-07 13:00:51 +00:00
Adrien Gallouët
0b26eb108d Add rate fixed|auto option
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-01-07 12:46:28 +00:00
Adrien Gallouët
ac167e74f5 Fix keepalive and use a small value for now
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-01-04 16:17:36 +00:00
Adrien Gallouët
203feba186 Update README.md about backup path
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-01-03 16:26:21 +00:00
Adrien Gallouët
3b938df408 Happy New Year
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-01-03 15:57:16 +00:00
Adrien Gallouët
0ccb3de68d Update mud
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-01-03 15:39:10 +00:00
Adrien Gallouët
020b115171 Add keepalive
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-01-03 15:28:27 +00:00
Adrien Gallouët
53e7a7ba0a Resize and align buf
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2020-01-03 15:09:06 +00:00
Adrien Gallouët
1ae7775ce1 Cleanup Makefile
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-12-31 20:04:52 +00:00
Adrien Gallouët
c75f5d5620 Do not allow mtu manipulation anymore
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-12-31 19:34:20 +00:00
Adrien Gallouët
5f72198a96 Fix upload-artifact
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-12-10 14:54:49 +00:00
Adrien Gallouët
c01dbe3e4b Update README.md
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-11-19 13:38:59 +00:00
Adrien Gallouët
6be944d7cb Update mud
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-11-19 12:00:07 +00:00
Adrien Gallouët
009d482fd1 Be careful with dirname()
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-11-15 10:43:41 +00:00
Adrien Gallouët
b9aaab661f Probe run/tmp directory at runtime
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-11-14 19:19:23 +00:00
Adrien Gallouët
a4f63ecf40 Add rundir option for make
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-11-13 14:12:58 +00:00
Adrien Gallouët
0ceedaec10 Update Makefile
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-11-13 13:54:15 +00:00
Adrien Gallouët
34486c20b1 Update EXTRA_DIST
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-11-13 13:39:07 +00:00
Adrien Gallouët
b1fca4c1d2 301 to wikis
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-11-12 11:19:56 +00:00
Adrien Gallouët
5e0900c8ee Add option losslimit in the set command
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-10-23 13:52:40 +00:00
Adrien Gallouët
8bd936929e Show bad behaviors with command show bad
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-10-15 14:15:21 +00:00
Adrien Gallouët
289d88f3a7 Update mud
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-10-15 13:06:36 +00:00
Adrien Gallouët
1673110de1 Update mud
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-10-08 08:53:38 +00:00
Adrien Gallouët
1ce919c1e5 Update README.md
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-10-08 07:31:11 +00:00
Adrien Gallouët
e19fcaa2b0 Show remote loss too
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-10-07 14:18:50 +00:00
Adrien Gallouët
104fb37075 Update submodules
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-10-05 15:21:40 +00:00
Adrien Gallouët
6787e90be7 Update .gitignore
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-10-05 15:17:48 +00:00
Adrien Gallouët
639853b665 Show loss in command path
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-10-05 09:47:04 +00:00
Adrien Gallouët
57ea0d283d Bench with more time to improve accuracy
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-10-05 09:17:22 +00:00
Adrien Gallouët
0c82c06119 Show correct cipher
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-10-05 06:05:34 +00:00
Adrien Gallouët
65f636555b Do a simpler boring bench
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-10-04 17:10:10 +00:00
Adrien Gallouët
c93cef5491 Faster sigma
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-10-03 15:35:07 +00:00
Adrien Gallouët
1fed2813e5 Fix the unprobable s.v==1 case
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-10-03 15:10:37 +00:00
Adrien Gallouët
860651d02f Rework bench without using -lm
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-10-02 16:49:27 +00:00
Adrien Gallouët
fd7ddf7814 Update mud
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-09-24 09:57:21 +00:00
18 changed files with 313 additions and 440 deletions

View File

@@ -20,5 +20,5 @@ jobs:
- uses: actions/upload-artifact@v1
with:
name: bin
name: ${{ matrix.os }}
path: ./bin

2
.gitignore vendored
View File

@@ -1,4 +1,4 @@
*.o
*.[ios]
*.log
*.scan
*.cache

View File

@@ -1,4 +1,4 @@
Copyright (c) 2015-2019, Adrien Gallouët <adrien@gallouet.fr>
Copyright (c) 2015-2020, Adrien Gallouët <adrien@gallouet.fr>
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@@ -2,11 +2,11 @@ NAME := glorytun
VERSION := $(shell ./version.sh)
DIST := $(NAME)-$(VERSION)
DESTDIR ?=
CC ?= gcc
INSTALL ?= install
CC ?= cc
prefix ?= /usr
CFLAGS ?= -std=c11 -O2 -Wall -fstack-protector-strong
Q := @
CFLAGS := -std=c11 -O2 -Wall -fstack-protector-strong
FLAGS := $(CFLAGS) $(LDFLAGS) $(CPPFLAGS)
FLAGS += -DPACKAGE_NAME=\"$(NAME)\" -DPACKAGE_VERSION=\"$(VERSION)\"
@@ -15,21 +15,26 @@ FLAGS += -I.static/$(CROSS)/libsodium-stable/src/libsodium/include
FLAGS += -L.static/$(CROSS)/libsodium-stable/src/libsodium/.libs
SRC := argz/argz.c mud/mud.c mud/aegis256/aegis256.c $(wildcard src/*.c)
HDR := argz/argz.h mud/mud.h mud/aegis256/aegis256.h $(wildcard src/*.h)
.PHONY: $(NAME)
$(NAME):
@echo "Building $(NAME)"
@$(CC) $(FLAGS) -o $(NAME) $(SRC) -lsodium -lm
ifneq ($(CROSS),)
X = $(CROSS)-
endif
$(NAME): $(SRC) $(HDR)
$(Q)$(X)$(CC) $(FLAGS) -o $(NAME) $(SRC) -lsodium
$(NAME)-strip: $(NAME)
$(Q)cp $< $@
$(Q)$(X)strip -x $@
.PHONY: install
install: $(NAME)
@echo "Installing $(NAME)"
@$(INSTALL) -m 755 -d $(DESTDIR)$(prefix)/bin
@$(INSTALL) -m 755 -s $(NAME) $(DESTDIR)$(prefix)/bin
install: $(NAME)-strip
@echo "$(DESTDIR)$(prefix)/bin/$(NAME)"
$(Q)install -m 755 -d $(DESTDIR)$(prefix)/bin
$(Q)install -m 755 $(NAME)-strip $(DESTDIR)$(prefix)/bin/$(NAME)
.PHONY: dist
dist:
@echo "Building $(DIST).tar.gz"
@(git --git-dir=.git ls-files --recurse-submodules -- ':!:.*' ':!:**/.*' && echo VERSION) | ( \
tar zcf $(DIST).tar.gz -T- --transform 's:^:$(DIST)/:' || \
tar zcf $(DIST).tar.gz -T- -s ':^:$(DIST)/:' ) 2>/dev/null
.PHONY: clean
clean:
$(Q)rm -f "$(NAME)"
$(Q)rm -f "$(DIST).tar.gz"

View File

@@ -31,11 +31,13 @@ glorytun_SOURCES = \
EXTRA_DIST = \
LICENSE \
Makefile \
README.md \
VERSION \
autogen.sh \
meson.build \
mud/LICENSE \
mud/README.md \
sodium.sh \
systemd \
version.sh

110
README.md
View File

@@ -2,6 +2,8 @@
Glorytun is a small, simple and secure VPN over [mud](https://github.com/angt/mud).
Please visit the [wiki](https://github.com/angt/glorytun/wiki) for how-to guides, tutorials, etc.
## Compatibility
Glorytun only depends on [libsodium](https://github.com/jedisct1/libsodium) version >= 1.0.4.
@@ -11,6 +13,7 @@ Linux is the platform of choice but the code is standard so it should be easily
It was successfully tested on OpenBSD, FreeBSD and MacOS.
IPv4 and IPv6 are supported.
On Linux you can have both at the same time by binding `::`.
## Features
@@ -18,18 +21,19 @@ The key features of Glorytun come directly from mud:
* **Fast and highly secure**
The use of UDP and [libsodium](https://github.com/jedisct1/libsodium) allows you to secure
your communications without impacting performance.
Glorytun uses AEGIS-256 only if AES-NI is available otherwise ChaCha20Poly1305 is used.
If you are not cpu bounded, you can force the use of ChaCha20Poly1305 for higher security.
All messages are encrypted, authenticated and marked with a timestamp.
Perfect forward secrecy is also implemented with ECDH over Curve25519.
Glorytun uses a new and very fast AEAD construction called AEGIS-256 if AES-NI is available otherwise ChaCha20-Poly1305 is used.
Of course, you can force the use of ChaCha20-Poly1305 for higher security.
All messages are encrypted, authenticated and timestamped to mitigate a large set of attacks.
This implies that the client and the server must be synchronized, an offset of 10min is accepted by default.
Perfect forward secrecy is also implemented with ECDH over Curve25519. Keys are rotated every hours.
* **Multipath and active failover**
* **Multipath and failover**
This is the main feature of Glorytun that allows to build an SD-WAN like service.
This allows a TCP connection to explore and exploit multiple links without being disconnected.
Aggregation should work on all conventional links, only very high latency (+500ms) links are not recommended for now.
Connectivity is now crucial, especially in the SD-WAN world.
This feature allows a TCP connection (and all other protocols) to explore and exploit all available links without being disconnected.
Aggregation should work on all conventional links.
Only very high latency (+500ms) links are not recommended for now.
Backup paths are also supported, they will be used only in case of emergency, it is useful when aggregation is not your priority.
* **Traffic shaping**
@@ -41,93 +45,9 @@ The key features of Glorytun come directly from mud:
Bad MTU configuration is a very common problem in the world of VPN.
As it is critical, Glorytun will try to setup it correctly by guessing its value.
It doesn't rely on ICMP Next-hop MTU to avoid black holes.
It doesn't rely on Next-hop MTU to avoid ICMP black holes.
In asymmetric situations the minimum MTU is selected.
## Caveats
Glorytun is strongly secure by default and protects against replay attacks,
the clock between the client and the server must be synchronized.
By default, an offset of 10min is accepted.
## Build and Install
You will need `git`, `make`, `gcc` and `libsodium`:
$ sudo apt install git make gcc libsodium-dev # debian based
$ sudo yum install git make gcc libsodium-devel # redhat based
To build and install the latest release from github:
$ git clone https://github.com/angt/glorytun --recursive
$ cd glorytun
$ sudo make install
This will install the binary in `/usr/bin` by default.
The more classical autotools suite is also available.
## Usage
Just run `glorytun` with no arguments to view the list of available commands:
```
$ glorytun
available commands:
show show tunnel info
bench start a crypto bench
bind start a new tunnel
set change tunnel properties
keygen generate a new secret key
path manage paths
version show version
```
Use the keyword `help` after a command to show its usage.
## Mini HowTo
Glorytun does not touch the configuration of its network interface (except for the MTU),
It is up to the user to do it according to the tools available
on his system (systemd-networkd, netifd, ...).
This also allows a wide variety of configurations.
To start a server:
# (umask 066; glorytun keygen > my_secret_key)
# glorytun bind 0.0.0.0 keyfile my_secret_key &
You should now have an unconfigured network interface (let's say `tun0`).
For example, the simplest setup with `ifconfig`:
# ifconfig tun0 10.0.1.1 pointopoint 10.0.1.2 up
To check if the server is running, simply call `glorytun show`.
It will show you all of the running tunnels.
To start a new client, you need to get the secret key generated for the server.
Then simply call:
# glorytun bind 0.0.0.0 to SERVER_IP keyfile my_secret_key &
# ifconfig tun0 10.0.1.2 pointopoint 10.0.1.1 up
Now you have to setup your path, let's say you have an ADSL link that can do 1Mbit upload and 20Mbit download then call:
# glorytun path up LOCAL_IPADDR rate tx 1mbit rx 20mbit
Again, to check if your path is working, you can watch its status with `glorytun path`.
You should now be able to ping your server with `ping 10.0.1.1`.
If you use systemd-networkd, you can easily setup your tunnels with the helper program `glorytun-setup`.
## Thanks
* @jedisct1 for all his help and the code for MacOS/BSD.
* The team OTB (@bessa, @gregdel, @pouulet, @sduponch and @simon) for all tests and discussions.
* OVH to support this soft :)
---
For feature requests and bug reports, please create an [issue](https://github.com/angt/glorytun/issues).

2
argz

Submodule argz updated: 47ad9daf43...f88a280d2b

View File

@@ -14,7 +14,6 @@ AM_PROG_CC_C_O
AC_PROG_CC_C99
AC_USE_SYSTEM_EXTENSIONS
AC_SEARCH_LIBS([socket], [socket])
AC_SEARCH_LIBS([fmin], [m])
AC_CHECK_LIB([rt], [clock_gettime])
AC_CHECK_FUNCS([clock_gettime])
PKG_CHECK_MODULES([libsodium], [libsodium >= 1.0.4])

View File

@@ -38,7 +38,6 @@ executable('glorytun', install: true,
],
dependencies: [
dependency('libsodium', version : '>=1.0.4'),
cc.find_library('m', required : false)
]
)

2
mud

Submodule mud updated: b59ab48407...bda2c6eaa7

View File

@@ -1,74 +1,34 @@
#include "common.h"
#include <math.h>
#include <sodium.h>
#include <string.h>
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#if defined __APPLE__
#include <mach/mach_time.h>
#endif
#include <inttypes.h>
#include "../argz/argz.h"
#include "../mud/aegis256/aegis256.h"
#define STR_S(X) (((X) > 1) ? "s" : "")
#define NPUBBYTES 32
#define KEYBYTES 32
#define ABYTES 16
static unsigned long long
gt_now(void)
{
#if defined __APPLE__
static mach_timebase_info_data_t mtid;
if (!mtid.denom)
mach_timebase_info(&mtid);
return (mach_absolute_time() * mtid.numer / mtid.denom) / 1000ULL;
#elif defined CLOCK_MONOTONIC
struct timespec tv;
clock_gettime(CLOCK_MONOTONIC, &tv);
return (unsigned long long)tv.tv_sec * 1000000ULL
+ (unsigned long long)tv.tv_nsec / 1000ULL;
#else
struct timeval tv;
gettimeofday(&tv, NULL);
return (unsigned long long)tv.tv_sec * 1000000ULL
+ (unsigned long long)tv.tv_usec;
#endif
}
int
gt_bench(int argc, char **argv)
{
unsigned long precision = 10;
size_t bufsize = 64 * 1024;
unsigned long duration = 1000;
struct argz bench_argz[] = {
{"aes|chacha", NULL, NULL, argz_option},
{"precision", "EXPONENT", &precision, argz_ulong},
{"bufsize", "BYTES", &bufsize, argz_bytes},
{"duration", "SECONDS", &duration, argz_time},
{NULL}};
if (argz(bench_argz, argc, argv))
return 1;
if (duration == 0 || bufsize == 0)
return 0;
if (sodium_init() == -1) {
gt_log("sodium init failed\n");
return 1;
}
duration /= 1000;
int term = isatty(1);
int aes = argz_is_set(bench_argz, "aes");
int chacha = argz_is_set(bench_argz, "chacha");
@@ -81,71 +41,65 @@ gt_bench(int argc, char **argv)
chacha = 1;
}
unsigned char *buf = calloc(1, bufsize + ABYTES);
if (!buf) {
perror("calloc");
return 1;
}
unsigned char buf[1450 + ABYTES];
unsigned char npub[NPUBBYTES];
unsigned char key[KEYBYTES];
memset(buf, 0, sizeof(buf));
randombytes_buf(npub, sizeof(npub));
randombytes_buf(key, sizeof(key));
if (term) {
printf("\n");
printf(" %-10s %s\n", "bench", chacha ? "chacha20poly1305" : "aegis256");
printf(" %-10s %s\n", "libsodium", sodium_version_string());
printf("\n");
printf(" %-10s 2^(-%lu)\n", "precision", precision);
printf(" %-10s %zu byte%s\n", "bufsize", bufsize, STR_S(bufsize));
printf(" %-10s %lu second%s\n", "duration", duration, STR_S(duration));
printf("\n");
printf("------------------------------------------------------------\n");
printf(" %3s %9s %14s %14s %14s\n", "2^n", "min", "avg", "max", "delta");
printf("------------------------------------------------------------\n");
printf("cipher: %s\n\n", GT_CIPHER(chacha));
printf(" size min mean max \n");
printf("----------------------------------------------------\n");
}
for (int i = 0; !gt_quit && bufsize >> i; i++) {
unsigned long long total_dt = 0ULL;
size_t total_bytes = 0;
double mbps = 0.0;
double mbps_min = INFINITY;
double mbps_max = 0.0;
double mbps_dlt = INFINITY;
int64_t size = 20;
while (!gt_quit && mbps_dlt > ldexp(mbps, -(int)precision)) {
unsigned long long now = gt_now();
double mbps_old = mbps;
size_t bytes = 0;
for (int i = 0; !gt_quit && size <= 1450; i++) {
struct {
int64_t min, mean, max, n;
} mbps = { .n = 0 };
gt_alarm = 0;
alarm((unsigned int)duration);
int64_t bytes_max = (int64_t)1 << 24;
while (!gt_quit && !gt_alarm) {
while (!gt_quit && mbps.n < 10) {
int64_t bytes = 0;
int64_t base = (int64_t)clock();
while (!gt_quit && bytes <= bytes_max) {
if (chacha) {
crypto_aead_chacha20poly1305_encrypt(
buf, NULL, buf, 1ULL << i, NULL, 0, NULL, npub, key);
buf, NULL, buf, size, NULL, 0, NULL, npub, key);
} else {
aegis256_encrypt(
buf, NULL, buf, 1ULL << i, NULL, 0, npub, key);
aegis256_encrypt(buf, NULL, buf, size, NULL, 0, npub, key);
}
bytes += 1ULL << i;
bytes += size;
}
total_dt += gt_now() - now;
total_bytes += bytes;
int64_t dt = (int64_t)clock() - base;
bytes_max = (bytes * (CLOCKS_PER_SEC / 3)) / dt;
int64_t _mbps = (8 * bytes * CLOCKS_PER_SEC) / (dt * 1000 * 1000);
mbps = ((double)total_bytes * 8.0) / (double)total_dt;
mbps_min = fmin(mbps_min, mbps);
mbps_max = fmax(mbps_max, mbps);
mbps_dlt = fabs(mbps_old - mbps);
if (!mbps.n++) {
mbps.min = _mbps;
mbps.max = _mbps;
mbps.mean = _mbps;
continue;
}
if (mbps.min > _mbps)
mbps.min = _mbps;
if (mbps.max < _mbps)
mbps.max = _mbps;
mbps.mean += (_mbps - mbps.mean) / mbps.n;
if (term) {
printf("\r %3i %9.2f Mbps %9.2f Mbps %9.2f Mbps %9.2e",
i, mbps_min, mbps, mbps_max, mbps_dlt);
printf("\r %5"PRIi64" %9"PRIi64" Mbps %9"PRIi64" Mbps %9"PRIi64" Mbps",
size, mbps.min, mbps.mean, mbps.max);
fflush(stdout);
}
}
@@ -153,12 +107,12 @@ gt_bench(int argc, char **argv)
if (term) {
printf("\n");
} else {
printf("%i %.2f %.2f %.2f\n", i, mbps_min, mbps, mbps_max);
printf("bench %s %"PRIi64" %"PRIi64" %"PRIi64" %"PRIi64"\n",
GT_CIPHER(chacha), size, mbps.min, mbps.mean, mbps.max);
}
}
printf("\n");
free(buf);
size += 2 * 5 * 13;
}
return 0;
}

View File

@@ -91,7 +91,7 @@ gt_setup_mtu(struct mud *mud, size_t old, const char *tun_name)
{
size_t mtu = mud_get_mtu(mud);
if (mtu == old)
if (!mtu || mtu == old)
return mtu;
if (iface_set_mtu(tun_name, mtu) == -1)
@@ -185,11 +185,16 @@ gt_bind(int argc, char **argv)
}
}
const int ctl_fd = ctl_create(GT_RUNDIR, tun_name);
const int ctl_fd = ctl_create(tun_name);
if (ctl_fd == -1) {
gt_log("couldn't create "GT_RUNDIR"/%s: %s\n",
tun_name, strerror(errno));
char dir[64];
if (ctl_rundir(dir, sizeof(dir))) {
gt_log("couldn't create %s/%s: %s\n",
dir, tun_name, strerror(errno));
} else {
gt_log("couldn't find a writable run/tmp directory\n");
}
return 1;
}
@@ -216,48 +221,31 @@ gt_bind(int argc, char **argv)
int last_fd = MAX(tun_fd, mud_fd);
last_fd = 1 + MAX(last_fd, ctl_fd);
unsigned char buf[4096];
__attribute__((aligned(16)))
unsigned char buf[1500];
while (!gt_quit) {
if (tun_can_write) {
FD_CLR(tun_fd, &wfds);
} else {
FD_SET(tun_fd, &wfds);
}
if (mud_can_write) {
FD_CLR(mud_fd, &wfds);
} else {
FD_SET(mud_fd, &wfds);
}
if (tun_can_read) {
FD_CLR(tun_fd, &rfds);
} else {
FD_SET(tun_fd, &rfds);
}
if (mud_can_read) {
FD_CLR(mud_fd, &rfds);
} else {
FD_SET(mud_fd, &rfds);
}
if (tun_can_write) FD_CLR(tun_fd, &wfds); else FD_SET(tun_fd, &wfds);
if (mud_can_write) FD_CLR(mud_fd, &wfds); else FD_SET(mud_fd, &wfds);
if (tun_can_read) FD_CLR(tun_fd, &rfds); else FD_SET(tun_fd, &rfds);
if (mud_can_read) FD_CLR(mud_fd, &rfds); else FD_SET(mud_fd, &rfds);
FD_SET(ctl_fd, &rfds);
struct timeval tv = {
.tv_usec = 100000,
};
struct timeval tv = { 0 };
int update = mud_update(mud);
if (mud_can_read && tun_can_write) {
tv.tv_usec = 0;
} else if (tun_can_read && mud_can_write) {
long send_wait = mud_send_wait(mud);
if (send_wait >= 0)
tv.tv_usec = send_wait * 1000;
if (update >= 0) {
if (mud_can_read && tun_can_write) {
} else if (tun_can_read && mud_can_write) {
if (update)
tv.tv_usec = 1000;
} else {
tv.tv_usec = 100000;
}
}
const int ret = select(last_fd, &rfds, &wfds, NULL, &tv);
const int ret = select(last_fd, &rfds, &wfds, NULL, update < 0 ? NULL : &tv);
if (ret == -1) {
if (errno == EBADF) {
@@ -267,17 +255,10 @@ gt_bind(int argc, char **argv)
continue;
}
if (FD_ISSET(tun_fd, &rfds))
tun_can_read = 1;
if (FD_ISSET(tun_fd, &wfds))
tun_can_write = 1;
if (FD_ISSET(mud_fd, &rfds))
mud_can_read = 1;
if (FD_ISSET(mud_fd, &wfds))
mud_can_write = 1;
if (FD_ISSET(tun_fd, &rfds)) tun_can_read = 1;
if (FD_ISSET(tun_fd, &wfds)) tun_can_write = 1;
if (FD_ISSET(mud_fd, &rfds)) mud_can_read = 1;
if (FD_ISSET(mud_fd, &wfds)) mud_can_write = 1;
mtu = gt_setup_mtu(mud, mtu, tun_name);
@@ -286,7 +267,7 @@ gt_bind(int argc, char **argv)
int r = tun_read(tun_fd, buf, sizeof(buf));
if (r > 0 && !ip_get_common(&ic, buf, r)) {
mud_send(mud, buf, (size_t)r, ic.tc);
mud_send(mud, buf, (size_t)r);
mud_can_write = 0;
}
@@ -320,9 +301,26 @@ gt_bind(int argc, char **argv)
break;
case CTL_STATE:
if (mud_set_state(mud, (struct sockaddr *)&req.path.addr,
req.path.state, req.path.rate_tx, req.path.rate_rx))
req.path.state,
req.path.rate_tx,
req.path.rate_rx,
req.path.beat,
req.path.fixed_rate,
req.path.loss_limit))
res.ret = errno;
break;
case CTL_CONF:
if (mud_set_conf(mud, &req.conf))
res.ret = errno;
break;
case CTL_STATUS:
memcpy(res.status.tun_name, tun_name, sizeof(tun_name)); // XXX
res.status.pid = pid;
res.status.mtu = mtu;
res.status.chacha = chacha;
res.status.bind = bind_addr;
res.status.peer = peer_addr;
break;
case CTL_PATH_STATUS:
{
unsigned count = 0;
@@ -346,30 +344,10 @@ gt_bind(int argc, char **argv)
res.ret = 0;
}
break;
case CTL_MTU:
mud_set_mtu(mud, req.mtu);
res.mtu = mtu = gt_setup_mtu(mud, mtu, tun_name);
break;
case CTL_TC:
if (mud_set_tc(mud, req.tc))
case CTL_BAD:
if (mud_get_bad(mud, &res.bad))
res.ret = errno;
break;
case CTL_KXTIMEOUT:
if (mud_set_keyx_timeout(mud, req.ms))
res.ret = errno;
break;
case CTL_TIMETOLERANCE:
if (mud_set_time_tolerance(mud, req.ms))
res.ret = errno;
break;
case CTL_STATUS:
memcpy(res.status.tun_name, tun_name, sizeof(tun_name)); // XXX
res.status.pid = pid;
res.status.mtu = mtu;
res.status.chacha = chacha;
res.status.bind = bind_addr;
res.status.peer = peer_addr;
break;
}
if (sendto(ctl_fd, &res, sizeof(res), 0,
(const struct sockaddr *)&ss, sl) == -1)

View File

@@ -21,10 +21,6 @@
#define PACKAGE_VERSION "0.0.0"
#endif
#ifndef GT_RUNDIR
#define GT_RUNDIR "/run/" PACKAGE_NAME
#endif
#define COUNT(x) (sizeof(x)/sizeof(x[0]))
#define ALIGN_SIZE (1<<4)
@@ -54,6 +50,8 @@
#undef MIN
#define MIN(x,y) ({ __typeof__(x) X=(x); __typeof__(y) Y=(y); X < Y ? X : Y; })
#define GT_CIPHER(x) ((x) ? "chacha20poly1305" : "aegis256")
extern volatile sig_atomic_t gt_alarm;
extern volatile sig_atomic_t gt_reload;
extern volatile sig_atomic_t gt_quit;

View File

@@ -5,11 +5,45 @@
#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <libgen.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/un.h>
char *
ctl_rundir(char *dst, size_t size)
{
if (dst && size)
dst[0] = 0;
const char *fmt[] = {
"/run/user/%u/" PACKAGE_NAME,
"/run/" PACKAGE_NAME ".%u",
"/var/run/" PACKAGE_NAME ".%u",
"/tmp/" PACKAGE_NAME ".%u",
};
for (unsigned i = 0; i < COUNT(fmt); i++) {
char path[128];
int ret = snprintf(dst, size, fmt[i], geteuid());
if ((ret <= 0) ||
((size_t)ret >= size) ||
((size_t)ret >= sizeof(path)))
continue;
memcpy(path, dst, (size_t)ret + 1);
char *p = dirname(path);
if (p && !access(p, W_OK))
return dst;
}
errno = EINTR;
return NULL;
}
int
ctl_reply(int fd, struct ctl_msg *res, struct ctl_msg *req)
{
@@ -88,12 +122,12 @@ ctl_delete(int fd)
}
int
ctl_create(const char *dir, const char *file)
ctl_create(const char *file)
{
if (str_empty(dir)) {
errno = EINVAL;
char dir[64];
if (!ctl_rundir(dir, sizeof(dir)))
return -1;
}
if (mkdir(dir, 0700) == -1 && errno != EEXIST)
return -1;
@@ -111,14 +145,13 @@ ctl_create(const char *dir, const char *file)
}
int
ctl_connect(const char *dir, const char *file)
ctl_connect(const char *file)
{
char dir[64];
DIR *dp = NULL;
if (str_empty(dir)) {
errno = EINVAL;
if (!ctl_rundir(dir, sizeof(dir)))
return -1;
}
if (!file) {
if (dp = opendir(dir), !dp)
@@ -156,9 +189,10 @@ ctl_connect(const char *dir, const char *file)
if (ret)
return -1;
int fd = ctl_create(dir, NULL);
int fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (connect(fd, (struct sockaddr *)&sun, sizeof(sun))) {
if (ctl_bind(fd, dir, NULL) ||
connect(fd, (struct sockaddr *)&sun, sizeof(sun))) {
int err = errno;
ctl_delete(fd);
errno = err;

View File

@@ -10,12 +10,10 @@
enum ctl_type {
CTL_NONE = 0,
CTL_STATE,
CTL_CONF,
CTL_STATUS,
CTL_MTU,
CTL_TC,
CTL_KXTIMEOUT,
CTL_TIMETOLERANCE,
CTL_PATH_STATUS,
CTL_BAD,
};
struct ctl_msg {
@@ -27,8 +25,10 @@ struct ctl_msg {
enum mud_state state;
unsigned long rate_tx;
unsigned long rate_rx;
unsigned long beat;
unsigned char fixed_rate;
unsigned char loss_limit;
} path;
struct mud_path path_status;
struct {
char tun_name[64];
long pid;
@@ -37,13 +37,14 @@ struct ctl_msg {
struct sockaddr_storage bind;
struct sockaddr_storage peer;
} status;
size_t mtu;
int tc;
unsigned long ms;
struct mud_conf conf;
struct mud_path path_status;
struct mud_bad bad;
};
};
int ctl_create (const char *, const char *);
int ctl_connect (const char *, const char *);
int ctl_reply (int, struct ctl_msg *, struct ctl_msg *);
void ctl_delete (int);
char *ctl_rundir (char *, size_t);
int ctl_create (const char *);
int ctl_connect (const char *);
int ctl_reply (int, struct ctl_msg *, struct ctl_msg *);
void ctl_delete (int);

View File

@@ -31,33 +31,35 @@ gt_path_print_status(struct mud_path *path, int term)
default: return;
}
const char *statusstr = path->ok ? "OK" : "DEGRADED";
printf(term ? "path %s\n"
" status: %s\n"
" bind: %s port %"PRIu16"\n"
" public: %s port %"PRIu16"\n"
" peer: %s port %"PRIu16"\n"
" mtu: %zu bytes\n"
" rtt: %.3f ms\n"
" rttvar: %.3f ms\n"
" rate tx: %"PRIu64" bytes/sec\n"
" rate rx: %"PRIu64" bytes/sec\n"
" total tx: %"PRIu64" packets\n"
" total rx: %"PRIu64" packets\n"
" status: %s\n"
" bind: %s port %"PRIu16"\n"
" public: %s port %"PRIu16"\n"
" peer: %s port %"PRIu16"\n"
" mtu: %zu bytes\n"
" rtt: %.3f ms\n"
" rttvar: %.3f ms\n"
" rate: %s\n"
" losslim: %u\n"
" beat: %"PRIu64" ms\n"
" tx:\n"
" rate: %"PRIu64" bytes/sec\n"
" loss: %"PRIu64" percent\n"
" total: %"PRIu64" packets\n"
" rx:\n"
" rate: %"PRIu64" bytes/sec\n"
" loss: %"PRIu64" percent\n"
" total: %"PRIu64" packets\n"
: "path %s %s"
" %s %"PRIu16
" %s %"PRIu16
" %s %"PRIu16
" %zu"
" %.3f %.3f"
" %"PRIu64
" %"PRIu64
" %"PRIu64
" %s %"PRIu16" %s %"PRIu16" %s %"PRIu16
" %zu %.3f %.3f"
" %s %u"
" %"PRIu64
" %"PRIu64" %"PRIu64" %"PRIu64
" %"PRIu64" %"PRIu64" %"PRIu64
"\n",
statestr,
statusstr,
path->ok ? "OK" : "DEGRADED",
bindstr[0] ? bindstr : "-",
gt_get_port((struct sockaddr *)&path->local_addr),
publstr[0] ? publstr : "-",
@@ -67,10 +69,15 @@ gt_path_print_status(struct mud_path *path, int term)
path->mtu.ok,
(double)path->rtt.val / 1e3,
(double)path->rtt.var / 1e3,
path->rate_tx,
path->rate_rx,
path->send.total,
path->recv.total);
path->conf.fixed_rate ? "fixed" : "auto",
path->conf.loss_limit * 100 / 255,
path->conf.beat / 1000,
path->tx.rate,
path->tx.loss * 100 / 255,
path->tx.total,
path->rx.rate,
path->rx.loss * 100 / 255,
path->rx.total);
}
static int
@@ -95,7 +102,7 @@ gt_path_cmp_addr(struct sockaddr_storage *a, struct sockaddr_storage *b)
}
static int
gt_path_status(int fd, int state, struct sockaddr_storage *addr)
gt_path_status(int fd, enum mud_state state, struct sockaddr_storage *addr)
{
struct ctl_msg req = {
.type = CTL_PATH_STATUS,
@@ -140,6 +147,7 @@ int
gt_path(int argc, char **argv)
{
const char *dev = NULL;
unsigned int loss_limit = 0;
struct ctl_msg req = {
.type = CTL_STATE,
@@ -149,6 +157,7 @@ gt_path(int argc, char **argv)
}, res = {0};
struct argz ratez[] = {
{"fixed|auto", NULL, NULL, argz_option},
{"tx", "BYTES/SEC", &req.path.rate_tx, argz_bytes},
{"rx", "BYTES/SEC", &req.path.rate_rx, argz_bytes},
{NULL}};
@@ -158,12 +167,14 @@ gt_path(int argc, char **argv)
{"dev", "NAME", &dev, argz_str},
{"up|backup|down", NULL, NULL, argz_option},
{"rate", NULL, &ratez, argz_option},
{"beat", "SECONDS", &req.path.beat, argz_time},
{"losslimit", "PERCENT", &loss_limit, argz_percent},
{NULL}};
if (argz(pathz, argc, argv))
return 1;
int fd = ctl_connect(GT_RUNDIR, dev);
int fd = ctl_connect(dev);
if (fd < 0) {
switch (fd) {
@@ -182,9 +193,11 @@ gt_path(int argc, char **argv)
return 1;
}
int set_rate = argz_is_set(pathz, "rate");
int set = argz_is_set(pathz, "rate")
|| argz_is_set(pathz, "beat")
|| argz_is_set(pathz, "losslimit");
if (set_rate && !req.path.addr.ss_family) {
if (set && !req.path.addr.ss_family) {
gt_log("please specify a path\n");
return 1;
}
@@ -197,10 +210,19 @@ gt_path(int argc, char **argv)
req.path.state = MUD_DOWN;
}
if (loss_limit)
req.path.loss_limit = loss_limit * 255 / 100;
if (argz_is_set(ratez, "fixed")) {
req.path.fixed_rate = 3;
} else if (argz_is_set(ratez, "auto")) {
req.path.fixed_rate = 1;
}
int ret;
if (!req.path.addr.ss_family ||
(req.path.state == MUD_EMPTY && !set_rate)) {
(req.path.state == MUD_EMPTY && !set)) {
ret = gt_path_status(fd, req.path.state, &req.path.addr);
} else {
ret = ctl_reply(fd, &res, &req);

111
src/set.c
View File

@@ -7,80 +7,6 @@
#include "../argz/argz.h"
static int
gt_set_mtu(int fd, size_t mtu)
{
struct ctl_msg res, req = {
.type = CTL_MTU,
.mtu = mtu,
};
int ret = ctl_reply(fd, &res, &req);
if (ret) {
perror("set mtu");
return 1;
}
printf("mtu set to %zu\n", res.mtu);
return 0;
}
static int
gt_set_kxtimeout(int fd, unsigned long ms)
{
struct ctl_msg res, req = {
.type = CTL_KXTIMEOUT,
.ms = ms,
};
int ret = ctl_reply(fd, &res, &req);
if (ret) {
perror("set kxtimeout");
return 1;
}
return 0;
}
static int
gt_set_timetolerance(int fd, unsigned long ms)
{
struct ctl_msg res, req = {
.type = CTL_TIMETOLERANCE,
.ms = ms,
};
int ret = ctl_reply(fd, &res, &req);
if (ret) {
perror("set timetolerance");
return 1;
}
return 0;
}
static int
gt_set_tc(int fd, int tc)
{
struct ctl_msg res, req = {
.type = CTL_TC,
.tc = tc,
};
int ret = ctl_reply(fd, &res, &req);
if (ret) {
perror("set tc");
return 1;
}
return 0;
}
static int
gt_argz_tc(void *data, int argc, char **argv)
{
@@ -102,7 +28,7 @@ gt_argz_tc(void *data, int argc, char **argv)
} else return -1;
if (data)
*(int *)data = val;
*(int *)data = (val << 1) | 1;
return 1;
}
@@ -111,23 +37,23 @@ int
gt_set(int argc, char **argv)
{
const char *dev = NULL;
size_t mtu;
int tc;
unsigned long kxtimeout;
unsigned long timetolerance;
struct ctl_msg req = {
.type = CTL_CONF,
}, res = {0};
struct argz pathz[] = {
{"dev", "NAME", &dev, argz_str},
{"mtu", "BYTES", &mtu, argz_bytes},
{"tc", "CS|AF|EF", &tc, gt_argz_tc},
{"kxtimeout", "SECONDS", &kxtimeout, argz_time},
{"timetolerance", "SECONDS", &timetolerance, argz_time},
{"tc", "CS|AF|EF", &req.conf.tc, gt_argz_tc},
{"kxtimeout", "SECONDS", &req.conf.kxtimeout, argz_time},
{"timetolerance", "SECONDS", &req.conf.timetolerance, argz_time},
{"keepalive", "SECONDS", &req.conf.keepalive, argz_time},
{NULL}};
if (argz(pathz, argc, argv))
return 1;
int fd = ctl_connect(GT_RUNDIR, dev);
int fd = ctl_connect(dev);
if (fd < 0) {
switch (fd) {
@@ -146,21 +72,12 @@ gt_set(int argc, char **argv)
return 1;
}
int ret = 0;
int ret = ctl_reply(fd, &res, &req);
if (argz_is_set(pathz, "mtu"))
ret |= gt_set_mtu(fd, mtu);
if (argz_is_set(pathz, "tc"))
ret |= gt_set_tc(fd, tc);
if (argz_is_set(pathz, "kxtimeout"))
ret |= gt_set_kxtimeout(fd, kxtimeout);
if (argz_is_set(pathz, "timetolerance"))
ret |= gt_set_timetolerance(fd, timetolerance);
if (ret)
perror("set");
ctl_delete(fd);
return ret;
return !!ret;
}

View File

@@ -11,6 +11,47 @@
#include <arpa/inet.h>
#include <unistd.h>
static void
gt_show_bad_line(int term, char *name, uint64_t count,
struct sockaddr_storage *ss)
{
if (!count)
return;
char addr[INET6_ADDRSTRLEN];
gt_toaddr(addr, sizeof(addr), (struct sockaddr *)ss);
printf(term ? "%s:\n"
" count: %"PRIu64"\n"
" last: %s port %"PRIu16"\n"
: "%s"
" %"PRIu64
" %s %"PRIu16
"\n",
name, count, addr[0] ? addr : "-",
gt_get_port((struct sockaddr *)ss));
}
static int
gt_show_bad(int fd)
{
struct ctl_msg res, req = {.type = CTL_BAD};
if (ctl_reply(fd, &res, &req))
return -1;
int term = isatty(1);
gt_show_bad_line(term, "decrypt",
res.bad.decrypt.count, &res.bad.decrypt.addr);
gt_show_bad_line(term, "difftime",
res.bad.difftime.count, &res.bad.difftime.addr);
gt_show_bad_line(term, "keyx",
res.bad.keyx.count, &res.bad.keyx.addr);
return 0;
}
static int
gt_show_status(int fd)
{
@@ -47,7 +88,7 @@ gt_show_status(int fd)
bindstr[0] ? bindstr : "-",
gt_get_port((struct sockaddr *)&res.status.bind),
res.status.mtu,
res.status.chacha ? "chacha20poly1305" : "aes256gcm");
GT_CIPHER(res.status.chacha));
} else {
printf(term ? "client %s:\n"
" pid: %li\n"
@@ -69,7 +110,7 @@ gt_show_status(int fd)
peerstr[0] ? peerstr : "-",
gt_get_port((struct sockaddr *)&res.status.peer),
res.status.mtu,
res.status.chacha ? "chacha20poly1305" : "aes256gcm");
GT_CIPHER(res.status.chacha));
}
return 0;
@@ -82,12 +123,13 @@ gt_show(int argc, char **argv)
struct argz showz[] = {
{"dev", "NAME", &dev, argz_str},
{"bad", NULL, NULL, argz_option},
{NULL}};
if (argz(showz, argc, argv))
return 1;
int fd = ctl_connect(GT_RUNDIR, dev);
int fd = ctl_connect(dev);
if (fd < 0) {
switch (fd) {
@@ -106,7 +148,9 @@ gt_show(int argc, char **argv)
return 1;
}
int ret = gt_show_status(fd);
int ret = argz_is_set(showz, "bad")
? gt_show_bad(fd)
: gt_show_status(fd);
if (ret == -1)
perror("show");