From 82e6ef764b4f1d2c2b6c1be35452cb87aff11350 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Fri, 11 Mar 2016 12:08:48 +0100 Subject: [PATCH] Add meshlink_get_external_address() and meshlink_add_external_address(). These functions try to discover the local node's external address by contacting the meshlink.io server. The get function just returns the discovered address as a string, the add function adds it as an Address, so it will end up in the list of addresses when calling meshlink_export(). --- src/meshlink.c | 88 +++++++++++++++++++++++++++++++++----------------- src/meshlink.h | 33 +++++++++++++++++++ 2 files changed, 92 insertions(+), 29 deletions(-) diff --git a/src/meshlink.c b/src/meshlink.c index 68286d29..418be9e8 100644 --- a/src/meshlink.c +++ b/src/meshlink.c @@ -181,27 +181,24 @@ static void scan_for_hostname(const char *filename, char **hostname, char **port fclose(f); } -static char *get_my_hostname(meshlink_handle_t* mesh) { - char *hostname = NULL; - char *port = NULL; - char *hostport = NULL; - char *name = mesh->self->name; - char filename[PATH_MAX] = ""; - char line[4096]; - FILE *f; - // Use first Address statement in own host config file - snprintf(filename, sizeof filename, "%s" SLASH "hosts" SLASH "%s", mesh->confbase, name); - scan_for_hostname(filename, &hostname, &port); +static bool is_valid_hostname(const char *hostname) { + for(const char *p = hostname; *p; p++) { + if(!(isalnum(*p) || *p == '-' || *p == '.' || *p == ':')) + return false; + } - if(hostname) - goto done; + return true; +} + +char *meshlink_get_external_address(meshlink_handle_t *mesh) { + char *hostname = NULL; - // If that doesn't work, guess externally visible hostname logger(mesh, MESHLINK_DEBUG, "Trying to discover externally visible hostname...\n"); struct addrinfo *ai = str2addrinfo("meshlink.io", "80", SOCK_STREAM); struct addrinfo *aip = ai; static const char request[] = "GET http://www.meshlink.io/host.cgi HTTP/1.0\r\n\r\n"; + char line[256]; while(aip) { int s = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol); @@ -234,17 +231,33 @@ static char *get_my_hostname(meshlink_handle_t* mesh) { freeaddrinfo(ai); // Check that the hostname is reasonable - if(hostname) { - for(char *p = hostname; *p; p++) { - if(isalnum(*p) || *p == '-' || *p == '.' || *p == ':') - continue; - // If not, forget it. - free(hostname); - hostname = NULL; - break; - } + if(hostname && !is_valid_hostname(hostname)) { + free(hostname); + hostname = NULL; } + if(!hostname) + meshlink_errno = MESHLINK_ERESOLV; + + return hostname; +} + +static char *get_my_hostname(meshlink_handle_t* mesh) { + char *hostname = NULL; + char *port = NULL; + char *hostport = NULL; + char *name = mesh->self->name; + char filename[PATH_MAX] = ""; + FILE *f; + + // Use first Address statement in own host config file + snprintf(filename, sizeof filename, "%s" SLASH "hosts" SLASH "%s", mesh->confbase, name); + scan_for_hostname(filename, &hostname, &port); + + if(hostname) + goto done; + + hostname = meshlink_get_external_address(mesh); if(!hostname) return NULL; @@ -1463,22 +1476,39 @@ bool meshlink_add_address(meshlink_handle_t *mesh, const char *address) { meshlink_errno = MESHLINK_EINVAL; return false; } - + + if(!is_valid_hostname(address)) { + logger(mesh, MESHLINK_DEBUG, "Invalid character in address: %s\n", address); + meshlink_errno = MESHLINK_EINVAL; + return false; + } + bool rval = false; pthread_mutex_lock(&(mesh->mesh_mutex)); + rval = append_config_file(mesh, mesh->self->name, "Address", address); + pthread_mutex_unlock(&(mesh->mesh_mutex)); - for(const char *p = address; *p; p++) { - if(isalnum(*p) || *p == '-' || *p == '.' || *p == ':') - continue; - logger(mesh, MESHLINK_DEBUG, "Invalid character in address: %s\n", address); + return rval; +} + +bool meshlink_add_external_address(meshlink_handle_t *mesh) { + if(!mesh) { meshlink_errno = MESHLINK_EINVAL; - pthread_mutex_unlock(&(mesh->mesh_mutex)); return false; } + char *address = meshlink_get_external_address(mesh); + if(!address) + return false; + + bool rval = false; + + pthread_mutex_lock(&(mesh->mesh_mutex)); rval = append_config_file(mesh, mesh->self->name, "Address", address); pthread_mutex_unlock(&(mesh->mesh_mutex)); + + free(address); return rval; } diff --git a/src/meshlink.h b/src/meshlink.h index 651f05c8..1c1e7af4 100644 --- a/src/meshlink.h +++ b/src/meshlink.h @@ -424,6 +424,39 @@ extern bool meshlink_verify(meshlink_handle_t *mesh, meshlink_node_t *source, co */ extern bool meshlink_add_address(meshlink_handle_t *mesh, const char *address); +/// Try to discover the external address for the local node. +/** This function performs tries to discover the local node's external address + * by contacting the meshlink.io server. If a reverse lookup of the address works, + * the FQDN associated with the address will be returned. + * + * Please note that this is function only returns a single address, + * even if the local node might have more than one external address. + * In that case, there is no control over which address will be selected. + * Also note that if you have a dynamic IP address, or are behind carrier-grade NAT, + * there is no guarantee that the external address will be valid for an extended period of time. + * + * @param mesh A handle which represents an instance of MeshLink. + * @param address A nul-terminated C string containing the address, which can be either in numeric format or a hostname. + * + * @return This function returns a pointer to a C string containing the discovered external address, + * or NULL if there was an error looking up the address. + * After meshlink_get_external_address() returns, the application is free to overwrite or free this string. + */ +extern char *meshlink_get_external_address(meshlink_handle_t *mesh); + +/// Try to discover the external address for the local node, and add it to its list of addresses. +/** This function is equivalent to: + * + * meshlink_add_address(mesh, meshlink_get_external_address(mesh)); + * + * Read the description of meshlink_get_external_address() for the limitations of this function. + * + * @param mesh A handle which represents an instance of MeshLink. + * + * @return This function returns true if the address was added, false otherwise. + */ +extern bool meshlink_add_external_address(meshlink_handle_t *mesh); + /// Invite another node into the mesh. /** This function generates an invitation that can be used by another node to join the same mesh as the local node. * The generated invitation is a string containing a URL. -- 2.39.2