Compare commits

...

75 Commits

Author SHA1 Message Date
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
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
20 changed files with 578 additions and 586 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: ${{ matrix.os }}
path: ./bin

3
.gitignore vendored
View File

@@ -1,4 +1,4 @@
*.o
*.[ios]
*.log
*.scan
*.cache
@@ -10,6 +10,7 @@ configure
build-aux
.deps
.dirstamp
.static
glorytun
build*
VERSION

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,31 +2,39 @@ 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)\"
SRC := argz/argz.c mud/mud.c $(wildcard src/*.c)
FLAGS += -I.static/$(CROSS)/libsodium-stable/src/libsodium/include
FLAGS += -L.static/$(CROSS)/libsodium-stable/src/libsodium/.libs
.PHONY: $(NAME)
$(NAME):
@echo "Building $(NAME)"
@$(CC) $(FLAGS) -o $(NAME) $(SRC) -lsodium -lm
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)
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

@@ -9,6 +9,8 @@ glorytun_SOURCES = \
argz/argz.h \
mud/mud.c \
mud/mud.h \
mud/aegis256/aegis256.c \
mud/aegis256/aegis256.h \
src/bench.c \
src/bind.c \
src/common.c \
@@ -29,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 AES only if AES-NI is available otherwise ChaCha20 is used.
If you are not cpu bounded, you can force the use of ChaCha20 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 all running tunnels
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: 31f3c44d9b...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

@@ -23,6 +23,7 @@ executable('glorytun', install: true,
sources: [
'argz/argz.c',
'mud/mud.c',
'mud/aegis256/aegis256.c',
'src/bench.c',
'src/bind.c',
'src/common.c',
@@ -37,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: 06e165e664...2f966bb365

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

@@ -1,148 +1,105 @@
#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" : "")
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
}
#define NPUBBYTES 32
#define KEYBYTES 32
#define ABYTES 16
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");
if (!chacha && !crypto_aead_aes256gcm_is_available()) {
if (!aegis256_is_available()) {
if (aes) {
gt_log("aes is not available on your platform\n");
return 1;
}
unsigned char *buf = calloc(1, bufsize + crypto_aead_aes256gcm_ABYTES);
if (!buf) {
perror("calloc");
return 1;
chacha = 1;
}
unsigned char npub[crypto_aead_aes256gcm_NPUBBYTES];
unsigned char key[crypto_aead_aes256gcm_KEYBYTES];
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" : "aes256gcm");
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)) {
crypto_aead_aes256gcm_state ctx;
for (int i = 0; !gt_quit && size <= 1450; i++) {
struct {
int64_t min, mean, max, n;
} mbps = { .n = 0 };
if (!chacha)
crypto_aead_aes256gcm_beforenm(&ctx, key);
int64_t bytes_max = (int64_t)1 << 24;
unsigned long long now = gt_now();
double mbps_old = mbps;
size_t bytes = 0;
while (!gt_quit && mbps.n < 10) {
int64_t bytes = 0;
int64_t base = (int64_t)clock();
gt_alarm = 0;
alarm((unsigned int)duration);
while (!gt_quit && !gt_alarm) {
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 {
crypto_aead_aes256gcm_encrypt_afternm(
buf, NULL, buf, 1ULL << i, NULL, 0, NULL, npub,
(const crypto_aead_aes256gcm_state *)&ctx);
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);
}
}
@@ -150,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,16 +185,21 @@ 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;
}
if (fd_set_nonblock(tun_fd) ||
fd_set_nonblock(mud_fd) ||
if (//fd_set_nonblock(tun_fd) ||
//fd_set_nonblock(mud_fd) ||
fd_set_nonblock(ctl_fd)) {
gt_log("couldn't setup non-blocking fds\n");
return 1;
@@ -204,31 +209,43 @@ gt_bind(int argc, char **argv)
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(&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;
unsigned char buf[4096];
int last_fd = MAX(tun_fd, mud_fd);
last_fd = 1 + MAX(last_fd, ctl_fd);
__attribute__((aligned(16)))
unsigned char buf[1500];
while (!gt_quit) {
long send_wait = mud_send_wait(mud);
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 (send_wait) {
FD_CLR(tun_fd, &rfds);
} else {
FD_SET(tun_fd, &rfds);
}
FD_SET(mud_fd, &rfds);
FD_SET(ctl_fd, &rfds);
struct timeval tv = {
.tv_sec = 0,
.tv_usec = send_wait,
};
struct timeval tv = { 0 };
int update = mud_update(mud);
const int ret = select(last_fd, &rfds, NULL, NULL, send_wait > 0 ? &tv : NULL);
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, update < 0 ? NULL : &tv);
if (ret == -1) {
if (errno == EBADF) {
@@ -238,8 +255,36 @@ 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;
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);
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)) {
struct ctl_msg req, res = {.reply = 1};
struct sockaddr_storage ss;
@@ -256,9 +301,25 @@ 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))
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;
@@ -282,29 +343,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:
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)
@@ -313,36 +355,6 @@ gt_bind(int argc, char **argv)
perror("recvfrom(ctl)");
}
}
if (FD_ISSET(mud_fd, &rfds)) {
int n = 1000;
while (n--) {
const int r = mud_recv(mud, buf, sizeof(buf));
if (r <= 0)
break;
if (ip_is_valid(buf, r))
tun_write(tun_fd, buf, (size_t)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 (r > 0 && !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, (size_t)r, (h << 8) | ic.tc);
}
}
}
if (gt_reload && tun_fd >= 0)

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,25 +5,54 @@
#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)
{
if (fd == -1) {
errno = EINVAL;
return -1;
}
if ((send(fd, req, sizeof(struct ctl_msg), 0) == -1) ||
(recv(fd, res, sizeof(struct ctl_msg), 0) == -1))
return -1;
if (res->type != req->type || !res->reply) {
errno = EINVAL;
errno = EBADMSG;
return -1;
}
@@ -58,23 +87,23 @@ ctl_setsun(struct sockaddr_un *dst, const char *dir, const char *file)
static int
ctl_bind(int fd, const char *dir, const char *file)
{
char name[10] = { [0] = '.' };
struct sockaddr_un sun;
if (str_empty(file)) {
char name[10] = { [0] = '.' };
unsigned pid = (unsigned)getpid();
for (size_t i = 1; i < sizeof(name) - 1; i++, pid >>= 4)
name[i] = "uncopyrightables"[pid & 15];
if (ctl_setsun(&sun, dir, name))
return -1;
} else {
file = name;
}
if (ctl_setsun(&sun, dir, file))
return -1;
unlink(sun.sun_path);
}
if (unlink(sun.sun_path) && errno != ENOENT)
return -1;
return bind(fd, (struct sockaddr *)&sun, sizeof(sun));
}
@@ -82,9 +111,6 @@ ctl_bind(int fd, const char *dir, const char *file)
void
ctl_delete(int fd)
{
if (fd == -1)
return;
struct sockaddr_storage ss = { 0 };
socklen_t sslen = sizeof(ss);
@@ -96,21 +122,18 @@ 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;
int fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (fd == -1)
return -1;
if (ctl_bind(fd, dir, file)) {
int err = errno;
close(fd);
@@ -122,19 +145,16 @@ 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) {
dp = opendir(dir);
if (!dp)
if (dp = opendir(dir), !dp)
return -1;
struct dirent *d = NULL;
@@ -145,7 +165,7 @@ ctl_connect(const char *dir, const char *file)
if (file) {
closedir(dp);
return -3;
return CTL_ERROR_MANY;
}
file = &d->d_name[0];
@@ -153,7 +173,7 @@ ctl_connect(const char *dir, const char *file)
if (!file) {
closedir(dp);
return -2;
return CTL_ERROR_NONE;
}
}
@@ -169,12 +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 (fd == -1)
return -1;
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

@@ -4,15 +4,16 @@
#include <sys/socket.h>
#define CTL_ERROR_NONE (-2)
#define CTL_ERROR_MANY (-3)
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 {
@@ -24,22 +25,25 @@ struct ctl_msg {
enum mud_state state;
unsigned long rate_tx;
unsigned long rate_rx;
unsigned long beat;
unsigned char fixed_rate;
} path;
struct mud_path path_status;
struct {
char tun_name[64];
long pid;
size_t mtu;
int chacha;
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 *);
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

@@ -1,8 +1,11 @@
#include "common.h"
#include "str.h"
#include <sodium.h>
#include <stdio.h>
#include "../argz/argz.h"
volatile sig_atomic_t gt_alarm;
volatile sig_atomic_t gt_reload;
volatile sig_atomic_t gt_quit;
@@ -46,7 +49,19 @@ gt_set_signal(void)
static int
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;
}
@@ -60,7 +75,7 @@ main(int argc, char **argv)
char *help;
int (*call)(int, char **);
} cmd[] = {
{"show", "show all running tunnels", gt_show},
{"show", "show tunnel info", gt_show},
{"bench", "start a crypto bench", gt_bench},
{"bind", "start a new tunnel", gt_bind},
{"set", "change tunnel properties", gt_set},

View File

@@ -8,50 +8,29 @@
#include "../argz/argz.h"
static int
gt_path_status(int fd)
static void
gt_path_print_status(struct mud_path *path, int term)
{
struct ctl_msg req = {
.type = CTL_PATH_STATUS,
}, res = {0};
if (send(fd, &req, sizeof(struct ctl_msg), 0) == -1)
return -1;
int term = isatty(1);
do {
if (recv(fd, &res, sizeof(struct ctl_msg), 0) == -1)
return -1;
if (res.type != req.type)
return -2;
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);
(struct sockaddr *)&path->local_addr);
gt_toaddr(publstr, sizeof(publstr),
(struct sockaddr *)&res.path_status.r_addr);
(struct sockaddr *)&path->r_addr);
gt_toaddr(peerstr, sizeof(peerstr),
(struct sockaddr *)&res.path_status.addr);
(struct sockaddr *)&path->addr);
const char *statestr = NULL;
switch (res.path_status.state) {
switch (path->state) {
case MUD_UP: statestr = "UP"; break;
case MUD_BACKUP: statestr = "BACKUP"; break;
case MUD_DOWN: statestr = "DOWN"; break;
default: return -2;
default: return;
}
const char *statusstr = res.path_status.ok ? "OK" : "DEGRADED";
printf(term ? "path %s\n"
" status: %s\n"
" bind: %s port %"PRIu16"\n"
@@ -60,37 +39,104 @@ gt_path_status(int fd)
" 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"
" rate: %s\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"
" %"PRIu64
" %"PRIu64" %"PRIu64" %"PRIu64
" %"PRIu64" %"PRIu64" %"PRIu64
"\n",
statestr,
statusstr,
path->ok ? "OK" : "DEGRADED",
bindstr[0] ? bindstr : "-",
gt_get_port((struct sockaddr *)&res.path_status.local_addr),
gt_get_port((struct sockaddr *)&path->local_addr),
publstr[0] ? publstr : "-",
gt_get_port((struct sockaddr *)&res.path_status.r_addr),
gt_get_port((struct sockaddr *)&path->r_addr),
peerstr[0] ? peerstr : "-",
gt_get_port((struct sockaddr *)&res.path_status.addr),
res.path_status.mtu.ok,
(double)res.path_status.rtt.val / 1e3,
(double)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);
gt_get_port((struct sockaddr *)&path->addr),
path->mtu.ok,
(double)path->rtt.val / 1e3,
(double)path->rtt.var / 1e3,
path->conf.fixed_rate ? "fixed" : "auto",
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
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, enum mud_state state, struct sockaddr_storage *addr)
{
struct ctl_msg req = {
.type = CTL_PATH_STATUS,
}, res = {0};
if (send(fd, &req, sizeof(struct ctl_msg), 0) == -1)
return -1;
struct mud_path path[MUD_PATH_MAX];
int count = 0;
while (1) {
if (recv(fd, &res, sizeof(struct ctl_msg), 0) == -1)
return -1;
if (res.type != req.type) {
errno = EBADMSG;
return -1;
}
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;
}
int term = isatty(1);
for (int i = 0; i < count; i++) {
if ((state == MUD_EMPTY || path[i].state == state) &&
(!addr->ss_family || !gt_path_cmp_addr(addr, &path[i].local_addr)))
gt_path_print_status(&path[i], term);
}
return 0;
}
@@ -102,9 +148,13 @@ gt_path(int argc, char **argv)
struct ctl_msg req = {
.type = CTL_STATE,
.path = {
.state = MUD_EMPTY,
},
}, 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}};
@@ -114,22 +164,23 @@ 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},
{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) {
case -1:
perror("path");
break;
case -2:
case CTL_ERROR_NONE:
gt_log("no device\n");
break;
case -3:
case CTL_ERROR_MANY:
gt_log("please choose a device\n");
break;
default:
@@ -138,15 +189,13 @@ gt_path(int argc, char **argv)
return 1;
}
int ret = 0;
int set = argz_is_set(pathz, "rate")
|| argz_is_set(pathz, "beat");
if (!req.path.addr.ss_family) {
ret = gt_path_status(fd);
if (ret == -2)
gt_log("bad reply from server\n");
} else {
req.path.state = MUD_EMPTY;
if (set && !req.path.addr.ss_family) {
gt_log("please specify a path\n");
return 1;
}
if (argz_is_set(pathz, "up")) {
req.path.state = MUD_UP;
@@ -156,6 +205,18 @@ gt_path(int argc, char **argv)
req.path.state = MUD_DOWN;
}
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)) {
ret = gt_path_status(fd, req.path.state, &req.path.addr);
} else {
ret = ctl_reply(fd, &res, &req);
}

116
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,33 +37,34 @@ 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},
{"losslimit", "PERCENT", &req.conf.losslimit, argz_percent},
{"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) {
case -1:
perror("set");
break;
case -2:
case CTL_ERROR_NONE:
gt_log("no device\n");
break;
case -3:
case CTL_ERROR_MANY:
gt_log("please choose a device\n");
break;
default:
@@ -146,21 +73,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,8 +11,49 @@
#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_dev_status(int fd, const char *dev)
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)
{
struct ctl_msg res, req = {.type = CTL_STATUS};
@@ -42,12 +83,12 @@ gt_show_dev_status(int fd, const char *dev)
" %zu"
" %s"
"\n",
dev,
res.status.tun_name,
res.status.pid,
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"
@@ -62,43 +103,19 @@ gt_show_dev_status(int fd, const char *dev)
" %zu"
" %s"
"\n",
dev,
res.status.tun_name,
res.status.pid,
bindstr[0] ? bindstr : "-",
gt_get_port((struct sockaddr *)&res.status.bind),
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;
}
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
gt_show(int argc, char **argv)
{
@@ -106,32 +123,39 @@ 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;
if (dev)
return !!gt_show_dev(dev);
int fd = ctl_connect(dev);
DIR *dp = opendir(GT_RUNDIR);
if (!dp) {
if (errno == ENOENT)
return 0;
if (fd < 0) {
switch (fd) {
case -1:
perror("show");
break;
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;
}
int ret = 0;
struct dirent *d = NULL;
int ret = argz_is_set(showz, "bad")
? gt_show_bad(fd)
: gt_show_status(fd);
while (d = readdir(dp), d) {
if (d->d_name[0] != '.')
ret |= !!gt_show_dev(d->d_name);
}
closedir(dp);
return ret;
if (ret == -1)
perror("show");
ctl_delete(fd);
return !!ret;
}