Compare commits

...

61 Commits

Author SHA1 Message Date
angt
30502e05ec Print state info in stdout if no statefile 2016-01-06 18:41:39 +01:00
angt
905673ecec Add timeout option 2016-01-06 18:33:59 +01:00
angt
cfbb77c710 Code cleanup 2016-01-06 17:57:12 +01:00
angt
13dcdc5afb Reduce GT_BUFFER_SIZE 2016-01-06 16:03:42 +01:00
angt
56ec81bf92 Fix last commit 2016-01-06 12:15:28 +01:00
angt
f1024381e0 Remove old code from qos 2016-01-06 11:29:13 +01:00
angt
3f3b21f08d Update Makefile.am 2016-01-05 14:16:30 +01:00
angt
40dd5ce18a Code cleanup 2016-01-05 14:07:18 +01:00
angt
5efb379251 Remove byte_*() as we don't use freestanding anymore 2016-01-05 12:26:38 +01:00
angt
2eb6521f9c Add a simple tcp tracker in debug mode 2016-01-05 08:24:03 +01:00
angt
bfd81e9666 Code cleanup 2016-01-04 20:07:11 +01:00
angt
8fa2322314 Add VERSION in the tarball 2016-01-01 12:32:20 +01:00
angt
8982f27220 Update LICENSE 2016-01-01 11:47:17 +01:00
angt
a5f97fcc8c States need EOL 2016-01-01 11:00:29 +01:00
angt
35a9bf27df Add state INITIALIZED 2015-12-31 16:07:36 +01:00
angt
ba0af8cc20 Define VERSION_MAJOR and use it in handshake 2015-12-29 18:31:23 +01:00
angt
ec85be5c6a Code cleanup 2015-12-29 12:59:55 +01:00
angt
fe989851ab Print more debug info 2015-12-29 12:58:39 +01:00
angt
46842dd200 Write state after the close() 2015-12-28 07:18:00 +01:00
angt
e5eb30598d Code cleanup 2015-12-24 17:38:08 +01:00
angt
c81ad0a7c6 One more time 2015-12-24 17:35:01 +01:00
angt
97641d6dda Reserve exclam for very bad message 2015-12-24 17:32:32 +01:00
angt
e48dac775c The statefile option needs an absolute path and a fifo 2015-12-24 17:29:41 +01:00
angt
6282f36ac7 Add statefile option 2015-12-24 16:53:50 +01:00
angt
cf022af4a9 Simplify the db by merging size and mask 2015-12-24 13:13:43 +01:00
angt
597c586657 Don't free data in db_remove() 2015-12-23 22:26:53 +01:00
angt
fc7f9aa0c8 Add a very simple low cost database 2015-12-23 17:11:20 +01:00
angt
7492f977b6 Define a simple proto 2015-12-21 12:34:24 +01:00
angt
38b7333533 Refuse to start the client without keyfile 2015-12-18 16:07:14 +01:00
angt
1ab854f058 Code cleanup 2015-12-18 11:57:20 +01:00
angt
c59def90fb Try to use SO_ACCEPTFILTER to defer accept on non-linux platforms 2015-12-17 23:20:31 +01:00
angt
347a3ecce7 Try to open tunX instead of glorytun by default in Linux 2015-12-17 17:06:04 +01:00
angt
98d13ef510 Print the tun name, not the path 2015-12-17 17:01:31 +01:00
angt
35b95001c4 Warn only when tun_create() fail 2015-12-17 14:07:14 +01:00
angt
75c12b36d6 Code cleanup 2015-12-17 13:59:40 +01:00
angt
db01c8b33f Update README.md 2015-12-17 08:51:07 +01:00
angt
fb4f6f6cb9 Do the md5sum after deploy 2015-12-16 11:27:53 +01:00
angt
a86aea431d Let travis do the md5sum 2015-12-16 08:35:20 +01:00
angt
1a128a6d92 Print readable ip in debug mode 2015-12-15 17:32:03 +01:00
angt
ddae22a3d9 Use a new random secret key without keyfile 2015-12-15 09:07:44 +01:00
angt
893de45272 Accept lower-case in fromhex() 2015-12-15 08:28:10 +01:00
angt
78ba4c9a59 Do not call ip_get_version() again and again 2015-12-14 18:37:50 +01:00
angt
ffa549e444 Fix and cleanup gt_{from,to}hex 2015-12-13 11:26:58 +01:00
angt
6040f17e1c Code cleanup 2015-12-13 11:07:55 +01:00
angt
da30c9110a Do not ask too much to macosx 2015-12-12 13:30:27 +01:00
angt
05de7b8109 Show udp hdr too in debug mode 2015-12-12 13:18:56 +01:00
angt
7cc6d08d7a Use __FAVOR_BSD... 2015-12-12 13:07:51 +01:00
angt
d526a3cfa5 Fix retry when kx fails 2015-12-12 12:19:09 +01:00
angt
0e319b068d Listener should retry accept() by default 2015-12-12 11:05:58 +01:00
angt
c82026cfd7 Update README.md 2015-12-11 17:44:16 +01:00
angt
109f70c208 Secret key must be stored in upper-case hex now 2015-12-11 17:33:35 +01:00
angt
23cdc37ea8 Add gt_tohex() and gt_fromhex() 2015-12-11 16:33:45 +01:00
angt
7688209093 Show tcp hdr in debug 2015-12-11 11:32:22 +01:00
angt
52a3a4b853 Add debug option to show ip_proto 2015-12-10 15:28:45 +01:00
angt
4cf0e7bc68 Function dt_ms() is pure too 2015-12-10 13:19:24 +01:00
angt
f36fde5054 Add ip_get_proto() 2015-12-10 13:17:27 +01:00
angt
e08eb73f98 Remove TCP_INFO 2015-12-10 12:33:54 +01:00
angt
f3143eff83 Do not print error for EPIPE or ECONNRESET on write() 2015-12-09 20:38:49 +01:00
angt
ea1fa120eb Allow IPv6 2015-12-09 20:27:40 +01:00
angt
be29a12842 Deploy only on linux-gcc 2015-12-09 11:25:51 +01:00
angt
113f1ae58d Use file_glob in travis 2015-12-08 18:27:59 +01:00
18 changed files with 997 additions and 492 deletions

View File

@@ -24,7 +24,12 @@ deploy:
api_key: api_key:
secure: Ira1jd3j+17QVFbJ7KlkytTNp0oMZLTqCWPQLxNHLEt32PVY/IPs/16BcvTbFpKrY+Ma7E3KCihfufTVG8T+jRlZ5hFO7HNpoQMgi7L7yZZAGScYO5pnMQvsr8O9hf7jzSi1DjFXgFHznbPJJ3lOSwegcqzSrbZflokiCR50GTLLWewHoPpfs+1gJ5XbtVyRhZlmXhMPC0NEH2sh33X2WdUiKUJUMOnlYC0atPBL+4n12qxnugF9YA9wPK5NHJSLiPHue7I2rHlSrOLX5NkN3vqnEvusiuIFQX1y0NuKtkpOscFD9n1CLHThGLuzMvPlwpdQfzRMVxwjYFGu6Ma5alf64ksFnMKl8Oo0yCXEA7WvHXz+qUai/a1gzYZLTGuasHtjrHN/mgKxM4QRSiHo8t5hj3CczUW+OFglytawZQyGjyUUiKdwx2kvlO96RVDIYEhUD4DeHzHR8rhvDLmlMlGAWqUPXq7d4D+bExqKmqWCCSkhrbubq5B1kChRmgw7/gly4SryqGy+R0xsC4oq9jUUxd7Sl801BIKcYDb5r5gFSw+hEhOzBb+uE2xJYFNO2KZ+eG69lkFeG3oNJMTy8afs8fRRUXq0poQJ39wFWerps3Md7h8Sxs61YLIAKHvLJJMfoMI+AORTcjnnpqujMhgWGWt8wLhJZdxaSycoQkU= secure: Ira1jd3j+17QVFbJ7KlkytTNp0oMZLTqCWPQLxNHLEt32PVY/IPs/16BcvTbFpKrY+Ma7E3KCihfufTVG8T+jRlZ5hFO7HNpoQMgi7L7yZZAGScYO5pnMQvsr8O9hf7jzSi1DjFXgFHznbPJJ3lOSwegcqzSrbZflokiCR50GTLLWewHoPpfs+1gJ5XbtVyRhZlmXhMPC0NEH2sh33X2WdUiKUJUMOnlYC0atPBL+4n12qxnugF9YA9wPK5NHJSLiPHue7I2rHlSrOLX5NkN3vqnEvusiuIFQX1y0NuKtkpOscFD9n1CLHThGLuzMvPlwpdQfzRMVxwjYFGu6Ma5alf64ksFnMKl8Oo0yCXEA7WvHXz+qUai/a1gzYZLTGuasHtjrHN/mgKxM4QRSiHo8t5hj3CczUW+OFglytawZQyGjyUUiKdwx2kvlO96RVDIYEhUD4DeHzHR8rhvDLmlMlGAWqUPXq7d4D+bExqKmqWCCSkhrbubq5B1kChRmgw7/gly4SryqGy+R0xsC4oq9jUUxd7Sl801BIKcYDb5r5gFSw+hEhOzBb+uE2xJYFNO2KZ+eG69lkFeG3oNJMTy8afs8fRRUXq0poQJ39wFWerps3Md7h8Sxs61YLIAKHvLJJMfoMI+AORTcjnnpqujMhgWGWt8wLhJZdxaSycoQkU=
skip_cleanup: true skip_cleanup: true
file: "glorytun-*.tar.gz" file_glob: true
file: glorytun-*.tar.gz
on: on:
tags: true tags: true
repo: angt/glorytun repo: angt/glorytun
condition: "${TRAVIS_OS_NAME}-${CC} == linux-gcc"
after_deploy:
- md5sum glorytun-*.tar.gz

View File

@@ -1,4 +1,4 @@
Copyright (c) 2015, angt Copyright (c) 2015-2016, angt
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

View File

@@ -6,17 +6,21 @@ glorytun_CFLAGS = $(libsodium_CFLAGS)
glorytun_LDADD = $(libsodium_LIBS) glorytun_LDADD = $(libsodium_LIBS)
glorytun_SOURCES = \ glorytun_SOURCES = \
src/common.h \ src/common.h \
src/common-static.h \
src/common.c \ src/common.c \
src/ip-static.h \ src/buffer.h \
src/ip.h \
src/str.h \
src/main.c \ src/main.c \
src/option.c \ src/option.c \
src/option.h \ src/option.h \
src/tun.c \ src/tun.c \
src/tun.h src/tun.h \
src/db.c \
src/db.h
EXTRA_DIST = \ EXTRA_DIST = \
LICENSE \ LICENSE \
README.md \ README.md \
autogen.sh \ VERSION \
version.sh autogen.sh \
version.sh

View File

@@ -1,8 +1,12 @@
# Glorytun # Glorytun
Small, Simple and Stupid **TCP** VPN. Small, Simple and Stupid TCP VPN.
**Work In Progress:** Do not touch! This code will probably format your harddisk! #### Work In Progress
This code will probably format your harddisk!
#### Build and Install
Glorytun depends on [libsodium](https://github.com/jedisct1/libsodium) version >= 1.0.4 Glorytun depends on [libsodium](https://github.com/jedisct1/libsodium) version >= 1.0.4
and needs an AES-NI capable CPU. and needs an AES-NI capable CPU.
@@ -16,7 +20,4 @@ To build and install the latest version:
$ make $ make
# make install # make install
To create and use a new secret key: For feature requests and bug reports, please create an [issue](https://github.com/angt/glorytun/issues).
$ dd if=/dev/urandom of=glorytun.key bs=32 count=1
# glorytun keyfile glorytun.key [...]

View File

@@ -4,6 +4,7 @@ AC_INIT([glorytun],
[https://github.com/angt/glorytun/issues], [https://github.com/angt/glorytun/issues],
[glorytun], [glorytun],
[https://github.com/angt/glorytun]) [https://github.com/angt/glorytun])
AC_DEFINE_UNQUOTED([VERSION_MAJOR], [m4_esyscmd([./version.sh major])])
AC_CONFIG_SRCDIR([src/common.h]) AC_CONFIG_SRCDIR([src/common.h])
AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])

63
src/buffer.h Normal file
View File

@@ -0,0 +1,63 @@
#pragma once
#include "common.h"
typedef struct buffer buffer_t;
struct buffer {
uint8_t *data;
uint8_t *read;
uint8_t *write;
uint8_t *end;
};
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;
}
_pure_
static inline size_t buffer_size (buffer_t *buffer)
{
return buffer->end-buffer->data;
}
_pure_
static inline size_t buffer_write_size (buffer_t *buffer)
{
return buffer->end-buffer->write;
}
_pure_
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) {
memcpy(buffer->data, src, size);
buffer->read -= src-buffer->data;
buffer->write -= src-buffer->data;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -36,5 +36,61 @@ void gt_fatal (const char *fmt, ...)
void gt_na (const char *name) void gt_na (const char *name)
{ {
gt_log("%s is not available on your platform!\n", name); gt_log("%s is not available on your platform\n", name);
}
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++ = (a<<4)|b;
}
return 0;
} }

View File

@@ -2,8 +2,11 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#define COUNT(x) (sizeof(x)/sizeof(x[0])) #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)
@@ -17,21 +20,19 @@
#define _1_(x) (__builtin_expect((x), 1)) #define _1_(x) (__builtin_expect((x), 1))
#define _0_(x) (__builtin_expect((x), 0)) #define _0_(x) (__builtin_expect((x), 0))
#define _printf_(A,B) __attribute__((format(printf,A,B))) #define CLZ(x) (__builtin_clz(x))
#define _noreturn_ __attribute__((noreturn))
#define _unused_ __attribute__((unused))
#define _align_(...) __attribute__((aligned(__VA_ARGS__)))
typedef struct buffer buffer_t; #define _printf_(A,B) __attribute__ ((format(printf,A,B)))
#define _noreturn_ __attribute__ ((noreturn))
struct buffer { #define _unused_ __attribute__ ((unused))
uint8_t *data; #define _pure_ __attribute__ ((pure))
uint8_t *read; #define _const_ __attribute__ ((const))
uint8_t *write; #define _align_(...) __attribute__ ((aligned(__VA_ARGS__)))
uint8_t *end;
};
int gt_print (const char *, ...) _printf_(1,2); int gt_print (const char *, ...) _printf_(1,2);
void gt_log (const char *, ...) _printf_(1,2); void gt_log (const char *, ...) _printf_(1,2);
void gt_fatal (const char *, ...) _printf_(1,2) _noreturn_; void gt_fatal (const char *, ...) _printf_(1,2) _noreturn_;
void gt_na (const char *); void gt_na (const char *);
int gt_tohex (char *, size_t, const uint8_t *, size_t);
int gt_fromhex (uint8_t *, size_t, const char *, size_t);

155
src/db.c Normal file
View File

@@ -0,0 +1,155 @@
#include "common.h"
#include "db.h"
#include "str.h"
#define CBIT(X) (1&(intptr_t)(X))
#define CBIT_PTR(X) (uint8_t *)(1|(intptr_t)(X))
#define CBIT_NODE(X) (struct node *)(1^(intptr_t)(X))
struct node {
uint8_t *child[2];
uint32_t point;
};
_pure_
static inline size_t db_size (const uint8_t *a)
{
return (a[0]?:str_len((char *)a+1))+1;
}
_pure_
static inline size_t db_cmp (const uint8_t *a, const uint8_t *b)
{
const size_t size = a[0];
if (size!=b[0])
return 1;
if (!size) {
size_t i = str_cmp((char *)a+1, (char *)b+1);
return i?i+1:0;
}
for (size_t i=1; i<=size; i++) {
if (a[i]!=b[i])
return i+1;
}
return 0;
}
_pure_
static inline int db_dir (const uint32_t point, uint8_t *data, const size_t size)
{
const size_t pos = point>>8;
if (pos>=size)
return 0;
return ((point|data[pos])&255)==255;
}
uint8_t *db_search (uint8_t **p, uint8_t *data)
{
if _0_(!*p)
return NULL;
uint8_t *r = *p;
const size_t size = db_size(data);
while (CBIT(r)) {
struct node *node = CBIT_NODE(r);
r = node->child[db_dir(node->point, data, size)];
}
if (!db_cmp(r, data))
return r;
return NULL;
}
uint8_t *db_insert (uint8_t **p, uint8_t *data)
{
if _0_(CBIT(data))
return NULL;
if _0_(!*p) {
*p = data;
return data;
}
uint8_t *r = *p;
size_t size = db_size(data);
while (CBIT(r)) {
struct node *node = CBIT_NODE(r);
r = node->child[db_dir(node->point, data, size)];
}
const size_t diff = db_cmp(r, data);
if _0_(!diff)
return r;
const size_t pos = diff-1;
const uint8_t mask = ~((1u<<31)>>CLZ(r[pos]^data[pos]));
const size_t point = (pos<<8)|mask;
while (CBIT(*p)) {
struct node *node = CBIT_NODE(*p);
if (node->point>point)
break;
p = node->child+db_dir(node->point, data, size);
}
struct node *node = malloc(sizeof(struct node));
if _0_(!node)
return NULL;
const int dir = (mask|r[pos])==255;
node->child[dir] = *p;
node->child[1-dir] = data;
node->point = point;
*p = CBIT_PTR(node);
return data;
}
uint8_t *db_remove (uint8_t **p, uint8_t *data)
{
if _0_(!*p)
return NULL;
const size_t size = db_size(data);
uint8_t **p_old = NULL;
struct node *node = NULL;
int dir = 0;
while (CBIT(*p)) {
p_old = p;
node = CBIT_NODE(*p);
dir = db_dir(node->point, data, size);
p = node->child+dir;
}
if _0_(db_cmp(data, *p))
return NULL;
uint8_t *r = *p;
if (p_old) {
*p_old = node->child[1-dir];
free(node);
} else {
*p = NULL;
}
return r;
}

7
src/db.h Normal file
View File

@@ -0,0 +1,7 @@
#pragma once
#include <stdint.h>
uint8_t *db_search (uint8_t **, uint8_t *);
uint8_t *db_insert (uint8_t **, uint8_t *);
uint8_t *db_remove (uint8_t **, uint8_t *);

View File

@@ -1,39 +0,0 @@
#pragma once
#include <stdint.h>
static inline int ip_get_version (const uint8_t *data, size_t size)
{
if (size<20) // XXX
return -1; // XXX
return data[0]>>4;
}
static inline void ip_set_size (uint8_t *data, size_t size)
{
data[2] = 0xFF&(size>>8);
data[3] = 0xFF&(size);
}
static inline ssize_t ip_get_size (const uint8_t *data, size_t size)
{
switch (ip_get_version(data, size)) {
case 4:
return (data[2]<<8)|data[3];
case -1:
return -1;
}
return 0;
}
static inline int ip_get_dscp (const uint8_t *data, size_t size)
{
switch (ip_get_version(data, size)) {
case 4:
return data[1]>>2;
}
return 0;
}

39
src/ip.h Normal file
View File

@@ -0,0 +1,39 @@
#pragma once
#include <stdint.h>
struct ip_common {
uint8_t version;
uint8_t proto;
uint8_t hdr_size;
uint16_t size;
};
_pure_
static inline uint8_t ip_get_version (const uint8_t *data, size_t size)
{
if (size<20)
return 0;
return data[0]>>4;
}
static inline int ip_get_common (struct ip_common *ic, const uint8_t *data, size_t size)
{
ic->version = ip_get_version(data, size);
switch (ic->version) {
case 4:
ic->proto = data[9];
ic->hdr_size = (data[0]&0xF)<<2;
ic->size = ((data[2]<<8)|data[3]);
return 0;
case 6:
ic->proto = data[6];
ic->hdr_size = 40;
ic->size = ((data[4]<<8)|data[5])+40;
return 0;
}
return -1;
}

View File

@@ -1,28 +1,45 @@
#include "common.h"
#include "buffer.h"
#include "ip.h"
#include "str.h"
#include "option.h"
#include "tun.h"
#include "db.h"
#include <inttypes.h> #include <inttypes.h>
#include <limits.h> #include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <signal.h> #include <signal.h>
#include <poll.h> #include <poll.h>
#include <fcntl.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/fcntl.h> #include <sys/stat.h>
#include <sys/socket.h>
#ifndef __FAVOR_BSD
#define __FAVOR_BSD
#define GT_FAKE_BSD
#endif
#include <netinet/in.h>
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <netinet/udp.h>
#ifdef GT_FAKE_BSD
#undef GT_FAKE_BSD
#undef __FAVOR_BSD
#endif
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netdb.h> #include <netdb.h>
#include <sodium.h> #include <sodium.h>
#include "common-static.h"
#include "ip-static.h"
#include "option.h"
#include "tun.h"
#ifndef O_CLOEXEC #ifndef O_CLOEXEC
#define O_CLOEXEC 0 #define O_CLOEXEC 0
#endif #endif
#define GT_BUFFER_SIZE (4*1024*1024) #define GT_BUFFER_SIZE (64*1024)
#define GT_TIMEOUT (5000) #define GT_TIMEOUT (5000)
#define GT_MTU_MAX (1500) #define GT_MTU_MAX (1500)
#define GT_TUNR_SIZE (0x7FFF-16) #define GT_TUNR_SIZE (0x7FFF-16)
@@ -34,11 +51,6 @@ struct fdbuf {
buffer_t write; buffer_t write;
}; };
struct blk {
size_t size;
uint8_t data[GT_MTU_MAX] _align_(16);
};
struct crypto_ctx { struct crypto_ctx {
struct { struct {
crypto_aead_aes256gcm_state state; crypto_aead_aes256gcm_state state;
@@ -50,6 +62,7 @@ struct crypto_ctx {
volatile sig_atomic_t gt_close = 0; volatile sig_atomic_t gt_close = 0;
volatile sig_atomic_t gt_info = 0; volatile sig_atomic_t gt_info = 0;
_pure_
static int64_t dt_ms (struct timeval *ta, struct timeval *tb) static int64_t dt_ms (struct timeval *ta, struct timeval *tb)
{ {
const int64_t s = ta->tv_sec-tb->tv_sec; const int64_t s = ta->tv_sec-tb->tv_sec;
@@ -84,7 +97,9 @@ enum sk_opt {
sk_keepintvl, sk_keepintvl,
sk_congestion, sk_congestion,
sk_defer_accept, sk_defer_accept,
sk_acceptfilter,
sk_quickack, sk_quickack,
sk_user_timeout,
}; };
static void sk_set (int fd, enum sk_opt opt, const void *val, socklen_t len) static void sk_set (int fd, enum sk_opt opt, const void *val, socklen_t len)
@@ -129,6 +144,16 @@ static void sk_set (int fd, enum sk_opt opt, const void *val, socklen_t len)
[sk_quickack] = { "TCP_QUICKACK", [sk_quickack] = { "TCP_QUICKACK",
#ifdef TCP_QUICKACK #ifdef TCP_QUICKACK
1, IPPROTO_TCP, TCP_QUICKACK, 1, IPPROTO_TCP, TCP_QUICKACK,
#endif
},
[sk_acceptfilter] = { "SO_ACCEPTFILTER",
#ifdef SO_ACCEPTFILTER
1, SOL_SOCKET, SO_ACCEPTFILTER,
#endif
},
[sk_user_timeout] = { "TCP_USER_TIMEOUT",
#ifdef TCP_USER_TIMEOUT
1, IPPROTO_TCP, TCP_USER_TIMEOUT,
#endif #endif
}, },
}; };
@@ -151,21 +176,23 @@ static int sk_listen (int fd, struct addrinfo *ai)
{ {
sk_set_int(fd, sk_reuseaddr, 1); sk_set_int(fd, sk_reuseaddr, 1);
int ret = bind(fd, ai->ai_addr, ai->ai_addrlen); if (bind(fd, ai->ai_addr, ai->ai_addrlen)==-1) {
if (ret==-1) {
perror("bind"); perror("bind");
return -1; return -1;
} }
ret = listen(fd, 8); if (listen(fd, 8)==-1) {
if (ret==-1) {
perror("listen"); perror("listen");
return -1; return -1;
} }
#ifdef __linux__
sk_set_int(fd, sk_defer_accept, GT_TIMEOUT/1000); sk_set_int(fd, sk_defer_accept, GT_TIMEOUT/1000);
#else
char data[256] = {0};
str_cpy(data, "dataready", sizeof(data)-1);
sk_set(fd, sk_acceptfilter, &data, sizeof(data));
#endif
return 0; return 0;
} }
@@ -245,41 +272,9 @@ static char *sk_get_name (int fd)
return str_cat(strs, COUNT(strs)); 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)
{
gt_log("%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) static struct addrinfo *ai_create (const char *host, const char *port, int listener)
{ {
if (!port || !port[0]) { if (str_empty(port)) {
gt_log("port is not valid\n"); gt_log("port is not valid\n");
return NULL; return NULL;
} }
@@ -351,7 +346,7 @@ static void gt_set_signal (void)
static ssize_t fd_read (int fd, void *data, size_t size) static ssize_t fd_read (int fd, void *data, size_t size)
{ {
if (!size) if ((fd==-1) || !size)
return -1; return -1;
ssize_t ret = read(fd, data, size); ssize_t ret = read(fd, data, size);
@@ -371,7 +366,7 @@ static ssize_t fd_read (int fd, void *data, size_t size)
static ssize_t fd_write (int fd, const void *data, size_t size) static ssize_t fd_write (int fd, const void *data, size_t size)
{ {
if (!size) if ((fd==-1) || !size)
return -1; return -1;
ssize_t ret = write(fd, data, size); ssize_t ret = write(fd, data, size);
@@ -380,6 +375,9 @@ static ssize_t fd_write (int fd, const void *data, size_t size)
if (errno==EAGAIN || errno==EINTR) if (errno==EAGAIN || errno==EINTR)
return -1; return -1;
if (errno==EPIPE || errno==ECONNRESET)
return 0;
if (errno) if (errno)
perror("write"); perror("write");
@@ -389,15 +387,19 @@ static ssize_t fd_write (int fd, const void *data, size_t size)
return ret; return ret;
} }
static ssize_t fd_read_all (int fd, void *data, size_t size) static void state_write (int fd, const char *str)
{
if (fd==-1) {
gt_print("state: %s", str);
} else {
fd_write(fd, str, str_len(str));
}
}
static size_t fd_read_all (int fd, void *data, size_t size)
{ {
size_t done = 0; size_t done = 0;
struct pollfd pollfd = {
.fd = fd,
.events = POLLIN,
};
while (done<size) { while (done<size) {
ssize_t ret = fd_read(fd, (uint8_t *)data+done, size-done); ssize_t ret = fd_read(fd, (uint8_t *)data+done, size-done);
@@ -405,8 +407,14 @@ static ssize_t fd_read_all (int fd, void *data, size_t size)
break; break;
if (ret<0) { if (ret<0) {
struct pollfd pollfd = {
.fd = fd,
.events = POLLIN,
};
if (!poll(&pollfd, 1, GT_TIMEOUT)) if (!poll(&pollfd, 1, GT_TIMEOUT))
break; break;
continue; continue;
} }
@@ -416,15 +424,10 @@ static ssize_t fd_read_all (int fd, void *data, size_t size)
return done; return done;
} }
static ssize_t fd_write_all (int fd, const void *data, size_t size) static size_t fd_write_all (int fd, const void *data, size_t size)
{ {
size_t done = 0; size_t done = 0;
struct pollfd pollfd = {
.fd = fd,
.events = POLLOUT,
};
while (done<size) { while (done<size) {
ssize_t ret = fd_write(fd, (const uint8_t *)data+done, size-done); ssize_t ret = fd_write(fd, (const uint8_t *)data+done, size-done);
@@ -432,8 +435,14 @@ static ssize_t fd_write_all (int fd, const void *data, size_t size)
break; break;
if (ret<0) { if (ret<0) {
struct pollfd pollfd = {
.fd = fd,
.events = POLLOUT,
};
if (!poll(&pollfd, 1, GT_TIMEOUT)) if (!poll(&pollfd, 1, GT_TIMEOUT))
break; break;
continue; continue;
} }
@@ -510,32 +519,221 @@ static int gt_decrypt (struct crypto_ctx *ctx, buffer_t *dst, buffer_t *src)
return 0; return 0;
} }
static void dump_ip_header (uint8_t *data, size_t size) _pure_
static inline uint32_t sum16 (uint32_t sum, const uint8_t *data, const size_t size)
{ {
if (size<20) const size_t lim = size&~1u;
return;
const char tbl[] = "0123456789ABCDEF"; for (size_t i=0; i<lim; i+=2)
char hex[41]; sum += (data[i]<<8)|data[i+1];
for (size_t i=0; i<20; i++) { if (size&1)
hex[(i<<1)+0] = tbl[0xF&(data[i]>>4)]; sum += data[size-1]<<8;
hex[(i<<1)+1] = tbl[0xF&(data[i])];
return sum;
}
_const_
static inline uint16_t sum16_final (uint32_t sum)
{
sum = (sum>>16)+(sum&0xFFFF);
return ~(sum+(sum>>16));
}
struct tcp_entry {
uint8_t key[37];
struct {
uint32_t seq;
uint32_t ack;
size_t count;
struct timeval time;
} data[2];
};
static int tcp_entry_set_key (struct tcp_entry *te, struct ip_common *ic, uint8_t *data)
{
uint8_t *key = &te->key[1];
size_t size = 0;
switch (ic->version) {
case 4:
size = 8;
memcpy(key, &data[12], 8);
break;
case 6:
size = 32;
memcpy(key, &data[9], 32);
break;
} }
hex[40] = 0; memcpy(&key[size], &data[ic->hdr_size], 4);
te->key[0] = size+4;
gt_log("DUMP(%zu): %s\n", size, hex); return 0;
}
static int tcp_entry_set_key_rev (struct tcp_entry *te, struct ip_common *ic, uint8_t *data)
{
uint8_t *key = &te->key[1];
size_t size = 0;
switch (ic->version) {
case 4:
size = 8;
memcpy(key, &data[12+4], 4);
memcpy(key+4, &data[12], 4);
break;
case 6:
size = 32;
memcpy(key, &data[9+16], 16);
memcpy(key+16, &data[9], 16);
break;
}
memcpy(&key[size], &data[ic->hdr_size+2], 2);
memcpy(&key[size+2], &data[ic->hdr_size], 2);
te->key[0] = size+4;
return 0;
}
static int gt_track (uint8_t **db, struct ip_common *ic, uint8_t *data, int rev)
{
if (ic->proto!=IPPROTO_TCP)
return 0;
if (!ic->hdr_size)
return 1;
struct tcp_entry entry;
if (rev) {
tcp_entry_set_key_rev(&entry, ic, data);
} else {
tcp_entry_set_key(&entry, ic, data);
}
struct tcphdr tcp;
memcpy(&tcp, &data[ic->hdr_size], sizeof(tcp));
tcp.th_seq = ntohl(tcp.th_seq);
tcp.th_ack = ntohl(tcp.th_ack);
struct tcp_entry *r_entry = (void *)db_search(db, entry.key);
if (!r_entry) {
r_entry = calloc(1, sizeof(entry));
if (!r_entry)
return 1;
memcpy(r_entry->key, entry.key, sizeof(entry.key));
if (!db_insert(db, r_entry->key)) {
free(r_entry);
return 1;
}
gt_print("new tcp entry\n");
} else {
gt_print("old_seq:%u\told_ack:%u\tcount:%zu\n",
r_entry->data[rev].seq,
r_entry->data[rev].ack,
r_entry->data[rev].count);
}
r_entry->data[rev].seq = tcp.th_seq;
r_entry->data[rev].ack = tcp.th_ack;
r_entry->data[rev].count++;
gettimeofday(&r_entry->data[rev].time, NULL);
return 0;
}
static void gt_print_hdr (struct ip_common *ic, uint8_t *data)
{
if (!ic->hdr_size)
return;
uint32_t sum = ic->proto+ic->size-ic->hdr_size;
char ip_src[INET6_ADDRSTRLEN];
char ip_dst[INET6_ADDRSTRLEN];
switch (ic->version) {
case 4:
inet_ntop(AF_INET, &data[12], ip_src, sizeof(ip_src));
inet_ntop(AF_INET, &data[16], ip_dst, sizeof(ip_dst));
sum = sum16(sum, &data[12], 2*4);
break;
case 6:
inet_ntop(AF_INET6, &data[9], ip_src, sizeof(ip_src));
inet_ntop(AF_INET6, &data[25], ip_dst, sizeof(ip_dst));
sum = sum16(sum, &data[9], 2*16); // XXX
break;
}
uint8_t *const packet = &data[ic->hdr_size];
if (ic->proto==IPPROTO_TCP) {
struct tcphdr tcp;
memcpy(&tcp, packet, sizeof(tcp));
uint16_t tcp_sum = ntohs(tcp.th_sum);
tcp.th_sum = 0;
sum = sum16(sum, (uint8_t *)&tcp, sizeof(tcp));
sum = sum16(sum, &packet[sizeof(tcp)], ic->size-ic->hdr_size-sizeof(tcp));
uint16_t computed_sum = sum16_final(sum);
tcp.th_sport = ntohs(tcp.th_sport);
tcp.th_dport = ntohs(tcp.th_dport);
tcp.th_seq = ntohl(tcp.th_seq);
tcp.th_ack = ntohl(tcp.th_ack);
tcp.th_win = ntohs(tcp.th_win);
gt_print("proto:%hhu\tsrc:%s.%u\tdst:%s.%u\tseq:%u\tack:%u\twin:%u\tsize:%u\tflags:%c%c%c%c%c%c\tsum:%i\n",
ic->proto, ip_src, tcp.th_sport, ip_dst, tcp.th_dport,
tcp.th_seq, tcp.th_ack, tcp.th_win, ic->size-ic->hdr_size-tcp.th_off*4,
(tcp.th_flags&TH_FIN) ?'F':'.',
(tcp.th_flags&TH_SYN) ?'S':'.',
(tcp.th_flags&TH_RST) ?'R':'.',
(tcp.th_flags&TH_PUSH)?'P':'.',
(tcp.th_flags&TH_ACK) ?'A':'.',
(tcp.th_flags&TH_URG) ?'U':'.',
(computed_sum==tcp_sum));
} else if (ic->proto==IPPROTO_UDP) {
struct udphdr udp;
memcpy(&udp, packet, sizeof(udp));
udp.uh_sport = ntohs(udp.uh_sport);
udp.uh_dport = ntohs(udp.uh_dport);
udp.uh_ulen = ntohs(udp.uh_ulen);
gt_print("proto:%hhu\tsrc:%s.%u\tdst:%s.%u\tsize:%u\n",
ic->proto, ip_src, udp.uh_sport, ip_dst, udp.uh_dport, udp.uh_ulen-8);
} else {
gt_print("proto:%hhu\tsrc:%s\tdst:%s\tsize:%hu\n",
ic->proto, ip_src, ip_dst, ic->size);
}
} }
static int gt_setup_secretkey (struct crypto_ctx *ctx, char *keyfile) static int gt_setup_secretkey (struct crypto_ctx *ctx, char *keyfile)
{ {
const size_t size = sizeof(ctx->skey); const size_t size = sizeof(ctx->skey);
byte_set(ctx->skey, 1, size); if (str_empty(keyfile)) {
char buf[2*size+1];
randombytes_buf(ctx->skey, size);
gt_tohex(buf, sizeof(buf), ctx->skey, size);
gt_print("new secret key: %s\n", buf);
if (!keyfile)
return 0; return 0;
}
int fd; int fd;
@@ -548,23 +746,33 @@ static int gt_setup_secretkey (struct crypto_ctx *ctx, char *keyfile)
return -1; return -1;
} }
if (fd_read_all(fd, ctx->skey, size)!=size) { char key[2*size];
gt_log("unable to read secret key in `%s'\n", keyfile); size_t r = fd_read_all(fd, key, sizeof(key));
close(fd);
close(fd);
if (r!=sizeof(key)) {
gt_log("unable to read secret key\n");
return -1; return -1;
} }
close(fd); if (gt_fromhex(ctx->skey, size, key, sizeof(key))) {
gt_log("secret key is not valid\n");
return -1;
}
return 0; return 0;
} }
static int gt_setup_crypto (struct crypto_ctx *ctx, int fd, int listener) static int gt_setup_crypto (struct crypto_ctx *ctx, int fd, int listener)
{ {
const uint8_t gt[] = {'G', 'T', VERSION_MAJOR, 0 };
const size_t size = 96;
const size_t hash_size = 32;
const size_t nonce_size = crypto_aead_aes256gcm_NPUBBYTES; const size_t nonce_size = crypto_aead_aes256gcm_NPUBBYTES;
const size_t public_size = crypto_scalarmult_SCALARBYTES; const size_t public_size = crypto_scalarmult_SCALARBYTES;
const size_t hash_size = crypto_generichash_BYTES;
const size_t size = nonce_size + public_size + hash_size;
uint8_t secret[crypto_scalarmult_SCALARBYTES]; uint8_t secret[crypto_scalarmult_SCALARBYTES];
uint8_t shared[crypto_scalarmult_BYTES]; uint8_t shared[crypto_scalarmult_BYTES];
@@ -576,10 +784,14 @@ static int gt_setup_crypto (struct crypto_ctx *ctx, int fd, int listener)
crypto_generichash_state state; crypto_generichash_state state;
memset(data_w, 0, size);
randombytes_buf(data_w, nonce_size); randombytes_buf(data_w, nonce_size);
randombytes_buf(secret, sizeof(secret)); randombytes_buf(secret, sizeof(secret));
crypto_scalarmult_base(&data_w[nonce_size], secret); crypto_scalarmult_base(&data_w[nonce_size], secret);
memcpy(&data_w[size-hash_size-sizeof(gt)], gt, sizeof(gt));
crypto_generichash(&data_w[size-hash_size], hash_size, crypto_generichash(&data_w[size-hash_size], hash_size,
data_w, size-hash_size, ctx->skey, sizeof(ctx->skey)); data_w, size-hash_size, ctx->skey, sizeof(ctx->skey));
@@ -589,6 +801,9 @@ static int gt_setup_crypto (struct crypto_ctx *ctx, int fd, int listener)
if (fd_read_all(fd, data_r, size)!=size) if (fd_read_all(fd, data_r, size)!=size)
return -1; return -1;
if (memcmp(&data_r[size-hash_size-sizeof(gt)], gt, sizeof(gt)))
return -2;
crypto_generichash(hash, hash_size, crypto_generichash(hash, hash_size,
data_r, size-hash_size, ctx->skey, sizeof(ctx->skey)); data_r, size-hash_size, ctx->skey, sizeof(ctx->skey));
@@ -634,8 +849,8 @@ static int gt_setup_crypto (struct crypto_ctx *ctx, int fd, int listener)
sodium_memzero(shared, sizeof(shared)); sodium_memzero(shared, sizeof(shared));
sodium_memzero(key, sizeof(key)); sodium_memzero(key, sizeof(key));
byte_cpy(ctx->read.nonce, data_r, nonce_size); memcpy(ctx->read.nonce, data_r, nonce_size);
byte_cpy(ctx->write.nonce, data_w, nonce_size); memcpy(ctx->write.nonce, data_w, nonce_size);
return 0; return 0;
} }
@@ -646,9 +861,10 @@ int main (int argc, char **argv)
char *host = NULL; char *host = NULL;
char *port = "5000"; char *port = "5000";
char *dev = PACKAGE_NAME; char *dev = NULL;
char *keyfile = NULL; char *keyfile = NULL;
char *congestion = NULL; char *congestion = NULL;
char *statefile = NULL;
long buffer_size = GT_BUFFER_SIZE; long buffer_size = GT_BUFFER_SIZE;
@@ -656,11 +872,13 @@ int main (int argc, char **argv)
long ka_idle = -1; long ka_idle = -1;
long ka_interval = -1; long ka_interval = -1;
long retry_count = 0; long retry_count = -1;
long retry_slope = 1000; long retry_slope = 0;
long retry_const = 0; long retry_const = 0;
long retry_limit = 1000000; long retry_limit = 1000000;
long user_timeout = 0;
struct option ka_opts[] = { struct option ka_opts[] = {
{ "count", &ka_count, option_long }, { "count", &ka_count, option_long },
{ "idle", &ka_idle, option_long }, { "idle", &ka_idle, option_long },
@@ -677,20 +895,23 @@ int main (int argc, char **argv)
}; };
struct option opts[] = { struct option opts[] = {
{ "listener", NULL, option_option }, { "listener", NULL, option_option },
{ "host", &host, option_str }, { "host", &host, option_str },
{ "port", &port, option_str }, { "port", &port, option_str },
{ "dev", &dev, option_str }, { "dev", &dev, option_str },
{ "keyfile", &keyfile, option_str }, { "keyfile", &keyfile, option_str },
{ "congestion", &congestion, option_str }, { "congestion", &congestion, option_str },
{ "delay", NULL, option_option }, { "delay", NULL, option_option },
{ "multiqueue", NULL, option_option }, { "multiqueue", NULL, option_option },
{ "keepalive", ka_opts, option_option }, { "keepalive", ka_opts, option_option },
{ "buffer-size", &buffer_size, option_long }, { "buffer-size", &buffer_size, option_long },
{ "noquickack", NULL, option_option }, { "noquickack", NULL, option_option },
{ "retry", &retry_opts, option_option }, { "retry", &retry_opts, option_option },
{ "daemon", NULL, option_option }, { "daemon", NULL, option_option },
{ "version", NULL, option_option }, { "statefile", &statefile, option_str },
{ "timeout", &user_timeout, option_long },
{ "debug", NULL, option_option },
{ "version", NULL, option_option },
{ NULL }, { NULL },
}; };
@@ -706,14 +927,30 @@ int main (int argc, char **argv)
const int delay = option_is_set(opts, "delay"); const int delay = option_is_set(opts, "delay");
const int keepalive = option_is_set(opts, "keepalive"); const int keepalive = option_is_set(opts, "keepalive");
const int noquickack = option_is_set(opts, "noquickack"); const int noquickack = option_is_set(opts, "noquickack");
const int debug = option_is_set(opts, "debug");
if (buffer_size < 2048) { if (buffer_size < 2048) {
buffer_size = 2048; buffer_size = 2048;
gt_log("buffer size must be greater than 2048!\n"); gt_log("buffer size must be greater than 2048\n");
}
if (!listener) {
if (!option_is_set(opts, "keyfile")) {
gt_log("keyfile option must be set\n");
return 1;
}
if (!option_is_set(opts, "retry"))
retry_count = 0;
}
if (statefile && statefile[0]!='/') {
gt_log("statefile must be an absolute path\n");
return 1;
} }
if (sodium_init()==-1) { if (sodium_init()==-1) {
gt_log("libsodium initialization has failed!\n"); gt_log("libsodium initialization has failed\n");
return 1; return 1;
} }
@@ -722,11 +959,6 @@ int main (int argc, char **argv)
return 1; return 1;
} }
struct crypto_ctx ctx;
if (gt_setup_secretkey(&ctx, keyfile))
return 1;
struct addrinfo *ai = ai_create(host, port, listener); struct addrinfo *ai = ai_create(host, port, listener);
if (!ai) if (!ai)
@@ -737,16 +969,10 @@ int main (int argc, char **argv)
tun.fd = tun_create(dev, option_is_set(opts, "multiqueue")); tun.fd = tun_create(dev, option_is_set(opts, "multiqueue"));
if (tun.fd==-1) if (tun.fd==-1) {
return 1; gt_log("couldn't create tun device\n");
struct blk *blks = calloc(256, sizeof(struct blk));
size_t blk_count = 0;
uint8_t blk_read = 0;
uint8_t blk_write = 0;
if (!blks)
return 1; return 1;
}
fd_set_nonblock(tun.fd); fd_set_nonblock(tun.fd);
@@ -765,6 +991,11 @@ int main (int argc, char **argv)
return 1; return 1;
} }
struct crypto_ctx ctx;
if (gt_setup_secretkey(&ctx, keyfile))
return 1;
if (option_is_set(opts, "daemon")) { if (option_is_set(opts, "daemon")) {
switch (fork()) { switch (fork()) {
case -1: case -1:
@@ -781,39 +1012,63 @@ int main (int argc, char **argv)
chdir("/"); chdir("/");
} }
int state_fd = -1;
if (statefile) {
state_fd = open(statefile, O_WRONLY);
if (state_fd==-1) {
if (errno!=EINTR)
perror("open statefile");
return 1;
}
struct stat st = {0};
if (fstat(state_fd, &st)==-1) {
perror("stat statefile");
return 1;
}
if (!S_ISFIFO(st.st_mode)) {
gt_log("`%s' is not a fifo\n", statefile);
return 1;
}
}
long retry = 0; long retry = 0;
uint8_t *db = NULL;
state_write(state_fd, "INITIALIZED\n");
while (!gt_close) { while (!gt_close) {
sock.fd = listener?sk_accept(fd):sk_create(ai, sk_connect); if (retry_count>=0 && retry>=retry_count+1) {
gt_log("couldn't %s (%d attempt%s)\n", listener?"listen":"connect",
if (sock.fd==-1) { (int)retry, (retry>1)?"s":"");
if (retry<LONG_MAX) break;
retry++; }
if (retry_slope || retry_const) {
long usec = retry*retry_slope+retry_const; long usec = retry*retry_slope+retry_const;
if (retry_count>=0 && retry>=retry_count) {
gt_log("couldn't %s (%d attempt%s)\n",
listener?"listen":"connect",
(int)retry, (retry>1)?"s":"");
break;
}
if (usec>retry_limit) if (usec>retry_limit)
usec = retry_limit; usec = retry_limit;
if (usec<=0) if (usec>0 && usleep(usec)==-1 && errno==EINVAL)
usec = 0;
if (usleep(usec)==-1 && errno==EINVAL)
sleep(usec/1000000); sleep(usec/1000000);
continue;
} }
if (retry<LONG_MAX)
retry++;
sock.fd = listener?sk_accept(fd):sk_create(ai, sk_connect);
if (sock.fd==-1)
continue;
char *sockname = sk_get_name(sock.fd); char *sockname = sk_get_name(sock.fd);
if (!sockname) { if (str_empty(sockname)) {
close(sock.fd); close(sock.fd);
continue; continue;
} }
@@ -836,6 +1091,9 @@ int main (int argc, char **argv)
sk_set_int(sock.fd, sk_keepintvl, ka_interval); sk_set_int(sock.fd, sk_keepintvl, ka_interval);
} }
if (user_timeout>0 && user_timeout<=INT_MAX)
sk_set_int(sock.fd, sk_user_timeout, user_timeout);
sk_set(sock.fd, sk_congestion, congestion, str_len(congestion)); sk_set(sock.fd, sk_congestion, congestion, str_len(congestion));
switch (gt_setup_crypto(&ctx, sock.fd, listener)) { switch (gt_setup_crypto(&ctx, sock.fd, listener)) {
@@ -851,7 +1109,7 @@ int main (int argc, char **argv)
retry = 0; retry = 0;
gt_log("%s: running\n", sockname); state_write(state_fd, "STARTED\n");
fd_set rfds; fd_set rfds;
FD_ZERO(&rfds); FD_ZERO(&rfds);
@@ -871,7 +1129,9 @@ int main (int argc, char **argv)
goto restart; goto restart;
FD_CLR(tun.fd, &rfds); FD_CLR(tun.fd, &rfds);
} else { } else {
if (!blks[blk_write].size) { buffer_shift(&tun.read);
if (buffer_write_size(&tun.read)>=GT_MTU_MAX) {
FD_SET(tun.fd, &rfds); FD_SET(tun.fd, &rfds);
} else { } else {
FD_CLR(tun.fd, &rfds); FD_CLR(tun.fd, &rfds);
@@ -901,78 +1161,54 @@ int main (int argc, char **argv)
// struct timeval now; // struct timeval now;
// gettimeofday(&now, NULL); // gettimeofday(&now, NULL);
#ifdef TCP_INFO
if _0_(gt_info) {
struct tcp_info ti;
if (sk_get_info(sock.fd, &ti))
print_tcp_info(sockname, &ti);
gt_info = 0;
}
#endif
if (FD_ISSET(tun.fd, &rfds)) { if (FD_ISSET(tun.fd, &rfds)) {
while (!blks[blk_write].size) { while (1) {
uint8_t *data = blks[blk_write].data; const size_t size = buffer_write_size(&tun.read);
const ssize_t r = tun_read(tun.fd, data, GT_MTU_MAX);
if (size<GT_MTU_MAX)
break;
const ssize_t r = tun_read(tun.fd, tun.read.write, GT_MTU_MAX);
if (r<=0) { if (r<=0) {
gt_close |= !r; gt_close |= !r;
break; break;
} }
const ssize_t ip_size = ip_get_size(data, GT_MTU_MAX); struct ip_common ic;
if _0_(ip_size<=0) if (ip_get_common(&ic, tun.read.write, GT_MTU_MAX))
continue; continue;
if _0_(ip_size!=r) { if _0_(ic.size!=r) {
dump_ip_header(data, r); char tmp[2*GT_MTU_MAX+1];
gt_tohex(tmp, sizeof(tmp), tun.read.write, r);
if (r>ip_size) gt_log("%s: DUMP %zi %s\n", sockname, r, tmp);
continue; continue;
ip_set_size(data, r);
} }
blks[blk_write++].size = r; if _0_(debug) {
blk_count++; gt_print_hdr(&ic, tun.read.write);
if (gt_track(&db, &ic, tun.read.write, 0))
continue;
}
tun.read.write += r;
} }
} }
while (1) { if _1_(!stop_loop)
buffer_shift(&tun.read); gt_encrypt(&ctx, &sock.write, &tun.read);
if _0_(!stop_loop) {
for (; blk_count; blk_read++) {
const size_t size = blks[blk_read].size;
if (!size || buffer_write_size(&tun.read)<size)
break;
byte_cpy(tun.read.write, blks[blk_read].data, size);
tun.read.write += size;
blks[blk_read].size = 0;
blk_count--;
}
gt_encrypt(&ctx, &sock.write, &tun.read);
}
if (!buffer_read_size(&sock.write))
break;
if (buffer_read_size(&sock.write)) {
const ssize_t r = fd_write(sock.fd, sock.write.read, const ssize_t r = fd_write(sock.fd, sock.write.read,
buffer_read_size(&sock.write)); buffer_read_size(&sock.write));
if (r>0) { if (r>0) {
sock.write.read += r; sock.write.read += r;
} else { } else if (!r) {
if (!r) stop_loop |= (1<<2);
stop_loop |= (1<<2);
break;
} }
} }
@@ -1009,17 +1245,27 @@ int main (int argc, char **argv)
} }
size_t size = buffer_read_size(&tun.write); size_t size = buffer_read_size(&tun.write);
ssize_t ip_size = ip_get_size(tun.write.read, size);
if _0_(!ip_size) { if (!size)
break;
struct ip_common ic;
if (ip_get_common(&ic, tun.write.read, size) || ic.size>size) {
gt_log("%s: bad packet!\n", sockname); gt_log("%s: bad packet!\n", sockname);
goto restart; goto restart;
} }
if (ip_size<0 || (size_t)ip_size>size) if _0_(debug) {
break; gt_print_hdr(&ic, tun.write.read);
ssize_t r = tun_write(tun.fd, tun.write.read, ip_size); if (gt_track(&db, &ic, tun.write.read, 1)) {
tun.write.read += ic.size;
continue;
}
}
ssize_t r = tun_write(tun.fd, tun.write.read, ic.size);
if (r>0) { if (r>0) {
tun.write.read += r; tun.write.read += r;
@@ -1040,12 +1286,12 @@ int main (int argc, char **argv)
close(sock.fd); close(sock.fd);
sock.fd = -1; sock.fd = -1;
} }
state_write(state_fd, "STOPPED\n");
} }
freeaddrinfo(ai); freeaddrinfo(ai);
free(blks);
free(sock.write.data); free(sock.write.data);
free(sock.read.data); free(sock.read.data);

View File

@@ -1,25 +1,23 @@
#include "common-static.h" #include "common.h"
#include <stdio.h>
#include <stdlib.h>
#include "option.h" #include "option.h"
#include "str.h"
int option_str (void *data, int argc, char **argv) int option_str (void *data, int argc, char **argv)
{ {
if (argc<2 || !argv[1]) { if (argc<2 || str_empty(argv[1])) {
gt_print("option `%s' need a string argument\n", argv[0]); gt_print("option `%s' need a string argument\n", argv[0]);
return -1; return -1;
} }
byte_cpy(data, &argv[1], sizeof(argv[1])); memcpy(data, &argv[1], sizeof(argv[1]));
return 1; return 1;
} }
int option_long (void *data, int argc, char **argv) int option_long (void *data, int argc, char **argv)
{ {
if (argc<2 || !argv[1]) { if (argc<2 || str_empty(argv[1])) {
gt_print("option `%s' need an integer argument\n", argv[0]); gt_print("option `%s' need an integer argument\n", argv[0]);
return -1; return -1;
} }
@@ -33,7 +31,7 @@ int option_long (void *data, int argc, char **argv)
return -1; return -1;
} }
byte_cpy(data, &val, sizeof(val)); memcpy(data, &val, sizeof(val));
return 1; return 1;
} }

73
src/str.h Normal file
View File

@@ -0,0 +1,73 @@
#pragma once
#include "common.h"
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;
}
_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)
{
if (!str)
return 0;
return strlen(str);
}
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]);
memcpy(p, strs[i], len);
p += len;
}
p[0] = 0;
return str;
}

177
src/tun.c
View File

@@ -1,7 +1,8 @@
#include "common-static.h" #include "common.h"
#include "ip-static.h"
#include "tun.h" #include "tun.h"
#include "str.h"
#include "ip.h"
#include <stdio.h> #include <stdio.h>
#include <fcntl.h> #include <fcntl.h>
@@ -11,116 +12,148 @@
#include <sys/uio.h> #include <sys/uio.h>
#ifdef __linux__ #ifdef __linux__
# include <linux/if.h> #include <linux/if.h>
# include <linux/if_tun.h> #include <linux/if_tun.h>
#endif #endif
#ifdef __APPLE__ #ifdef __APPLE__
# include <sys/sys_domain.h> #include <sys/sys_domain.h>
# include <sys/kern_control.h> #include <sys/kern_control.h>
# include <net/if_utun.h> #include <net/if_utun.h>
#endif #endif
#if defined(__APPLE__) || defined(__OpenBSD__) #if defined(__APPLE__) || defined(__OpenBSD__)
# define GT_BSD_TUN 1 #define GT_BSD_TUN
#endif #endif
#ifdef __APPLE__
static int tun_create_by_id (char *name, size_t size, unsigned id, _unused_ int mq)
{
int fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
if (fd==-1)
return -1;
struct ctl_info ci;
memset(&ci, 0, sizeof(ci));
str_cpy(ci.ctl_name, UTUN_CONTROL_NAME, sizeof(ci.ctl_name)-1);
if (ioctl(fd, CTLIOCGINFO, &ci)) {
close(fd);
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))) {
close(fd);
return -1;
}
snprintf(name, size, "utun%u", id);
return fd;
}
static int tun_create_by_name (char *name, size_t size, char *dev_name, int mq)
{
unsigned id = 0;
if (sscanf(dev_name, "utun%u", &id)!=1)
return -1;
return tun_create_by_id(name, size, id, mq);
}
#else /* not __APPLE__ */
#ifdef __linux__ #ifdef __linux__
int tun_create (char *name, int multiqueue)
static int tun_create_by_name (char *name, size_t size, char *dev_name, int mq)
{ {
int fd = open("/dev/net/tun", O_RDWR); int fd = open("/dev/net/tun", O_RDWR);
if (fd<0) { if (fd==-1)
perror("open /dev/net/tun");
return -1; return -1;
}
struct ifreq ifr = { struct ifreq ifr = {
.ifr_flags = IFF_TUN|IFF_NO_PI, .ifr_flags = IFF_TUN|IFF_NO_PI,
}; };
if (multiqueue) { if (mq) {
#ifdef IFF_MULTI_QUEUE #ifdef IFF_MULTI_QUEUE
ifr.ifr_flags |= IFF_MULTI_QUEUE; ifr.ifr_flags |= IFF_MULTI_QUEUE;
#else
gt_na("IFF_MULTI_QUEUE");
#endif #endif
} }
str_cpy(ifr.ifr_name, name, IFNAMSIZ-1); str_cpy(ifr.ifr_name, dev_name, IFNAMSIZ-1);
int ret = ioctl(fd, TUNSETIFF, &ifr); if (ioctl(fd, TUNSETIFF, &ifr)) {
close(fd);
if (ret<0) {
perror("ioctl TUNSETIFF");
return -1; return -1;
} }
gt_log("tun name: %s\n", ifr.ifr_name); str_cpy(name, ifr.ifr_name, size-1);
return fd; return fd;
} }
#elif defined(__APPLE__)
int tun_create (_unused_ char *name, _unused_ int mq) #else /* not __linux__ not __APPLE__ */
static int tun_create_by_name (char *name, size_t size, char *dev_name, _unused_ int mq)
{ {
for (unsigned dev_id = 0; dev_id < 32; dev_id++) { char path[64];
struct ctl_info ci;
byte_set(&ci, 0, sizeof(ci)); snprintf(path, sizeof(path), "/dev/%s", dev_name);
str_cpy(ci.ctl_name, UTUN_CONTROL_NAME, sizeof(ci.ctl_name)-1); str_cpy(name, dev_name, size-1);
int fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); return open(path, O_RDWR);
if (fd==-1)
return -1;
if (ioctl(fd, CTLIOCGINFO, &ci)==-1) {
close(fd);
continue;
}
struct sockaddr_ctl sc = {
.sc_id = ci.ctl_id,
.sc_len = sizeof(sc),
.sc_family = AF_SYSTEM,
.ss_sysaddr = AF_SYS_CONTROL,
.sc_unit = dev_id+1,
};
if (connect(fd, (struct sockaddr *)&sc, sizeof(sc))==-1) {
close(fd);
continue;
}
gt_log("tun name: /dev/utun%u\n", dev_id);
return fd;
}
return -1;
} }
#else
int tun_create (_unused_ char *name, _unused_ int mq) #endif /* not __APPLE__ */
static int tun_create_by_id (char *name, size_t size, unsigned id, int mq)
{ {
for (unsigned dev_id = 0; dev_id < 32; dev_id++) { char dev_name[64];
char dev_path[11];
snprintf(dev_path, sizeof(dev_path), "/dev/tun%u", dev_id); snprintf(dev_name, sizeof(dev_name), "tun%u", id);
int fd = open(dev_path, O_RDWR); return tun_create_by_name(name, size, dev_name, mq);
if (fd==-1)
continue;
gt_log("tun name: %s\n", dev_path);
return fd;
}
return -1;
} }
#endif #endif
int tun_create (char *dev_name, int mq)
{
char name[64];
int fd = -1;
#ifndef IFF_MULTI_QUEUE
if (mq)
gt_na("IFF_MULTI_QUEUE");
#endif
if (str_empty(dev_name)) {
for (unsigned id=0; id<32 && fd==-1; id++)
fd = tun_create_by_id(name, sizeof(name), id, mq);
} else {
fd = tun_create_by_name(name, sizeof(name), dev_name, mq);
}
if (fd!=-1)
gt_print("tun name: %s\n", name);
return fd;
}
ssize_t tun_read (int fd, void *data, size_t size) ssize_t tun_read (int fd, void *data, size_t size)
{ {
if (!size) if (!size)

View File

@@ -3,7 +3,11 @@
[ -z "${VERSION}" ] && VERSION=`git describe --tags --always 2>/dev/null` \ [ -z "${VERSION}" ] && VERSION=`git describe --tags --always 2>/dev/null` \
&& VERSION=${VERSION#v} && VERSION=${VERSION#v}
[ -z "${VERSION}" ] && VERSION=`basename \`pwd\`` \ [ -z "${VERSION}" ] && VERSION=`cat VERSION 2>/dev/null`
&& VERSION=${VERSION#*-}
printf ${VERSION} [ -z "${VERSION}" ] && VERSION=0.0.0
[ "$1" = "major" ] && printf ${VERSION%%.*} \
&& exit 0
printf ${VERSION} | tee VERSION