From 44e9f1e1d8d6dbd4625e5458cfffcf6b5168374a Mon Sep 17 00:00:00 2001 From: Guus Sliepen 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 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 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 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 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 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)