Merge branch 'master' into 1.1
Conflicts: NEWS README configure.in doc/tinc.texi doc/tincd.8.in src/Makefile.am src/connection.c src/edge.c src/meta.c src/net.c src/net.h src/net_packet.c src/net_setup.c src/net_socket.c src/node.c src/openssl/rsagen.h src/protocol_auth.c src/protocol_edge.c src/subnet.c
This commit is contained in:
commit
108b238915
26 changed files with 288 additions and 124 deletions
|
@ -6,7 +6,7 @@ SUBDIRS = m4 lib src doc
|
|||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
EXTRA_DIST = config.rpath mkinstalldirs have.h system.h COPYING.README depcomp
|
||||
EXTRA_DIST = have.h system.h COPYING.README
|
||||
|
||||
ChangeLog:
|
||||
git log > ChangeLog
|
||||
|
|
27
NEWS
27
NEWS
|
@ -4,20 +4,39 @@ Version 1.1-cvs Work in progress
|
|||
|
||||
* Use splay trees instead of AVL trees.
|
||||
|
||||
Version 1.0.10 not yet released
|
||||
Version 1.0.11 Nov 1 2009
|
||||
|
||||
* Fixed potential crash when the HUP signal is sent.
|
||||
|
||||
* Fixes handling of weighted Subnets in switch and hub modes, preventing
|
||||
unnecessary broadcasts.
|
||||
|
||||
* Works around a MinGW bug that caused packets to Windows nodes to always be
|
||||
sent via TCP.
|
||||
|
||||
* Improvements to the PMTU discovery code, especially on Windows.
|
||||
|
||||
* Use UDP again in certain cases where 1.0.10 was too conservative and fell
|
||||
back to TCP unnecessarily.
|
||||
|
||||
* Allow fast roaming of hosts to other nodes in a switched VPN.
|
||||
|
||||
Version 1.0.10 Oct 18 2009
|
||||
|
||||
* Fixed potential crashes during shutdown and (in rare conditions) when other
|
||||
nodes disconnected from the VPN.
|
||||
|
||||
* Improved NAT handling: tinc now copes with mangled port numbers, and will
|
||||
automatically fall back to TCP if direct UDP connection between nodes is not
|
||||
possible.
|
||||
possible. The TCPOnly option should not have to be used anymore.
|
||||
|
||||
* Allow configuration files with CRLF line endings to be read on UNIX.
|
||||
|
||||
* Disable old RSA keys when generating new ones.
|
||||
* Disable old RSA keys when generating new ones, and raise the default size of
|
||||
new RSA keys to 2048 bits.
|
||||
|
||||
* Many fixes in the path MTU discovery code.
|
||||
* Many fixes in the path MTU discovery code, especially when Compression is
|
||||
being used.
|
||||
|
||||
* Tinc can now drop privileges and/or chroot itself.
|
||||
|
||||
|
|
3
README
3
README
|
@ -118,8 +118,7 @@ Support for routing IPv6 packets has been added. Just add Subnet lines with
|
|||
IPv6 addresses (without using :: abbreviations) and use ifconfig or ip (from
|
||||
the iproute package) to give the virtual network interface corresponding IPv6
|
||||
addresses. tinc does not provide autoconfiguration for IPv6 hosts, if you need
|
||||
it use radvd or zebra. Tunneling IPv6 packets only works on Linux, FreeBSD,
|
||||
Windows and possibly OpenBSD.
|
||||
it use radvd or zebra.
|
||||
|
||||
It is also possible to make tunnels to other tinc daemons over IPv6 networks,
|
||||
if the operating system supports IPv6. tinc will automatically use both IPv6
|
||||
|
|
3
THANKS
3
THANKS
|
@ -4,8 +4,9 @@ We would like to thank the following people for their contributions to tinc:
|
|||
* Allesandro Gatti
|
||||
* Andreas van Cranenburgh
|
||||
* Armijn Hemel
|
||||
* dnk
|
||||
* Cris van Pelt
|
||||
* Delf Eldkraft
|
||||
* dnk
|
||||
* Enrique Zanardi
|
||||
* Flynn Marquardt
|
||||
* Grzegorz Dymarek
|
||||
|
|
|
@ -427,13 +427,17 @@ higher priority. Packets will be sent to the node with the highest priority,
|
|||
unless that node is not reachable, in which case the node with the next highest
|
||||
priority will be tried, and so on.
|
||||
|
||||
.It Va TCPOnly Li = yes | no Pq no
|
||||
.It Va TCPOnly Li = yes | no Pq no Bq obsolete
|
||||
If this variable is set to yes,
|
||||
then the packets are tunnelled over the TCP connection instead of a UDP connection.
|
||||
This is especially useful for those who want to run a tinc daemon
|
||||
from behind a masquerading firewall,
|
||||
or if UDP packet routing is disabled somehow.
|
||||
Setting this options also implicitly sets IndirectData.
|
||||
|
||||
.Pp
|
||||
Since version 1.0.10, tinc will automatically detect whether communication via
|
||||
UDP is possible or not.
|
||||
.El
|
||||
|
||||
.Sh SCRIPTS
|
||||
|
@ -515,6 +519,9 @@ When a host becomes (un)reachable, this is set to the port number it uses for co
|
|||
|
||||
.It Ev SUBNET
|
||||
When a subnet becomes (un)reachable, this is set to the subnet.
|
||||
|
||||
.It Ev WEIGHT
|
||||
When a subnet becomes (un)reachable, this is set to the subnet weight.
|
||||
.El
|
||||
|
||||
.Sh FILES
|
||||
|
|
|
@ -85,8 +85,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#define getpid() GetCurrentProcessId()
|
||||
#endif
|
||||
|
||||
#include "gettext.h"
|
||||
|
||||
/* This version of `getopt' appears to the caller like standard Unix `getopt'
|
||||
but it behaves differently for the user, since it allows the user
|
||||
to intersperse the options with the other arguments.
|
||||
|
|
11
lib/utils.h
11
lib/utils.h
|
@ -27,6 +27,17 @@ extern void bin2hex(char *src, char *dst, int length);
|
|||
#ifdef HAVE_MINGW
|
||||
extern const char *winerror(int);
|
||||
#define strerror(x) ((x)>0?strerror(x):winerror(GetLastError()))
|
||||
#define sockerrno WSAGetLastError()
|
||||
#define sockstrerror(x) winerror(x)
|
||||
#define sockwouldblock(x) ((x) == WSAEWOULDBLOCK || (x) == WSAEINTR)
|
||||
#define sockmsgsize(x) ((x) == WSAEMSGSIZE)
|
||||
#define sockinprogress(x) ((x) == WSAEINPROGRESS || (x) == WSAEWOULDBLOCK)
|
||||
#else
|
||||
#define sockerrno errno
|
||||
#define sockstrerror(x) strerror(x)
|
||||
#define sockwouldblock(x) ((x) == EWOULDBLOCK || (x) == EINTR)
|
||||
#define sockmsgsize(x) ((x) == EMSGSIZE)
|
||||
#define sockinprogress(x) ((x) == EINPROGRESS)
|
||||
#endif
|
||||
|
||||
extern unsigned int bitfield_to_int(void *bitfield, size_t size);
|
||||
|
|
|
@ -34,6 +34,7 @@ void *realloc ();
|
|||
void free ();
|
||||
#endif
|
||||
|
||||
#include "dropin.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
#ifndef EXIT_FAILURE
|
||||
|
|
|
@ -35,9 +35,7 @@ tincd_LDADD = \
|
|||
tincctl_LDADD = \
|
||||
$(top_builddir)/lib/libvpn.a
|
||||
|
||||
localedir = $(datadir)/locale
|
||||
|
||||
AM_CFLAGS = @CFLAGS@ -DCONFDIR=\"$(sysconfdir)\" -DLOCALEDIR=\"$(localedir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\"
|
||||
AM_CFLAGS = @CFLAGS@ -DCONFDIR=\"$(sysconfdir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\"
|
||||
|
||||
dist-hook:
|
||||
rm -f `find . -type l`
|
||||
|
|
|
@ -150,6 +150,17 @@ bool setup_device(void) {
|
|||
if(routing_mode == RMODE_ROUTER)
|
||||
overwrite_mac = true;
|
||||
device_info = "Generic BSD tap device";
|
||||
#ifdef TAPGIFNAME
|
||||
{
|
||||
struct ifreq ifr;
|
||||
if(ioctl(device_fd, TAPGIFNAME, (void*)&ifr) == 0) {
|
||||
if(iface)
|
||||
free(iface);
|
||||
iface = xstrdup(ifr.ifr_name);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
break;
|
||||
#ifdef HAVE_TUNEMU
|
||||
case DEVICE_TYPE_TUNEMU:
|
||||
|
@ -209,7 +220,7 @@ bool read_packet(vpn_packet_t *packet) {
|
|||
break;
|
||||
default:
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR,
|
||||
_ ("Unknown IP version %d while reading packet from %s %s"),
|
||||
"Unknown IP version %d while reading packet from %s %s",
|
||||
packet->data[14] >> 4, device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
@ -240,7 +251,7 @@ bool read_packet(vpn_packet_t *packet) {
|
|||
|
||||
default:
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR,
|
||||
_ ("Unknown address family %x while reading packet from %s %s"),
|
||||
"Unknown address family %x while reading packet from %s %s",
|
||||
ntohl(type), device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
@ -268,7 +279,6 @@ bool read_packet(vpn_packet_t *packet) {
|
|||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s",
|
||||
packet->len, device_info);
|
||||
|
||||
logger(LOG_INFO, "E:fd_read");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ typedef struct connection_t {
|
|||
int protocol_version; /* used protocol */
|
||||
|
||||
int socket; /* socket used for this connection */
|
||||
long int options; /* options for this connection */
|
||||
uint32_t options; /* options for this connection */
|
||||
connection_status_t status; /* status info */
|
||||
int estimated_weight; /* estimation for the weight of the edge for this connection */
|
||||
struct timeval start; /* time this connection was started, used for above estimation */
|
||||
|
|
54
src/dummy/device.c
Normal file
54
src/dummy/device.c
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
device.c -- Dummy device
|
||||
Copyright (C) 2009 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 "logger.h"
|
||||
#include "net.h"
|
||||
|
||||
int device_fd = -1;
|
||||
char *device = "dummy";
|
||||
char *iface = "dummy";
|
||||
static char *device_info = "dummy device";
|
||||
|
||||
static int device_total_in = 0;
|
||||
static int device_total_out = 0;
|
||||
|
||||
bool setup_device(void) {
|
||||
logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
|
||||
return true;
|
||||
}
|
||||
|
||||
void close_device(void) {
|
||||
}
|
||||
|
||||
bool read_packet(vpn_packet_t *packet) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool write_packet(vpn_packet_t *packet) {
|
||||
device_total_out += packet->len;
|
||||
return true;
|
||||
}
|
||||
|
||||
void dump_device_stats(void) {
|
||||
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(LOG_DEBUG, " total bytes in: %10d", device_total_in);
|
||||
logger(LOG_DEBUG, " total bytes out: %10d", device_total_out);
|
||||
}
|
|
@ -31,7 +31,7 @@ typedef struct edge_t {
|
|||
struct node_t *to;
|
||||
sockaddr_t address;
|
||||
|
||||
long int options; /* options turned on for this edge */
|
||||
uint32_t options; /* options turned on for this edge */
|
||||
int weight; /* weight of this edge */
|
||||
|
||||
struct connection_t *connection; /* connection associated with this edge, if available */
|
||||
|
|
11
src/meta.c
11
src/meta.c
|
@ -92,7 +92,14 @@ bool receive_meta(connection_t *c) {
|
|||
inlen = recv(c->socket, inbuf, sizeof inbuf, 0);
|
||||
|
||||
if(inlen <= 0) {
|
||||
logger(LOG_ERR, "Receive callback called for %s (%s) but no data to receive: %s", c->name, c->hostname, strerror(errno));
|
||||
if(!inlen || !errno) {
|
||||
ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection closed by %s (%s)",
|
||||
c->name, c->hostname);
|
||||
} else if(sockwouldblock(sockerrno))
|
||||
return true;
|
||||
else
|
||||
logger(LOG_ERR, "Metadata socket read error for %s (%s): %s",
|
||||
c->name, c->hostname, sockstrerror(sockerrno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -152,7 +159,5 @@ bool receive_meta(connection_t *c) {
|
|||
}
|
||||
} while(inlen);
|
||||
|
||||
c->last_ping_time = time(NULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -208,7 +208,7 @@ void handle_meta_connection_data(int fd, short events, void *data) {
|
|||
else {
|
||||
ifdebug(CONNECTIONS) logger(LOG_DEBUG,
|
||||
"Error while connecting to %s (%s): %s",
|
||||
c->name, c->hostname, strerror(result));
|
||||
c->name, c->hostname, sockstrerror(result));
|
||||
closesocket(c->socket);
|
||||
do_outgoing_connection(c);
|
||||
return;
|
||||
|
|
|
@ -42,10 +42,6 @@
|
|||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
#ifdef WSAEMSGSIZE
|
||||
#define EMSGSIZE WSAEMSGSIZE
|
||||
#endif
|
||||
|
||||
int keylifetime = 0;
|
||||
int keyexpires = 0;
|
||||
static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999_MEM_COMPRESS : LZO1X_1_MEM_COMPRESS];
|
||||
|
@ -54,31 +50,61 @@ static void send_udppacket(node_t *, vpn_packet_t *);
|
|||
|
||||
#define MAX_SEQNO 1073741824
|
||||
|
||||
// mtuprobes == 1..30: initial discovery, send bursts with 1 second interval
|
||||
// mtuprobes == 31: sleep pinginterval seconds
|
||||
// mtuprobes == 32: send 1 burst, sleep pingtimeout second
|
||||
// mtuprobes == 33: no response from other side, restart PMTU discovery process
|
||||
|
||||
static void send_mtu_probe_handler(int fd, short events, void *data) {
|
||||
node_t *n = data;
|
||||
vpn_packet_t packet;
|
||||
int len, i;
|
||||
int timeout = 1;
|
||||
|
||||
n->mtuprobes++;
|
||||
|
||||
if(!n->status.reachable) {
|
||||
logger(LOG_DEBUG, "Trying to send MTU probe to unreachable node %s (%s)", n->name, n->hostname);
|
||||
if(!n->status.reachable || !n->status.validkey) {
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "Trying to send MTU probe to unreachable or rekeying node %s (%s)", n->name, n->hostname);
|
||||
n->mtuprobes = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if(n->mtuprobes > 32) {
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "%s (%s) did not respond to UDP ping, restarting PMTU discovery", n->name, n->hostname);
|
||||
n->mtuprobes = 1;
|
||||
n->minmtu = 0;
|
||||
n->maxmtu = MTU;
|
||||
}
|
||||
|
||||
if(n->mtuprobes >= 10 && !n->minmtu) {
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "No response to MTU probes from %s (%s)", n->name, n->hostname);
|
||||
n->mtuprobes = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
for(i = 0; i < 3; i++) {
|
||||
if(n->mtuprobes >= 30 || n->minmtu >= n->maxmtu) {
|
||||
n->mtu = n->minmtu;
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "Fixing MTU of %s (%s) to %d after %d probes", n->name, n->hostname, n->mtu, n->mtuprobes);
|
||||
return;
|
||||
}
|
||||
if(n->mtuprobes == 30 || (n->mtuprobes < 30 && n->minmtu >= n->maxmtu)) {
|
||||
if(n->minmtu > n->maxmtu)
|
||||
n->minmtu = n->maxmtu;
|
||||
else
|
||||
n->maxmtu = n->minmtu;
|
||||
n->mtu = n->minmtu;
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "Fixing MTU of %s (%s) to %d after %d probes", n->name, n->hostname, n->mtu, n->mtuprobes);
|
||||
n->mtuprobes = 31;
|
||||
}
|
||||
|
||||
if(n->mtuprobes == 31) {
|
||||
timeout = pinginterval;
|
||||
goto end;
|
||||
} else if(n->mtuprobes == 32) {
|
||||
timeout = pingtimeout;
|
||||
}
|
||||
|
||||
for(i = 0; i < 3; i++) {
|
||||
if(n->maxmtu <= n->minmtu)
|
||||
len = n->maxmtu;
|
||||
else
|
||||
len = n->minmtu + 1 + rand() % (n->maxmtu - n->minmtu);
|
||||
|
||||
len = n->minmtu + 1 + rand() % (n->maxmtu - n->minmtu);
|
||||
if(len < 64)
|
||||
len = 64;
|
||||
|
||||
|
@ -92,7 +118,8 @@ static void send_mtu_probe_handler(int fd, short events, void *data) {
|
|||
send_udppacket(n, &packet);
|
||||
}
|
||||
|
||||
event_add(&n->mtuevent, &(struct timeval){1, 0});
|
||||
end:
|
||||
event_add(&n->mtuevent, &(struct timeval){timeout, 0});
|
||||
}
|
||||
|
||||
void send_mtu_probe(node_t *n) {
|
||||
|
@ -106,10 +133,14 @@ void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
|
|||
|
||||
if(!packet->data[0]) {
|
||||
packet->data[0] = 1;
|
||||
send_packet(n, packet);
|
||||
send_udppacket(n, packet);
|
||||
} else {
|
||||
if(len > n->maxmtu)
|
||||
len = n->maxmtu;
|
||||
if(n->minmtu < len)
|
||||
n->minmtu = len;
|
||||
if(n->mtuprobes > 30)
|
||||
n->mtuprobes = 30;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -317,10 +348,13 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
|||
|
||||
if(n->options & OPTION_PMTU_DISCOVERY && inpkt->len > n->minmtu && (inpkt->data[12] | inpkt->data[13])) {
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO,
|
||||
"Packet for %s (%s) larger than minimum MTU, forwarding via TCP",
|
||||
n->name, n->hostname);
|
||||
"Packet for %s (%s) larger than minimum MTU, forwarding via %s",
|
||||
n->name, n->hostname, n != n->nexthop ? n->nexthop->name : "TCP");
|
||||
|
||||
send_tcppacket(n->nexthop->connection, origpkt);
|
||||
if(n != n->nexthop)
|
||||
send_packet(n->nexthop, origpkt);
|
||||
else
|
||||
send_tcppacket(n->nexthop->connection, origpkt);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -390,14 +424,14 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
|||
}
|
||||
#endif
|
||||
|
||||
if((sendto(listen_socket[sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, &(n->address.sa), SALEN(n->address.sa))) < 0) {
|
||||
if(errno == EMSGSIZE) {
|
||||
if(sendto(listen_socket[sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, &(n->address.sa), SALEN(n->address.sa)) < 0 && !sockwouldblock(sockerrno)) {
|
||||
if(sockmsgsize(sockerrno)) {
|
||||
if(n->maxmtu >= origlen)
|
||||
n->maxmtu = origlen - 1;
|
||||
if(n->mtu >= origlen)
|
||||
n->mtu = origlen - 1;
|
||||
} else
|
||||
logger(LOG_ERR, "Error sending packet to %s (%s): %s", n->name, n->hostname, strerror(errno));
|
||||
logger(LOG_ERR, "Error sending packet to %s (%s): %s", n->name, n->hostname, sockstrerror(sockerrno));
|
||||
}
|
||||
|
||||
end:
|
||||
|
@ -469,12 +503,17 @@ static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
|
|||
splay_node_t *node;
|
||||
edge_t *e;
|
||||
node_t *n = NULL;
|
||||
static time_t last_hard_try = 0;
|
||||
time_t now = time(NULL);
|
||||
|
||||
for(node = edge_weight_tree->head; node; node = node->next) {
|
||||
e = node->data;
|
||||
|
||||
if(sockaddrcmp_noport(from, &e->address))
|
||||
continue;
|
||||
if(sockaddrcmp_noport(from, &e->address)) {
|
||||
if(last_hard_try == now)
|
||||
continue;
|
||||
last_hard_try = now;
|
||||
}
|
||||
|
||||
if(!n)
|
||||
n = e->to;
|
||||
|
@ -499,8 +538,8 @@ void handle_incoming_vpn_data(int sock, short events, void *data) {
|
|||
pkt.len = recvfrom(sock, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen);
|
||||
|
||||
if(pkt.len < 0) {
|
||||
if(errno != EAGAIN && errno != EINTR)
|
||||
logger(LOG_ERR, "Receiving packet failed: %s", strerror(errno));
|
||||
if(!sockwouldblock(sockerrno))
|
||||
logger(LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -293,7 +293,7 @@ bool setup_myself(void) {
|
|||
/* Generate packet encryption key */
|
||||
|
||||
if(!get_config_string(lookup_config(myself->connection->config_tree, "Cipher"), &cipher))
|
||||
cipher = xstrdup("aes256");
|
||||
cipher = xstrdup("blowfish");
|
||||
|
||||
if(!cipher_open_by_name(&myself->incipher, cipher)) {
|
||||
logger(LOG_ERR, "Unrecognized cipher type!");
|
||||
|
@ -308,7 +308,7 @@ bool setup_myself(void) {
|
|||
/* Check if we want to use message authentication codes... */
|
||||
|
||||
if(!get_config_string(lookup_config(myself->connection->config_tree, "Digest"), &digest))
|
||||
digest = xstrdup("sha256");
|
||||
digest = xstrdup("sha1");
|
||||
|
||||
int maclength = 4;
|
||||
get_config_int(lookup_config(myself->connection->config_tree, "MACLength"), &maclength);
|
||||
|
|
|
@ -35,10 +35,6 @@
|
|||
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef WSAEINPROGRESS
|
||||
#define EINPROGRESS WSAEINPROGRESS
|
||||
#endif
|
||||
|
||||
/* Needed on Mac OS/X */
|
||||
#ifndef SOL_TCP
|
||||
#define SOL_TCP IPPROTO_TCP
|
||||
|
@ -67,7 +63,7 @@ static void configure_tcp(connection_t *c) {
|
|||
unsigned long arg = 1;
|
||||
|
||||
if(ioctlsocket(c->socket, FIONBIO, &arg) != 0) {
|
||||
logger(LOG_ERR, "ioctlsocket for %s: WSA error %d", c->hostname, WSAGetLastError());
|
||||
logger(LOG_ERR, "ioctlsocket for %s: %d", c->hostname, sockstrerror(sockerrno));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -156,8 +152,7 @@ static bool bind_to_address(connection_t *c) {
|
|||
|
||||
|
||||
if(status) {
|
||||
logger(LOG_ERR, "Can't bind to %s/tcp: %s", node,
|
||||
strerror(errno));
|
||||
logger(LOG_ERR, "Can't bind to %s/tcp: %s", node, sockstrerror(sockerrno));
|
||||
} else ifdebug(CONNECTIONS) {
|
||||
logger(LOG_DEBUG, "Successfully bound outgoing "
|
||||
"TCP socket to %s", node);
|
||||
|
@ -178,7 +173,7 @@ int setup_listen_socket(const sockaddr_t *sa) {
|
|||
nfd = socket(sa->sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
|
||||
if(nfd < 0) {
|
||||
ifdebug(STATUS) logger(LOG_ERR, "Creating metasocket failed: %s", strerror(errno));
|
||||
ifdebug(STATUS) logger(LOG_ERR, "Creating metasocket failed: %s", sockstrerror(sockerrno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -203,7 +198,7 @@ int setup_listen_socket(const sockaddr_t *sa) {
|
|||
if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof ifr)) {
|
||||
closesocket(nfd);
|
||||
logger(LOG_ERR, "Can't bind to interface %s: %s", iface,
|
||||
strerror(errno));
|
||||
strerror(sockerrno));
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
|
@ -214,16 +209,14 @@ int setup_listen_socket(const sockaddr_t *sa) {
|
|||
if(bind(nfd, &sa->sa, SALEN(sa->sa))) {
|
||||
closesocket(nfd);
|
||||
addrstr = sockaddr2hostname(sa);
|
||||
logger(LOG_ERR, "Can't bind to %s/tcp: %s", addrstr,
|
||||
strerror(errno));
|
||||
logger(LOG_ERR, "Can't bind to %s/tcp: %s", addrstr, sockstrerror(sockerrno));
|
||||
free(addrstr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(listen(nfd, 3)) {
|
||||
closesocket(nfd);
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "listen",
|
||||
strerror(errno));
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "listen", sockstrerror(sockerrno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -238,7 +231,7 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
|
|||
nfd = socket(sa->sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
|
||||
|
||||
if(nfd < 0) {
|
||||
logger(LOG_ERR, "Creating UDP socket failed: %s", strerror(errno));
|
||||
logger(LOG_ERR, "Creating UDP socket failed: %s", sockstrerror(sockerrno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -258,8 +251,7 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
|
|||
unsigned long arg = 1;
|
||||
if(ioctlsocket(nfd, FIONBIO, &arg) != 0) {
|
||||
closesocket(nfd);
|
||||
logger(LOG_ERR, "Call to `%s' failed: WSA error %d", "ioctlsocket",
|
||||
WSAGetLastError());
|
||||
logger(LOG_ERR, "Call to `%s' failed: %s", "ioctlsocket", sockstrerror(sockerrno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -278,6 +270,11 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
|
|||
option = IP_PMTUDISC_DO;
|
||||
setsockopt(nfd, SOL_IP, IP_MTU_DISCOVER, &option, sizeof(option));
|
||||
}
|
||||
#elif defined(IPPROTO_IP) && defined(IP_DONTFRAGMENT)
|
||||
if(myself->options & OPTION_PMTU_DISCOVERY) {
|
||||
option = 1;
|
||||
setsockopt(nfd, IPPROTO_IP, IP_DONTFRAGMENT, &option, sizeof(option));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(SOL_IPV6) && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
|
||||
|
@ -295,8 +292,7 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
|
|||
if(bind(nfd, &sa->sa, SALEN(sa->sa))) {
|
||||
closesocket(nfd);
|
||||
addrstr = sockaddr2hostname(sa);
|
||||
logger(LOG_ERR, "Can't bind to %s/udp: %s", addrstr,
|
||||
strerror(errno));
|
||||
logger(LOG_ERR, "Can't bind to %s/udp: %s", addrstr, sockstrerror(sockerrno));
|
||||
free(addrstr);
|
||||
return -1;
|
||||
}
|
||||
|
@ -337,6 +333,11 @@ void do_outgoing_connection(connection_t *c) {
|
|||
char *address, *port;
|
||||
int result;
|
||||
|
||||
if(!c->outgoing) {
|
||||
logger(LOG_ERR, "do_outgoing_connection() for %s called without c->outgoing", c->name);
|
||||
abort();
|
||||
}
|
||||
|
||||
begin:
|
||||
if(!c->outgoing->ai) {
|
||||
if(!c->outgoing->cfg) {
|
||||
|
@ -382,9 +383,7 @@ begin:
|
|||
c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
|
||||
if(c->socket == -1) {
|
||||
ifdebug(CONNECTIONS) logger(LOG_ERR, "Creating socket for %s failed: %s", c->hostname,
|
||||
strerror(errno));
|
||||
|
||||
ifdebug(CONNECTIONS) logger(LOG_ERR, "Creating socket for %s failed: %s", c->hostname, sockstrerror(sockerrno));
|
||||
goto begin;
|
||||
}
|
||||
|
||||
|
@ -406,18 +405,14 @@ begin:
|
|||
result = connect(c->socket, &c->address.sa, SALEN(c->address.sa));
|
||||
|
||||
if(result == -1) {
|
||||
if(errno == EINPROGRESS
|
||||
#if defined(WIN32) && !defined(O_NONBLOCK)
|
||||
|| WSAGetLastError() == WSAEWOULDBLOCK
|
||||
#endif
|
||||
) {
|
||||
if(sockinprogress(sockerrno)) {
|
||||
c->status.connecting = true;
|
||||
return;
|
||||
}
|
||||
|
||||
closesocket(c->socket);
|
||||
|
||||
ifdebug(CONNECTIONS) logger(LOG_ERR, "%s: %s", c->hostname, strerror(errno));
|
||||
ifdebug(CONNECTIONS) logger(LOG_ERR, "%s: %s", c->hostname, sockstrerror(sockerrno));
|
||||
|
||||
goto begin;
|
||||
}
|
||||
|
@ -446,6 +441,8 @@ void setup_outgoing_connection(outgoing_t *outgoing) {
|
|||
connection_t *c;
|
||||
node_t *n;
|
||||
|
||||
event_del(&outgoing->ev);
|
||||
|
||||
n = lookup_node(outgoing->name);
|
||||
|
||||
if(n)
|
||||
|
@ -504,7 +501,7 @@ void handle_new_meta_connection(int sock, short events, void *data) {
|
|||
fd = accept(sock, &sa.sa, &len);
|
||||
|
||||
if(fd < 0) {
|
||||
logger(LOG_ERR, "Accepting a new connection failed: %s", strerror(errno));
|
||||
logger(LOG_ERR, "Accepting a new connection failed: %s", sockstrerror(sockerrno));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -555,18 +552,7 @@ void try_outgoing_connections(void) {
|
|||
static config_t *cfg = NULL;
|
||||
char *name;
|
||||
outgoing_t *outgoing;
|
||||
connection_t *c;
|
||||
splay_node_t *node;
|
||||
|
||||
if(outgoing_list) {
|
||||
for(node = connection_tree->head; node; node = node->next) {
|
||||
c = node->data;
|
||||
c->outgoing = NULL;
|
||||
}
|
||||
|
||||
list_delete_list(outgoing_list);
|
||||
}
|
||||
|
||||
outgoing_list = list_alloc((list_action_t)free_outgoing);
|
||||
|
||||
for(cfg = lookup_config(config_tree, "ConnectTo"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
|
||||
|
|
|
@ -42,7 +42,7 @@ typedef struct node_status_t {
|
|||
|
||||
typedef struct node_t {
|
||||
char *name; /* name of this node */
|
||||
long int options; /* options turned on for this node */
|
||||
uint32_t options; /* options turned on for this node */
|
||||
|
||||
sockaddr_t address; /* his real (internet) ip to send UDP packets to */
|
||||
char *hostname; /* the hostname of its real ip */
|
||||
|
|
|
@ -98,13 +98,18 @@ bool install_service(void) {
|
|||
command, NULL, NULL, NULL, NULL, NULL);
|
||||
|
||||
if(!service) {
|
||||
logger(LOG_ERR, "Could not create %s service: %s", identname, winerror(GetLastError()));
|
||||
return false;
|
||||
DWORD lasterror = GetLastError();
|
||||
logger(LOG_ERR, "Could not create %s service: %s", identname, winerror(lasterror));
|
||||
if(lasterror != ERROR_SERVICE_EXISTS)
|
||||
return false;
|
||||
}
|
||||
|
||||
ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &description);
|
||||
|
||||
logger(LOG_INFO, "%s service installed", identname);
|
||||
if(service) {
|
||||
ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &description);
|
||||
logger(LOG_INFO, "%s service installed", identname);
|
||||
} else {
|
||||
service = OpenService(manager, identname, SERVICE_ALL_ACCESS);
|
||||
}
|
||||
|
||||
if(!StartService(service, 0, NULL))
|
||||
logger(LOG_WARNING, "Could not start %s service: %s", identname, winerror(GetLastError()));
|
||||
|
|
|
@ -348,7 +348,7 @@ bool send_ack(connection_t *c) {
|
|||
|
||||
get_config_int(lookup_config(c->config_tree, "Weight"), &c->estimated_weight);
|
||||
|
||||
return send_request(c, "%d %s %d %lx", ACK, myport, c->estimated_weight, c->options);
|
||||
return send_request(c, "%d %s %d %x", ACK, myport, c->estimated_weight, c->options);
|
||||
}
|
||||
|
||||
static void send_everything(connection_t *c) {
|
||||
|
@ -387,10 +387,10 @@ bool ack_h(connection_t *c, char *request) {
|
|||
char hisport[MAX_STRING_SIZE];
|
||||
char *hisaddress, *dummy;
|
||||
int weight, mtu;
|
||||
long int options;
|
||||
uint32_t options;
|
||||
node_t *n;
|
||||
|
||||
if(sscanf(request, "%*d " MAX_STRING " %d %lx", hisport, &weight, &options) != 3) {
|
||||
if(sscanf(request, "%*d " MAX_STRING " %d %x", hisport, &weight, &options) != 3) {
|
||||
logger(LOG_ERR, "Got bad %s from %s (%s)", "ACK", c->name,
|
||||
c->hostname);
|
||||
return false;
|
||||
|
|
|
@ -41,7 +41,7 @@ bool send_add_edge(connection_t *c, const edge_t *e) {
|
|||
|
||||
sockaddr2str(&e->address, &address, &port);
|
||||
|
||||
x = send_request(c, "%d %x %s %s %s %s %lx %d", ADD_EDGE, rand(),
|
||||
x = send_request(c, "%d %x %s %s %s %s %x %d", ADD_EDGE, rand(),
|
||||
e->from->name, e->to->name, address, port,
|
||||
e->options, e->weight);
|
||||
free(address);
|
||||
|
@ -58,10 +58,10 @@ bool add_edge_h(connection_t *c, char *request) {
|
|||
char to_address[MAX_STRING_SIZE];
|
||||
char to_port[MAX_STRING_SIZE];
|
||||
sockaddr_t address;
|
||||
long int options;
|
||||
uint32_t options;
|
||||
int weight;
|
||||
|
||||
if(sscanf(request, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %lx %d",
|
||||
if(sscanf(request, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %x %d",
|
||||
from_name, to_name, to_address, to_port, &options, &weight) != 6) {
|
||||
logger(LOG_ERR, "Got bad %s from %s (%s)", "ADD_EDGE", c->name,
|
||||
c->hostname);
|
||||
|
@ -70,13 +70,7 @@ bool add_edge_h(connection_t *c, char *request) {
|
|||
|
||||
/* Check if names are valid */
|
||||
|
||||
if(!check_id(from_name)) {
|
||||
logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ADD_EDGE", c->name,
|
||||
c->hostname, "invalid name");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!check_id(to_name)) {
|
||||
if(!check_id(from_name) || !check_id(to_name)) {
|
||||
logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ADD_EDGE", c->name,
|
||||
c->hostname, "invalid name");
|
||||
return false;
|
||||
|
@ -186,13 +180,7 @@ bool del_edge_h(connection_t *c, char *request) {
|
|||
|
||||
/* Check if names are valid */
|
||||
|
||||
if(!check_id(from_name)) {
|
||||
logger(LOG_ERR, "Got bad %s from %s (%s): %s", "DEL_EDGE", c->name,
|
||||
c->hostname, "invalid name");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!check_id(to_name)) {
|
||||
if(!check_id(from_name) || !check_id(to_name)) {
|
||||
logger(LOG_ERR, "Got bad %s from %s (%s): %s", "DEL_EDGE", c->name,
|
||||
c->hostname, "invalid name");
|
||||
return false;
|
||||
|
|
|
@ -45,7 +45,7 @@ bool add_subnet_h(connection_t *c, char *request) {
|
|||
char subnetstr[MAX_STRING_SIZE];
|
||||
char name[MAX_STRING_SIZE];
|
||||
node_t *owner;
|
||||
subnet_t s = {0}, *new;
|
||||
subnet_t s = {0}, *new, *old;
|
||||
|
||||
if(sscanf(request, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) {
|
||||
logger(LOG_ERR, "Got bad %s from %s (%s)", "ADD_SUBNET", c->name,
|
||||
|
@ -112,7 +112,7 @@ bool add_subnet_h(connection_t *c, char *request) {
|
|||
|
||||
for(cfg = lookup_config(c->config_tree, "Subnet"); cfg; cfg = lookup_config_next(c->config_tree, cfg)) {
|
||||
if(!get_config_subnet(cfg, &allowed))
|
||||
return false;
|
||||
continue;
|
||||
|
||||
if(!subnet_compare(&s, allowed))
|
||||
break;
|
||||
|
@ -121,9 +121,9 @@ bool add_subnet_h(connection_t *c, char *request) {
|
|||
}
|
||||
|
||||
if(!cfg) {
|
||||
logger(LOG_WARNING, "Unauthorized %s from %s (%s) for %s",
|
||||
"ADD_SUBNET", c->name, c->hostname, subnetstr);
|
||||
return false;
|
||||
logger(LOG_WARNING, "Ignoring unauthorized %s from %s (%s): %s",
|
||||
"ADD_SUBNET", c->name, c->hostname, subnetstr);
|
||||
return true;
|
||||
}
|
||||
|
||||
free_subnet(allowed);
|
||||
|
@ -142,6 +142,11 @@ bool add_subnet_h(connection_t *c, char *request) {
|
|||
if(!tunnelserver)
|
||||
forward_request(c, request);
|
||||
|
||||
/* Fast handoff of roaming MAC addresses */
|
||||
|
||||
if(s.type == SUBNET_MAC && owner != myself && (old = lookup_subnet(myself, &s)) && old->expires)
|
||||
old->expires = 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -154,6 +154,7 @@ static void learn_mac(mac_t *address) {
|
|||
subnet->type = SUBNET_MAC;
|
||||
subnet->expires = time(NULL) + macexpire;
|
||||
subnet->net.mac.address = *address;
|
||||
subnet->weight = 10;
|
||||
subnet_add(myself, subnet);
|
||||
|
||||
/* And tell all other tinc daemons it's our MAC */
|
||||
|
|
|
@ -131,7 +131,7 @@ bool read_packet(vpn_packet_t *packet) {
|
|||
break;
|
||||
default:
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR,
|
||||
_ ("Unknown IP version %d while reading packet from %s %s"),
|
||||
"Unknown IP version %d while reading packet from %s %s",
|
||||
packet->data[14] >> 4, device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
|
43
src/subnet.c
43
src/subnet.c
|
@ -47,9 +47,15 @@ static subnet_t *cache_ipv6_subnet[2];
|
|||
static bool cache_ipv6_valid[2];
|
||||
static int cache_ipv6_slot;
|
||||
|
||||
static mac_t cache_mac_address[2];
|
||||
static subnet_t *cache_mac_subnet[2];
|
||||
static bool cache_mac_valid[2];
|
||||
static int cache_mac_slot;
|
||||
|
||||
void subnet_cache_flush() {
|
||||
cache_ipv4_valid[0] = cache_ipv4_valid[1] = false;
|
||||
cache_ipv6_valid[0] = cache_ipv6_valid[1] = false;
|
||||
cache_mac_valid[0] = cache_mac_valid[1] = false;
|
||||
}
|
||||
|
||||
/* Subnet comparison */
|
||||
|
@ -324,15 +330,46 @@ subnet_t *lookup_subnet(const node_t *owner, const subnet_t *subnet) {
|
|||
}
|
||||
|
||||
subnet_t *lookup_subnet_mac(const mac_t *address) {
|
||||
subnet_t *p, subnet = {0};
|
||||
subnet_t *p, *r = NULL, subnet = {0};
|
||||
splay_node_t *n;
|
||||
int i;
|
||||
|
||||
// Check if this address is cached
|
||||
|
||||
for(i = 0; i < 2; i++) {
|
||||
if(!cache_mac_valid[i])
|
||||
continue;
|
||||
if(!memcmp(address, &cache_mac_address[i], sizeof *address))
|
||||
return cache_mac_subnet[i];
|
||||
}
|
||||
|
||||
// Search all subnets for a matching one
|
||||
|
||||
subnet.type = SUBNET_MAC;
|
||||
subnet.net.mac.address = *address;
|
||||
subnet.owner = NULL;
|
||||
|
||||
p = splay_search(subnet_tree, &subnet);
|
||||
for(n = subnet_tree->head; n; n = n->next) {
|
||||
p = n->data;
|
||||
|
||||
if(!p || p->type != subnet.type)
|
||||
continue;
|
||||
|
||||
return p;
|
||||
if(!memcmp(address, &p->net.mac.address, sizeof *address)) {
|
||||
r = p;
|
||||
if(p->owner->status.reachable)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Cache the result
|
||||
|
||||
cache_mac_slot = !cache_mac_slot;
|
||||
memcpy(&cache_mac_address[cache_mac_slot], address, sizeof *address);
|
||||
cache_mac_subnet[cache_mac_slot] = r;
|
||||
cache_mac_valid[cache_mac_slot] = true;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
subnet_t *lookup_subnet_ipv4(const ipv4_t *address) {
|
||||
|
|
Loading…
Reference in a new issue