Import Upstream version 1.1~pre4
This commit is contained in:
parent
34d5939212
commit
ff64081061
48 changed files with 1739 additions and 1176 deletions
|
|
@ -8,7 +8,7 @@ tincd_SOURCES = \
|
|||
utils.c getopt.c getopt1.c list.c splay_tree.c dropin.c fake-getaddrinfo.c fake-getnameinfo.c hash.c \
|
||||
buffer.c conf.c connection.c control.c edge.c graph.c logger.c meta.c net.c net_packet.c net_setup.c \
|
||||
net_socket.c netutl.c node.c process.c protocol.c protocol_auth.c protocol_edge.c protocol_misc.c \
|
||||
protocol_key.c protocol_subnet.c route.c sptps.c subnet.c subnet_parse.c tincd.c \
|
||||
protocol_key.c protocol_subnet.c route.c sptps.c subnet.c subnet_parse.c event.c tincd.c \
|
||||
dummy_device.c raw_socket_device.c multicast_device.c
|
||||
|
||||
if UML
|
||||
|
|
@ -46,7 +46,7 @@ INCLUDES = @INCLUDES@ -I$(top_builddir)
|
|||
noinst_HEADERS = \
|
||||
xalloc.h utils.h getopt.h list.h splay_tree.h dropin.h fake-getaddrinfo.h fake-getnameinfo.h fake-gai-errnos.h ipv6.h ipv4.h ethernet.h \
|
||||
buffer.h conf.h connection.h control.h control_common.h device.h edge.h graph.h info.h logger.h meta.h net.h netutl.h node.h process.h \
|
||||
protocol.h route.h subnet.h sptps.h tincctl.h top.h bsd/tunemu.h hash.h
|
||||
protocol.h route.h subnet.h sptps.h tincctl.h top.h bsd/tunemu.h hash.h event.h
|
||||
|
||||
nodist_noinst_HEADERS = \
|
||||
cipher.h crypto.h ecdh.h ecdsa.h digest.h prf.h rsa.h ecdsagen.h rsagen.h
|
||||
|
|
|
|||
|
|
@ -62,10 +62,9 @@ DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
|
|||
$(srcdir)/Makefile.in
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
|
||||
$(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \
|
||||
$(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.m4 \
|
||||
$(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/zlib.m4 \
|
||||
$(top_srcdir)/configure.in
|
||||
$(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/lzo.m4 \
|
||||
$(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/readline.m4 \
|
||||
$(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.in
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
|
|
@ -95,8 +94,8 @@ am__tincd_SOURCES_DIST = utils.c getopt.c getopt1.c list.c \
|
|||
netutl.c node.c process.c protocol.c protocol_auth.c \
|
||||
protocol_edge.c protocol_misc.c protocol_key.c \
|
||||
protocol_subnet.c route.c sptps.c subnet.c subnet_parse.c \
|
||||
tincd.c dummy_device.c raw_socket_device.c multicast_device.c \
|
||||
uml_device.c vde_device.c bsd/tunemu.c
|
||||
event.c tincd.c dummy_device.c raw_socket_device.c \
|
||||
multicast_device.c uml_device.c vde_device.c bsd/tunemu.c
|
||||
@UML_TRUE@am__objects_1 = uml_device.$(OBJEXT)
|
||||
@VDE_TRUE@am__objects_2 = vde_device.$(OBJEXT)
|
||||
@TUNEMU_TRUE@am__objects_3 = tunemu.$(OBJEXT)
|
||||
|
|
@ -112,9 +111,10 @@ am_tincd_OBJECTS = utils.$(OBJEXT) getopt.$(OBJEXT) getopt1.$(OBJEXT) \
|
|||
protocol_edge.$(OBJEXT) protocol_misc.$(OBJEXT) \
|
||||
protocol_key.$(OBJEXT) protocol_subnet.$(OBJEXT) \
|
||||
route.$(OBJEXT) sptps.$(OBJEXT) subnet.$(OBJEXT) \
|
||||
subnet_parse.$(OBJEXT) tincd.$(OBJEXT) dummy_device.$(OBJEXT) \
|
||||
raw_socket_device.$(OBJEXT) multicast_device.$(OBJEXT) \
|
||||
$(am__objects_1) $(am__objects_2) $(am__objects_3)
|
||||
subnet_parse.$(OBJEXT) event.$(OBJEXT) tincd.$(OBJEXT) \
|
||||
dummy_device.$(OBJEXT) raw_socket_device.$(OBJEXT) \
|
||||
multicast_device.$(OBJEXT) $(am__objects_1) $(am__objects_2) \
|
||||
$(am__objects_3)
|
||||
nodist_tincd_OBJECTS = device.$(OBJEXT) cipher.$(OBJEXT) \
|
||||
crypto.$(OBJEXT) ecdh.$(OBJEXT) ecdsa.$(OBJEXT) \
|
||||
digest.$(OBJEXT) prf.$(OBJEXT) rsa.$(OBJEXT)
|
||||
|
|
@ -251,7 +251,7 @@ tincd_SOURCES = utils.c getopt.c getopt1.c list.c splay_tree.c \
|
|||
net.c net_packet.c net_setup.c net_socket.c netutl.c node.c \
|
||||
process.c protocol.c protocol_auth.c protocol_edge.c \
|
||||
protocol_misc.c protocol_key.c protocol_subnet.c route.c \
|
||||
sptps.c subnet.c subnet_parse.c tincd.c dummy_device.c \
|
||||
sptps.c subnet.c subnet_parse.c event.c tincd.c dummy_device.c \
|
||||
raw_socket_device.c multicast_device.c $(am__append_1) \
|
||||
$(am__append_2) $(am__append_3)
|
||||
nodist_tincd_SOURCES = \
|
||||
|
|
@ -273,7 +273,7 @@ DEFAULT_INCLUDES =
|
|||
noinst_HEADERS = \
|
||||
xalloc.h utils.h getopt.h list.h splay_tree.h dropin.h fake-getaddrinfo.h fake-getnameinfo.h fake-gai-errnos.h ipv6.h ipv4.h ethernet.h \
|
||||
buffer.h conf.h connection.h control.h control_common.h device.h edge.h graph.h info.h logger.h meta.h net.h netutl.h node.h process.h \
|
||||
protocol.h route.h subnet.h sptps.h tincctl.h top.h bsd/tunemu.h hash.h
|
||||
protocol.h route.h subnet.h sptps.h tincctl.h top.h bsd/tunemu.h hash.h event.h
|
||||
|
||||
nodist_noinst_HEADERS = \
|
||||
cipher.h crypto.h ecdh.h ecdsa.h digest.h prf.h rsa.h ecdsagen.h rsagen.h
|
||||
|
|
@ -383,6 +383,7 @@ distclean-compile:
|
|||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecdsa.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecdsagen.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edge.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fake-getaddrinfo.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fake-getnameinfo.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt.Po@am__quote@
|
||||
|
|
|
|||
|
|
@ -68,11 +68,7 @@ void free_connection(connection_t *c) {
|
|||
buffer_clear(&c->inbuf);
|
||||
buffer_clear(&c->outbuf);
|
||||
|
||||
if(event_initialized(&c->inevent))
|
||||
event_del(&c->inevent);
|
||||
|
||||
if(event_initialized(&c->outevent))
|
||||
event_del(&c->outevent);
|
||||
io_del(&c->io);
|
||||
|
||||
if(c->socket > 0)
|
||||
closesocket(c->socket);
|
||||
|
|
|
|||
|
|
@ -90,8 +90,7 @@ typedef struct connection_t {
|
|||
|
||||
struct buffer_t inbuf;
|
||||
struct buffer_t outbuf;
|
||||
struct event inevent; /* input event on this metadata connection */
|
||||
struct event outevent; /* output event on this metadata connection */
|
||||
io_t io; /* input/output event on this metadata connection */
|
||||
int tcplen; /* length of incoming TCPpacket */
|
||||
int allow_request; /* defined if there's only one request possible */
|
||||
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ bool control_h(connection_t *c, const char *request) {
|
|||
|
||||
switch (type) {
|
||||
case REQ_STOP:
|
||||
event_loopexit(NULL);
|
||||
event_exit();
|
||||
return control_ok(c, REQ_STOP);
|
||||
|
||||
case REQ_DUMP_NODES:
|
||||
|
|
@ -156,7 +156,7 @@ bool init_control(void) {
|
|||
|
||||
// Make sure we have a valid address, and map 0.0.0.0 and :: to 127.0.0.1 and ::1.
|
||||
|
||||
if(getsockname(listen_socket[0].tcp, (struct sockaddr *)&sa, &len)) {
|
||||
if(getsockname(listen_socket[0].tcp.fd, (struct sockaddr *)&sa, &len)) {
|
||||
xasprintf(&localhost, "127.0.0.1 port %d", myport);
|
||||
} else {
|
||||
if(sa.sa.sa_family == AF_INET) {
|
||||
|
|
|
|||
18
src/dropin.h
18
src/dropin.h
|
|
@ -45,4 +45,22 @@ extern int gettimeofday(struct timeval *, void *);
|
|||
extern int usleep(long long usec);
|
||||
#endif
|
||||
|
||||
#ifndef timeradd
|
||||
#define timeradd(a, b, r) do {\
|
||||
(r)->tv_sec = (a)->tv_sec + (b)->tv_sec;\
|
||||
(r)->tv_usec = (a)->tv_usec + (b)->tv_usec;\
|
||||
if((r)->tv_usec >= 1000000)\
|
||||
(r)->tv_sec++, (r)->tv_usec -= 1000000;\
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef timersub
|
||||
#define timersub(a, b, r) do {\
|
||||
(r)->tv_sec = (a)->tv_sec - (b)->tv_sec;\
|
||||
(r)->tv_usec = (a)->tv_usec - (b)->tv_usec;\
|
||||
if((r)->tv_usec < 1000000)\
|
||||
(r)->tv_sec--, (r)->tv_usec += 1000000;\
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#endif /* __DROPIN_H__ */
|
||||
|
|
|
|||
|
|
@ -41,6 +41,10 @@
|
|||
#define ETH_P_IPV6 0x86DD
|
||||
#endif
|
||||
|
||||
#ifndef ETH_P_8021Q
|
||||
#define ETH_P_8021Q 0x8100
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ETHER_HEADER
|
||||
struct ether_header {
|
||||
uint8_t ether_dhost[ETH_ALEN];
|
||||
|
|
|
|||
250
src/event.c
Normal file
250
src/event.c
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
event.c -- I/O, timeout and signal event handling
|
||||
Copyright (C) 2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "dropin.h"
|
||||
#include "event.h"
|
||||
#include "net.h"
|
||||
#include "utils.h"
|
||||
|
||||
struct timeval now;
|
||||
|
||||
static fd_set readfds;
|
||||
static fd_set writefds;
|
||||
static volatile bool running;
|
||||
|
||||
static int io_compare(const io_t *a, const io_t *b) {
|
||||
return a->fd - b->fd;
|
||||
}
|
||||
|
||||
static int timeout_compare(const timeout_t *a, const timeout_t *b) {
|
||||
struct timeval diff;
|
||||
timersub(&a->tv, &b->tv, &diff);
|
||||
if(diff.tv_sec < 0)
|
||||
return -1;
|
||||
if(diff.tv_sec > 0)
|
||||
return 1;
|
||||
if(diff.tv_usec < 0)
|
||||
return -1;
|
||||
if(diff.tv_usec > 0)
|
||||
return 1;
|
||||
if(a < b)
|
||||
return -1;
|
||||
if(a > b)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int signal_compare(const signal_t *a, const signal_t *b) {
|
||||
return a->signum - b->signum;
|
||||
}
|
||||
|
||||
static splay_tree_t io_tree = {.compare = (splay_compare_t)io_compare};
|
||||
static splay_tree_t timeout_tree = {.compare = (splay_compare_t)timeout_compare};
|
||||
static splay_tree_t signal_tree = {.compare = (splay_compare_t)signal_compare};
|
||||
|
||||
void io_add(io_t *io, io_cb_t cb, void *data, int fd, int flags) {
|
||||
if(io->cb)
|
||||
return;
|
||||
|
||||
io->fd = fd;
|
||||
io->cb = cb;
|
||||
io->data = data;
|
||||
io->node.data = io;
|
||||
|
||||
io_set(io, flags);
|
||||
|
||||
if(!splay_insert_node(&io_tree, &io->node))
|
||||
abort();
|
||||
}
|
||||
|
||||
void io_set(io_t *io, int flags) {
|
||||
io->flags = flags;
|
||||
|
||||
if(flags & IO_READ)
|
||||
FD_SET(io->fd, &readfds);
|
||||
else
|
||||
FD_CLR(io->fd, &readfds);
|
||||
|
||||
if(flags & IO_WRITE)
|
||||
FD_SET(io->fd, &writefds);
|
||||
else
|
||||
FD_CLR(io->fd, &writefds);
|
||||
}
|
||||
|
||||
void io_del(io_t *io) {
|
||||
if(!io->cb)
|
||||
return;
|
||||
|
||||
io_set(io, 0);
|
||||
|
||||
splay_unlink_node(&io_tree, &io->node);
|
||||
io->cb = NULL;
|
||||
}
|
||||
|
||||
void timeout_add(timeout_t *timeout, timeout_cb_t cb, void *data, struct timeval *tv) {
|
||||
timeout->cb = cb;
|
||||
timeout->data = data;
|
||||
timeout->node.data = timeout;
|
||||
|
||||
timeout_set(timeout, tv);
|
||||
}
|
||||
|
||||
void timeout_set(timeout_t *timeout, struct timeval *tv) {
|
||||
if(timerisset(&timeout->tv))
|
||||
splay_unlink_node(&timeout_tree, &timeout->node);
|
||||
|
||||
if(!now.tv_sec)
|
||||
gettimeofday(&now, NULL);
|
||||
|
||||
timeradd(&now, tv, &timeout->tv);
|
||||
|
||||
if(!splay_insert_node(&timeout_tree, &timeout->node))
|
||||
abort();
|
||||
}
|
||||
|
||||
void timeout_del(timeout_t *timeout) {
|
||||
if(!timeout->cb)
|
||||
return;
|
||||
|
||||
splay_unlink_node(&timeout_tree, &timeout->node);
|
||||
timeout->cb = 0;
|
||||
timeout->tv = (struct timeval){0, 0};
|
||||
}
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
static io_t signalio;
|
||||
static int pipefd[2] = {-1, -1};
|
||||
|
||||
static void signal_handler(int signum) {
|
||||
unsigned char num = signum;
|
||||
write(pipefd[1], &num, 1);
|
||||
}
|
||||
|
||||
static void signalio_handler(void *data, int flags) {
|
||||
unsigned char signum;
|
||||
if(read(pipefd[0], &signum, 1) != 1)
|
||||
return;
|
||||
|
||||
signal_t *sig = splay_search(&signal_tree, &((signal_t){.signum = signum}));
|
||||
if(sig)
|
||||
sig->cb(sig->data);
|
||||
}
|
||||
|
||||
static void pipe_init(void) {
|
||||
if(!pipe(pipefd))
|
||||
io_add(&signalio, signalio_handler, NULL, pipefd[0], IO_READ);
|
||||
}
|
||||
|
||||
void signal_add(signal_t *sig, signal_cb_t cb, void *data, int signum) {
|
||||
if(sig->cb)
|
||||
return;
|
||||
|
||||
sig->cb = cb;
|
||||
sig->data = data;
|
||||
sig->signum = signum;
|
||||
sig->node.data = sig;
|
||||
|
||||
if(pipefd[0] == -1)
|
||||
pipe_init();
|
||||
|
||||
signal(sig->signum, signal_handler);
|
||||
|
||||
if(!splay_insert_node(&signal_tree, &sig->node))
|
||||
abort();
|
||||
}
|
||||
|
||||
void signal_del(signal_t *sig) {
|
||||
if(!sig->cb)
|
||||
return;
|
||||
|
||||
signal(sig->signum, SIG_DFL);
|
||||
|
||||
splay_unlink_node(&signal_tree, &sig->node);
|
||||
sig->cb = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool event_loop(void) {
|
||||
running = true;
|
||||
|
||||
fd_set readable;
|
||||
fd_set writable;
|
||||
|
||||
while(running) {
|
||||
gettimeofday(&now, NULL);
|
||||
struct timeval diff, *tv = NULL;
|
||||
|
||||
while(timeout_tree.head) {
|
||||
timeout_t *timeout = timeout_tree.head->data;
|
||||
timersub(&timeout->tv, &now, &diff);
|
||||
|
||||
if(diff.tv_sec < 0) {
|
||||
timeout->cb(timeout->data);
|
||||
if(timercmp(&timeout->tv, &now, <))
|
||||
timeout_del(timeout);
|
||||
} else {
|
||||
tv = &diff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&readable, &readfds, sizeof readable);
|
||||
memcpy(&writable, &writefds, sizeof writable);
|
||||
|
||||
int fds = 0;
|
||||
|
||||
if(io_tree.tail) {
|
||||
io_t *last = io_tree.tail->data;
|
||||
fds = last->fd + 1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
LeaveCriticalSection(&mutex);
|
||||
#endif
|
||||
int n = select(fds, &readable, &writable, NULL, tv);
|
||||
#ifdef HAVE_MINGW
|
||||
EnterCriticalSection(&mutex);
|
||||
#endif
|
||||
|
||||
if(n < 0) {
|
||||
if(sockwouldblock(errno))
|
||||
continue;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!n)
|
||||
continue;
|
||||
|
||||
for splay_each(io_t, io, &io_tree) {
|
||||
if(FD_ISSET(io->fd, &writable))
|
||||
io->cb(io->data, IO_WRITE);
|
||||
else if(FD_ISSET(io->fd, &readable))
|
||||
io->cb(io->data, IO_READ);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void event_exit(void) {
|
||||
running = false;
|
||||
}
|
||||
70
src/event.h
Normal file
70
src/event.h
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
event.h -- I/O, timeout and signal event handling
|
||||
Copyright (C) 2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef __TINC_EVENT_H__
|
||||
#define __TINC_EVENT_H__
|
||||
|
||||
#include "splay_tree.h"
|
||||
|
||||
#define IO_READ 1
|
||||
#define IO_WRITE 2
|
||||
|
||||
typedef void (*io_cb_t)(void *data, int flags);
|
||||
typedef void (*timeout_cb_t)(void *data);
|
||||
typedef void (*signal_cb_t)(void *data);
|
||||
|
||||
typedef struct io_t {
|
||||
int fd;
|
||||
int flags;
|
||||
io_cb_t cb;
|
||||
void *data;
|
||||
splay_node_t node;
|
||||
} io_t;
|
||||
|
||||
typedef struct timeout_t {
|
||||
struct timeval tv;
|
||||
timeout_cb_t cb;
|
||||
void *data;
|
||||
splay_node_t node;
|
||||
} timeout_t;
|
||||
|
||||
typedef struct signal_t {
|
||||
int signum;
|
||||
signal_cb_t cb;
|
||||
void *data;
|
||||
splay_node_t node;
|
||||
} signal_t;
|
||||
|
||||
extern struct timeval now;
|
||||
|
||||
extern void io_add(io_t *io, io_cb_t cb, void *data, int fd, int flags);
|
||||
extern void io_del(io_t *io);
|
||||
extern void io_set(io_t *io, int flags);
|
||||
|
||||
extern void timeout_add(timeout_t *timeout, timeout_cb_t cb, void *data, struct timeval *tv);
|
||||
extern void timeout_del(timeout_t *timeout);
|
||||
extern void timeout_set(timeout_t *timeout, struct timeval *tv);
|
||||
|
||||
extern void signal_add(signal_t *sig, signal_cb_t cb, void *data, int signum);
|
||||
extern void signal_del(signal_t *sig);
|
||||
|
||||
extern bool event_loop(void);
|
||||
extern void event_exit(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -213,8 +213,7 @@ static void check_reachability(void) {
|
|||
n->minmtu = 0;
|
||||
n->mtuprobes = 0;
|
||||
|
||||
if(timeout_initialized(&n->mtuevent))
|
||||
event_del(&n->mtuevent);
|
||||
timeout_del(&n->mtutimeout);
|
||||
|
||||
char *name;
|
||||
char *address;
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ hash_t *hash_alloc(size_t n, size_t size) {
|
|||
hash_t *hash = xmalloc_and_zero(sizeof *hash);
|
||||
hash->n = n;
|
||||
hash->size = size;
|
||||
hash->keys = xmalloc(hash->n * hash->size);
|
||||
hash->keys = xmalloc_and_zero(hash->n * hash->size);
|
||||
hash->values = xmalloc_and_zero(hash->n * sizeof *hash->values);
|
||||
return hash;
|
||||
}
|
||||
|
|
@ -100,6 +100,8 @@ void hash_clear(hash_t *hash) {
|
|||
void hash_resize(hash_t *hash, size_t n) {
|
||||
hash->keys = xrealloc(hash->keys, n * hash->size);
|
||||
hash->values = xrealloc(hash->values, n * sizeof *hash->values);
|
||||
if(n > hash->n)
|
||||
if(n > hash->n) {
|
||||
memset(hash->keys + hash->n * hash->size, 0, (n - hash->n) * hash->size);
|
||||
memset(hash->values + hash->n, 0, (n - hash->n) * sizeof *hash->values);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ bool logcontrol = false;
|
|||
|
||||
static void real_logger(int level, int priority, const char *message) {
|
||||
char timestr[32] = "";
|
||||
time_t now;
|
||||
static bool suppress = false;
|
||||
|
||||
// Bail out early if there is nothing to do.
|
||||
|
|
@ -58,8 +57,10 @@ static void real_logger(int level, int priority, const char *message) {
|
|||
fflush(stderr);
|
||||
break;
|
||||
case LOGMODE_FILE:
|
||||
now = time(NULL);
|
||||
strftime(timestr, sizeof timestr, "%Y-%m-%d %H:%M:%S", localtime(&now));
|
||||
if(!now.tv_sec)
|
||||
gettimeofday(&now, NULL);
|
||||
time_t now_sec = now.tv_sec;
|
||||
strftime(timestr, sizeof timestr, "%Y-%m-%d %H:%M:%S", localtime(&now_sec));
|
||||
fprintf(logfile, "%s %s[%ld]: %s\n", timestr, logident, (long)logpid, message);
|
||||
fflush(logfile);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ bool send_meta_sptps(void *handle, uint8_t type, const char *buffer, size_t leng
|
|||
}
|
||||
|
||||
buffer_add(&c->outbuf, buffer, length);
|
||||
event_add(&c->outevent, NULL);
|
||||
io_set(&c->io, IO_READ | IO_WRITE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -65,12 +65,11 @@ bool send_meta(connection_t *c, const char *buffer, int length) {
|
|||
c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
buffer_add(&c->outbuf, buffer, length);
|
||||
}
|
||||
|
||||
event_add(&c->outevent, NULL);
|
||||
io_set(&c->io, IO_READ | IO_WRITE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
175
src/net.c
175
src/net.c
|
|
@ -74,7 +74,7 @@ void purge(void) {
|
|||
if(e->to == n)
|
||||
return;
|
||||
|
||||
if(!strictsubnets || !n->subnet_tree->head)
|
||||
if(!autoconnect && (!strictsubnets || !n->subnet_tree->head))
|
||||
/* in strictsubnets mode do not delete nodes with subnets */
|
||||
node_del(n);
|
||||
}
|
||||
|
|
@ -137,18 +137,16 @@ void terminate_connection(connection_t *c, bool report) {
|
|||
end does not reply in time, we consider them dead
|
||||
and close the connection.
|
||||
*/
|
||||
static void timeout_handler(int fd, short events, void *event) {
|
||||
time_t now = time(NULL);
|
||||
|
||||
static void timeout_handler(void *data) {
|
||||
for list_each(connection_t, c, connection_list) {
|
||||
if(c->status.control)
|
||||
continue;
|
||||
|
||||
if(c->last_ping_time + pingtimeout <= now) {
|
||||
if(c->last_ping_time + pingtimeout <= now.tv_sec) {
|
||||
if(c->status.active) {
|
||||
if(c->status.pinged) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds", c->name, c->hostname, (long)now - c->last_ping_time);
|
||||
} else if(c->last_ping_time + pinginterval <= now) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds", c->name, c->hostname, (long)now.tv_sec - c->last_ping_time);
|
||||
} else if(c->last_ping_time + pinginterval <= now.tv_sec) {
|
||||
send_ping(c);
|
||||
continue;
|
||||
} else {
|
||||
|
|
@ -164,6 +162,15 @@ static void timeout_handler(int fd, short events, void *event) {
|
|||
}
|
||||
}
|
||||
|
||||
timeout_set(data, &(struct timeval){pingtimeout, rand() % 100000});
|
||||
}
|
||||
|
||||
static void periodic_handler(void *data) {
|
||||
/* Check if there are too many contradicting ADD_EDGE and DEL_EDGE messages.
|
||||
This usually only happens when another node has the same Name as this node.
|
||||
If so, sleep for a short while to prevent a storm of contradicting messages.
|
||||
*/
|
||||
|
||||
if(contradicting_del_edge > 100 && contradicting_add_edge > 100) {
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Possible node with same Name as us! Sleeping %d seconds.", sleeptime);
|
||||
usleep(sleeptime * 1000000LL);
|
||||
|
|
@ -179,11 +186,100 @@ static void timeout_handler(int fd, short events, void *event) {
|
|||
contradicting_add_edge = 0;
|
||||
contradicting_del_edge = 0;
|
||||
|
||||
event_add(event, &(struct timeval){pingtimeout, 0});
|
||||
/* If AutoConnect is set, check if we need to make or break connections. */
|
||||
|
||||
if(autoconnect && node_tree->count > 1) {
|
||||
/* Count number of active connections */
|
||||
int nc = 0;
|
||||
for list_each(connection_t, c, connection_list) {
|
||||
if(c->status.active && !c->status.control)
|
||||
nc++;
|
||||
}
|
||||
|
||||
if(nc < autoconnect) {
|
||||
/* Not enough active connections, try to add one.
|
||||
Choose a random node, if we don't have a connection to it,
|
||||
and we are not already trying to make one, create an
|
||||
outgoing connection to this node.
|
||||
*/
|
||||
int r = rand() % node_tree->count;
|
||||
int i = 0;
|
||||
|
||||
for splay_each(node_t, n, node_tree) {
|
||||
if(i++ != r)
|
||||
continue;
|
||||
|
||||
if(n->connection)
|
||||
break;
|
||||
|
||||
bool found = false;
|
||||
|
||||
for list_each(outgoing_t, outgoing, outgoing_list) {
|
||||
if(!strcmp(outgoing->name, n->name)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Autoconnecting to %s", n->name);
|
||||
outgoing_t *outgoing = xmalloc_and_zero(sizeof *outgoing);
|
||||
outgoing->name = xstrdup(n->name);
|
||||
list_insert_tail(outgoing_list, outgoing);
|
||||
setup_outgoing_connection(outgoing);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if(nc > autoconnect) {
|
||||
/* Too many active connections, try to remove one.
|
||||
Choose a random outgoing connection to a node
|
||||
that has at least one other connection.
|
||||
*/
|
||||
int r = rand() % nc;
|
||||
int i = 0;
|
||||
|
||||
for list_each(connection_t, c, connection_list) {
|
||||
if(!c->status.active || c->status.control)
|
||||
continue;
|
||||
|
||||
if(i++ != r)
|
||||
continue;
|
||||
|
||||
if(!c->outgoing || !c->node || c->node->edge_tree->count < 2)
|
||||
break;
|
||||
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Autodisconnecting from %s", c->name);
|
||||
list_delete(outgoing_list, c->outgoing);
|
||||
c->outgoing = NULL;
|
||||
terminate_connection(c, c->status.active);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(nc >= autoconnect) {
|
||||
/* If we have enough active connections,
|
||||
remove any pending outgoing connections.
|
||||
*/
|
||||
for list_each(outgoing_t, o, outgoing_list) {
|
||||
bool found = false;
|
||||
for list_each(connection_t, c, connection_list) {
|
||||
if(c->outgoing == o) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Cancelled outgoing connection to %s", o->name);
|
||||
list_delete_node(outgoing_list, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
timeout_set(data, &(struct timeval){5, rand() % 100000});
|
||||
}
|
||||
|
||||
void handle_meta_connection_data(int fd, short events, void *data) {
|
||||
connection_t *c = data;
|
||||
void handle_meta_connection_data(connection_t *c) {
|
||||
int result;
|
||||
socklen_t len = sizeof result;
|
||||
|
||||
|
|
@ -207,19 +303,19 @@ void handle_meta_connection_data(int fd, short events, void *data) {
|
|||
}
|
||||
}
|
||||
|
||||
static void sigterm_handler(int signal, short events, void *data) {
|
||||
logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(signal));
|
||||
event_loopexit(NULL);
|
||||
static void sigterm_handler(void *data) {
|
||||
logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(((signal_t *)data)->signum));
|
||||
event_exit();
|
||||
}
|
||||
|
||||
static void sighup_handler(int signal, short events, void *data) {
|
||||
logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(signal));
|
||||
static void sighup_handler(void *data) {
|
||||
logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(((signal_t *)data)->signum));
|
||||
reopenlogger();
|
||||
reload_configuration();
|
||||
}
|
||||
|
||||
static void sigalrm_handler(int signal, short events, void *data) {
|
||||
logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(signal));
|
||||
static void sigalrm_handler(void *data) {
|
||||
logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(((signal_t *)data)->signum));
|
||||
retry();
|
||||
}
|
||||
|
||||
|
|
@ -233,7 +329,7 @@ int reload_configuration(void) {
|
|||
|
||||
if(!read_server_config()) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to reread configuration file, exitting.");
|
||||
event_loopexit(NULL);
|
||||
event_exit();
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -332,8 +428,7 @@ int reload_configuration(void) {
|
|||
void retry(void) {
|
||||
for list_each(connection_t, c, connection_list) {
|
||||
if(c->outgoing && !c->node) {
|
||||
if(timeout_initialized(&c->outgoing->ev))
|
||||
event_del(&c->outgoing->ev);
|
||||
timeout_del(&c->outgoing->ev);
|
||||
if(c->status.connecting)
|
||||
close(c->socket);
|
||||
c->outgoing->timeout = 0;
|
||||
|
|
@ -346,40 +441,38 @@ void retry(void) {
|
|||
this is where it all happens...
|
||||
*/
|
||||
int main_loop(void) {
|
||||
struct event timeout_event;
|
||||
timeout_t pingtimer = {{0}};
|
||||
timeout_t periodictimer = {{0}};
|
||||
|
||||
timeout_set(&timeout_event, timeout_handler, &timeout_event);
|
||||
event_add(&timeout_event, &(struct timeval){pingtimeout, 0});
|
||||
timeout_add(&pingtimer, timeout_handler, &pingtimer, &(struct timeval){pingtimeout, rand() % 100000});
|
||||
timeout_add(&periodictimer, periodic_handler, &periodictimer, &(struct timeval){pingtimeout, rand() % 100000});
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
struct event sighup_event;
|
||||
struct event sigterm_event;
|
||||
struct event sigquit_event;
|
||||
struct event sigalrm_event;
|
||||
signal_t sighup = {0};
|
||||
signal_t sigterm = {0};
|
||||
signal_t sigquit = {0};
|
||||
signal_t sigalrm = {0};
|
||||
|
||||
signal_set(&sighup_event, SIGHUP, sighup_handler, NULL);
|
||||
signal_add(&sighup_event, NULL);
|
||||
signal_set(&sigterm_event, SIGTERM, sigterm_handler, NULL);
|
||||
signal_add(&sigterm_event, NULL);
|
||||
signal_set(&sigquit_event, SIGQUIT, sigterm_handler, NULL);
|
||||
signal_add(&sigquit_event, NULL);
|
||||
signal_set(&sigalrm_event, SIGALRM, sigalrm_handler, NULL);
|
||||
signal_add(&sigalrm_event, NULL);
|
||||
signal_add(&sighup, sighup_handler, &sighup, SIGHUP);
|
||||
signal_add(&sigterm, sigterm_handler, &sigterm, SIGTERM);
|
||||
signal_add(&sigquit, sigterm_handler, &sigquit, SIGQUIT);
|
||||
signal_add(&sigalrm, sigalrm_handler, &sigalrm, SIGALRM);
|
||||
#endif
|
||||
|
||||
if(event_loop(0) < 0) {
|
||||
if(!event_loop()) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while waiting for input: %s", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
signal_del(&sighup_event);
|
||||
signal_del(&sigterm_event);
|
||||
signal_del(&sigquit_event);
|
||||
signal_del(&sigalrm_event);
|
||||
signal_del(&sighup);
|
||||
signal_del(&sigalrm);
|
||||
signal_del(&sigquit);
|
||||
signal_del(&sigterm);
|
||||
#endif
|
||||
|
||||
event_del(&timeout_event);
|
||||
timeout_del(&periodictimer);
|
||||
timeout_del(&pingtimer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
19
src/net.h
19
src/net.h
|
|
@ -24,6 +24,7 @@
|
|||
#include "ipv6.h"
|
||||
#include "cipher.h"
|
||||
#include "digest.h"
|
||||
#include "event.h"
|
||||
|
||||
#ifdef ENABLE_JUMBOGRAMS
|
||||
#define MTU 9018 /* 9000 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */
|
||||
|
|
@ -99,10 +100,8 @@ typedef enum packet_type_t {
|
|||
} packet_type_t;
|
||||
|
||||
typedef struct listen_socket_t {
|
||||
struct event ev_tcp;
|
||||
struct event ev_udp;
|
||||
int tcp;
|
||||
int udp;
|
||||
io_t tcp;
|
||||
io_t udp;
|
||||
sockaddr_t sa;
|
||||
} listen_socket_t;
|
||||
|
||||
|
|
@ -116,7 +115,7 @@ typedef struct outgoing_t {
|
|||
struct config_t *cfg;
|
||||
struct addrinfo *ai;
|
||||
struct addrinfo *aip;
|
||||
struct event ev;
|
||||
timeout_t ev;
|
||||
} outgoing_t;
|
||||
|
||||
extern list_t *outgoing_list;
|
||||
|
|
@ -134,6 +133,7 @@ extern int udp_rcvbuf;
|
|||
extern int udp_sndbuf;
|
||||
extern bool do_prune;
|
||||
extern char *myport;
|
||||
extern int autoconnect;
|
||||
extern int contradicting_add_edge;
|
||||
extern int contradicting_del_edge;
|
||||
extern time_t last_config_check;
|
||||
|
|
@ -160,10 +160,10 @@ extern char *scriptextension;
|
|||
#include "node.h"
|
||||
|
||||
extern void retry_outgoing(outgoing_t *);
|
||||
extern void handle_incoming_vpn_data(int, short, void *);
|
||||
extern void handle_incoming_vpn_data(void *, int);
|
||||
extern void finish_connecting(struct connection_t *);
|
||||
extern bool do_outgoing_connection(struct outgoing_t *);
|
||||
extern void handle_new_meta_connection(int, short, void *);
|
||||
extern void handle_new_meta_connection(void *, int);
|
||||
extern int setup_listen_socket(const sockaddr_t *);
|
||||
extern int setup_vpn_in_socket(const sockaddr_t *);
|
||||
extern bool send_sptps_data(void *handle, uint8_t type, const char *data, size_t len);
|
||||
|
|
@ -183,13 +183,14 @@ extern bool node_read_ecdsa_public_key(struct node_t *);
|
|||
extern bool read_ecdsa_public_key(struct connection_t *);
|
||||
extern bool read_rsa_public_key(struct connection_t *);
|
||||
extern void send_mtu_probe(struct node_t *);
|
||||
extern void handle_device_data(int, short, void *);
|
||||
extern void handle_meta_connection_data(int, short, void *);
|
||||
extern void handle_device_data(void *, int);
|
||||
extern void handle_meta_connection_data(struct connection_t *);
|
||||
extern void regenerate_key(void);
|
||||
extern void purge(void);
|
||||
extern void retry(void);
|
||||
extern int reload_configuration(void);
|
||||
extern void load_all_subnets(void);
|
||||
extern void load_all_nodes(void);
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
#define closesocket(s) close(s)
|
||||
|
|
|
|||
220
src/net_packet.c
220
src/net_packet.c
|
|
@ -77,7 +77,7 @@ bool localdiscovery = false;
|
|||
which will be broadcast to the local network.
|
||||
*/
|
||||
|
||||
static void send_mtu_probe_handler(int fd, short events, void *data) {
|
||||
static void send_mtu_probe_handler(void *data) {
|
||||
node_t *n = data;
|
||||
int timeout = 1;
|
||||
|
||||
|
|
@ -151,23 +151,37 @@ static void send_mtu_probe_handler(int fd, short events, void *data) {
|
|||
}
|
||||
|
||||
end:
|
||||
event_add(&n->mtuevent, &(struct timeval){timeout, 0});
|
||||
timeout_set(&n->mtutimeout, &(struct timeval){timeout, rand() % 100000});
|
||||
}
|
||||
|
||||
void send_mtu_probe(node_t *n) {
|
||||
if(!timeout_initialized(&n->mtuevent))
|
||||
timeout_set(&n->mtuevent, send_mtu_probe_handler, n);
|
||||
send_mtu_probe_handler(0, 0, n);
|
||||
timeout_add(&n->mtutimeout, send_mtu_probe_handler, n, &(struct timeval){1, 0});
|
||||
send_mtu_probe_handler(n);
|
||||
}
|
||||
|
||||
static void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Got MTU probe length %d from %s (%s)", packet->len, n->name, n->hostname);
|
||||
|
||||
if(!packet->data[0]) {
|
||||
/* It's a probe request, send back a reply */
|
||||
|
||||
packet->data[0] = 1;
|
||||
send_udppacket(n, packet);
|
||||
} else {
|
||||
|
||||
/* Temporarily set udp_confirmed, so that the reply is sent
|
||||
back exactly the way it came in. */
|
||||
|
||||
bool udp_confirmed = n->status.udp_confirmed;
|
||||
n->status.udp_confirmed = true;
|
||||
send_udppacket(n, packet);
|
||||
n->status.udp_confirmed = udp_confirmed;
|
||||
} else {
|
||||
/* It's a valid reply: now we know bidirectional communication
|
||||
is possible using the address and socket that the reply
|
||||
packet used. */
|
||||
|
||||
n->status.udp_confirmed = true;
|
||||
|
||||
/* If we haven't established the PMTU yet, restart the discovery process. */
|
||||
|
||||
if(n->mtuprobes > 30) {
|
||||
if(n->minmtu)
|
||||
|
|
@ -176,6 +190,8 @@ static void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
|
|||
n->mtuprobes = 1;
|
||||
}
|
||||
|
||||
/* If applicable, raise the minimum supported MTU */
|
||||
|
||||
if(len > n->maxmtu)
|
||||
len = n->maxmtu;
|
||||
if(n->minmtu < len)
|
||||
|
|
@ -438,6 +454,84 @@ static void send_sptps_packet(node_t *n, vpn_packet_t *origpkt) {
|
|||
return;
|
||||
}
|
||||
|
||||
static void choose_udp_address(const node_t *n, const sockaddr_t **sa, int *sock) {
|
||||
/* Latest guess */
|
||||
*sa = &n->address;
|
||||
*sock = n->sock;
|
||||
|
||||
/* If the UDP address is confirmed, use it. */
|
||||
if(n->status.udp_confirmed)
|
||||
return;
|
||||
|
||||
/* Send every third packet to n->address; that could be set
|
||||
to the node's reflexive UDP address discovered during key
|
||||
exchange. */
|
||||
|
||||
static int x = 0;
|
||||
if(++x >= 3) {
|
||||
x = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise, address are found in edges to this node.
|
||||
So we pick a random edge and a random socket. */
|
||||
|
||||
int i = 0;
|
||||
int j = rand() % n->edge_tree->count;
|
||||
edge_t *candidate = NULL;
|
||||
|
||||
for splay_each(edge_t, e, n->edge_tree) {
|
||||
if(i++ == j) {
|
||||
candidate = e->reverse;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(candidate) {
|
||||
*sa = &candidate->address;
|
||||
*sock = rand() % listen_sockets;
|
||||
}
|
||||
|
||||
/* Make sure we have a suitable socket for the chosen address */
|
||||
if(listen_socket[*sock].sa.sa.sa_family != (*sa)->sa.sa_family) {
|
||||
for(int i = 0; i < listen_sockets; i++) {
|
||||
if(listen_socket[i].sa.sa.sa_family == (*sa)->sa.sa_family) {
|
||||
*sock = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void choose_broadcast_address(const node_t *n, const sockaddr_t **sa, int *sock) {
|
||||
static sockaddr_t broadcast_ipv4 = {
|
||||
.in = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr.s_addr = -1,
|
||||
}
|
||||
};
|
||||
|
||||
static sockaddr_t broadcast_ipv6 = {
|
||||
.in6 = {
|
||||
.sin6_family = AF_INET6,
|
||||
.sin6_addr.s6_addr[0x0] = 0xff,
|
||||
.sin6_addr.s6_addr[0x1] = 0x02,
|
||||
.sin6_addr.s6_addr[0xf] = 0x01,
|
||||
}
|
||||
};
|
||||
|
||||
*sock = rand() % listen_sockets;
|
||||
|
||||
if(listen_socket[*sock].sa.sa.sa_family == AF_INET6) {
|
||||
broadcast_ipv6.in6.sin6_port = n->prevedge->address.in.sin_port;
|
||||
broadcast_ipv6.in6.sin6_scope_id = listen_socket[*sock].sa.in6.sin6_scope_id;
|
||||
*sa = &broadcast_ipv6;
|
||||
} else {
|
||||
broadcast_ipv4.in.sin_port = n->prevedge->address.in.sin_port;
|
||||
*sa = &broadcast_ipv4;
|
||||
}
|
||||
}
|
||||
|
||||
static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
||||
vpn_packet_t pkt1, pkt2;
|
||||
vpn_packet_t *pkt[] = { &pkt1, &pkt2, &pkt1, &pkt2 };
|
||||
|
|
@ -462,15 +556,13 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
|||
/* Make sure we have a valid key */
|
||||
|
||||
if(!n->status.validkey) {
|
||||
time_t now = time(NULL);
|
||||
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO,
|
||||
"No valid key known yet for %s (%s), forwarding via TCP",
|
||||
n->name, n->hostname);
|
||||
|
||||
if(n->last_req_key + 10 <= now) {
|
||||
if(n->last_req_key + 10 <= now.tv_sec) {
|
||||
send_req_key(n);
|
||||
n->last_req_key = now;
|
||||
n->last_req_key = now.tv_sec;
|
||||
}
|
||||
|
||||
send_tcppacket(n->nexthop->connection, origpkt);
|
||||
|
|
@ -534,88 +626,27 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
|||
|
||||
/* Send the packet */
|
||||
|
||||
sockaddr_t *sa;
|
||||
const sockaddr_t *sa;
|
||||
int sock;
|
||||
|
||||
/* Overloaded use of priority field: -1 means local broadcast */
|
||||
|
||||
if(origpriority == -1 && n->prevedge) {
|
||||
sockaddr_t broadcast;
|
||||
broadcast.in.sin_family = AF_INET;
|
||||
broadcast.in.sin_addr.s_addr = -1;
|
||||
broadcast.in.sin_port = n->prevedge->address.in.sin_port;
|
||||
sa = &broadcast;
|
||||
sock = 0;
|
||||
} else {
|
||||
if(origpriority == -1)
|
||||
origpriority = 0;
|
||||
|
||||
if(n->status.udp_confirmed) {
|
||||
/* Address of this node is confirmed, so use it. */
|
||||
sa = &n->address;
|
||||
sock = n->sock;
|
||||
} else {
|
||||
/* Otherwise, go through the list of known addresses of
|
||||
this node. The first address we try is always the
|
||||
one in n->address; that could be set to the node's
|
||||
reflexive UDP address discovered during key
|
||||
exchange. The other known addresses are those found
|
||||
in edges to this node. */
|
||||
|
||||
static unsigned int i;
|
||||
int j = 0;
|
||||
edge_t *candidate = NULL;
|
||||
|
||||
if(i) {
|
||||
for splay_each(edge_t, e, edge_weight_tree) {
|
||||
if(e->to != n)
|
||||
continue;
|
||||
j++;
|
||||
if(!candidate || j == i)
|
||||
candidate = e;
|
||||
}
|
||||
}
|
||||
|
||||
if(!candidate) {
|
||||
sa = &n->address;
|
||||
sock = n->sock;
|
||||
} else {
|
||||
sa = &candidate->address;
|
||||
sock = rand() % listen_sockets;
|
||||
}
|
||||
|
||||
if(i++)
|
||||
if(i > j)
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine which socket we have to use */
|
||||
|
||||
if(sa->sa.sa_family != listen_socket[sock].sa.sa.sa_family)
|
||||
for(sock = 0; sock < listen_sockets; sock++)
|
||||
if(sa->sa.sa_family == listen_socket[sock].sa.sa.sa_family)
|
||||
break;
|
||||
|
||||
if(sock >= listen_sockets)
|
||||
sock = 0;
|
||||
|
||||
if(!n->status.udp_confirmed)
|
||||
n->sock = sock;
|
||||
if(origpriority == -1 && n->prevedge)
|
||||
choose_broadcast_address(n, &sa, &sock);
|
||||
else
|
||||
choose_udp_address(n, &sa, &sock);
|
||||
|
||||
#if defined(SOL_IP) && defined(IP_TOS)
|
||||
if(priorityinheritance && origpriority != priority
|
||||
&& listen_socket[n->sock].sa.sa.sa_family == AF_INET) {
|
||||
priority = origpriority;
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Setting outgoing packet priority to %d", priority);
|
||||
if(setsockopt(listen_socket[n->sock].udp, SOL_IP, IP_TOS, &priority, sizeof(priority))) /* SO_PRIORITY doesn't seem to work */
|
||||
if(setsockopt(listen_socket[n->sock].udp.fd, SOL_IP, IP_TOS, &priority, sizeof(priority))) /* SO_PRIORITY doesn't seem to work */
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
socklen_t sl = SALEN(n->address.sa);
|
||||
|
||||
if(sendto(listen_socket[sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, &sa->sa, sl) < 0 && !sockwouldblock(sockerrno)) {
|
||||
if(sendto(listen_socket[sock].udp.fd, (char *) &inpkt->seqno, inpkt->len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
|
||||
if(sockmsgsize(sockerrno)) {
|
||||
if(n->maxmtu >= origlen)
|
||||
n->maxmtu = origlen - 1;
|
||||
|
|
@ -647,15 +678,12 @@ bool send_sptps_data(void *handle, uint8_t type, const char *data, size_t len) {
|
|||
|
||||
/* Otherwise, send the packet via UDP */
|
||||
|
||||
struct sockaddr *sa;
|
||||
socklen_t sl;
|
||||
const sockaddr_t *sa;
|
||||
int sock;
|
||||
|
||||
sa = &(to->address.sa);
|
||||
sl = SALEN(to->address.sa);
|
||||
sock = to->sock;
|
||||
choose_udp_address(to, &sa, &sock);
|
||||
|
||||
if(sendto(listen_socket[sock].udp, data, len, 0, sa, sl) < 0 && !sockwouldblock(sockerrno)) {
|
||||
if(sendto(listen_socket[sock].udp.fd, data, len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
|
||||
if(sockmsgsize(sockerrno)) {
|
||||
if(to->maxmtu >= len)
|
||||
to->maxmtu = len - 1;
|
||||
|
|
@ -711,11 +739,11 @@ bool receive_sptps_record(void *handle, uint8_t type, const char *data, uint16_t
|
|||
|
||||
int offset = (type & PKT_MAC) ? 0 : 14;
|
||||
if(type & PKT_COMPRESSED) {
|
||||
len = uncompress_packet(inpkt.data + offset, (const uint8_t *)data, len, from->incompression);
|
||||
if(len < 0) {
|
||||
length_t ulen = uncompress_packet(inpkt.data + offset, (const uint8_t *)data, len, from->incompression);
|
||||
if(ulen < 0) {
|
||||
return false;
|
||||
} else {
|
||||
inpkt.len = len + offset;
|
||||
inpkt.len = ulen + offset;
|
||||
}
|
||||
if(inpkt.len > MAXSIZE)
|
||||
abort();
|
||||
|
|
@ -838,14 +866,13 @@ static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
|
|||
node_t *n = NULL;
|
||||
bool hard = false;
|
||||
static time_t last_hard_try = 0;
|
||||
time_t now = time(NULL);
|
||||
|
||||
for splay_each(edge_t, e, edge_weight_tree) {
|
||||
if(!e->to->status.reachable || e->to == myself)
|
||||
continue;
|
||||
|
||||
if(sockaddrcmp_noport(from, &e->address)) {
|
||||
if(last_hard_try == now)
|
||||
if(last_hard_try == now.tv_sec)
|
||||
continue;
|
||||
hard = true;
|
||||
}
|
||||
|
|
@ -858,13 +885,14 @@ static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
|
|||
}
|
||||
|
||||
if(hard)
|
||||
last_hard_try = now;
|
||||
last_hard_try = now.tv_sec;
|
||||
|
||||
last_hard_try = now;
|
||||
last_hard_try = now.tv_sec;
|
||||
return n;
|
||||
}
|
||||
|
||||
void handle_incoming_vpn_data(int sock, short events, void *data) {
|
||||
void handle_incoming_vpn_data(void *data, int flags) {
|
||||
listen_socket_t *ls = data;
|
||||
vpn_packet_t pkt;
|
||||
char *hostname;
|
||||
sockaddr_t from = {{0}};
|
||||
|
|
@ -872,7 +900,7 @@ void handle_incoming_vpn_data(int sock, short events, void *data) {
|
|||
node_t *n;
|
||||
int len;
|
||||
|
||||
len = recvfrom(sock, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen);
|
||||
len = recvfrom(ls->udp.fd, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen);
|
||||
|
||||
if(len <= 0 || len > MAXSIZE) {
|
||||
if(!sockwouldblock(sockerrno))
|
||||
|
|
@ -900,12 +928,12 @@ void handle_incoming_vpn_data(int sock, short events, void *data) {
|
|||
return;
|
||||
}
|
||||
|
||||
n->sock = (intptr_t)data;
|
||||
n->sock = ls - listen_socket;
|
||||
|
||||
receive_udppacket(n, &pkt);
|
||||
}
|
||||
|
||||
void handle_device_data(int sock, short events, void *data) {
|
||||
void handle_device_data(void *data, int flags) {
|
||||
vpn_packet_t packet;
|
||||
|
||||
packet.priority = 0;
|
||||
|
|
|
|||
127
src/net_setup.c
127
src/net_setup.c
|
|
@ -42,7 +42,7 @@
|
|||
#include "xalloc.h"
|
||||
|
||||
char *myport;
|
||||
static struct event device_ev;
|
||||
static io_t device_io;
|
||||
devops_t devops;
|
||||
|
||||
char *proxyhost;
|
||||
|
|
@ -50,6 +50,7 @@ char *proxyport;
|
|||
char *proxyuser;
|
||||
char *proxypass;
|
||||
proxytype_t proxytype;
|
||||
int autoconnect;
|
||||
|
||||
char *scriptinterpreter;
|
||||
char *scriptextension;
|
||||
|
|
@ -269,22 +270,16 @@ static bool read_rsa_private_key(void) {
|
|||
return result;
|
||||
}
|
||||
|
||||
static struct event keyexpire_event;
|
||||
static timeout_t keyexpire_timeout;
|
||||
|
||||
static void keyexpire_handler(int fd, short events, void *data) {
|
||||
static void keyexpire_handler(void *data) {
|
||||
regenerate_key();
|
||||
timeout_set(data, &(struct timeval){keylifetime, rand() % 100000});
|
||||
}
|
||||
|
||||
void regenerate_key(void) {
|
||||
if(timeout_initialized(&keyexpire_event)) {
|
||||
logger(DEBUG_STATUS, LOG_INFO, "Expiring symmetric keys");
|
||||
event_del(&keyexpire_event);
|
||||
send_key_changed();
|
||||
} else {
|
||||
timeout_set(&keyexpire_event, keyexpire_handler, NULL);
|
||||
}
|
||||
|
||||
event_add(&keyexpire_event, &(struct timeval){keylifetime, 0});
|
||||
logger(DEBUG_STATUS, LOG_INFO, "Expiring symmetric keys");
|
||||
send_key_changed();
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -347,6 +342,36 @@ void load_all_subnets(void) {
|
|||
closedir(dir);
|
||||
}
|
||||
|
||||
void load_all_nodes(void) {
|
||||
DIR *dir;
|
||||
struct dirent *ent;
|
||||
char *dname;
|
||||
|
||||
xasprintf(&dname, "%s" SLASH "hosts", confbase);
|
||||
dir = opendir(dname);
|
||||
if(!dir) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s", dname, strerror(errno));
|
||||
free(dname);
|
||||
return;
|
||||
}
|
||||
|
||||
while((ent = readdir(dir))) {
|
||||
if(!check_id(ent->d_name))
|
||||
continue;
|
||||
|
||||
node_t *n = lookup_node(ent->d_name);
|
||||
if(n)
|
||||
continue;
|
||||
|
||||
n = new_node();
|
||||
n->name = xstrdup(ent->d_name);
|
||||
node_add(n);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
|
||||
char *get_name(void) {
|
||||
char *name = NULL;
|
||||
|
||||
|
|
@ -362,7 +387,7 @@ char *get_name(void) {
|
|||
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid Name: environment variable %s does not exist\n", name + 1);
|
||||
return false;
|
||||
}
|
||||
envname = alloca(32);
|
||||
char envname[32];
|
||||
if(gethostname(envname, 32)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not get hostname: %s\n", strerror(errno));
|
||||
return false;
|
||||
|
|
@ -570,6 +595,8 @@ bool setup_myself_reloadable(void) {
|
|||
if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime))
|
||||
keylifetime = 3600;
|
||||
|
||||
get_config_int(lookup_config(config_tree, "AutoConnect"), &autoconnect);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -683,7 +710,8 @@ static bool setup_myself(void) {
|
|||
|
||||
free(cipher);
|
||||
|
||||
regenerate_key();
|
||||
send_key_changed();
|
||||
timeout_add(&keyexpire_timeout, keyexpire_handler, &keyexpire_timeout, &(struct timeval){keylifetime, rand() % 100000});
|
||||
|
||||
/* Check if we want to use message authentication codes... */
|
||||
|
||||
|
|
@ -730,6 +758,8 @@ static bool setup_myself(void) {
|
|||
|
||||
if(strictsubnets)
|
||||
load_all_subnets();
|
||||
else if(autoconnect)
|
||||
load_all_nodes();
|
||||
|
||||
/* Open device */
|
||||
|
||||
|
|
@ -755,15 +785,8 @@ static bool setup_myself(void) {
|
|||
if(!devops.setup())
|
||||
return false;
|
||||
|
||||
if(device_fd >= 0) {
|
||||
event_set(&device_ev, device_fd, EV_READ|EV_PERSIST, handle_device_data, NULL);
|
||||
|
||||
if (event_add(&device_ev, NULL) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno));
|
||||
devops.close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(device_fd >= 0)
|
||||
io_add(&device_io, handle_device_data, NULL, device_fd, IO_READ);
|
||||
|
||||
/* Run tinc-up script to further initialize the tap interface */
|
||||
char *envp[5];
|
||||
|
|
@ -805,27 +828,16 @@ static bool setup_myself(void) {
|
|||
return false;
|
||||
}
|
||||
|
||||
listen_socket[i].tcp = i + 3;
|
||||
|
||||
#ifdef FD_CLOEXEC
|
||||
fcntl(i + 3, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
listen_socket[i].udp = setup_vpn_in_socket(&sa);
|
||||
if(listen_socket[i].udp < 0)
|
||||
int udp_fd = setup_vpn_in_socket(&sa);
|
||||
if(udp_fd < 0)
|
||||
return false;
|
||||
|
||||
event_set(&listen_socket[i].ev_tcp, listen_socket[i].tcp, EV_READ|EV_PERSIST, handle_new_meta_connection, NULL);
|
||||
if(event_add(&listen_socket[i].ev_tcp, NULL) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno));
|
||||
abort();
|
||||
}
|
||||
|
||||
event_set(&listen_socket[i].ev_udp, listen_socket[i].udp, EV_READ|EV_PERSIST, handle_incoming_vpn_data, (void *)(intptr_t)listen_sockets);
|
||||
if(event_add(&listen_socket[listen_sockets].ev_udp, NULL) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno));
|
||||
abort();
|
||||
}
|
||||
io_add(&listen_socket[i].tcp, (io_cb_t)handle_new_meta_connection, &listen_socket[i], i + 3, IO_READ);
|
||||
io_add(&listen_socket[i].udp, (io_cb_t)handle_incoming_vpn_data, &listen_socket[i], udp_fd, IO_READ);
|
||||
|
||||
if(debug_level >= DEBUG_CONNECTIONS) {
|
||||
hostname = sockaddr2hostname(&sa);
|
||||
|
|
@ -878,37 +890,20 @@ static bool setup_myself(void) {
|
|||
return false;
|
||||
}
|
||||
|
||||
listen_socket[listen_sockets].tcp =
|
||||
setup_listen_socket((sockaddr_t *) aip->ai_addr);
|
||||
int tcp_fd = setup_listen_socket((sockaddr_t *) aip->ai_addr);
|
||||
|
||||
if(listen_socket[listen_sockets].tcp < 0)
|
||||
if(tcp_fd < 0)
|
||||
continue;
|
||||
|
||||
listen_socket[listen_sockets].udp =
|
||||
setup_vpn_in_socket((sockaddr_t *) aip->ai_addr);
|
||||
int udp_fd = setup_vpn_in_socket((sockaddr_t *) aip->ai_addr);
|
||||
|
||||
if(listen_socket[listen_sockets].udp < 0) {
|
||||
close(listen_socket[listen_sockets].tcp);
|
||||
if(tcp_fd < 0) {
|
||||
close(tcp_fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
event_set(&listen_socket[listen_sockets].ev_tcp,
|
||||
listen_socket[listen_sockets].tcp,
|
||||
EV_READ|EV_PERSIST,
|
||||
handle_new_meta_connection, NULL);
|
||||
if(event_add(&listen_socket[listen_sockets].ev_tcp, NULL) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno));
|
||||
abort();
|
||||
}
|
||||
|
||||
event_set(&listen_socket[listen_sockets].ev_udp,
|
||||
listen_socket[listen_sockets].udp,
|
||||
EV_READ|EV_PERSIST,
|
||||
handle_incoming_vpn_data, (void *)(intptr_t)listen_sockets);
|
||||
if(event_add(&listen_socket[listen_sockets].ev_udp, NULL) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno));
|
||||
abort();
|
||||
}
|
||||
io_add(&listen_socket[listen_sockets].tcp, handle_new_meta_connection, &listen_socket[listen_sockets], tcp_fd, IO_READ);
|
||||
io_add(&listen_socket[listen_sockets].udp, handle_incoming_vpn_data, &listen_socket[listen_sockets], udp_fd, IO_READ);
|
||||
|
||||
if(debug_level >= DEBUG_CONNECTIONS) {
|
||||
hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr);
|
||||
|
|
@ -990,10 +985,10 @@ void close_network_connections(void) {
|
|||
}
|
||||
|
||||
for(int i = 0; i < listen_sockets; i++) {
|
||||
event_del(&listen_socket[i].ev_tcp);
|
||||
event_del(&listen_socket[i].ev_udp);
|
||||
close(listen_socket[i].tcp);
|
||||
close(listen_socket[i].udp);
|
||||
io_del(&listen_socket[i].tcp);
|
||||
io_del(&listen_socket[i].udp);
|
||||
close(listen_socket[i].tcp.fd);
|
||||
close(listen_socket[i].udp.fd);
|
||||
}
|
||||
|
||||
char *envp[5];
|
||||
|
|
|
|||
|
|
@ -271,7 +271,7 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
|
|||
return nfd;
|
||||
} /* int setup_vpn_in_socket */
|
||||
|
||||
static void retry_outgoing_handler(int fd, short events, void *data) {
|
||||
static void retry_outgoing_handler(void *data) {
|
||||
setup_outgoing_connection(data);
|
||||
}
|
||||
|
||||
|
|
@ -281,12 +281,9 @@ void retry_outgoing(outgoing_t *outgoing) {
|
|||
if(outgoing->timeout > maxtimeout)
|
||||
outgoing->timeout = maxtimeout;
|
||||
|
||||
timeout_set(&outgoing->ev, retry_outgoing_handler, outgoing);
|
||||
event_add(&outgoing->ev, &(struct timeval){outgoing->timeout, 0});
|
||||
timeout_add(&outgoing->ev, retry_outgoing_handler, outgoing, &(struct timeval){outgoing->timeout, rand() % 100000});
|
||||
|
||||
logger(DEBUG_CONNECTIONS, LOG_NOTICE,
|
||||
"Trying to re-establish outgoing connection in %d seconds",
|
||||
outgoing->timeout);
|
||||
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Trying to re-establish outgoing connection in %d seconds", outgoing->timeout);
|
||||
}
|
||||
|
||||
void finish_connecting(connection_t *c) {
|
||||
|
|
@ -349,9 +346,7 @@ static void do_outgoing_pipe(connection_t *c, char *command) {
|
|||
#endif
|
||||
}
|
||||
|
||||
static void handle_meta_write(int sock, short events, void *data) {
|
||||
connection_t *c = data;
|
||||
|
||||
static void handle_meta_write(connection_t *c) {
|
||||
ssize_t outlen = send(c->socket, c->outbuf.data + c->outbuf.offset, c->outbuf.len - c->outbuf.offset, 0);
|
||||
if(outlen <= 0) {
|
||||
if(!errno || errno == EPIPE) {
|
||||
|
|
@ -368,10 +363,16 @@ static void handle_meta_write(int sock, short events, void *data) {
|
|||
}
|
||||
|
||||
buffer_read(&c->outbuf, outlen);
|
||||
if(!c->outbuf.len && event_initialized(&c->outevent))
|
||||
event_del(&c->outevent);
|
||||
if(!c->outbuf.len)
|
||||
io_set(&c->io, IO_READ);
|
||||
}
|
||||
|
||||
static void handle_meta_io(void *data, int flags) {
|
||||
if(flags & IO_WRITE)
|
||||
handle_meta_write(data);
|
||||
else
|
||||
handle_meta_connection_data(data);
|
||||
}
|
||||
|
||||
bool do_outgoing_connection(outgoing_t *outgoing) {
|
||||
char *address, *port, *space;
|
||||
|
|
@ -487,16 +488,13 @@ begin:
|
|||
|
||||
connection_add(c);
|
||||
|
||||
event_set(&c->inevent, c->socket, EV_READ | EV_PERSIST, handle_meta_connection_data, c);
|
||||
event_set(&c->outevent, c->socket, EV_WRITE | EV_PERSIST, handle_meta_write, c);
|
||||
event_add(&c->inevent, NULL);
|
||||
io_add(&c->io, handle_meta_io, c, c->socket, IO_READ);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void setup_outgoing_connection(outgoing_t *outgoing) {
|
||||
if(event_initialized(&outgoing->ev))
|
||||
event_del(&outgoing->ev);
|
||||
timeout_del(&outgoing->ev);
|
||||
|
||||
node_t *n = lookup_node(outgoing->name);
|
||||
|
||||
|
|
@ -523,13 +521,14 @@ void setup_outgoing_connection(outgoing_t *outgoing) {
|
|||
accept a new tcp connect and create a
|
||||
new connection
|
||||
*/
|
||||
void handle_new_meta_connection(int sock, short events, void *data) {
|
||||
void handle_new_meta_connection(void *data, int flags) {
|
||||
listen_socket_t *l = data;
|
||||
connection_t *c;
|
||||
sockaddr_t sa;
|
||||
int fd;
|
||||
socklen_t len = sizeof sa;
|
||||
|
||||
fd = accept(sock, &sa.sa, &len);
|
||||
fd = accept(l->tcp.fd, &sa.sa, &len);
|
||||
|
||||
if(fd < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Accepting a new connection failed: %s", sockstrerror(sockerrno));
|
||||
|
|
@ -552,9 +551,7 @@ void handle_new_meta_connection(int sock, short events, void *data) {
|
|||
|
||||
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Connection from %s", c->hostname);
|
||||
|
||||
event_set(&c->inevent, c->socket, EV_READ | EV_PERSIST, handle_meta_connection_data, c);
|
||||
event_set(&c->outevent, c->socket, EV_WRITE | EV_PERSIST, handle_meta_write, c);
|
||||
event_add(&c->inevent, NULL);
|
||||
io_add(&c->io, handle_meta_io, c, c->socket, IO_READ);
|
||||
|
||||
configure_tcp(c);
|
||||
|
||||
|
|
@ -565,8 +562,7 @@ void handle_new_meta_connection(int sock, short events, void *data) {
|
|||
}
|
||||
|
||||
static void free_outgoing(outgoing_t *outgoing) {
|
||||
if(event_initialized(&outgoing->ev))
|
||||
event_del(&outgoing->ev);
|
||||
timeout_del(&outgoing->ev);
|
||||
|
||||
if(outgoing->ai)
|
||||
freeaddrinfo(outgoing->ai);
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ struct addrinfo *str2addrinfo(const char *address, const char *service, int sock
|
|||
|
||||
sockaddr_t str2sockaddr(const char *address, const char *port) {
|
||||
struct addrinfo *ai, hint = {0};
|
||||
sockaddr_t result;
|
||||
sockaddr_t result = {{0}};
|
||||
int err;
|
||||
|
||||
hint.ai_family = AF_UNSPEC;
|
||||
|
|
|
|||
10
src/node.c
10
src/node.c
|
|
@ -78,8 +78,7 @@ void free_node(node_t *n) {
|
|||
ecdsa_free(&n->ecdsa);
|
||||
sptps_stop(&n->sptps);
|
||||
|
||||
if(timeout_initialized(&n->mtuevent))
|
||||
event_del(&n->mtuevent);
|
||||
timeout_del(&n->mtutimeout);
|
||||
|
||||
if(n->hostname)
|
||||
free(n->hostname);
|
||||
|
|
@ -129,6 +128,13 @@ void update_node_udp(node_t *n, const sockaddr_t *sa) {
|
|||
|
||||
if(sa) {
|
||||
n->address = *sa;
|
||||
n->sock = 0;
|
||||
for(int i = 0; i < listen_sockets; i++) {
|
||||
if(listen_socket[i].sa.sa.sa_family == sa->sa.sa_family) {
|
||||
n->sock = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
hash_insert(node_udp_cache, sa, n);
|
||||
free(n->hostname);
|
||||
n->hostname = sockaddr2hostname(&n->address);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "cipher.h"
|
||||
#include "connection.h"
|
||||
#include "digest.h"
|
||||
#include "event.h"
|
||||
#include "subnet.h"
|
||||
|
||||
typedef struct node_status_t {
|
||||
|
|
@ -83,7 +84,7 @@ typedef struct node_t {
|
|||
length_t minmtu; /* Probed minimum MTU */
|
||||
length_t maxmtu; /* Probed maximum MTU */
|
||||
int mtuprobes; /* Number of probes */
|
||||
struct event mtuevent; /* Probe event */
|
||||
timeout_t mtutimeout; /* Probe event */
|
||||
|
||||
uint64_t in_packets;
|
||||
uint64_t in_bytes;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "control.h"
|
||||
#include "device.h"
|
||||
#include "edge.h"
|
||||
#include "event.h"
|
||||
#include "logger.h"
|
||||
#include "net.h"
|
||||
#include "node.h"
|
||||
|
|
@ -127,7 +128,7 @@ DWORD WINAPI controlhandler(DWORD request, DWORD type, LPVOID boe, LPVOID bah) {
|
|||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
event_loopexit(NULL);
|
||||
event_exit();
|
||||
status.dwWaitHint = 30000;
|
||||
status.dwCurrentState = SERVICE_STOP_PENDING;
|
||||
SetServiceStatus(statushandle, &status);
|
||||
|
|
|
|||
|
|
@ -165,7 +165,24 @@ static void free_past_request(past_request_t *r) {
|
|||
free(r);
|
||||
}
|
||||
|
||||
static struct event past_request_event;
|
||||
static timeout_t past_request_timeout;
|
||||
|
||||
static void age_past_requests(void *data) {
|
||||
int left = 0, deleted = 0;
|
||||
|
||||
for splay_each(past_request_t, p, past_request_tree) {
|
||||
if(p->firstseen + pinginterval <= now.tv_sec)
|
||||
splay_delete_node(past_request_tree, node), deleted++;
|
||||
else
|
||||
left++;
|
||||
}
|
||||
|
||||
if(left || deleted)
|
||||
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Aging past requests: deleted %d, left %d", deleted, left);
|
||||
|
||||
if(left)
|
||||
timeout_set(&past_request_timeout, &(struct timeval){10, rand() % 100000});
|
||||
}
|
||||
|
||||
bool seen_request(const char *request) {
|
||||
past_request_t *new, p = {NULL};
|
||||
|
|
@ -180,39 +197,17 @@ bool seen_request(const char *request) {
|
|||
new->request = xstrdup(request);
|
||||
new->firstseen = time(NULL);
|
||||
splay_insert(past_request_tree, new);
|
||||
event_add(&past_request_event, &(struct timeval){10, 0});
|
||||
timeout_add(&past_request_timeout, age_past_requests, NULL, &(struct timeval){10, rand() % 100000});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void age_past_requests(int fd, short events, void *data) {
|
||||
int left = 0, deleted = 0;
|
||||
time_t now = time(NULL);
|
||||
|
||||
for splay_each(past_request_t, p, past_request_tree) {
|
||||
if(p->firstseen + pinginterval <= now)
|
||||
splay_delete_node(past_request_tree, node), deleted++;
|
||||
else
|
||||
left++;
|
||||
}
|
||||
|
||||
if(left || deleted)
|
||||
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Aging past requests: deleted %d, left %d",
|
||||
deleted, left);
|
||||
|
||||
if(left)
|
||||
event_add(&past_request_event, &(struct timeval){10, 0});
|
||||
}
|
||||
|
||||
void init_requests(void) {
|
||||
past_request_tree = splay_alloc_tree((splay_compare_t) past_request_compare, (splay_action_t) free_past_request);
|
||||
|
||||
timeout_set(&past_request_event, age_past_requests, NULL);
|
||||
}
|
||||
|
||||
void exit_requests(void) {
|
||||
splay_delete_tree(past_request_tree);
|
||||
|
||||
if(timeout_initialized(&past_request_event))
|
||||
event_del(&past_request_event);
|
||||
timeout_del(&past_request_timeout);
|
||||
}
|
||||
|
|
|
|||
120
src/route.c
120
src/route.c
|
|
@ -59,7 +59,7 @@ static const size_t opt_size = sizeof(struct nd_opt_hdr);
|
|||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
static struct event age_subnets_event;
|
||||
static timeout_t age_subnets_timeout;
|
||||
|
||||
/* RFC 1071 */
|
||||
|
||||
|
|
@ -84,13 +84,12 @@ static uint16_t inet_checksum(void *data, int len, uint16_t prevsum) {
|
|||
static bool ratelimit(int frequency) {
|
||||
static time_t lasttime = 0;
|
||||
static int count = 0;
|
||||
time_t now = time(NULL);
|
||||
|
||||
if(lasttime == now) {
|
||||
if(lasttime == now.tv_sec) {
|
||||
if(count >= frequency)
|
||||
return true;
|
||||
} else {
|
||||
lasttime = now;
|
||||
lasttime = now.tv_sec;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
|
|
@ -115,15 +114,22 @@ static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *pac
|
|||
mtu = via->mtu;
|
||||
|
||||
/* Find TCP header */
|
||||
int start = 0;
|
||||
int start = ether_size;
|
||||
uint16_t type = packet->data[12] << 8 | packet->data[13];
|
||||
|
||||
if(type == ETH_P_IP && packet->data[23] == 6)
|
||||
start = 14 + (packet->data[14] & 0xf) * 4;
|
||||
else if(type == ETH_P_IPV6 && packet->data[20] == 6)
|
||||
start = 14 + 40;
|
||||
if(type == ETH_P_8021Q) {
|
||||
start += 4;
|
||||
type = packet->data[16] << 8 | packet->data[17];
|
||||
}
|
||||
|
||||
if(!start || packet->len <= start + 20)
|
||||
if(type == ETH_P_IP && packet->data[start + 9] == 6)
|
||||
start += (packet->data[start] & 0xf) * 4;
|
||||
else if(type == ETH_P_IPV6 && packet->data[start + 6] == 6)
|
||||
start += 40;
|
||||
else
|
||||
return;
|
||||
|
||||
if(packet->len <= start + 20)
|
||||
return;
|
||||
|
||||
/* Use data offset field to calculate length of options field */
|
||||
|
|
@ -185,12 +191,11 @@ static void swap_mac_addresses(vpn_packet_t *packet) {
|
|||
memcpy(&packet->data[6], &tmp, sizeof tmp);
|
||||
}
|
||||
|
||||
static void age_subnets(int fd, short events, void *data) {
|
||||
static void age_subnets(void *data) {
|
||||
bool left = false;
|
||||
time_t now = time(NULL);
|
||||
|
||||
for splay_each(subnet_t, s, myself->subnet_tree) {
|
||||
if(s->expires && s->expires < now) {
|
||||
if(s->expires && s->expires < now.tv_sec) {
|
||||
if(debug_level >= DEBUG_TRAFFIC) {
|
||||
char netstr[MAXNETSTR];
|
||||
if(net2str(netstr, sizeof netstr, s))
|
||||
|
|
@ -209,7 +214,7 @@ static void age_subnets(int fd, short events, void *data) {
|
|||
}
|
||||
|
||||
if(left)
|
||||
event_add(&age_subnets_event, &(struct timeval){10, 0});
|
||||
timeout_set(&age_subnets_timeout, &(struct timeval){10, rand() % 100000});
|
||||
}
|
||||
|
||||
static void learn_mac(mac_t *address) {
|
||||
|
|
@ -236,9 +241,7 @@ static void learn_mac(mac_t *address) {
|
|||
if(c->status.active)
|
||||
send_add_subnet(c, subnet);
|
||||
|
||||
if(!timeout_initialized(&age_subnets_event))
|
||||
timeout_set(&age_subnets_event, age_subnets, NULL);
|
||||
event_add(&age_subnets_event, &(struct timeval){10, 0});
|
||||
timeout_add(&age_subnets_timeout, age_subnets, NULL, &(struct timeval){10, rand() % 100000});
|
||||
} else {
|
||||
if(subnet->expires)
|
||||
subnet->expires = time(NULL) + macexpire;
|
||||
|
|
@ -247,7 +250,7 @@ static void learn_mac(mac_t *address) {
|
|||
|
||||
/* RFC 792 */
|
||||
|
||||
static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, uint8_t type, uint8_t code) {
|
||||
static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) {
|
||||
struct ip ip = {0};
|
||||
struct icmp icmp = {0};
|
||||
|
||||
|
|
@ -320,7 +323,7 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, uint8_t
|
|||
|
||||
/* RFC 791 */
|
||||
|
||||
static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet) {
|
||||
static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet, length_t ether_size) {
|
||||
struct ip ip;
|
||||
vpn_packet_t fragment;
|
||||
int len, maxlen, todo;
|
||||
|
|
@ -384,7 +387,7 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) {
|
|||
dest.x[2],
|
||||
dest.x[3]);
|
||||
|
||||
route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_NET_UNKNOWN);
|
||||
route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_UNKNOWN);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -394,10 +397,10 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) {
|
|||
}
|
||||
|
||||
if(!subnet->owner->status.reachable)
|
||||
return route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_NET_UNREACH);
|
||||
return route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_UNREACH);
|
||||
|
||||
if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself)
|
||||
return route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_NET_ANO);
|
||||
return route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_ANO);
|
||||
|
||||
if(priorityinheritance)
|
||||
packet->priority = packet->data[15];
|
||||
|
|
@ -410,15 +413,15 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) {
|
|||
}
|
||||
|
||||
if(directonly && subnet->owner != via)
|
||||
return route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_NET_ANO);
|
||||
return route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_ANO);
|
||||
|
||||
if(via && packet->len > MAX(via->mtu, 590) && via != myself) {
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
|
||||
if(packet->data[20] & 0x40) {
|
||||
packet->len = MAX(via->mtu, 590);
|
||||
route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED);
|
||||
route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED);
|
||||
} else {
|
||||
fragment_ipv4_packet(via, packet);
|
||||
fragment_ipv4_packet(via, packet, ether_size);
|
||||
}
|
||||
|
||||
return;
|
||||
|
|
@ -445,7 +448,7 @@ static void route_ipv4(node_t *source, vpn_packet_t *packet) {
|
|||
|
||||
/* RFC 2463 */
|
||||
|
||||
static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, uint8_t type, uint8_t code) {
|
||||
static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) {
|
||||
struct ip6_hdr ip6;
|
||||
struct icmp6_hdr icmp6 = {0};
|
||||
uint16_t checksum;
|
||||
|
|
@ -543,7 +546,7 @@ static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) {
|
|||
ntohs(dest.x[6]),
|
||||
ntohs(dest.x[7]));
|
||||
|
||||
route_ipv6_unreachable(source, packet, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR);
|
||||
route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -553,10 +556,10 @@ static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) {
|
|||
}
|
||||
|
||||
if(!subnet->owner->status.reachable)
|
||||
return route_ipv6_unreachable(source, packet, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE);
|
||||
return route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE);
|
||||
|
||||
if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself)
|
||||
return route_ipv6_unreachable(source, packet, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN);
|
||||
return route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN);
|
||||
|
||||
via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
|
||||
|
||||
|
|
@ -566,12 +569,12 @@ static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) {
|
|||
}
|
||||
|
||||
if(directonly && subnet->owner != via)
|
||||
return route_ipv6_unreachable(source, packet, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN);
|
||||
return route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN);
|
||||
|
||||
if(via && packet->len > MAX(via->mtu, 1294) && via != myself) {
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
|
||||
packet->len = MAX(via->mtu, 1294);
|
||||
route_ipv6_unreachable(source, packet, ICMP6_PACKET_TOO_BIG, 0);
|
||||
route_ipv6_unreachable(source, packet, ether_size, ICMP6_PACKET_TOO_BIG, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -842,17 +845,24 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
|
|||
if(via && packet->len > via->mtu && via != myself) {
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
|
||||
uint16_t type = packet->data[12] << 8 | packet->data[13];
|
||||
if(type == ETH_P_IP && packet->len > 590) {
|
||||
if(packet->data[20] & 0x40) {
|
||||
length_t ethlen = 14;
|
||||
|
||||
if(type == ETH_P_8021Q) {
|
||||
type = packet->data[16] << 8 | packet->data[17];
|
||||
ethlen += 4;
|
||||
}
|
||||
|
||||
if(type == ETH_P_IP && packet->len > 576 + ethlen) {
|
||||
if(packet->data[6 + ethlen] & 0x40) {
|
||||
packet->len = via->mtu;
|
||||
route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED);
|
||||
route_ipv4_unreachable(source, packet, ethlen, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED);
|
||||
} else {
|
||||
fragment_ipv4_packet(via, packet);
|
||||
fragment_ipv4_packet(via, packet, ethlen);
|
||||
}
|
||||
return;
|
||||
} else if(type == ETH_P_IPV6 && packet->len > 1294) {
|
||||
} else if(type == ETH_P_IPV6 && packet->len > 1280 + ethlen) {
|
||||
packet->len = via->mtu;
|
||||
route_ipv6_unreachable(source, packet, ICMP6_PACKET_TOO_BIG, 0);
|
||||
route_ipv6_unreachable(source, packet, ethlen, ICMP6_PACKET_TOO_BIG, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -881,42 +891,48 @@ static void send_pcap(vpn_packet_t *packet) {
|
|||
|
||||
static bool do_decrement_ttl(node_t *source, vpn_packet_t *packet) {
|
||||
uint16_t type = packet->data[12] << 8 | packet->data[13];
|
||||
length_t ethlen = ether_size;
|
||||
|
||||
if(type == ETH_P_8021Q) {
|
||||
type = packet->data[16] << 8 | packet->data[17];
|
||||
ethlen += 4;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case ETH_P_IP:
|
||||
if(!checklength(source, packet, 14 + 32))
|
||||
if(!checklength(source, packet, ethlen + ip_size))
|
||||
return false;
|
||||
|
||||
if(packet->data[22] < 1) {
|
||||
if(packet->data[25] != IPPROTO_ICMP || packet->data[46] != ICMP_TIME_EXCEEDED)
|
||||
route_ipv4_unreachable(source, packet, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL);
|
||||
if(packet->data[ethlen + 8] < 1) {
|
||||
if(packet->data[ethlen + 11] != IPPROTO_ICMP || packet->data[ethlen + 32] != ICMP_TIME_EXCEEDED)
|
||||
route_ipv4_unreachable(source, packet, ethlen, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t old = packet->data[22] << 8 | packet->data[23];
|
||||
packet->data[22]--;
|
||||
uint16_t new = packet->data[22] << 8 | packet->data[23];
|
||||
uint16_t old = packet->data[ethlen + 8] << 8 | packet->data[ethlen + 9];
|
||||
packet->data[ethlen + 8]--;
|
||||
uint16_t new = packet->data[ethlen + 8] << 8 | packet->data[ethlen + 9];
|
||||
|
||||
uint32_t checksum = packet->data[24] << 8 | packet->data[25];
|
||||
uint32_t checksum = packet->data[ethlen + 10] << 8 | packet->data[ethlen + 11];
|
||||
checksum += old + (~new & 0xFFFF);
|
||||
while(checksum >> 16)
|
||||
checksum = (checksum & 0xFFFF) + (checksum >> 16);
|
||||
packet->data[24] = checksum >> 8;
|
||||
packet->data[25] = checksum & 0xff;
|
||||
packet->data[ethlen + 10] = checksum >> 8;
|
||||
packet->data[ethlen + 11] = checksum & 0xff;
|
||||
|
||||
return true;
|
||||
|
||||
case ETH_P_IPV6:
|
||||
if(!checklength(source, packet, 14 + 40))
|
||||
if(!checklength(source, packet, ethlen + ip6_size))
|
||||
return false;
|
||||
|
||||
if(packet->data[21] < 1) {
|
||||
if(packet->data[20] != IPPROTO_ICMPV6 || packet->data[54] != ICMP6_TIME_EXCEEDED)
|
||||
route_ipv6_unreachable(source, packet, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT);
|
||||
if(packet->data[ethlen + 7] < 1) {
|
||||
if(packet->data[ethlen + 6] != IPPROTO_ICMPV6 || packet->data[ethlen + 40] != ICMP6_TIME_EXCEEDED)
|
||||
route_ipv6_unreachable(source, packet, ethlen, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT);
|
||||
return false;
|
||||
}
|
||||
|
||||
packet->data[21]--;
|
||||
packet->data[ethlen + 7]--;
|
||||
|
||||
return true;
|
||||
|
||||
|
|
|
|||
|
|
@ -398,6 +398,8 @@ splay_node_t *splay_insert_node(splay_tree_t *tree, splay_node_t *node) {
|
|||
splay_node_t *closest;
|
||||
int result;
|
||||
|
||||
node->left = node->right = node->parent = node->next = node->prev = NULL;
|
||||
|
||||
if(!tree->root)
|
||||
splay_insert_top(tree, node);
|
||||
else {
|
||||
|
|
@ -418,6 +420,7 @@ splay_node_t *splay_insert_node(splay_tree_t *tree, splay_node_t *node) {
|
|||
void splay_insert_top(splay_tree_t *tree, splay_node_t *node) {
|
||||
node->prev = node->next = node->left = node->right = node->parent = NULL;
|
||||
tree->head = tree->tail = tree->root = node;
|
||||
tree->count++;
|
||||
}
|
||||
|
||||
void splay_insert_before(splay_tree_t *tree, splay_node_t *before, splay_node_t *node) {
|
||||
|
|
@ -446,6 +449,7 @@ void splay_insert_before(splay_tree_t *tree, splay_node_t *before, splay_node_t
|
|||
|
||||
node->parent = NULL;
|
||||
tree->root = node;
|
||||
tree->count++;
|
||||
}
|
||||
|
||||
void splay_insert_after(splay_tree_t *tree, splay_node_t *after, splay_node_t *node) {
|
||||
|
|
@ -474,6 +478,7 @@ void splay_insert_after(splay_tree_t *tree, splay_node_t *after, splay_node_t *n
|
|||
|
||||
node->parent = NULL;
|
||||
tree->root = node;
|
||||
tree->count++;
|
||||
}
|
||||
|
||||
splay_node_t *splay_unlink(splay_tree_t *tree, void *data) {
|
||||
|
|
@ -511,6 +516,8 @@ void splay_unlink_node(splay_tree_t *tree, splay_node_t *node) {
|
|||
} else {
|
||||
tree->root = NULL;
|
||||
}
|
||||
|
||||
tree->count--;
|
||||
}
|
||||
|
||||
void splay_delete_node(splay_tree_t *tree, splay_node_t *node) {
|
||||
|
|
|
|||
|
|
@ -58,6 +58,8 @@ typedef struct splay_tree_t {
|
|||
splay_compare_t compare;
|
||||
splay_action_t delete;
|
||||
|
||||
int count;
|
||||
|
||||
} splay_tree_t;
|
||||
|
||||
/* (De)constructors */
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ bool send_request(void *c, const char *msg, ...) { return false; }
|
|||
struct list_t *connection_list = NULL;
|
||||
bool send_meta(void *c, const char *msg , int len) { return false; }
|
||||
char *logfilename = NULL;
|
||||
struct timeval now;
|
||||
|
||||
ecdsa_t mykey, hiskey;
|
||||
|
||||
|
|
|
|||
|
|
@ -57,11 +57,12 @@ static char *name = NULL;
|
|||
static char *identname = NULL; /* program name for syslog */
|
||||
static char *pidfilename = NULL; /* pid file location */
|
||||
static char *confdir = NULL;
|
||||
static char controlcookie[1024];
|
||||
static char controlcookie[1025];
|
||||
char *netname = NULL;
|
||||
char *confbase = NULL;
|
||||
static char *tinc_conf = NULL;
|
||||
static char *hosts_dir = NULL;
|
||||
struct timeval now;
|
||||
|
||||
// Horrible global variables...
|
||||
static int pid = 0;
|
||||
|
|
@ -134,7 +135,7 @@ static void usage(bool status) {
|
|||
" generate-rsa-keys [bits] Generate a new RSA public/private keypair.\n"
|
||||
" generate-ecdsa-keys Generate a new ECDSA public/private keypair.\n"
|
||||
" dump Dump a list of one of the following things:\n"
|
||||
" nodes - all known nodes in the VPN\n"
|
||||
" [reachable] nodes - all known nodes in the VPN\n"
|
||||
" edges - all known connections in the VPN\n"
|
||||
" subnets - all known subnets in the VPN\n"
|
||||
" connections - all meta connections with ourself\n"
|
||||
|
|
@ -708,8 +709,8 @@ static bool connect_tincd(bool verbose) {
|
|||
return false;
|
||||
}
|
||||
|
||||
char host[128];
|
||||
char port[128];
|
||||
char host[129];
|
||||
char port[129];
|
||||
|
||||
if(fscanf(f, "%20d %1024s %128s port %128s", &pid, controlcookie, host, port) != 4) {
|
||||
if(verbose)
|
||||
|
|
@ -911,6 +912,19 @@ static int cmd_reload(int argc, char *argv[]) {
|
|||
}
|
||||
|
||||
static int cmd_dump(int argc, char *argv[]) {
|
||||
bool only_reachable = false;
|
||||
|
||||
if(argc > 2 && !strcasecmp(argv[1], "reachable")) {
|
||||
if(strcasecmp(argv[2], "nodes")) {
|
||||
fprintf(stderr, "`reachable' only supported for nodes.\n");
|
||||
usage(true);
|
||||
return 1;
|
||||
}
|
||||
only_reachable = true;
|
||||
argv++;
|
||||
argc--;
|
||||
}
|
||||
|
||||
if(argc != 2) {
|
||||
fprintf(stderr, "Invalid number of arguments.\n");
|
||||
usage(true);
|
||||
|
|
@ -985,8 +999,10 @@ static int cmd_dump(int argc, char *argv[]) {
|
|||
fprintf(stderr, "Unable to parse node dump from tincd: %s\n", line);
|
||||
return 1;
|
||||
}
|
||||
|
||||
memcpy(&status, &status_int, sizeof status);
|
||||
|
||||
if(do_graph) {
|
||||
memcpy(&status, &status_int, sizeof status);
|
||||
const char *color = "black";
|
||||
if(!strcmp(host, "MYSELF"))
|
||||
color = "green";
|
||||
|
|
@ -1000,6 +1016,8 @@ static int cmd_dump(int argc, char *argv[]) {
|
|||
color = "green";
|
||||
printf(" %s [label = \"%s\", color = \"%s\"%s];\n", node, node, color, strcmp(host, "MYSELF") ? "" : ", style = \"filled\"");
|
||||
} else {
|
||||
if(only_reachable && !status.reachable)
|
||||
continue;
|
||||
printf("%s at %s port %s cipher %d digest %d maclength %d compression %d options %x status %04x nexthop %s via %s distance %d pmtu %hd (min %hd max %hd)\n",
|
||||
node, host, port, cipher, digest, maclength, compression, options, status_int, nexthop, via, distance, pmtu, minmtu, maxmtu);
|
||||
}
|
||||
|
|
@ -1233,6 +1251,7 @@ static struct {
|
|||
} const variables[] = {
|
||||
/* Server configuration */
|
||||
{"AddressFamily", VAR_SERVER},
|
||||
{"AutoConnect", VAR_SERVER},
|
||||
{"BindToAddress", VAR_SERVER | VAR_MULTIPLE},
|
||||
{"BindToInterface", VAR_SERVER},
|
||||
{"Broadcast", VAR_SERVER},
|
||||
|
|
@ -1945,7 +1964,7 @@ static char *complete_command(const char *text, int state) {
|
|||
}
|
||||
|
||||
static char *complete_dump(const char *text, int state) {
|
||||
const char *matches[] = {"nodes", "edges", "subnets", "connections", "graph", NULL};
|
||||
const char *matches[] = {"reachable", "nodes", "edges", "subnets", "connections", "graph", NULL};
|
||||
static int i;
|
||||
|
||||
if(!state)
|
||||
|
|
|
|||
|
|
@ -450,11 +450,6 @@ int main2(int argc, char **argv) {
|
|||
}
|
||||
#endif
|
||||
|
||||
if(!event_init()) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error initializing libevent!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Setup sockets and open device. */
|
||||
|
||||
if(!setup_network())
|
||||
|
|
|
|||
198
src/top.c
198
src/top.c
|
|
@ -57,11 +57,13 @@ static int sortmode = 0;
|
|||
static bool cumulative = false;
|
||||
|
||||
static list_t node_list;
|
||||
static struct timeval now, prev, diff;
|
||||
static struct timeval cur, prev, diff;
|
||||
static int delay = 1000;
|
||||
static bool changed = true;
|
||||
static const char *unit = "bytes";
|
||||
static float scale = 1;
|
||||
static const char *bunit = "bytes";
|
||||
static float bscale = 1;
|
||||
static const char *punit = "pkts";
|
||||
static float pscale = 1;
|
||||
|
||||
#ifndef timersub
|
||||
#define timersub(a, b, c) do {(c)->tv_sec = (a)->tv_sec - (b)->tv_sec; (c)->tv_usec = (a)->tv_usec = (b)->tv_usec;} while(0)
|
||||
|
|
@ -69,10 +71,10 @@ static float scale = 1;
|
|||
|
||||
static void update(int fd) {
|
||||
sendline(fd, "%d %d", CONTROL, REQ_DUMP_TRAFFIC);
|
||||
gettimeofday(&now, NULL);
|
||||
gettimeofday(&cur, NULL);
|
||||
|
||||
timersub(&now, &prev, &diff);
|
||||
prev = now;
|
||||
timersub(&cur, &prev, &diff);
|
||||
prev = cur;
|
||||
float interval = diff.tv_sec + diff.tv_usec * 1e-6;
|
||||
|
||||
char line[4096];
|
||||
|
|
@ -136,12 +138,69 @@ static void update(int fd) {
|
|||
}
|
||||
}
|
||||
|
||||
static int cmpfloat(float a, float b) {
|
||||
if(a < b)
|
||||
return -1;
|
||||
else if(a > b)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmpu64(uint64_t a, uint64_t b) {
|
||||
if(a < b)
|
||||
return -1;
|
||||
else if(a > b)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sortfunc(const void *a, const void *b) {
|
||||
const nodestats_t *na = *(const nodestats_t **)a;
|
||||
const nodestats_t *nb = *(const nodestats_t **)b;
|
||||
switch(sortmode) {
|
||||
case 1:
|
||||
if(cumulative)
|
||||
return -cmpu64(na->in_packets, nb->in_packets) ?: na->i - nb->i;
|
||||
else
|
||||
return -cmpfloat(na->in_packets_rate, nb->in_packets_rate) ?: na->i - nb->i;
|
||||
case 2:
|
||||
if(cumulative)
|
||||
return -cmpu64(na->in_bytes, nb->in_bytes) ?: na->i - nb->i;
|
||||
else
|
||||
return -cmpfloat(na->in_bytes_rate, nb->in_bytes_rate) ?: na->i - nb->i;
|
||||
case 3:
|
||||
if(cumulative)
|
||||
return -cmpu64(na->out_packets, nb->out_packets) ?: na->i - nb->i;
|
||||
else
|
||||
return -cmpfloat(na->out_packets_rate, nb->out_packets_rate) ?: na->i - nb->i;
|
||||
case 4:
|
||||
if(cumulative)
|
||||
return -cmpu64(na->out_bytes, nb->out_bytes) ?: na->i - nb->i;
|
||||
else
|
||||
return -cmpfloat(na->out_bytes_rate, nb->out_bytes_rate) ?: na->i - nb->i;
|
||||
case 5:
|
||||
if(cumulative)
|
||||
return -cmpu64(na->in_packets + na->out_packets, nb->in_packets + nb->out_packets) ?: na->i - nb->i;
|
||||
else
|
||||
return -cmpfloat(na->in_packets_rate + na->out_packets_rate, nb->in_packets_rate + nb->out_packets_rate) ?: na->i - nb->i;
|
||||
case 6:
|
||||
if(cumulative)
|
||||
return -cmpu64(na->in_bytes + na->out_bytes, nb->in_bytes + nb->out_bytes) ?: na->i - nb->i;
|
||||
else
|
||||
return -cmpfloat(na->in_bytes_rate + na->out_bytes_rate, nb->in_bytes_rate + nb->out_bytes_rate) ?: na->i - nb->i;
|
||||
default:
|
||||
return strcmp(na->name, nb->name) ?: na->i - nb->i;
|
||||
}
|
||||
}
|
||||
|
||||
static void redraw(void) {
|
||||
erase();
|
||||
|
||||
mvprintw(0, 0, "Tinc %-16s Nodes: %4d Sort: %-10s %s", netname ?: "", node_list.count, sortname[sortmode], cumulative ? "Cumulative" : "Current");
|
||||
attrset(A_REVERSE);
|
||||
mvprintw(2, 0, "Node IN pkts IN %s OUT pkts OUT %s", unit, unit);
|
||||
mvprintw(2, 0, "Node IN %s IN %s OUT %s OUT %s", punit, bunit, punit, bunit);
|
||||
chgat(-1, A_REVERSE, 0, NULL);
|
||||
|
||||
static nodestats_t **sorted = 0;
|
||||
|
|
@ -157,63 +216,6 @@ static void redraw(void) {
|
|||
for(int i = 0; i < n; i++)
|
||||
sorted[i]->i = i;
|
||||
|
||||
int cmpfloat(float a, float b) {
|
||||
if(a < b)
|
||||
return -1;
|
||||
else if(a > b)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmpu64(uint64_t a, uint64_t b) {
|
||||
if(a < b)
|
||||
return -1;
|
||||
else if(a > b)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sortfunc(const void *a, const void *b) {
|
||||
const nodestats_t *na = *(const nodestats_t **)a;
|
||||
const nodestats_t *nb = *(const nodestats_t **)b;
|
||||
switch(sortmode) {
|
||||
case 1:
|
||||
if(cumulative)
|
||||
return -cmpu64(na->in_packets, nb->in_packets) ?: na->i - nb->i;
|
||||
else
|
||||
return -cmpfloat(na->in_packets_rate, nb->in_packets_rate) ?: na->i - nb->i;
|
||||
case 2:
|
||||
if(cumulative)
|
||||
return -cmpu64(na->in_bytes, nb->in_bytes) ?: na->i - nb->i;
|
||||
else
|
||||
return -cmpfloat(na->in_bytes_rate, nb->in_bytes_rate) ?: na->i - nb->i;
|
||||
case 3:
|
||||
if(cumulative)
|
||||
return -cmpu64(na->out_packets, nb->out_packets) ?: na->i - nb->i;
|
||||
else
|
||||
return -cmpfloat(na->out_packets_rate, nb->out_packets_rate) ?: na->i - nb->i;
|
||||
case 4:
|
||||
if(cumulative)
|
||||
return -cmpu64(na->out_bytes, nb->out_bytes) ?: na->i - nb->i;
|
||||
else
|
||||
return -cmpfloat(na->out_bytes_rate, nb->out_bytes_rate) ?: na->i - nb->i;
|
||||
case 5:
|
||||
if(cumulative)
|
||||
return -cmpu64(na->in_packets + na->out_packets, nb->in_packets + nb->out_packets) ?: na->i - nb->i;
|
||||
else
|
||||
return -cmpfloat(na->in_packets_rate + na->out_packets_rate, nb->in_packets_rate + nb->out_packets_rate) ?: na->i - nb->i;
|
||||
case 6:
|
||||
if(cumulative)
|
||||
return -cmpu64(na->in_bytes + na->out_bytes, nb->in_bytes + nb->out_bytes) ?: na->i - nb->i;
|
||||
else
|
||||
return -cmpfloat(na->in_bytes_rate + na->out_bytes_rate, nb->in_bytes_rate + nb->out_bytes_rate) ?: na->i - nb->i;
|
||||
default:
|
||||
return strcmp(na->name, nb->name) ?: na->i - nb->i;
|
||||
}
|
||||
}
|
||||
|
||||
qsort(sorted, n, sizeof *sorted, sortfunc);
|
||||
|
||||
for(int i = 0, row = 3; i < n; i++, row++) {
|
||||
|
|
@ -228,10 +230,10 @@ static void redraw(void) {
|
|||
|
||||
if(cumulative)
|
||||
mvprintw(row, 0, "%-16s %10"PRIu64" %10.0f %10"PRIu64" %10.0f",
|
||||
node->name, node->in_packets, node->in_bytes * scale, node->out_packets, node->out_bytes * scale);
|
||||
node->name, node->in_packets * pscale, node->in_bytes * bscale, node->out_packets * pscale, node->out_bytes * bscale);
|
||||
else
|
||||
mvprintw(row, 0, "%-16s %10.0f %10.0f %10.0f %10.0f",
|
||||
node->name, node->in_packets_rate, node->in_bytes_rate * scale, node->out_packets_rate, node->out_bytes_rate * scale);
|
||||
node->name, node->in_packets_rate * pscale, node->in_bytes_rate * bscale, node->out_packets_rate * pscale, node->out_bytes_rate * bscale);
|
||||
}
|
||||
|
||||
attrset(A_NORMAL);
|
||||
|
|
@ -262,45 +264,53 @@ void top(int fd) {
|
|||
break;
|
||||
}
|
||||
case 'c':
|
||||
cumulative = !cumulative;
|
||||
break;
|
||||
cumulative = !cumulative;
|
||||
break;
|
||||
case 'n':
|
||||
sortmode = 0;
|
||||
break;
|
||||
sortmode = 0;
|
||||
break;
|
||||
case 'i':
|
||||
sortmode = 2;
|
||||
break;
|
||||
sortmode = 2;
|
||||
break;
|
||||
case 'I':
|
||||
sortmode = 1;
|
||||
break;
|
||||
sortmode = 1;
|
||||
break;
|
||||
case 'o':
|
||||
sortmode = 4;
|
||||
break;
|
||||
sortmode = 4;
|
||||
break;
|
||||
case 'O':
|
||||
sortmode = 3;
|
||||
break;
|
||||
sortmode = 3;
|
||||
break;
|
||||
case 't':
|
||||
sortmode = 6;
|
||||
break;
|
||||
sortmode = 6;
|
||||
break;
|
||||
case 'T':
|
||||
sortmode = 5;
|
||||
break;
|
||||
sortmode = 5;
|
||||
break;
|
||||
case 'b':
|
||||
unit = "bytes";
|
||||
scale = 1;
|
||||
break;
|
||||
bunit = "bytes";
|
||||
bscale = 1;
|
||||
punit = "pkts";
|
||||
pscale = 1;
|
||||
break;
|
||||
case 'k':
|
||||
unit = "kbyte";
|
||||
scale = 1e-3;
|
||||
break;
|
||||
bunit = "kbyte";
|
||||
bscale = 1e-3;
|
||||
punit = "pkts";
|
||||
pscale = 1;
|
||||
break;
|
||||
case 'M':
|
||||
unit = "Mbyte";
|
||||
scale = 1e-6;
|
||||
break;
|
||||
bunit = "Mbyte";
|
||||
bscale = 1e-6;
|
||||
punit = "kpkt";
|
||||
pscale = 1e-3;
|
||||
break;
|
||||
case 'G':
|
||||
unit = "Gbyte";
|
||||
scale = 1e-9;
|
||||
break;
|
||||
bunit = "Gbyte";
|
||||
bscale = 1e-9;
|
||||
punit = "Mpkt";
|
||||
pscale = 1e-6;
|
||||
break;
|
||||
case 'q':
|
||||
case KEY_BREAK:
|
||||
running = false;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue