Etienne Dechamps [Sat, 28 Jun 2014 17:39:00 +0000 (18:39 +0100)]
Remove the TAP-Win32 reader thread.
tinc is using a separate thread to read from the TAP device on Windows.
The rationale was that the notification mechanism for packets arriving
on the virtual network device is based on Win32 events, and the event
loop did not support listening to these events.
Thanks to recent improvements, this event loop limitation has been
lifted. Therefore we can get rid of the separate thread and simply add
the Win32 "incoming packet" event to the event loop, just like a socket.
The result is cleaner code that's easier to reason about.
Etienne Dechamps [Sat, 28 Jun 2014 14:19:11 +0000 (15:19 +0100)]
Use a Windows event to stop tinc when running as a service.
Currently, when the tinc service handler callback (which runs in a
separate thread) receives a service shutdown request, it calls
event_exit() to request the event loop to exit.
This approach has a few issues:
- The event loop will only notice the exit request when the next event
fires. This slows down tinc service shutdown. In some extreme cases
(DeviceStandby enabled, long PingTimeout and no connections),
shutdown can take ages.
- Strictly speaking, because of the absence of memory barriers, there
is no guarantee that the event loop will even notice an exit request
coming from another thread. I suppose marking the "running" variable
as "volatile" is supposed to alleviate that, but it's unclear whether
that provides any guarantees with modern systems and compilers.
This commit fixes the issue by leveraging the new event loop Windows
interface, using a custom Windows event that is manually set when
shutdown is requested.
Etienne Dechamps [Fri, 27 Jun 2014 20:58:35 +0000 (21:58 +0100)]
Use native Windows events for the event loop.
This commit changes the event loop to use WSAEventSelect() and
WSAWaitForMultipleEvents() on Windows. This paves the way for making the
event loop more flexible on Windows by introducing the required
infrastructure to make the event loop wait on any Win32 event.
This commit only affects the internal implementation of the event
module. Externally visible behavior remains strictly unchanged (for
now).
Etienne Dechamps [Fri, 27 Jun 2014 18:33:31 +0000 (19:33 +0100)]
Protect against spurious connection events.
The event loop does not guarantee that spurious write I/O events do not
happen; in fact, they are guaranteed to happen on Windows when
event_flush_output() is called. Because handle_meta_io() does not check
for spurious events, a metaconnection socket might appear connected even
though it's not, and will fail immediately when sending the ID request.
This commit fixes this issue by making handle_meta_io() check the
connection status before assuming the socket is connected. It seems that
the only reliable way to do that is to try to call connect() again and
look at the error code, which will be EISCONN if the socket is
connected, or EALREADY if it's not.
Etienne Dechamps [Thu, 26 Jun 2014 19:42:40 +0000 (20:42 +0100)]
Fix errno references when handling socket errors.
When using socket functions, "sockerrno" is supposed to be used to
retrieve the error code as opposed to "errno", so that it is translated
to the correct call on Windows (WSAGetLastError() - Windows does not
update errno on socket errors). Unfortunately, the use of sockerrno is
inconsistent throughout the tinc codebase, as errno is often used
incorrectly on socket-related calls.
This commit fixes these oversights, which improves socket error
handling on Windows.
Etienne Dechamps [Sun, 22 Jun 2014 17:45:49 +0000 (18:45 +0100)]
Fix Windows includes.
These Windows include lines are capitalized, which causes the build to fail
when cross-compiling from Linux to Windows using MinGW as the MinGW headers
are entirely lower case.
Etienne Dechamps [Sun, 22 Jun 2014 09:48:34 +0000 (10:48 +0100)]
Make DeviceStandby control network interface link status on Windows.
Besides controlling when tinc-up and tinc-down get called, this commit makes
DeviceStandby control when the virtual network interface "cable" is "plugged"
on Windows. This is more user-friendly as the status of the tinc network can
be seen just by looking at the state of the network interface, and it makes
Windows behave better when isolated.
Etienne Dechamps [Sun, 22 Jun 2014 09:48:34 +0000 (10:48 +0100)]
Add DeviceStandby option to only enable the device when nodes are reachable.
This adds a new DeviceStandby option; when it is disabled (the default),
behavior is unchanged. If it is enabled, tinc-up will not be called during
tinc initialization, but will instead be deferred until the first node is
reachable, and it will be closed as soon as no nodes are reachable.
This is useful because it means the device won't be set up until we are fairly
sure there is something listening on the other side. This is more user-friendly,
as one can check on the status of the tinc network connection just by checking
the status of the network interface. Besides, it prevents the OS from thinking
it is connected to some network when it is in fact completely isolated.
Guus Sliepen [Mon, 12 May 2014 13:57:40 +0000 (15:57 +0200)]
Fix PMTU discovery via datagram SPTPS.
In send_sptps_data(), the len variable contains the length of the whole
datagram that needs to be sent to the peer, including the overhead from SPTPS
itself.
Guus Sliepen [Tue, 6 May 2014 10:58:25 +0000 (12:58 +0200)]
Nexthop calculation should always use the shortest path.
When tinc runs the graph algorithms and updates the nexthop and via pointers,
it uses a breadth-first search, but it can sometimes revisit nodes that have
already been visited if the previous path is marked as being indirect, and
there is a longer path that is "direct". The via pointer should be updated in
this case, because this points to the closest hop to the destination that can
be reached directly. However, the nexthop pointer should not be updated.
This fixes a bug where there could potentially be a routing loop if a node in
the graph has an edge with the indirect flag set, and some other edge without
that flag, the indirect edge is part of the minimum spanning tree, and a
broadcast packet is being sent.
Use the ChaCha-Poly1305 cipher for the SPTPS protocol.
The main reason to switch from AES-256-GCM to ChaCha-Poly1305 is to remove a
dependency on OpenSSL, whose behaviour of the AES-256-GCM decryption function
changes between versions. The source code for ChaCha-Pol1305 is small and in
the public domain, and can therefore be easily included in tinc itself.
Moreover, it is very fast even without using any optimized assembler, easily
outperforming AES-256-GCM on platforms that don't have special AES instructions
in hardware.
Guus Sliepen [Sun, 9 Mar 2014 14:32:10 +0000 (15:32 +0100)]
Handle a disconnecting tincd better.
- Try to prevent SIGPIPE from being sent for errors sending to the control
socket. We don't outright block the SIGPIPE signal because we still want the
tinc CLI to exit when its output is actually sent to a real (broken) pipe.
- Don't call exit() from top(), and properly detect when the control socket is
closed by the tincd.
Guus Sliepen [Fri, 7 Feb 2014 15:34:08 +0000 (16:34 +0100)]
Handle errors from TAP-Win32/64 adapter in a better way.
Before, the tapreader thread would just exit immediately after encountering the
first error, without notifying the main thread. Now, the tapreader thead never
exits itself, but tells the main thread to stop when more than ten errors are
encountered in a row.
Guus Sliepen [Thu, 30 Jan 2014 16:10:30 +0000 (17:10 +0100)]
Use addresses learned from other nodes when making outgoing connections.
Before, when making a meta-connection to a node (either because of a ConnectTo
or because AutoConnect is set), tinc required one or more Address statements
in the corresponding host config file. However, tinc learns addresses from
other nodes that it uses for UDP connections. We can use those just as well for
TCP connections.
Guus Sliepen [Wed, 29 Jan 2014 16:17:59 +0000 (17:17 +0100)]
Don't ask questions if we are not running interactively.
When creating invitations or using them to join a VPN, and the tinc command is
not run interactively (ie, when stdin and stdout are not connected or
redirected to/from a file), don't ask questions. If normally tinc would ask for
a confirmation, just assume the default answer instead. If tinc really needs
some input, just print an error message instead.
In case an invitation is used for a VPN which uses a netname that is already in
use on the local host, tinc will store the configuration in a temporary
directory. Normally it asks for an alternative netname and then renames the
temporary directory, but when not run interactively, it now just prints the
location of the unchanged temporary directory.
Guus Sliepen [Fri, 24 Jan 2014 15:09:32 +0000 (16:09 +0100)]
Test two tinc daemons using network namespaces.
Testing multiple daemons connecting to each other on the same computer is
usually difficult, because connections to local IP addresses will bypass most
of the network stack. However, recent versions of Linux support network
namespaces, which can isolate network interfaces. We use this to isolate the
virtual interface of the daemons from each other, so we get the behaviour as if
the daemons were each running on their own machine. This can also be used for
more complicated tests (including those with firewall rules) without disturbing
the real network setup of the host computer.
Guus Sliepen [Mon, 20 Jan 2014 20:19:13 +0000 (21:19 +0100)]
Add the ListenAddress option.
ListenAddress works the same as BindToAddress, except that from now on,
explicitly binding outgoing packets to the address of a socket is only done for
sockets specified with BindToAddress.
Guus Sliepen [Thu, 5 Dec 2013 14:01:30 +0000 (15:01 +0100)]
If no Port is specified, set myport to actual port of first listening socket.
If the Port statement is not used, there are two other ways to let tinc listen
on a non-default port: either by specifying one or more BindToAddress
statements including port numbers, or by starting it from systemd with socket
activation. Tinc announces its own port to other nodes, but before it only
announced what was set using the Port statement.