Compare commits

..

19 Commits

Author SHA1 Message Date
Adrien Gallouët
0a797b4f5f Try value 42 for mptcp (fallback to 26) 2017-06-07 11:27:44 +02:00
Adrien Gallouët
8cb849fbc3 Update pkg.m4 2017-06-07 11:26:22 +02:00
Adrien Gallouët
13f9f4c896 Fix printf format 2016-07-20 15:32:22 +00:00
Adrien Gallouët
cfd7af9241 Add .build.sh 2016-07-11 11:13:29 +00:00
Adrien Gallouët
c81592fcc5 Don't fd_set_nonblock(-1) 2016-06-23 12:15:01 +00:00
Adrien Gallouët
b4a311cdc8 Check for clock_gettime() 2016-06-15 14:12:21 +00:00
Adrien Gallouët
08617d0017 Fix macosx build 2016-06-15 14:01:20 +00:00
Adrien Gallouët
38cd3b0371 Try to do a more accurate bench 2016-06-15 09:20:18 +00:00
Adrien Gallouët
5944e61dfe Fix bench output 2016-06-15 09:10:57 +00:00
Adrien Gallouët
585b2b08bc Be more verbose on kx errors 2016-06-06 13:37:05 +00:00
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
19 changed files with 1846 additions and 598 deletions

View File

@@ -11,8 +11,5 @@ cd ..
[ -x glorytun ] || exit 1 [ -x glorytun ] || exit 1
mkdir -p deploy mkdir -p deploy
cp glorytun deploy/glorytun-$(cat VERSION)-$(uname -m).debug.bin
strip -s glorytun strip -s glorytun
cp glorytun deploy/glorytun-$(cat VERSION)-$(uname -m).bin mv glorytun deploy/glorytun-$(cat VERSION)-$(uname -m).bin

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 \
@@ -15,11 +16,9 @@ glorytun_SOURCES = \
src/tun.c \ src/tun.c \
src/tun.h \ src/tun.h \
src/db.c \ src/db.c \
src/db.h src/db.h \
src/state.c \
glorytun_SOURCES += \ src/state.h
mud/mud.h \
mud/mud.c
EXTRA_DIST = \ EXTRA_DIST = \
LICENSE \ LICENSE \

View File

@@ -1,6 +1,10 @@
# π₁(Glorytun)=0 # π₁(Glorytun)=ℤ²
Small, Simple and Stupid VPN over [mud](https://github.com/angt/mud). Small, Simple and Stupid TCP VPN.
#### Work In Progress
This code will probably format your harddisk!
#### Build and Install #### Build and Install
@@ -8,7 +12,7 @@ Glorytun depends on [libsodium](https://github.com/jedisct1/libsodium) version >
To build and install the latest version: To build and install the latest version:
$ git clone https://github.com/angt/glorytun --recursive --branch mud $ git clone https://github.com/angt/glorytun
$ cd glorytun $ cd glorytun
$ ./autogen.sh $ ./autogen.sh
$ ./configure $ ./configure

View File

@@ -14,6 +14,7 @@ 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_LIB([rt], [clock_gettime])
AC_CHECK_FUNCS([clock_gettime]) AC_CHECK_FUNCS([clock_gettime])

View File

@@ -1,6 +1,6 @@
dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
dnl serial 11 (pkg-config-0.29) # serial 12 (pkg-config-0.29.2)
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]) [m4_define([PKG_MACROS_VERSION], [0.29.2])
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 $1]) AC_MSG_CHECKING([for $2])
_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

1
mud

Submodule mud deleted from f67eae0a7f

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,8 +24,7 @@ gt_log(const char *fmt, ...)
va_end(ap); va_end(ap);
} }
void void gt_fatal (const char *fmt, ...)
gt_fatal(const char *fmt, ...)
{ {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
@@ -37,26 +34,24 @@ gt_fatal(const char *fmt, ...)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
void void gt_na (const char *name)
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 int gt_tohex (char *dst, size_t dst_size, const uint8_t *src, size_t src_size)
gt_tohex(char *dst, size_t dst_size, const uint8_t *src, size_t src_size)
{ {
if (_0_(!dst_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;
@@ -64,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,12 +29,6 @@
#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_fatal (const char *, ...) _printf_(1,2) _noreturn_;

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

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

1829
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;

178
src/tun.c
View File

@@ -1,28 +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)
#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__)
@@ -31,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;
} }
@@ -56,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;
} }
@@ -71,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;
@@ -209,54 +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 #endif
} }
int
tun_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,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_mtu (char *, int); ssize_t tun_read (int, void *, size_t);
ssize_t tun_write (int, const void *, size_t);