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 8a2aa34..a6ae4f5 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 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
 .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 b6d0c21..0697f10 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.
 
 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.
 @cindex Mode
 @item Mode = <router|switch|hub> (router)
 This option selects the way packets are routed to other daemons.
index 9aadcd8..297832c 100644 (file)
@@ -174,6 +174,7 @@ static void sssp_bfs(void) {
        myself->status.visited = true;
        myself->status.indirect = false;
        myself->nexthop = myself;
        myself->status.visited = true;
        myself->status.indirect = false;
        myself->nexthop = myself;
+       myself->prevedge = NULL;
        myself->via = myself;
        list_insert_head(todo_list, myself);
 
        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->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;
 
                        e->to->via = indirect ? n->via : e->to;
                        e->to->options = e->options;
 
index b831cdd..03cbec7 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 int seconds_till_retry;
 extern int addressfamily;
 extern unsigned replaywin;
+extern bool localdiscovery;
 
 extern listen_socket_t listen_socket[MAXSOCKETS];
 extern int listen_sockets;
 
 extern listen_socket_t listen_socket[MAXSOCKETS];
 extern int listen_sockets;
index 46fc875..18a898d 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;
 static void send_udppacket(node_t *, vpn_packet_t *);
 
 unsigned replaywin = 16;
+bool localdiscovery = false;
 
 #define MAX_SEQNO 1073741824
 
 
 #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;
 
 void send_mtu_probe(node_t *n) {
        vpn_packet_t packet;
@@ -118,7 +126,7 @@ void send_mtu_probe(node_t *n) {
                timeout = pingtimeout;
        }
 
                timeout = pingtimeout;
        }
 
-       for(i = 0; i < 3; i++) {
+       for(i = 0; i < 3 + localdiscovery; i++) {
                if(n->maxmtu <= n->minmtu)
                        len = n->maxmtu;
                else
                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;
                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);
 
 
                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 */
 
 
        /* 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) {
 #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
 
        }
 #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;
                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;
 
        if(hard)
                last_hard_try = now;
 
+       last_hard_try = now;
        return n;
 }
 
        return n;
 }
 
index 299e372..bab50fe 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, "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)) {
        strictsubnets |= tunnelserver;
 
        if(get_config_string(lookup_config(config_tree, "Mode"), &mode)) {
index f371dc1..94db11c 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));
 
        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));
 
        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 66cb6c6..d1cb97f 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 */
        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 */
        struct node_t *via;                     /* next hop for UDP packets */
 
        avl_tree_t *subnet_tree;                /* Pointer to a tree of subnets belonging to this node */