Compare commits
527 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e7b52f9fd | ||
|
|
97784c43ac | ||
|
|
4b4c080cc4 | ||
|
|
43e1dfe86f | ||
|
|
ed1cf51af2 | ||
|
|
264f26286d | ||
|
|
7c17e16fea | ||
|
|
38d31c0637 | ||
|
|
bccc9945f4 | ||
|
|
9c9f679497 | ||
|
|
9177778d0f | ||
|
|
6853b59dc3 | ||
|
|
d451bc75b0 | ||
|
|
1f82b15373 | ||
|
|
56b5a41633 | ||
|
|
004380827f | ||
|
|
a7f57de42a | ||
|
|
2f3f9e7e86 | ||
|
|
0528adcfe2 | ||
|
|
67ea65b1a8 | ||
|
|
ed82531fc0 | ||
|
|
e077554304 | ||
|
|
b9f31b2445 | ||
|
|
76036a6535 | ||
|
|
cce55fac21 | ||
|
|
a72075036a | ||
|
|
84184c644a | ||
|
|
7f238c2599 | ||
|
|
170b3df0af | ||
|
|
4a68866201 | ||
|
|
5e89ebc550 | ||
|
|
7e95f7a8ae | ||
|
|
968cafe21b | ||
|
|
d4e5ea7c0a | ||
|
|
e6793f9b54 | ||
|
|
5976434285 | ||
|
|
db718d5942 | ||
|
|
3da880f5c5 | ||
|
|
86fe69d644 | ||
|
|
5c29753343 | ||
|
|
70bc9cc205 | ||
|
|
5c3ec8e264 | ||
|
|
6496adcd91 | ||
|
|
4ec2079e22 | ||
|
|
f4611efbb2 | ||
|
|
d703a66988 | ||
|
|
568eeee70b | ||
|
|
6e6c72746f | ||
|
|
cd2ee2a7af | ||
|
|
e338626c46 | ||
|
|
71aedce8b2 | ||
|
|
9c8e043053 | ||
|
|
871f488097 | ||
|
|
159104ce9c | ||
|
|
0dddca3b61 | ||
|
|
cbae4f5a30 | ||
|
|
61db08063c | ||
|
|
dec3151fd2 | ||
|
|
a36f1d5354 | ||
|
|
ae713a2197 | ||
|
|
6555cd98d5 | ||
|
|
bde9e6e59a | ||
|
|
9a8d95399d | ||
|
|
324ba6d525 | ||
|
|
b91788080f | ||
|
|
a65cb2ad15 | ||
|
|
9131af6e85 | ||
|
|
5fca6bcab1 | ||
|
|
067ddd4aa0 | ||
|
|
3d184721ab | ||
|
|
20d589fa70 | ||
|
|
adb825020a | ||
|
|
e14045ffa2 | ||
|
|
4d5ae60844 | ||
|
|
5b64c697ea | ||
|
|
b4f796469f | ||
|
|
0e052dc2db | ||
|
|
8ff9d3d7a1 | ||
|
|
6bcc46c757 | ||
|
|
3898afd524 | ||
|
|
f20fff0e87 | ||
|
|
9e1001fa17 | ||
|
|
9957581e60 | ||
|
|
61176d4f47 | ||
|
|
e8bda24ec0 | ||
|
|
5c9cbfc952 | ||
|
|
13c905d725 | ||
|
|
56a3a751db | ||
|
|
6719b19681 | ||
|
|
310513c569 | ||
|
|
a0bdb56441 | ||
|
|
c15343f8f6 | ||
|
|
41f66e55bc | ||
|
|
9c7f98a823 | ||
|
|
da350aff9c | ||
|
|
c7fed357fb | ||
|
|
524ae42069 | ||
|
|
2dbf5fb765 | ||
|
|
a3bb488fd5 | ||
|
|
022e478fb9 | ||
|
|
f3b44e2f45 | ||
|
|
23b7aeb68f | ||
|
|
1e2004c7dd | ||
|
|
e12d136ba3 | ||
|
|
ca96be5fe5 | ||
|
|
d0a9c69f7c | ||
|
|
3ffce5da1b | ||
|
|
aeb33342a4 | ||
|
|
ca71508e5c | ||
|
|
36be8008d8 | ||
|
|
be17650555 | ||
|
|
873efb4f82 | ||
|
|
357d5a0859 | ||
|
|
5c532b2e56 | ||
|
|
0cce48e9fd | ||
|
|
ee9ed7e3a6 | ||
|
|
841c2afed0 | ||
|
|
60a5b3e00a | ||
|
|
e243d8371a | ||
|
|
767aff211f | ||
|
|
eb04190c58 | ||
|
|
d25957b108 | ||
|
|
a5f634ee28 | ||
|
|
1736b6e043 | ||
|
|
8401b7c112 | ||
|
|
7276305906 | ||
|
|
6e75f4282d | ||
|
|
7999344c39 | ||
|
|
7a9f6fc8b8 | ||
|
|
dabd16e4b4 | ||
|
|
1698a08b08 | ||
|
|
4646cbb15e | ||
|
|
c2bd415382 | ||
|
|
245b8e671e | ||
|
|
c06abdbe3c | ||
|
|
b0a589b792 | ||
|
|
66cdcf2ee3 | ||
|
|
7c50a9d162 | ||
|
|
6538d301d1 | ||
|
|
63831d6efc | ||
|
|
cbb498bb74 | ||
|
|
e2706aecdb | ||
|
|
cb8db71e72 | ||
|
|
4fab60ea87 | ||
|
|
b4ec962a3b | ||
|
|
235250e49d | ||
|
|
016045b222 | ||
|
|
8403b0606d | ||
|
|
c685ecf124 | ||
|
|
f95aaef092 | ||
|
|
ff5b966866 | ||
|
|
44f75458d1 | ||
|
|
44dd8124b7 | ||
|
|
da44a9f55b | ||
|
|
4fa56178cf | ||
|
|
21df85cd94 | ||
|
|
e21c83602f | ||
|
|
7eecb435b9 | ||
|
|
1db79f77d7 | ||
|
|
3bfe9d6cd1 | ||
|
|
99b51efbb3 | ||
|
|
dd3ba523a4 | ||
|
|
d34a9a6ce8 | ||
|
|
bf83c83720 | ||
|
|
dcc460204d | ||
|
|
651b5c577c | ||
|
|
7ba60a5b61 | ||
|
|
40c6e3bc40 | ||
|
|
155fb32d61 | ||
|
|
b6ef00a0b3 | ||
|
|
fe96617f78 | ||
|
|
3c2423a38b | ||
|
|
7548ba2c27 | ||
|
|
22634d14fe | ||
|
|
e8262257fb | ||
|
|
e856c3c7d0 | ||
|
|
5b929a90b9 | ||
|
|
29297ff210 | ||
|
|
4b41b9baf5 | ||
|
|
04c93b6fe6 | ||
|
|
567e5d0193 | ||
|
|
0169a09469 | ||
|
|
3ce6c15a81 | ||
|
|
9ea48eaf66 | ||
|
|
f843b23365 | ||
|
|
dc9e19961a | ||
|
|
4047abee33 | ||
|
|
36e9a5d57d | ||
|
|
0c3c2ca28b | ||
|
|
ecdaeaf368 | ||
|
|
6ce92e43ac | ||
|
|
36ba7ddb7b | ||
|
|
975bb1610d | ||
|
|
660a6ace2b | ||
|
|
aeedc361c0 | ||
|
|
70086d295a | ||
|
|
69bcf664a8 | ||
|
|
6754ec0385 | ||
|
|
3b787a2043 | ||
|
|
8f35528fde | ||
|
|
f65ecac5fe | ||
|
|
086fa412ed | ||
|
|
8476332224 | ||
|
|
9dacd85713 | ||
|
|
ff83707581 | ||
|
|
a02839712e | ||
|
|
495138ffe4 | ||
|
|
e26ecf37a3 | ||
|
|
827876647f | ||
|
|
d1940692b2 | ||
|
|
d3307a22f8 | ||
|
|
93cefd6dba | ||
|
|
21718c8c14 | ||
|
|
aa54a72bbc | ||
|
|
32e6e7575a | ||
|
|
19eea3e96d | ||
|
|
75b2903ac2 | ||
|
|
0f5a6f5d98 | ||
|
|
ed90fdea02 | ||
|
|
520bd33cb3 | ||
|
|
361c695c5c | ||
|
|
bc5d622169 | ||
|
|
7859746f66 | ||
|
|
c3b8c44c68 | ||
|
|
297e93ed54 | ||
|
|
325575c6a7 | ||
|
|
3b1c9db3f8 | ||
|
|
557d3f7869 | ||
|
|
195908d379 | ||
|
|
eb5c6853c1 | ||
|
|
3c2481dc33 | ||
|
|
355040f576 | ||
|
|
bbf1c12f7a | ||
|
|
c54303da8f | ||
|
|
e3440cf1e9 | ||
|
|
86916f1999 | ||
|
|
9cebabfe01 | ||
|
|
0664fc3b21 | ||
|
|
2cb24c0523 | ||
|
|
65be22202c | ||
|
|
6cc32bafd9 | ||
|
|
6c268e658f | ||
|
|
33e24632d0 | ||
|
|
e1b4c6aafc | ||
|
|
09d1932588 | ||
|
|
4988479df4 | ||
|
|
7779e61c15 | ||
|
|
2cc8caec35 | ||
|
|
8c8715187b | ||
|
|
c591a4d3cc | ||
|
|
76cd7ed4b8 | ||
|
|
a8595c36b4 | ||
|
|
1dfe105bd0 | ||
|
|
f2ead2e4e2 | ||
|
|
234f0d8592 | ||
|
|
bd102c5fb0 | ||
|
|
521d02e6e8 | ||
|
|
91efdfe4e8 | ||
|
|
deba26a7cb | ||
|
|
b2f01687a8 | ||
|
|
dc295f9dc0 | ||
|
|
04f7c20494 | ||
|
|
cd1f122a59 | ||
|
|
8ecd24564f | ||
|
|
577938432a | ||
|
|
89f8379c73 | ||
|
|
5934e3b94d | ||
|
|
0e5974aea2 | ||
|
|
3675820555 | ||
|
|
3ba1b914d6 | ||
|
|
1dbf3fcc80 | ||
|
|
6167145454 | ||
|
|
97ae583707 | ||
|
|
0d97df6b50 | ||
|
|
0645f0d4d0 | ||
|
|
3656ab9e2a | ||
|
|
adb791d3ba | ||
|
|
f1a5d55613 | ||
|
|
f46305847e | ||
|
|
a75f3b0fd8 | ||
|
|
2934228005 | ||
|
|
d599e545f7 | ||
|
|
048870e280 | ||
|
|
31045456fe | ||
|
|
0bb5be63b9 | ||
|
|
c9f737197c | ||
|
|
d4e70feddc | ||
|
|
726a3eed13 | ||
|
|
caeed75918 | ||
|
|
9a6795125d | ||
|
|
db26fc5676 | ||
|
|
05cc7b1087 | ||
|
|
6df1f9e243 | ||
|
|
73ce84ccf7 | ||
|
|
91bb0b1231 | ||
|
|
84156a9eba | ||
|
|
b13501b9fb | ||
|
|
3363e219a7 | ||
|
|
00ee23b0b6 | ||
|
|
1286b0f69e | ||
|
|
fe5bc5454e | ||
|
|
f4e94a9089 | ||
|
|
6a7da371e2 | ||
|
|
4cf5f7a118 | ||
|
|
35fd01f9ee | ||
|
|
04aad57789 | ||
|
|
7a277a8810 | ||
|
|
b232a101d2 | ||
|
|
a01dc81500 | ||
|
|
1db628d84a | ||
|
|
f11cd34dc4 | ||
|
|
d0376e3aa5 | ||
|
|
a7518c0e5a | ||
|
|
378316bd68 | ||
|
|
286d6abf2d | ||
|
|
1f1464e90d | ||
|
|
55d9dd9277 | ||
|
|
2f290dbf85 | ||
|
|
39e3f53139 | ||
|
|
babe14d544 | ||
|
|
278fc69789 | ||
|
|
99262777fc | ||
|
|
b0f60caab2 | ||
|
|
efd5e0bb36 | ||
|
|
ade4617d53 | ||
|
|
64a5fd8227 | ||
|
|
eba968797c | ||
|
|
d60f28a7fe | ||
|
|
32069eb104 | ||
|
|
a6adcefc25 | ||
|
|
743b0ee0da | ||
|
|
ba06a6fc10 | ||
|
|
80d4c2814f | ||
|
|
b0d5007bfb | ||
|
|
d2046eb00b | ||
|
|
d04acc9c0f | ||
|
|
03cd87df1c | ||
|
|
8e8ad7178d | ||
|
|
0e26b4def7 | ||
|
|
f800985766 | ||
|
|
7b88c28a45 | ||
|
|
194dfe17d3 | ||
|
|
664160e0cc | ||
|
|
1dd760e382 | ||
|
|
05219b81f7 | ||
|
|
0bb7e4f1d0 | ||
|
|
a7fbf806fb | ||
|
|
e750c46665 | ||
|
|
935111cfea | ||
|
|
c4b2512df4 | ||
|
|
27970e24fb | ||
|
|
acc3ee3461 | ||
|
|
eefa7722c5 | ||
|
|
17547f555d | ||
|
|
ec9c59ce69 | ||
|
|
679927a684 | ||
|
|
2999faf5d7 | ||
|
|
219384b7e5 | ||
|
|
3649e46b03 | ||
|
|
88f314bc75 | ||
|
|
e2b3dc1b46 | ||
|
|
1815ea519f | ||
|
|
33356d5d35 | ||
|
|
4a5d07ec45 | ||
|
|
a50882e1ac | ||
|
|
b2cb8ebcbe | ||
|
|
6fd6cf8c4a | ||
|
|
f0fc2751e5 | ||
|
|
81cab007d0 | ||
|
|
606396839f | ||
|
|
a8e37bafb9 | ||
|
|
87a38012cd | ||
|
|
f04816e9a5 | ||
|
|
7107d036b1 | ||
|
|
30502e05ec | ||
|
|
905673ecec | ||
|
|
cfbb77c710 | ||
|
|
13dcdc5afb | ||
|
|
56ec81bf92 | ||
|
|
f1024381e0 | ||
|
|
3f3b21f08d | ||
|
|
40dd5ce18a | ||
|
|
5efb379251 | ||
|
|
2eb6521f9c | ||
|
|
bfd81e9666 | ||
|
|
8fa2322314 | ||
|
|
8982f27220 | ||
|
|
a5f97fcc8c | ||
|
|
35a9bf27df | ||
|
|
ba0af8cc20 | ||
|
|
ec85be5c6a | ||
|
|
fe989851ab | ||
|
|
46842dd200 | ||
|
|
e5eb30598d | ||
|
|
c81ad0a7c6 | ||
|
|
97641d6dda | ||
|
|
e48dac775c | ||
|
|
6282f36ac7 | ||
|
|
cf022af4a9 | ||
|
|
597c586657 | ||
|
|
fc7f9aa0c8 | ||
|
|
7492f977b6 | ||
|
|
38b7333533 | ||
|
|
1ab854f058 | ||
|
|
c59def90fb | ||
|
|
347a3ecce7 | ||
|
|
98d13ef510 | ||
|
|
35b95001c4 | ||
|
|
75c12b36d6 | ||
|
|
db01c8b33f | ||
|
|
fb4f6f6cb9 | ||
|
|
a86aea431d | ||
|
|
1a128a6d92 | ||
|
|
ddae22a3d9 | ||
|
|
893de45272 | ||
|
|
78ba4c9a59 | ||
|
|
ffa549e444 | ||
|
|
6040f17e1c | ||
|
|
da30c9110a | ||
|
|
05de7b8109 | ||
|
|
7cc6d08d7a | ||
|
|
d526a3cfa5 | ||
|
|
0e319b068d | ||
|
|
c82026cfd7 | ||
|
|
109f70c208 | ||
|
|
23cdc37ea8 | ||
|
|
7688209093 | ||
|
|
52a3a4b853 | ||
|
|
4cf0e7bc68 | ||
|
|
f36fde5054 | ||
|
|
e08eb73f98 | ||
|
|
f3143eff83 | ||
|
|
ea1fa120eb | ||
|
|
be29a12842 | ||
|
|
113f1ae58d | ||
|
|
73fff34bfe | ||
|
|
84ae6dae32 | ||
|
|
5cf39c288c | ||
|
|
7a0db79e31 | ||
|
|
40d0b20ece | ||
|
|
09cd749107 | ||
|
|
9dda940928 | ||
|
|
b7b64f98fd | ||
|
|
ed2114a1ce | ||
|
|
8b6ae96a2e | ||
|
|
72d771e126 | ||
|
|
4d7192667e | ||
|
|
43f5457802 | ||
|
|
2005068039 | ||
|
|
9028aaea88 | ||
|
|
e80eb158d8 | ||
|
|
68abb63f74 | ||
|
|
c458a4d86f | ||
|
|
cbdba8cba3 | ||
|
|
d787fa1dca | ||
|
|
b7582d0107 | ||
|
|
2d46958f9f | ||
|
|
9131742ff3 | ||
|
|
590bac0f89 | ||
|
|
a43f2c935d | ||
|
|
200dd6273f | ||
|
|
2a97e94770 | ||
|
|
bd46acb672 | ||
|
|
723006a10d | ||
|
|
da6a2a7d61 | ||
|
|
7db50de8df | ||
|
|
22a6b511f7 | ||
|
|
2f2e5e6f99 | ||
|
|
3472771a6f | ||
|
|
8989138051 | ||
|
|
c2f76213cc | ||
|
|
6ed736327a | ||
|
|
e20be0ad97 | ||
|
|
2e7355bb92 | ||
|
|
8ec7238f49 | ||
|
|
ac10f5a4e1 | ||
|
|
d658669a04 | ||
|
|
746d998d4e | ||
|
|
d1c51d90d4 | ||
|
|
0b1303b029 | ||
|
|
a78089ba10 | ||
|
|
128aaae368 | ||
|
|
230c9fa26a | ||
|
|
9834498d94 | ||
|
|
9454b5c9e1 | ||
|
|
ca3ed9ff1a | ||
|
|
836ffaad37 | ||
|
|
4c02e38954 | ||
|
|
540d0e2dff | ||
|
|
0c1e3a5f09 | ||
|
|
4337251218 | ||
|
|
baca343fdf | ||
|
|
c20a2a5a13 | ||
|
|
7fc368cf3c | ||
|
|
25b62bf4c6 | ||
|
|
47432ecafa | ||
|
|
e4f2a92c5b | ||
|
|
89d2edb61b | ||
|
|
310e499234 | ||
|
|
9ff87109f9 | ||
|
|
bfcf38f380 | ||
|
|
286f54aed4 | ||
|
|
6ef8ca45d7 | ||
|
|
85ddb8a8d6 | ||
|
|
a261f1a8b1 | ||
|
|
53a55e83c4 | ||
|
|
20bdaa22e8 | ||
|
|
246f1bd7c0 | ||
|
|
6095cc021a | ||
|
|
2ad21e9375 | ||
|
|
21ae1f34c3 | ||
|
|
a8ebefbef3 | ||
|
|
14c0c2edb1 | ||
|
|
b8148600f2 | ||
|
|
164c32c23c | ||
|
|
a5e415736d | ||
|
|
0359c21643 | ||
|
|
725a8e2fd0 | ||
|
|
dae5d4a800 | ||
|
|
704e663d6a | ||
|
|
c63885a748 | ||
|
|
8530e4c378 | ||
|
|
4944e76f97 | ||
|
|
5865e61fd2 | ||
|
|
8855ce75fc | ||
|
|
3e1809a608 | ||
|
|
04370f0aa0 |
24
.github/workflows/build.yml
vendored
Normal file
24
.github/workflows/build.yml
vendored
Normal 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
|
||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,13 +1,16 @@
|
|||||||
*.o
|
*.o
|
||||||
*.log
|
*.log
|
||||||
*.scan
|
*.scan
|
||||||
*.m4
|
|
||||||
*.cache
|
*.cache
|
||||||
*.status
|
*.status
|
||||||
|
aclocal.m4
|
||||||
Makefile
|
Makefile
|
||||||
Makefile.in
|
Makefile.in
|
||||||
configure
|
configure
|
||||||
build-aux
|
build-aux
|
||||||
.deps
|
.deps
|
||||||
.dirstamp
|
.dirstamp
|
||||||
|
.static
|
||||||
glorytun
|
glorytun
|
||||||
|
build*
|
||||||
|
VERSION
|
||||||
|
|||||||
8
.gitmodules
vendored
Normal file
8
.gitmodules
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[submodule "mud"]
|
||||||
|
path = mud
|
||||||
|
url = https://github.com/angt/mud.git
|
||||||
|
ignore = dirty
|
||||||
|
[submodule "argz"]
|
||||||
|
path = argz
|
||||||
|
url = https://github.com/angt/argz.git
|
||||||
|
ignore = dirty
|
||||||
17
.travis.yml
17
.travis.yml
@@ -14,7 +14,22 @@ before_script:
|
|||||||
- export PKG_CONFIG_PATH=/tmp/lib/pkgconfig
|
- export PKG_CONFIG_PATH=/tmp/lib/pkgconfig
|
||||||
- git clone https://github.com/jedisct1/libsodium.git --branch=stable
|
- git clone https://github.com/jedisct1/libsodium.git --branch=stable
|
||||||
- cd libsodium && ./autogen.sh && ./configure --enable-minimal --disable-dependency-tracking --prefix=/tmp && make install && cd -
|
- cd libsodium && ./autogen.sh && ./configure --enable-minimal --disable-dependency-tracking --prefix=/tmp && make install && cd -
|
||||||
- ./autogen.sh
|
- ./autogen.sh
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- ./configure --disable-dependency-tracking && make distcheck
|
- ./configure --disable-dependency-tracking && make distcheck
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
provider: releases
|
||||||
|
api_key:
|
||||||
|
secure: Ira1jd3j+17QVFbJ7KlkytTNp0oMZLTqCWPQLxNHLEt32PVY/IPs/16BcvTbFpKrY+Ma7E3KCihfufTVG8T+jRlZ5hFO7HNpoQMgi7L7yZZAGScYO5pnMQvsr8O9hf7jzSi1DjFXgFHznbPJJ3lOSwegcqzSrbZflokiCR50GTLLWewHoPpfs+1gJ5XbtVyRhZlmXhMPC0NEH2sh33X2WdUiKUJUMOnlYC0atPBL+4n12qxnugF9YA9wPK5NHJSLiPHue7I2rHlSrOLX5NkN3vqnEvusiuIFQX1y0NuKtkpOscFD9n1CLHThGLuzMvPlwpdQfzRMVxwjYFGu6Ma5alf64ksFnMKl8Oo0yCXEA7WvHXz+qUai/a1gzYZLTGuasHtjrHN/mgKxM4QRSiHo8t5hj3CczUW+OFglytawZQyGjyUUiKdwx2kvlO96RVDIYEhUD4DeHzHR8rhvDLmlMlGAWqUPXq7d4D+bExqKmqWCCSkhrbubq5B1kChRmgw7/gly4SryqGy+R0xsC4oq9jUUxd7Sl801BIKcYDb5r5gFSw+hEhOzBb+uE2xJYFNO2KZ+eG69lkFeG3oNJMTy8afs8fRRUXq0poQJ39wFWerps3Md7h8Sxs61YLIAKHvLJJMfoMI+AORTcjnnpqujMhgWGWt8wLhJZdxaSycoQkU=
|
||||||
|
skip_cleanup: true
|
||||||
|
file_glob: true
|
||||||
|
file: glorytun-*.tar.gz
|
||||||
|
on:
|
||||||
|
tags: true
|
||||||
|
repo: angt/glorytun
|
||||||
|
condition: "${TRAVIS_OS_NAME}-${CC} == linux-gcc"
|
||||||
|
|
||||||
|
after_deploy:
|
||||||
|
- md5sum glorytun-*.tar.gz
|
||||||
|
|||||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
|||||||
Copyright (c) 2015, 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
35
Makefile
Normal 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
|
||||||
39
Makefile.am
39
Makefile.am
@@ -1,4 +1,41 @@
|
|||||||
|
ACLOCAL_AMFLAGS = -I m4 --install
|
||||||
|
|
||||||
bin_PROGRAMS = glorytun
|
bin_PROGRAMS = glorytun
|
||||||
glorytun_SOURCES = src/common.h src/common-static.h src/main.c src/option.c src/option.h
|
|
||||||
glorytun_CFLAGS = $(libsodium_CFLAGS)
|
glorytun_CFLAGS = $(libsodium_CFLAGS)
|
||||||
glorytun_LDADD = $(libsodium_LIBS)
|
glorytun_LDADD = $(libsodium_LIBS)
|
||||||
|
glorytun_SOURCES = \
|
||||||
|
argz/argz.c \
|
||||||
|
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 \
|
||||||
|
src/common.h \
|
||||||
|
src/ctl.c \
|
||||||
|
src/ctl.h \
|
||||||
|
src/iface.c \
|
||||||
|
src/iface.h \
|
||||||
|
src/ip.h \
|
||||||
|
src/keygen.c \
|
||||||
|
src/main.c \
|
||||||
|
src/path.c \
|
||||||
|
src/set.c \
|
||||||
|
src/show.c \
|
||||||
|
src/str.h \
|
||||||
|
src/tun.c \
|
||||||
|
src/tun.h
|
||||||
|
|
||||||
|
EXTRA_DIST = \
|
||||||
|
LICENSE \
|
||||||
|
README.md \
|
||||||
|
VERSION \
|
||||||
|
autogen.sh \
|
||||||
|
meson.build \
|
||||||
|
mud/LICENSE \
|
||||||
|
mud/README.md \
|
||||||
|
systemd \
|
||||||
|
version.sh
|
||||||
|
|||||||
139
README.md
139
README.md
@@ -1,20 +1,133 @@
|
|||||||
# glorytun
|
# Glorytun
|
||||||
|
|
||||||
**Work In Progress:** Do not touch!
|
Glorytun is a small, simple and secure VPN over [mud](https://github.com/angt/mud).
|
||||||
|
|
||||||
glorytun depends on [libsodium](https://github.com/jedisct1/libsodium) version >= 1.0.4
|
## Compatibility
|
||||||
and needs an AES-NI capable CPU.
|
|
||||||
|
|
||||||
To build and install the latest version:
|
Glorytun only depends on [libsodium](https://github.com/jedisct1/libsodium) version >= 1.0.4.
|
||||||
|
Which can be installed on a wide variety of systems.
|
||||||
|
|
||||||
$ git clone https://github.com/angt/glorytun
|
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.
|
||||||
|
|
||||||
|
IPv4 and IPv6 are supported.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
The key features of Glorytun come directly from mud:
|
||||||
|
|
||||||
|
* **Fast and highly secure**
|
||||||
|
|
||||||
|
The use of UDP and [libsodium](https://github.com/jedisct1/libsodium) allows you to secure
|
||||||
|
your communications without impacting performance.
|
||||||
|
Glorytun uses AEGIS-256 only if AES-NI is available otherwise ChaCha20Poly1305 is used.
|
||||||
|
If you are not cpu bounded, you can force the use of ChaCha20Poly1305 for higher security.
|
||||||
|
All messages are encrypted, authenticated and marked with a timestamp.
|
||||||
|
Perfect forward secrecy is also implemented with ECDH over Curve25519.
|
||||||
|
|
||||||
|
* **Multipath and active 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.
|
||||||
|
|
||||||
|
* **Traffic shaping**
|
||||||
|
|
||||||
|
Shaping is very important in network, it allows to keep a low latency without sacrificing the bandwidth.
|
||||||
|
It also helps the multipath scheduler to make better decisions.
|
||||||
|
Currently it must be configured by hand, but soon Glorytun will do it for you.
|
||||||
|
|
||||||
|
* **Path MTU discovery without ICMP**
|
||||||
|
|
||||||
|
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.
|
||||||
|
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
|
$ cd glorytun
|
||||||
$ ./autogen.sh
|
$ sudo make install
|
||||||
$ ./configure
|
|
||||||
$ make
|
|
||||||
# make install
|
|
||||||
|
|
||||||
To create and use a new secret key:
|
This will install the binary in `/usr/bin` by default.
|
||||||
|
|
||||||
$ dd if=/dev/random iflag=fullblock of=glorytun.key bs=32 count=1
|
The more classical autotools suite is also available.
|
||||||
# glorytun keyfile glorytun.key [...]
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Just run `glorytun` with no arguments to view the list of available commands:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ glorytun
|
||||||
|
available commands:
|
||||||
|
|
||||||
|
show show tunnel info
|
||||||
|
bench start a crypto bench
|
||||||
|
bind start a new tunnel
|
||||||
|
set change tunnel properties
|
||||||
|
keygen generate a new secret key
|
||||||
|
path manage paths
|
||||||
|
version show version
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Use the keyword `help` after a command to show its usage.
|
||||||
|
|
||||||
|
## Mini HowTo
|
||||||
|
|
||||||
|
Glorytun does not touch the configuration of its network interface (except for the MTU),
|
||||||
|
It is up to the user to do it according to the tools available
|
||||||
|
on his system (systemd-networkd, netifd, ...).
|
||||||
|
This also allows a wide variety of configurations.
|
||||||
|
|
||||||
|
To start a server:
|
||||||
|
|
||||||
|
# (umask 066; glorytun keygen > my_secret_key)
|
||||||
|
# glorytun bind 0.0.0.0 keyfile my_secret_key &
|
||||||
|
|
||||||
|
You should now have an unconfigured network interface (let's say `tun0`).
|
||||||
|
For example, the simplest setup with `ifconfig`:
|
||||||
|
|
||||||
|
# ifconfig tun0 10.0.1.1 pointopoint 10.0.1.2 up
|
||||||
|
|
||||||
|
To check if the server is running, simply call `glorytun show`.
|
||||||
|
It will show you all of the running tunnels.
|
||||||
|
|
||||||
|
To start a new client, you need to get the secret key generated for the server.
|
||||||
|
Then simply call:
|
||||||
|
|
||||||
|
# glorytun bind 0.0.0.0 to SERVER_IP keyfile my_secret_key &
|
||||||
|
# ifconfig tun0 10.0.1.2 pointopoint 10.0.1.1 up
|
||||||
|
|
||||||
|
Now you have to setup your path, let's say you have an ADSL link that can do 1Mbit upload and 20Mbit download then call:
|
||||||
|
|
||||||
|
# glorytun path up LOCAL_IPADDR rate tx 1mbit rx 20mbit
|
||||||
|
|
||||||
|
Again, to check if your path is working, you can watch its status with `glorytun path`.
|
||||||
|
You should now be able to ping your server with `ping 10.0.1.1`.
|
||||||
|
|
||||||
|
If you use systemd-networkd, you can easily setup your tunnels with the helper program `glorytun-setup`.
|
||||||
|
|
||||||
|
## Thanks
|
||||||
|
|
||||||
|
* @jedisct1 for all his help and the code for MacOS/BSD.
|
||||||
|
* The team OTB (@bessa, @gregdel, @pouulet, @sduponch and @simon) for all tests and discussions.
|
||||||
|
* OVH to support this soft :)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
For feature requests and bug reports, please create an [issue](https://github.com/angt/glorytun/issues).
|
||||||
|
|||||||
1
argz
Submodule
1
argz
Submodule
Submodule argz added at 47ad9daf43
@@ -1,2 +1,3 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
autoreconf -i -f
|
autoreconf -i -f
|
||||||
|
|||||||
15
configure.ac
15
configure.ac
@@ -1,15 +1,22 @@
|
|||||||
AC_PREREQ([2.65])
|
AC_PREREQ([2.65])
|
||||||
AC_INIT([glorytun], [0.0.1], [https://github.com/angt/glorytun/issues],
|
AC_INIT([glorytun],
|
||||||
[glorytun], [https://github.com/angt/glorytun])
|
[m4_esyscmd([./version.sh])],
|
||||||
|
[https://github.com/angt/glorytun/issues],
|
||||||
|
[glorytun],
|
||||||
|
[https://github.com/angt/glorytun])
|
||||||
AC_CONFIG_SRCDIR([src/common.h])
|
AC_CONFIG_SRCDIR([src/common.h])
|
||||||
AC_CONFIG_AUX_DIR([build-aux])
|
AC_CONFIG_AUX_DIR([build-aux])
|
||||||
AM_INIT_AUTOMAKE([1.9 -Wall -Werror foreign tar-ustar subdir-objects])
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
|
AM_INIT_AUTOMAKE([1.12 -Wall -Werror foreign tar-ustar subdir-objects])
|
||||||
AM_DEP_TRACK
|
AM_DEP_TRACK
|
||||||
AM_SILENT_RULES([yes])
|
AM_SILENT_RULES([yes])
|
||||||
|
AM_PROG_CC_C_O
|
||||||
AC_PROG_CC_C99
|
AC_PROG_CC_C99
|
||||||
AC_USE_SYSTEM_EXTENSIONS
|
AC_USE_SYSTEM_EXTENSIONS
|
||||||
AC_SEARCH_LIBS([getaddrinfo], [resolv nsl])
|
|
||||||
AC_SEARCH_LIBS([socket], [socket])
|
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])
|
PKG_CHECK_MODULES([libsodium], [libsodium >= 1.0.4])
|
||||||
AC_CONFIG_FILES([Makefile])
|
AC_CONFIG_FILES([Makefile])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|||||||
275
m4/pkg.m4
Normal file
275
m4/pkg.m4
Normal file
@@ -0,0 +1,275 @@
|
|||||||
|
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||||
|
# serial 12 (pkg-config-0.29.2)
|
||||||
|
|
||||||
|
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
|
||||||
|
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
|
||||||
|
dnl
|
||||||
|
dnl This program is free software; you can redistribute it and/or modify
|
||||||
|
dnl it under the terms of the GNU General Public License as published by
|
||||||
|
dnl the Free Software Foundation; either version 2 of the License, or
|
||||||
|
dnl (at your option) any later version.
|
||||||
|
dnl
|
||||||
|
dnl This program is distributed in the hope that it will be useful, but
|
||||||
|
dnl WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
dnl General Public License for more details.
|
||||||
|
dnl
|
||||||
|
dnl You should have received a copy of the GNU General Public License
|
||||||
|
dnl along with this program; if not, write to the Free Software
|
||||||
|
dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
dnl 02111-1307, USA.
|
||||||
|
dnl
|
||||||
|
dnl As a special exception to the GNU General Public License, if you
|
||||||
|
dnl distribute this file as part of a program that contains a
|
||||||
|
dnl configuration script generated by Autoconf, you may include it under
|
||||||
|
dnl the same distribution terms that you use for the rest of that
|
||||||
|
dnl program.
|
||||||
|
|
||||||
|
dnl PKG_PREREQ(MIN-VERSION)
|
||||||
|
dnl -----------------------
|
||||||
|
dnl Since: 0.29
|
||||||
|
dnl
|
||||||
|
dnl Verify that the version of the pkg-config macros are at least
|
||||||
|
dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's
|
||||||
|
dnl installed version of pkg-config, this checks the developer's version
|
||||||
|
dnl of pkg.m4 when generating configure.
|
||||||
|
dnl
|
||||||
|
dnl To ensure that this macro is defined, also add:
|
||||||
|
dnl m4_ifndef([PKG_PREREQ],
|
||||||
|
dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])])
|
||||||
|
dnl
|
||||||
|
dnl See the "Since" comment for each macro you use to see what version
|
||||||
|
dnl of the macros you require.
|
||||||
|
m4_defun([PKG_PREREQ],
|
||||||
|
[m4_define([PKG_MACROS_VERSION], [0.29.2])
|
||||||
|
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
|
||||||
|
[m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
|
||||||
|
])dnl PKG_PREREQ
|
||||||
|
|
||||||
|
dnl PKG_PROG_PKG_CONFIG([MIN-VERSION])
|
||||||
|
dnl ----------------------------------
|
||||||
|
dnl Since: 0.16
|
||||||
|
dnl
|
||||||
|
dnl Search for the pkg-config tool and set the PKG_CONFIG variable to
|
||||||
|
dnl first found in the path. Checks that the version of pkg-config found
|
||||||
|
dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is
|
||||||
|
dnl used since that's the first version where most current features of
|
||||||
|
dnl pkg-config existed.
|
||||||
|
AC_DEFUN([PKG_PROG_PKG_CONFIG],
|
||||||
|
[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
|
||||||
|
m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
|
||||||
|
m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
|
||||||
|
AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
|
||||||
|
AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
|
||||||
|
AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
|
||||||
|
|
||||||
|
if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
|
||||||
|
AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
|
||||||
|
fi
|
||||||
|
if test -n "$PKG_CONFIG"; then
|
||||||
|
_pkg_min_version=m4_default([$1], [0.9.0])
|
||||||
|
AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
|
||||||
|
if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
PKG_CONFIG=""
|
||||||
|
fi
|
||||||
|
fi[]dnl
|
||||||
|
])dnl PKG_PROG_PKG_CONFIG
|
||||||
|
|
||||||
|
dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||||
|
dnl -------------------------------------------------------------------
|
||||||
|
dnl Since: 0.18
|
||||||
|
dnl
|
||||||
|
dnl Check to see whether a particular set of modules exists. Similar to
|
||||||
|
dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
|
||||||
|
dnl
|
||||||
|
dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||||
|
dnl only at the first occurence in configure.ac, so if the first place
|
||||||
|
dnl it's called might be skipped (such as if it is within an "if", you
|
||||||
|
dnl have to call PKG_CHECK_EXISTS manually
|
||||||
|
AC_DEFUN([PKG_CHECK_EXISTS],
|
||||||
|
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||||
|
if test -n "$PKG_CONFIG" && \
|
||||||
|
AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
|
||||||
|
m4_default([$2], [:])
|
||||||
|
m4_ifvaln([$3], [else
|
||||||
|
$3])dnl
|
||||||
|
fi])
|
||||||
|
|
||||||
|
dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
|
||||||
|
dnl ---------------------------------------------
|
||||||
|
dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting
|
||||||
|
dnl pkg_failed based on the result.
|
||||||
|
m4_define([_PKG_CONFIG],
|
||||||
|
[if test -n "$$1"; then
|
||||||
|
pkg_cv_[]$1="$$1"
|
||||||
|
elif test -n "$PKG_CONFIG"; then
|
||||||
|
PKG_CHECK_EXISTS([$3],
|
||||||
|
[pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
|
||||||
|
test "x$?" != "x0" && pkg_failed=yes ],
|
||||||
|
[pkg_failed=yes])
|
||||||
|
else
|
||||||
|
pkg_failed=untried
|
||||||
|
fi[]dnl
|
||||||
|
])dnl _PKG_CONFIG
|
||||||
|
|
||||||
|
dnl _PKG_SHORT_ERRORS_SUPPORTED
|
||||||
|
dnl ---------------------------
|
||||||
|
dnl Internal check to see if pkg-config supports short errors.
|
||||||
|
AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
|
||||||
|
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||||
|
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
|
||||||
|
_pkg_short_errors_supported=yes
|
||||||
|
else
|
||||||
|
_pkg_short_errors_supported=no
|
||||||
|
fi[]dnl
|
||||||
|
])dnl _PKG_SHORT_ERRORS_SUPPORTED
|
||||||
|
|
||||||
|
|
||||||
|
dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
|
||||||
|
dnl [ACTION-IF-NOT-FOUND])
|
||||||
|
dnl --------------------------------------------------------------
|
||||||
|
dnl Since: 0.4.0
|
||||||
|
dnl
|
||||||
|
dnl Note that if there is a possibility the first call to
|
||||||
|
dnl PKG_CHECK_MODULES might not happen, you should be sure to include an
|
||||||
|
dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
|
||||||
|
AC_DEFUN([PKG_CHECK_MODULES],
|
||||||
|
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||||
|
AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
|
||||||
|
AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
|
||||||
|
|
||||||
|
pkg_failed=no
|
||||||
|
AC_MSG_CHECKING([for $2])
|
||||||
|
|
||||||
|
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
|
||||||
|
_PKG_CONFIG([$1][_LIBS], [libs], [$2])
|
||||||
|
|
||||||
|
m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
|
||||||
|
and $1[]_LIBS to avoid the need to call pkg-config.
|
||||||
|
See the pkg-config man page for more details.])
|
||||||
|
|
||||||
|
if test $pkg_failed = yes; then
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
_PKG_SHORT_ERRORS_SUPPORTED
|
||||||
|
if test $_pkg_short_errors_supported = yes; then
|
||||||
|
$1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
|
||||||
|
else
|
||||||
|
$1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
|
||||||
|
fi
|
||||||
|
# Put the nasty error message in config.log where it belongs
|
||||||
|
echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
|
||||||
|
|
||||||
|
m4_default([$4], [AC_MSG_ERROR(
|
||||||
|
[Package requirements ($2) were not met:
|
||||||
|
|
||||||
|
$$1_PKG_ERRORS
|
||||||
|
|
||||||
|
Consider adjusting the PKG_CONFIG_PATH environment variable if you
|
||||||
|
installed software in a non-standard prefix.
|
||||||
|
|
||||||
|
_PKG_TEXT])[]dnl
|
||||||
|
])
|
||||||
|
elif test $pkg_failed = untried; then
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
m4_default([$4], [AC_MSG_FAILURE(
|
||||||
|
[The pkg-config script could not be found or is too old. Make sure it
|
||||||
|
is in your PATH or set the PKG_CONFIG environment variable to the full
|
||||||
|
path to pkg-config.
|
||||||
|
|
||||||
|
_PKG_TEXT
|
||||||
|
|
||||||
|
To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
|
||||||
|
])
|
||||||
|
else
|
||||||
|
$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
|
||||||
|
$1[]_LIBS=$pkg_cv_[]$1[]_LIBS
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
$3
|
||||||
|
fi[]dnl
|
||||||
|
])dnl PKG_CHECK_MODULES
|
||||||
|
|
||||||
|
|
||||||
|
dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
|
||||||
|
dnl [ACTION-IF-NOT-FOUND])
|
||||||
|
dnl ---------------------------------------------------------------------
|
||||||
|
dnl Since: 0.29
|
||||||
|
dnl
|
||||||
|
dnl Checks for existence of MODULES and gathers its build flags with
|
||||||
|
dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags
|
||||||
|
dnl and VARIABLE-PREFIX_LIBS from --libs.
|
||||||
|
dnl
|
||||||
|
dnl Note that if there is a possibility the first call to
|
||||||
|
dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to
|
||||||
|
dnl include an explicit call to PKG_PROG_PKG_CONFIG in your
|
||||||
|
dnl configure.ac.
|
||||||
|
AC_DEFUN([PKG_CHECK_MODULES_STATIC],
|
||||||
|
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||||
|
_save_PKG_CONFIG=$PKG_CONFIG
|
||||||
|
PKG_CONFIG="$PKG_CONFIG --static"
|
||||||
|
PKG_CHECK_MODULES($@)
|
||||||
|
PKG_CONFIG=$_save_PKG_CONFIG[]dnl
|
||||||
|
])dnl PKG_CHECK_MODULES_STATIC
|
||||||
|
|
||||||
|
|
||||||
|
dnl PKG_INSTALLDIR([DIRECTORY])
|
||||||
|
dnl -------------------------
|
||||||
|
dnl Since: 0.27
|
||||||
|
dnl
|
||||||
|
dnl Substitutes the variable pkgconfigdir as the location where a module
|
||||||
|
dnl should install pkg-config .pc files. By default the directory is
|
||||||
|
dnl $libdir/pkgconfig, but the default can be changed by passing
|
||||||
|
dnl DIRECTORY. The user can override through the --with-pkgconfigdir
|
||||||
|
dnl parameter.
|
||||||
|
AC_DEFUN([PKG_INSTALLDIR],
|
||||||
|
[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
|
||||||
|
m4_pushdef([pkg_description],
|
||||||
|
[pkg-config installation directory @<:@]pkg_default[@:>@])
|
||||||
|
AC_ARG_WITH([pkgconfigdir],
|
||||||
|
[AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
|
||||||
|
[with_pkgconfigdir=]pkg_default)
|
||||||
|
AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
|
||||||
|
m4_popdef([pkg_default])
|
||||||
|
m4_popdef([pkg_description])
|
||||||
|
])dnl PKG_INSTALLDIR
|
||||||
|
|
||||||
|
|
||||||
|
dnl PKG_NOARCH_INSTALLDIR([DIRECTORY])
|
||||||
|
dnl --------------------------------
|
||||||
|
dnl Since: 0.27
|
||||||
|
dnl
|
||||||
|
dnl Substitutes the variable noarch_pkgconfigdir as the location where a
|
||||||
|
dnl module should install arch-independent pkg-config .pc files. By
|
||||||
|
dnl default the directory is $datadir/pkgconfig, but the default can be
|
||||||
|
dnl changed by passing DIRECTORY. The user can override through the
|
||||||
|
dnl --with-noarch-pkgconfigdir parameter.
|
||||||
|
AC_DEFUN([PKG_NOARCH_INSTALLDIR],
|
||||||
|
[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
|
||||||
|
m4_pushdef([pkg_description],
|
||||||
|
[pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
|
||||||
|
AC_ARG_WITH([noarch-pkgconfigdir],
|
||||||
|
[AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
|
||||||
|
[with_noarch_pkgconfigdir=]pkg_default)
|
||||||
|
AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
|
||||||
|
m4_popdef([pkg_default])
|
||||||
|
m4_popdef([pkg_description])
|
||||||
|
])dnl PKG_NOARCH_INSTALLDIR
|
||||||
|
|
||||||
|
|
||||||
|
dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
|
||||||
|
dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||||
|
dnl -------------------------------------------
|
||||||
|
dnl Since: 0.28
|
||||||
|
dnl
|
||||||
|
dnl Retrieves the value of the pkg-config variable for the given module.
|
||||||
|
AC_DEFUN([PKG_CHECK_VAR],
|
||||||
|
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||||
|
AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
|
||||||
|
|
||||||
|
_PKG_CONFIG([$1], [variable="][$3]["], [$2])
|
||||||
|
AS_VAR_COPY([$1], [pkg_cv_][$1])
|
||||||
|
|
||||||
|
AS_VAR_IF([$1], [""], [$5], [$4])dnl
|
||||||
|
])dnl PKG_CHECK_VAR
|
||||||
63
meson.build
Normal file
63
meson.build
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
project('glorytun', 'c',
|
||||||
|
version: run_command('./version.sh').stdout(),
|
||||||
|
license: 'BSD-3-Clause',
|
||||||
|
default_options : [
|
||||||
|
'buildtype=debugoptimized',
|
||||||
|
'c_std=gnu99'
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
cc = meson.get_compiler('c')
|
||||||
|
|
||||||
|
prefix = get_option('prefix')
|
||||||
|
bindir = join_paths(prefix, get_option('bindir'))
|
||||||
|
|
||||||
|
conf_data = configuration_data()
|
||||||
|
conf_data.set('prefix', prefix)
|
||||||
|
conf_data.set('bindir', bindir)
|
||||||
|
|
||||||
|
add_global_arguments('-DPACKAGE_VERSION="'+meson.project_version()+'"', language : 'c')
|
||||||
|
add_global_arguments('-DPACKAGE_NAME="'+meson.project_name()+'"', language : 'c')
|
||||||
|
|
||||||
|
executable('glorytun', install: true,
|
||||||
|
sources: [
|
||||||
|
'argz/argz.c',
|
||||||
|
'mud/mud.c',
|
||||||
|
'mud/aegis256/aegis256.c',
|
||||||
|
'src/bench.c',
|
||||||
|
'src/bind.c',
|
||||||
|
'src/common.c',
|
||||||
|
'src/ctl.c',
|
||||||
|
'src/iface.c',
|
||||||
|
'src/keygen.c',
|
||||||
|
'src/main.c',
|
||||||
|
'src/path.c',
|
||||||
|
'src/set.c',
|
||||||
|
'src/show.c',
|
||||||
|
'src/tun.c',
|
||||||
|
],
|
||||||
|
dependencies: [
|
||||||
|
dependency('libsodium', version : '>=1.0.4'),
|
||||||
|
cc.find_library('m', required : false)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
systemd = dependency('systemd', required: false)
|
||||||
|
|
||||||
|
if systemd.found()
|
||||||
|
systemdutildir = systemd.get_pkgconfig_variable('systemdutildir')
|
||||||
|
configure_file(
|
||||||
|
input: 'systemd/glorytun@.service.in',
|
||||||
|
output: 'glorytun@.service',
|
||||||
|
configuration: conf_data,
|
||||||
|
install_dir: join_paths(systemdutildir, 'system')
|
||||||
|
)
|
||||||
|
install_data('systemd/glorytun.network',
|
||||||
|
install_dir: join_paths(systemdutildir, 'network'))
|
||||||
|
install_data('systemd/glorytun-client.network',
|
||||||
|
install_dir: join_paths(systemdutildir, 'network'))
|
||||||
|
install_data('systemd/glorytun-run',
|
||||||
|
install_dir: bindir)
|
||||||
|
install_data('systemd/glorytun-setup',
|
||||||
|
install_dir: bindir)
|
||||||
|
endif
|
||||||
1
mud
Submodule
1
mud
Submodule
Submodule mud added at b59ab48407
29
sodium.sh
Executable file
29
sodium.sh
Executable 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))"
|
||||||
164
src/bench.c
Normal file
164
src/bench.c
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
#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 "../argz/argz.h"
|
||||||
|
#include "../mud/aegis256/aegis256.h"
|
||||||
|
|
||||||
|
#define STR_S(X) (((X) > 1) ? "s" : "")
|
||||||
|
|
||||||
|
#define NPUBBYTES 32
|
||||||
|
#define KEYBYTES 32
|
||||||
|
#define ABYTES 16
|
||||||
|
|
||||||
|
static unsigned long long
|
||||||
|
gt_now(void)
|
||||||
|
{
|
||||||
|
#if defined __APPLE__
|
||||||
|
static mach_timebase_info_data_t mtid;
|
||||||
|
if (!mtid.denom)
|
||||||
|
mach_timebase_info(&mtid);
|
||||||
|
return (mach_absolute_time() * mtid.numer / mtid.denom) / 1000ULL;
|
||||||
|
#elif defined CLOCK_MONOTONIC
|
||||||
|
struct timespec tv;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &tv);
|
||||||
|
return (unsigned long long)tv.tv_sec * 1000000ULL
|
||||||
|
+ (unsigned long long)tv.tv_nsec / 1000ULL;
|
||||||
|
#else
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
return (unsigned long long)tv.tv_sec * 1000000ULL
|
||||||
|
+ (unsigned long long)tv.tv_usec;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
gt_bench(int argc, char **argv)
|
||||||
|
{
|
||||||
|
unsigned long precision = 10;
|
||||||
|
size_t bufsize = 64 * 1024;
|
||||||
|
unsigned long duration = 1000;
|
||||||
|
|
||||||
|
struct argz bench_argz[] = {
|
||||||
|
{"aes|chacha", NULL, NULL, argz_option},
|
||||||
|
{"precision", "EXPONENT", &precision, argz_ulong},
|
||||||
|
{"bufsize", "BYTES", &bufsize, argz_bytes},
|
||||||
|
{"duration", "SECONDS", &duration, argz_time},
|
||||||
|
{NULL}};
|
||||||
|
|
||||||
|
if (argz(bench_argz, argc, argv))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (duration == 0 || bufsize == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (sodium_init() == -1) {
|
||||||
|
gt_log("sodium init failed\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
duration /= 1000;
|
||||||
|
|
||||||
|
int term = isatty(1);
|
||||||
|
int aes = argz_is_set(bench_argz, "aes");
|
||||||
|
int chacha = argz_is_set(bench_argz, "chacha");
|
||||||
|
|
||||||
|
if (!aegis256_is_available()) {
|
||||||
|
if (aes) {
|
||||||
|
gt_log("aes is not available on your platform\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
chacha = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *buf = calloc(1, bufsize + ABYTES);
|
||||||
|
|
||||||
|
if (!buf) {
|
||||||
|
perror("calloc");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char npub[NPUBBYTES];
|
||||||
|
unsigned char key[KEYBYTES];
|
||||||
|
|
||||||
|
randombytes_buf(npub, sizeof(npub));
|
||||||
|
randombytes_buf(key, sizeof(key));
|
||||||
|
|
||||||
|
if (term) {
|
||||||
|
printf("\n");
|
||||||
|
printf(" %-10s %s\n", "bench", chacha ? "chacha20poly1305" : "aegis256");
|
||||||
|
printf(" %-10s %s\n", "libsodium", sodium_version_string());
|
||||||
|
printf("\n");
|
||||||
|
printf(" %-10s 2^(-%lu)\n", "precision", precision);
|
||||||
|
printf(" %-10s %zu byte%s\n", "bufsize", bufsize, STR_S(bufsize));
|
||||||
|
printf(" %-10s %lu second%s\n", "duration", duration, STR_S(duration));
|
||||||
|
printf("\n");
|
||||||
|
printf("------------------------------------------------------------\n");
|
||||||
|
printf(" %3s %9s %14s %14s %14s\n", "2^n", "min", "avg", "max", "delta");
|
||||||
|
printf("------------------------------------------------------------\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
while (!gt_quit && mbps_dlt > ldexp(mbps, -(int)precision)) {
|
||||||
|
unsigned long long now = gt_now();
|
||||||
|
double mbps_old = mbps;
|
||||||
|
size_t bytes = 0;
|
||||||
|
|
||||||
|
gt_alarm = 0;
|
||||||
|
alarm((unsigned int)duration);
|
||||||
|
|
||||||
|
while (!gt_quit && !gt_alarm) {
|
||||||
|
if (chacha) {
|
||||||
|
crypto_aead_chacha20poly1305_encrypt(
|
||||||
|
buf, NULL, buf, 1ULL << i, NULL, 0, NULL, npub, key);
|
||||||
|
} else {
|
||||||
|
aegis256_encrypt(
|
||||||
|
buf, NULL, buf, 1ULL << i, NULL, 0, npub, key);
|
||||||
|
}
|
||||||
|
bytes += 1ULL << i;
|
||||||
|
}
|
||||||
|
|
||||||
|
total_dt += gt_now() - now;
|
||||||
|
total_bytes += bytes;
|
||||||
|
|
||||||
|
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 (term) {
|
||||||
|
printf("\r %3i %9.2f Mbps %9.2f Mbps %9.2f Mbps %9.2e",
|
||||||
|
i, mbps_min, mbps, mbps_max, mbps_dlt);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (term) {
|
||||||
|
printf("\n");
|
||||||
|
} else {
|
||||||
|
printf("%i %.2f %.2f %.2f\n", i, mbps_min, mbps, mbps_max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
390
src/bind.c
Normal file
390
src/bind.c
Normal file
@@ -0,0 +1,390 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "ctl.h"
|
||||||
|
#include "iface.h"
|
||||||
|
#include "ip.h"
|
||||||
|
#include "str.h"
|
||||||
|
#include "tun.h"
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
|
||||||
|
#include "../argz/argz.h"
|
||||||
|
#include "../mud/mud.h"
|
||||||
|
|
||||||
|
#include <sodium.h>
|
||||||
|
|
||||||
|
#ifndef O_CLOEXEC
|
||||||
|
#define O_CLOEXEC 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int
|
||||||
|
fd_set_nonblock(int fd)
|
||||||
|
{
|
||||||
|
if (fd == -1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
do {
|
||||||
|
ret = fcntl(fd, F_GETFL, 0);
|
||||||
|
} while (ret == -1 && errno == EINTR);
|
||||||
|
|
||||||
|
int flags = (ret == -1) ? 0 : ret;
|
||||||
|
|
||||||
|
do {
|
||||||
|
ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
||||||
|
} while (ret == -1 && errno == EINTR);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
gt_setup_secretkey(struct mud *mud, const char *keyfile)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
do {
|
||||||
|
fd = open(keyfile, O_RDONLY | O_CLOEXEC);
|
||||||
|
} while (fd == -1 && errno == EINTR);
|
||||||
|
|
||||||
|
if (fd == -1) {
|
||||||
|
gt_log("couldn't open %s: %s\n", keyfile, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char key[32];
|
||||||
|
char buf[2 * sizeof(key)];
|
||||||
|
size_t size = 0;
|
||||||
|
|
||||||
|
while (size < sizeof(buf)) {
|
||||||
|
ssize_t r = read(fd, &buf[size], sizeof(buf) - size);
|
||||||
|
|
||||||
|
if (r <= (ssize_t)0) {
|
||||||
|
if (r && (errno == EAGAIN || errno == EINTR))
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
size += (size_t)r;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
if (size != sizeof(buf)) {
|
||||||
|
gt_log("couldn't read secret key\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gt_fromhex(key, sizeof(key), buf, sizeof(buf))) {
|
||||||
|
gt_log("secret key is not valid\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mud_set_key(mud, key, sizeof(key));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
gt_setup_mtu(struct mud *mud, size_t old, const char *tun_name)
|
||||||
|
{
|
||||||
|
size_t mtu = mud_get_mtu(mud);
|
||||||
|
|
||||||
|
if (mtu == old)
|
||||||
|
return mtu;
|
||||||
|
|
||||||
|
if (iface_set_mtu(tun_name, mtu) == -1)
|
||||||
|
gt_log("couldn't setup MTU at %zu on device %s\n", mtu, tun_name);
|
||||||
|
|
||||||
|
return mtu;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
gt_bind(int argc, char **argv)
|
||||||
|
{
|
||||||
|
struct sockaddr_storage bind_addr = { .ss_family = AF_INET };
|
||||||
|
struct sockaddr_storage peer_addr = { 0 };
|
||||||
|
unsigned short bind_port = 5000;
|
||||||
|
unsigned short peer_port = bind_port;
|
||||||
|
const char *dev = NULL;
|
||||||
|
const char *keyfile = NULL;
|
||||||
|
|
||||||
|
struct argz toz[] = {
|
||||||
|
{NULL, "IPADDR", &peer_addr, argz_addr},
|
||||||
|
{NULL, "PORT", &peer_port, argz_ushort},
|
||||||
|
{NULL}};
|
||||||
|
|
||||||
|
struct argz bindz[] = {
|
||||||
|
{NULL, "IPADDR", &bind_addr, argz_addr},
|
||||||
|
{NULL, "PORT", &bind_port, argz_ushort},
|
||||||
|
{"to", NULL, &toz, argz_option},
|
||||||
|
{"dev", "NAME", &dev, argz_str},
|
||||||
|
{"keyfile", "FILE", &keyfile, argz_str},
|
||||||
|
{"chacha", NULL, NULL, argz_option},
|
||||||
|
{"persist", NULL, NULL, argz_option},
|
||||||
|
{NULL}};
|
||||||
|
|
||||||
|
if (argz(bindz, argc, argv))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (str_empty(keyfile)) {
|
||||||
|
gt_log("a keyfile is needed!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gt_set_port((struct sockaddr *)&bind_addr, bind_port);
|
||||||
|
gt_set_port((struct sockaddr *)&peer_addr, peer_port);
|
||||||
|
|
||||||
|
int chacha = argz_is_set(bindz, "chacha");
|
||||||
|
int persist = argz_is_set(bindz, "persist");
|
||||||
|
|
||||||
|
if (sodium_init() == -1) {
|
||||||
|
gt_log("couldn't init sodium\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char hashkey[crypto_shorthash_KEYBYTES];
|
||||||
|
randombytes_buf(hashkey, sizeof(hashkey));
|
||||||
|
|
||||||
|
struct mud *mud = mud_create((struct sockaddr *)&bind_addr);
|
||||||
|
const int mud_fd = mud_get_fd(mud);
|
||||||
|
|
||||||
|
if (mud_fd == -1) {
|
||||||
|
gt_log("couldn't create mud\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gt_setup_secretkey(mud, keyfile))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!chacha && mud_set_aes(mud)) {
|
||||||
|
gt_log("AES is not available, enjoy ChaCha20!\n");
|
||||||
|
chacha = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char tun_name[64];
|
||||||
|
const int tun_fd = tun_create(tun_name, sizeof(tun_name), dev);
|
||||||
|
|
||||||
|
if (tun_fd == -1) {
|
||||||
|
gt_log("couldn't create tun device\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t mtu = gt_setup_mtu(mud, 0, tun_name);
|
||||||
|
|
||||||
|
if (tun_set_persist(tun_fd, persist) == -1) {
|
||||||
|
gt_log("couldn't %sable persist mode on device %s\n",
|
||||||
|
persist ? "en" : "dis", tun_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peer_addr.ss_family) {
|
||||||
|
if (mud_peer(mud, (struct sockaddr *)&peer_addr)) {
|
||||||
|
perror("mud_peer");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const int ctl_fd = ctl_create(GT_RUNDIR, tun_name);
|
||||||
|
|
||||||
|
if (ctl_fd == -1) {
|
||||||
|
gt_log("couldn't create "GT_RUNDIR"/%s: %s\n",
|
||||||
|
tun_name, strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
const long pid = (long)getpid();
|
||||||
|
|
||||||
|
gt_log("running on device %s as pid %li\n", tun_name, pid);
|
||||||
|
|
||||||
|
fd_set rfds, wfds;
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
FD_ZERO(&wfds);
|
||||||
|
|
||||||
|
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];
|
||||||
|
|
||||||
|
while (!gt_quit) {
|
||||||
|
if (tun_can_write) {
|
||||||
|
FD_CLR(tun_fd, &wfds);
|
||||||
|
} else {
|
||||||
|
FD_SET(tun_fd, &wfds);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mud_can_write) {
|
||||||
|
FD_CLR(mud_fd, &wfds);
|
||||||
|
} else {
|
||||||
|
FD_SET(mud_fd, &wfds);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tun_can_read) {
|
||||||
|
FD_CLR(tun_fd, &rfds);
|
||||||
|
} else {
|
||||||
|
FD_SET(tun_fd, &rfds);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mud_can_read) {
|
||||||
|
FD_CLR(mud_fd, &rfds);
|
||||||
|
} else {
|
||||||
|
FD_SET(mud_fd, &rfds);
|
||||||
|
}
|
||||||
|
|
||||||
|
FD_SET(ctl_fd, &rfds);
|
||||||
|
|
||||||
|
struct timeval tv = {
|
||||||
|
.tv_usec = 100000,
|
||||||
|
};
|
||||||
|
|
||||||
|
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 (errno == EBADF) {
|
||||||
|
perror("select");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
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, 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)) {
|
||||||
|
struct ctl_msg req, res = {.reply = 1};
|
||||||
|
struct sockaddr_storage ss;
|
||||||
|
socklen_t sl = sizeof(ss);
|
||||||
|
|
||||||
|
ssize_t r = recvfrom(ctl_fd, &req, sizeof(req), 0,
|
||||||
|
(struct sockaddr *)&ss, &sl);
|
||||||
|
|
||||||
|
if (r == (ssize_t)sizeof(req)) {
|
||||||
|
res.type = req.type;
|
||||||
|
|
||||||
|
switch (req.type) {
|
||||||
|
case CTL_NONE:
|
||||||
|
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))
|
||||||
|
res.ret = errno;
|
||||||
|
break;
|
||||||
|
case CTL_PATH_STATUS:
|
||||||
|
{
|
||||||
|
unsigned count = 0;
|
||||||
|
struct mud_path *paths = mud_get_paths(mud, &count);
|
||||||
|
|
||||||
|
if (!paths) {
|
||||||
|
res.ret = errno;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.ret = EAGAIN;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < count; i++) {
|
||||||
|
memcpy(&res.path_status, &paths[i], sizeof(struct mud_path));
|
||||||
|
if (sendto(ctl_fd, &res, sizeof(res), 0,
|
||||||
|
(const struct sockaddr *)&ss, sl) == -1)
|
||||||
|
perror("sendto(ctl)");
|
||||||
|
}
|
||||||
|
|
||||||
|
free(paths);
|
||||||
|
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))
|
||||||
|
res.ret = errno;
|
||||||
|
break;
|
||||||
|
case CTL_KXTIMEOUT:
|
||||||
|
if (mud_set_keyx_timeout(mud, req.ms))
|
||||||
|
res.ret = errno;
|
||||||
|
break;
|
||||||
|
case CTL_TIMETOLERANCE:
|
||||||
|
if (mud_set_time_tolerance(mud, req.ms))
|
||||||
|
res.ret = errno;
|
||||||
|
break;
|
||||||
|
case CTL_STATUS:
|
||||||
|
memcpy(res.status.tun_name, tun_name, sizeof(tun_name)); // XXX
|
||||||
|
res.status.pid = pid;
|
||||||
|
res.status.mtu = mtu;
|
||||||
|
res.status.chacha = chacha;
|
||||||
|
res.status.bind = bind_addr;
|
||||||
|
res.status.peer = peer_addr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (sendto(ctl_fd, &res, sizeof(res), 0,
|
||||||
|
(const struct sockaddr *)&ss, sl) == -1)
|
||||||
|
perror("sendto(ctl)");
|
||||||
|
} else if (r == -1 && errno != EAGAIN) {
|
||||||
|
perror("recvfrom(ctl)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gt_reload && tun_fd >= 0)
|
||||||
|
tun_set_persist(tun_fd, 1);
|
||||||
|
|
||||||
|
mud_delete(mud);
|
||||||
|
ctl_delete(ctl_fd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -1,142 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
static inline void byte_set (void *dst, const char value, size_t size)
|
|
||||||
{
|
|
||||||
if (!dst)
|
|
||||||
return;
|
|
||||||
|
|
||||||
char *restrict d = dst;
|
|
||||||
|
|
||||||
while (size--)
|
|
||||||
*d++ = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void byte_cpy (void *dst, const void *src, size_t size)
|
|
||||||
{
|
|
||||||
if (!dst || !src)
|
|
||||||
return;
|
|
||||||
|
|
||||||
char *restrict d = dst;
|
|
||||||
const char *restrict s = src;
|
|
||||||
|
|
||||||
while (size--)
|
|
||||||
*d++ = *s++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline size_t str_cpy (char *restrict dst, const char *restrict src, size_t len)
|
|
||||||
{
|
|
||||||
if (!dst || !src)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for (i=0; i<len && src[i]; i++)
|
|
||||||
dst[i] = src[i];
|
|
||||||
|
|
||||||
dst[i] = 0;
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int str_cmp (const char *restrict sa, const char *restrict sb)
|
|
||||||
{
|
|
||||||
if (!sa || !sb)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
while (*sa==*sb++)
|
|
||||||
if (!*sa++)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline size_t str_len (const char *restrict str)
|
|
||||||
{
|
|
||||||
if (!str)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
size_t i = 0;
|
|
||||||
|
|
||||||
while (str[i])
|
|
||||||
i++;
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline char *str_cat (const char *const strs[], size_t count)
|
|
||||||
{
|
|
||||||
size_t size = 1;
|
|
||||||
|
|
||||||
for (size_t i=0; i<count; i++)
|
|
||||||
size += str_len(strs[i]);
|
|
||||||
|
|
||||||
char *str = malloc(size);
|
|
||||||
|
|
||||||
if (!str)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
char *p = str;
|
|
||||||
|
|
||||||
for (size_t i=0; i<count; i++) {
|
|
||||||
size_t len = str_len(strs[i]);
|
|
||||||
byte_cpy(p, strs[i], len);
|
|
||||||
p += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
p[0] = 0;
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void buffer_setup (buffer_t *buffer, void *data, size_t size)
|
|
||||||
{
|
|
||||||
if (!data)
|
|
||||||
data = malloc(ALIGN(size));
|
|
||||||
|
|
||||||
buffer->data = data;
|
|
||||||
buffer->read = data;
|
|
||||||
buffer->write = data;
|
|
||||||
buffer->end = data;
|
|
||||||
buffer->end += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void buffer_format (buffer_t *buffer)
|
|
||||||
{
|
|
||||||
buffer->write = buffer->data;
|
|
||||||
buffer->read = buffer->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline size_t buffer_size (buffer_t *buffer)
|
|
||||||
{
|
|
||||||
return buffer->end-buffer->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline size_t buffer_write_size (buffer_t *buffer)
|
|
||||||
{
|
|
||||||
return buffer->end-buffer->write;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline size_t buffer_read_size (buffer_t *buffer)
|
|
||||||
{
|
|
||||||
return buffer->write-buffer->read;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void buffer_shift (buffer_t *buffer)
|
|
||||||
{
|
|
||||||
if (buffer->read==buffer->write) {
|
|
||||||
buffer_format(buffer);
|
|
||||||
} else {
|
|
||||||
const uint8_t *src = PALIGN_DOWN(buffer->read);
|
|
||||||
const size_t size = ALIGN(buffer->write-src);
|
|
||||||
if (buffer->data+size<src) {
|
|
||||||
byte_cpy(buffer->data, src, size);
|
|
||||||
buffer->read -= src-buffer->data;
|
|
||||||
buffer->write -= src-buffer->data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
116
src/common.c
Normal file
116
src/common.c
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void
|
||||||
|
gt_log(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
gt_tohex(char *dst, size_t dst_size, const uint8_t *src, size_t src_size)
|
||||||
|
{
|
||||||
|
if (_0_(!dst_size))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (_0_(((dst_size - 1) / 2) < src_size))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
static const char tbl[] = "0123456789ABCDEF";
|
||||||
|
|
||||||
|
for (size_t i = 0; i < src_size; i++) {
|
||||||
|
*dst++ = tbl[0xF & (src[i] >> 4)];
|
||||||
|
*dst++ = tbl[0xF & (src[i])];
|
||||||
|
}
|
||||||
|
|
||||||
|
*dst = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_const_ static inline int
|
||||||
|
fromhex(const char c)
|
||||||
|
{
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
return c - '0';
|
||||||
|
|
||||||
|
if (c >= 'A' && c <= 'F')
|
||||||
|
return c - 'A' + 10;
|
||||||
|
|
||||||
|
if (c >= 'a' && c <= 'f')
|
||||||
|
return c - 'a' + 10;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
gt_fromhex(uint8_t *dst, size_t dst_size, const char *src, size_t src_size)
|
||||||
|
{
|
||||||
|
if (_0_(src_size & 1))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (_0_(dst_size < (src_size / 2)))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < src_size; i += 2) {
|
||||||
|
const int a = fromhex(src[i]);
|
||||||
|
const int b = fromhex(src[i + 1]);
|
||||||
|
|
||||||
|
if (_0_(a == -1 || b == -1))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
*dst++ = (uint8_t)((a << 4) | b);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gt_set_port(struct sockaddr *sa, uint16_t port)
|
||||||
|
{
|
||||||
|
switch (sa->sa_family) {
|
||||||
|
case AF_INET:
|
||||||
|
((struct sockaddr_in *)sa)->sin_port = htons(port);
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t
|
||||||
|
gt_get_port(struct sockaddr *sa)
|
||||||
|
{
|
||||||
|
switch (sa->sa_family) {
|
||||||
|
case AF_INET:
|
||||||
|
return ntohs(((struct sockaddr_in *)sa)->sin_port);
|
||||||
|
case AF_INET6:
|
||||||
|
return ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
gt_toaddr(char *str, size_t size, struct sockaddr *sa)
|
||||||
|
{
|
||||||
|
if (str)
|
||||||
|
str[0] = 0;
|
||||||
|
|
||||||
|
switch (sa->sa_family) {
|
||||||
|
case AF_INET:
|
||||||
|
return -!inet_ntop(AF_INET,
|
||||||
|
&((struct sockaddr_in *)sa)->sin_addr, str, (socklen_t)size);
|
||||||
|
case AF_INET6:
|
||||||
|
return -!inet_ntop(AF_INET6,
|
||||||
|
&((struct sockaddr_in6 *)sa)->sin6_addr, str, (socklen_t)size);
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = EAFNOSUPPORT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
68
src/common.h
68
src/common.h
@@ -1,9 +1,31 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#if defined __linux__ && !defined _GNU_SOURCE
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#define COUNT(x) (sizeof(x)/sizeof(x[0]))
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#ifndef PACKAGE_NAME
|
||||||
|
#define PACKAGE_NAME "glorytun"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PACKAGE_VERSION
|
||||||
|
#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)
|
#define ALIGN_SIZE (1<<4)
|
||||||
#define ALIGN_MASK (ALIGN_SIZE-1)
|
#define ALIGN_MASK (ALIGN_SIZE-1)
|
||||||
@@ -14,13 +36,41 @@
|
|||||||
#define PALIGN(x) ((void *)ALIGN((size_t)(x)))
|
#define PALIGN(x) ((void *)ALIGN((size_t)(x)))
|
||||||
#define PALIGN_DOWN(x) ((void *)ALIGN_DOWN((size_t)(x)))
|
#define PALIGN_DOWN(x) ((void *)ALIGN_DOWN((size_t)(x)))
|
||||||
|
|
||||||
#define _unused_ __attribute__((unused))
|
#define _1_(x) (__builtin_expect((x), 1))
|
||||||
|
#define _0_(x) (__builtin_expect((x), 0))
|
||||||
|
|
||||||
typedef struct buffer buffer_t;
|
#define CLZ(x) (__builtin_clz(x))
|
||||||
|
|
||||||
struct buffer {
|
#define _printf_(A,B) __attribute__ ((format(printf,A,B)))
|
||||||
uint8_t *data;
|
#define _noreturn_ __attribute__ ((noreturn))
|
||||||
uint8_t *read;
|
#define _unused_ __attribute__ ((unused))
|
||||||
uint8_t *write;
|
#define _pure_ __attribute__ ((pure))
|
||||||
uint8_t *end;
|
#define _const_ __attribute__ ((const))
|
||||||
};
|
#define _align_(...) __attribute__ ((aligned(__VA_ARGS__)))
|
||||||
|
|
||||||
|
#undef MAX
|
||||||
|
#define MAX(x,y) ({ __typeof__(x) X=(x); __typeof__(y) Y=(y); X > Y ? X : Y; })
|
||||||
|
|
||||||
|
#undef MIN
|
||||||
|
#define MIN(x,y) ({ __typeof__(x) X=(x); __typeof__(y) Y=(y); X < Y ? X : Y; })
|
||||||
|
|
||||||
|
extern volatile sig_atomic_t gt_alarm;
|
||||||
|
extern volatile sig_atomic_t gt_reload;
|
||||||
|
extern volatile sig_atomic_t gt_quit;
|
||||||
|
|
||||||
|
int gt_print (const char *, ...) _printf_(1,2);
|
||||||
|
void gt_log (const char *, ...) _printf_(1,2);
|
||||||
|
|
||||||
|
int gt_tohex (char *, size_t, const uint8_t *, size_t);
|
||||||
|
int gt_fromhex (uint8_t *, size_t, const char *, size_t);
|
||||||
|
|
||||||
|
void gt_set_port (struct sockaddr *, uint16_t);
|
||||||
|
uint16_t gt_get_port (struct sockaddr *);
|
||||||
|
int gt_toaddr (char *, size_t, struct sockaddr *);
|
||||||
|
|
||||||
|
int gt_show (int, char **);
|
||||||
|
int gt_bind (int, char **);
|
||||||
|
int gt_path (int, char **);
|
||||||
|
int gt_keygen (int, char **);
|
||||||
|
int gt_bench (int, char **);
|
||||||
|
int gt_set (int, char **);
|
||||||
|
|||||||
169
src/ctl.c
Normal file
169
src/ctl.c
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "ctl.h"
|
||||||
|
#include "str.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
ctl_reply(int fd, struct ctl_msg *res, struct ctl_msg *req)
|
||||||
|
{
|
||||||
|
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 = EBADMSG;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res->ret) {
|
||||||
|
errno = res->ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ctl_setsun(struct sockaddr_un *dst, const char *dir, const char *file)
|
||||||
|
{
|
||||||
|
struct sockaddr_un sun = {
|
||||||
|
.sun_family = AF_UNIX,
|
||||||
|
};
|
||||||
|
|
||||||
|
int ret = snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/%s", dir, file);
|
||||||
|
|
||||||
|
if (ret <= 0 || (size_t)ret >= sizeof(sun.sun_path)) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dst)
|
||||||
|
*dst = sun;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ctl_bind(int fd, const char *dir, const char *file)
|
||||||
|
{
|
||||||
|
char name[10] = { [0] = '.' };
|
||||||
|
struct sockaddr_un sun;
|
||||||
|
|
||||||
|
if (str_empty(file)) {
|
||||||
|
unsigned pid = (unsigned)getpid();
|
||||||
|
|
||||||
|
for (size_t i = 1; i < sizeof(name) - 1; i++, pid >>= 4)
|
||||||
|
name[i] = "uncopyrightables"[pid & 15];
|
||||||
|
|
||||||
|
file = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
ctl_delete(int fd)
|
||||||
|
{
|
||||||
|
struct sockaddr_storage ss = { 0 };
|
||||||
|
socklen_t sslen = sizeof(ss);
|
||||||
|
|
||||||
|
if ((getsockname(fd, (struct sockaddr *)&ss, &sslen) == 0) &&
|
||||||
|
(ss.ss_family == AF_UNIX))
|
||||||
|
unlink(((struct sockaddr_un *)&ss)->sun_path);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ctl_create(const char *dir, const char *file)
|
||||||
|
{
|
||||||
|
if (str_empty(dir)) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mkdir(dir, 0700) == -1 && errno != EEXIST)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int fd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||||
|
|
||||||
|
if (ctl_bind(fd, dir, file)) {
|
||||||
|
int err = errno;
|
||||||
|
close(fd);
|
||||||
|
errno = err;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ctl_connect(const char *dir, const char *file)
|
||||||
|
{
|
||||||
|
DIR *dp = NULL;
|
||||||
|
|
||||||
|
if (str_empty(dir)) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file) {
|
||||||
|
if (dp = opendir(dir), !dp)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
struct dirent *d = NULL;
|
||||||
|
|
||||||
|
while (d = readdir(dp), d) {
|
||||||
|
if (d->d_name[0] == '.')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
closedir(dp);
|
||||||
|
return CTL_ERROR_MANY;
|
||||||
|
}
|
||||||
|
|
||||||
|
file = &d->d_name[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file) {
|
||||||
|
closedir(dp);
|
||||||
|
return CTL_ERROR_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_un sun;
|
||||||
|
const int ret = ctl_setsun(&sun, dir, file);
|
||||||
|
|
||||||
|
if (dp) {
|
||||||
|
int err = errno;
|
||||||
|
closedir(dp);
|
||||||
|
errno = err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int fd = ctl_create(dir, NULL);
|
||||||
|
|
||||||
|
if (connect(fd, (struct sockaddr *)&sun, sizeof(sun))) {
|
||||||
|
int err = errno;
|
||||||
|
ctl_delete(fd);
|
||||||
|
errno = err;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
49
src/ctl.h
Normal file
49
src/ctl.h
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../mud/mud.h"
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#define CTL_ERROR_NONE (-2)
|
||||||
|
#define CTL_ERROR_MANY (-3)
|
||||||
|
|
||||||
|
enum ctl_type {
|
||||||
|
CTL_NONE = 0,
|
||||||
|
CTL_STATE,
|
||||||
|
CTL_STATUS,
|
||||||
|
CTL_MTU,
|
||||||
|
CTL_TC,
|
||||||
|
CTL_KXTIMEOUT,
|
||||||
|
CTL_TIMETOLERANCE,
|
||||||
|
CTL_PATH_STATUS,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ctl_msg {
|
||||||
|
enum ctl_type type;
|
||||||
|
int reply, ret;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
struct sockaddr_storage addr;
|
||||||
|
enum mud_state state;
|
||||||
|
unsigned long rate_tx;
|
||||||
|
unsigned long rate_rx;
|
||||||
|
} 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;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
int ctl_create (const char *, const char *);
|
||||||
|
int ctl_connect (const char *, const char *);
|
||||||
|
int ctl_reply (int, struct ctl_msg *, struct ctl_msg *);
|
||||||
|
void ctl_delete (int);
|
||||||
39
src/iface.c
Normal file
39
src/iface.c
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "iface.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
iface_set_mtu(const char *dev_name, size_t mtu)
|
||||||
|
{
|
||||||
|
if (mtu > (size_t)0xFFFF) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ifreq ifr = {
|
||||||
|
.ifr_mtu = (int)mtu,
|
||||||
|
};
|
||||||
|
|
||||||
|
int ret = snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", dev_name);
|
||||||
|
|
||||||
|
if (ret <= 0 || (size_t)ret >= sizeof(ifr.ifr_name)) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
|
||||||
|
if (fd == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
ret = ioctl(fd, SIOCSIFMTU, &ifr);
|
||||||
|
|
||||||
|
int err = errno;
|
||||||
|
close(fd);
|
||||||
|
errno = err;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
3
src/iface.h
Normal file
3
src/iface.h
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
int iface_set_mtu (const char *, size_t);
|
||||||
97
src/ip.h
Normal file
97
src/ip.h
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct ip_common {
|
||||||
|
uint8_t tc;
|
||||||
|
uint8_t proto;
|
||||||
|
struct { // data are not reordered
|
||||||
|
union {
|
||||||
|
unsigned char v6[16];
|
||||||
|
struct {
|
||||||
|
unsigned char zero[10];
|
||||||
|
unsigned char ff[2];
|
||||||
|
unsigned char v4[4];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
unsigned char port[2];
|
||||||
|
} src, dst;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
ip_read16(const uint8_t *src)
|
||||||
|
{
|
||||||
|
return ((int)src[1]) | (((int)src[0]) << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t
|
||||||
|
ip_get_version(const uint8_t *data, int size)
|
||||||
|
{
|
||||||
|
if (size < 20)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return data[0] >> 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
ip_is_valid(const uint8_t *data, int size)
|
||||||
|
{
|
||||||
|
switch (ip_get_version(data, size)) {
|
||||||
|
case 4: return size == ip_read16(&data[2]);
|
||||||
|
case 6: return size == ip_read16(&data[4]) + 40;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
ip_get_common(struct ip_common *ic, const uint8_t *data, int size)
|
||||||
|
{
|
||||||
|
switch (ip_get_version(data, size)) {
|
||||||
|
case 4:
|
||||||
|
ic->tc = data[1];
|
||||||
|
ic->proto = data[9];
|
||||||
|
if (size == ip_read16(&data[2])) {
|
||||||
|
const int hdrsize = (data[0] & 0xF) << 2;
|
||||||
|
memset(ic->src.zero, 0, sizeof(ic->src.zero));
|
||||||
|
memset(ic->src.ff, 0xff, sizeof(ic->src.ff));
|
||||||
|
memcpy(ic->src.v4, &data[12], sizeof(ic->src.v4));
|
||||||
|
memset(ic->dst.zero, 0, sizeof(ic->dst.zero));
|
||||||
|
memset(ic->dst.ff, 0xff, sizeof(ic->dst.ff));
|
||||||
|
memcpy(ic->dst.v4, &data[16], sizeof(ic->dst.v4));
|
||||||
|
switch (ic->proto) {
|
||||||
|
case 6: // tcp
|
||||||
|
case 17: // udp
|
||||||
|
memcpy(ic->src.port, &data[hdrsize], sizeof(ic->src.port));
|
||||||
|
memcpy(ic->dst.port, &data[hdrsize + 2], sizeof(ic->dst.port));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
memset(ic->src.port, 0, sizeof(ic->src.port));
|
||||||
|
memset(ic->dst.port, 0, sizeof(ic->dst.port));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
ic->tc = (uint8_t)((data[0] << 4) | (data[1] >> 4));
|
||||||
|
ic->proto = data[6];
|
||||||
|
if (size == ip_read16(&data[4]) + 40) {
|
||||||
|
memcpy(ic->src.v6, &data[8], sizeof(ic->src.v6));
|
||||||
|
memcpy(ic->dst.v6, &data[24], sizeof(ic->dst.v6));
|
||||||
|
switch (ic->proto) {
|
||||||
|
case 6: // tcp
|
||||||
|
case 17: // udp
|
||||||
|
memcpy(ic->src.port, &data[40], sizeof(ic->src.port));
|
||||||
|
memcpy(ic->dst.port, &data[42], sizeof(ic->dst.port));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
memset(ic->src.port, 0, sizeof(ic->src.port));
|
||||||
|
memset(ic->dst.port, 0, sizeof(ic->dst.port));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
22
src/keygen.c
Normal file
22
src/keygen.c
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#include <sodium.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
gt_keygen(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if (sodium_init() == -1) {
|
||||||
|
gt_log("sodium init failed\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char key[32];
|
||||||
|
randombytes_buf(key, sizeof(key));
|
||||||
|
|
||||||
|
char buf[2 * sizeof(key) + 1];
|
||||||
|
gt_tohex(buf, sizeof(buf), key, sizeof(key));
|
||||||
|
printf("%s\n", buf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
919
src/main.c
919
src/main.c
@@ -1,890 +1,107 @@
|
|||||||
#include "common-static.h"
|
#include "common.h"
|
||||||
#include "option.h"
|
#include "str.h"
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <poll.h>
|
|
||||||
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/fcntl.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/tcp.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <netdb.h>
|
|
||||||
|
|
||||||
#ifdef __linux__
|
|
||||||
# include <linux/if.h>
|
|
||||||
# include <linux/if_tun.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <sodium.h>
|
#include <sodium.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#ifndef O_CLOEXEC
|
#include "../argz/argz.h"
|
||||||
#define O_CLOEXEC 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define GT_BUFFER_SIZE (4*1024*1024)
|
volatile sig_atomic_t gt_alarm;
|
||||||
#define GT_TIMEOUT (1000)
|
volatile sig_atomic_t gt_reload;
|
||||||
|
volatile sig_atomic_t gt_quit;
|
||||||
|
|
||||||
struct netio {
|
static void
|
||||||
int fd;
|
gt_sa_handler(int sig)
|
||||||
struct {
|
|
||||||
buffer_t buf;
|
|
||||||
ssize_t ret;
|
|
||||||
} write, read;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct crypto_ctx {
|
|
||||||
crypto_aead_aes256gcm_state state_r;
|
|
||||||
crypto_aead_aes256gcm_state state_w;
|
|
||||||
uint8_t nonce_r[crypto_aead_aes256gcm_NPUBBYTES];
|
|
||||||
uint8_t nonce_w[crypto_aead_aes256gcm_NPUBBYTES];
|
|
||||||
uint8_t skey[crypto_generichash_KEYBYTES];
|
|
||||||
};
|
|
||||||
|
|
||||||
volatile sig_atomic_t running;
|
|
||||||
|
|
||||||
static void gt_not_available (const char *name)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "%s is not available on your platform!\n", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int64_t dt_ms (struct timeval *ta, struct timeval *tb)
|
|
||||||
{
|
|
||||||
const int64_t s = ta->tv_sec-tb->tv_sec;
|
|
||||||
const int64_t n = ta->tv_usec-tb->tv_usec;
|
|
||||||
return s*1000LL+n/1000LL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fd_set_nonblock (int fd)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
do {
|
|
||||||
ret = fcntl(fd, F_GETFL, 0);
|
|
||||||
} while (ret==-1 && errno==EINTR);
|
|
||||||
|
|
||||||
int flags = (ret==-1)?0:ret;
|
|
||||||
|
|
||||||
do {
|
|
||||||
ret = fcntl(fd, F_SETFL, flags|O_NONBLOCK);
|
|
||||||
} while (ret==-1 && errno==EINTR);
|
|
||||||
|
|
||||||
if (ret==-1)
|
|
||||||
perror("fcntl O_NONBLOCK");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sk_set_nodelay (int fd)
|
|
||||||
{
|
|
||||||
int val = 1;
|
|
||||||
|
|
||||||
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY , &val, sizeof(val))==-1)
|
|
||||||
perror("setsockopt TCP_NODELAY");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sk_set_reuseaddr (int fd)
|
|
||||||
{
|
|
||||||
int val = 1;
|
|
||||||
|
|
||||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))==-1)
|
|
||||||
perror("setsockopt SO_REUSEADDR");
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef TCP_CONGESTION
|
|
||||||
static void sk_set_congestion (int fd, const char *name)
|
|
||||||
{
|
|
||||||
size_t len = str_len(name);
|
|
||||||
|
|
||||||
if (!len)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (setsockopt(fd, IPPROTO_TCP, TCP_CONGESTION, name, len+1)==-1)
|
|
||||||
perror("setsockopt TCP_CONGESTION");
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static void sk_set_congestion (_unused_ int fd, _unused_ const char *name)
|
|
||||||
{
|
|
||||||
gt_not_available("TCP_CONGESTION");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int sk_listen (int fd, struct addrinfo *ai)
|
|
||||||
{
|
|
||||||
sk_set_reuseaddr(fd);
|
|
||||||
|
|
||||||
int ret = bind(fd, ai->ai_addr, ai->ai_addrlen);
|
|
||||||
|
|
||||||
if (ret==-1) {
|
|
||||||
perror("bind");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = listen(fd, 1);
|
|
||||||
|
|
||||||
if (ret==-1) {
|
|
||||||
perror("listen");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sk_connect (int fd, struct addrinfo *ai)
|
|
||||||
{
|
|
||||||
int ret = connect(fd, ai->ai_addr, ai->ai_addrlen);
|
|
||||||
|
|
||||||
if (ret==-1 && errno==EINTR)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sk_create (struct addrinfo *res, int(*func)(int, struct addrinfo *))
|
|
||||||
{
|
|
||||||
for (struct addrinfo *ai=res; ai; ai=ai->ai_next) {
|
|
||||||
int fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
|
||||||
|
|
||||||
if (fd==-1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (func(fd, ai)!=-1)
|
|
||||||
return fd;
|
|
||||||
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sk_accept (int fd)
|
|
||||||
{
|
|
||||||
struct sockaddr_storage addr;
|
|
||||||
socklen_t addr_size = sizeof(addr);
|
|
||||||
|
|
||||||
int ret = accept(fd, (struct sockaddr *)&addr, &addr_size);
|
|
||||||
|
|
||||||
if (ret==-1 && errno!=EINTR)
|
|
||||||
perror("accept");
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *sk_get_name (int fd)
|
|
||||||
{
|
|
||||||
struct sockaddr_storage addr;
|
|
||||||
socklen_t addr_size = sizeof(addr);
|
|
||||||
|
|
||||||
if (getpeername(fd, (struct sockaddr *)&addr, &addr_size)==-1) {
|
|
||||||
perror("getpeername");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
char host[64] = {0};
|
|
||||||
char port[32] = {0};
|
|
||||||
|
|
||||||
int ret = getnameinfo((struct sockaddr *)&addr, addr_size,
|
|
||||||
host, sizeof(host),
|
|
||||||
port, sizeof(port),
|
|
||||||
NI_NUMERICHOST|NI_NUMERICSERV);
|
|
||||||
|
|
||||||
switch (ret) {
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
case EAI_MEMORY:
|
|
||||||
errno = ENOMEM;
|
|
||||||
case EAI_SYSTEM:
|
|
||||||
perror("getnameinfo");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *const strs[] = {
|
|
||||||
host, ".", port
|
|
||||||
};
|
|
||||||
|
|
||||||
return str_cat(strs, COUNT(strs));
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef TCP_INFO
|
|
||||||
static socklen_t sk_get_info (int fd, struct tcp_info *ti)
|
|
||||||
{
|
|
||||||
socklen_t len = sizeof(struct tcp_info);
|
|
||||||
|
|
||||||
if (getsockopt(fd, SOL_TCP, TCP_INFO, ti, &len)==-1) {
|
|
||||||
perror("getsockopt TCP_INFO");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_tcp_info (const char *name, struct tcp_info *ti)
|
|
||||||
{
|
|
||||||
fprintf(stderr,
|
|
||||||
"%s: tcpinfo"
|
|
||||||
" rto:%" PRIu32 " ato:%" PRIu32 " snd_mss:%" PRIu32
|
|
||||||
" rcv_mss:%" PRIu32 " unacked:%" PRIu32 " sacked:%" PRIu32
|
|
||||||
" lost:%" PRIu32 " retrans:%" PRIu32 " fackets:%" PRIu32
|
|
||||||
" pmtu:%" PRIu32 " rcv_ssthresh:%" PRIu32 " rtt:%" PRIu32
|
|
||||||
" rttvar:%" PRIu32 " snd_ssthresh:%" PRIu32 " snd_cwnd:%" PRIu32
|
|
||||||
" advmss:%" PRIu32 " reordering:%" PRIu32 "\n",
|
|
||||||
name,
|
|
||||||
ti->tcpi_rto, ti->tcpi_ato, ti->tcpi_snd_mss,
|
|
||||||
ti->tcpi_rcv_mss, ti->tcpi_unacked, ti->tcpi_sacked,
|
|
||||||
ti->tcpi_lost, ti->tcpi_retrans, ti->tcpi_fackets,
|
|
||||||
ti->tcpi_pmtu, ti->tcpi_rcv_ssthresh, ti->tcpi_rtt,
|
|
||||||
ti->tcpi_rttvar, ti->tcpi_snd_ssthresh, ti->tcpi_snd_cwnd,
|
|
||||||
ti->tcpi_advmss, ti->tcpi_reordering);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static struct addrinfo *ai_create (const char *host, const char *port, int listener)
|
|
||||||
{
|
|
||||||
if (!port || !port[0]) {
|
|
||||||
fprintf(stderr, "port is not valid\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct addrinfo hints = {
|
|
||||||
.ai_family = AF_UNSPEC,
|
|
||||||
.ai_socktype = SOCK_STREAM,
|
|
||||||
.ai_protocol = IPPROTO_TCP,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (listener)
|
|
||||||
hints.ai_flags = AI_PASSIVE;
|
|
||||||
|
|
||||||
struct addrinfo *ai = NULL;
|
|
||||||
|
|
||||||
int ret = getaddrinfo(host, port, &hints, &ai);
|
|
||||||
|
|
||||||
switch (ret) {
|
|
||||||
case 0:
|
|
||||||
return ai;
|
|
||||||
case EAI_MEMORY:
|
|
||||||
errno = ENOMEM;
|
|
||||||
case EAI_SYSTEM:
|
|
||||||
perror("getaddrinfo");
|
|
||||||
break;
|
|
||||||
case EAI_FAIL:
|
|
||||||
case EAI_AGAIN:
|
|
||||||
fprintf(stderr, "the name server returned a failure\n");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "%s.%s is not valid\n", host?:"", port);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __linux__
|
|
||||||
static int tun_create (char *name, int multiqueue)
|
|
||||||
{
|
|
||||||
int fd = open("/dev/net/tun", O_RDWR);
|
|
||||||
|
|
||||||
if (fd<0) {
|
|
||||||
perror("open /dev/net/tun");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ifreq ifr = {
|
|
||||||
.ifr_flags = IFF_TUN|IFF_NO_PI,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (multiqueue) {
|
|
||||||
#ifdef IFF_MULTI_QUEUE
|
|
||||||
ifr.ifr_flags |= IFF_MULTI_QUEUE;
|
|
||||||
#else
|
|
||||||
gt_not_available("IFF_MULTI_QUEUE");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
str_cpy(ifr.ifr_name, name, IFNAMSIZ-1);
|
|
||||||
|
|
||||||
int ret = ioctl(fd, TUNSETIFF, &ifr);
|
|
||||||
|
|
||||||
if (ret<0) {
|
|
||||||
perror("ioctl TUNSETIFF");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("tun name: %s\n", ifr.ifr_name);
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static int tun_create (_unused_ char *name, _unused_ int mq)
|
|
||||||
{
|
|
||||||
for (unsigned dev_id = 0U; dev_id < 32U; dev_id++) {
|
|
||||||
char dev_path[11U];
|
|
||||||
|
|
||||||
snprintf(dev_path, sizeof(dev_path), "/dev/tun%u", dev_id);
|
|
||||||
|
|
||||||
int fd = open(dev_path, O_RDWR);
|
|
||||||
|
|
||||||
if (fd!=-1)
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void gt_sa_stop (int sig)
|
|
||||||
{
|
{
|
||||||
switch (sig) {
|
switch (sig) {
|
||||||
case SIGINT:
|
case SIGALRM:
|
||||||
case SIGTERM:
|
gt_alarm = 1;
|
||||||
running = 0;
|
return;
|
||||||
|
case SIGHUP:
|
||||||
|
gt_reload = 1; /* FALLTHRU */
|
||||||
|
default:
|
||||||
|
gt_quit = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gt_set_signal (void)
|
static void
|
||||||
|
gt_set_signal(void)
|
||||||
{
|
{
|
||||||
struct sigaction sa;
|
struct sigaction sa = {
|
||||||
|
.sa_flags = 0,
|
||||||
|
};
|
||||||
|
|
||||||
byte_set(&sa, 0, sizeof(sa));
|
sigemptyset(&sa.sa_mask);
|
||||||
running = 1;
|
|
||||||
|
|
||||||
sa.sa_handler = gt_sa_stop;
|
sa.sa_handler = gt_sa_handler;
|
||||||
sigaction(SIGINT, &sa, NULL);
|
sigaction(SIGINT, &sa, NULL);
|
||||||
|
sigaction(SIGQUIT, &sa, NULL);
|
||||||
sigaction(SIGTERM, &sa, NULL);
|
sigaction(SIGTERM, &sa, NULL);
|
||||||
|
sigaction(SIGHUP, &sa, NULL);
|
||||||
|
sigaction(SIGALRM, &sa, NULL);
|
||||||
|
|
||||||
sa.sa_handler = SIG_IGN;
|
sa.sa_handler = SIG_IGN;
|
||||||
sigaction(SIGHUP, &sa, NULL);
|
|
||||||
sigaction(SIGPIPE, &sa, NULL);
|
sigaction(SIGPIPE, &sa, NULL);
|
||||||
|
sigaction(SIGUSR1, &sa, NULL);
|
||||||
|
sigaction(SIGUSR2, &sa, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t fd_read (int fd, void *data, size_t size)
|
static int
|
||||||
|
gt_version(int argc, char **argv)
|
||||||
{
|
{
|
||||||
if (!size)
|
struct argz version_argz[] = {
|
||||||
return -2;
|
{"libsodium", NULL, NULL, argz_option},
|
||||||
|
{NULL}};
|
||||||
|
|
||||||
ssize_t ret = read(fd, data, size);
|
if (argz(version_argz, argc, argv))
|
||||||
|
|
||||||
if (ret==-1) {
|
|
||||||
if (errno==EAGAIN || errno==EINTR)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (errno)
|
|
||||||
perror("read");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t fd_write (int fd, const void *data, size_t size)
|
|
||||||
{
|
|
||||||
if (!size)
|
|
||||||
return -2;
|
|
||||||
|
|
||||||
ssize_t ret = write(fd, data, size);
|
|
||||||
|
|
||||||
if (ret==-1) {
|
|
||||||
if (errno==EAGAIN || errno==EINTR)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (errno)
|
|
||||||
perror("write");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t fd_read_all (int fd, void *data, size_t size)
|
|
||||||
{
|
|
||||||
size_t done = 0;
|
|
||||||
|
|
||||||
struct pollfd pollfd = {
|
|
||||||
.fd = fd,
|
|
||||||
.events = POLLIN,
|
|
||||||
};
|
|
||||||
|
|
||||||
while (done<size) {
|
|
||||||
ssize_t ret = fd_read(fd, data+done, size-done);
|
|
||||||
|
|
||||||
if (!ret)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (ret<0) {
|
|
||||||
if (!poll(&pollfd, 1, GT_TIMEOUT))
|
|
||||||
break;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
done += ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return done;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t fd_write_all (int fd, const void *data, size_t size)
|
|
||||||
{
|
|
||||||
size_t done = 0;
|
|
||||||
|
|
||||||
struct pollfd pollfd = {
|
|
||||||
.fd = fd,
|
|
||||||
.events = POLLOUT,
|
|
||||||
};
|
|
||||||
|
|
||||||
while (done<size) {
|
|
||||||
ssize_t ret = fd_write(fd, data+done, size-done);
|
|
||||||
|
|
||||||
if (!ret)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (ret<0) {
|
|
||||||
if (!poll(&pollfd, 1, GT_TIMEOUT))
|
|
||||||
break;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
done += ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return done;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int encrypt_packet (struct crypto_ctx *ctx, uint8_t *packet, size_t size, buffer_t *buffer)
|
|
||||||
{
|
|
||||||
const size_t ws = size + crypto_aead_aes256gcm_ABYTES;
|
|
||||||
|
|
||||||
if (buffer_write_size(buffer) < ws)
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
const int hs = 4;
|
if (argz_is_set(version_argz, "libsodium")) {
|
||||||
|
printf("%s\n", sodium_version_string());
|
||||||
byte_cpy(buffer->write, packet, size);
|
} else {
|
||||||
|
printf("%s\n", PACKAGE_VERSION);
|
||||||
crypto_aead_aes256gcm_encrypt_afternm(
|
|
||||||
buffer->write + hs, NULL,
|
|
||||||
packet + hs, size - hs,
|
|
||||||
packet, hs,
|
|
||||||
NULL, ctx->nonce_w,
|
|
||||||
(const crypto_aead_aes256gcm_state *)&ctx->state_w);
|
|
||||||
|
|
||||||
sodium_increment(ctx->nonce_w, crypto_aead_aes256gcm_NPUBBYTES);
|
|
||||||
buffer->write += ws;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int decrypt_packet (struct crypto_ctx *ctx, uint8_t *packet, size_t size, buffer_t *buffer)
|
|
||||||
{
|
|
||||||
const size_t rs = size + crypto_aead_aes256gcm_ABYTES;
|
|
||||||
|
|
||||||
if (buffer_read_size(buffer) < rs)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
const int hs = 4;
|
|
||||||
|
|
||||||
byte_cpy(packet, buffer->read, hs);
|
|
||||||
|
|
||||||
if (crypto_aead_aes256gcm_decrypt_afternm(
|
|
||||||
packet + hs, NULL,
|
|
||||||
NULL,
|
|
||||||
buffer->read + hs, rs - hs,
|
|
||||||
packet, hs,
|
|
||||||
ctx->nonce_r,
|
|
||||||
(const crypto_aead_aes256gcm_state *)&ctx->state_r))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
sodium_increment(ctx->nonce_r, crypto_aead_aes256gcm_NPUBBYTES);
|
|
||||||
buffer->read += rs;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dump_ip_header (uint8_t *data, size_t size)
|
|
||||||
{
|
|
||||||
if (size<20)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const char tbl[] = "0123456789ABCDEF";
|
|
||||||
char hex[41];
|
|
||||||
|
|
||||||
for (size_t i=0; i<20; i++) {
|
|
||||||
hex[(i<<1)+0] = tbl[0xF&(data[i]>>4)];
|
|
||||||
hex[(i<<1)+1] = tbl[0xF&(data[i])];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hex[40] = 0;
|
|
||||||
|
|
||||||
fprintf(stderr, "DUMP(%zu): %s\n", size, hex);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_ip_size (uint8_t *data, size_t size)
|
|
||||||
{
|
|
||||||
data[2] = 0xFF&(size>>8);
|
|
||||||
data[3] = 0xFF&(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t get_ip_size (const uint8_t *data, size_t size)
|
|
||||||
{
|
|
||||||
if (size<20)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if ((data[0]>>4)==4)
|
|
||||||
return (data[2]<<8)|data[3];
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gt_setup_secretkey (struct crypto_ctx *ctx, char *keyfile)
|
int
|
||||||
{
|
main(int argc, char **argv)
|
||||||
size_t size = sizeof(ctx->skey);
|
|
||||||
|
|
||||||
byte_set(ctx->skey, 1, size);
|
|
||||||
|
|
||||||
if (!keyfile)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
int fd = open(keyfile, O_RDONLY|O_CLOEXEC);
|
|
||||||
|
|
||||||
if (fd<0) {
|
|
||||||
perror("open keyfile");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fd_read_all(fd, ctx->skey, size)!=size) {
|
|
||||||
fprintf(stderr, "unable to read secret key in `%s'\n", keyfile);
|
|
||||||
close(fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: check key
|
|
||||||
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int gt_setup_crypto (struct crypto_ctx *ctx, int fd, int listener)
|
|
||||||
{
|
|
||||||
const size_t nonce_size = crypto_aead_aes256gcm_NPUBBYTES;
|
|
||||||
const size_t public_size = crypto_scalarmult_SCALARBYTES;
|
|
||||||
const size_t hkey_size = crypto_generichash_BYTES;
|
|
||||||
const size_t size = nonce_size + public_size + hkey_size;
|
|
||||||
|
|
||||||
uint8_t secret[crypto_scalarmult_SCALARBYTES];
|
|
||||||
uint8_t shared[crypto_scalarmult_BYTES];
|
|
||||||
uint8_t key[crypto_aead_aes256gcm_KEYBYTES];
|
|
||||||
|
|
||||||
uint8_t data_r[size], data_w[size];
|
|
||||||
uint8_t hkey_c[hkey_size];
|
|
||||||
|
|
||||||
randombytes_buf(data_w, nonce_size);
|
|
||||||
randombytes_buf(secret, sizeof(secret));
|
|
||||||
crypto_scalarmult_base(&data_w[nonce_size], secret);
|
|
||||||
|
|
||||||
crypto_generichash(&data_w[size-hkey_size], hkey_size,
|
|
||||||
data_w, size-hkey_size, ctx->skey, sizeof(ctx->skey));
|
|
||||||
|
|
||||||
if (!listener && fd_write_all(fd, data_w, size)!=size)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (fd_read_all(fd, data_r, size)!=size)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
crypto_generichash(hkey_c, hkey_size,
|
|
||||||
data_r, size-hkey_size, ctx->skey, sizeof(ctx->skey));
|
|
||||||
|
|
||||||
if (sodium_memcmp(&data_r[size-hkey_size], hkey_c, hkey_size))
|
|
||||||
return -2;
|
|
||||||
|
|
||||||
if (listener && fd_write_all(fd, data_w, size)!=size)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
crypto_scalarmult(shared, secret, &data_r[nonce_size]);
|
|
||||||
|
|
||||||
crypto_generichash_state state;
|
|
||||||
crypto_generichash_init(&state, ctx->skey, sizeof(ctx->skey), sizeof(key));
|
|
||||||
crypto_generichash_update(&state, shared, sizeof(shared));
|
|
||||||
crypto_generichash_update(&state, data_r, size);
|
|
||||||
crypto_generichash_update(&state, data_w, size);
|
|
||||||
crypto_generichash_final(&state, key, sizeof(key));
|
|
||||||
crypto_aead_aes256gcm_beforenm(&ctx->state_r, key);
|
|
||||||
|
|
||||||
crypto_generichash_init(&state, ctx->skey, sizeof(ctx->skey), sizeof(key));
|
|
||||||
crypto_generichash_update(&state, shared, sizeof(shared));
|
|
||||||
crypto_generichash_update(&state, data_w, size);
|
|
||||||
crypto_generichash_update(&state, data_r, size);
|
|
||||||
crypto_generichash_final(&state, key, sizeof(key));
|
|
||||||
crypto_aead_aes256gcm_beforenm(&ctx->state_w, key);
|
|
||||||
|
|
||||||
sodium_memzero(secret, sizeof(secret));
|
|
||||||
sodium_memzero(shared, sizeof(shared));
|
|
||||||
sodium_memzero(key, sizeof(key));
|
|
||||||
|
|
||||||
byte_cpy(ctx->nonce_r, data_r, nonce_size);
|
|
||||||
byte_cpy(ctx->nonce_w, data_w, nonce_size);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main (int argc, char **argv)
|
|
||||||
{
|
{
|
||||||
gt_set_signal();
|
gt_set_signal();
|
||||||
|
|
||||||
int listener = 0;
|
|
||||||
char *host = NULL;
|
|
||||||
char *port = "5000";
|
|
||||||
char *dev = PACKAGE_NAME;
|
|
||||||
char *keyfile = NULL;
|
|
||||||
char *congestion = NULL;
|
|
||||||
int delay = 0;
|
|
||||||
int multiqueue = 0;
|
|
||||||
int version = 0;
|
|
||||||
int debug = 0;
|
|
||||||
|
|
||||||
#ifdef TCP_INFO
|
|
||||||
struct {
|
struct {
|
||||||
struct timeval time;
|
char *name;
|
||||||
struct tcp_info info;
|
char *help;
|
||||||
} tcpinfo = {0};
|
int (*call)(int, char **);
|
||||||
#endif
|
} cmd[] = {
|
||||||
|
{"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},
|
||||||
|
{"keygen", "generate a new secret key", gt_keygen},
|
||||||
|
{"path", "manage paths", gt_path},
|
||||||
|
{"version", "show version", gt_version},
|
||||||
|
{NULL}};
|
||||||
|
|
||||||
struct option opts[] = {
|
if (argv[1]) {
|
||||||
{ "listener", &listener, option_flag },
|
for (int k = 0; cmd[k].name; k++) {
|
||||||
{ "host", &host, option_str },
|
if (!str_cmp(cmd[k].name, argv[1]))
|
||||||
{ "port", &port, option_str },
|
return cmd[k].call(argc - 1, argv + 1);
|
||||||
{ "dev", &dev, option_str },
|
|
||||||
{ "keyfile", &keyfile, option_str },
|
|
||||||
{ "congestion", &congestion, option_str },
|
|
||||||
{ "delay", &delay, option_flag },
|
|
||||||
{ "multiqueue", &multiqueue, option_flag },
|
|
||||||
{ "debug", &debug, option_flag },
|
|
||||||
{ "version", &version, option_flag },
|
|
||||||
{ NULL },
|
|
||||||
};
|
|
||||||
|
|
||||||
if (option(opts, argc, argv))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (version) {
|
|
||||||
printf(PACKAGE_STRING"\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sodium_init()==-1) {
|
|
||||||
fprintf(stderr, "libsodium initialization has failed!\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!crypto_aead_aes256gcm_is_available()) {
|
|
||||||
gt_not_available("AES-256-GCM");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct crypto_ctx ctx;
|
|
||||||
|
|
||||||
if (gt_setup_secretkey(&ctx, keyfile))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
struct addrinfo *ai = ai_create(host, port, listener);
|
|
||||||
|
|
||||||
if (!ai)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
struct netio tun = { .fd = -1 };
|
|
||||||
struct netio sock = { .fd = -1 };
|
|
||||||
|
|
||||||
tun.fd = tun_create(dev, multiqueue);
|
|
||||||
|
|
||||||
if (tun.fd==-1)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
fd_set_nonblock(tun.fd);
|
|
||||||
|
|
||||||
buffer_setup(&sock.write.buf, NULL, GT_BUFFER_SIZE);
|
|
||||||
buffer_setup(&sock.read.buf, NULL, GT_BUFFER_SIZE);
|
|
||||||
|
|
||||||
int fd = -1;
|
|
||||||
|
|
||||||
if (listener) {
|
|
||||||
fd = sk_create(ai, sk_listen);
|
|
||||||
|
|
||||||
if (fd==-1)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (running) {
|
|
||||||
sock.fd = listener?sk_accept(fd):sk_create(ai, sk_connect);
|
|
||||||
|
|
||||||
if (sock.fd==-1) {
|
|
||||||
usleep(100000);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char *sockname = sk_get_name(sock.fd);
|
|
||||||
|
|
||||||
if (!sockname)
|
|
||||||
goto restart;
|
|
||||||
|
|
||||||
fprintf(stderr, "%s: connected\n", sockname);
|
|
||||||
|
|
||||||
if (!delay)
|
|
||||||
sk_set_nodelay(sock.fd);
|
|
||||||
|
|
||||||
fd_set_nonblock(sock.fd);
|
|
||||||
sk_set_congestion(sock.fd, congestion);
|
|
||||||
|
|
||||||
switch (gt_setup_crypto(&ctx, sock.fd, listener)) {
|
|
||||||
case -2: fprintf(stderr, "%s: key exchange could not be verified!\n", sockname);
|
|
||||||
case -1: goto restart;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct pollfd fds[] = {
|
|
||||||
{ .fd = tun.fd, .events = POLLIN },
|
|
||||||
{ .fd = sock.fd, .events = POLLIN },
|
|
||||||
};
|
|
||||||
|
|
||||||
struct {
|
|
||||||
uint8_t buf[2048];
|
|
||||||
size_t size;
|
|
||||||
} tunr, tunw;
|
|
||||||
|
|
||||||
tunr.size = 0;
|
|
||||||
tunw.size = 0;
|
|
||||||
|
|
||||||
while (running) {
|
|
||||||
if (poll(fds, COUNT(fds), -1)==-1 && errno!=EINTR) {
|
|
||||||
perror("poll");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef TCP_INFO
|
|
||||||
struct timeval now;
|
|
||||||
gettimeofday(&now, NULL);
|
|
||||||
|
|
||||||
if (debug && dt_ms(&now, &tcpinfo.time)>1000LL) {
|
|
||||||
tcpinfo.time = now;
|
|
||||||
if (sk_get_info(sock.fd, &tcpinfo.info))
|
|
||||||
print_tcp_info(sockname, &tcpinfo.info);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
buffer_shift(&sock.write.buf);
|
|
||||||
|
|
||||||
if (fds[0].revents & POLLIN) {
|
|
||||||
while (1) {
|
|
||||||
if (buffer_write_size(&sock.write.buf)<sizeof(tunr.buf)+16)
|
|
||||||
break;
|
|
||||||
|
|
||||||
ssize_t r = fd_read(fds[0].fd, tunr.buf, sizeof(tunr.buf));
|
|
||||||
|
|
||||||
if (!r)
|
|
||||||
return 2;
|
|
||||||
|
|
||||||
if (r<0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
ssize_t ip_size = get_ip_size(tunr.buf, sizeof(tunr.buf));
|
|
||||||
|
|
||||||
if (ip_size<=0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ip_size!=r) {
|
|
||||||
dump_ip_header(tunr.buf, r);
|
|
||||||
|
|
||||||
if (r<ip_size) {
|
|
||||||
set_ip_size(tunr.buf, r);
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
encrypt_packet(&ctx, tunr.buf, r, &sock.write.buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fds[1].revents & POLLOUT)
|
|
||||||
fds[1].events = POLLIN;
|
|
||||||
|
|
||||||
if (buffer_read_size(&sock.write.buf)) {
|
|
||||||
sock.write.ret = fd_write(fds[1].fd, sock.write.buf.read, buffer_read_size(&sock.write.buf));
|
|
||||||
|
|
||||||
if (!sock.write.ret)
|
|
||||||
goto restart;
|
|
||||||
|
|
||||||
if (sock.write.ret==-1)
|
|
||||||
fds[1].events = POLLIN|POLLOUT;
|
|
||||||
|
|
||||||
if (sock.write.ret>0)
|
|
||||||
sock.write.buf.read += sock.write.ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer_shift(&sock.read.buf);
|
|
||||||
|
|
||||||
if (fds[1].revents & POLLIN) {
|
|
||||||
sock.read.ret = fd_read(fds[1].fd, sock.read.buf.write, buffer_write_size(&sock.read.buf));
|
|
||||||
|
|
||||||
if (!sock.read.ret)
|
|
||||||
goto restart;
|
|
||||||
|
|
||||||
if (sock.read.ret>0)
|
|
||||||
sock.read.buf.write += sock.read.ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fds[0].revents & POLLOUT)
|
|
||||||
fds[0].events = POLLIN;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
if (!tunw.size) {
|
|
||||||
size_t size = buffer_read_size(&sock.read.buf);
|
|
||||||
ssize_t ip_size = get_ip_size(sock.read.buf.read, size);
|
|
||||||
|
|
||||||
if (!ip_size)
|
|
||||||
goto restart;
|
|
||||||
|
|
||||||
if (ip_size<0 || (size_t)ip_size+16>size)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (decrypt_packet(&ctx, tunw.buf, ip_size, &sock.read.buf)) {
|
|
||||||
fprintf(stderr, "%s: message could not be verified!\n", sockname);
|
|
||||||
goto restart;
|
|
||||||
}
|
|
||||||
|
|
||||||
tunw.size = ip_size;
|
|
||||||
}
|
|
||||||
if (tunw.size) {
|
|
||||||
ssize_t r = fd_write(fds[0].fd, tunw.buf, tunw.size);
|
|
||||||
|
|
||||||
if (!r)
|
|
||||||
return 2;
|
|
||||||
|
|
||||||
if (r==-1)
|
|
||||||
fds[0].events = POLLIN|POLLOUT;
|
|
||||||
|
|
||||||
if (r<0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
tunw.size = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
restart:
|
|
||||||
if (sockname) {
|
|
||||||
free(sockname);
|
|
||||||
sockname = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
close(sock.fd);
|
|
||||||
sock.fd = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
freeaddrinfo(ai);
|
printf("available commands:\n\n");
|
||||||
|
|
||||||
free(sock.write.buf.data);
|
int len = 0;
|
||||||
free(sock.read.buf.data);
|
|
||||||
|
|
||||||
return 0;
|
for (int k = 0; cmd[k].name; k++)
|
||||||
|
len = MAX(len, (int)str_len(cmd[k].name, 32));
|
||||||
|
|
||||||
|
for (int k = 0; cmd[k].name; k++)
|
||||||
|
printf(" %-*s %s\n", len, cmd[k].name, cmd[k].help);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
128
src/option.c
128
src/option.c
@@ -1,128 +0,0 @@
|
|||||||
#include "common-static.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "option.h"
|
|
||||||
|
|
||||||
int option_flag (void *data, _unused_ int argc, _unused_ char **argv)
|
|
||||||
{
|
|
||||||
const int one = 1;
|
|
||||||
byte_cpy(data, &one, sizeof(one));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int option_str (void *data, int argc, char **argv)
|
|
||||||
{
|
|
||||||
if (argc<2 || !argv[1]) {
|
|
||||||
printf("option `%s' need a string argument\n", argv[0]);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte_cpy(data, &argv[1], sizeof(argv[1]));
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int option_long (void *data, int argc, char **argv)
|
|
||||||
{
|
|
||||||
if (argc<2 || !argv[1]) {
|
|
||||||
printf("option `%s' need an integer argument\n", argv[0]);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
errno = 0;
|
|
||||||
char *end;
|
|
||||||
long val = strtol(argv[1], &end, 0);
|
|
||||||
|
|
||||||
if (errno || argv[1]==end) {
|
|
||||||
printf("argument `%s' is not a valid integer\n", argv[1]);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte_cpy(data, &val, sizeof(val));
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int option_option (void *data, int argc, char **argv)
|
|
||||||
{
|
|
||||||
struct option *opts = (struct option *)data;
|
|
||||||
|
|
||||||
for (int k=0; opts[k].name; k++)
|
|
||||||
opts[k].set = 0;
|
|
||||||
|
|
||||||
for (int i=1; i<argc; i++) {
|
|
||||||
int found = 0;
|
|
||||||
|
|
||||||
for (int k=0; opts[k].name; k++) {
|
|
||||||
if (str_cmp(opts[k].name, argv[i]))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (opts[k].set) {
|
|
||||||
printf("option `%s' is already set\n", opts[k].name);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ret = opts[k].call(opts[k].data, argc-i, &argv[i]);
|
|
||||||
|
|
||||||
if (ret<0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
opts[k].set = 1;
|
|
||||||
|
|
||||||
i += ret;
|
|
||||||
found = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found)
|
|
||||||
return i-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return argc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void option_usage (struct option *opts, char *name)
|
|
||||||
{
|
|
||||||
char *usage = "usage: ";
|
|
||||||
size_t slen = str_len(usage)+str_len(name);
|
|
||||||
size_t len = slen;
|
|
||||||
|
|
||||||
printf("%s%s", usage, name);
|
|
||||||
|
|
||||||
if (slen>40)
|
|
||||||
slen = 12;
|
|
||||||
|
|
||||||
for (int k=0; opts[k].name; k++) {
|
|
||||||
char *arg = (opts[k].call==option_flag)?"":" ARG";
|
|
||||||
size_t inc = str_len(opts[k].name)+str_len(arg)+3;
|
|
||||||
|
|
||||||
if (len+inc>72) {
|
|
||||||
printf("\n%*s", (int)slen, "");
|
|
||||||
len = slen;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf(" [%s%s]", opts[k].name, arg);
|
|
||||||
len += inc;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
int option (struct option *opts, int argc, char **argv)
|
|
||||||
{
|
|
||||||
int ret = option_option(opts, argc, argv);
|
|
||||||
|
|
||||||
if (ret==argc)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (ret<0 || ret+1>=argc)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
printf("option `%s' is unknown\n", argv[ret+1]);
|
|
||||||
option_usage(opts, argv[0]);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
15
src/option.h
15
src/option.h
@@ -1,15 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
struct option {
|
|
||||||
char *name;
|
|
||||||
void *data;
|
|
||||||
int (*call) (void *, int, char **);
|
|
||||||
int set;
|
|
||||||
};
|
|
||||||
|
|
||||||
int option_flag (void *, int, char **);
|
|
||||||
int option_str (void *, int, char **);
|
|
||||||
int option_long (void *, int, char **);
|
|
||||||
int option_option (void *, int, char **);
|
|
||||||
|
|
||||||
int option (struct option *, int, char **);
|
|
||||||
215
src/path.c
Normal file
215
src/path.c
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "ctl.h"
|
||||||
|
#include "str.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <unistd.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
|
||||||
|
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 = {
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
gt_path(int argc, char **argv)
|
||||||
|
{
|
||||||
|
const char *dev = NULL;
|
||||||
|
|
||||||
|
struct ctl_msg req = {
|
||||||
|
.type = CTL_STATE,
|
||||||
|
.path = {
|
||||||
|
.state = MUD_EMPTY,
|
||||||
|
},
|
||||||
|
}, res = {0};
|
||||||
|
|
||||||
|
struct argz ratez[] = {
|
||||||
|
{"tx", "BYTES/SEC", &req.path.rate_tx, argz_bytes},
|
||||||
|
{"rx", "BYTES/SEC", &req.path.rate_rx, argz_bytes},
|
||||||
|
{NULL}};
|
||||||
|
|
||||||
|
struct argz pathz[] = {
|
||||||
|
{NULL, "IPADDR", &req.path.addr, argz_addr},
|
||||||
|
{"dev", "NAME", &dev, argz_str},
|
||||||
|
{"up|backup|down", NULL, NULL, argz_option},
|
||||||
|
{"rate", NULL, &ratez, argz_option},
|
||||||
|
{NULL}};
|
||||||
|
|
||||||
|
if (argz(pathz, argc, argv))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
int fd = ctl_connect(GT_RUNDIR, dev);
|
||||||
|
|
||||||
|
if (fd < 0) {
|
||||||
|
switch (fd) {
|
||||||
|
case -1:
|
||||||
|
perror("path");
|
||||||
|
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 set_rate = argz_is_set(pathz, "rate");
|
||||||
|
|
||||||
|
if (set_rate && !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;
|
||||||
|
} 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 {
|
||||||
|
ret = ctl_reply(fd, &res, &req);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == -1)
|
||||||
|
perror("path");
|
||||||
|
|
||||||
|
ctl_delete(fd);
|
||||||
|
|
||||||
|
return !!ret;
|
||||||
|
}
|
||||||
166
src/set.c
Normal file
166
src/set.c
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "ctl.h"
|
||||||
|
#include "str.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
if (argc < 1 || !argv[0])
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int val = 0;
|
||||||
|
const char *s = argv[0];
|
||||||
|
|
||||||
|
if ((s[0] == 'C') && (s[1] == 'S') &&
|
||||||
|
(s[2] >= '0') && (s[2] <= '7') && !s[3]) {
|
||||||
|
val = (s[2] - '0') << 3;
|
||||||
|
} else if ((s[0] == 'A') && (s[1] == 'F') &&
|
||||||
|
(s[2] >= '1') && (s[2] <= '4') &&
|
||||||
|
(s[3] >= '1') && (s[3] <= '3') && !s[4]) {
|
||||||
|
val = ((s[2] - '0') << 3) | ((s[3] - '0') << 1);
|
||||||
|
} else if ((s[0] == 'E') && (s[1] == 'F') && !s[2]) {
|
||||||
|
val = 46;
|
||||||
|
} else return -1;
|
||||||
|
|
||||||
|
if (data)
|
||||||
|
*(int *)data = val;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
gt_set(int argc, char **argv)
|
||||||
|
{
|
||||||
|
const char *dev = NULL;
|
||||||
|
size_t mtu;
|
||||||
|
int tc;
|
||||||
|
unsigned long kxtimeout;
|
||||||
|
unsigned long timetolerance;
|
||||||
|
|
||||||
|
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},
|
||||||
|
{NULL}};
|
||||||
|
|
||||||
|
if (argz(pathz, argc, argv))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
int fd = ctl_connect(GT_RUNDIR, dev);
|
||||||
|
|
||||||
|
if (fd < 0) {
|
||||||
|
switch (fd) {
|
||||||
|
case -1:
|
||||||
|
perror("set");
|
||||||
|
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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
ctl_delete(fd);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
117
src/show.c
Normal file
117
src/show.c
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "ctl.h"
|
||||||
|
#include "str.h"
|
||||||
|
|
||||||
|
#include "../argz/argz.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
static int
|
||||||
|
gt_show_status(int fd)
|
||||||
|
{
|
||||||
|
struct ctl_msg res, req = {.type = CTL_STATUS};
|
||||||
|
|
||||||
|
if (ctl_reply(fd, &res, &req))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
char bindstr[INET6_ADDRSTRLEN];
|
||||||
|
char peerstr[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
|
gt_toaddr(bindstr, sizeof(bindstr),
|
||||||
|
(struct sockaddr *)&res.status.bind);
|
||||||
|
|
||||||
|
int server = gt_toaddr(peerstr, sizeof(peerstr),
|
||||||
|
(struct sockaddr *)&res.status.peer);
|
||||||
|
|
||||||
|
int term = isatty(1);
|
||||||
|
|
||||||
|
if (server) {
|
||||||
|
printf(term ? "server %s:\n"
|
||||||
|
" pid: %li\n"
|
||||||
|
" bind: %s port %"PRIu16"\n"
|
||||||
|
" mtu: %zu\n"
|
||||||
|
" cipher: %s\n"
|
||||||
|
: "server %s"
|
||||||
|
" %li"
|
||||||
|
" %s %"PRIu16
|
||||||
|
" %zu"
|
||||||
|
" %s"
|
||||||
|
"\n",
|
||||||
|
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");
|
||||||
|
} else {
|
||||||
|
printf(term ? "client %s:\n"
|
||||||
|
" pid: %li\n"
|
||||||
|
" bind: %s port %"PRIu16"\n"
|
||||||
|
" peer: %s port %"PRIu16"\n"
|
||||||
|
" mtu: %zu\n"
|
||||||
|
" cipher: %s\n"
|
||||||
|
: "client %s"
|
||||||
|
" %li"
|
||||||
|
" %s %"PRIu16
|
||||||
|
" %s %"PRIu16
|
||||||
|
" %zu"
|
||||||
|
" %s"
|
||||||
|
"\n",
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
gt_show(int argc, char **argv)
|
||||||
|
{
|
||||||
|
const char *dev = NULL;
|
||||||
|
|
||||||
|
struct argz showz[] = {
|
||||||
|
{"dev", "NAME", &dev, argz_str},
|
||||||
|
{NULL}};
|
||||||
|
|
||||||
|
if (argz(showz, argc, argv))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
int fd = ctl_connect(GT_RUNDIR, dev);
|
||||||
|
|
||||||
|
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 = gt_show_status(fd);
|
||||||
|
|
||||||
|
if (ret == -1)
|
||||||
|
perror("show");
|
||||||
|
|
||||||
|
ctl_delete(fd);
|
||||||
|
|
||||||
|
return !!ret;
|
||||||
|
}
|
||||||
33
src/str.h
Normal file
33
src/str.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
_pure_ static inline int
|
||||||
|
str_empty(const char *restrict str)
|
||||||
|
{
|
||||||
|
return !str || !str[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
_pure_ static inline size_t
|
||||||
|
str_cmp(const char *restrict sa, const char *restrict sb)
|
||||||
|
{
|
||||||
|
if (!sa || !sb)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
while (sa[i] == sb[i])
|
||||||
|
if (!sa[i++])
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_pure_ static inline size_t
|
||||||
|
str_len(const char *restrict str, size_t len)
|
||||||
|
{
|
||||||
|
if (!str)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return strnlen(str, len);
|
||||||
|
}
|
||||||
266
src/tun.c
Normal file
266
src/tun.c
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "ip.h"
|
||||||
|
#include "str.h"
|
||||||
|
#include "tun.h"
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
#define IFF_TUN 0x0001
|
||||||
|
#define IFF_NO_PI 0x1000
|
||||||
|
#define TUNSETIFF _IOW('T', 202, int)
|
||||||
|
#define TUNSETPERSIST _IOW('T', 203, int)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <net/if_utun.h>
|
||||||
|
#include <sys/kern_control.h>
|
||||||
|
#include <sys/sys_domain.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__APPLE__) || defined(__OpenBSD__)
|
||||||
|
#define GT_BSD_TUN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
|
||||||
|
static int
|
||||||
|
tun_create_by_id(char *name, size_t len, unsigned id)
|
||||||
|
{
|
||||||
|
int ret = snprintf(name, len, "utun%u", id);
|
||||||
|
|
||||||
|
if (ret <= 0 || (size_t)ret >= len) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
|
||||||
|
|
||||||
|
if (fd == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
struct ctl_info ci = {
|
||||||
|
.ctl_name = UTUN_CONTROL_NAME,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (ioctl(fd, CTLIOCGINFO, &ci)) {
|
||||||
|
int err = errno;
|
||||||
|
close(fd);
|
||||||
|
errno = err;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_ctl sc = {
|
||||||
|
.sc_id = ci.ctl_id,
|
||||||
|
.sc_len = sizeof(sc),
|
||||||
|
.sc_family = AF_SYSTEM,
|
||||||
|
.ss_sysaddr = AF_SYS_CONTROL,
|
||||||
|
.sc_unit = id + 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (connect(fd, (struct sockaddr *)&sc, sizeof(sc))) {
|
||||||
|
int err = errno;
|
||||||
|
close(fd);
|
||||||
|
errno = err;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
tun_create_by_name(char *name, size_t len, const char *dev_name)
|
||||||
|
{
|
||||||
|
unsigned id = 0;
|
||||||
|
|
||||||
|
if (sscanf(dev_name, "utun%u", &id) != 1) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tun_create_by_id(name, len, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* not __APPLE__ */
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
|
||||||
|
static int
|
||||||
|
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 = {
|
||||||
|
.ifr_flags = IFF_TUN | IFF_NO_PI,
|
||||||
|
};
|
||||||
|
|
||||||
|
ret = snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", dev_name);
|
||||||
|
|
||||||
|
if (ret <= 0 || (size_t)ret >= sizeof(ifr.ifr_name)) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd = open("/dev/net/tun", O_RDWR);
|
||||||
|
|
||||||
|
if (fd == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (ioctl(fd, TUNSETIFF, &ifr)) {
|
||||||
|
int err = errno;
|
||||||
|
close(fd);
|
||||||
|
errno = err;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* not __linux__ not __APPLE__ */
|
||||||
|
|
||||||
|
static int
|
||||||
|
tun_create_by_name(char *name, size_t len, const char *dev_name)
|
||||||
|
{
|
||||||
|
int ret = snprintf(name, len, "/dev/%s", dev_name);
|
||||||
|
|
||||||
|
if (ret <= 0 || (size_t)ret >= len) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return open(tmp, O_RDWR);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* not __APPLE__ */
|
||||||
|
|
||||||
|
static int
|
||||||
|
tun_create_by_id(char *name, size_t len, unsigned id)
|
||||||
|
{
|
||||||
|
char tmp[64];
|
||||||
|
int ret = snprintf(tmp, sizeof(tmp), "tun%u", id);
|
||||||
|
|
||||||
|
if (ret <= 0 || (size_t)ret >= sizeof(tmp)) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tun_create_by_name(name, len, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int
|
||||||
|
tun_create(char *name, size_t len, const char *dev_name)
|
||||||
|
{
|
||||||
|
int fd = -1;
|
||||||
|
|
||||||
|
if (str_empty(dev_name)) {
|
||||||
|
for (unsigned id = 0; id < 32 && fd == -1; id++)
|
||||||
|
fd = tun_create_by_id(name, len, id);
|
||||||
|
} else {
|
||||||
|
fd = tun_create_by_name(name, len, dev_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
tun_read(int fd, void *data, size_t size)
|
||||||
|
{
|
||||||
|
if (!size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#ifdef GT_BSD_TUN
|
||||||
|
uint32_t family;
|
||||||
|
|
||||||
|
struct iovec iov[2] = {
|
||||||
|
{
|
||||||
|
.iov_base = &family,
|
||||||
|
.iov_len = sizeof(family),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.iov_base = data,
|
||||||
|
.iov_len = size,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
int ret = (int)readv(fd, iov, 2);
|
||||||
|
|
||||||
|
if (ret <= 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if ((size_t)ret <= sizeof(family))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return ret - (int)sizeof(family);
|
||||||
|
#else
|
||||||
|
return (int)read(fd, data, size);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
tun_write(int fd, const void *data, size_t size)
|
||||||
|
{
|
||||||
|
if (!size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#ifdef GT_BSD_TUN
|
||||||
|
uint32_t family;
|
||||||
|
|
||||||
|
switch (ip_get_version(data, (int)size)) {
|
||||||
|
case 4:
|
||||||
|
family = htonl(AF_INET);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
family = htonl(AF_INET6);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct iovec iov[2] = {
|
||||||
|
{
|
||||||
|
.iov_base = &family,
|
||||||
|
.iov_len = sizeof(family),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.iov_base = (void *)data,
|
||||||
|
.iov_len = size,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
int ret = (int)writev(fd, iov, 2);
|
||||||
|
|
||||||
|
if (ret <= 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if ((size_t)ret <= sizeof(family))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return ret - (int)sizeof(family);
|
||||||
|
#else
|
||||||
|
return (int)write(fd, data, size);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
tun_set_persist(int fd, int on)
|
||||||
|
{
|
||||||
|
#ifdef TUNSETPERSIST
|
||||||
|
return ioctl(fd, TUNSETPERSIST, on);
|
||||||
|
#else
|
||||||
|
errno = ENOSYS;
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
6
src/tun.h
Normal file
6
src/tun.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
int tun_create (char *, size_t, const char *);
|
||||||
|
int tun_read (int, void *, size_t);
|
||||||
|
int tun_write (int, const void *, size_t);
|
||||||
|
int tun_set_persist (int, int);
|
||||||
10
systemd/glorytun-client.network
Normal file
10
systemd/glorytun-client.network
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[Match]
|
||||||
|
Name=gtc-*
|
||||||
|
|
||||||
|
[Network]
|
||||||
|
Description=Glorytun client device
|
||||||
|
DHCP=ipv4
|
||||||
|
|
||||||
|
[DHCP]
|
||||||
|
CriticalConnection=yes
|
||||||
|
RouteTable=200
|
||||||
6
systemd/glorytun-run
Executable file
6
systemd/glorytun-run
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
exec glorytun bind "$@" \
|
||||||
|
$BIND $BIND_PORT \
|
||||||
|
${DEV:+dev "$DEV"} \
|
||||||
|
${HOST:+to "$HOST" "$PORT"}
|
||||||
75
systemd/glorytun-setup
Executable file
75
systemd/glorytun-setup
Executable file
@@ -0,0 +1,75 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
_ask() {
|
||||||
|
printf "%s: " "$1"
|
||||||
|
read -r "$2"
|
||||||
|
}
|
||||||
|
|
||||||
|
_ask "Config filename (tun0)" NAME
|
||||||
|
NAME=${NAME:-tun0}
|
||||||
|
DIR="/etc/glorytun/$NAME"
|
||||||
|
|
||||||
|
if [ -d "$DIR" ]; then
|
||||||
|
echo "This config already exit!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_ask "Server ip (enter for server conf)" HOST
|
||||||
|
if [ -z "$HOST" ]; then
|
||||||
|
_ask "Bind to port (5000)" BIND_PORT
|
||||||
|
BIND_PORT=${BIND_PORT:-5000}
|
||||||
|
else
|
||||||
|
_ask "Server port (5000)" PORT
|
||||||
|
PORT=${PORT:-5000}
|
||||||
|
fi
|
||||||
|
|
||||||
|
BIND=0.0.0.0
|
||||||
|
case "$HOST" in
|
||||||
|
*:*) BIND=::
|
||||||
|
esac
|
||||||
|
|
||||||
|
_ask "Server key (enter to generate a new one)" KEY
|
||||||
|
if [ -z "$KEY" ]; then
|
||||||
|
KEY=$(glorytun keygen)
|
||||||
|
echo "Your new key: $KEY"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# install files
|
||||||
|
mkdir -p "$DIR"
|
||||||
|
|
||||||
|
cat > "$DIR/env" <<EOF
|
||||||
|
DEV=gt${HOST:+c}-$NAME
|
||||||
|
HOST=$HOST
|
||||||
|
PORT=$PORT
|
||||||
|
BIND=$BIND
|
||||||
|
BIND_PORT=$BIND_PORT
|
||||||
|
OPTIONS=
|
||||||
|
EOF
|
||||||
|
|
||||||
|
( umask 077; echo "$KEY" > "$DIR/key" )
|
||||||
|
|
||||||
|
[ "$HOST" ] && cat > "$DIR/post.sh" <<'EOF'
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
PREF=32765
|
||||||
|
TABLE=200
|
||||||
|
|
||||||
|
# keep the current route to HOST
|
||||||
|
SRC=$(ip route get "$HOST" | awk '/src/{getline;print $0}' RS=' ')
|
||||||
|
ip rule add from "$SRC" table main pref "$((PREF-1))" || true
|
||||||
|
|
||||||
|
# limit to 100Mbit by default
|
||||||
|
glorytun path up "$SRC" dev "$DEV" rate rx 12500000 tx 12500000
|
||||||
|
|
||||||
|
# forward everything else to the tunnel
|
||||||
|
ip rule add from all table "$TABLE" pref "$PREF" || true
|
||||||
|
EOF
|
||||||
|
[ -f "$DIR/post.sh" ] && chmod u+x "$DIR/post.sh"
|
||||||
|
|
||||||
|
# start services
|
||||||
|
_ask "Start glorytun now ? (enter to skip)" START
|
||||||
|
case "$START" in y*|Y*)
|
||||||
|
systemctl start glorytun@"$NAME" ;;
|
||||||
|
esac
|
||||||
14
systemd/glorytun.network
Normal file
14
systemd/glorytun.network
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[Match]
|
||||||
|
Name=gt-*
|
||||||
|
|
||||||
|
[Network]
|
||||||
|
Description=Glorytun server device
|
||||||
|
Address=0.0.0.0/24
|
||||||
|
DHCPServer=yes
|
||||||
|
IPMasquerade=yes
|
||||||
|
|
||||||
|
[DHCPServer]
|
||||||
|
PoolOffset=2
|
||||||
|
PoolSize=1
|
||||||
|
EmitDNS=yes
|
||||||
|
DNS=9.9.9.9
|
||||||
14
systemd/glorytun@.service.in
Normal file
14
systemd/glorytun@.service.in
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Glorytun on %I
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
EnvironmentFile=/etc/glorytun/%i/env
|
||||||
|
ExecStart=@bindir@/glorytun-run keyfile /etc/glorytun/%i/key $OPTIONS
|
||||||
|
ExecStartPost=-/etc/glorytun/%i/post.sh
|
||||||
|
CapabilityBoundingSet=CAP_NET_ADMIN
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
15
version.sh
Executable file
15
version.sh
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
export GIT_DIR=.git
|
||||||
|
export GIT_WORK_TREE=.
|
||||||
|
|
||||||
|
[ -z "$VERSION" ] && VERSION="$(git describe --tags --match='v[0-9].*' 2>/dev/null)" \
|
||||||
|
&& VERSION="${VERSION#v}"
|
||||||
|
|
||||||
|
[ -z "$VERSION" ] && VERSION="$(git rev-parse HEAD 2>/dev/null)"
|
||||||
|
|
||||||
|
[ -z "$VERSION" ] && VERSION="$(cat VERSION 2>/dev/null)"
|
||||||
|
|
||||||
|
[ -z "$VERSION" ] && VERSION="0.0.0"
|
||||||
|
|
||||||
|
printf "%s" "$VERSION" | tee VERSION
|
||||||
Reference in New Issue
Block a user