From 5a28aa7b8b0ab6237c2eab5f8b11253ea3ec5a05 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Wed, 22 Feb 2012 23:17:43 +0100 Subject: [PATCH] Add LocalDiscovery option which tries to detect peers on the local network. Currently, this is implemented by sending IPv4 broadcast packets to the LAN during path MTU discovery. --- doc/tinc.conf.5.in | 12 ++++++++++++ doc/tinc.texi | 10 ++++++++++ src/graph.c | 2 ++ src/net.h | 1 + src/net_packet.c | 46 +++++++++++++++++++++++++++++++++++++++------- src/net_setup.c | 1 + src/net_socket.c | 1 + src/node.h | 1 + 8 files changed, 67 insertions(+), 7 deletions(-) diff --git a/doc/tinc.conf.5.in b/doc/tinc.conf.5.in index 8a2aa348..a6ae4f5a 100644 --- a/doc/tinc.conf.5.in +++ b/doc/tinc.conf.5.in @@ -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 diff --git a/doc/tinc.texi b/doc/tinc.texi index b6d0c216..0697f103 100644 --- a/doc/tinc.texi +++ b/doc/tinc.texi @@ -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 = (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) This option selects the way packets are routed to other daemons. diff --git a/src/graph.c b/src/graph.c index 9aadcd86..297832cd 100644 --- a/src/graph.c +++ b/src/graph.c @@ -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; diff --git a/src/net.h b/src/net.h index b831cdd8..03cbec75 100644 --- 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; diff --git a/src/net_packet.c b/src/net_packet.c index 46fc875b..18a898d3 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -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 *)∈ + 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; } diff --git a/src/net_setup.c b/src/net_setup.c index 299e3729..bab50fe4 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -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)) { diff --git a/src/net_socket.c b/src/net_socket.c index f371dc12..94db11c0 100644 --- a/src/net_socket.c +++ b/src/net_socket.c @@ -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)); diff --git a/src/node.h b/src/node.h index 66cb6c62..d1cb97f7 100644 --- a/src/node.h +++ b/src/node.h @@ -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 */ -- 2.20.1