Merge branch '1.1' of github.com:gsliepen/tinc into thkr-1.1-ponyhof
This commit is contained in:
commit
35af740537
21 changed files with 301 additions and 136 deletions
14
Makefile.am
14
Makefile.am
|
@ -2,14 +2,22 @@
|
|||
|
||||
AUTOMAKE_OPTIONS = gnu
|
||||
|
||||
SUBDIRS = m4 src doc gui test
|
||||
SUBDIRS = src doc gui test
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
EXTRA_DIST = COPYING.README README.android
|
||||
|
||||
# If git describe works, force autoconf to run in order to make sure we have the
|
||||
# current version number from git in the resulting configure script.
|
||||
configure-version:
|
||||
-cd $(srcdir) && git describe && autoconf --force
|
||||
|
||||
# Triggering the README target means we are building a distribution (make dist).
|
||||
README: configure-version
|
||||
|
||||
ChangeLog:
|
||||
git log > ChangeLog
|
||||
(cd $(srcdir) && git log) > ChangeLog
|
||||
|
||||
deb:
|
||||
dpkg-buildpackage -rfakeroot
|
||||
|
@ -23,5 +31,5 @@ release:
|
|||
rm -f ChangeLog
|
||||
$(MAKE) ChangeLog
|
||||
echo "Please edit the NEWS file now..."
|
||||
/usr/bin/editor NEWS
|
||||
/usr/bin/editor $(srcdir)/NEWS
|
||||
$(MAKE) dist
|
||||
|
|
18
configure.ac
18
configure.ac
|
@ -1,10 +1,10 @@
|
|||
dnl Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.61)
|
||||
AC_INIT([tinc], [1.1pre11])
|
||||
AC_INIT([tinc], m4_esyscmd_s((git describe || echo UNKNOWN) | sed 's/release-//'))
|
||||
AC_CONFIG_SRCDIR([src/tincd.c])
|
||||
AC_GNU_SOURCE
|
||||
AM_INIT_AUTOMAKE([check-news std-options subdir-objects -Wall])
|
||||
AM_INIT_AUTOMAKE([info-in-builddir std-options subdir-objects -Wall])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
# Enable GNU extensions.
|
||||
|
@ -161,13 +161,13 @@ dnl We do this in multiple stages, because unlike Linux all the other operating
|
|||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS([stdbool.h syslog.h sys/file.h sys/ioctl.h sys/mman.h sys/param.h sys/resource.h sys/socket.h sys/time.h sys/uio.h sys/un.h sys/wait.h netdb.h arpa/inet.h dirent.h])
|
||||
AC_CHECK_HEADERS([net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/tun/if_tun.h net/if_tap.h net/tap/if_tap.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h time.h netpacket/packet.h],
|
||||
[], [], [#include "src/have.h"]
|
||||
[], [], [#include "$srcdir/src/have.h"]
|
||||
)
|
||||
AC_CHECK_HEADERS([netinet/if_ether.h netinet/ip.h netinet/ip6.h resolv.h],
|
||||
[], [], [#include "src/have.h"]
|
||||
[], [], [#include "$srcdir/src/have.h"]
|
||||
)
|
||||
AC_CHECK_HEADERS([netinet/tcp.h netinet/ip_icmp.h netinet/icmp6.h],
|
||||
[], [], [#include "src/have.h"]
|
||||
[], [], [#include "$srcdir/src/have.h"]
|
||||
)
|
||||
|
||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||
|
@ -182,13 +182,13 @@ tinc_ATTRIBUTE(__malloc__)
|
|||
tinc_ATTRIBUTE(__warn_unused_result__)
|
||||
|
||||
AC_CHECK_TYPES([socklen_t, struct ether_header, struct arphdr, struct ether_arp, struct in_addr, struct addrinfo, struct ip, struct icmp, struct in6_addr, struct sockaddr_in6, struct ip6_hdr, struct icmp6_hdr, struct nd_neighbor_solicit, struct nd_opt_hdr], , ,
|
||||
[#include "src/have.h"]
|
||||
[#include "$srcdir/src/have.h"]
|
||||
)
|
||||
|
||||
dnl Checks for library functions.
|
||||
AC_TYPE_SIGNAL
|
||||
AC_CHECK_FUNCS([asprintf daemon fchmod flock ftime fork get_current_dir_name gettimeofday mlockall putenv random select strdup strerror strsignal strtol system time usleep unsetenv vsyslog writev],
|
||||
[], [], [#include "src/have.h"]
|
||||
[], [], [#include "$srcdir/src/have.h"]
|
||||
)
|
||||
|
||||
dnl Support for SunOS
|
||||
|
@ -201,7 +201,7 @@ AC_CHECK_FUNC(gethostbyname, [], [
|
|||
])
|
||||
|
||||
AC_CHECK_DECLS([freeaddrinfo, gai_strerror, getaddrinfo, getnameinfo],
|
||||
[], [], [#include "src/have.h"]
|
||||
[], [], [#include "$srcdir/src/have.h"]
|
||||
)
|
||||
|
||||
AC_CHECK_DECLS([res_init], [AC_CHECK_LIB(resolv, res_init)], [], [
|
||||
|
@ -249,6 +249,6 @@ AC_ARG_ENABLE(jumbograms,
|
|||
]
|
||||
)
|
||||
|
||||
AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile m4/Makefile gui/Makefile test/Makefile])
|
||||
AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile gui/Makefile test/Makefile])
|
||||
|
||||
AC_OUTPUT
|
||||
|
|
|
@ -17,7 +17,7 @@ transform = s/ginstall/install/; @program_transform_name@
|
|||
# see GNUmakefile and Makefile.maint.
|
||||
|
||||
sample-config.tar.gz: sample-config
|
||||
GZIP=$(GZIP_ENV) $(AMTAR) chozf sample-config.tar.gz --exclude .svn sample-config
|
||||
GZIP=$(GZIP_ENV) $(AMTAR) chozf $@ --exclude .svn $<
|
||||
|
||||
tincd.8.html: tincd.8
|
||||
w3mman2html $? > $@
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
## Process this file with automake to produce Makefile.in -*-Makefile-*-
|
||||
|
||||
EXTRA_DIST = README *.m4
|
||||
|
|
@ -2,9 +2,12 @@
|
|||
|
||||
sbin_PROGRAMS = tincd tinc sptps_test sptps_keypair
|
||||
|
||||
## Make sure version.c is always rebuilt
|
||||
.PHONY: version.c
|
||||
version.c:
|
||||
## Make sure version.c is always rebuilt with the latest git information
|
||||
.PHONY: $(srcdir)/version.c version_git.h
|
||||
version_git.h:
|
||||
echo >$@
|
||||
-(cd $(srcdir) && git describe) && echo '#define GIT_DESCRIPTION "'`(cd $(srcdir) && git describe) | sed 's/release-//'`'"' >$@
|
||||
$(srcdir)/version.c: version_git.h
|
||||
|
||||
if LINUX
|
||||
sbin_PROGRAMS += sptps_speed
|
||||
|
@ -257,4 +260,4 @@ if TUNEMU
|
|||
LIBS += -lpcap
|
||||
endif
|
||||
|
||||
AM_CFLAGS = -DCONFDIR=\"$(sysconfdir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\"
|
||||
AM_CFLAGS = -DCONFDIR=\"$(sysconfdir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\" -I.
|
||||
|
|
|
@ -97,6 +97,7 @@ typedef struct connection_t {
|
|||
struct buffer_t outbuf;
|
||||
io_t io; /* input/output event on this metadata connection */
|
||||
int tcplen; /* length of incoming TCPpacket */
|
||||
int sptpslen; /* length of incoming SPTPS packet */
|
||||
int allow_request; /* defined if there's only one request possible */
|
||||
|
||||
struct timeval last_ping_time; /* last time we saw some activity from the other end or pinged them */
|
||||
|
|
43
src/meta.c
43
src/meta.c
|
@ -78,6 +78,20 @@ bool send_meta(connection_t *c, const char *buffer, int length) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void send_meta_raw(connection_t *c, const char *buffer, int length) {
|
||||
if(!c) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "send_meta() called with NULL pointer!");
|
||||
abort();
|
||||
}
|
||||
|
||||
logger(DEBUG_META, LOG_DEBUG, "Sending %d bytes of raw metadata to %s (%s)", length,
|
||||
c->name, c->hostname);
|
||||
|
||||
buffer_add(&c->outbuf, buffer, length);
|
||||
|
||||
io_set(&c->io, IO_READ | IO_WRITE);
|
||||
}
|
||||
|
||||
void broadcast_meta(connection_t *from, const char *buffer, int length) {
|
||||
for list_each(connection_t, c, connection_list)
|
||||
if(c != from && c->edge)
|
||||
|
@ -159,8 +173,33 @@ bool receive_meta(connection_t *c) {
|
|||
}
|
||||
|
||||
do {
|
||||
if(c->protocol_minor >= 2)
|
||||
return sptps_receive_data(&c->sptps, bufp, inlen);
|
||||
/* Are we receiving a SPTPS packet? */
|
||||
|
||||
if(c->sptpslen) {
|
||||
int len = MIN(inlen, c->sptpslen - c->inbuf.len);
|
||||
buffer_add(&c->inbuf, bufp, len);
|
||||
|
||||
char *sptpspacket = buffer_read(&c->inbuf, c->sptpslen);
|
||||
if(!sptpspacket)
|
||||
return true;
|
||||
|
||||
if(!receive_tcppacket_sptps(c, sptpspacket, c->sptpslen))
|
||||
return false;
|
||||
c->sptpslen = 0;
|
||||
|
||||
bufp += len;
|
||||
inlen -= len;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(c->protocol_minor >= 2) {
|
||||
int len = sptps_receive_data(&c->sptps, bufp, inlen);
|
||||
if(!len)
|
||||
return false;
|
||||
bufp += len;
|
||||
inlen -= len;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!c->status.decryptin) {
|
||||
endp = memchr(bufp, '\n', inlen);
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "connection.h"
|
||||
|
||||
extern bool send_meta(struct connection_t *, const char *, int);
|
||||
extern void send_meta_raw(struct connection_t *, const char *, int);
|
||||
extern bool send_meta_sptps(void *, uint8_t, const void *, size_t);
|
||||
extern bool receive_meta_sptps(void *, uint8_t, const void *, uint16_t);
|
||||
extern void broadcast_meta(struct connection_t *, const char *, int);
|
||||
|
|
|
@ -192,10 +192,11 @@ extern void handle_new_meta_connection(void *, int);
|
|||
extern void handle_new_unix_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 void *data, size_t len);
|
||||
extern bool send_sptps_data(node_t *to, node_t *from, int type, const void *data, size_t len);
|
||||
extern bool receive_sptps_record(void *handle, uint8_t type, const void *data, uint16_t len);
|
||||
extern void send_packet(struct node_t *, vpn_packet_t *);
|
||||
extern void receive_tcppacket(struct connection_t *, const char *, int);
|
||||
extern bool receive_tcppacket_sptps(struct connection_t *, const char *, int);
|
||||
extern void broadcast_packet(const struct node_t *, vpn_packet_t *);
|
||||
extern char *get_name(void);
|
||||
extern void device_enable(void);
|
||||
|
|
|
@ -429,6 +429,51 @@ void receive_tcppacket(connection_t *c, const char *buffer, int len) {
|
|||
receive_packet(c->node, &outpkt);
|
||||
}
|
||||
|
||||
bool receive_tcppacket_sptps(connection_t *c, const char *data, int len) {
|
||||
if (len < sizeof(node_id_t) + sizeof(node_id_t)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Got too short TCP SPTPS packet from %s (%s)", c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
node_t *to = lookup_node_id((node_id_t *)data);
|
||||
data += sizeof(node_id_t); len -= sizeof(node_id_t);
|
||||
if(!to) {
|
||||
logger(DEBUG_PROTOCOL, LOG_ERR, "Got TCP SPTPS packet from %s (%s) with unknown destination ID", c->name, c->hostname);
|
||||
return true;
|
||||
}
|
||||
|
||||
node_t *from = lookup_node_id((node_id_t *)data);
|
||||
data += sizeof(node_id_t); len -= sizeof(node_id_t);
|
||||
if(!from) {
|
||||
logger(DEBUG_PROTOCOL, LOG_ERR, "Got TCP SPTPS packet from %s (%s) with unknown source ID", c->name, c->hostname);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Help the sender reach us over UDP.
|
||||
Note that we only do this if we're the destination or the static relay;
|
||||
otherwise every hop would initiate its own UDP info message, resulting in elevated chatter. */
|
||||
if(to->via == myself)
|
||||
send_udp_info(myself, from);
|
||||
|
||||
/* If we're not the final recipient, relay the packet. */
|
||||
|
||||
if(to != myself) {
|
||||
send_sptps_data(to, from, 0, data, len);
|
||||
try_tx(to, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* The packet is for us */
|
||||
|
||||
if(!from->status.validkey) {
|
||||
logger(DEBUG_PROTOCOL, LOG_ERR, "Got SPTPS packet from %s (%s) but we don't have a valid key yet", from->name, from->hostname);
|
||||
return true;
|
||||
}
|
||||
sptps_receive_data(&from->sptps, data, len);
|
||||
send_mtu_info(myself, from, MTU);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void send_sptps_packet(node_t *n, vpn_packet_t *origpkt) {
|
||||
if(!n->status.validkey && !n->connection)
|
||||
return;
|
||||
|
@ -682,7 +727,7 @@ end:
|
|||
#endif
|
||||
}
|
||||
|
||||
static bool send_sptps_data_priv(node_t *to, node_t *from, int type, const void *data, size_t len) {
|
||||
bool send_sptps_data(node_t *to, node_t *from, int type, const void *data, size_t len) {
|
||||
node_t *relay = (to->via != myself && (type == PKT_PROBE || (len - SPTPS_DATAGRAM_OVERHEAD) <= to->via->minmtu)) ? to->via : to->nexthop;
|
||||
bool direct = from == myself && to == relay;
|
||||
bool relay_supported = (relay->options >> 24) >= 4;
|
||||
|
@ -691,6 +736,15 @@ static bool send_sptps_data_priv(node_t *to, node_t *from, int type, const void
|
|||
/* Send it via TCP if it is a handshake packet, TCPOnly is in use, this is a relay packet that the other node cannot understand, or this packet is larger than the MTU. */
|
||||
|
||||
if(type == SPTPS_HANDSHAKE || tcponly || (!direct && !relay_supported) || (type != PKT_PROBE && (len - SPTPS_DATAGRAM_OVERHEAD) > relay->minmtu)) {
|
||||
if((from != myself || to->status.validkey) && (to->nexthop->connection->options >> 24) >= 7) {
|
||||
char buf[len + sizeof to->id + sizeof from->id]; char* buf_ptr = buf;
|
||||
memcpy(buf_ptr, &to->id, sizeof to->id); buf_ptr += sizeof to->id;
|
||||
memcpy(buf_ptr, &from->id, sizeof from->id); buf_ptr += sizeof from->id;
|
||||
memcpy(buf_ptr, data, len); buf_ptr += len;
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Sending packet from %s (%s) to %s (%s) via %s (%s) (TCP)", from->name, from->hostname, to->name, to->hostname, to->nexthop->name, to->nexthop->hostname);
|
||||
return send_sptps_tcppacket(to->nexthop->connection, buf, sizeof buf);
|
||||
}
|
||||
|
||||
char buf[len * 4 / 3 + 5];
|
||||
b64encode(data, buf, len);
|
||||
/* If no valid key is known yet, send the packets using ANS_KEY requests,
|
||||
|
@ -699,7 +753,7 @@ static bool send_sptps_data_priv(node_t *to, node_t *from, int type, const void
|
|||
to->incompression = myself->incompression;
|
||||
return send_request(to->nexthop->connection, "%d %s %s %s -1 -1 -1 %d", ANS_KEY, from->name, to->name, buf, to->incompression);
|
||||
} else {
|
||||
return send_request(to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, from->name, to->name, REQ_SPTPS, buf);
|
||||
return send_request(to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, from->name, to->name, SPTPS_PACKET, buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -726,7 +780,7 @@ static bool send_sptps_data_priv(node_t *to, node_t *from, int type, const void
|
|||
choose_local_address(relay, &sa, &sock);
|
||||
if(!sa)
|
||||
choose_udp_address(relay, &sa, &sock);
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Sending packet from %s (%s) to %s (%s) via %s (%s)", from->name, from->hostname, to->name, to->hostname, relay->name, relay->hostname);
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Sending packet from %s (%s) to %s (%s) via %s (%s) (UDP)", from->name, from->hostname, to->name, to->hostname, relay->name, relay->hostname);
|
||||
if(sendto(listen_socket[sock].udp.fd, buf, buf_ptr - buf, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
|
||||
if(sockmsgsize(sockerrno)) {
|
||||
// Compensate for SPTPS overhead
|
||||
|
@ -745,10 +799,6 @@ static bool send_sptps_data_priv(node_t *to, node_t *from, int type, const void
|
|||
return true;
|
||||
}
|
||||
|
||||
bool send_sptps_data(void *handle, uint8_t type, const void *data, size_t len) {
|
||||
return send_sptps_data_priv(handle, myself, type, data, len);
|
||||
}
|
||||
|
||||
bool receive_sptps_record(void *handle, uint8_t type, const void *data, uint16_t len) {
|
||||
node_t *from = handle;
|
||||
|
||||
|
@ -1405,8 +1455,8 @@ skip_harder:
|
|||
/* If we're not the final recipient, relay the packet. */
|
||||
|
||||
if(to != myself) {
|
||||
send_sptps_data_priv(to, n, 0, DATA(&pkt), pkt.len - 2 * sizeof(node_id_t));
|
||||
try_tx_sptps(n, true);
|
||||
send_sptps_data(to, from, 0, DATA(&pkt), pkt.len - 2 * sizeof(node_id_t));
|
||||
try_tx_sptps(to, true);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -223,7 +223,7 @@ bool detach(void) {
|
|||
openlogger(identname, logmode);
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_NOTICE, "tincd %s (%s %s) starting, debug level %d",
|
||||
VERSION, BUILD_DATE, BUILD_TIME, debug_level);
|
||||
BUILD_VERSION, BUILD_DATE, BUILD_TIME, debug_level);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -41,7 +41,8 @@ static bool (*request_handlers[])(connection_t *, const char *) = {
|
|||
add_subnet_h, del_subnet_h,
|
||||
add_edge_h, del_edge_h,
|
||||
key_changed_h, req_key_h, ans_key_h, tcppacket_h, control_h,
|
||||
NULL, NULL, NULL, /* Not "real" requests (yet) */
|
||||
NULL, NULL, /* Not "real" requests (yet) */
|
||||
sptps_tcppacket_h,
|
||||
udp_info_h, mtu_info_h,
|
||||
};
|
||||
|
||||
|
@ -53,7 +54,7 @@ static char (*request_name[]) = {
|
|||
"PING", "PONG",
|
||||
"ADD_SUBNET", "DEL_SUBNET",
|
||||
"ADD_EDGE", "DEL_EDGE", "KEY_CHANGED", "REQ_KEY", "ANS_KEY", "PACKET", "CONTROL",
|
||||
"REQ_PUBKEY", "ANS_PUBKEY", "REQ_SPTPS", "UDP_INFO", "MTU_INFO",
|
||||
"REQ_PUBKEY", "ANS_PUBKEY", "SPTPS_PACKET", "UDP_INFO", "MTU_INFO",
|
||||
};
|
||||
|
||||
static splay_tree_t *past_request_tree;
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
/* Protocol version. Different major versions are incompatible. */
|
||||
|
||||
#define PROT_MAJOR 17
|
||||
#define PROT_MINOR 6 /* Should not exceed 255! */
|
||||
#define PROT_MINOR 7 /* Should not exceed 255! */
|
||||
|
||||
/* Silly Windows */
|
||||
|
||||
|
@ -48,7 +48,7 @@ typedef enum request_t {
|
|||
/* Tinc 1.1 requests */
|
||||
CONTROL,
|
||||
REQ_PUBKEY, ANS_PUBKEY,
|
||||
REQ_SPTPS,
|
||||
SPTPS_PACKET,
|
||||
UDP_INFO, MTU_INFO,
|
||||
LAST /* Guardian for the highest request number */
|
||||
} request_t;
|
||||
|
@ -109,6 +109,7 @@ extern void send_key_changed(void);
|
|||
extern bool send_req_key(struct node_t *);
|
||||
extern bool send_ans_key(struct node_t *);
|
||||
extern bool send_tcppacket(struct connection_t *, const struct vpn_packet_t *);
|
||||
extern bool send_sptps_tcppacket(struct connection_t *, const char*, int);
|
||||
extern bool send_udp_info(struct node_t *, struct node_t *);
|
||||
extern bool send_mtu_info(struct node_t *, struct node_t *, int);
|
||||
|
||||
|
@ -132,6 +133,7 @@ extern bool key_changed_h(struct connection_t *, const char *);
|
|||
extern bool req_key_h(struct connection_t *, const char *);
|
||||
extern bool ans_key_h(struct connection_t *, const char *);
|
||||
extern bool tcppacket_h(struct connection_t *, const char *);
|
||||
extern bool sptps_tcppacket_h(struct connection_t *, const char *);
|
||||
extern bool control_h(struct connection_t *, const char *);
|
||||
extern bool udp_info_h(struct connection_t *, const char *);
|
||||
extern bool mtu_info_h(struct connection_t *, const char *);
|
||||
|
|
|
@ -87,9 +87,13 @@ bool key_changed_h(connection_t *c, const char *request) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool send_sptps_data_myself(void *handle, uint8_t type, const void *data, size_t len) {
|
||||
return send_sptps_data(handle, myself, type, data, len);
|
||||
}
|
||||
|
||||
static bool send_initial_sptps_data(void *handle, uint8_t type, const void *data, size_t len) {
|
||||
node_t *to = handle;
|
||||
to->sptps.send_data = send_sptps_data;
|
||||
to->sptps.send_data = send_sptps_data_myself;
|
||||
char buf[len * 4 / 3 + 5];
|
||||
b64encode(data, buf, len);
|
||||
return send_request(to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, myself->name, to->name, REQ_KEY, buf);
|
||||
|
@ -121,7 +125,47 @@ bool send_req_key(node_t *to) {
|
|||
|
||||
/* REQ_KEY is overloaded to allow arbitrary requests to be routed between two nodes. */
|
||||
|
||||
static bool req_key_ext_h(connection_t *c, const char *request, node_t *from, int reqno) {
|
||||
static bool req_key_ext_h(connection_t *c, const char *request, node_t *from, node_t *to, int reqno) {
|
||||
/* If this is a SPTPS packet, see if sending UDP info helps.
|
||||
Note that we only do this if we're the destination or the static relay;
|
||||
otherwise every hop would initiate its own UDP info message, resulting in elevated chatter. */
|
||||
if((reqno == REQ_KEY || reqno == SPTPS_PACKET) && to->via == myself)
|
||||
send_udp_info(myself, from);
|
||||
|
||||
if(reqno == SPTPS_PACKET) {
|
||||
/* This is a SPTPS data packet. */
|
||||
|
||||
char buf[MAX_STRING_SIZE];
|
||||
int len;
|
||||
if(sscanf(request, "%*d %*s %*s %*d " MAX_STRING, buf) != 1 || !(len = b64decode(buf, buf, strlen(buf)))) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s) to %s (%s): %s", "SPTPS_PACKET", from->name, from->hostname, to->name, to->hostname, "invalid SPTPS data");
|
||||
return true;
|
||||
}
|
||||
|
||||
if(to != myself) {
|
||||
/* We don't just forward the request, because we want to use UDP if it's available. */
|
||||
send_sptps_data(to, from, 0, buf, len);
|
||||
try_tx(to, true);
|
||||
} else {
|
||||
/* The packet is for us */
|
||||
if(!from->status.validkey) {
|
||||
logger(DEBUG_PROTOCOL, LOG_ERR, "Got SPTPS_PACKET from %s (%s) but we don't have a valid key yet", from->name, from->hostname);
|
||||
return true;
|
||||
}
|
||||
sptps_receive_data(&from->sptps, buf, len);
|
||||
send_mtu_info(myself, from, MTU);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Requests that are not SPTPS data packets are forwarded as-is. */
|
||||
|
||||
if (to != myself)
|
||||
return send_request(to->nexthop->connection, "%s", request);
|
||||
|
||||
/* The request is for us */
|
||||
|
||||
switch(reqno) {
|
||||
case REQ_PUBKEY: {
|
||||
if(!node_read_ecdsa_public_key(from)) {
|
||||
|
@ -176,24 +220,7 @@ static bool req_key_ext_h(connection_t *c, const char *request, node_t *from, in
|
|||
from->status.validkey = false;
|
||||
from->status.waitingforkey = true;
|
||||
from->last_req_key = now.tv_sec;
|
||||
sptps_start(&from->sptps, from, false, true, myself->connection->ecdsa, from->ecdsa, label, sizeof label, send_sptps_data, receive_sptps_record);
|
||||
sptps_receive_data(&from->sptps, buf, len);
|
||||
send_mtu_info(myself, from, MTU);
|
||||
return true;
|
||||
}
|
||||
|
||||
case REQ_SPTPS: {
|
||||
if(!from->status.validkey) {
|
||||
logger(DEBUG_PROTOCOL, LOG_ERR, "Got REQ_SPTPS from %s (%s) but we don't have a valid key yet", from->name, from->hostname);
|
||||
return true;
|
||||
}
|
||||
|
||||
char buf[MAX_STRING_SIZE];
|
||||
int len;
|
||||
if(sscanf(request, "%*d %*s %*s %*d " MAX_STRING, buf) != 1 || !(len = b64decode(buf, buf, strlen(buf)))) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "REQ_SPTPS", from->name, from->hostname, "invalid SPTPS data");
|
||||
return true;
|
||||
}
|
||||
sptps_start(&from->sptps, from, false, true, myself->connection->ecdsa, from->ecdsa, label, sizeof label, send_sptps_data_myself, receive_sptps_record);
|
||||
sptps_receive_data(&from->sptps, buf, len);
|
||||
send_mtu_info(myself, from, MTU);
|
||||
return true;
|
||||
|
@ -238,19 +265,12 @@ bool req_key_h(connection_t *c, const char *request) {
|
|||
return true;
|
||||
}
|
||||
|
||||
/* If this is a SPTPS packet, see if sending UDP info helps.
|
||||
Note that we only do this if we're the destination or the static relay;
|
||||
otherwise every hop would initiate its own UDP info message, resulting in elevated chatter. */
|
||||
|
||||
if(experimental && (reqno == REQ_KEY || reqno == REQ_SPTPS) && to->via == myself)
|
||||
send_udp_info(myself, from);
|
||||
|
||||
/* Check if this key request is for us */
|
||||
|
||||
if(to == myself) { /* Yes */
|
||||
/* Is this an extended REQ_KEY message? */
|
||||
if(experimental && reqno)
|
||||
return req_key_ext_h(c, request, from, reqno);
|
||||
return req_key_ext_h(c, request, from, to, reqno);
|
||||
|
||||
/* No, just send our key back */
|
||||
send_ans_key(from);
|
||||
|
@ -264,7 +284,10 @@ bool req_key_h(connection_t *c, const char *request) {
|
|||
return true;
|
||||
}
|
||||
|
||||
/* TODO: forwarding SPTPS packets in this way is inefficient because we send them over TCP without checking for UDP connectivity */
|
||||
/* Is this an extended REQ_KEY message? */
|
||||
if(experimental && reqno)
|
||||
return req_key_ext_h(c, request, from, to, reqno);
|
||||
|
||||
send_request(to->nexthop->connection, "%s", request);
|
||||
}
|
||||
|
||||
|
|
|
@ -193,6 +193,36 @@ bool tcppacket_h(connection_t *c, const char *request) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool send_sptps_tcppacket(connection_t *c, const char* packet, int len) {
|
||||
/* If there already is a lot of data in the outbuf buffer, discard this packet.
|
||||
We use a very simple Random Early Drop algorithm. */
|
||||
|
||||
if(2.0 * c->outbuf.len / (float)maxoutbufsize - 1 > (float)rand()/(float)RAND_MAX)
|
||||
return true;
|
||||
|
||||
if(!send_request(c, "%d %hd", SPTPS_PACKET, len))
|
||||
return false;
|
||||
|
||||
send_meta_raw(c, packet, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sptps_tcppacket_h(connection_t *c, const char* request) {
|
||||
short int len;
|
||||
|
||||
if(sscanf(request, "%*d %hd", &len) != 1) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "SPTPS_PACKET", c->name,
|
||||
c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Set sptpslen to len, this will tell receive_meta() that a SPTPS packet is coming. */
|
||||
|
||||
c->sptpslen = len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Transmitting UDP information */
|
||||
|
||||
bool send_udp_info(node_t *from, node_t *to) {
|
||||
|
|
132
src/sptps.c
132
src/sptps.c
|
@ -495,90 +495,92 @@ static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len
|
|||
}
|
||||
|
||||
// Receive incoming data. Check if it contains a complete record, if so, handle it.
|
||||
bool sptps_receive_data(sptps_t *s, const void *data, size_t len) {
|
||||
size_t sptps_receive_data(sptps_t *s, const void *data, size_t len) {
|
||||
size_t total_read = 0;
|
||||
|
||||
if(!s->state)
|
||||
return error(s, EIO, "Invalid session state zero");
|
||||
|
||||
if(s->datagram)
|
||||
return sptps_receive_data_datagram(s, data, len);
|
||||
return sptps_receive_data_datagram(s, data, len) ? len : false;
|
||||
|
||||
while(len) {
|
||||
// First read the 2 length bytes.
|
||||
if(s->buflen < 2) {
|
||||
size_t toread = 2 - s->buflen;
|
||||
if(toread > len)
|
||||
toread = len;
|
||||
|
||||
memcpy(s->inbuf + s->buflen, data, toread);
|
||||
|
||||
s->buflen += toread;
|
||||
len -= toread;
|
||||
data += toread;
|
||||
|
||||
// Exit early if we don't have the full length.
|
||||
if(s->buflen < 2)
|
||||
return true;
|
||||
|
||||
// Get the length bytes
|
||||
|
||||
memcpy(&s->reclen, s->inbuf, 2);
|
||||
s->reclen = ntohs(s->reclen);
|
||||
|
||||
// If we have the length bytes, ensure our buffer can hold the whole request.
|
||||
s->inbuf = realloc(s->inbuf, s->reclen + 19UL);
|
||||
if(!s->inbuf)
|
||||
return error(s, errno, strerror(errno));
|
||||
|
||||
// Exit early if we have no more data to process.
|
||||
if(!len)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read up to the end of the record.
|
||||
size_t toread = s->reclen + (s->instate ? 19UL : 3UL) - s->buflen;
|
||||
// First read the 2 length bytes.
|
||||
if(s->buflen < 2) {
|
||||
size_t toread = 2 - s->buflen;
|
||||
if(toread > len)
|
||||
toread = len;
|
||||
|
||||
memcpy(s->inbuf + s->buflen, data, toread);
|
||||
|
||||
total_read += toread;
|
||||
s->buflen += toread;
|
||||
len -= toread;
|
||||
data += toread;
|
||||
|
||||
// If we don't have a whole record, exit.
|
||||
if(s->buflen < s->reclen + (s->instate ? 19UL : 3UL))
|
||||
return true;
|
||||
// Exit early if we don't have the full length.
|
||||
if(s->buflen < 2)
|
||||
return total_read;
|
||||
|
||||
// Update sequence number.
|
||||
// Get the length bytes
|
||||
|
||||
uint32_t seqno = s->inseqno++;
|
||||
memcpy(&s->reclen, s->inbuf, 2);
|
||||
s->reclen = ntohs(s->reclen);
|
||||
|
||||
// Check HMAC and decrypt.
|
||||
if(s->instate) {
|
||||
if(!chacha_poly1305_decrypt(s->incipher, seqno, s->inbuf + 2UL, s->reclen + 17UL, s->inbuf + 2UL, NULL))
|
||||
return error(s, EINVAL, "Failed to decrypt and verify record");
|
||||
}
|
||||
// If we have the length bytes, ensure our buffer can hold the whole request.
|
||||
s->inbuf = realloc(s->inbuf, s->reclen + 19UL);
|
||||
if(!s->inbuf)
|
||||
return error(s, errno, strerror(errno));
|
||||
|
||||
// Append a NULL byte for safety.
|
||||
s->inbuf[s->reclen + 3UL] = 0;
|
||||
|
||||
uint8_t type = s->inbuf[2];
|
||||
|
||||
if(type < SPTPS_HANDSHAKE) {
|
||||
if(!s->instate)
|
||||
return error(s, EIO, "Application record received before handshake finished");
|
||||
if(!s->receive_record(s->handle, type, s->inbuf + 3, s->reclen))
|
||||
return false;
|
||||
} else if(type == SPTPS_HANDSHAKE) {
|
||||
if(!receive_handshake(s, s->inbuf + 3, s->reclen))
|
||||
return false;
|
||||
} else {
|
||||
return error(s, EIO, "Invalid record type %d", type);
|
||||
}
|
||||
|
||||
s->buflen = 0;
|
||||
// Exit early if we have no more data to process.
|
||||
if(!len)
|
||||
return total_read;
|
||||
}
|
||||
|
||||
return true;
|
||||
// Read up to the end of the record.
|
||||
size_t toread = s->reclen + (s->instate ? 19UL : 3UL) - s->buflen;
|
||||
if(toread > len)
|
||||
toread = len;
|
||||
|
||||
memcpy(s->inbuf + s->buflen, data, toread);
|
||||
total_read += toread;
|
||||
s->buflen += toread;
|
||||
len -= toread;
|
||||
data += toread;
|
||||
|
||||
// If we don't have a whole record, exit.
|
||||
if(s->buflen < s->reclen + (s->instate ? 19UL : 3UL))
|
||||
return total_read;
|
||||
|
||||
// Update sequence number.
|
||||
|
||||
uint32_t seqno = s->inseqno++;
|
||||
|
||||
// Check HMAC and decrypt.
|
||||
if(s->instate) {
|
||||
if(!chacha_poly1305_decrypt(s->incipher, seqno, s->inbuf + 2UL, s->reclen + 17UL, s->inbuf + 2UL, NULL))
|
||||
return error(s, EINVAL, "Failed to decrypt and verify record");
|
||||
}
|
||||
|
||||
// Append a NULL byte for safety.
|
||||
s->inbuf[s->reclen + 3UL] = 0;
|
||||
|
||||
uint8_t type = s->inbuf[2];
|
||||
|
||||
if(type < SPTPS_HANDSHAKE) {
|
||||
if(!s->instate)
|
||||
return error(s, EIO, "Application record received before handshake finished");
|
||||
if(!s->receive_record(s->handle, type, s->inbuf + 3, s->reclen))
|
||||
return false;
|
||||
} else if(type == SPTPS_HANDSHAKE) {
|
||||
if(!receive_handshake(s, s->inbuf + 3, s->reclen))
|
||||
return false;
|
||||
} else {
|
||||
return error(s, EIO, "Invalid record type %d", type);
|
||||
}
|
||||
|
||||
s->buflen = 0;
|
||||
|
||||
return total_read;
|
||||
}
|
||||
|
||||
// Start a SPTPS session.
|
||||
|
|
|
@ -88,7 +88,7 @@ extern void (*sptps_log)(sptps_t *s, int s_errno, const char *format, va_list ap
|
|||
extern bool sptps_start(sptps_t *s, void *handle, bool initiator, bool datagram, ecdsa_t *mykey, ecdsa_t *hiskey, const void *label, size_t labellen, send_data_t send_data, receive_record_t receive_record);
|
||||
extern bool sptps_stop(sptps_t *s);
|
||||
extern bool sptps_send_record(sptps_t *s, uint8_t type, const void *data, uint16_t len);
|
||||
extern bool sptps_receive_data(sptps_t *s, const void *data, size_t len);
|
||||
extern size_t sptps_receive_data(sptps_t *s, const void *data, size_t len);
|
||||
extern bool sptps_force_kex(sptps_t *s);
|
||||
extern bool sptps_verify_datagram(sptps_t *s, const void *data, size_t len);
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ static struct option const long_options[] = {
|
|||
|
||||
static void version(void) {
|
||||
printf("%s version %s (built %s %s, protocol %d.%d)\n", PACKAGE,
|
||||
VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
|
||||
BUILD_VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
|
||||
printf("Copyright (C) 1998-2014 Ivo Timmermans, Guus Sliepen and others.\n"
|
||||
"See the AUTHORS file for a complete list.\n\n"
|
||||
"tinc comes with ABSOLUTELY NO WARRANTY. This is free software,\n"
|
||||
|
@ -150,7 +150,7 @@ static void usage(bool status) {
|
|||
" exchange Same as export followed by import\n"
|
||||
" exchange-all Same as export-all followed by import\n"
|
||||
" invite NODE [...] Generate an invitation for NODE\n"
|
||||
" join INVITATION Join a VPN using an INVITIATION\n"
|
||||
" join INVITATION Join a VPN using an INVITATION\n"
|
||||
" network [NETNAME] List all known networks, or switch to the one named NETNAME.\n"
|
||||
" fsck Check the configuration files for problems.\n"
|
||||
"\n");
|
||||
|
|
|
@ -343,7 +343,7 @@ int main(int argc, char **argv) {
|
|||
|
||||
if(show_version) {
|
||||
printf("%s version %s (built %s %s, protocol %d.%d)\n", PACKAGE,
|
||||
VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
|
||||
BUILD_VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
|
||||
printf("Copyright (C) 1998-2014 Ivo Timmermans, Guus Sliepen and others.\n"
|
||||
"See the AUTHORS file for a complete list.\n\n"
|
||||
"tinc comes with ABSOLUTELY NO WARRANTY. This is free software,\n"
|
||||
|
|
|
@ -18,7 +18,14 @@
|
|||
*/
|
||||
|
||||
#include "version.h"
|
||||
#include "version_git.h"
|
||||
#include "../config.h"
|
||||
|
||||
/* This file is always rebuilt (even if there are no changes) so that the following is updated */
|
||||
const char* const BUILD_DATE = __DATE__;
|
||||
const char* const BUILD_TIME = __TIME__;
|
||||
#ifdef GIT_DESCRIPTION
|
||||
const char* const BUILD_VERSION = GIT_DESCRIPTION;
|
||||
#else
|
||||
const char* const BUILD_VERSION = VERSION;
|
||||
#endif
|
||||
|
|
|
@ -22,5 +22,6 @@
|
|||
|
||||
extern const char* const BUILD_DATE;
|
||||
extern const char* const BUILD_TIME;
|
||||
extern const char* const BUILD_VERSION;
|
||||
|
||||
#endif /* __TINC_VERSION_H__ */
|
||||
|
|
Loading…
Reference in a new issue