Compare commits

...

11 Commits

Author SHA1 Message Date
angt
4337251218 Code cleanup 2015-11-18 10:17:50 +01:00
angt
baca343fdf Simplify setsockopt() code 2015-11-18 09:24:30 +01:00
angt
c20a2a5a13 Code cleanup 2015-11-17 23:58:19 +01:00
angt
7fc368cf3c Make keepalive an option (and not a flag) 2015-11-17 23:48:55 +01:00
angt
25b62bf4c6 Simplify and generalize option_usage() 2015-11-17 23:36:03 +01:00
angt
47432ecafa Add gt_print() 2015-11-17 23:29:56 +01:00
angt
e4f2a92c5b Add ka-count, ka-idle and ka-interval options to setup keepalive 2015-11-17 22:14:35 +01:00
angt
89d2edb61b Try again to open() on EINTR 2015-11-17 21:39:56 +01:00
angt
310e499234 Version 0.0.3 2015-11-17 21:22:24 +01:00
angt
9ff87109f9 Add buffer-size option 2015-11-17 21:19:16 +01:00
angt
bfcf38f380 Try to be more robust on restart but accept some lost for now 2015-11-17 21:04:26 +01:00
7 changed files with 186 additions and 125 deletions

View File

@@ -1,5 +1,5 @@
AC_PREREQ([2.65]) AC_PREREQ([2.65])
AC_INIT([glorytun], [0.0.2], [https://github.com/angt/glorytun/issues], AC_INIT([glorytun], [0.0.3], [https://github.com/angt/glorytun/issues],
[glorytun], [https://github.com/angt/glorytun]) [glorytun], [https://github.com/angt/glorytun])
AC_CONFIG_SRCDIR([src/common.h]) AC_CONFIG_SRCDIR([src/common.h])
AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_AUX_DIR([build-aux])

View File

@@ -3,6 +3,19 @@
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
int gt_print (const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int ret = vfprintf(stdout, fmt, ap);
va_end(ap);
if (ret<0)
return 0;
return ret;
}
void gt_log (const char *fmt, ...) void gt_log (const char *fmt, ...)
{ {
va_list ap; va_list ap;

View File

@@ -27,6 +27,7 @@ struct buffer {
uint8_t *end; uint8_t *end;
}; };
int gt_print (const char *, ...) _printf_(1,2);
void gt_log (const char *, ...) _printf_(1,2); void gt_log (const char *, ...) _printf_(1,2);
void gt_fatal (const char *, ...) _printf_(1,2) _noreturn_; void gt_fatal (const char *, ...) _printf_(1,2) _noreturn_;
void gt_na (const char *); void gt_na (const char *);

View File

@@ -1,8 +1,8 @@
#include <inttypes.h> #include <inttypes.h>
#include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <signal.h> #include <signal.h>
#include <poll.h> #include <poll.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/fcntl.h> #include <sys/fcntl.h>
#include <sys/socket.h> #include <sys/socket.h>
@@ -67,51 +67,54 @@ static void fd_set_nonblock (int fd)
perror("fcntl O_NONBLOCK"); perror("fcntl O_NONBLOCK");
} }
static void sk_set_nodelay (int fd) static void sk_set (int fd, const char *name, const void *val, socklen_t len)
{ {
int val = 1; if (!name || !val || len<=0)
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY , &val, sizeof(val))==-1)
perror("setsockopt TCP_NODELAY");
}
static void sk_set_reuseaddr (int fd)
{
int val = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))==-1)
perror("setsockopt SO_REUSEADDR");
}
static void sk_set_keepalive (int fd)
{
int val = 1;
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val))==-1)
perror("setsockopt SO_KEEPALIVE");
}
#ifdef TCP_CONGESTION
static void sk_set_congestion (int fd, const char *name)
{
size_t len = str_len(name);
if (!len)
return; return;
if (setsockopt(fd, IPPROTO_TCP, TCP_CONGESTION, name, len+1)==-1) struct {
perror("setsockopt TCP_CONGESTION"); const char *name;
} const int level;
#else const int option;
static void sk_set_congestion (_unused_ int fd, _unused_ const char *name) } ops[] = {
{ { "TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY },
gt_na("TCP_CONGESTION"); { "SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR },
} { "SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE },
#ifdef TCP_KEEPCNT
{ "TCP_KEEPCNT", IPPROTO_TCP, TCP_KEEPCNT },
#endif #endif
#ifdef TCP_KEEPIDLE
{ "TCP_KEEPIDLE", IPPROTO_TCP, TCP_KEEPIDLE },
#endif
#ifdef TCP_KEEPINTVL
{ "TCP_KEEPINTVL", IPPROTO_TCP, TCP_KEEPINTVL },
#endif
#ifdef TCP_CONGESTION
{ "TCP_CONGESTION", IPPROTO_TCP, TCP_CONGESTION },
#endif
};
for (int k=0; k<COUNT(ops); k++) {
if (str_cmp(ops[k].name, name))
continue;
if (setsockopt(fd, ops[k].level, ops[k].option, val, len)==-1)
gt_log("couldn't set socket option `%s'\n", name);
return;
}
gt_na(name);
}
static void sk_set_int (int fd, const char *name, int val)
{
return sk_set(fd, name, &val, sizeof(val));
}
static int sk_listen (int fd, struct addrinfo *ai) static int sk_listen (int fd, struct addrinfo *ai)
{ {
sk_set_reuseaddr(fd); sk_set_int(fd, "SO_REUSEADDR", 1);
int ret = bind(fd, ai->ai_addr, ai->ai_addrlen); int ret = bind(fd, ai->ai_addr, ai->ai_addrlen);
@@ -471,9 +474,13 @@ static int gt_setup_secretkey (struct crypto_ctx *ctx, char *keyfile)
if (!keyfile) if (!keyfile)
return 0; return 0;
int fd = open(keyfile, O_RDONLY|O_CLOEXEC); int fd;
if (fd<0) { do {
fd = open(keyfile, O_RDONLY|O_CLOEXEC);
} while (fd==-1 && errno==EINTR);
if (fd==-1) {
perror("open keyfile"); perror("open keyfile");
return -1; return -1;
} }
@@ -580,9 +587,12 @@ int main (int argc, char **argv)
char *dev = PACKAGE_NAME; char *dev = PACKAGE_NAME;
char *keyfile = NULL; char *keyfile = NULL;
char *congestion = NULL; char *congestion = NULL;
long buffer_size = GT_BUFFER_SIZE;
int delay = 0; int delay = 0;
int multiqueue = 0; int multiqueue = 0;
int keepalive = 0; long ka_count = -1;
long ka_idle = -1;
long ka_interval = -1;
int version = 0; int version = 0;
int debug = 0; int debug = 0;
@@ -593,18 +603,26 @@ int main (int argc, char **argv)
} tcpinfo = {0}; } tcpinfo = {0};
#endif #endif
struct option ka_opts[] = {
{ "count", &ka_count, option_long },
{ "idle", &ka_idle, option_long },
{ "interval", &ka_interval, option_long },
{ NULL },
};
struct option opts[] = { struct option opts[] = {
{ "listener", &listener, option_flag }, { "listener", &listener, option_flag },
{ "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", &delay, option_flag }, { "delay", &delay, option_flag },
{ "multiqueue", &multiqueue, option_flag }, { "multiqueue", &multiqueue, option_flag },
{ "keepalive", &keepalive, option_flag }, { "keepalive", ka_opts, option_option },
{ "debug", &debug, option_flag }, { "buffer-size", &buffer_size, option_long },
{ "version", &version, option_flag }, { "debug", &debug, option_flag },
{ "version", &version, option_flag },
{ NULL }, { NULL },
}; };
@@ -612,10 +630,17 @@ int main (int argc, char **argv)
return 1; return 1;
if (version) { if (version) {
printf(PACKAGE_STRING"\n"); gt_print(PACKAGE_STRING"\n");
return 0; return 0;
} }
int keepalive = option_is_set(opts, "keepalive");
if (buffer_size < 2048) {
buffer_size = 2048;
gt_log("buffer size must be greater than 2048!\n");
}
if (sodium_init()==-1) { if (sodium_init()==-1) {
gt_log("libsodium initialization has failed!\n"); gt_log("libsodium initialization has failed!\n");
return 1; return 1;
@@ -646,8 +671,8 @@ int main (int argc, char **argv)
fd_set_nonblock(tun.fd); fd_set_nonblock(tun.fd);
buffer_setup(&sock.write.buf, NULL, GT_BUFFER_SIZE); buffer_setup(&sock.write.buf, NULL, buffer_size);
buffer_setup(&sock.read.buf, NULL, GT_BUFFER_SIZE); buffer_setup(&sock.read.buf, NULL, buffer_size);
int fd = -1; int fd = -1;
@@ -658,7 +683,7 @@ int main (int argc, char **argv)
return 1; return 1;
} }
while (1) { while (!gt_close) {
sock.fd = listener?sk_accept(fd):sk_create(ai, sk_connect); sock.fd = listener?sk_accept(fd):sk_create(ai, sk_connect);
if (sock.fd==-1) { if (sock.fd==-1) {
@@ -673,15 +698,23 @@ int main (int argc, char **argv)
gt_log("%s: connected\n", sockname); gt_log("%s: connected\n", sockname);
if (!delay)
sk_set_nodelay(sock.fd);
fd_set_nonblock(sock.fd); fd_set_nonblock(sock.fd);
if (keepalive) sk_set_int(sock.fd, "TCP_NODELAY", !delay);
sk_set_keepalive(sock.fd); sk_set_int(sock.fd, "SO_KEEPALIVE", keepalive);
sk_set_congestion(sock.fd, congestion); if (keepalive) {
if (ka_count>=0 && ka_count<=INT_MAX)
sk_set_int(sock.fd, "TCP_KEEPCNT", ka_count);
if (ka_idle>=0 && ka_idle<=INT_MAX)
sk_set_int(sock.fd, "TCP_KEEPIDLE", ka_idle);
if (ka_interval>=0 && ka_interval<=INT_MAX)
sk_set_int(sock.fd, "TCP_KEEPINTVL", ka_interval);
}
sk_set(sock.fd, "TCP_CONGESTION", congestion, str_len(congestion));
switch (gt_setup_crypto(&ctx, sock.fd, listener)) { switch (gt_setup_crypto(&ctx, sock.fd, listener)) {
case -2: gt_log("%s: key exchange could not be verified!\n", sockname); case -2: gt_log("%s: key exchange could not be verified!\n", sockname);
@@ -703,14 +736,16 @@ int main (int argc, char **argv)
int stop_loop = 0; int stop_loop = 0;
buffer_format(&sock.write.buf);
buffer_format(&sock.read.buf);
while (1) { while (1) {
if (gt_close) if (gt_close)
stop_loop = 1; stop_loop = 1;
if (stop_loop) { if (stop_loop) {
if (((stop_loop>>1)==3) && if (((stop_loop&(1<<2)) || !buffer_read_size(&sock.write.buf)) &&
(buffer_read_size(&sock.write.buf)==0) && ((stop_loop&(1<<1)) || !buffer_read_size(&sock.read.buf)))
(buffer_read_size(&sock.read.buf)==0))
goto restart; goto restart;
FD_CLR(tun.fd, &rfds); FD_CLR(tun.fd, &rfds);
} else { } else {
@@ -719,7 +754,9 @@ int main (int argc, char **argv)
FD_SET(sock.fd, &rfds); FD_SET(sock.fd, &rfds);
if (select(sock.fd+1, &rfds, &wfds, NULL, NULL)==-1 && errno!=EINTR) { if (select(sock.fd+1, &rfds, &wfds, NULL, NULL)==-1) {
if (errno==EINTR)
continue;
perror("select"); perror("select");
return 1; return 1;
} }
@@ -773,29 +810,27 @@ int main (int argc, char **argv)
FD_CLR(sock.fd, &wfds); FD_CLR(sock.fd, &wfds);
if (buffer_read_size(&sock.write.buf)) { if (buffer_read_size(&sock.write.buf)) {
ssize_t r = fd_write(sock.fd, sock.write.buf.read, buffer_read_size(&sock.write.buf)); ssize_t r = fd_write(sock.fd, sock.write.buf.read,
buffer_read_size(&sock.write.buf));
if (r==-1) if (r==-1)
FD_SET(sock.fd, &wfds); FD_SET(sock.fd, &wfds);
if (!r) { if (!r)
stop_loop |= (1<<2); stop_loop |= (1<<2);
buffer_format(&sock.write.buf);
}
if (r>0) if (r>0)
sock.write.buf.read += r; sock.write.buf.read += r;
} else { } else {
if (stop_loop) { if (stop_loop)
stop_loop |= (1<<2);
shutdown(sock.fd, SHUT_WR); shutdown(sock.fd, SHUT_WR);
}
} }
buffer_shift(&sock.read.buf); buffer_shift(&sock.read.buf);
if (FD_ISSET(sock.fd, &rfds)) { if (FD_ISSET(sock.fd, &rfds)) {
ssize_t r = fd_read(sock.fd, sock.read.buf.write, buffer_write_size(&sock.read.buf)); ssize_t r = fd_read(sock.fd, sock.read.buf.write,
buffer_write_size(&sock.read.buf));
if (!r) if (!r)
stop_loop |= (1<<1); stop_loop |= (1<<1);
@@ -815,11 +850,8 @@ int main (int argc, char **argv)
if (!ip_size) if (!ip_size)
goto restart; goto restart;
if (ip_size<0 || (size_t)ip_size+16>size) { if (ip_size<0 || (size_t)ip_size+16>size)
if (stop_loop&(1<<1))
buffer_format(&sock.read.buf);
break; break;
}
if (decrypt_packet(&ctx, tunw.buf, ip_size, &sock.read.buf)) { if (decrypt_packet(&ctx, tunw.buf, ip_size, &sock.read.buf)) {
gt_log("%s: message could not be verified!\n", sockname); gt_log("%s: message could not be verified!\n", sockname);
@@ -855,9 +887,6 @@ int main (int argc, char **argv)
close(sock.fd); close(sock.fd);
sock.fd = -1; sock.fd = -1;
} }
if (gt_close)
break;
} }
freeaddrinfo(ai); freeaddrinfo(ai);

View File

@@ -16,7 +16,7 @@ int option_flag (void *data, _unused_ int argc, _unused_ char **argv)
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 || !argv[1]) {
printf("option `%s' need a string argument\n", argv[0]); gt_print("option `%s' need a string argument\n", argv[0]);
return -1; return -1;
} }
@@ -28,7 +28,7 @@ int option_str (void *data, int argc, char **argv)
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 || !argv[1]) {
printf("option `%s' need an integer argument\n", argv[0]); gt_print("option `%s' need an integer argument\n", argv[0]);
return -1; return -1;
} }
@@ -37,7 +37,7 @@ int option_long (void *data, int argc, char **argv)
long val = strtol(argv[1], &end, 0); long val = strtol(argv[1], &end, 0);
if (errno || argv[1]==end) { if (errno || argv[1]==end) {
printf("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;
} }
@@ -46,6 +46,16 @@ int option_long (void *data, int argc, char **argv)
return 1; return 1;
} }
int option_is_set (struct option *opts, const char *name)
{
for (int k=0; opts[k].name; k++) {
if (!str_cmp(opts[k].name, name))
return opts[k].set;
}
return 0;
}
int option_option (void *data, int argc, char **argv) int option_option (void *data, int argc, char **argv)
{ {
struct option *opts = (struct option *)data; struct option *opts = (struct option *)data;
@@ -61,7 +71,7 @@ int option_option (void *data, int argc, char **argv)
continue; continue;
if (opts[k].set) { if (opts[k].set) {
printf("option `%s' is already set\n", opts[k].name); gt_print("option `%s' is already set\n", opts[k].name);
return -1; return -1;
} }
@@ -84,31 +94,30 @@ int option_option (void *data, int argc, char **argv)
return argc; return argc;
} }
static void option_usage (struct option *opts, char *name) static int option_usage (struct option *opts, int slen)
{ {
char *usage = "usage: "; int len = slen;
size_t slen = str_len(usage)+str_len(name);
size_t len = slen;
printf("%s%s", usage, name);
if (slen>40)
slen = 12;
for (int k=0; opts[k].name; k++) { for (int k=0; opts[k].name; k++) {
char *arg = (opts[k].call==option_flag)?"":" ARG"; if (len>60) {
size_t inc = str_len(opts[k].name)+str_len(arg)+3; gt_print("\n%*s", (int)slen, "");
if (len+inc>72) {
printf("\n%*s", (int)slen, "");
len = slen; len = slen;
} }
printf(" [%s%s]", opts[k].name, arg); len += gt_print(" [%s", opts[k].name);
len += inc;
if (opts[k].call!=option_flag) {
if (opts[k].call==option_option) {
len += option_usage((struct option *)opts[k].data, len);
} else {
len += gt_print(" ARG");
}
}
len += gt_print("]");
} }
printf("\n"); return len;
} }
int option (struct option *opts, int argc, char **argv) int option (struct option *opts, int argc, char **argv)
@@ -121,8 +130,16 @@ int option (struct option *opts, int argc, char **argv)
if (ret<0 || ret+1>=argc) if (ret<0 || ret+1>=argc)
return 1; return 1;
printf("option `%s' is unknown\n", argv[ret+1]); gt_print("option `%s' is unknown\n", argv[ret+1]);
option_usage(opts, argv[0]);
int slen = gt_print("usage: %s", argv[0]);
if (slen>40)
slen = 12;
option_usage(opts, slen);
printf("\n");
return 1; return 1;
} }

View File

@@ -12,4 +12,5 @@ int option_str (void *, int, char **);
int option_long (void *, int, char **); int option_long (void *, int, char **);
int option_option (void *, int, char **); int option_option (void *, int, char **);
int option (struct option *, int, char **); int option_is_set (struct option *, const char *);
int option (struct option *, int, char **);

View File

@@ -56,42 +56,42 @@ int tun_create (char *name, int multiqueue)
return -1; return -1;
} }
printf("tun name: %s\n", ifr.ifr_name); gt_print("tun name: %s\n", ifr.ifr_name);
return fd; return fd;
} }
#elif defined(__APPLE__) #elif defined(__APPLE__)
int tun_create (_unused_ char *name, _unused_ int mq) int tun_create (_unused_ char *name, _unused_ int mq)
{ {
struct ctl_info ctlInfo;
struct sockaddr_ctl sc;
int fd;
for (unsigned dev_id = 0U; dev_id<32U; dev_id++) { for (unsigned dev_id = 0U; dev_id<32U; dev_id++) {
byte_set(&ctlInfo, 0, sizeof(ctlInfo)); struct ctl_info ci;
str_cpy(ctlInfo.ctl_name, UTUN_CONTROL_NAME, sizeof(ctlInfo.ctl_name)); byte_set(&ci, 0, sizeof(ci));
fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); str_cpy(ci.ctl_name, UTUN_CONTROL_NAME, sizeof(ci.ctl_name)-1);
int fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
if (fd==-1) if (fd==-1)
return -1; return -1;
if (ioctl(fd, CTLIOCGINFO, &ctlInfo)==-1) { if (ioctl(fd, CTLIOCGINFO, &ci)==-1) {
close(fd); close(fd);
continue; continue;
} }
sc.sc_id = ctlInfo.ctl_id; struct sockaddr_ctl sc = {
sc.sc_len = sizeof(sc); .sc_id = ci.ctl_id,
sc.sc_family = AF_SYSTEM; .sc_len = sizeof(sc),
sc.ss_sysaddr = AF_SYS_CONTROL; .sc_family = AF_SYSTEM,
sc.sc_unit = dev_id+1; .ss_sysaddr = AF_SYS_CONTROL,
.sc_unit = dev_id+1,
};
if (connect(fd, (struct sockaddr *) &sc, sizeof(sc))==-1) { if (connect(fd, (struct sockaddr *)&sc, sizeof(sc))==-1) {
close(fd); close(fd);
continue; continue;
} }
printf("tun name: /dev/utun%u\n", dev_id); gt_print("tun name: /dev/utun%u\n", dev_id);
return fd; return fd;
} }
@@ -104,12 +104,12 @@ int tun_create (_unused_ char *name, _unused_ int mq)
for (unsigned dev_id = 0U; dev_id<32U; dev_id++) { for (unsigned dev_id = 0U; dev_id<32U; dev_id++) {
char dev_path[11U]; char dev_path[11U];
snprintf(dev_path, sizeof(dev_path), "/dev/tun%u", dev_id); sngt_print(dev_path, sizeof(dev_path), "/dev/tun%u", dev_id);
int fd = open(dev_path, O_RDWR); int fd = open(dev_path, O_RDWR);
if (fd!=-1) { if (fd!=-1) {
printf("tun name: /dev/tun%u\n", dev_id); gt_print("tun name: /dev/tun%u\n", dev_id);
return fd; return fd;
} }
} }