gsliepen/tinc — pull request #26 by dechamps (2014-06-28 20:22:24+00:00)
Title: Improved local discovery using local edge addresses

This branch implements [an idea that I published a year ago][idea] about improving the local discovery feature and make it much more reliable. There are several significant changes:

- Add a `local_address` field to `edge_t`. The new field contains the local address of `from`'s metaconnection socket to `to` (in contrast to `address` which contains the peer address).
- Introduce a protocol change to transmit this new information in `ADD_EDGE` messages, in a backward-compatible way. The minor protocol number is bumped accordingly, and the new message format is only sent to nodes that understand them.
- Finally, use this new information to send MTU probes to the local addresses of the destination nodes instead of sending broadcasts.

This new way of doing local discovery provides numerous advantages compared to using broadcasts:

- No broadcast packets "polluting" the local network;
- Reliable even if the sending host has multiple network interfaces (in contrast, broadcasts will only be sent through one unpredictable interface)
- Works even if the two hosts are not on the same broadcast domain. One example is a large LAN where the two hosts might be on different local subnets. In fact, thanks to UDP hole punching this might even work if there is a NAT sitting in the middle of the LAN between the two nodes!
- Sometimes a node is reachable through its "normal" address, and via a local subnet as well. One might think the local subnet is the best route to the node in this case, but more often than not it's actually worse - one example is where the local segment is a third party VPN running in parallel, or ironically it can be the local segment formed by the tinc VPN itself! Because this new algorithm only checks the addresses for which an edge is already established, it is less likely to fall into these traps.

The new local discovery behavior is controlled by a new `LocalDiscoveryBroadcast` option (edge local addresses, however, are always transmitted if possible). It defaults to the old behavior. @gsliepen: the reason it defaults to the old behavior is to keep the branch "neutral", but it probably makes more sense to enable it by default, since this new mechanism is vastly superior to using broadcasts IMHO. In fact I believe the old mechanism should probably be deleted once there is a good penetration of local edge address aware clients.

Testing: I tested this between two local nodes connected to a non-local third node, it seems to work perfectly. Note that currently this is broken with SPTPS because `sptps_verify_datagram()` is not implemented which breaks `try_harder()`, preventing the discovered address from being used. To be clear, this is not a regression: local discovery was already broken because of this. I verified that this works even with SPTPS by writing a quick & dirty implementation of `sptps_verify_datagram()`. I intend on cleaning up this fix in another pull request.

[idea]: http://www.tinc-vpn.org/pipermail/tinc-devel/2013-July/000608.html