]> git.meshlink.io Git - meshlink/commitdiff
Add meshlink_get_external_address() and meshlink_add_external_address().
authorGuus Sliepen <guus@meshlink.io>
Fri, 11 Mar 2016 11:08:48 +0000 (12:08 +0100)
committerGuus Sliepen <guus@meshlink.io>
Sun, 25 Jun 2017 08:55:46 +0000 (10:55 +0200)
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
src/meshlink.h

index 68286d29046aa9e6477e012f5075f0a643f9e2d3..418be9e878d636b59844356d10b6a28e05bea162 100644 (file)
@@ -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;
 }
 
index 651f05c8bd355f54002c90881322f029d303337d..1c1e7af4d3a051706bd6f212b5ec9e64a193fab5 100644 (file)
@@ -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.