X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=src%2Fmeshlink.c;h=3ebaee01da441aa589279e2ecd4076dd75cc7f1b;hb=11d4da4957cb576abe9ee79c9893809a34f1f3d9;hp=eb9142cc743d842c7f8967e0b9a4408aa170113e;hpb=543a5ecbb12d13350a345044632a6b6d04f3d640;p=meshlink diff --git a/src/meshlink.c b/src/meshlink.c index eb9142cc..3ebaee01 100644 --- a/src/meshlink.c +++ b/src/meshlink.c @@ -221,12 +221,42 @@ char *meshlink_get_external_address(meshlink_handle_t *mesh) { } char *meshlink_get_external_address_for_family(meshlink_handle_t *mesh, int family) { - char *hostname = NULL; + const char *url = mesh->external_address_url; + + if(!url) { + url = "http://meshlink.io/host.cgi"; + } + + /* Find the hostname part between the slashes */ + if(strncmp(url, "http://", 7)) { + abort(); + meshlink_errno = MESHLINK_EINTERNAL; + return NULL; + } + + const char *begin = url + 7; + + const char *end = strchr(begin, '/'); + + if(!end) { + end = begin + strlen(begin); + } + + /* Make a copy */ + char host[end - begin + 1]; + strncpy(host, begin, end - begin); + host[end - begin] = 0; + + char *port = strchr(host, ':'); + + if(port) { + *port++ = 0; + } logger(mesh, MESHLINK_DEBUG, "Trying to discover externally visible hostname...\n"); - struct addrinfo *ai = str2addrinfo("meshlink.io", "80", SOCK_STREAM); - static const char request[] = "GET http://www.meshlink.io/host.cgi HTTP/1.0\r\n\r\n"; + struct addrinfo *ai = str2addrinfo(host, port ? port : "80", SOCK_STREAM); char line[256]; + char *hostname = NULL; for(struct addrinfo *aip = ai; aip; aip = aip->ai_next) { if(family != AF_UNSPEC && aip->ai_family != family) { @@ -245,7 +275,9 @@ char *meshlink_get_external_address_for_family(meshlink_handle_t *mesh, int fami } if(s >= 0) { - send(s, request, sizeof(request) - 1, 0); + send(s, "GET ", 4, 0); + send(s, url, strlen(url), 0); + send(s, " HTTP/1.0\r\n\r\n", 13, 0); int len = recv(s, line, sizeof(line) - 1, MSG_WAITALL); if(len > 0) { @@ -537,26 +569,52 @@ static bool try_bind(int port) { return false; } - //while(ai) { + bool success = false; + for(struct addrinfo *aip = ai; aip; aip = aip->ai_next) { - int fd = socket(aip->ai_family, SOCK_STREAM, IPPROTO_TCP); + /* Try to bind to TCP. */ - if(!fd) { - freeaddrinfo(ai); - return false; + int tcp_fd = socket(aip->ai_family, SOCK_STREAM, IPPROTO_TCP); + + if(tcp_fd == -1) { + continue; } - int result = bind(fd, aip->ai_addr, aip->ai_addrlen); - closesocket(fd); + int result = bind(tcp_fd, aip->ai_addr, aip->ai_addrlen); + closesocket(tcp_fd); if(result) { - freeaddrinfo(ai); - return false; + if(errno == EADDRINUSE) { + /* If this port is in use for any address family, avoid it. */ + success = false; + break; + } else { + continue; + } + } + + /* If TCP worked, then we require that UDP works as well. */ + + int udp_fd = socket(aip->ai_family, SOCK_DGRAM, IPPROTO_UDP); + + if(udp_fd == -1) { + success = false; + break; + } + + result = bind(udp_fd, aip->ai_addr, aip->ai_addrlen); + closesocket(udp_fd); + + if(result) { + success = false; + break; } + + success = true; } freeaddrinfo(ai); - return true; + return success; } static int check_port(meshlink_handle_t *mesh) { @@ -743,6 +801,10 @@ static bool finalize_join(join_state_t *state, const void *buf, uint16_t len) { return false; } + if(!mesh->inviter_commits_first) { + devtool_set_inviter_commits_first(false); + } + sptps_send_record(&state->sptps, 1, ecdsa_get_public_key(mesh->private_key), 32); logger(mesh, MESHLINK_DEBUG, "Configuration stored in: %s\n", mesh->confbase); @@ -775,21 +837,44 @@ static bool invitation_receive(void *handle, uint8_t type, const void *msg, uint join_state_t *state = handle; meshlink_handle_t *mesh = state->mesh; - switch(type) { - case SPTPS_HANDSHAKE: - return sptps_send_record(&state->sptps, 0, state->cookie, 18); + if(mesh->inviter_commits_first) { + switch(type) { + case SPTPS_HANDSHAKE: + return sptps_send_record(&state->sptps, 2, state->cookie, 18 + 32); - case 0: - return finalize_join(state, msg, len); + case 1: + break; - case 1: - logger(mesh, MESHLINK_DEBUG, "Invitation successfully accepted.\n"); - shutdown(state->sock, SHUT_RDWR); - state->success = true; - break; + case 0: + if(!finalize_join(state, msg, len)) { + return false; + } - default: - return false; + logger(mesh, MESHLINK_DEBUG, "Invitation successfully accepted.\n"); + shutdown(state->sock, SHUT_RDWR); + state->success = true; + break; + + default: + return false; + } + } else { + switch(type) { + case SPTPS_HANDSHAKE: + return sptps_send_record(&state->sptps, 0, state->cookie, 18); + + case 0: + return finalize_join(state, msg, len); + + case 1: + logger(mesh, MESHLINK_DEBUG, "Invitation successfully accepted.\n"); + shutdown(state->sock, SHUT_RDWR); + state->success = true; + break; + + default: + return false; + } } return true; @@ -1531,9 +1616,6 @@ static void *meshlink_main_loop(void *arg) { } bool meshlink_start(meshlink_handle_t *mesh) { - assert(mesh->self); - assert(mesh->private_key); - if(!mesh) { meshlink_errno = MESHLINK_EINVAL; return false; @@ -1543,6 +1625,8 @@ bool meshlink_start(meshlink_handle_t *mesh) { pthread_mutex_lock(&mesh->mutex); + assert(mesh->self); + assert(mesh->private_key); assert(mesh->self->ecdsa); assert(!memcmp((uint8_t *)mesh->self->ecdsa + 64, (uint8_t *)mesh->private_key + 64, 32)); @@ -1702,6 +1786,7 @@ void meshlink_close(meshlink_handle_t *mesh) { free(mesh->appname); free(mesh->confbase); free(mesh->config_key); + free(mesh->external_address_url); ecdsa_free(mesh->private_key); main_config_unlock(mesh); @@ -2252,7 +2337,7 @@ bool meshlink_sign(meshlink_handle_t *mesh, const void *data, size_t len, void * } bool meshlink_verify(meshlink_handle_t *mesh, meshlink_node_t *source, const void *data, size_t len, const void *signature, size_t siglen) { - if(!mesh || !data || !len || !signature) { + if(!mesh || !source || !data || !len || !signature) { meshlink_errno = MESHLINK_EINVAL; return false; } @@ -2647,6 +2732,10 @@ bool meshlink_join(meshlink_handle_t *mesh, const char *invitation) { goto invalid; } + if(mesh->inviter_commits_first) { + memcpy(state.cookie + 18, ecdsa_get_public_key(mesh->private_key), 32); + } + // Generate a throw-away key for the invitation. key = ecdsa_generate(); @@ -2713,6 +2802,8 @@ bool meshlink_join(meshlink_handle_t *mesh, const char *invitation) { state.sock = -1; continue; } + + break; } freeaddrinfo(ai); @@ -3928,6 +4019,23 @@ extern void meshlink_set_inviter_commits_first(struct meshlink_handle *mesh, boo pthread_mutex_unlock(&mesh->mutex); } +void meshlink_set_external_address_discovery_url(struct meshlink_handle *mesh, const char *url) { + if(!mesh) { + meshlink_errno = EINVAL; + return; + } + + if(url && (strncmp(url, "http://", 7) || strchr(url, ' '))) { + meshlink_errno = EINVAL; + return; + } + + pthread_mutex_lock(&mesh->mutex); + free(mesh->external_address_url); + mesh->external_address_url = url ? xstrdup(url) : NULL; + pthread_mutex_unlock(&mesh->mutex); +} + void handle_network_change(meshlink_handle_t *mesh, bool online) { (void)online;