X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=src%2Fmeshlink.c;h=1c81ad22673957362d0b11de8ef9bbd0c3eb38c8;hb=fe4cf1f57aa26458d1c2a9c44a06f9e49fe8d615;hp=84f6e29cf725897deb9b52e78460dbf5a0e8609a;hpb=a8c5d9fc9f1274608bf9b3a2430f3f72f00ecbcc;p=meshlink diff --git a/src/meshlink.c b/src/meshlink.c index 84f6e29c..1c81ad22 100644 --- a/src/meshlink.c +++ b/src/meshlink.c @@ -56,64 +56,13 @@ meshlink_log_level_t global_log_level; //TODO: this can go away completely const var_t variables[] = { /* Server configuration */ - {"AddressFamily", VAR_SERVER}, - {"AutoConnect", VAR_SERVER | VAR_SAFE}, - {"BindToAddress", VAR_SERVER | VAR_MULTIPLE}, - {"BindToInterface", VAR_SERVER}, - {"Broadcast", VAR_SERVER | VAR_SAFE}, {"ConnectTo", VAR_SERVER | VAR_MULTIPLE | VAR_SAFE}, - {"DecrementTTL", VAR_SERVER}, - {"Device", VAR_SERVER}, - {"DeviceType", VAR_SERVER}, - {"DirectOnly", VAR_SERVER}, - {"ECDSAPrivateKeyFile", VAR_SERVER}, - {"ExperimentalProtocol", VAR_SERVER}, - {"Forwarding", VAR_SERVER}, - {"GraphDumpFile", VAR_SERVER | VAR_OBSOLETE}, - {"Hostnames", VAR_SERVER}, - {"IffOneQueue", VAR_SERVER}, - {"Interface", VAR_SERVER}, - {"KeyExpire", VAR_SERVER}, - {"ListenAddress", VAR_SERVER | VAR_MULTIPLE}, - {"LocalDiscovery", VAR_SERVER}, - {"MACExpire", VAR_SERVER}, - {"MaxConnectionBurst", VAR_SERVER}, - {"MaxOutputBufferSize", VAR_SERVER}, - {"MaxTimeout", VAR_SERVER}, - {"Mode", VAR_SERVER | VAR_SAFE}, {"Name", VAR_SERVER}, - {"PingInterval", VAR_SERVER}, - {"PingTimeout", VAR_SERVER}, - {"PriorityInheritance", VAR_SERVER}, - {"PrivateKey", VAR_SERVER | VAR_OBSOLETE}, - {"PrivateKeyFile", VAR_SERVER}, - {"ProcessPriority", VAR_SERVER}, - {"Proxy", VAR_SERVER}, - {"ReplayWindow", VAR_SERVER}, - {"ScriptsExtension", VAR_SERVER}, - {"ScriptsInterpreter", VAR_SERVER}, - {"StrictSubnets", VAR_SERVER}, - {"TunnelServer", VAR_SERVER}, - {"VDEGroup", VAR_SERVER}, - {"VDEPort", VAR_SERVER}, /* Host configuration */ + {"CanonicalAddress", VAR_HOST}, {"Address", VAR_HOST | VAR_MULTIPLE}, - {"Cipher", VAR_SERVER | VAR_HOST}, - {"ClampMSS", VAR_SERVER | VAR_HOST}, - {"Compression", VAR_SERVER | VAR_HOST}, - {"Digest", VAR_SERVER | VAR_HOST}, {"ECDSAPublicKey", VAR_HOST}, - {"ECDSAPublicKeyFile", VAR_SERVER | VAR_HOST}, - {"IndirectData", VAR_SERVER | VAR_HOST}, - {"MACLength", VAR_SERVER | VAR_HOST}, - {"PMTU", VAR_SERVER | VAR_HOST}, - {"PMTUDiscovery", VAR_SERVER | VAR_HOST}, {"Port", VAR_HOST}, - {"PublicKey", VAR_HOST | VAR_OBSOLETE}, - {"PublicKeyFile", VAR_SERVER | VAR_HOST | VAR_OBSOLETE}, - {"Subnet", VAR_HOST | VAR_MULTIPLE | VAR_SAFE}, - {"TCPOnly", VAR_SERVER | VAR_HOST}, - {"Weight", VAR_HOST | VAR_SAFE}, {NULL, 0} }; @@ -148,6 +97,7 @@ static int rstrip(char *value) { static void scan_for_hostname(const char *filename, char **hostname, char **port) { char line[4096]; + bool canonical = false; if(!filename || (*hostname && *port)) { return; @@ -187,25 +137,33 @@ static void scan_for_hostname(const char *filename, char **hostname, char **port p += strspn(p, "\t "); p[strcspn(p, "\t ")] = 0; - // p is now pointing to the port - - // Check that the hostname is a symbolic name (it's not a numeric IPv4 or IPv6 address) - if(!q[strspn(q, "0123456789.")] || strchr(q, ':')) { - continue; - } + // p is now pointing to the port, if present if(!*port && !strcasecmp(line, "Port")) { *port = xstrdup(q); - } else if(!*hostname && !strcasecmp(line, "Address")) { + } else if(!canonical && !*hostname && !strcasecmp(line, "Address")) { + // Check that the hostname is a symbolic name (it's not a numeric IPv4 or IPv6 address) + if(!q[strspn(q, "0123456789.")] || strchr(q, ':')) { + continue; + } + *hostname = xstrdup(q); + if(*p) { + free(*port); + *port = xstrdup(p); + } + } else if(!strcasecmp(line, "CanonicalAddress")) { + *hostname = xstrdup(q); + canonical = true; + if(*p) { free(*port); *port = xstrdup(p); } } - if(*hostname && *port) { + if(canonical && *hostname && *port) { break; } } @@ -214,6 +172,10 @@ static void scan_for_hostname(const char *filename, char **hostname, char **port } static bool is_valid_hostname(const char *hostname) { + if(!*hostname) { + return false; + } + for(const char *p = hostname; *p; p++) { if(!(isalnum(*p) || *p == '-' || *p == '.' || *p == ':')) { return false; @@ -223,6 +185,26 @@ static bool is_valid_hostname(const char *hostname) { return true; } +static bool is_valid_port(const char *port) { + if(!*port) { + return false; + } + + if(isdigit(*port)) { + char *end; + unsigned long int result = strtoul(port, &end, 10); + return result && result < 65536 && !*end; + } + + for(const char *p = port; *p; p++) { + if(!(isalnum(*p) || *p == '-')) { + return false; + } + } + + return true; +} + static void set_timeout(int sock, int timeout) { #ifdef _WIN32 DWORD tv = timeout; @@ -388,7 +370,7 @@ static char *get_my_hostname(meshlink_handle_t *mesh) { return NULL; } - if(!strcmp(hostname[0], hostname[1])) { + if(hostname[0] && hostname[1] && !strcmp(hostname[0], hostname[1])) { free(hostname[1]); hostname[1] = NULL; } @@ -619,7 +601,7 @@ static bool finalize_join(meshlink_handle_t *mesh) { continue; } - // Check the list of known variables //TODO: most variables will not be available in meshlink, only name and key will be absolutely necessary + // Check the list of known variables bool found = false; int i; @@ -1050,6 +1032,7 @@ meshlink_handle_t *meshlink_open(const char *confbase, const char *name, const c mesh->confbase = xstrdup(confbase); mesh->appname = xstrdup(appname); mesh->devclass = devclass; + mesh->discovery = true; if(usingname) { mesh->name = xstrdup(name); @@ -1178,6 +1161,7 @@ bool meshlink_start(meshlink_handle_t *mesh) { logger(mesh, MESHLINK_DEBUG, "Could not start thread: %s\n", strerror(errno)); memset(&mesh->thread, 0, sizeof(mesh)->thread); meshlink_errno = MESHLINK_EINTERNAL; + event_loop_stop(&mesh->loop); pthread_mutex_unlock(&(mesh->mesh_mutex)); return false; } @@ -1210,18 +1194,28 @@ void meshlink_stop(meshlink_handle_t *mesh) { event_loop_stop(&mesh->loop); // Send ourselves a UDP packet to kick the event loop - listen_socket_t *s = &mesh->listen_socket[0]; + for(int i = 0; i < mesh->listen_sockets; i++) { + sockaddr_t sa; + socklen_t salen = sizeof(sa.sa); + + if(getsockname(mesh->listen_socket[i].udp.fd, &sa.sa, &salen) == -1) { + logger(mesh, MESHLINK_ERROR, "System call `%s' failed: %s", "getsockname", sockstrerror(sockerrno)); + continue; + } - if(sendto(s->udp.fd, "", 1, MSG_NOSIGNAL, &s->sa.sa, SALEN(s->sa.sa)) == -1) { - logger(mesh, MESHLINK_ERROR, "Could not send a UDP packet to ourself"); + if(sendto(mesh->listen_socket[i].udp.fd, "", 1, MSG_NOSIGNAL, &sa.sa, salen) == -1) { + logger(mesh, MESHLINK_ERROR, "Could not send a UDP packet to ourself: %s", sockstrerror(sockerrno)); + } } - // Wait for the main thread to finish - pthread_mutex_unlock(&(mesh->mesh_mutex)); - pthread_join(mesh->thread, NULL); - pthread_mutex_lock(&(mesh->mesh_mutex)); + if(mesh->threadstarted) { + // Wait for the main thread to finish + pthread_mutex_unlock(&(mesh->mesh_mutex)); + pthread_join(mesh->thread, NULL); + pthread_mutex_lock(&(mesh->mesh_mutex)); - mesh->threadstarted = false; + mesh->threadstarted = false; + } // Close all metaconnections if(mesh->connections) { @@ -1235,10 +1229,9 @@ void meshlink_stop(meshlink_handle_t *mesh) { if(mesh->outgoings) { list_delete_list(mesh->outgoings); + mesh->outgoings = NULL; } - mesh->outgoings = NULL; - pthread_mutex_unlock(&(mesh->mesh_mutex)); } @@ -1716,8 +1709,8 @@ static bool refresh_invitation_key(meshlink_handle_t *mesh) { return mesh->invitation_key; } -bool meshlink_add_address(meshlink_handle_t *mesh, const char *address) { - if(!mesh || !address) { +bool meshlink_set_canonical_address(meshlink_handle_t *mesh, meshlink_node_t *node, const char *address, const char *port) { + if(!mesh || !node || !address) { meshlink_errno = MESHLINK_EINVAL; return false; } @@ -1728,15 +1721,32 @@ bool meshlink_add_address(meshlink_handle_t *mesh, const char *address) { return false; } - bool rval = false; + if(port && !is_valid_port(port)) { + logger(mesh, MESHLINK_DEBUG, "Invalid character in port: %s\n", address); + meshlink_errno = MESHLINK_EINVAL; + return false; + } + + char *canonical_address; + + if(port) { + xasprintf(&canonical_address, "%s %s", address, port); + } else { + canonical_address = xstrdup(address); + } pthread_mutex_lock(&(mesh->mesh_mutex)); - rval = append_config_file(mesh, mesh->self->name, "Address", address); + bool rval = modify_config_file(mesh, node->name, "CanonicalAddress", canonical_address, 1); pthread_mutex_unlock(&(mesh->mesh_mutex)); + free(canonical_address); return rval; } +bool meshlink_add_address(meshlink_handle_t *mesh, const char *address) { + return meshlink_set_canonical_address(mesh, (meshlink_node_t *)mesh->self, address, NULL); +} + bool meshlink_add_external_address(meshlink_handle_t *mesh) { if(!mesh) { meshlink_errno = MESHLINK_EINVAL; @@ -1915,8 +1925,6 @@ char *meshlink_invite(meshlink_handle_t *mesh, const char *name) { // Fill in the details. fprintf(f, "Name = %s\n", name); - //if(netname) - // fprintf(f, "NetName = %s\n", netname); fprintf(f, "ConnectTo = %s\n", mesh->self->name); // Copy Broadcast and Mode @@ -2441,6 +2449,11 @@ static void channel_accept(struct utcp_connection *utcp_connection, uint16_t por static ssize_t channel_send(struct utcp *utcp, const void *data, size_t len) { node_t *n = utcp->priv; + + if(n->status.destroyed) { + return -1; + } + meshlink_handle_t *mesh = n->mesh; return meshlink_send(mesh, (meshlink_node_t *)n, data, len) ? (ssize_t)len : -1; }