#include "system.h"
#include <pthread.h>
-#include "adns.h"
#include "crypto.h"
#include "ecdsagen.h"
#include "logger.h"
#include "utils.h"
#include "xalloc.h"
#include "ed25519/sha512.h"
-#include "discovery.h"
#include "devtools.h"
-#include "graph.h"
#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
}
logger(mesh, MESHLINK_DEBUG, "Trying to discover externally visible hostname...\n");
- struct addrinfo *ai = adns_blocking_request(mesh, xstrdup(host), xstrdup(port ? port : "80"), SOCK_STREAM, 5);
+ struct addrinfo *ai = str2addrinfo(host, port ? port : "80", SOCK_STREAM);
char line[256];
char *hostname = NULL;
}
}
- /* If TCP worked, then we require that UDP works as well. */
-
- int udp_fd = setup_udp_listen_socket(mesh, aip);
-
- if(udp_fd == -1) {
- closesocket(tcp_fd);
- success = false;
- break;
- }
-
closesocket(tcp_fd);
- closesocket(udp_fd);
success = true;
}
}
}
- /* Clear the reachability times, since we ourself have never seen these nodes yet */
- n->last_reachable = 0;
- n->last_unreachable = 0;
-
if(!node_write_config(mesh, n, true)) {
free_node(n);
return false;
mesh->appname = xstrdup(params->appname);
mesh->devclass = params->devclass;
- mesh->discovery.enabled = true;
mesh->netns = params->netns;
mesh->submeshes = NULL;
mesh->log_cb = global_log_cb;
pthread_mutex_init(&mesh->mutex, &attr);
pthread_cond_init(&mesh->cond, NULL);
- pthread_cond_init(&mesh->adns_cond, NULL);
-
mesh->threadstarted = false;
event_loop_init(&mesh->loop);
mesh->loop.data = mesh;
#endif // HAVE_SETNS
}
- if(mesh->discovery.enabled) {
- discovery_start(mesh);
- }
-
if(pthread_mutex_lock(&mesh->mutex) != 0) {
abort();
}
pthread_mutex_unlock(&mesh->mutex);
- // Stop discovery
- if(mesh->discovery.enabled) {
- discovery_stop(mesh);
- }
-
return NULL;
}
}
init_outgoings(mesh);
- init_adns(mesh);
// Start the main thread
pthread_cond_wait(&mesh->cond, &mesh->mutex);
mesh->threadstarted = true;
- // Ensure we are considered reachable
- graph(mesh);
-
pthread_mutex_unlock(&mesh->mutex);
return true;
}
// Shut down the main thread
event_loop_stop(&mesh->loop);
- // Send ourselves a UDP packet to kick the event loop
- for(int i = 0; i < mesh->listen_sockets; i++) {
- sockaddr_t sa;
- socklen_t salen = sizeof(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(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));
- }
- }
+ // TODO: send something to a local socket to kick the event loop
if(mesh->threadstarted) {
// Wait for the main thread to finish
}
}
- exit_adns(mesh);
exit_outgoings(mesh);
- // Ensure we are considered unreachable
- if(mesh->nodes) {
- graph(mesh);
- }
-
// Try to write out any changed node config files, ignore errors at this point.
if(mesh->nodes) {
for splay_each(node_t, n, mesh->nodes) {
pthread_mutex_unlock(&mesh->mutex);
}
-void meshlink_set_blacklisted_cb(struct meshlink_handle *mesh, meshlink_blacklisted_cb_t cb) {
- logger(mesh, MESHLINK_DEBUG, "meshlink_set_blacklisted_cb(%p)", (void *)(intptr_t)cb);
-
- if(!mesh) {
- meshlink_errno = MESHLINK_EINVAL;
- return;
- }
-
- if(pthread_mutex_lock(&mesh->mutex) != 0) {
- abort();
- }
-
- mesh->blacklisted_cb = cb;
- pthread_mutex_unlock(&mesh->mutex);
-}
-
static bool prepare_packet(meshlink_handle_t *mesh, meshlink_node_t *destination, const void *data, size_t len, vpn_packet_t *packet) {
meshlink_packethdr_t *hdr;
return false;
}
-static bool search_node_by_blacklisted(const node_t *node, const void *condition) {
- return *(bool *)condition == node->status.blacklisted;
-}
-
static bool search_node_by_submesh(const node_t *node, const void *condition) {
if(condition == node->submesh) {
return true;
time_t end;
};
-static bool search_node_by_last_reachable(const node_t *node, const void *condition) {
- const struct time_range *range = condition;
- time_t start = node->last_reachable;
- time_t end = node->last_unreachable;
-
- if(end < start) {
- end = time(NULL);
-
- if(end < start) {
- start = end;
- }
- }
-
- if(range->end >= range->start) {
- return start <= range->end && end >= range->start;
- } else {
- return start > range->start || end < range->end;
- }
-}
-
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 || devclass < 0 || devclass >= DEV_CLASS_COUNT || !nmemb) {
meshlink_errno = MESHLINK_EINVAL;
return meshlink_get_all_nodes_by_condition(mesh, submesh, nodes, nmemb, search_node_by_submesh);
}
-meshlink_node_t **meshlink_get_all_nodes_by_last_reachable(meshlink_handle_t *mesh, time_t start, time_t end, meshlink_node_t **nodes, size_t *nmemb) {
- if(!mesh || !nmemb) {
- meshlink_errno = MESHLINK_EINVAL;
- return NULL;
- }
-
- struct time_range range = {start, end};
-
- return meshlink_get_all_nodes_by_condition(mesh, &range, nodes, nmemb, search_node_by_last_reachable);
-}
-
-meshlink_node_t **meshlink_get_all_nodes_by_blacklisted(meshlink_handle_t *mesh, bool blacklisted, meshlink_node_t **nodes, size_t *nmemb) {
- if(!mesh || !nmemb) {
- meshlink_errno = MESHLINK_EINVAL;
- return NULL;
- }
-
- return meshlink_get_all_nodes_by_condition(mesh, &blacklisted, nodes, nmemb, search_node_by_blacklisted);
-}
-
dev_class_t meshlink_get_node_dev_class(meshlink_handle_t *mesh, meshlink_node_t *node) {
if(!mesh || !node) {
meshlink_errno = MESHLINK_EINVAL;
return devclass;
}
-bool meshlink_get_node_blacklisted(meshlink_handle_t *mesh, meshlink_node_t *node) {
- if(!mesh) {
- meshlink_errno = MESHLINK_EINVAL;
- }
-
- if(!node) {
- return mesh->default_blacklist;
- }
-
- bool blacklisted;
-
- if(pthread_mutex_lock(&mesh->mutex) != 0) {
- abort();
- }
-
- blacklisted = ((node_t *)node)->status.blacklisted;
-
- pthread_mutex_unlock(&mesh->mutex);
-
- return blacklisted;
-}
-
meshlink_submesh_t *meshlink_get_node_submesh(meshlink_handle_t *mesh, meshlink_node_t *node) {
if(!mesh || !node) {
meshlink_errno = MESHLINK_EINVAL;
reachable = n->status.reachable && !n->status.blacklisted;
- if(last_reachable) {
- *last_reachable = n->last_reachable;
- }
-
- if(last_unreachable) {
- *last_unreachable = n->last_unreachable;
- }
+ // TODO: handle reachable times?
+ (void)last_reachable;
+ (void)last_unreachable;
pthread_mutex_unlock(&mesh->mutex);
}
// Connect to the meshlink daemon mentioned in the URL.
- struct addrinfo *ai = adns_blocking_request(mesh, xstrdup(address), xstrdup(port), SOCK_STREAM, 30);
+ struct addrinfo *ai = str2addrinfo(address, port, SOCK_STREAM);
if(ai) {
for(struct addrinfo *aip = ai; aip; aip = aip->ai_next) {
break;
}
- /* Clear the reachability times, since we ourself have never seen these nodes yet */
- n->last_reachable = 0;
- n->last_unreachable = 0;
-
if(!node_write_config(mesh, n, true)) {
free_node(n);
free(buf);
return true;
}
-static bool blacklist(meshlink_handle_t *mesh, node_t *n) {
- if(n == mesh->self) {
- logger(mesh, MESHLINK_ERROR, "%s blacklisting itself?\n", n->name);
- meshlink_errno = MESHLINK_EINVAL;
- return false;
- }
-
- if(n->status.blacklisted) {
- logger(mesh, MESHLINK_DEBUG, "Node %s already blacklisted\n", n->name);
- return true;
- }
-
- n->status.blacklisted = true;
-
- /* Immediately shut down any connections we have with the blacklisted node.
- * We can't call terminate_connection(), because we might be called from a callback function.
- */
- for list_each(connection_t, c, mesh->connections) {
- if(c->node == n) {
- if(c->status.active) {
- send_error(mesh, c, BLACKLISTED, "blacklisted");
- }
-
- shutdown(c->socket, SHUT_RDWR);
- }
- }
-
- utcp_reset_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) {
- n->last_unreachable = time(NULL);
- }
-
- /* Graph updates will suppress status updates for blacklisted nodes, so we need to
- * manually call the status callback if necessary.
- */
- if(n->status.reachable && mesh->node_status_cb) {
- mesh->node_status_cb(mesh, (meshlink_node_t *)n, false);
- }
-
- return node_write_config(mesh, n, true) && config_sync(mesh, "current");
-}
-
-bool meshlink_blacklist(meshlink_handle_t *mesh, meshlink_node_t *node) {
- logger(mesh, MESHLINK_DEBUG, "meshlink_blacklist(%s)", node ? node->name : "(null)");
-
- if(!mesh || !node) {
- meshlink_errno = MESHLINK_EINVAL;
- return false;
- }
-
- if(pthread_mutex_lock(&mesh->mutex) != 0) {
- abort();
- }
-
- if(!blacklist(mesh, (node_t *)node)) {
- pthread_mutex_unlock(&mesh->mutex);
- return false;
- }
-
- pthread_mutex_unlock(&mesh->mutex);
-
- logger(mesh, MESHLINK_DEBUG, "Blacklisted %s.\n", node->name);
- return true;
-}
-
-bool meshlink_blacklist_by_name(meshlink_handle_t *mesh, const char *name) {
- logger(mesh, MESHLINK_DEBUG, "meshlink_blacklist_by_name(%s)", name ? name : "(null)");
-
- if(!mesh || !name) {
- meshlink_errno = MESHLINK_EINVAL;
- return false;
- }
-
- if(pthread_mutex_lock(&mesh->mutex) != 0) {
- abort();
- }
-
- node_t *n = lookup_node(mesh, (char *)name);
-
- if(!n) {
- n = new_node();
- n->name = xstrdup(name);
- node_add(mesh, n);
- }
-
- if(!blacklist(mesh, (node_t *)n)) {
- pthread_mutex_unlock(&mesh->mutex);
- return false;
- }
-
- pthread_mutex_unlock(&mesh->mutex);
-
- logger(mesh, MESHLINK_DEBUG, "Blacklisted %s.\n", name);
- return true;
-}
-
-static bool whitelist(meshlink_handle_t *mesh, node_t *n) {
- if(n == mesh->self) {
- logger(mesh, MESHLINK_ERROR, "%s whitelisting itself?\n", n->name);
- meshlink_errno = MESHLINK_EINVAL;
- return false;
- }
-
- if(!n->status.blacklisted) {
- logger(mesh, MESHLINK_DEBUG, "Node %s was already whitelisted\n", n->name);
- return true;
- }
-
- n->status.blacklisted = false;
-
- if(n->status.reachable) {
- n->last_reachable = time(NULL);
- update_node_status(mesh, n);
- }
-
- return node_write_config(mesh, n, true) && config_sync(mesh, "current");
-}
-
-bool meshlink_whitelist(meshlink_handle_t *mesh, meshlink_node_t *node) {
- logger(mesh, MESHLINK_DEBUG, "meshlink_whitelist(%s)", node ? node->name : "(null)");
-
- if(!mesh || !node) {
- meshlink_errno = MESHLINK_EINVAL;
- return false;
- }
-
- if(pthread_mutex_lock(&mesh->mutex) != 0) {
- abort();
- }
-
- if(!whitelist(mesh, (node_t *)node)) {
- pthread_mutex_unlock(&mesh->mutex);
- return false;
- }
-
- pthread_mutex_unlock(&mesh->mutex);
-
- logger(mesh, MESHLINK_DEBUG, "Whitelisted %s.\n", node->name);
- return true;
-}
-
-bool meshlink_whitelist_by_name(meshlink_handle_t *mesh, const char *name) {
- logger(mesh, MESHLINK_DEBUG, "meshlink_whitelist_by_name(%s)", name ? name : "(null)");
-
- if(!mesh || !name) {
- meshlink_errno = MESHLINK_EINVAL;
- return false;
- }
-
- if(pthread_mutex_lock(&mesh->mutex) != 0) {
- abort();
- }
-
- node_t *n = lookup_node(mesh, (char *)name);
-
- if(!n) {
- n = new_node();
- n->name = xstrdup(name);
- node_add(mesh, n);
- }
-
- if(!whitelist(mesh, (node_t *)n)) {
- pthread_mutex_unlock(&mesh->mutex);
- return false;
- }
-
- pthread_mutex_unlock(&mesh->mutex);
-
- logger(mesh, MESHLINK_DEBUG, "Whitelisted %s.\n", name);
- return true;
-}
-
-void meshlink_set_default_blacklist(meshlink_handle_t *mesh, bool blacklist) {
- mesh->default_blacklist = blacklist;
-}
-
bool meshlink_forget_node(meshlink_handle_t *mesh, meshlink_node_t *node) {
logger(mesh, MESHLINK_DEBUG, "meshlink_forget_node(%s)", node ? node->name : "(null)");
mesh->node_duplicate_cb(mesh, (meshlink_node_t *)n);
}
-void meshlink_enable_discovery(meshlink_handle_t *mesh, bool enable) {
- logger(mesh, MESHLINK_DEBUG, "meshlink_enable_discovery(%d)", enable);
-
- if(!mesh) {
- meshlink_errno = MESHLINK_EINVAL;
- return;
- }
-
- if(pthread_mutex_lock(&mesh->mutex) != 0) {
- abort();
- }
-
- if(mesh->discovery.enabled == enable) {
- goto end;
- }
-
- if(mesh->threadstarted) {
- if(enable) {
- discovery_start(mesh);
- } else {
- discovery_stop(mesh);
- }
- }
-
- mesh->discovery.enabled = enable;
-
-end:
- pthread_mutex_unlock(&mesh->mutex);
-}
-
void meshlink_hint_network_change(struct meshlink_handle *mesh) {
logger(mesh, MESHLINK_DEBUG, "meshlink_hint_network_change()");
abort();
}
- if(mesh->discovery.enabled) {
- scan_ifaddrs(mesh);
- }
-
- if(mesh->loop.now.tv_sec > mesh->discovery.last_update + 5) {
- mesh->discovery.last_update = mesh->loop.now.tv_sec;
- handle_network_change(mesh, 1);
- }
-
pthread_mutex_unlock(&mesh->mutex);
}
handle_network_change(mesh, true);
- if(mesh->discovery.enabled) {
- discovery_refresh(mesh);
- }
-
pthread_mutex_unlock(&mesh->mutex);
}
pthread_mutex_unlock(&mesh->mutex);
}
-void meshlink_set_external_address_discovery_url(struct meshlink_handle *mesh, const char *url) {
- logger(mesh, MESHLINK_DEBUG, "meshlink_set_external_address_discovery_url(%s)", url ? url : "(null)");
-
- if(!mesh) {
- meshlink_errno = EINVAL;
- return;
- }
-
- if(url && (strncmp(url, "http://", 7) || strchr(url, ' '))) {
- meshlink_errno = EINVAL;
- return;
- }
-
- if(pthread_mutex_lock(&mesh->mutex) != 0) {
- abort();
- }
-
- free(mesh->external_address_url);
- mesh->external_address_url = url ? xstrdup(url) : NULL;
- pthread_mutex_unlock(&mesh->mutex);
-}
-
void meshlink_set_scheduling_granularity(struct meshlink_handle *mesh, long granularity) {
logger(mesh, MESHLINK_DEBUG, "meshlink_set_scheduling_granularity(%ld)", granularity);