]> git.meshlink.io Git - meshlink/blobdiff - src/meshlink.c
Allow multiple addresses in an invitation URL.
[meshlink] / src / meshlink.c
index 769e52c6e896c8021691fe678619a424ea8ddabb..60a4306ceb5ae16b8ba633a440eae0968ce11c85 100644 (file)
@@ -444,7 +444,7 @@ static bool try_bind(int port) {
        return true;
 }
 
-static int check_port(meshlink_handle_t *mesh) {
+int check_port(meshlink_handle_t *mesh) {
        for(int i = 0; i < 1000; i++) {
                int port = 0x1000 + (rand() & 0x7fff);
 
@@ -454,7 +454,8 @@ static int check_port(meshlink_handle_t *mesh) {
                        FILE *f = fopen(filename, "a");
 
                        if(!f) {
-                               logger(mesh, MESHLINK_DEBUG, "Please change MeshLink's Port manually.\n");
+                               meshlink_errno = MESHLINK_ESTORAGE;
+                               logger(mesh, MESHLINK_DEBUG, "Could not store Port.\n");
                                return 0;
                        }
 
@@ -464,7 +465,8 @@ static int check_port(meshlink_handle_t *mesh) {
                }
        }
 
-       logger(mesh, MESHLINK_DEBUG, "Please change MeshLink's Port manually.\n");
+       meshlink_errno = MESHLINK_ENETWORK;
+       logger(mesh, MESHLINK_DEBUG, "Could not find any available network port.\n");
        return 0;
 }
 
@@ -639,9 +641,10 @@ static bool finalize_join(meshlink_handle_t *mesh) {
 static bool invitation_send(void *handle, uint8_t type, const void *data, size_t len) {
        (void)type;
        meshlink_handle_t *mesh = handle;
+       const char *ptr = data;
 
        while(len) {
-               int result = send(mesh->sock, data, len, 0);
+               int result = send(mesh->sock, ptr, len, 0);
 
                if(result == -1 && errno == EINTR) {
                        continue;
@@ -649,7 +652,7 @@ static bool invitation_send(void *handle, uint8_t type, const void *data, size_t
                        return false;
                }
 
-               data += result;
+               ptr += result;
                len -= result;
        }
 
@@ -788,7 +791,12 @@ static bool ecdsa_keygen(meshlink_handle_t *mesh) {
                logger(mesh, MESHLINK_DEBUG, "Done.\n");
        }
 
-       snprintf(privname, sizeof(privname), "%s" SLASH "ecdsa_key.priv", mesh->confbase);
+       if (snprintf(privname, sizeof(privname), "%s" SLASH "ecdsa_key.priv", mesh->confbase) >= PATH_MAX) {
+               logger(mesh, MESHLINK_DEBUG, "Filename too long: %s" SLASH "ecdsa_key.priv\n", mesh->confbase);
+               meshlink_errno = MESHLINK_ESTORAGE;
+               return false;
+       }
+
        f = fopen(privname, "wb");
 
        if(!f) {
@@ -948,10 +956,15 @@ static bool meshlink_setup(meshlink_handle_t *mesh) {
 
        if(!ecdsa_keygen(mesh)) {
                meshlink_errno = MESHLINK_EINTERNAL;
+               unlink(filename);
                return false;
        }
 
-       check_port(mesh);
+       if (check_port(mesh) == 0) {
+               meshlink_errno = MESHLINK_ENETWORK;
+               unlink(filename);
+               return false;
+       }
 
        return true;
 }
@@ -1573,7 +1586,10 @@ static bool refresh_invitation_key(meshlink_handle_t *mesh) {
 
                char invname[PATH_MAX];
                struct stat st;
-               snprintf(invname, sizeof(invname), "%s" SLASH "%s", filename, ent->d_name);
+               if (snprintf(invname, sizeof(invname), "%s" SLASH "%s", filename, ent->d_name) >= PATH_MAX) {
+                       logger(mesh, MESHLINK_DEBUG, "Filename too long: %s" SLASH "%s", filename, ent->d_name);
+                       continue;
+               }
 
                if(!stat(invname, &st)) {
                        if(mesh->invitation_key && deadline < st.st_mtime) {
@@ -1914,6 +1930,14 @@ bool meshlink_join(meshlink_handle_t *mesh, const char *invitation) {
 
        pthread_mutex_lock(&(mesh->mesh_mutex));
 
+       //Before doing meshlink_join make sure we are not connected to another mesh
+       if(mesh->threadstarted) {
+               logger(mesh, MESHLINK_DEBUG, "Already connected to a mesh\n");
+               meshlink_errno = MESHLINK_EINVAL;
+               pthread_mutex_unlock(&(mesh->mesh_mutex));
+               return false;
+       }
+
        //TODO: think of a better name for this variable, or of a different way to tokenize the invitation URL.
        char copy[strlen(invitation) + 1];
        strcpy(copy, invitation);
@@ -1933,33 +1957,14 @@ bool meshlink_join(meshlink_handle_t *mesh, const char *invitation) {
        }
 
        char *address = copy;
-       char *port = NULL;
-
-       if(*address == '[') {
-               address++;
-               char *bracket = strchr(address, ']');
-
-               if(!bracket) {
-                       goto invalid;
-               }
-
-               *bracket = 0;
+       char *port = strrchr(address, ':');
 
-               if(bracket[1] == ':') {
-                       port = bracket + 2;
-               }
-       } else {
-               port = strchr(address, ':');
-
-               if(port) {
-                       *port++ = 0;
-               }
-       }
-
-       if(!port) {
+       if (!port) {
                goto invalid;
        }
 
+       *port++ = 0;
+
        if(!b64decode(slash, mesh->hash, 18) || !b64decode(slash + 24, mesh->cookie, 18)) {
                goto invalid;
        }
@@ -1974,43 +1979,64 @@ bool meshlink_join(meshlink_handle_t *mesh, const char *invitation) {
        }
 
        char *b64key = ecdsa_get_base64_public_key(key);
+       char *comma;
+       mesh->sock = -1;
+
+       while (address && *address) {
+               // We allow commas in the address part to support multiple addresses in one invitation URL.
+               comma = strchr(address, ',');
+               if (comma)
+                       *comma++ = 0;
+
+               // IPv6 address are enclosed in brackets, per RFC 3986
+               if (*address == '[') {
+                       address++;
+                       char *bracket = strchr(address, ']');
+                       if (!bracket)
+                               goto invalid;
+                       *bracket++ = 0;
+                       if (comma && bracket != comma)
+                               goto invalid;
+               }
 
-       //Before doing meshlink_join make sure we are not connected to another mesh
-       if(mesh->threadstarted) {
-               goto invalid;
-       }
+               // Connect to the meshlink daemon mentioned in the URL.
+               struct addrinfo *ai = str2addrinfo(address, port, SOCK_STREAM);
+               if (ai) {
+                       for (struct addrinfo *aip = ai; aip; aip = aip->ai_next) {
+                               mesh->sock = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol);
 
-       // Connect to the meshlink daemon mentioned in the URL.
-       struct addrinfo *ai = str2addrinfo(address, port, SOCK_STREAM);
+                               if(mesh->sock == -1) {
+                                       logger(mesh, MESHLINK_DEBUG, "Could not open socket: %s\n", strerror(errno));
+                                       meshlink_errno = MESHLINK_ENETWORK;
+                                       continue;
+                               }
 
-       if(!ai) {
-               meshlink_errno = MESHLINK_ERESOLV;
-               pthread_mutex_unlock(&(mesh->mesh_mutex));
-               return false;
-       }
+                               set_timeout(mesh->sock, 5000);
 
-       mesh->sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+                               if(connect(mesh->sock, aip->ai_addr, aip->ai_addrlen)) {
+                                       logger(mesh, MESHLINK_DEBUG, "Could not connect to %s port %s: %s\n", address, port, strerror(errno));
+                                       meshlink_errno = MESHLINK_ENETWORK;
+                                       closesocket(mesh->sock);
+                                       mesh->sock = -1;
+                                       continue;
+                               }
+                       }
 
-       if(mesh->sock <= 0) {
-               logger(mesh, MESHLINK_DEBUG, "Could not open socket: %s\n", strerror(errno));
-               freeaddrinfo(ai);
-               meshlink_errno = MESHLINK_ENETWORK;
-               pthread_mutex_unlock(&(mesh->mesh_mutex));
-               return false;
-       }
+                       freeaddrinfo(ai);
+               } else {
+                       meshlink_errno = MESHLINK_ERESOLV;
+               }
 
-       set_timeout(mesh->sock, 5000);
+               if (mesh->sock != -1 || !comma)
+                       break;
 
-       if(connect(mesh->sock, ai->ai_addr, ai->ai_addrlen)) {
-               logger(mesh, MESHLINK_DEBUG, "Could not connect to %s port %s: %s\n", address, port, strerror(errno));
-               closesocket(mesh->sock);
-               freeaddrinfo(ai);
-               meshlink_errno = MESHLINK_ENETWORK;
-               pthread_mutex_unlock(&(mesh->mesh_mutex));
-               return false;
+               address = comma;
        }
 
-       freeaddrinfo(ai);
+       if (mesh->sock == -1) {
+               pthread_mutex_unlock(&mesh->mesh_mutex);
+               return false;
+       }
 
        logger(mesh, MESHLINK_DEBUG, "Connected to %s port %s...\n", address, port);
 
@@ -2117,7 +2143,7 @@ bool meshlink_join(meshlink_handle_t *mesh, const char *invitation) {
        return true;
 
 invalid:
-       logger(mesh, MESHLINK_DEBUG, "Invalid invitation URL or you are already connected to a Mesh ?\n");
+       logger(mesh, MESHLINK_DEBUG, "Invalid invitation URL\n");
        meshlink_errno = MESHLINK_EINVAL;
        pthread_mutex_unlock(&(mesh->mesh_mutex));
        return false;