Compare commits

...

59 Commits

Author SHA1 Message Date
Adrien Gallouët
fd7ddf7814 Update mud
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-09-24 09:57:21 +00:00
Adrien Gallouët
7e7b52f9fd Try to limit pkt drops
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-09-19 14:00:00 +00:00
Adrien Gallouët
97784c43ac Revert "Try to use submodules"
This reverts commit bccc9945f4.
2019-09-17 17:07:45 +00:00
Adrien Gallouët
4b4c080cc4 Use aegis256
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-09-17 16:48:42 +00:00
Adrien Gallouët
43e1dfe86f Update argz
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-09-16 15:20:58 +00:00
Adrien Gallouët
ed1cf51af2 Don't use -j alone for portability
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-09-16 15:20:41 +00:00
Adrien Gallouët
264f26286d Move static build files in .static
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-09-11 21:08:59 +00:00
Adrien Gallouët
7c17e16fea Block on sendmsg and revert 4a68866
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-09-09 16:25:35 +00:00
Adrien Gallouët
38d31c0637 Upload artifact
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-09-04 10:33:01 +00:00
Adrien Gallouët
bccc9945f4 Try to use submodules
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-09-04 09:59:59 +00:00
Adrien Gallouët
9c9f679497 Update mud
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-09-03 16:56:50 +00:00
Adrien Gallouët
9177778d0f Add .github/workflows/ccpp.yml
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-09-03 16:27:57 +00:00
Adrien Gallouët
6853b59dc3 Add sodium.sh
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-09-03 16:27:57 +00:00
Adrien Gallouët
d451bc75b0 Doll up
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-07-23 13:17:59 +00:00
Adrien Gallouët
1f82b15373 Code cleanup
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-07-22 13:08:17 +00:00
Adrien Gallouët
56b5a41633 Code cleanup
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-07-21 15:05:48 +00:00
Adrien Gallouët
004380827f A more friendly command path
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-07-21 15:05:48 +00:00
Adrien Gallouët
a7f57de42a Remove useless tests in ctl
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-07-21 15:05:48 +00:00
Adrien Gallouët
2f3f9e7e86 Update desc of show
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-07-20 08:53:47 +00:00
Adrien Gallouët
0528adcfe2 Code cleanup
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-07-20 08:19:55 +00:00
Adrien Gallouët
67ea65b1a8 Don't show all tunnels
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-07-19 22:40:31 +00:00
Adrien Gallouët
ed82531fc0 Always unlink ctl socket
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-07-19 21:51:28 +00:00
Adrien Gallouët
e077554304 Update mud
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-07-19 13:20:55 +00:00
Adrien Gallouët
b9f31b2445 Update mud
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-07-19 13:00:33 +00:00
Adrien Gallouët
76036a6535 Update mud
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-07-17 15:00:23 +00:00
Adrien Gallouët
cce55fac21 Unlock glorytun path
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-07-17 14:30:23 +00:00
Adrien Gallouët
a72075036a Use argz for libsodium version
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-07-15 13:36:31 +00:00
Adrien Gallouët
84184c644a Add command version libsodium
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-07-15 11:09:12 +00:00
Adrien Gallouët
7f238c2599 Bench chacha if aes is not supported and not asked
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-07-15 10:23:41 +00:00
Adrien Gallouët
170b3df0af Improve error messages
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-06-27 14:18:31 +00:00
Adrien Gallouët
4a68866201 Try to get all packets from mud
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-06-27 14:17:39 +00:00
Adrien Gallouët
5e89ebc550 Improve error messages
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-06-24 13:04:39 +00:00
Adrien Gallouët
7e95f7a8ae Remove duplicate code in ctl_bind()
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-06-24 12:22:54 +00:00
Adrien Gallouët
968cafe21b Fix errno
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-06-24 12:07:36 +00:00
Adrien Gallouët
d4e5ea7c0a Abort if fd_set_nonblock() fails
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-06-24 11:36:01 +00:00
Adrien Gallouët
e6793f9b54 Fix last commit
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-06-21 15:27:42 +00:00
Adrien Gallouët
5976434285 Just enjoy snprintf()
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-06-14 18:42:29 +00:00
Adrien Gallouët
db718d5942 Update README.md
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-04-03 10:00:59 +00:00
Adrien Gallouët
3da880f5c5 Use -fstack-protector-strong
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-04-03 09:38:53 +00:00
Adrien Gallouët
86fe69d644 Fix conversion in src/bind.c
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-04-03 09:33:07 +00:00
Adrien Gallouët
5c29753343 Fix conversion in src/bench.c
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-04-03 09:30:54 +00:00
Adrien Gallouët
70bc9cc205 Update mud
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-04-03 09:25:42 +00:00
Adrien Gallouët
5c3ec8e264 Update argz
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-04-03 09:10:21 +00:00
Adrien Gallouët
6496adcd91 Cleanup Makefile
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-04-02 15:52:28 +00:00
Adrien Gallouët
4ec2079e22 Always use size_t for MTU
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-04-02 14:41:33 +00:00
Adrien Gallouët
f4611efbb2 Fix conversion in src/path.c
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-04-02 14:41:33 +00:00
Adrien Gallouët
d703a66988 Compute sun_path from PID
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-04-02 14:15:13 +00:00
Adrien Gallouët
568eeee70b Fix conversion in src/common.c
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-04-02 14:15:13 +00:00
Adrien Gallouët
6e6c72746f Fix conversion in src/tun.c
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-04-02 14:15:02 +00:00
Adrien Gallouët
cd2ee2a7af Fix conversion in src/ip.h
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-04-02 14:14:47 +00:00
Adrien Gallouët
e338626c46 Update mud
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-04-01 15:38:07 +00:00
Adrien Gallouët
71aedce8b2 Ask for a non pedantic c11 compiler 2019-04-01 13:16:29 +00:00
Adrien Gallouët
9c8e043053 Add a stupid untracked Makefile 2019-04-01 07:48:55 +00:00
Adrien Gallouët
871f488097 Remove old sync command
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-03-09 15:07:18 +00:00
Adrien Gallouët
159104ce9c Don't wake up without paths
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-03-09 14:39:22 +00:00
Adrien Gallouët
0dddca3b61 Update LICENSE --recursive
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-03-05 21:59:37 +00:00
Adrien Gallouët
cbae4f5a30 Update mud
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-03-05 11:06:43 +00:00
Adrien Gallouët
61db08063c Update README.md
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-02-22 09:16:15 +00:00
Adrien Gallouët
dec3151fd2 Update README.md
Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
2019-02-17 20:21:02 +00:00
26 changed files with 485 additions and 440 deletions

24
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,24 @@
name: Build
on: [push]
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macOS-latest]
steps:
- uses: actions/checkout@v1
- name: Build glorytun
run: |
git submodule update --init --recursive
./sodium.sh
make prefix=. install
- uses: actions/upload-artifact@v1
with:
name: bin
path: ./bin

1
.gitignore vendored
View File

@@ -10,6 +10,7 @@ configure
build-aux build-aux
.deps .deps
.dirstamp .dirstamp
.static
glorytun glorytun
build* build*
VERSION VERSION

View File

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

35
Makefile Normal file
View File

@@ -0,0 +1,35 @@
NAME := glorytun
VERSION := $(shell ./version.sh)
DIST := $(NAME)-$(VERSION)
DESTDIR ?=
CC ?= gcc
INSTALL ?= install
prefix ?= /usr
CFLAGS ?= -std=c11 -O2 -Wall -fstack-protector-strong
FLAGS := $(CFLAGS) $(LDFLAGS) $(CPPFLAGS)
FLAGS += -DPACKAGE_NAME=\"$(NAME)\" -DPACKAGE_VERSION=\"$(VERSION)\"
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)
.PHONY: $(NAME)
$(NAME):
@echo "Building $(NAME)"
@$(CC) $(FLAGS) -o $(NAME) $(SRC) -lsodium -lm
.PHONY: install
install: $(NAME)
@echo "Installing $(NAME)"
@$(INSTALL) -m 755 -d $(DESTDIR)$(prefix)/bin
@$(INSTALL) -m 755 -s $(NAME) $(DESTDIR)$(prefix)/bin
.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

View File

@@ -9,6 +9,8 @@ glorytun_SOURCES = \
argz/argz.h \ argz/argz.h \
mud/mud.c \ mud/mud.c \
mud/mud.h \ mud/mud.h \
mud/aegis256/aegis256.c \
mud/aegis256/aegis256.h \
src/bench.c \ src/bench.c \
src/bind.c \ src/bind.c \
src/common.c \ src/common.c \
@@ -24,7 +26,6 @@ glorytun_SOURCES = \
src/set.c \ src/set.c \
src/show.c \ src/show.c \
src/str.h \ src/str.h \
src/sync.c \
src/tun.c \ src/tun.c \
src/tun.h src/tun.h

View File

@@ -6,9 +6,12 @@ Glorytun is a small, simple and secure VPN over [mud](https://github.com/angt/mu
Glorytun only depends on [libsodium](https://github.com/jedisct1/libsodium) version >= 1.0.4. Glorytun only depends on [libsodium](https://github.com/jedisct1/libsodium) version >= 1.0.4.
Which can be installed on a wide variety of systems. Which can be installed on a wide variety of systems.
Linux is the platform of choice but the code is standard so it should be easily ported on other posix systems. Linux is the platform of choice but the code is standard so it should be easily ported on other posix systems.
It was successfully tested on OpenBSD, FreeBSD and MacOS. It was successfully tested on OpenBSD, FreeBSD and MacOS.
IPv4 and IPv6 are supported.
## Features ## Features
The key features of Glorytun come directly from mud: The key features of Glorytun come directly from mud:
@@ -17,8 +20,8 @@ The key features of Glorytun come directly from mud:
The use of UDP and [libsodium](https://github.com/jedisct1/libsodium) allows you to secure The use of UDP and [libsodium](https://github.com/jedisct1/libsodium) allows you to secure
your communications without impacting performance. your communications without impacting performance.
Glorytun uses AES only if AES-NI is available otherwise ChaCha20 is used. Glorytun uses AEGIS-256 only if AES-NI is available otherwise ChaCha20Poly1305 is used.
You can force the use of ChaCha20 for higher security. 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. All messages are encrypted, authenticated and marked with a timestamp.
Perfect forward secrecy is also implemented with ECDH over Curve25519. Perfect forward secrecy is also implemented with ECDH over Curve25519.
@@ -26,6 +29,7 @@ The key features of Glorytun come directly from mud:
This is the main feature of Glorytun that allows to build an SD-WAN like service. 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. 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.
* **Traffic shaping** * **Traffic shaping**
@@ -48,22 +52,20 @@ By default, an offset of 10min is accepted.
## Build and Install ## Build and Install
We recommend the use of [meson](http://mesonbuild.com) for building instead of You will need `git`, `make`, `gcc` and `libsodium`:
the more classical autotools suite (also available for old systems).
On Ubuntu, the following command should be sufficient to get all the necessary build dependencies: $ sudo apt install git make gcc libsodium-dev # debian based
$ sudo yum install git make gcc libsodium-devel # redhat based
$ sudo apt-get install meson libsodium-dev pkg-config
To build and install the latest release from github: To build and install the latest release from github:
$ git clone https://github.com/angt/glorytun --recursive $ git clone https://github.com/angt/glorytun --recursive
$ meson glorytun glorytun/build $ cd glorytun
$ sudo ninja -C glorytun/build install $ sudo make install
This will install all binaries in `/usr/local/bin` by default. This will install the binary in `/usr/bin` by default.
You can easily customize your setup with meson (see `meson help`). The more classical autotools suite is also available.
## Usage ## Usage
@@ -73,11 +75,10 @@ Just run `glorytun` with no arguments to view the list of available commands:
$ glorytun $ glorytun
available commands: available commands:
show show all running tunnels show show tunnel info
bench start a crypto bench bench start a crypto bench
bind start a new tunnel bind start a new tunnel
set change tunnel properties set change tunnel properties
sync re-sync tunnels
keygen generate a new secret key keygen generate a new secret key
path manage paths path manage paths
version show version version show version

2
argz

Submodule argz updated: 331948c772...47ad9daf43

View File

@@ -23,6 +23,7 @@ executable('glorytun', install: true,
sources: [ sources: [
'argz/argz.c', 'argz/argz.c',
'mud/mud.c', 'mud/mud.c',
'mud/aegis256/aegis256.c',
'src/bench.c', 'src/bench.c',
'src/bind.c', 'src/bind.c',
'src/common.c', 'src/common.c',
@@ -33,7 +34,6 @@ executable('glorytun', install: true,
'src/path.c', 'src/path.c',
'src/set.c', 'src/set.c',
'src/show.c', 'src/show.c',
'src/sync.c',
'src/tun.c', 'src/tun.c',
], ],
dependencies: [ dependencies: [

2
mud

Submodule mud updated: adf3bf6710...4d14689ff1

29
sodium.sh Executable file
View File

@@ -0,0 +1,29 @@
#!/bin/sh
mkdir -p .static
cd .static || exit 1
file=LATEST.tar.gz
url=https://download.libsodium.org/libsodium/releases
dir="$PWD"
[ -f "$file" ] || wget -q "$url/$file" -O "$file"
[ -f "$file" ] || curl -SsfLO "$url/$file"
[ -f "$file" ] || {
echo "Couldn't download $url/$file"
exit 1
}
if [ "$1" ]; then
mkdir -p "$1"
cd "$1" || exit 1
fi
rm -rf libsodium-stable
tar zxf "$dir/$file"
cd libsodium-stable || exit 1
NPROC=$(sysctl -n hw.ncpu || nproc) 2>/dev/null
./configure ${1+--host=$1} --enable-minimal --disable-dependency-tracking --enable-static --disable-shared
make "-j$((NPROC+1))"

View File

@@ -13,9 +13,14 @@
#endif #endif
#include "../argz/argz.h" #include "../argz/argz.h"
#include "../mud/aegis256/aegis256.h"
#define STR_S(X) (((X) > 1) ? "s" : "") #define STR_S(X) (((X) > 1) ? "s" : "")
#define NPUBBYTES 32
#define KEYBYTES 32
#define ABYTES 16
static unsigned long long static unsigned long long
gt_now(void) gt_now(void)
{ {
@@ -27,11 +32,13 @@ gt_now(void)
#elif defined CLOCK_MONOTONIC #elif defined CLOCK_MONOTONIC
struct timespec tv; struct timespec tv;
clock_gettime(CLOCK_MONOTONIC, &tv); clock_gettime(CLOCK_MONOTONIC, &tv);
return tv.tv_sec * 1000000ULL + tv.tv_nsec / 1000ULL; return (unsigned long long)tv.tv_sec * 1000000ULL
+ (unsigned long long)tv.tv_nsec / 1000ULL;
#else #else
struct timeval tv; struct timeval tv;
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
return tv.tv_sec * 1000000ULL + tv.tv_usec; return (unsigned long long)tv.tv_sec * 1000000ULL
+ (unsigned long long)tv.tv_usec;
#endif #endif
} }
@@ -63,29 +70,33 @@ gt_bench(int argc, char **argv)
duration /= 1000; duration /= 1000;
int term = isatty(1); int term = isatty(1);
int aes = argz_is_set(bench_argz, "aes");
int chacha = argz_is_set(bench_argz, "chacha"); int chacha = argz_is_set(bench_argz, "chacha");
if (!chacha && !crypto_aead_aes256gcm_is_available()) { if (!aegis256_is_available()) {
gt_log("aes is not available on your platform\n"); if (aes) {
return 1; gt_log("aes is not available on your platform\n");
return 1;
}
chacha = 1;
} }
unsigned char *buf = calloc(1, bufsize + crypto_aead_aes256gcm_ABYTES); unsigned char *buf = calloc(1, bufsize + ABYTES);
if (!buf) { if (!buf) {
perror("calloc"); perror("calloc");
return 1; return 1;
} }
unsigned char npub[crypto_aead_aes256gcm_NPUBBYTES]; unsigned char npub[NPUBBYTES];
unsigned char key[crypto_aead_aes256gcm_KEYBYTES]; unsigned char key[KEYBYTES];
randombytes_buf(npub, sizeof(npub)); randombytes_buf(npub, sizeof(npub));
randombytes_buf(key, sizeof(key)); randombytes_buf(key, sizeof(key));
if (term) { if (term) {
printf("\n"); printf("\n");
printf(" %-10s %s\n", "bench", chacha ? "chacha20poly1305" : "aes256gcm"); printf(" %-10s %s\n", "bench", chacha ? "chacha20poly1305" : "aegis256");
printf(" %-10s %s\n", "libsodium", sodium_version_string()); printf(" %-10s %s\n", "libsodium", sodium_version_string());
printf("\n"); printf("\n");
printf(" %-10s 2^(-%lu)\n", "precision", precision); printf(" %-10s 2^(-%lu)\n", "precision", precision);
@@ -106,26 +117,20 @@ gt_bench(int argc, char **argv)
double mbps_dlt = INFINITY; double mbps_dlt = INFINITY;
while (!gt_quit && mbps_dlt > ldexp(mbps, -(int)precision)) { while (!gt_quit && mbps_dlt > ldexp(mbps, -(int)precision)) {
crypto_aead_aes256gcm_state ctx;
if (!chacha)
crypto_aead_aes256gcm_beforenm(&ctx, key);
unsigned long long now = gt_now(); unsigned long long now = gt_now();
double mbps_old = mbps; double mbps_old = mbps;
size_t bytes = 0; size_t bytes = 0;
gt_alarm = 0; gt_alarm = 0;
alarm(duration); alarm((unsigned int)duration);
while (!gt_quit && !gt_alarm) { while (!gt_quit && !gt_alarm) {
if (chacha) { if (chacha) {
crypto_aead_chacha20poly1305_encrypt( crypto_aead_chacha20poly1305_encrypt(
buf, NULL, buf, 1ULL << i, NULL, 0, NULL, npub, key); buf, NULL, buf, 1ULL << i, NULL, 0, NULL, npub, key);
} else { } else {
crypto_aead_aes256gcm_encrypt_afternm( aegis256_encrypt(
buf, NULL, buf, 1ULL << i, NULL, 0, NULL, npub, buf, NULL, buf, 1ULL << i, NULL, 0, npub, key);
(const crypto_aead_aes256gcm_state *)&ctx);
} }
bytes += 1ULL << i; bytes += 1ULL << i;
} }
@@ -133,7 +138,7 @@ gt_bench(int argc, char **argv)
total_dt += gt_now() - now; total_dt += gt_now() - now;
total_bytes += bytes; total_bytes += bytes;
mbps = (total_bytes * 8.0) / total_dt; mbps = ((double)total_bytes * 8.0) / (double)total_dt;
mbps_min = fmin(mbps_min, mbps); mbps_min = fmin(mbps_min, mbps);
mbps_max = fmax(mbps_max, mbps); mbps_max = fmax(mbps_max, mbps);
mbps_dlt = fabs(mbps_old - mbps); mbps_dlt = fabs(mbps_old - mbps);

View File

@@ -18,13 +18,13 @@
#define O_CLOEXEC 0 #define O_CLOEXEC 0
#endif #endif
static void static int
fd_set_nonblock(int fd) fd_set_nonblock(int fd)
{ {
int ret;
if (fd == -1) if (fd == -1)
return; return 0;
int ret;
do { do {
ret = fcntl(fd, F_GETFL, 0); ret = fcntl(fd, F_GETFL, 0);
@@ -36,8 +36,7 @@ fd_set_nonblock(int fd)
ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK); ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
} while (ret == -1 && errno == EINTR); } while (ret == -1 && errno == EINTR);
if (ret == -1) return ret;
perror("fcntl O_NONBLOCK");
} }
static int static int
@@ -50,7 +49,7 @@ gt_setup_secretkey(struct mud *mud, const char *keyfile)
} while (fd == -1 && errno == EINTR); } while (fd == -1 && errno == EINTR);
if (fd == -1) { if (fd == -1) {
perror("open keyfile"); gt_log("couldn't open %s: %s\n", keyfile, strerror(errno));
return -1; return -1;
} }
@@ -67,13 +66,13 @@ gt_setup_secretkey(struct mud *mud, const char *keyfile)
break; break;
} }
size += r; size += (size_t)r;
} }
close(fd); close(fd);
if (size != sizeof(buf)) { if (size != sizeof(buf)) {
gt_log("unable to read secret key\n"); gt_log("couldn't read secret key\n");
return -1; return -1;
} }
@@ -96,7 +95,7 @@ gt_setup_mtu(struct mud *mud, size_t old, const char *tun_name)
return mtu; return mtu;
if (iface_set_mtu(tun_name, mtu) == -1) if (iface_set_mtu(tun_name, mtu) == -1)
perror("tun_set_mtu"); gt_log("couldn't setup MTU at %zu on device %s\n", mtu, tun_name);
return mtu; return mtu;
} }
@@ -165,7 +164,7 @@ gt_bind(int argc, char **argv)
} }
char tun_name[64]; char tun_name[64];
const int tun_fd = tun_create(tun_name, sizeof(tun_name) - 1, dev); const int tun_fd = tun_create(tun_name, sizeof(tun_name), dev);
if (tun_fd == -1) { if (tun_fd == -1) {
gt_log("couldn't create tun device\n"); gt_log("couldn't create tun device\n");
@@ -174,8 +173,10 @@ gt_bind(int argc, char **argv)
size_t mtu = gt_setup_mtu(mud, 0, tun_name); size_t mtu = gt_setup_mtu(mud, 0, tun_name);
if (tun_set_persist(tun_fd, persist) == -1) if (tun_set_persist(tun_fd, persist) == -1) {
perror("tun_set_persist"); gt_log("couldn't %sable persist mode on device %s\n",
persist ? "en" : "dis", tun_name);
}
if (peer_addr.ss_family) { if (peer_addr.ss_family) {
if (mud_peer(mud, (struct sockaddr *)&peer_addr)) { if (mud_peer(mud, (struct sockaddr *)&peer_addr)) {
@@ -187,43 +188,76 @@ gt_bind(int argc, char **argv)
const int ctl_fd = ctl_create(GT_RUNDIR, tun_name); const int ctl_fd = ctl_create(GT_RUNDIR, tun_name);
if (ctl_fd == -1) { if (ctl_fd == -1) {
perror("ctl_create"); gt_log("couldn't create "GT_RUNDIR"/%s: %s\n",
tun_name, strerror(errno));
return 1; return 1;
} }
fd_set_nonblock(tun_fd); if (//fd_set_nonblock(tun_fd) ||
fd_set_nonblock(mud_fd); //fd_set_nonblock(mud_fd) ||
fd_set_nonblock(ctl_fd); fd_set_nonblock(ctl_fd)) {
gt_log("couldn't setup non-blocking fds\n");
return 1;
}
const long pid = (long)getpid(); const long pid = (long)getpid();
gt_log("running on device %s as pid %li\n", tun_name, pid); gt_log("running on device %s as pid %li\n", tun_name, pid);
fd_set rfds; fd_set rfds, wfds;
FD_ZERO(&rfds); FD_ZERO(&rfds);
FD_ZERO(&wfds);
const int last_fd = 1 + MAX(tun_fd, MAX(mud_fd, ctl_fd)); int tun_can_read = 0;
int tun_can_write = 0;
int mud_can_read = 0;
int mud_can_write = 0;
int last_fd = MAX(tun_fd, mud_fd);
last_fd = 1 + MAX(last_fd, ctl_fd);
unsigned char buf[4096]; unsigned char buf[4096];
while (!gt_quit) { while (!gt_quit) {
unsigned long send_wait = mud_send_wait(mud); if (tun_can_write) {
FD_CLR(tun_fd, &wfds);
} else {
FD_SET(tun_fd, &wfds);
}
if (send_wait) { if (mud_can_write) {
FD_CLR(mud_fd, &wfds);
} else {
FD_SET(mud_fd, &wfds);
}
if (tun_can_read) {
FD_CLR(tun_fd, &rfds); FD_CLR(tun_fd, &rfds);
} else { } else {
FD_SET(tun_fd, &rfds); FD_SET(tun_fd, &rfds);
} }
FD_SET(mud_fd, &rfds); if (mud_can_read) {
FD_CLR(mud_fd, &rfds);
} else {
FD_SET(mud_fd, &rfds);
}
FD_SET(ctl_fd, &rfds); FD_SET(ctl_fd, &rfds);
struct timeval tv = { struct timeval tv = {
.tv_sec = 0, .tv_usec = 100000,
.tv_usec = send_wait,
}; };
const int ret = select(last_fd, &rfds, NULL, NULL, send_wait ? &tv : NULL); 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;
}
const int ret = select(last_fd, &rfds, &wfds, NULL, &tv);
if (ret == -1) { if (ret == -1) {
if (errno == EBADF) { if (errno == EBADF) {
@@ -233,8 +267,43 @@ gt_bind(int argc, char **argv)
continue; 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;
mtu = gt_setup_mtu(mud, mtu, tun_name); mtu = gt_setup_mtu(mud, mtu, tun_name);
if (tun_can_read && mud_can_write && !mud_send_wait(mud)) {
struct ip_common ic;
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_can_write = 0;
}
tun_can_read = 0;
}
if (mud_can_read && tun_can_write) {
int r = mud_recv(mud, buf, sizeof(buf));
if (r > 0 && ip_is_valid(buf, r)) {
tun_write(tun_fd, buf, (size_t)r);
tun_can_write = 0;
}
mud_can_read = 0;
}
if (FD_ISSET(ctl_fd, &rfds)) { if (FD_ISSET(ctl_fd, &rfds)) {
struct ctl_msg req, res = {.reply = 1}; struct ctl_msg req, res = {.reply = 1};
struct sockaddr_storage ss; struct sockaddr_storage ss;
@@ -294,15 +363,13 @@ gt_bind(int argc, char **argv)
res.ret = errno; res.ret = errno;
break; break;
case CTL_STATUS: case CTL_STATUS:
memcpy(res.status.tun_name, tun_name, sizeof(tun_name)); // XXX
res.status.pid = pid; res.status.pid = pid;
res.status.mtu = mtu; res.status.mtu = mtu;
res.status.chacha = chacha; res.status.chacha = chacha;
res.status.bind = bind_addr; res.status.bind = bind_addr;
res.status.peer = peer_addr; res.status.peer = peer_addr;
break; break;
case CTL_SYNC:
res.ms = mud_sync(mud);
break;
} }
if (sendto(ctl_fd, &res, sizeof(res), 0, if (sendto(ctl_fd, &res, sizeof(res), 0,
(const struct sockaddr *)&ss, sl) == -1) (const struct sockaddr *)&ss, sl) == -1)
@@ -311,35 +378,10 @@ gt_bind(int argc, char **argv)
perror("recvfrom(ctl)"); perror("recvfrom(ctl)");
} }
} }
if (FD_ISSET(mud_fd, &rfds)) {
const int r = mud_recv(mud, buf, sizeof(buf));
if (ip_is_valid(buf, r))
tun_write(tun_fd, buf, r);
}
if (FD_ISSET(tun_fd, &rfds) && !mud_send_wait(mud)) {
struct ip_common ic;
const int r = tun_read(tun_fd, buf, sizeof(buf));
if (!ip_get_common(&ic, buf, r)) {
// TODO: disable hash for now
// unsigned char hash[crypto_shorthash_BYTES];
// crypto_shorthash(hash, (const unsigned char *)&ic, sizeof(ic), hashkey);
unsigned h = 0;
// memcpy(&h, hash, sizeof(h));
mud_send(mud, buf, r, (h << 8) | ic.tc);
}
}
} }
if (gt_reload && tun_fd >= 0) { if (gt_reload && tun_fd >= 0)
if (tun_set_persist(tun_fd, 1) == -1) tun_set_persist(tun_fd, 1);
perror("tun_set_persist");
}
mud_delete(mud); mud_delete(mud);
ctl_delete(ctl_fd); ctl_delete(ctl_fd);

View File

@@ -64,7 +64,7 @@ gt_fromhex(uint8_t *dst, size_t dst_size, const char *src, size_t src_size)
if (_0_(a == -1 || b == -1)) if (_0_(a == -1 || b == -1))
return -1; return -1;
*dst++ = (a << 4) | b; *dst++ = (uint8_t)((a << 4) | b);
} }
return 0; return 0;
@@ -105,10 +105,10 @@ gt_toaddr(char *str, size_t size, struct sockaddr *sa)
switch (sa->sa_family) { switch (sa->sa_family) {
case AF_INET: case AF_INET:
return -!inet_ntop(AF_INET, return -!inet_ntop(AF_INET,
&((struct sockaddr_in *)sa)->sin_addr, str, size); &((struct sockaddr_in *)sa)->sin_addr, str, (socklen_t)size);
case AF_INET6: case AF_INET6:
return -!inet_ntop(AF_INET6, return -!inet_ntop(AF_INET6,
&((struct sockaddr_in6 *)sa)->sin6_addr, str, size); &((struct sockaddr_in6 *)sa)->sin6_addr, str, (socklen_t)size);
} }
errno = EAFNOSUPPORT; errno = EAFNOSUPPORT;

View File

@@ -74,4 +74,3 @@ int gt_path (int, char **);
int gt_keygen (int, char **); int gt_keygen (int, char **);
int gt_bench (int, char **); int gt_bench (int, char **);
int gt_set (int, char **); int gt_set (int, char **);
int gt_sync (int, char **);

View File

@@ -6,25 +6,19 @@
#include <unistd.h> #include <unistd.h>
#include <dirent.h> #include <dirent.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/un.h> #include <sys/un.h>
#define CTL_BIND_MAX 64
int int
ctl_reply(int fd, struct ctl_msg *res, struct ctl_msg *req) ctl_reply(int fd, struct ctl_msg *res, struct ctl_msg *req)
{ {
if (fd == -1) {
errno = EINVAL;
return -1;
}
if ((send(fd, req, sizeof(struct ctl_msg), 0) == -1) || if ((send(fd, req, sizeof(struct ctl_msg), 0) == -1) ||
(recv(fd, res, sizeof(struct ctl_msg), 0) == -1)) (recv(fd, res, sizeof(struct ctl_msg), 0) == -1))
return -1; return -1;
if (res->type != req->type || !res->reply) { if (res->type != req->type || !res->reply) {
errno = EINTR; errno = EBADMSG;
return -1; return -1;
} }
@@ -43,17 +37,15 @@ ctl_setsun(struct sockaddr_un *dst, const char *dir, const char *file)
.sun_family = AF_UNIX, .sun_family = AF_UNIX,
}; };
const char *path[] = {dir, "/", file}; int ret = snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/%s", dir, file);
const size_t len = sizeof(sun.sun_path) - 1;
if (str_cat(sun.sun_path, len, path, COUNT(path)) == len) { if (ret <= 0 || (size_t)ret >= sizeof(sun.sun_path)) {
if (str_cat(NULL, len + 1, path, COUNT(path)) > len) { errno = EINVAL;
errno = EINVAL; return -1;
return -1;
}
} }
*dst = sun; if (dst)
*dst = sun;
return 0; return 0;
} }
@@ -61,39 +53,30 @@ ctl_setsun(struct sockaddr_un *dst, const char *dir, const char *file)
static int static int
ctl_bind(int fd, const char *dir, const char *file) ctl_bind(int fd, const char *dir, const char *file)
{ {
char tmp[32]; char name[10] = { [0] = '.' };
struct sockaddr_un sun; struct sockaddr_un sun;
if (str_empty(file)) { if (str_empty(file)) {
for (int i = 0; i < CTL_BIND_MAX; i++) { unsigned pid = (unsigned)getpid();
if (snprintf(tmp, sizeof(tmp), ".%i", i) >= sizeof(tmp))
return -1;
if (ctl_setsun(&sun, dir, tmp)) for (size_t i = 1; i < sizeof(name) - 1; i++, pid >>= 4)
return -1; name[i] = "uncopyrightables"[pid & 15];
if (!bind(fd, (struct sockaddr *)&sun, sizeof(sun))) file = name;
return 0;
}
} else {
if (ctl_setsun(&sun, dir, file))
return -1;
unlink(sun.sun_path);
if (!bind(fd, (struct sockaddr *)&sun, sizeof(sun)))
return 0;
} }
return -1; if (ctl_setsun(&sun, dir, file))
return -1;
if (unlink(sun.sun_path) && errno != ENOENT)
return -1;
return bind(fd, (struct sockaddr *)&sun, sizeof(sun));
} }
void void
ctl_delete(int fd) ctl_delete(int fd)
{ {
if (fd == -1)
return;
struct sockaddr_storage ss = { 0 }; struct sockaddr_storage ss = { 0 };
socklen_t sslen = sizeof(ss); socklen_t sslen = sizeof(ss);
@@ -117,9 +100,6 @@ ctl_create(const char *dir, const char *file)
int fd = socket(AF_UNIX, SOCK_DGRAM, 0); int fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (fd == -1)
return -1;
if (ctl_bind(fd, dir, file)) { if (ctl_bind(fd, dir, file)) {
int err = errno; int err = errno;
close(fd); close(fd);
@@ -141,9 +121,7 @@ ctl_connect(const char *dir, const char *file)
} }
if (!file) { if (!file) {
dp = opendir(dir); if (dp = opendir(dir), !dp)
if (!dp)
return -1; return -1;
struct dirent *d = NULL; struct dirent *d = NULL;
@@ -154,7 +132,7 @@ ctl_connect(const char *dir, const char *file)
if (file) { if (file) {
closedir(dp); closedir(dp);
return -3; return CTL_ERROR_MANY;
} }
file = &d->d_name[0]; file = &d->d_name[0];
@@ -162,7 +140,7 @@ ctl_connect(const char *dir, const char *file)
if (!file) { if (!file) {
closedir(dp); closedir(dp);
return -2; return CTL_ERROR_NONE;
} }
} }
@@ -180,9 +158,6 @@ ctl_connect(const char *dir, const char *file)
int fd = ctl_create(dir, NULL); int fd = ctl_create(dir, NULL);
if (fd == -1)
return -1;
if (connect(fd, (struct sockaddr *)&sun, sizeof(sun))) { if (connect(fd, (struct sockaddr *)&sun, sizeof(sun))) {
int err = errno; int err = errno;
ctl_delete(fd); ctl_delete(fd);

View File

@@ -4,6 +4,9 @@
#include <sys/socket.h> #include <sys/socket.h>
#define CTL_ERROR_NONE (-2)
#define CTL_ERROR_MANY (-3)
enum ctl_type { enum ctl_type {
CTL_NONE = 0, CTL_NONE = 0,
CTL_STATE, CTL_STATE,
@@ -13,7 +16,6 @@ enum ctl_type {
CTL_KXTIMEOUT, CTL_KXTIMEOUT,
CTL_TIMETOLERANCE, CTL_TIMETOLERANCE,
CTL_PATH_STATUS, CTL_PATH_STATUS,
CTL_SYNC,
}; };
struct ctl_msg { struct ctl_msg {
@@ -28,6 +30,7 @@ struct ctl_msg {
} path; } path;
struct mud_path path_status; struct mud_path path_status;
struct { struct {
char tun_name[64];
long pid; long pid;
size_t mtu; size_t mtu;
int chacha; int chacha;

View File

@@ -1,24 +1,27 @@
#include "common.h" #include "common.h"
#include "iface.h" #include "iface.h"
#include "str.h"
#include <stdio.h>
#include <net/if.h> #include <net/if.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
int int
iface_set_mtu(const char *dev_name, int mtu) iface_set_mtu(const char *dev_name, size_t mtu)
{ {
if (mtu > (size_t)0xFFFF) {
errno = EINVAL;
return -1;
}
struct ifreq ifr = { struct ifreq ifr = {
.ifr_mtu = mtu, .ifr_mtu = (int)mtu,
}; };
const size_t len = sizeof(ifr.ifr_name) - 1; int ret = snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", dev_name);
if (str_cpy(ifr.ifr_name, len, dev_name) == len) { if (ret <= 0 || (size_t)ret >= sizeof(ifr.ifr_name)) {
if (str_len(dev_name, len + 1) > len) { errno = EINVAL;
errno = EINTR; return -1;
return -1;
}
} }
int fd = socket(AF_INET, SOCK_DGRAM, 0); int fd = socket(AF_INET, SOCK_DGRAM, 0);
@@ -26,7 +29,7 @@ iface_set_mtu(const char *dev_name, int mtu)
if (fd == -1) if (fd == -1)
return -1; return -1;
int ret = ioctl(fd, SIOCSIFMTU, &ifr); ret = ioctl(fd, SIOCSIFMTU, &ifr);
int err = errno; int err = errno;
close(fd); close(fd);

View File

@@ -1,3 +1,3 @@
#pragma once #pragma once
int iface_set_mtu (const char *, int); int iface_set_mtu (const char *, size_t);

View File

@@ -21,9 +21,7 @@ struct ip_common {
static inline int static inline int
ip_read16(const uint8_t *src) ip_read16(const uint8_t *src)
{ {
uint16_t ret = src[1]; return ((int)src[1]) | (((int)src[0]) << 8);
ret |= ((uint16_t)src[0]) << 8;
return (int)ret;
} }
static inline uint8_t static inline uint8_t
@@ -75,7 +73,7 @@ ip_get_common(struct ip_common *ic, const uint8_t *data, int size)
} }
break; break;
case 6: case 6:
ic->tc = ((data[0] & 0xF) << 4) | (data[1] >> 4); ic->tc = (uint8_t)((data[0] << 4) | (data[1] >> 4));
ic->proto = data[6]; ic->proto = data[6];
if (size == ip_read16(&data[4]) + 40) { if (size == ip_read16(&data[4]) + 40) {
memcpy(ic->src.v6, &data[8], sizeof(ic->src.v6)); memcpy(ic->src.v6, &data[8], sizeof(ic->src.v6));

View File

@@ -1,8 +1,11 @@
#include "common.h" #include "common.h"
#include "str.h" #include "str.h"
#include <sodium.h>
#include <stdio.h> #include <stdio.h>
#include "../argz/argz.h"
volatile sig_atomic_t gt_alarm; volatile sig_atomic_t gt_alarm;
volatile sig_atomic_t gt_reload; volatile sig_atomic_t gt_reload;
volatile sig_atomic_t gt_quit; volatile sig_atomic_t gt_quit;
@@ -46,7 +49,19 @@ gt_set_signal(void)
static int static int
gt_version(int argc, char **argv) gt_version(int argc, char **argv)
{ {
printf(PACKAGE_VERSION "\n"); struct argz version_argz[] = {
{"libsodium", NULL, NULL, argz_option},
{NULL}};
if (argz(version_argz, argc, argv))
return 1;
if (argz_is_set(version_argz, "libsodium")) {
printf("%s\n", sodium_version_string());
} else {
printf("%s\n", PACKAGE_VERSION);
}
return 0; return 0;
} }
@@ -60,11 +75,10 @@ main(int argc, char **argv)
char *help; char *help;
int (*call)(int, char **); int (*call)(int, char **);
} cmd[] = { } cmd[] = {
{"show", "show all running tunnels", gt_show}, {"show", "show tunnel info", gt_show},
{"bench", "start a crypto bench", gt_bench}, {"bench", "start a crypto bench", gt_bench},
{"bind", "start a new tunnel", gt_bind}, {"bind", "start a new tunnel", gt_bind},
{"set", "change tunnel properties", gt_set}, {"set", "change tunnel properties", gt_set},
{"sync", "re-sync tunnels", gt_sync},
{"keygen", "generate a new secret key", gt_keygen}, {"keygen", "generate a new secret key", gt_keygen},
{"path", "manage paths", gt_path}, {"path", "manage paths", gt_path},
{"version", "show version", gt_version}, {"version", "show version", gt_version},

View File

@@ -8,8 +8,94 @@
#include "../argz/argz.h" #include "../argz/argz.h"
static void
gt_path_print_status(struct mud_path *path, int term)
{
char bindstr[INET6_ADDRSTRLEN];
char publstr[INET6_ADDRSTRLEN];
char peerstr[INET6_ADDRSTRLEN];
gt_toaddr(bindstr, sizeof(bindstr),
(struct sockaddr *)&path->local_addr);
gt_toaddr(publstr, sizeof(publstr),
(struct sockaddr *)&path->r_addr);
gt_toaddr(peerstr, sizeof(peerstr),
(struct sockaddr *)&path->addr);
const char *statestr = NULL;
switch (path->state) {
case MUD_UP: statestr = "UP"; break;
case MUD_BACKUP: statestr = "BACKUP"; break;
case MUD_DOWN: statestr = "DOWN"; break;
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"
: "path %s %s"
" %s %"PRIu16
" %s %"PRIu16
" %s %"PRIu16
" %zu"
" %.3f %.3f"
" %"PRIu64
" %"PRIu64
" %"PRIu64
" %"PRIu64
"\n",
statestr,
statusstr,
bindstr[0] ? bindstr : "-",
gt_get_port((struct sockaddr *)&path->local_addr),
publstr[0] ? publstr : "-",
gt_get_port((struct sockaddr *)&path->r_addr),
peerstr[0] ? peerstr : "-",
gt_get_port((struct sockaddr *)&path->addr),
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);
}
static int static int
gt_path_status(int fd) gt_path_cmp_addr(struct sockaddr_storage *a, struct sockaddr_storage *b)
{
if (a->ss_family != b->ss_family)
return 1;
if (a->ss_family == AF_INET) {
struct sockaddr_in *A = (struct sockaddr_in *)a;
struct sockaddr_in *B = (struct sockaddr_in *)b;
return ((memcmp(&A->sin_addr, &B->sin_addr, sizeof(A->sin_addr))));
}
if (a->ss_family == AF_INET6) {
struct sockaddr_in6 *A = (struct sockaddr_in6 *)a;
struct sockaddr_in6 *B = (struct sockaddr_in6 *)b;
return ((memcmp(&A->sin6_addr, &B->sin6_addr, sizeof(A->sin6_addr))));
}
return 1;
}
static int
gt_path_status(int fd, int state, struct sockaddr_storage *addr)
{ {
struct ctl_msg req = { struct ctl_msg req = {
.type = CTL_PATH_STATUS, .type = CTL_PATH_STATUS,
@@ -18,79 +104,34 @@ gt_path_status(int fd)
if (send(fd, &req, sizeof(struct ctl_msg), 0) == -1) if (send(fd, &req, sizeof(struct ctl_msg), 0) == -1)
return -1; return -1;
int term = isatty(1); struct mud_path path[MUD_PATH_MAX];
int count = 0;
do { while (1) {
if (recv(fd, &res, sizeof(struct ctl_msg), 0) == -1) if (recv(fd, &res, sizeof(struct ctl_msg), 0) == -1)
return -1; return -1;
if (res.type != req.type) if (res.type != req.type) {
return -2; errno = EBADMSG;
return -1;
if (!res.ret)
return 0;
char bindstr[INET6_ADDRSTRLEN];
char publstr[INET6_ADDRSTRLEN];
char peerstr[INET6_ADDRSTRLEN];
gt_toaddr(bindstr, sizeof(bindstr),
(struct sockaddr *)&res.path_status.local_addr);
gt_toaddr(publstr, sizeof(publstr),
(struct sockaddr *)&res.path_status.r_addr);
gt_toaddr(peerstr, sizeof(peerstr),
(struct sockaddr *)&res.path_status.addr);
const char *statestr = NULL;
switch (res.path_status.state) {
case MUD_UP: statestr = "UP"; break;
case MUD_BACKUP: statestr = "BACKUP"; break;
case MUD_DOWN: statestr = "DOWN"; break;
default: return -2;
} }
const char *statusstr = res.path_status.ok ? "OK" : "DEGRADED"; if (res.ret == EAGAIN) {
memcpy(&path[count], &res.path_status, sizeof(struct mud_path));
count++;
} else if (res.ret) {
errno = res.ret;
return -1;
} else break;
}
printf(term ? "path %s\n" int term = isatty(1);
" status: %s\n"
" bind: %s port %"PRIu16"\n" for (int i = 0; i < count; i++) {
" public: %s port %"PRIu16"\n" if ((state == MUD_EMPTY || path[i].state == state) &&
" peer: %s port %"PRIu16"\n" (!addr->ss_family || !gt_path_cmp_addr(addr, &path[i].local_addr)))
" mtu: %zu bytes\n" gt_path_print_status(&path[i], term);
" 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"
: "path %s %s"
" %s %"PRIu16
" %s %"PRIu16
" %s %"PRIu16
" %zu"
" %.3f %.3f"
" %"PRIu64
" %"PRIu64
" %"PRIu64
" %"PRIu64
"\n",
statestr,
statusstr,
bindstr[0] ? bindstr : "-",
gt_get_port((struct sockaddr *)&res.path_status.local_addr),
publstr[0] ? publstr : "-",
gt_get_port((struct sockaddr *)&res.path_status.r_addr),
peerstr[0] ? peerstr : "-",
gt_get_port((struct sockaddr *)&res.path_status.addr),
res.path_status.mtu.ok,
res.path_status.rtt.val / 1e3,
res.path_status.rtt.var / 1e3,
res.path_status.rate_tx,
res.path_status.rate_rx,
res.path_status.send.total,
res.path_status.recv.total);
} while (res.ret == EAGAIN);
return 0; return 0;
} }
@@ -102,6 +143,9 @@ gt_path(int argc, char **argv)
struct ctl_msg req = { struct ctl_msg req = {
.type = CTL_STATE, .type = CTL_STATE,
.path = {
.state = MUD_EMPTY,
},
}, res = {0}; }, res = {0};
struct argz ratez[] = { struct argz ratez[] = {
@@ -126,10 +170,10 @@ gt_path(int argc, char **argv)
case -1: case -1:
perror("path"); perror("path");
break; break;
case -2: case CTL_ERROR_NONE:
gt_log("no device\n"); gt_log("no device\n");
break; break;
case -3: case CTL_ERROR_MANY:
gt_log("please choose a device\n"); gt_log("please choose a device\n");
break; break;
default: default:
@@ -138,24 +182,27 @@ gt_path(int argc, char **argv)
return 1; return 1;
} }
int ret = 0; int set_rate = argz_is_set(pathz, "rate");
if (!req.path.addr.ss_family) { if (set_rate && !req.path.addr.ss_family) {
ret = gt_path_status(fd); gt_log("please specify a path\n");
return 1;
}
if (ret == -2) if (argz_is_set(pathz, "up")) {
gt_log("bad reply from server\n"); req.path.state = MUD_UP;
} else if (argz_is_set(pathz, "backup")) {
req.path.state = MUD_BACKUP;
} else if (argz_is_set(pathz, "down")) {
req.path.state = MUD_DOWN;
}
int ret;
if (!req.path.addr.ss_family ||
(req.path.state == MUD_EMPTY && !set_rate)) {
ret = gt_path_status(fd, req.path.state, &req.path.addr);
} else { } else {
req.path.state = MUD_EMPTY;
if (argz_is_set(pathz, "up")) {
req.path.state = MUD_UP;
} else if (argz_is_set(pathz, "backup")) {
req.path.state = MUD_BACKUP;
} else if (argz_is_set(pathz, "down")) {
req.path.state = MUD_DOWN;
}
ret = ctl_reply(fd, &res, &req); ret = ctl_reply(fd, &res, &req);
} }

View File

@@ -134,10 +134,10 @@ gt_set(int argc, char **argv)
case -1: case -1:
perror("set"); perror("set");
break; break;
case -2: case CTL_ERROR_NONE:
gt_log("no device\n"); gt_log("no device\n");
break; break;
case -3: case CTL_ERROR_MANY:
gt_log("please choose a device\n"); gt_log("please choose a device\n");
break; break;
default: default:

View File

@@ -12,7 +12,7 @@
#include <unistd.h> #include <unistd.h>
static int static int
gt_show_dev_status(int fd, const char *dev) gt_show_status(int fd)
{ {
struct ctl_msg res, req = {.type = CTL_STATUS}; struct ctl_msg res, req = {.type = CTL_STATUS};
@@ -32,17 +32,17 @@ gt_show_dev_status(int fd, const char *dev)
if (server) { if (server) {
printf(term ? "server %s:\n" printf(term ? "server %s:\n"
" pid: %li\n" " pid: %li\n"
" bind: %s port %"PRIu16"\n" " bind: %s port %"PRIu16"\n"
" mtu: %zu\n" " mtu: %zu\n"
" cipher: %s\n" " cipher: %s\n"
: "server %s" : "server %s"
" %li" " %li"
" %s %"PRIu16 " %s %"PRIu16
" %zu" " %zu"
" %s" " %s"
"\n", "\n",
dev, res.status.tun_name,
res.status.pid, res.status.pid,
bindstr[0] ? bindstr : "-", bindstr[0] ? bindstr : "-",
gt_get_port((struct sockaddr *)&res.status.bind), gt_get_port((struct sockaddr *)&res.status.bind),
@@ -50,11 +50,11 @@ gt_show_dev_status(int fd, const char *dev)
res.status.chacha ? "chacha20poly1305" : "aes256gcm"); res.status.chacha ? "chacha20poly1305" : "aes256gcm");
} else { } else {
printf(term ? "client %s:\n" printf(term ? "client %s:\n"
" pid: %li\n" " pid: %li\n"
" bind: %s port %"PRIu16"\n" " bind: %s port %"PRIu16"\n"
" peer: %s port %"PRIu16"\n" " peer: %s port %"PRIu16"\n"
" mtu: %zu\n" " mtu: %zu\n"
" cipher: %s\n" " cipher: %s\n"
: "client %s" : "client %s"
" %li" " %li"
" %s %"PRIu16 " %s %"PRIu16
@@ -62,7 +62,7 @@ gt_show_dev_status(int fd, const char *dev)
" %zu" " %zu"
" %s" " %s"
"\n", "\n",
dev, res.status.tun_name,
res.status.pid, res.status.pid,
bindstr[0] ? bindstr : "-", bindstr[0] ? bindstr : "-",
gt_get_port((struct sockaddr *)&res.status.bind), gt_get_port((struct sockaddr *)&res.status.bind),
@@ -75,30 +75,6 @@ gt_show_dev_status(int fd, const char *dev)
return 0; return 0;
} }
static int
gt_show_dev(const char *dev)
{
int fd = ctl_connect(GT_RUNDIR, dev);
if (fd < 0) {
if (fd == -1)
perror("show");
return -1;
}
int ret = gt_show_dev_status(fd, dev);
if (ret == -1)
perror(dev);
if (ret == -2)
gt_log("%s: bad reply from server\n", dev);
ctl_delete(fd);
return ret;
}
int int
gt_show(int argc, char **argv) gt_show(int argc, char **argv)
{ {
@@ -111,27 +87,31 @@ gt_show(int argc, char **argv)
if (argz(showz, argc, argv)) if (argz(showz, argc, argv))
return 1; return 1;
if (dev) int fd = ctl_connect(GT_RUNDIR, dev);
return !!gt_show_dev(dev);
DIR *dp = opendir(GT_RUNDIR); if (fd < 0) {
switch (fd) {
if (!dp) { case -1:
if (errno == ENOENT) perror("show");
return 0; break;
perror("show"); case CTL_ERROR_NONE:
gt_log("no device\n");
break;
case CTL_ERROR_MANY:
gt_log("please choose a device\n");
break;
default:
gt_log("couldn't connect\n");
}
return 1; return 1;
} }
int ret = 0; int ret = gt_show_status(fd);
struct dirent *d = NULL;
while (d = readdir(dp), d) { if (ret == -1)
if (d->d_name[0] != '.') perror("show");
ret |= !!gt_show_dev(d->d_name);
}
closedir(dp); ctl_delete(fd);
return ret; return !!ret;
} }

View File

@@ -31,32 +31,3 @@ str_len(const char *restrict str, size_t len)
return strnlen(str, len); return strnlen(str, len);
} }
static inline size_t
str_cat(char *dst, size_t dst_len, const char **src, size_t count)
{
if (count && !src)
return 0;
size_t len = 0;
for (size_t i = 0; i < count && dst_len > len; i++) {
size_t n = str_len(src[i], dst_len - len);
if (dst && n)
memmove(&dst[len], src[i], n);
len += n;
}
if (dst)
dst[len] = 0;
return len;
}
static inline size_t
str_cpy(char *dst, size_t dst_len, const char *src)
{
return str_cat(dst, dst_len, &src, 1);
}

View File

@@ -1,76 +0,0 @@
#include "common.h"
#include "ctl.h"
#include "str.h"
#include "../argz/argz.h"
#include <stdio.h>
#include <dirent.h>
static int
gt_sync_dev(const char *dev, unsigned long timeout)
{
const int fd = ctl_connect(GT_RUNDIR, dev);
if (fd < 0) {
if (fd == -1)
perror("sync");
return 1;
}
struct ctl_msg res, req = {
.type = CTL_SYNC,
};
int ret = ctl_reply(fd, &res, &req);
if (!ret) {
if (res.ms > timeout)
ret = 1;
} else {
perror("sync");
}
ctl_delete(fd);
return ret;
}
int
gt_sync(int argc, char **argv)
{
const char *dev = NULL;
unsigned long timeout = 20000;
struct argz syncz[] = {
{"dev", "NAME", &dev, argz_str},
{"timeout", "SECONDS", &timeout, argz_time},
{NULL}};
if (argz(syncz, argc, argv))
return 1;
if (dev)
return !!gt_sync_dev(dev, timeout);
DIR *dp = opendir(GT_RUNDIR);
if (!dp) {
if (errno == ENOENT)
return 0;
perror("sync");
return 1;
}
int ret = 0;
struct dirent *d = NULL;
while (d = readdir(dp), d) {
if (d->d_name[0] != '.')
ret |= !!gt_sync_dev(d->d_name, timeout);
}
closedir(dp);
return ret;
}

View File

@@ -32,9 +32,9 @@
static int static int
tun_create_by_id(char *name, size_t len, unsigned id) tun_create_by_id(char *name, size_t len, unsigned id)
{ {
int ret = snprintf(name, len + 1, "utun%u", id); int ret = snprintf(name, len, "utun%u", id);
if (ret <= 0 || ret > len) { if (ret <= 0 || (size_t)ret >= len) {
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
@@ -44,8 +44,9 @@ tun_create_by_id(char *name, size_t len, unsigned id)
if (fd == -1) if (fd == -1)
return -1; return -1;
struct ctl_info ci = {0}; struct ctl_info ci = {
str_cpy(ci.ctl_name, sizeof(ci.ctl_name) - 1, UTUN_CONTROL_NAME); .ctl_name = UTUN_CONTROL_NAME,
};
if (ioctl(fd, CTLIOCGINFO, &ci)) { if (ioctl(fd, CTLIOCGINFO, &ci)) {
int err = errno; int err = errno;
@@ -92,14 +93,20 @@ tun_create_by_name(char *name, size_t len, const char *dev_name)
static int static int
tun_create_by_name(char *name, size_t len, const char *dev_name) tun_create_by_name(char *name, size_t len, const char *dev_name)
{ {
int ret = snprintf(name, len, "%s", dev_name);
if (ret <= 0 || (size_t)ret >= len) {
errno = EINVAL;
return -1;
}
struct ifreq ifr = { struct ifreq ifr = {
.ifr_flags = IFF_TUN | IFF_NO_PI, .ifr_flags = IFF_TUN | IFF_NO_PI,
}; };
const size_t ifr_len = sizeof(ifr.ifr_name) - 1; ret = snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", dev_name);
if ((len < ifr_len) || if (ret <= 0 || (size_t)ret >= sizeof(ifr.ifr_name)) {
(str_len(dev_name, ifr_len + 1) > ifr_len)) {
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
@@ -109,8 +116,6 @@ tun_create_by_name(char *name, size_t len, const char *dev_name)
if (fd == -1) if (fd == -1)
return -1; return -1;
str_cpy(ifr.ifr_name, ifr_len, dev_name);
if (ioctl(fd, TUNSETIFF, &ifr)) { if (ioctl(fd, TUNSETIFF, &ifr)) {
int err = errno; int err = errno;
close(fd); close(fd);
@@ -118,8 +123,6 @@ tun_create_by_name(char *name, size_t len, const char *dev_name)
return -1; return -1;
} }
str_cpy(name, len, ifr.ifr_name);
return fd; return fd;
} }
@@ -128,22 +131,13 @@ tun_create_by_name(char *name, size_t len, const char *dev_name)
static int static int
tun_create_by_name(char *name, size_t len, const char *dev_name) tun_create_by_name(char *name, size_t len, const char *dev_name)
{ {
char tmp[128]; int ret = snprintf(name, len, "/dev/%s", dev_name);
int ret = snprintf(tmp, sizeof(tmp), "/dev/%s", dev_name); if (ret <= 0 || (size_t)ret >= len) {
if (ret <= 0 || ret >= sizeof(tmp)) {
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
if (str_cpy(name, len, dev_name) == len) {
if (str_len(dev_name, len + 1) > len) {
errno = EINVAL;
return -1;
}
}
return open(tmp, O_RDWR); return open(tmp, O_RDWR);
} }
@@ -153,10 +147,9 @@ static int
tun_create_by_id(char *name, size_t len, unsigned id) tun_create_by_id(char *name, size_t len, unsigned id)
{ {
char tmp[64]; char tmp[64];
int ret = snprintf(tmp, sizeof(tmp), "tun%u", id); int ret = snprintf(tmp, sizeof(tmp), "tun%u", id);
if (ret <= 0 || ret >= sizeof(tmp)) { if (ret <= 0 || (size_t)ret >= sizeof(tmp)) {
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
@@ -201,17 +194,17 @@ tun_read(int fd, void *data, size_t size)
}, },
}; };
ssize_t ret = readv(fd, iov, 2); int ret = (int)readv(fd, iov, 2);
if (ret <= (ssize_t)0) if (ret <= 0)
return ret; return ret;
if (ret <= (ssize_t)sizeof(family)) if ((size_t)ret <= sizeof(family))
return 0; return 0;
return ret - sizeof(family); return ret - (int)sizeof(family);
#else #else
return read(fd, data, size); return (int)read(fd, data, size);
#endif #endif
} }
@@ -247,17 +240,17 @@ tun_write(int fd, const void *data, size_t size)
}, },
}; };
ssize_t ret = writev(fd, iov, 2); int ret = (int)writev(fd, iov, 2);
if (ret <= (ssize_t)0) if (ret <= 0)
return ret; return ret;
if (ret <= (ssize_t)sizeof(family)) if ((size_t)ret <= sizeof(family))
return 0; return 0;
return ret - sizeof(family); return ret - (int)sizeof(family);
#else #else
return write(fd, data, size); return (int)write(fd, data, size);
#endif #endif
} }