From 44e9f1e1d8d6dbd4625e5458cfffcf6b5168374a Mon Sep 17 00:00:00 2001
From: Guus Sliepen <guus@tinc-vpn.org>
Date: Wed, 13 May 2015 14:28:28 +0200
Subject: [PATCH 1/6] Fix invitations.

These were broken due to a change in behaviour of sptps_receive_data()
introduced in commit d237efd325cd7bdd73f5eb111c769470238dce6e.
---
 src/invitation.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/invitation.c b/src/invitation.c
index 38634886..229c6066 100644
--- a/src/invitation.c
+++ b/src/invitation.c
@@ -988,8 +988,14 @@ int cmd_join(int argc, char *argv[]) {
 			return 1;
 		}
 
-		if(!sptps_receive_data(&sptps, line, len))
-			return 1;
+		char *p = line;
+		while(len) {
+			int done = sptps_receive_data(&sptps, p, len);
+			if(!done)
+				return 1;
+			len -= done;
+			p += done;
+		}
 	}
 	
 	sptps_stop(&sptps);

From fd1cff6df23c3f16a46edaff8a52a7212914b2f0 Mon Sep 17 00:00:00 2001
From: Guus Sliepen <guus@tinc-vpn.org>
Date: Fri, 15 May 2015 00:21:48 +0200
Subject: [PATCH 2/6] Fix receiving UDP packets from tinc 1.0.x nodes.

In try_mac(), the wrong offsets were used into the packet buffer,
causing the digest verification to always fail.
---
 src/net_packet.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/net_packet.c b/src/net_packet.c
index 1fdc0fe8..f734af29 100644
--- a/src/net_packet.c
+++ b/src/net_packet.c
@@ -260,7 +260,7 @@ static bool try_mac(node_t *n, const vpn_packet_t *inpkt) {
 	if(!n->status.validkey_in || !digest_active(n->indigest) || inpkt->len < sizeof(seqno_t) + digest_length(n->indigest))
 		return false;
 
-	return digest_verify(n->indigest, SEQNO(inpkt), inpkt->len - digest_length(n->indigest), DATA(inpkt) + inpkt->len - digest_length(n->indigest));
+	return digest_verify(n->indigest, inpkt->data, inpkt->len - digest_length(n->indigest), inpkt->data + inpkt->len - digest_length(n->indigest));
 #endif
 }
 

From 8028e01100eb40f64da5e50ef33fbf9e3f8099de Mon Sep 17 00:00:00 2001
From: Guus Sliepen <guus@tinc-vpn.org>
Date: Fri, 15 May 2015 23:01:06 +0200
Subject: [PATCH 3/6] Use AF_UNSPEC instead of AF_UNKNOWN for unspecified local
 address in add_edge_h().

AF_UNKNOWN is reserved for valid addresses that the local node cannot
parse, but remote nodes possibly can.
---
 src/protocol_edge.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/src/protocol_edge.c b/src/protocol_edge.c
index 4760162c..43e32364 100644
--- a/src/protocol_edge.c
+++ b/src/protocol_edge.c
@@ -61,9 +61,9 @@ bool add_edge_h(connection_t *c, const char *request) {
 	char to_name[MAX_STRING_SIZE];
 	char to_address[MAX_STRING_SIZE];
 	char to_port[MAX_STRING_SIZE];
-	char address_local[MAX_STRING_SIZE] = "unknown";
-	char port_local[MAX_STRING_SIZE] = "unknown";
-	sockaddr_t address, local_address;
+	char address_local[MAX_STRING_SIZE];
+	char port_local[MAX_STRING_SIZE];
+	sockaddr_t address, local_address = {{0}};
 	uint32_t options;
 	int weight;
 
@@ -117,7 +117,8 @@ bool add_edge_h(connection_t *c, const char *request) {
 	/* Convert addresses */
 
 	address = str2sockaddr(to_address, to_port);
-	local_address = str2sockaddr(address_local, port_local);
+	if(parameter_count >= 8)
+		local_address = str2sockaddr(address_local, port_local);
 
 	/* Check if edge already exists */
 

From 54a8bd78e3fbe2de4d9daea748643f9c9b5b240e Mon Sep 17 00:00:00 2001
From: Guus Sliepen <guus@tinc-vpn.org>
Date: Fri, 15 May 2015 23:08:53 +0200
Subject: [PATCH 4/6] Be more liberal accepting ADD_EDGE messages with
 conflicting local address information.

If the ADD_EDGE is for one of the edges we own, and if it is not the
same as we actually have, send a correcting ADD_EDGE back. Otherwise, if
the ADD_EDGE contains new information, update our idea of the local
address for that edge.

If the ADD_EDGE does not contain local address information, then we
never make a correction nor log a warning.
---
 src/protocol_edge.c | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/src/protocol_edge.c b/src/protocol_edge.c
index 43e32364..76e6eb48 100644
--- a/src/protocol_edge.c
+++ b/src/protocol_edge.c
@@ -125,7 +125,7 @@ bool add_edge_h(connection_t *c, const char *request) {
 	e = lookup_edge(from, to);
 
 	if(e) {
-		if(e->weight != weight || e->options != options || sockaddrcmp(&e->address, &address) || sockaddrcmp(&e->local_address, &local_address)) {
+		if(e->weight != weight || e->options != options || sockaddrcmp(&e->address, &address)) {
 			if(from == myself) {
 				logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) for ourself which does not match existing entry",
 						   "ADD_EDGE", c->name, c->hostname);
@@ -137,6 +137,28 @@ bool add_edge_h(connection_t *c, const char *request) {
 				edge_del(e);
 				graph();
 			}
+		} else if(sockaddrcmp(&e->local_address, &local_address)) {
+			if(from == myself) {
+				if(e->local_address.sa.sa_family && local_address.sa.sa_family) {
+					// Someone has the wrong local address for ourself. Correct then.
+					logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) for ourself which does not match existing entry",
+							   "ADD_EDGE", c->name, c->hostname);
+					send_add_edge(c, e);
+					return true;
+				}
+				// Otherwise, just ignore it.
+				return true;
+			} else if(local_address.sa.sa_family) {
+				// We learned a new local address for this edge.
+				sockaddrfree(&e->local_address);
+				e->local_address = local_address;
+
+				// Tell others about it.
+				if(!tunnelserver)
+					forward_request(c, request);
+
+				return true;
+			}
 		} else
 			return true;
 	} else if(from == myself) {

From 613c121cdceec0199dc4d056857be021ed1d21de Mon Sep 17 00:00:00 2001
From: Guus Sliepen <guus@tinc-vpn.org>
Date: Fri, 15 May 2015 23:35:46 +0200
Subject: [PATCH 5/6] Try all addresses for the hostname in an invitation URL.

---
 src/invitation.c | 33 ++++++++++++++++++++++++---------
 1 file changed, 24 insertions(+), 9 deletions(-)

diff --git a/src/invitation.c b/src/invitation.c
index 229c6066..1a2f93f5 100644
--- a/src/invitation.c
+++ b/src/invitation.c
@@ -921,16 +921,31 @@ int cmd_join(int argc, char *argv[]) {
 	if(!ai)
 		return 1;
 
-	sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
-	if(sock <= 0) {
-		fprintf(stderr, "Could not open socket: %s\n", strerror(errno));
-		return 1;
+	struct addrinfo *aip = NULL;
+
+next:
+	if(!aip)
+		aip = ai;
+	else {
+		aip = aip->ai_next;
+		if(!aip)
+			return 1;
 	}
 
-	if(connect(sock, ai->ai_addr, ai->ai_addrlen)) {
-		fprintf(stderr, "Could not connect to %s port %s: %s\n", address, port, strerror(errno));
+	sock = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol);
+	if(sock <= 0) {
+		fprintf(stderr, "Could not open socket: %s\n", strerror(errno));
+		goto next;
+	}
+
+	if(connect(sock, aip->ai_addr, aip->ai_addrlen)) {
+		char *addrstr, *portstr;
+		sockaddr2str((sockaddr_t *)aip->ai_addr, &addrstr, &portstr);
+		fprintf(stderr, "Could not connect to %s port %s: %s\n", addrstr, portstr, strerror(errno));
+		free(addrstr);
+		free(portstr);
 		closesocket(sock);
-		return 1;
+		goto next;
 	}
 
 	fprintf(stderr, "Connected to %s port %s...\n", address, port);
@@ -943,7 +958,7 @@ int cmd_join(int argc, char *argv[]) {
 	if(!sendline(sock, "0 ?%s %d.%d", b64key, PROT_MAJOR, 1)) {
 		fprintf(stderr, "Error sending request to %s port %s: %s\n", address, port, strerror(errno));
 		closesocket(sock);
-		return 1;
+		goto next;
 	}
 
 	char hisname[4096] = "";
@@ -952,7 +967,7 @@ int cmd_join(int argc, char *argv[]) {
 	if(!recvline(sock, line, sizeof line) || sscanf(line, "%d %s %d.%d", &code, hisname, &hismajor, &hisminor) < 3 || code != 0 || hismajor != PROT_MAJOR || !check_id(hisname) || !recvline(sock, line, sizeof line) || !rstrip(line) || sscanf(line, "%d ", &code) != 1 || code != ACK || strlen(line) < 3) {
 		fprintf(stderr, "Cannot read greeting from peer\n");
 		closesocket(sock);
-		return 1;
+		goto next;
 	}
 
 	// Check if the hash of the key he gave us matches the hash in the URL.

From eecfeadeb4fc70ee002b81c20ba12ba3e3acb843 Mon Sep 17 00:00:00 2001
From: Guus Sliepen <guus@tinc-vpn.org>
Date: Sat, 16 May 2015 02:01:54 +0200
Subject: [PATCH 6/6] Let sockaddr2str() handle AF_UNSPEC addresses.

---
 src/netutl.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/src/netutl.c b/src/netutl.c
index bff734e1..701a4309 100644
--- a/src/netutl.c
+++ b/src/netutl.c
@@ -83,7 +83,13 @@ void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr) {
 	char *scopeid;
 	int err;
 
-	if(sa->sa.sa_family == AF_UNKNOWN) {
+	if(sa->sa.sa_family == AF_UNSPEC) {
+		if(addrstr)
+			*addrstr = xstrdup("unspec");
+		if(portstr)
+			*portstr = xstrdup("unspec");
+		return;
+	} else if(sa->sa.sa_family == AF_UNKNOWN) {
 		if(addrstr)
 			*addrstr = xstrdup(sa->unknown.address);
 		if(portstr)