Compare commits

..

9 Commits

Author SHA1 Message Date
angt
a3aa6fc4fb Add option bench 2016-06-02 13:44:24 +00:00
angt
6f36424d12 Code cleanup 2016-04-26 06:18:12 +00:00
angt
fa9301da16 Show tun_name in all states and fix state_send() 2016-04-26 06:13:14 +00:00
angt
c154a00358 Use a bigger timeout when buffers are empty 2016-04-12 14:11:16 +00:00
Adrien Gallouët
4246b510d2 Never trust frank :) 2016-03-30 15:41:53 +02:00
Adrien Gallouët
c71db48ae1 Add a nice geek logo for glorytun 2016-03-23 17:44:40 +01:00
Adrien Gallouët
e3cce8aeb9 AES-NI is no longer mandatory 2016-03-18 21:19:24 +01:00
angt
ad0d205ff3 Add option chacha20
Chacha20 will be automatically used if aesni is not available.
2016-03-18 14:43:30 +00:00
angt
030087cb27 Add mptcp option 2016-02-25 14:38:51 +00:00
27 changed files with 1810 additions and 862 deletions

2
.gitignore vendored
View File

@@ -11,5 +11,3 @@ build-aux
.deps .deps
.dirstamp .dirstamp
glorytun glorytun
build*
VERSION

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "mud"]
path = mud
url = https://github.com/angt/mud.git

View File

@@ -7,6 +7,7 @@ glorytun_LDADD = $(libsodium_LIBS)
glorytun_SOURCES = \ glorytun_SOURCES = \
src/common.h \ src/common.h \
src/common.c \ src/common.c \
src/buffer.h \
src/ip.h \ src/ip.h \
src/str.h \ src/str.h \
src/main.c \ src/main.c \
@@ -14,24 +15,14 @@ glorytun_SOURCES = \
src/option.h \ src/option.h \
src/tun.c \ src/tun.c \
src/tun.h \ src/tun.h \
src/iface.c \
src/iface.h \
src/db.c \ src/db.c \
src/db.h \ src/db.h \
mud/mud.h \ src/state.c \
mud/mud.c src/state.h
EXTRA_DIST = \ EXTRA_DIST = \
LICENSE \ LICENSE \
README.md \ README.md \
VERSION \ VERSION \
systemd/glorytun-client.network \
systemd/glorytun-run \
systemd/glorytun-setup \
systemd/glorytun.network \
systemd/glorytun@.service.in \
mud/LICENSE \
mud/README.md \
meson.build \
autogen.sh \ autogen.sh \
version.sh version.sh

View File

@@ -1,53 +1,22 @@
# Glorytun # π₁(Glorytun)=ℤ²
Small, Simple and Stupid VPN over [mud](https://github.com/angt/mud). Small, Simple and Stupid TCP VPN.
### Build and Install #### 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.
On Ubuntu, the following command should be sufficient: To build and install the latest version:
$ sudo apt-get install meson libsodium-dev pkg-config $ git clone https://github.com/angt/glorytun
Grab the latest release from github:
$ git clone https://github.com/angt/glorytun --recursive
$ cd glorytun $ cd glorytun
$ ./autogen.sh
To build and install the latest version with [meson](http://mesonbuild.com): $ ./configure
$ make
$ meson build # make install
$ sudo ninja -C build install
The more classical autotools suite is also available.
### Easy setup with systemd
Just call `glorytun-setup` and follow the instructions.
First, setup the server:
$ sudo glorytun-setup
Config filename (tun0):
Server ip (enter for server conf):
Server key (enter to generate a new one):
Your new key: NEW_KEY
Start glorytun now ? (enter to skip): y
Copy the new generated key and use it when configuring the client:
$ sudo glorytun-setup
Config filename (tun0):
Server ip (enter for server conf): SERVER_IP
Server key (enter to generate a new one): NEW_KEY
Start glorytun now ? (enter to skip): y
You can check easily if it works by looking at your public ip.
To stop the service:
$ sudo systemctl stop glorytun@tun0
---
For feature requests and bug reports, please create an [issue](https://github.com/angt/glorytun/issues). For feature requests and bug reports, please create an [issue](https://github.com/angt/glorytun/issues).

View File

@@ -8,15 +8,14 @@ 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])
AM_INIT_AUTOMAKE([1.12 -Wall -Werror foreign tar-ustar subdir-objects]) AM_INIT_AUTOMAKE([1.9 -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 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_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

View File

@@ -1,6 +1,6 @@
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
# serial 12 (pkg-config-0.29.2) dnl serial 11 (pkg-config-0.29)
dnl
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>. dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com> dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
dnl dnl
@@ -41,7 +41,7 @@ dnl
dnl See the "Since" comment for each macro you use to see what version dnl See the "Since" comment for each macro you use to see what version
dnl of the macros you require. dnl of the macros you require.
m4_defun([PKG_PREREQ], m4_defun([PKG_PREREQ],
[m4_define([PKG_MACROS_VERSION], [0.29.2]) [m4_define([PKG_MACROS_VERSION], [0.29])
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, 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])]) [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
])dnl PKG_PREREQ ])dnl PKG_PREREQ
@@ -142,7 +142,7 @@ 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 AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
pkg_failed=no pkg_failed=no
AC_MSG_CHECKING([for $2]) AC_MSG_CHECKING([for $1])
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
_PKG_CONFIG([$1][_LIBS], [libs], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2])
@@ -152,11 +152,11 @@ and $1[]_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details.]) See the pkg-config man page for more details.])
if test $pkg_failed = yes; then if test $pkg_failed = yes; then
AC_MSG_RESULT([no]) AC_MSG_RESULT([no])
_PKG_SHORT_ERRORS_SUPPORTED _PKG_SHORT_ERRORS_SUPPORTED
if test $_pkg_short_errors_supported = yes; then if test $_pkg_short_errors_supported = yes; then
$1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
else else
$1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
fi fi
# Put the nasty error message in config.log where it belongs # Put the nasty error message in config.log where it belongs
@@ -173,7 +173,7 @@ installed software in a non-standard prefix.
_PKG_TEXT])[]dnl _PKG_TEXT])[]dnl
]) ])
elif test $pkg_failed = untried; then elif test $pkg_failed = untried; then
AC_MSG_RESULT([no]) AC_MSG_RESULT([no])
m4_default([$4], [AC_MSG_FAILURE( m4_default([$4], [AC_MSG_FAILURE(
[The pkg-config script could not be found or is too old. Make sure it [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 is in your PATH or set the PKG_CONFIG environment variable to the full

View File

@@ -1,49 +0,0 @@
project('glorytun', 'c',
version: run_command('./version.sh').stdout(),
license: 'BSD-3-Clause',
default_options : [ 'buildtype=debugoptimized' ]
)
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')
src = [
'src/common.c',
'src/iface.c',
'src/option.c',
'src/tun.c',
'mud/mud.c',
'src/main.c'
]
deps = [
dependency('libsodium', version : '>=1.0.4')
]
executable('glorytun', install: true, sources: src, dependencies: deps)
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 mud deleted from 13cf44c813

66
src/buffer.h Normal file
View File

@@ -0,0 +1,66 @@
#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->data)
return;
if (buffer->read==buffer->write) {
buffer_format(buffer);
return;
}
const size_t size = buffer_read_size(buffer);
memmove(buffer->data, buffer->read, size);
buffer->read = buffer->data;
buffer->write = buffer->data+size;
}

View File

@@ -1,24 +1,22 @@
#include "common.h" #include "common.h"
#include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdarg.h>
int int gt_print (const char *fmt, ...)
gt_print(const char *fmt, ...)
{ {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
int ret = vfprintf(stdout, fmt, ap); int ret = vfprintf(stdout, fmt, ap);
va_end(ap); va_end(ap);
if (ret < 0) if (ret<0)
return 0; return 0;
return ret; return ret;
} }
void void gt_log (const char *fmt, ...)
gt_log(const char *fmt, ...)
{ {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
@@ -26,20 +24,34 @@ gt_log(const char *fmt, ...)
va_end(ap); va_end(ap);
} }
int void gt_fatal (const char *fmt, ...)
gt_tohex(char *dst, size_t dst_size, const uint8_t *src, size_t src_size)
{ {
if (_0_(!dst_size)) va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
exit(EXIT_FAILURE);
}
void gt_na (const char *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; return -1;
if (_0_(((dst_size - 1) / 2) < src_size)) if _0_(((dst_size-1)/2)<src_size)
return -1; return -1;
static const char tbl[] = "0123456789ABCDEF"; static const char tbl[] = "0123456789ABCDEF";
for (size_t i = 0; i < src_size; i++) { for (size_t i=0; i<src_size; i++) {
*dst++ = tbl[0xF & (src[i] >> 4)]; *dst++ = tbl[0xF&(src[i]>>4)];
*dst++ = tbl[0xF & (src[i])]; *dst++ = tbl[0xF&(src[i])];
} }
*dst = 0; *dst = 0;
@@ -47,38 +59,37 @@ gt_tohex(char *dst, size_t dst_size, const uint8_t *src, size_t src_size)
return 0; return 0;
} }
_const_ static inline int _const_
fromhex(const char c) static inline int fromhex (const char c)
{ {
if (c >= '0' && c <= '9') if (c>='0' && c<='9')
return c - '0'; return c-'0';
if (c >= 'A' && c <= 'F') if (c>='A' && c<='F')
return c - 'A' + 10; return c-'A'+10;
if (c >= 'a' && c <= 'f') if (c>='a' && c<='f')
return c - 'a' + 10; return c-'a'+10;
return -1; return -1;
} }
int int gt_fromhex (uint8_t *dst, size_t dst_size, const char *src, size_t src_size)
gt_fromhex(uint8_t *dst, size_t dst_size, const char *src, size_t src_size)
{ {
if (_0_(src_size & 1)) if _0_(src_size&1)
return -1; return -1;
if (_0_(dst_size < (src_size / 2))) if _0_(dst_size<(src_size/2))
return -1; return -1;
for (size_t i = 0; i < src_size; i += 2) { for (size_t i=0; i<src_size; i+=2) {
const int a = fromhex(src[i]); const int a = fromhex(src[i]);
const int b = fromhex(src[i + 1]); const int b = fromhex(src[i+1]);
if (_0_(a == -1 || b == -1)) if _0_(a==-1 || b==-1)
return -1; return -1;
*dst++ = (a << 4) | b; *dst++ = (a<<4)|b;
} }
return 0; return 0;

View File

@@ -29,14 +29,10 @@
#define _const_ __attribute__ ((const)) #define _const_ __attribute__ ((const))
#define _align_(...) __attribute__ ((aligned(__VA_ARGS__))) #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; })
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_na (const char *);
int gt_tohex (char *, size_t, const uint8_t *, size_t); int gt_tohex (char *, size_t, const uint8_t *, size_t);
int gt_fromhex (uint8_t *, size_t, const char *, size_t); int gt_fromhex (uint8_t *, size_t, const char *, size_t);

View File

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

View File

@@ -1,30 +0,0 @@
#include "common.h"
#include "str.h"
#include "iface.h"
#include <sys/ioctl.h>
#include <net/if.h>
int
iface_set_mtu(char *dev_name, int mtu)
{
struct ifreq ifr = {
.ifr_mtu = mtu,
};
str_cpy(ifr.ifr_name, dev_name, IFNAMSIZ - 1);
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd == -1)
return -1;
int ret = ioctl(fd, SIOCSIFMTU, &ifr);
int err = errno;
close(fd);
errno = err;
return ret;
}

View File

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

View File

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

1807
src/main.c

File diff suppressed because it is too large Load Diff

View File

@@ -3,10 +3,9 @@
#include "option.h" #include "option.h"
#include "str.h" #include "str.h"
int int option_str (void *data, int argc, char **argv)
option_str(void *data, int argc, char **argv)
{ {
if (argc < 2 || str_empty(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;
} }
@@ -16,10 +15,9 @@ option_str(void *data, int argc, char **argv)
return 1; return 1;
} }
int int option_long (void *data, int argc, char **argv)
option_long(void *data, int argc, char **argv)
{ {
if (argc < 2 || str_empty(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;
} }
@@ -28,7 +26,7 @@ option_long(void *data, int argc, char **argv)
char *end; char *end;
long val = strtol(argv[1], &end, 0); long val = strtol(argv[1], &end, 0);
if (errno || argv[1] == end) { if (errno || argv[1]==end) {
gt_print("argument `%s' is not a valid integer\n", argv[1]); gt_print("argument `%s' is not a valid integer\n", argv[1]);
return -1; return -1;
} }
@@ -38,10 +36,9 @@ option_long(void *data, int argc, char **argv)
return 1; return 1;
} }
int int option_is_set (struct option *opts, const char *name)
option_is_set(struct option *opts, const char *name)
{ {
for (int k = 0; opts[k].name; k++) { for (int k=0; opts[k].name; k++) {
if (!str_cmp(opts[k].name, name)) if (!str_cmp(opts[k].name, name))
return opts[k].set; return opts[k].set;
} }
@@ -49,21 +46,20 @@ option_is_set(struct option *opts, const char *name)
return 0; return 0;
} }
int int option_option (void *data, int argc, char **argv)
option_option(void *data, int argc, char **argv)
{ {
if (!data) if (!data)
return 0; return 0;
struct option *opts = (struct option *)data; struct option *opts = (struct option *)data;
for (int k = 0; opts[k].name; k++) for (int k=0; opts[k].name; k++)
opts[k].set = 0; opts[k].set = 0;
for (int i = 1; i < argc; i++) { for (int i=1; i<argc; i++) {
int found = 0; int found = 0;
for (int k = 0; opts[k].name; k++) { for (int k=0; opts[k].name; k++) {
if (str_cmp(opts[k].name, argv[i])) if (str_cmp(opts[k].name, argv[i]))
continue; continue;
@@ -72,9 +68,9 @@ option_option(void *data, int argc, char **argv)
return -1; return -1;
} }
int ret = opts[k].call(opts[k].data, argc - i, &argv[i]); int ret = opts[k].call(opts[k].data, argc-i, &argv[i]);
if (ret < 0) if (ret<0)
return -1; return -1;
opts[k].set = 1; opts[k].set = 1;
@@ -85,30 +81,29 @@ option_option(void *data, int argc, char **argv)
} }
if (!found) if (!found)
return i - 1; return i-1;
} }
return argc; return argc;
} }
static int static int option_usage (struct option *opts, int slen)
option_usage(struct option *opts, int slen)
{ {
if (!opts) if (!opts)
return 0; return 0;
int len = 0; int len = 0;
for (int k = 0; opts[k].name; k++) { for (int k=0; opts[k].name; k++) {
if (len > 40) { if (len>40) {
gt_print("\n%*s", slen, ""); gt_print("\n%*s", slen, "");
len = 0; len = 0;
} }
len += gt_print(" [%s", opts[k].name); len += gt_print(" [%s", opts[k].name);
if (opts[k].call == option_option) { if (opts[k].call==option_option) {
len += option_usage((struct option *)opts[k].data, slen + len); len += option_usage((struct option *)opts[k].data, slen+len);
} else { } else {
len += gt_print(" ARG"); len += gt_print(" ARG");
} }
@@ -119,22 +114,21 @@ option_usage(struct option *opts, int slen)
return len; return len;
} }
int int option (struct option *opts, int argc, char **argv)
option(struct option *opts, int argc, char **argv)
{ {
int ret = option_option(opts, argc, argv); int ret = option_option(opts, argc, argv);
if (ret == argc) if (ret==argc)
return 0; return 0;
if (ret < 0 || ret + 1 >= argc) if (ret<0 || ret+1>=argc)
return 1; return 1;
gt_print("option `%s' is unknown\n", argv[ret + 1]); gt_print("option `%s' is unknown\n", argv[ret+1]);
int slen = gt_print("usage: %s", argv[0]); int slen = gt_print("usage: %s", argv[0]);
if (slen > 40) { if (slen>40) {
slen = 12; slen = 12;
gt_print("\n%*s", slen, ""); gt_print("\n%*s", slen, "");
} }

62
src/state.c Normal file
View File

@@ -0,0 +1,62 @@
#include "common.h"
#include "state.h"
#include "str.h"
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
int state_create (const char *filename)
{
if (str_empty(filename))
return -1;
int fd = open(filename, O_WRONLY);
if (fd==-1) {
if (errno!=EINTR)
perror("open");
return -1;
}
struct stat st = {0};
if (fstat(fd, &st)==-1) {
perror("fstat");
close(fd);
return -1;
}
if (!S_ISFIFO(st.st_mode)) {
gt_log("`%s' is not a fifo\n", filename);
close(fd);
return -1;
}
return fd;
}
void state_send (int fd, const char *state, const char *info)
{
if (str_empty(state))
return;
if (fd==-1) {
gt_print("%s %s\n", state, info);
return;
}
const char *strs[] = { state, " ", info, "\n" };
char *str = str_cat(strs, COUNT(strs));
if (!str) {
perror("str_cat");
return;
}
if (write(fd, str, str_len(str))==-1 && errno!=EINTR)
perror("write");
free(str);
}

4
src/state.h Normal file
View File

@@ -0,0 +1,4 @@
#pragma once
int state_create (const char *);
void state_send (int, const char *, const char *);

View File

@@ -2,15 +2,14 @@
#include "common.h" #include "common.h"
static inline size_t static inline size_t str_cpy (char *restrict dst, const char *restrict src, size_t len)
str_cpy(char *restrict dst, const char *restrict src, size_t len)
{ {
if (!dst || !src) if (!dst || !src)
return 0; return 0;
size_t i; size_t i;
for (i = 0; i < len && src[i]; i++) for (i=0; i<len && src[i]; i++)
dst[i] = src[i]; dst[i] = src[i];
dst[i] = 0; dst[i] = 0;
@@ -18,29 +17,29 @@ str_cpy(char *restrict dst, const char *restrict src, size_t len)
return i; return i;
} }
_pure_ static inline int _pure_
str_empty(const char *restrict str) static inline int str_empty (const char *restrict str)
{ {
return !str || !str[0]; return !str || !str[0];
} }
_pure_ static inline size_t _pure_
str_cmp(const char *restrict sa, const char *restrict sb) static inline size_t str_cmp (const char *restrict sa, const char *restrict sb)
{ {
if (!sa || !sb) if (!sa || !sb)
return 1; return 1;
size_t i = 0; size_t i = 0;
while (sa[i] == sb[i]) while (sa[i]==sb[i])
if (!sa[i++]) if (!sa[i++])
return 0; return 0;
return i + 1; return i+1;
} }
_pure_ static inline size_t _pure_
str_len(const char *restrict str) static inline size_t str_len (const char *restrict str)
{ {
if (!str) if (!str)
return 0; return 0;
@@ -48,12 +47,11 @@ str_len(const char *restrict str)
return strlen(str); return strlen(str);
} }
static inline char * static inline char *str_cat (const char **strs, size_t count)
str_cat(const char **strs, size_t count)
{ {
size_t size = 1; size_t size = 1;
for (size_t i = 0; i < count; i++) for (size_t i=0; i<count; i++)
size += str_len(strs[i]); size += str_len(strs[i]);
char *str = malloc(size); char *str = malloc(size);
@@ -63,7 +61,7 @@ str_cat(const char **strs, size_t count)
char *p = str; char *p = str;
for (size_t i = 0; i < count; i++) { for (size_t i=0; i<count; i++) {
size_t len = str_len(strs[i]); size_t len = str_len(strs[i]);
memcpy(p, strs[i], len); memcpy(p, strs[i], len);
p += len; p += len;

167
src/tun.c
View File

@@ -1,29 +1,25 @@
#include "common.h" #include "common.h"
#include "ip.h"
#include "str.h"
#include "tun.h" #include "tun.h"
#include "str.h"
#include "ip.h"
#include <fcntl.h>
#include <stdio.h> #include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <net/if.h>
#ifdef __linux__ #ifdef __linux__
#define IFF_TUN 0x0001 #include <linux/if.h>
#define IFF_NO_PI 0x1000 #include <linux/if_tun.h>
#define TUNSETIFF _IOW('T', 202, int)
#define TUNSETPERSIST _IOW('T', 203, int)
#endif #endif
#ifdef __APPLE__ #ifdef __APPLE__
#include <net/if_utun.h>
#include <sys/kern_control.h>
#include <sys/sys_domain.h> #include <sys/sys_domain.h>
#include <sys/kern_control.h>
#include <net/if_utun.h>
#endif #endif
#if defined(__APPLE__) || defined(__OpenBSD__) #if defined(__APPLE__) || defined(__OpenBSD__)
@@ -32,23 +28,20 @@
#ifdef __APPLE__ #ifdef __APPLE__
static int static int tun_create_by_id (char *name, size_t size, unsigned id, _unused_ int mq)
tun_create_by_id(char *name, size_t size, unsigned id)
{ {
int fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); int fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
if (fd == -1) if (fd==-1)
return -1; return -1;
struct ctl_info ci; struct ctl_info ci;
memset(&ci, 0, sizeof(ci)); memset(&ci, 0, sizeof(ci));
str_cpy(ci.ctl_name, UTUN_CONTROL_NAME, sizeof(ci.ctl_name) - 1); str_cpy(ci.ctl_name, UTUN_CONTROL_NAME, sizeof(ci.ctl_name)-1);
if (ioctl(fd, CTLIOCGINFO, &ci)) { if (ioctl(fd, CTLIOCGINFO, &ci)) {
int err = errno;
close(fd); close(fd);
errno = err;
return -1; return -1;
} }
@@ -57,13 +50,11 @@ tun_create_by_id(char *name, size_t size, unsigned id)
.sc_len = sizeof(sc), .sc_len = sizeof(sc),
.sc_family = AF_SYSTEM, .sc_family = AF_SYSTEM,
.ss_sysaddr = AF_SYS_CONTROL, .ss_sysaddr = AF_SYS_CONTROL,
.sc_unit = id + 1, .sc_unit = id+1,
}; };
if (connect(fd, (struct sockaddr *)&sc, sizeof(sc))) { if (connect(fd, (struct sockaddr *)&sc, sizeof(sc))) {
int err = errno;
close(fd); close(fd);
errno = err;
return -1; return -1;
} }
@@ -72,132 +63,139 @@ tun_create_by_id(char *name, size_t size, unsigned id)
return fd; return fd;
} }
static int static int tun_create_by_name (char *name, size_t size, char *dev_name, int mq)
tun_create_by_name(char *name, size_t size, char *dev_name)
{ {
unsigned id = 0; unsigned id = 0;
if (sscanf(dev_name, "utun%u", &id) != 1) { if (sscanf(dev_name, "utun%u", &id)!=1)
errno = EINVAL;
return -1; return -1;
}
return tun_create_by_id(name, size, id); return tun_create_by_id(name, size, id, mq);
} }
#else /* not __APPLE__ */ #else /* not __APPLE__ */
#ifdef __linux__ #ifdef __linux__
static int static int tun_create_by_name (char *name, size_t size, char *dev_name, int mq)
tun_create_by_name(char *name, size_t size, char *dev_name)
{ {
int fd = open("/dev/net/tun", O_RDWR); int fd = open("/dev/net/tun", O_RDWR);
if (fd == -1) if (fd==-1)
return -1; return -1;
struct ifreq ifr = { struct ifreq ifr = {
.ifr_flags = IFF_TUN | IFF_NO_PI, .ifr_flags = IFF_TUN|IFF_NO_PI,
}; };
str_cpy(ifr.ifr_name, dev_name, IFNAMSIZ - 1); if (mq) {
#ifdef IFF_MULTI_QUEUE
ifr.ifr_flags |= IFF_MULTI_QUEUE;
#endif
}
str_cpy(ifr.ifr_name, dev_name, IFNAMSIZ-1);
if (ioctl(fd, TUNSETIFF, &ifr)) { if (ioctl(fd, TUNSETIFF, &ifr)) {
close(fd); close(fd);
return -1; return -1;
} }
str_cpy(name, ifr.ifr_name, size - 1); str_cpy(name, ifr.ifr_name, size-1);
return fd; return fd;
} }
#else /* not __linux__ not __APPLE__ */ #else /* not __linux__ not __APPLE__ */
static int static int tun_create_by_name (char *name, size_t size, char *dev_name, _unused_ int mq)
tun_create_by_name(char *name, size_t size, char *dev_name)
{ {
char path[64]; char path[64];
snprintf(path, sizeof(path), "/dev/%s", dev_name); snprintf(path, sizeof(path), "/dev/%s", dev_name);
str_cpy(name, dev_name, size - 1); str_cpy(name, dev_name, size-1);
return open(path, O_RDWR); return open(path, O_RDWR);
} }
#endif /* not __APPLE__ */ #endif /* not __APPLE__ */
static int static int tun_create_by_id (char *name, size_t size, unsigned id, int mq)
tun_create_by_id(char *name, size_t size, unsigned id)
{ {
char dev_name[64]; char dev_name[64];
snprintf(dev_name, sizeof(dev_name), "tun%u", id); snprintf(dev_name, sizeof(dev_name), "tun%u", id);
return tun_create_by_name(name, size, dev_name); return tun_create_by_name(name, size, dev_name, mq);
} }
#endif #endif
int int tun_create (char *dev_name, char **ret_name, int mq)
tun_create(char *dev_name, char **ret_name)
{ {
char name[64] = {0}; char name[64] = {0};
int fd = -1; int fd = -1;
#ifndef IFF_MULTI_QUEUE
if (mq)
gt_na("IFF_MULTI_QUEUE");
#endif
if (str_empty(dev_name)) { if (str_empty(dev_name)) {
for (unsigned id = 0; id < 32 && fd == -1; id++) for (unsigned id=0; id<32 && fd==-1; id++)
fd = tun_create_by_id(name, sizeof(name), id); fd = tun_create_by_id(name, sizeof(name), id, mq);
} else { } else {
fd = tun_create_by_name(name, sizeof(name), dev_name); fd = tun_create_by_name(name, sizeof(name), dev_name, mq);
} }
if (fd != -1 && ret_name) if (fd!=-1 && ret_name)
*ret_name = strdup(name); *ret_name = strdup(name);
return fd; return fd;
} }
int ssize_t tun_read (int fd, void *data, size_t size)
tun_read(int fd, void *data, size_t size)
{ {
if (!size) if (!size)
return 0; return -1;
#ifdef GT_BSD_TUN #ifdef GT_BSD_TUN
uint32_t family; uint32_t family;
struct iovec iov[2] = { struct iovec iov[2] = {
{ { .iov_base = &family, .iov_len = sizeof(family) },
.iov_base = &family, { .iov_base = data, .iov_len = size }
.iov_len = sizeof(family),
},
{
.iov_base = data,
.iov_len = size,
},
}; };
ssize_t ret = readv(fd, iov, 2); ssize_t ret = readv(fd, iov, 2);
#else
ssize_t ret = read(fd, data, size);
#endif
if (ret <= (ssize_t)0) if (ret==-1) {
return ret; if (errno==EAGAIN || errno==EINTR)
return -1;
if (ret <= (ssize_t)sizeof(family)) if (errno)
perror("tun read");
return 0;
}
#ifdef GT_BSD_TUN
if (ret<(ssize_t) sizeof(family))
return 0; return 0;
return ret - sizeof(family); return ret-sizeof(family);
#else #else
return read(fd, data, size); return ret;
#endif #endif
} }
int ssize_t tun_write (int fd, const void *data, size_t size)
tun_write(int fd, const void *data, size_t size)
{ {
if (!size) if (!size)
return 0; return -1;
#ifdef GT_BSD_TUN #ifdef GT_BSD_TUN
uint32_t family; uint32_t family;
@@ -210,42 +208,35 @@ tun_write(int fd, const void *data, size_t size)
family = htonl(AF_INET6); family = htonl(AF_INET6);
break; break;
default: default:
errno = EINVAL;
return -1; return -1;
} }
struct iovec iov[2] = { struct iovec iov[2] = {
{ { .iov_base = &family, .iov_len = sizeof(family) },
.iov_base = &family, { .iov_base = (void *) data, .iov_len = size },
.iov_len = sizeof(family),
},
{
.iov_base = (void *)data,
.iov_len = size,
},
}; };
ssize_t ret = writev(fd, iov, 2); ssize_t ret = writev(fd, iov, 2);
#else
ssize_t ret = write(fd, data, size);
#endif
if (ret <= (ssize_t)0) if (ret==-1) {
return ret; if (errno==EAGAIN || errno==EINTR)
return -1;
if (ret <= (ssize_t)sizeof(family)) if (errno)
perror("tun write");
return 0;
}
#ifdef GT_BSD_TUN
if (ret<(ssize_t) sizeof(family))
return 0; return 0;
return ret - sizeof(family); return ret-sizeof(family);
#else #else
return write(fd, data, size); return ret;
#endif
}
int
tun_set_persist(int fd, int on)
{
#ifdef TUNSETPERSIST
return ioctl(fd, TUNSETPERSIST, on);
#else
errno = ENOSYS;
return -1;
#endif #endif
} }

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
int tun_create (char *, char **); #include <unistd.h>
int tun_read (int, void *, size_t);
int tun_write (int, const void *, size_t); int tun_create (char *, char **, int);
int tun_set_persist (int, int); ssize_t tun_read (int, void *, size_t);
ssize_t tun_write (int, const void *, size_t);

View File

@@ -1,10 +0,0 @@
[Match]
Name=gtc-*
[Network]
Description=Glorytun client device
DHCP=ipv4
[DHCP]
CriticalConnection=yes
RouteTable=200

View File

@@ -1,37 +0,0 @@
#!/bin/sh
set -e
if [ ! -f "$1" ]; then
echo "usage: $(basename "$0") FILE"
exit 1
fi
. "$(readlink -f "$1")"
DEV="gt${HOST:+c}-$(basename "$1")"
# Setting BIND is like going to 'expert mode'
# This helper is pretty stupid and still needs some work
if [ -n "$HOST" ]; then
if [ -z "$PREF" ]; then
PREF=$(ip rule | awk '/from all lookup main/{print $1; exit}' | tr -d :)
PREF=$((PREF-1))
fi
if [ -z "$BIND" ]; then
BIND=$(ip route get "$HOST" | awk '/src/{getline;print $0}' RS=' ')
ip rule add from "$BIND" table main pref "$((PREF-1))" || true
fi
ip rule add from all table 200 pref "$PREF" || true
fi
exec glorytun \
v4only \
keyfile "$1".key \
dev "$DEV" \
${HOST:+host "$HOST"} \
${PORT:+port "$PORT"} \
${BIND:+bind "$BIND"} \
${BIND_PORT:+bind-port "$BIND_PORT"} \
${MTU:+mtu "$MTU"} \
${MTU_AUTO:+mtu-auto}

View File

@@ -1,41 +0,0 @@
#!/bin/sh
set -e
_ask() {
printf "%s: " "$1"
read -r "$2"
}
_ask "Config filename (tun0)" NAME
NAME=${NAME:-tun0}
if [ -f /etc/glorytun/"$NAME" ]; then
echo "This config already exit!"
exit 1
fi
_ask "Server ip (enter for server conf)" HOST
_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 /etc/glorytun
cat > /etc/glorytun/"$NAME" <<EOF
${HOST:+HOST="$HOST"}
MTU_AUTO=yes
EOF
( umask 077; echo "$KEY" > /etc/glorytun/"$NAME".key )
# start services
_ask "Start glorytun now ? (enter to skip)" START
case "$START" in y*|Y*)
systemctl restart systemd-networkd
systemctl start glorytun@"$NAME" ;;
esac

View File

@@ -1,14 +0,0 @@
[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

View File

@@ -1,12 +0,0 @@
[Unit]
Description=Glorytun on %I
After=network.target
[Service]
Type=simple
Restart=always
ExecStart=@bindir@/glorytun-run /etc/glorytun/%i
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW
[Install]
WantedBy=multi-user.target