Compare commits

...

36 Commits

Author SHA1 Message Date
angt
eefa7722c5 Use timeout in connect() too 2016-01-21 16:22:31 +01:00
angt
17547f555d Add SECRETKEY state 2016-01-18 18:07:35 +01:00
angt
ec9c59ce69 Code cleanup 2016-01-18 18:00:41 +01:00
angt
679927a684 Show device name in INITIALIZED state 2016-01-18 17:58:20 +01:00
angt
2999faf5d7 Move up state_init() 2016-01-18 17:26:42 +01:00
angt
219384b7e5 Remove the old school daemon option 2016-01-18 16:09:29 +01:00
angt
3649e46b03 Remove the absolute path restriction on statefile 2016-01-18 16:02:29 +01:00
angt
88f314bc75 Add state.[ch] 2016-01-18 15:59:18 +01:00
angt
e2b3dc1b46 Use only v[0-9].* tags to get VERSION 2016-01-17 10:56:55 +01:00
angt
1815ea519f Create a tcp_entry only on ACK 2016-01-17 10:18:39 +01:00
angt
33356d5d35 Don't work too much 2016-01-17 09:40:56 +01:00
angt
4a5d07ec45 Merge pull request #11 from jedisct1/notag
Cope with branches that don't have tags
2016-01-16 16:16:05 +01:00
Frank Denis
a50882e1ac Cope with branches that don't have tags
`version.sh` used to return only the hash of the last commit, causing
VERSION_MAJOR to possibly contain non-numeric junk.
2016-01-16 15:37:42 +01:00
angt
b2cb8ebcbe The minimum value for buffer-size option is GT_PKT_MAX 2016-01-15 17:02:11 +01:00
angt
6fd6cf8c4a Merge pull request #10 from jedisct1/socket
Include <sys/socket.h> for AF_INET/AF_INET6 definitions
2016-01-14 17:14:56 +01:00
Frank Denis
f0fc2751e5 Include <sys/socket.h> for AF_INET/AF_INET6 definitions
Required on OpenBSD
2016-01-14 17:11:27 +01:00
angt
81cab007d0 Resend packet on partial tun_write() 2016-01-14 10:25:37 +01:00
angt
606396839f Don't update sa->base with old acks 2016-01-14 09:27:15 +01:00
angt
a8e37bafb9 Use realloc(): easier, better, faster, stronger 2016-01-13 16:19:58 +01:00
angt
87a38012cd Don't forget to free() seq_elem 2016-01-13 16:16:05 +01:00
angt
f04816e9a5 Try to detect TCP retransmission 2016-01-12 18:07:58 +01:00
angt
7107d036b1 Code cleanup 2016-01-07 08:30:21 +01:00
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
16 changed files with 766 additions and 451 deletions

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,19 +6,23 @@ 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.c \
src/db.h src/db.h \
src/state.c \
src/state.h
EXTRA_DIST = \ EXTRA_DIST = \
LICENSE \ LICENSE \
README.md \ README.md \
autogen.sh \ VERSION \
version.sh autogen.sh \
version.sh

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,155 +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)
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;
}
_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;
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;
}
_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) {
byte_cpy(buffer->data, src, size);
buffer->read -= src-buffer->data;
buffer->write -= src-buffer->data;
}
}
}

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)
@@ -26,15 +29,6 @@
#define _const_ __attribute__ ((const)) #define _const_ __attribute__ ((const))
#define _align_(...) __attribute__ ((aligned(__VA_ARGS__))) #define _align_(...) __attribute__ ((aligned(__VA_ARGS__)))
typedef struct buffer buffer_t;
struct buffer {
uint8_t *data;
uint8_t *read;
uint8_t *write;
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_;

View File

@@ -1,5 +1,7 @@
#include "common.h"
#include "db.h" #include "db.h"
#include "common-static.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))

View File

@@ -1,57 +0,0 @@
#pragma once
#include <stdint.h>
_pure_
static inline int ip_get_version (const uint8_t *data, size_t size)
{
if (size<20) // XXX
return -1; // XXX
return data[0]>>4;
}
_pure_
static inline ssize_t ip_get_size (const int ip_version, const uint8_t *data, size_t size)
{
switch (ip_version) {
case 4:
return ((data[2]<<8)|data[3]);
case 6:
return ((data[4]<<8)|data[5])+40;
case -1:
return -1;
}
return 0;
}
_pure_
static inline ssize_t ip_get_proto (const int ip_version, const uint8_t *data, size_t size)
{
switch (ip_version) {
case 4:
return data[9];
case 6:
return data[6];
case -1:
return -1;
}
return 0;
}
_pure_
static inline ssize_t ip_get_hdr_size (const int ip_version, const uint8_t *data, size_t size)
{
switch (ip_version) {
case 4:
return (data[0]&0xF)<<2;
case 6:
return 40;
case -1:
return -1;
}
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,12 +1,21 @@
#include "common.h"
#include "buffer.h"
#include "ip.h"
#include "str.h"
#include "option.h"
#include "tun.h"
#include "db.h"
#include "state.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 <string.h>
#include <poll.h> #include <poll.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#ifndef __FAVOR_BSD #ifndef __FAVOR_BSD
#define __FAVOR_BSD #define __FAVOR_BSD
@@ -27,21 +36,18 @@
#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_MTU_MAX (1500)
#define GT_TIMEOUT (5000) #define GT_PKT_MAX (32*1024)
#define GT_MTU_MAX (1500) #define GT_TUNR_SIZE (GT_PKT_MAX-16-2)
#define GT_TUNR_SIZE (0x7FFF-16) #define GT_TUNW_SIZE (GT_PKT_MAX)
#define GT_TUNW_SIZE (0x7FFF)
static struct {
int timeout;
} gt;
struct fdbuf { struct fdbuf {
int fd; int fd;
@@ -49,11 +55,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;
@@ -102,6 +103,7 @@ enum sk_opt {
sk_defer_accept, sk_defer_accept,
sk_acceptfilter, 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)
@@ -151,6 +153,11 @@ static void sk_set (int fd, enum sk_opt opt, const void *val, socklen_t len)
[sk_acceptfilter] = { "SO_ACCEPTFILTER", [sk_acceptfilter] = { "SO_ACCEPTFILTER",
#ifdef SO_ACCEPTFILTER #ifdef SO_ACCEPTFILTER
1, SOL_SOCKET, 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
}, },
}; };
@@ -184,10 +191,9 @@ static int sk_listen (int fd, struct addrinfo *ai)
} }
#ifdef __linux__ #ifdef __linux__
sk_set_int(fd, sk_defer_accept, GT_TIMEOUT/1000); sk_set_int(fd, sk_defer_accept, gt.timeout/1000);
#else #else
char data[256] = {0}; char data[256] = "dataready";
str_cpy(data, "dataready", sizeof(data)-1);
sk_set(fd, sk_acceptfilter, &data, sizeof(data)); sk_set(fd, sk_acceptfilter, &data, sizeof(data));
#endif #endif
@@ -196,10 +202,34 @@ static int sk_listen (int fd, struct addrinfo *ai)
static int sk_connect (int fd, struct addrinfo *ai) static int sk_connect (int fd, struct addrinfo *ai)
{ {
fd_set_nonblock(fd);
int ret = connect(fd, ai->ai_addr, ai->ai_addrlen); int ret = connect(fd, ai->ai_addr, ai->ai_addrlen);
if (ret==-1 && errno==EINTR) if (ret==-1) {
return 0; if (errno==EINTR)
return 0;
if (errno==EINPROGRESS) {
struct pollfd pollfd = {
.fd = fd,
.events = POLLOUT,
};
if (!poll(&pollfd, 1, gt.timeout))
return -1;
int opt = 0;
socklen_t optlen = sizeof(opt);
getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &optlen);
if (!opt)
return 0;
errno = opt;
}
}
return ret; return ret;
} }
@@ -231,6 +261,8 @@ static int sk_accept (int fd)
if (ret==-1 && errno!=EINTR) if (ret==-1 && errno!=EINTR)
perror("accept"); perror("accept");
fd_set_nonblock(ret);
return ret; return ret;
} }
@@ -262,7 +294,7 @@ static char *sk_get_name (int fd)
return NULL; return NULL;
} }
const char *const strs[] = { const char *strs[] = {
host, ".", port host, ".", port
}; };
@@ -271,7 +303,7 @@ static char *sk_get_name (int fd)
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;
} }
@@ -384,11 +416,6 @@ static ssize_t fd_write (int fd, const void *data, size_t size)
return ret; return ret;
} }
static ssize_t fd_write_str (int fd, const char *str)
{
return fd_write(fd, str, str_len(str));
}
static size_t fd_read_all (int fd, void *data, size_t size) static size_t fd_read_all (int fd, void *data, size_t size)
{ {
size_t done = 0; size_t done = 0;
@@ -405,7 +432,7 @@ static size_t fd_read_all (int fd, void *data, size_t size)
.events = POLLIN, .events = POLLIN,
}; };
if (!poll(&pollfd, 1, GT_TIMEOUT)) if (!poll(&pollfd, 1, gt.timeout))
break; break;
continue; continue;
@@ -433,7 +460,7 @@ static size_t fd_write_all (int fd, const void *data, size_t size)
.events = POLLOUT, .events = POLLOUT,
}; };
if (!poll(&pollfd, 1, GT_TIMEOUT)) if (!poll(&pollfd, 1, gt.timeout))
break; break;
continue; continue;
@@ -533,20 +560,256 @@ static inline uint16_t sum16_final (uint32_t sum)
return ~(sum+(sum>>16)); return ~(sum+(sum>>16));
} }
static void gt_print_hdr (const int ip_version, uint8_t *data, size_t ip_size) struct seq_elem {
{ uint32_t seq;
const ssize_t ip_proto = ip_get_proto(ip_version, data, ip_size); uint32_t size;
const ssize_t ip_hdr_size = ip_get_hdr_size(ip_version, data, ip_size); };
if (ip_proto<0 || ip_hdr_size<=0) struct seq_array {
struct seq_elem *elem;
uint32_t count;
uint32_t base;
};
struct tcp_entry {
uint8_t key[37];
struct {
struct seq_array sa;
size_t retrans;
} data[2];
};
void tcp_entry_free (struct tcp_entry *te)
{
free(te->data[0].sa.elem);
free(te->data[1].sa.elem);
free(te);
}
void sa_insert_elem (struct seq_array *sa, uint32_t i, uint32_t seq, uint32_t size)
{
if (sa->count<i)
return; return;
uint32_t sum = (size_t)ip_proto+ip_size-(size_t)ip_hdr_size; if (!(sa->count&7)) {
struct seq_elem *tmp = realloc(sa->elem, (sa->count+8)*sizeof(struct seq_elem));
if (!tmp) {
gt_log("couldn't realloc!\n");
return;
}
sa->elem = tmp;
}
memmove(&sa->elem[i+1], &sa->elem[i], (sa->count-i)*sizeof(struct seq_elem));
sa->elem[i].seq = seq;
sa->elem[i].size = size;
sa->count++;
}
void sa_remove_elem (struct seq_array *sa, uint32_t i)
{
if (sa->count<i+1)
return;
sa->count--;
memmove(&sa->elem[i], &sa->elem[i+1], (sa->count-i)*sizeof(struct seq_elem));
}
int sa_have (struct seq_array *sa, uint32_t seq, uint32_t size)
{
uint32_t i;
uint32_t seqa = seq-sa->base;
for (i=0; i<sa->count; i++) {
uint32_t seqb = sa->elem[i].seq-sa->base;
if (seqb>=seqa) {
uint32_t d = seqb-seqa;
if (d>size)
return 0;
} else {
uint32_t d = seqa-seqb;
if (d>=sa->elem[i].size)
continue;
if (d+size>sa->elem[i].size) {
gt_print("sa_have:part\n");
return 0; // XXX 0
}
}
return 1;
}
return 0;
}
void sa_rebase (struct seq_array *sa, uint32_t seq)
{
if (!sa->count)
return;
if (seq==sa->base)
return;
uint32_t size = seq-sa->elem[0].seq;
if (size==sa->elem[0].size) {
sa_remove_elem(sa, 0);
} else {
if (size>sa->elem[0].size)
return;
sa->elem[0].seq = seq;
sa->elem[0].size -= size;
}
sa->base = seq;
}
void sa_insert (struct seq_array *sa, uint32_t seq, uint32_t size)
{
uint32_t i;
uint32_t seqa = seq-sa->base;
for (i=0; i<sa->count; i++) {
uint32_t seqb = sa->elem[i].seq-sa->base;
if (seqb>=seqa) {
uint32_t d = seqb-seqa;
if (d>size)
break;
sa->elem[i].seq = seq;
uint32_t new_size = sa->elem[i].size+d;
if (new_size>size) {
sa->elem[i].size = new_size;
} else {
sa->elem[i].size = size;
}
} else {
uint32_t d = seqa-seqb;
if (d>sa->elem[i].size)
continue;
uint32_t new_size = size+d;
if (new_size>sa->elem[i].size)
sa->elem[i].size = new_size;
}
if (i+1<sa->count) {
if (seqb+sa->elem[i].size==sa->elem[i+1].seq-sa->base) {
sa->elem[i].size += sa->elem[i+1].size;
sa_remove_elem(sa, i+1);
}
}
return;
}
sa_insert_elem(sa, i, seq, size);
}
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;
}
memcpy(&key[size], &data[ic->hdr_size], 4);
te->key[0] = size+4;
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 void gt_print_entry (struct tcp_entry *te)
{
uint8_t *key = &te->key[1];
size_t size = te->key[0];
char ip0[INET6_ADDRSTRLEN];
char ip1[INET6_ADDRSTRLEN];
uint16_t port0, port1;
switch (size) {
case 8+4:
inet_ntop(AF_INET, key, ip0, sizeof(ip0));
inet_ntop(AF_INET, key+4, ip1, sizeof(ip1));
port0 = (key[8]<<8)|key[9];
port1 = (key[10]<<8)|key[11];
break;
case 32+4:
inet_ntop(AF_INET6, key, ip0, sizeof(ip0));
inet_ntop(AF_INET6, key+16, ip1, sizeof(ip1));
port0 = (key[32]<<8)|key[33];
port1 = (key[34]<<8)|key[35];
break;
}
gt_print("connection:%s.%hu-%s.%hu\t"
"retrans:%zu, %zu\n",
ip0, port0, ip1, port1,
te->data[0].retrans,
te->data[1].retrans);
}
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_src[INET6_ADDRSTRLEN];
char ip_dst[INET6_ADDRSTRLEN]; char ip_dst[INET6_ADDRSTRLEN];
switch (ip_version) { switch (ic->version) {
case 4: case 4:
inet_ntop(AF_INET, &data[12], ip_src, sizeof(ip_src)); inet_ntop(AF_INET, &data[12], ip_src, sizeof(ip_src));
inet_ntop(AF_INET, &data[16], ip_dst, sizeof(ip_dst)); inet_ntop(AF_INET, &data[16], ip_dst, sizeof(ip_dst));
@@ -559,16 +822,18 @@ static void gt_print_hdr (const int ip_version, uint8_t *data, size_t ip_size)
break; break;
} }
if (ip_proto==IPPROTO_TCP) { uint8_t *const packet = &data[ic->hdr_size];
if (ic->proto==IPPROTO_TCP) {
struct tcphdr tcp; struct tcphdr tcp;
byte_cpy(&tcp, &data[ip_hdr_size], sizeof(tcp)); memcpy(&tcp, packet, sizeof(tcp));
uint16_t tcp_sum = ntohs(tcp.th_sum); uint16_t tcp_sum = ntohs(tcp.th_sum);
tcp.th_sum = 0; tcp.th_sum = 0;
sum = sum16(sum, (uint8_t *)&tcp, sizeof(tcp)); sum = sum16(sum, (uint8_t *)&tcp, sizeof(tcp));
sum = sum16(sum, &data[ip_hdr_size+sizeof(tcp)], ip_size-ip_hdr_size-sizeof(tcp)); sum = sum16(sum, &packet[sizeof(tcp)], ic->size-ic->hdr_size-sizeof(tcp));
uint16_t computed_sum = sum16_final(sum); uint16_t computed_sum = sum16_final(sum);
tcp.th_sport = ntohs(tcp.th_sport); tcp.th_sport = ntohs(tcp.th_sport);
@@ -577,9 +842,9 @@ static void gt_print_hdr (const int ip_version, uint8_t *data, size_t ip_size)
tcp.th_ack = ntohl(tcp.th_ack); tcp.th_ack = ntohl(tcp.th_ack);
tcp.th_win = ntohs(tcp.th_win); tcp.th_win = ntohs(tcp.th_win);
gt_print("proto:%zi\tsrc:%s.%u\tdst:%s.%u\tseq:%u\tack:%u\twin:%u\tsize:%zu\tflags:%c%c%c%c%c%c\tsum:%i\n", 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",
ip_proto, ip_src, tcp.th_sport, ip_dst, tcp.th_dport, ic->proto, ip_src, tcp.th_sport, ip_dst, tcp.th_dport,
tcp.th_seq, tcp.th_ack, tcp.th_win, ip_size-ip_hdr_size+tcp.th_off*4, 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_FIN) ?'F':'.',
(tcp.th_flags&TH_SYN) ?'S':'.', (tcp.th_flags&TH_SYN) ?'S':'.',
(tcp.th_flags&TH_RST) ?'R':'.', (tcp.th_flags&TH_RST) ?'R':'.',
@@ -588,34 +853,105 @@ static void gt_print_hdr (const int ip_version, uint8_t *data, size_t ip_size)
(tcp.th_flags&TH_URG) ?'U':'.', (tcp.th_flags&TH_URG) ?'U':'.',
(computed_sum==tcp_sum)); (computed_sum==tcp_sum));
} else if (ip_proto==IPPROTO_UDP) { } else if (ic->proto==IPPROTO_UDP) {
struct udphdr udp; struct udphdr udp;
byte_cpy(&udp, &data[ip_hdr_size], sizeof(udp)); memcpy(&udp, packet, sizeof(udp));
udp.uh_sport = ntohs(udp.uh_sport); udp.uh_sport = ntohs(udp.uh_sport);
udp.uh_dport = ntohs(udp.uh_dport); udp.uh_dport = ntohs(udp.uh_dport);
udp.uh_ulen = ntohs(udp.uh_ulen); udp.uh_ulen = ntohs(udp.uh_ulen);
gt_print("proto:%zi\tsrc:%s.%u\tdst:%s.%u\tsize:%u\n", gt_print("proto:%hhu\tsrc:%s.%u\tdst:%s.%u\tsize:%u\n",
ip_proto, ip_src, udp.uh_sport, ip_dst, udp.uh_dport, udp.uh_ulen-8); ic->proto, ip_src, udp.uh_sport, ip_dst, udp.uh_dport, udp.uh_ulen-8);
} else { } else {
gt_print("proto:%zi\tsrc:%s\tdst:%s\tsize:%zu\n", gt_print("proto:%hhu\tsrc:%s\tdst:%s\tsize:%hu\n",
ip_proto, ip_src, ip_dst, ip_size); ic->proto, ip_src, ip_dst, ic->size);
} }
} }
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 (tcp.th_flags&(TH_FIN|TH_RST)) {
if (r_entry) {
gt_print_entry(r_entry);
db_remove(db, entry.key);
tcp_entry_free(r_entry);
}
return 0;
}
if (tcp.th_flags&TH_ACK) {
if (!r_entry) {
r_entry = calloc(1, sizeof(entry));
if (!r_entry)
return 0;
memcpy(r_entry->key, entry.key, sizeof(entry.key));
if (!db_insert(db, r_entry->key)) {
free(r_entry);
return 0;
}
gt_print_entry(r_entry);
r_entry->data[1-rev].sa.base = tcp.th_ack;
r_entry->data[rev].sa.base = tcp.th_seq;
} else {
sa_rebase(&r_entry->data[1-rev].sa, tcp.th_ack);
}
}
if (!r_entry)
return 0;
uint32_t size = ic->size-ic->hdr_size-tcp.th_off*4;
if (!size)
return 0;
if (sa_have(&r_entry->data[rev].sa, tcp.th_seq, size)) {
r_entry->data[rev].retrans++;
} else {
sa_insert(&r_entry->data[rev].sa, tcp.th_seq, size);
}
return 0;
}
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);
if (!keyfile) { if (str_empty(keyfile)) {
char buf[2*size+1]; char buf[2*size+1];
randombytes_buf(ctx->skey, size); randombytes_buf(ctx->skey, size);
gt_tohex(buf, sizeof(buf), ctx->skey, size); gt_tohex(buf, sizeof(buf), ctx->skey, size);
state("SECRETKEY", buf);
gt_print("new secret key: %s\n", buf);
return 0; return 0;
} }
@@ -669,13 +1005,13 @@ static int gt_setup_crypto (struct crypto_ctx *ctx, int fd, int listener)
crypto_generichash_state state; crypto_generichash_state state;
byte_set(data_w, 0, size); 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);
byte_cpy(&data_w[size-hash_size-sizeof(gt)], gt, sizeof(gt)); 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));
@@ -734,8 +1070,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;
} }
@@ -751,7 +1087,7 @@ int main (int argc, char **argv)
char *congestion = NULL; char *congestion = NULL;
char *statefile = NULL; char *statefile = NULL;
long buffer_size = GT_BUFFER_SIZE; long buffer_size = GT_PKT_MAX;
long ka_count = -1; long ka_count = -1;
long ka_idle = -1; long ka_idle = -1;
@@ -762,6 +1098,8 @@ int main (int argc, char **argv)
long retry_const = 0; long retry_const = 0;
long retry_limit = 1000000; long retry_limit = 1000000;
gt.timeout = 5000;
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 },
@@ -778,22 +1116,22 @@ 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 }, { "statefile", &statefile, option_str },
{ "statefile", &statefile, option_str }, { "timeout", &gt.timeout, option_long },
{ "debug", NULL, option_option }, { "debug", NULL, option_option },
{ "version", NULL, option_option }, { "version", NULL, option_option },
{ NULL }, { NULL },
}; };
@@ -811,9 +1149,9 @@ int main (int argc, char **argv)
const int noquickack = option_is_set(opts, "noquickack"); const int noquickack = option_is_set(opts, "noquickack");
const int debug = option_is_set(opts, "debug"); const int debug = option_is_set(opts, "debug");
if (buffer_size < 2048) { if (buffer_size < GT_PKT_MAX) {
buffer_size = 2048; buffer_size = GT_PKT_MAX;
gt_log("buffer size must be greater than 2048\n"); gt_log("buffer size must be greater than or equal to %li\n", buffer_size);
} }
if (!listener) { if (!listener) {
@@ -826,8 +1164,8 @@ int main (int argc, char **argv)
retry_count = 0; retry_count = 0;
} }
if (statefile && statefile[0]!='/') { if (gt.timeout<=0 || gt.timeout>INT_MAX) {
gt_log("statefile must be an absolute path\n"); gt_log("bad timeout\n");
return 1; return 1;
} }
@@ -846,24 +1184,21 @@ int main (int argc, char **argv)
if (!ai) if (!ai)
return 1; return 1;
if (state_init(statefile))
return 1;
struct fdbuf tun = { .fd = -1 }; struct fdbuf tun = { .fd = -1 };
struct fdbuf sock = { .fd = -1 }; struct fdbuf sock = { .fd = -1 };
tun.fd = tun_create(dev, option_is_set(opts, "multiqueue")); char *tun_name = NULL;
tun.fd = tun_create(dev, &tun_name, option_is_set(opts, "multiqueue"));
if (tun.fd==-1) { if (tun.fd==-1) {
gt_log("couldn't create tun device\n"); gt_log("couldn't create tun device\n");
return 1; return 1;
} }
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;
fd_set_nonblock(tun.fd); fd_set_nonblock(tun.fd);
buffer_setup(&tun.write, NULL, GT_TUNW_SIZE); buffer_setup(&tun.write, NULL, GT_TUNW_SIZE);
@@ -886,49 +1221,10 @@ int main (int argc, char **argv)
if (gt_setup_secretkey(&ctx, keyfile)) if (gt_setup_secretkey(&ctx, keyfile))
return 1; return 1;
if (option_is_set(opts, "daemon")) {
switch (fork()) {
case -1:
perror("fork");
return 1;
case 0:
if (setsid()==-1)
perror("setsid");
break;
default:
_exit(0);
}
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;
fd_write_str(state_fd, "INITIALIZED"); state("INITIALIZED", tun_name);
while (!gt_close) { while (!gt_close) {
if (retry_count>=0 && retry>=retry_count+1) { if (retry_count>=0 && retry>=retry_count+1) {
@@ -957,15 +1253,13 @@ int main (int argc, char **argv)
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;
} }
gt_log("%s: connected\n", sockname); gt_log("%s: connected\n", sockname);
fd_set_nonblock(sock.fd);
sk_set_int(sock.fd, sk_nodelay, !delay); sk_set_int(sock.fd, sk_nodelay, !delay);
sk_set_int(sock.fd, sk_keepalive, keepalive); sk_set_int(sock.fd, sk_keepalive, keepalive);
@@ -980,6 +1274,7 @@ int main (int argc, char **argv)
sk_set_int(sock.fd, sk_keepintvl, ka_interval); sk_set_int(sock.fd, sk_keepintvl, ka_interval);
} }
sk_set_int(sock.fd, sk_user_timeout, gt.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)) {
@@ -995,7 +1290,7 @@ int main (int argc, char **argv)
retry = 0; retry = 0;
fd_write_str(state_fd, "STARTED"); state("STARTED", sockname);
fd_set rfds; fd_set rfds;
FD_ZERO(&rfds); FD_ZERO(&rfds);
@@ -1015,7 +1310,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);
@@ -1046,68 +1343,53 @@ int main (int argc, char **argv)
// gettimeofday(&now, NULL); // gettimeofday(&now, NULL);
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 int ip_version = ip_get_version(data, GT_MTU_MAX); struct ip_common ic;
const ssize_t ip_size = ip_get_size(ip_version, data, GT_MTU_MAX);
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) {
char tmp[2*GT_MTU_MAX+1]; char tmp[2*GT_MTU_MAX+1];
gt_tohex(tmp, sizeof(tmp), data, r); gt_tohex(tmp, sizeof(tmp), tun.read.write, r);
gt_log("%s: DUMP %zi %s\n", sockname, r, tmp); gt_log("%s: DUMP %zi %s\n", sockname, r, tmp);
continue; continue;
} }
if _0_(debug) if _0_(debug) {
gt_print_hdr(ip_version, data, ip_size); if (gt_track(&db, &ic, tun.read.write, 0))
continue;
}
blks[blk_write++].size = r; tun.read.write += r;
blk_count++;
} }
} }
while (1) { buffer_shift(&sock.write);
buffer_shift(&tun.read);
if _0_(!stop_loop) { if _1_(!stop_loop)
for (; blk_count; blk_read++) { gt_encrypt(&ctx, &sock.write, &tun.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;
} }
} }
@@ -1119,8 +1401,6 @@ int main (int argc, char **argv)
} }
} }
buffer_shift(&sock.write);
if (FD_ISSET(sock.fd, &rfds)) { if (FD_ISSET(sock.fd, &rfds)) {
if (noquickack) if (noquickack)
sk_set_int(sock.fd, sk_quickack, 0); sk_set_int(sock.fd, sk_quickack, 0);
@@ -1135,33 +1415,38 @@ int main (int argc, char **argv)
} }
} }
buffer_shift(&tun.write);
if _0_(gt_decrypt(&ctx, &tun.write, &sock.read)) {
gt_log("%s: message could not be verified!\n", sockname);
goto restart;
}
while (1) { while (1) {
buffer_shift(&tun.write);
if _0_(gt_decrypt(&ctx, &tun.write, &sock.read)) {
gt_log("%s: message could not be verified!\n", sockname);
goto restart;
}
size_t size = buffer_read_size(&tun.write); size_t size = buffer_read_size(&tun.write);
const int ip_version = ip_get_version(tun.write.read, size); if (!size)
ssize_t ip_size = ip_get_size(ip_version, tun.write.read, size); break;
if _0_(!ip_size) { 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; 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, ip_size); ssize_t r = tun_write(tun.fd, tun.write.read, ic.size);
if (r>0) { if (r>0) {
if _0_(debug) if (r==ic.size)
gt_print_hdr(ip_version, tun.write.read, ip_size); tun.write.read += r;
tun.write.read += r;
} else { } else {
gt_close |= !r; gt_close |= !r;
break; break;
@@ -1170,23 +1455,21 @@ int main (int argc, char **argv)
} }
restart: restart:
if (sockname) {
free(sockname);
sockname = NULL;
}
if (sock.fd!=-1) { if (sock.fd!=-1) {
close(sock.fd); close(sock.fd);
sock.fd = -1; sock.fd = -1;
} }
fd_write_str(state_fd, "STOPPED"); state("STOPPED", sockname);
if (sockname) {
free(sockname);
sockname = NULL;
}
} }
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;
} }

61
src/state.c Normal file
View File

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

4
src/state.h Normal file
View File

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

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

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>
@@ -36,7 +37,7 @@ static int tun_create_by_id (char *name, size_t size, unsigned id, _unused_ int
struct ctl_info ci; struct ctl_info ci;
byte_set(&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)) {
@@ -130,9 +131,9 @@ static int tun_create_by_id (char *name, size_t size, unsigned id, int mq)
#endif #endif
int tun_create (char *dev_name, int mq) int tun_create (char *dev_name, char **ret_name, int mq)
{ {
char name[64]; char name[64] = {0};
int fd = -1; int fd = -1;
#ifndef IFF_MULTI_QUEUE #ifndef IFF_MULTI_QUEUE
@@ -147,8 +148,8 @@ int tun_create (char *dev_name, int mq)
fd = tun_create_by_name(name, sizeof(name), dev_name, mq); fd = tun_create_by_name(name, sizeof(name), dev_name, mq);
} }
if (fd!=-1) if (fd!=-1 && ret_name)
gt_print("tun name: %s\n", name); *ret_name = strdup(name);
return fd; return fd;
} }

View File

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

View File

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