X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=src%2Fmeshlink.c;h=496e5d3c753763560bf173591a3aa8f883559dd6;hb=7075cf7bc81998b6cf72ccb6748050cd40b006be;hp=0ea38dbb55c952c5ea69e0ab70181f4cb8f17706;hpb=ed1f31db1e8840ffd6849b48bcad93e9975a24bb;p=meshlink diff --git a/src/meshlink.c b/src/meshlink.c index 0ea38dbb..496e5d3c 100644 --- a/src/meshlink.c +++ b/src/meshlink.c @@ -49,17 +49,19 @@ typedef struct { #ifndef MSG_NOSIGNAL #define MSG_NOSIGNAL 0 #endif - __thread meshlink_errno_t meshlink_errno; meshlink_log_cb_t global_log_cb; meshlink_log_level_t global_log_level; +typedef bool (*search_node_by_condition_t)(const node_t *, const void *); + //TODO: this can go away completely const var_t variables[] = { /* Server configuration */ {"ConnectTo", VAR_SERVER | VAR_MULTIPLE | VAR_SAFE}, {"Name", VAR_SERVER}, /* Host configuration */ + {"SubMesh", VAR_HOST | VAR_SAFE}, {"CanonicalAddress", VAR_HOST}, {"Address", VAR_HOST | VAR_MULTIPLE}, {"ECDSAPublicKey", VAR_HOST}, @@ -212,23 +214,27 @@ struct socket_in_netns_params { int fd; }; +#ifdef HAVE_SETNS static void *socket_in_netns_thread(void *arg) { struct socket_in_netns_params *params = arg; if(setns(params->netns, CLONE_NEWNET) == -1) { meshlink_errno = MESHLINK_EINVAL; - } else { - params->fd = socket(params->domain, params->type, params->protocol); + return NULL; } + params->fd = socket(params->domain, params->type, params->protocol); + return NULL; } +#endif // HAVE_SETNS static int socket_in_netns(int domain, int type, int protocol, int netns) { if(netns == -1) { return socket(domain, type, protocol); } +#ifdef HAVE_SETNS struct socket_in_netns_params params = {domain, type, protocol, netns, -1}; pthread_t thr; @@ -238,6 +244,10 @@ static int socket_in_netns(int domain, int type, int protocol, int netns) { } return params.fd; +#else + return -1; +#endif // HAVE_SETNS + } // Find out what local address a socket would use if we connect to the given address. @@ -623,23 +633,22 @@ static bool try_bind(int port) { return false; } - while(ai) { - int fd = socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP); + //while(ai) { + for(struct addrinfo *aip = ai; aip; aip = aip->ai_next) { + int fd = socket(aip->ai_family, SOCK_STREAM, IPPROTO_TCP); if(!fd) { freeaddrinfo(ai); return false; } - int result = bind(fd, ai->ai_addr, ai->ai_addrlen); + int result = bind(fd, aip->ai_addr, aip->ai_addrlen); closesocket(fd); if(result) { freeaddrinfo(ai); return false; } - - ai = ai->ai_next; } freeaddrinfo(ai); @@ -920,7 +929,7 @@ static bool invitation_receive(void *handle, uint8_t type, const void *msg, uint return finalize_join(mesh); case 2: - logger(mesh, MESHLINK_DEBUG, "Invitation succesfully accepted.\n"); + logger(mesh, MESHLINK_DEBUG, "Invitation successfully accepted.\n"); shutdown(mesh->sock, SHUT_RDWR); mesh->success = true; break; @@ -1170,6 +1179,7 @@ static bool meshlink_setup(meshlink_handle_t *mesh) { return true; } +#ifdef HAVE_SETNS static void *setup_network_in_netns_thread(void *arg) { meshlink_handle_t *mesh = arg; @@ -1181,6 +1191,7 @@ static void *setup_network_in_netns_thread(void *arg) { add_local_addresses(mesh); return success ? arg : NULL; } +#endif // HAVE_SETNS meshlink_open_params_t *meshlink_open_params_init(const char *confbase, const char *name, const char *appname, dev_class_t devclass) { if(!confbase || !*confbase) { @@ -1244,7 +1255,8 @@ void meshlink_open_params_free(meshlink_open_params_t *params) { meshlink_handle_t *meshlink_open(const char *confbase, const char *name, const char *appname, dev_class_t devclass) { /* Create a temporary struct on the stack, to avoid allocating and freeing one. */ - meshlink_open_params_t params = {NULL}; + meshlink_open_params_t params; + memset(¶ms, 0, sizeof(params)); params.confbase = (char *)confbase; params.name = (char *)name; @@ -1305,6 +1317,7 @@ meshlink_handle_t *meshlink_open_ex(const meshlink_open_params_t *params) { mesh->discovery = true; mesh->invitation_timeout = 604800; // 1 week mesh->netns = params->netns; + mesh->submeshes = NULL; if(usingname) { mesh->name = xstrdup(params->name); @@ -1393,12 +1406,19 @@ meshlink_handle_t *meshlink_open_ex(const meshlink_open_params_t *params) { bool success = false; if(mesh->netns != -1) { +#ifdef HAVE_SETNS pthread_t thr; if(pthread_create(&thr, NULL, setup_network_in_netns_thread, mesh) == 0) { void *retval = NULL; success = pthread_join(thr, &retval) == 0 && retval; } + +#else + meshlink_errno = MESHLINK_EINTERNAL; + return NULL; + +#endif // HAVE_SETNS } else { success = setup_network(mesh); add_local_addresses(mesh); @@ -1418,6 +1438,7 @@ meshlink_handle_t *meshlink_open_ex(const meshlink_open_params_t *params) { meshlink_submesh_t *meshlink_submesh_open(meshlink_handle_t *mesh, const char *submesh) { meshlink_submesh_t *s = NULL; + if(!mesh) { logger(NULL, MESHLINK_ERROR, "No mesh handle given!\n"); meshlink_errno = MESHLINK_EINVAL; @@ -1430,20 +1451,13 @@ meshlink_submesh_t *meshlink_submesh_open(meshlink_handle_t *mesh, const char * return NULL; } - s = (meshlink_submesh_t *)lookup_submesh(mesh, submesh); - - if (s) { - logger(NULL, MESHLINK_ERROR, "SubMesh Already exists!\n"); - meshlink_errno = MESHLINK_EEXIST; - return NULL; - } + //lock mesh->nodes + pthread_mutex_lock(&(mesh->mesh_mutex)); - s = (meshlink_submesh_t *)new_submesh(); - s->name = xstrdup(submesh); + s = (meshlink_submesh_t *)create_submesh(mesh, submesh); - submesh_add(mesh, (submesh_t *)s); + pthread_mutex_unlock(&(mesh->mesh_mutex)); - meshlink_errno = MESHLINK_OK; return s; } @@ -1451,9 +1465,15 @@ static void *meshlink_main_loop(void *arg) { meshlink_handle_t *mesh = arg; if(mesh->netns != -1) { +#ifdef HAVE_SETNS + if(setns(mesh->netns, CLONE_NEWNET) != 0) { return NULL; } + +#else + return NULL; +#endif // HAVE_SETNS } pthread_mutex_lock(&(mesh->mesh_mutex)); @@ -1677,6 +1697,17 @@ void meshlink_set_receive_cb(meshlink_handle_t *mesh, meshlink_receive_cb_t cb) pthread_mutex_unlock(&(mesh->mesh_mutex)); } +void meshlink_set_connection_try_cb(meshlink_handle_t *mesh, meshlink_connection_try_cb_t cb) { + if(!mesh) { + meshlink_errno = MESHLINK_EINVAL; + return; + } + + pthread_mutex_lock(&(mesh->mesh_mutex)); + mesh->connection_try_cb = cb; + pthread_mutex_unlock(&(mesh->mesh_mutex)); +} + void meshlink_set_node_status_cb(meshlink_handle_t *mesh, meshlink_node_status_cb_t cb) { if(!mesh) { meshlink_errno = MESHLINK_EINVAL; @@ -1729,6 +1760,13 @@ bool meshlink_send(meshlink_handle_t *mesh, meshlink_node_t *destination, const return false; } + node_t *n = (node_t *)destination; + + if(n->status.blacklisted) { + logger(mesh, MESHLINK_ERROR, "Node %s blacklisted, dropping packet\n", n->name); + return false; + } + // Prepare the packet vpn_packet_t *packet = malloc(sizeof(*packet)); @@ -1848,6 +1886,20 @@ meshlink_node_t *meshlink_get_node(meshlink_handle_t *mesh, const char *name) { return node; } +meshlink_submesh_t *meshlink_get_submesh(meshlink_handle_t *mesh, const char *name) { + if(!mesh || !name) { + meshlink_errno = MESHLINK_EINVAL; + return NULL; + } + + meshlink_submesh_t *submesh = NULL; + + pthread_mutex_lock(&(mesh->mesh_mutex)); + submesh = (meshlink_submesh_t *)lookup_submesh(mesh, name); + pthread_mutex_unlock(&(mesh->mesh_mutex)); + return submesh; +} + meshlink_node_t **meshlink_get_all_nodes(meshlink_handle_t *mesh, meshlink_node_t **nodes, size_t *nmemb) { if(!mesh || !nmemb || (*nmemb && !nodes)) { meshlink_errno = MESHLINK_EINVAL; @@ -1879,12 +1931,7 @@ meshlink_node_t **meshlink_get_all_nodes(meshlink_handle_t *mesh, meshlink_node_ return result; } -meshlink_node_t **meshlink_get_all_nodes_by_dev_class(meshlink_handle_t *mesh, dev_class_t devclass, meshlink_node_t **nodes, size_t *nmemb) { - if(!mesh || ((int)devclass < 0) || (devclass > _DEV_CLASS_MAX) || !nmemb) { - meshlink_errno = MESHLINK_EINVAL; - return NULL; - } - +static meshlink_node_t **meshlink_get_all_nodes_by_condition(meshlink_handle_t *mesh, const void *condition, meshlink_node_t **nodes, size_t *nmemb, search_node_by_condition_t search_node) { meshlink_node_t **result; pthread_mutex_lock(&(mesh->mesh_mutex)); @@ -1892,7 +1939,7 @@ meshlink_node_t **meshlink_get_all_nodes_by_dev_class(meshlink_handle_t *mesh, d *nmemb = 0; for splay_each(node_t, n, mesh->nodes) { - if(n->devclass == devclass) { + if(true == search_node(n, condition)) { *nmemb = *nmemb + 1; } } @@ -1909,7 +1956,7 @@ meshlink_node_t **meshlink_get_all_nodes_by_dev_class(meshlink_handle_t *mesh, d meshlink_node_t **p = result; for splay_each(node_t, n, mesh->nodes) { - if(n->devclass == devclass) { + if(true == search_node(n, condition)) { *p++ = (meshlink_node_t *)n; } } @@ -1924,6 +1971,42 @@ meshlink_node_t **meshlink_get_all_nodes_by_dev_class(meshlink_handle_t *mesh, d return result; } +static bool search_node_by_dev_class(const node_t *node, const void *condition) { + dev_class_t *devclass = (dev_class_t *)condition; + + if(*devclass == node->devclass) { + return true; + } + + return false; +} + +static bool search_node_by_submesh(const node_t *node, const void *condition) { + if(condition == node->submesh) { + return true; + } + + return false; +} + +meshlink_node_t **meshlink_get_all_nodes_by_dev_class(meshlink_handle_t *mesh, dev_class_t devclass, meshlink_node_t **nodes, size_t *nmemb) { + if(!mesh || ((int)devclass < 0) || (devclass > _DEV_CLASS_MAX) || !nmemb) { + meshlink_errno = MESHLINK_EINVAL; + return NULL; + } + + return meshlink_get_all_nodes_by_condition(mesh, &devclass, nodes, nmemb, search_node_by_dev_class); +} + +meshlink_node_t **meshlink_get_all_nodes_by_submesh(meshlink_handle_t *mesh, meshlink_submesh_t *submesh, meshlink_node_t **nodes, size_t *nmemb) { + if(!mesh || !submesh || !nmemb) { + meshlink_errno = MESHLINK_EINVAL; + return NULL; + } + + return meshlink_get_all_nodes_by_condition(mesh, submesh, nodes, nmemb, search_node_by_submesh); +} + dev_class_t meshlink_get_node_dev_class(meshlink_handle_t *mesh, meshlink_node_t *node) { if(!mesh || !node) { meshlink_errno = MESHLINK_EINVAL; @@ -1941,6 +2024,21 @@ dev_class_t meshlink_get_node_dev_class(meshlink_handle_t *mesh, meshlink_node_t return devclass; } +meshlink_submesh_t *meshlink_get_node_submesh(meshlink_handle_t *mesh, meshlink_node_t *node) { + if(!mesh || !node) { + meshlink_errno = MESHLINK_EINVAL; + return NULL; + } + + node_t *n = (node_t *)node; + + meshlink_submesh_t *s; + + s = (meshlink_submesh_t *)n->submesh; + + return s; +} + bool meshlink_sign(meshlink_handle_t *mesh, const void *data, size_t len, void *signature, size_t *siglen) { if(!mesh || !data || !len || !signature || !siglen) { meshlink_errno = MESHLINK_EINVAL; @@ -2037,7 +2135,7 @@ static bool refresh_invitation_key(meshlink_handle_t *mesh) { } if(!stat(invname, &st)) { - if(mesh->invitation_key && deadline < st.st_mtime) { + if(mesh->invitation_key && deadline < (time_t)st.st_mtime) { count++; } else { unlink(invname); @@ -2241,19 +2339,33 @@ bool meshlink_set_port(meshlink_handle_t *mesh, int port) { done: pthread_mutex_unlock(&(mesh->mesh_mutex)); - return rval; + return rval && meshlink_get_port(mesh) == port; } void meshlink_set_invitation_timeout(meshlink_handle_t *mesh, int timeout) { mesh->invitation_timeout = timeout; } -char *meshlink_invite_ex(meshlink_handle_t *mesh, const char *name, uint32_t flags) { +char *meshlink_invite_ex(meshlink_handle_t *mesh, meshlink_submesh_t *submesh, const char *name, uint32_t flags) { + meshlink_submesh_t *s = NULL; + if(!mesh) { meshlink_errno = MESHLINK_EINVAL; return NULL; } + if(submesh) { + s = (meshlink_submesh_t *)lookup_submesh(mesh, submesh->name); + + if(s != submesh) { + logger(mesh, MESHLINK_DEBUG, "Invalid SubMesh Handle.\n"); + meshlink_errno = MESHLINK_EINVAL; + return NULL; + } + } else { + s = (meshlink_submesh_t *)mesh->self->submesh; + } + pthread_mutex_lock(&(mesh->mesh_mutex)); // Check validity of the new node's name @@ -2341,6 +2453,11 @@ char *meshlink_invite_ex(meshlink_handle_t *mesh, const char *name, uint32_t fla // Fill in the details. fprintf(f, "Name = %s\n", name); + + if(s) { + fprintf(f, "SubMesh = %s\n", s->name); + } + fprintf(f, "ConnectTo = %s\n", mesh->self->name); // Copy Broadcast and Mode @@ -2386,8 +2503,8 @@ char *meshlink_invite_ex(meshlink_handle_t *mesh, const char *name, uint32_t fla return url; } -char *meshlink_invite(meshlink_handle_t *mesh, const char *name) { - return meshlink_invite_ex(mesh, name, 0); +char *meshlink_invite(meshlink_handle_t *mesh, meshlink_submesh_t *submesh, const char *name) { + return meshlink_invite_ex(mesh, submesh, name, 0); } bool meshlink_join(meshlink_handle_t *mesh, const char *invitation) { @@ -2753,6 +2870,20 @@ void meshlink_blacklist(meshlink_handle_t *mesh, meshlink_node_t *node) { node_t *n; n = (node_t *)node; + + if(n == mesh->self) { + logger(mesh, MESHLINK_ERROR, "%s blacklisting itself?\n", node->name); + meshlink_errno = MESHLINK_EINVAL; + pthread_mutex_unlock(&(mesh->mesh_mutex)); + return; + } + + if(n->status.blacklisted) { + logger(mesh, MESHLINK_DEBUG, "Node %s already blacklisted\n", node->name); + pthread_mutex_unlock(&(mesh->mesh_mutex)); + return; + } + n->status.blacklisted = true; logger(mesh, MESHLINK_DEBUG, "Blacklisted %s.\n", node->name); @@ -2766,6 +2897,18 @@ void meshlink_blacklist(meshlink_handle_t *mesh, meshlink_node_t *node) { } } + utcp_abort_all_connections(n->utcp); + + n->mtu = 0; + n->minmtu = 0; + n->maxmtu = MTU; + n->mtuprobes = 0; + n->status.udp_confirmed = false; + + if(n->status.reachable) { + update_node_status(mesh, n); + } + pthread_mutex_unlock(&(mesh->mesh_mutex)); } @@ -2778,9 +2921,22 @@ void meshlink_whitelist(meshlink_handle_t *mesh, meshlink_node_t *node) { pthread_mutex_lock(&(mesh->mesh_mutex)); node_t *n = (node_t *)node; + + if(!n->status.blacklisted) { + logger(mesh, MESHLINK_DEBUG, "Node %s was already whitelisted\n", node->name); + meshlink_errno = MESHLINK_EINVAL; + pthread_mutex_unlock(&(mesh->mesh_mutex)); + return; + } + n->status.blacklisted = false; - //TODO: remove blacklisted = yes from the config file + if(n->status.reachable) { + update_node_status(mesh, n); + } + + //Remove blacklisting from the config file + append_config_file(mesh, n->name, "blacklisted", NULL); pthread_mutex_unlock(&(mesh->mesh_mutex)); return; @@ -2969,6 +3125,11 @@ meshlink_channel_t *meshlink_channel_open_ex(meshlink_handle_t *mesh, meshlink_n } } + if(n->status.blacklisted) { + logger(mesh, MESHLINK_ERROR, "Cannot open a channel with blacklisted node\n"); + return NULL; + } + meshlink_channel_t *channel = xzalloc(sizeof(*channel)); channel->node = n; channel->receive_cb = cb; @@ -3023,7 +3184,7 @@ ssize_t meshlink_channel_send(meshlink_handle_t *mesh, meshlink_channel_t *chann // TODO: more finegrained locking. // Ideally we want to put the data into the UTCP connection's send buffer. - // Then, preferrably only if there is room in the receiver window, + // Then, preferably only if there is room in the receiver window, // kick the meshlink thread to go send packets. pthread_mutex_lock(&mesh->mesh_mutex); @@ -3046,13 +3207,31 @@ uint32_t meshlink_channel_get_flags(meshlink_handle_t *mesh, meshlink_channel_t return channel->c->flags; } +size_t meshlink_channel_get_sendq(meshlink_handle_t *mesh, meshlink_channel_t *channel) { + if(!mesh || !channel) { + meshlink_errno = MESHLINK_EINVAL; + return -1; + } + + return utcp_get_sendq(channel->c); +} + +size_t meshlink_channel_get_recvq(meshlink_handle_t *mesh, meshlink_channel_t *channel) { + if(!mesh || !channel) { + meshlink_errno = MESHLINK_EINVAL; + return -1; + } + + return utcp_get_recvq(channel->c); +} + void update_node_status(meshlink_handle_t *mesh, node_t *n) { if(n->status.reachable && mesh->channel_accept_cb && !n->utcp) { n->utcp = utcp_init(channel_accept, channel_pre_accept, channel_send, n); } if(mesh->node_status_cb) { - mesh->node_status_cb(mesh, (meshlink_node_t *)n, n->status.reachable); + mesh->node_status_cb(mesh, (meshlink_node_t *)n, n->status.reachable && !n->status.blacklisted); } }