Add LocalDiscovery option which tries to detect peers on the local network.
authorGuus Sliepen <guus@tinc-vpn.org>
Wed, 22 Feb 2012 22:17:43 +0000 (23:17 +0100)
committerGuus Sliepen <guus@tinc-vpn.org>
Wed, 22 Feb 2012 22:17:43 +0000 (23:17 +0100)
Currently, this is implemented by sending IPv4 broadcast packets to the
LAN during path MTU discovery.

doc/tinc.conf.5.in
doc/tinc.texi
src/graph.c
src/net.h
src/net_packet.c
src/net_setup.c
src/net_socket.c
src/node.h

index 8a2aa348cd29c43b0b925abcd4a5499709af469b..a6ae4f5ac3ee8d4355fff4d7814138506a908c1f 100644 (file)
@@ -320,6 +320,18 @@ This option controls the period the encryption keys used to encrypt the data are
 It is common practice to change keys at regular intervals to make it even harder for crackers,
 even though it is thought to be nearly impossible to crack a single key.
 
+.It Va LocalDiscovery Li = yes | no Po no Pc Bq experimental
+When enabled,
+.Nm tinc
+will try to detect peers that are on the same local network.
+This will allow direct communication using LAN addresses, even if both peers are behind a NAT
+and they only ConnectTo a third node outside the NAT,
+which normally would prevent the peers from learning each other's LAN address.
+
+.Pp
+Currently, local discovery is implemented by sending broadcast packets to the LAN during path MTU discovery.
+This feature may not work in all possible situations.
+
 .It Va MACExpire Li = Ar seconds Pq 600
 This option controls the amount of time MAC addresses are kept before they are removed.
 This only has effect when
index b6d0c21626ee080049b9d3132379a261e1a0c254..0697f103bedbbba1030079d33eaf6fb726e3152d 100644 (file)
@@ -923,6 +923,16 @@ Depending on the operating system and the type of device this may or may not act
 Under Windows, this variable is used to select which network interface will be used.
 If you specified a Device, this variable is almost always already correctly set.
 
+@cindex LocalDiscovery
+@item LocalDiscovery = <yes | no> (no) [experimental]
+When enabled, tinc will try to detect peers that are on the same local network.
+This will allow direct communication using LAN addresses, even if both peers are behind a NAT
+and they only ConnectTo a third node outside the NAT,
+which normally would prevent the peers from learning each other's LAN address.
+
+Currently, local discovery is implemented by sending broadcast packets to the LAN during path MTU discovery.
+This feature may not work in all possible situations.
+
 @cindex Mode
 @item Mode = <router|switch|hub> (router)
 This option selects the way packets are routed to other daemons.
index 9aadcd8616eaa99ea86dd5bf9db8accb526ae058..297832cda5bb8f3eeabd8cf241c3eeacfc8601f0 100644 (file)
@@ -174,6 +174,7 @@ static void sssp_bfs(void) {
        myself->status.visited = true;
        myself->status.indirect = false;
        myself->nexthop = myself;
+       myself->prevedge = NULL;
        myself->via = myself;
        list_insert_head(todo_list, myself);
 
@@ -214,6 +215,7 @@ static void sssp_bfs(void) {
                        e->to->status.visited = true;
                        e->to->status.indirect = indirect;
                        e->to->nexthop = (n->nexthop == myself) ? e->to : n->nexthop;
+                       e->to->prevedge = e;
                        e->to->via = indirect ? n->via : e->to;
                        e->to->options = e->options;
 
index b831cdd8da55063b964071fe6c48ffcf6d027964..03cbec75f96437c9aa93fec66a5f50907921ce0c 100644 (file)
--- a/src/net.h
+++ b/src/net.h
@@ -107,6 +107,7 @@ extern int maxoutbufsize;
 extern int seconds_till_retry;
 extern int addressfamily;
 extern unsigned replaywin;
+extern bool localdiscovery;
 
 extern listen_socket_t listen_socket[MAXSOCKETS];
 extern int listen_sockets;
index 46fc875bf53c6869f564037339e8e76803035063..18a898d30f3dba95fcc709cfb02981b2e9d3ef05 100644 (file)
@@ -61,13 +61,21 @@ static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999
 static void send_udppacket(node_t *, vpn_packet_t *);
 
 unsigned replaywin = 16;
+bool localdiscovery = false;
 
 #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
+/* 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
+
+   Probes are sent in batches of three, with random sizes between the lower and
+   upper boundaries for the MTU thus far discovered.
+
+   In case local discovery is enabled, a fourth packet is added to each batch,
+   which will be broadcast to the local network.
+*/
 
 void send_mtu_probe(node_t *n) {
        vpn_packet_t packet;
@@ -118,7 +126,7 @@ void send_mtu_probe(node_t *n) {
                timeout = pingtimeout;
        }
 
-       for(i = 0; i < 3; i++) {
+       for(i = 0; i < 3 + localdiscovery; i++) {
                if(n->maxmtu <= n->minmtu)
                        len = n->maxmtu;
                else
@@ -130,7 +138,7 @@ void send_mtu_probe(node_t *n) {
                memset(packet.data, 0, 14);
                RAND_pseudo_bytes(packet.data + 14, len - 14);
                packet.len = len;
-               packet.priority = 0;
+               packet.priority = i < 3 ? 0 : -1;
 
                ifdebug(TRAFFIC) logger(LOG_INFO, "Sending MTU probe length %d to %s (%s)", len, n->name, n->hostname);
 
@@ -486,6 +494,29 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
 
        /* Send the packet */
 
+       struct sockaddr *sa;
+       socklen_t sl;
+       int sock;
+
+       /* Overloaded use of priority field: -1 means local broadcast */
+
+       if(origpriority == -1 && n->prevedge) {
+               struct sockaddr_in in;
+               in.sin_family = AF_INET;
+               in.sin_addr.s_addr = -1;
+               in.sin_port = n->prevedge->address.in.sin_port;
+               sa = (struct sockaddr *)&in;
+               sl = sizeof in;
+               sock = 0;
+       } else {
+               if(origpriority == -1)
+                       origpriority = 0;
+
+               sa = &(n->address.sa);
+               sl = SALEN(n->address.sa);
+               sock = n->sock;
+       }
+
 #if defined(SOL_IP) && defined(IP_TOS)
        if(priorityinheritance && origpriority != priority
           && listen_socket[n->sock].sa.sa.sa_family == AF_INET) {
@@ -496,7 +527,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
        }
 #endif
 
-       if(sendto(listen_socket[n->sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, &(n->address.sa), SALEN(n->address.sa)) < 0 && !sockwouldblock(sockerrno)) {
+       if(sendto(listen_socket[sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, sa, sl) < 0 && !sockwouldblock(sockerrno)) {
                if(sockmsgsize(sockerrno)) {
                        if(n->maxmtu >= origlen)
                                n->maxmtu = origlen - 1;
@@ -600,6 +631,7 @@ static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
        if(hard)
                last_hard_try = now;
 
+       last_hard_try = now;
        return n;
 }
 
index 299e3729e0cb131555d99238e8b4c2745325c69b..bab50fe4389d36aa1b168543ad356c24635a3e38 100644 (file)
@@ -356,6 +356,7 @@ static bool setup_myself(void) {
        get_config_bool(lookup_config(config_tree, "DirectOnly"), &directonly);
        get_config_bool(lookup_config(config_tree, "StrictSubnets"), &strictsubnets);
        get_config_bool(lookup_config(config_tree, "TunnelServer"), &tunnelserver);
+       get_config_bool(lookup_config(config_tree, "LocalDiscovery"), &localdiscovery);
        strictsubnets |= tunnelserver;
 
        if(get_config_string(lookup_config(config_tree, "Mode"), &mode)) {
index f371dc12f91fe2e88322cfb99b64a27e1c960c02..94db11c0fa650a457d4a43c5e694136a28510335 100644 (file)
@@ -211,6 +211,7 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
 
        option = 1;
        setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof(option));
+       setsockopt(nfd, SOL_SOCKET, SO_BROADCAST, (void *)&option, sizeof(option));
 
        if(udp_rcvbuf && setsockopt(nfd, SOL_SOCKET, SO_RCVBUF, (void *)&udp_rcvbuf, sizeof(udp_rcvbuf)))
                logger(LOG_WARNING, "Can't set UDP SO_RCVBUF to %i: %s", udp_rcvbuf, strerror(errno));
index 66cb6c62f6024696149af1441133fc7e5a2c26f1..d1cb97f7e0c7a45bf6cf0fd13581192bd148d9d9 100644 (file)
@@ -67,6 +67,7 @@ typedef struct node_t {
        int outcompression;                     /* Compressionlevel, 0 = no compression */
 
        struct node_t *nexthop;                 /* nearest node from us to him */
+       struct edge_t *prevedge;                /* nearest node from him to us */
        struct node_t *via;                     /* next hop for UDP packets */
 
        avl_tree_t *subnet_tree;                /* Pointer to a tree of subnets belonging to this node */