X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=src%2Fmeshlink.c;h=7552c9f0be6d1bf064a90512b87facb9f198d186;hb=a1b50920b9a52f86ca6e33fcb24d7fa34313a1ee;hp=6fe57c024e9d0f1b8278c665a0056cc5f2654a3f;hpb=98376916eae96a058d4291187d3960eeea218fee;p=meshlink diff --git a/src/meshlink.c b/src/meshlink.c index 6fe57c02..7552c9f0 100644 --- a/src/meshlink.c +++ b/src/meshlink.c @@ -18,9 +18,14 @@ */ #include "system.h" +#include +#include "crypto.h" +#include "ecdsagen.h" #include "meshlink_internal.h" +#include "node.h" #include "protocol.h" +#include "route.h" #include "xalloc.h" static const char *errstr[] = { @@ -33,17 +38,155 @@ const char *meshlink_strerror(meshlink_errno_t errno) { return errstr[errno]; } -// TODO: hack, remove once all global variables are gone. -static void set_mesh(meshlink_handle_t *localmesh) { - mesh = localmesh; +static bool ecdsa_keygen(meshlink_handle_t *mesh) { + ecdsa_t *key; + FILE *f; + char pubname[PATH_MAX], privname[PATH_MAX]; + + fprintf(stderr, "Generating ECDSA keypair:\n"); + + if(!(key = ecdsa_generate())) { + fprintf(stderr, "Error during key generation!\n"); + return false; + } else + fprintf(stderr, "Done.\n"); + + snprintf(privname, sizeof privname, "%s" SLASH "ecdsa_key.priv", mesh->confbase); + f = fopen(privname, "w"); + + if(!f) + return false; + +#ifdef HAVE_FCHMOD + fchmod(fileno(f), 0600); +#endif + + if(!ecdsa_write_pem_private_key(key, f)) { + fprintf(stderr, "Error writing private key!\n"); + ecdsa_free(key); + fclose(f); + return false; + } + + fclose(f); + + + snprintf(pubname, sizeof pubname, "%s" SLASH "hosts" SLASH "%s", mesh->confbase, mesh->name); + f = fopen(pubname, "a"); + + if(!f) + return false; + + char *pubkey = ecdsa_get_base64_public_key(key); + fprintf(f, "ECDSAPublicKey = %s\n", pubkey); + free(pubkey); + + fclose(f); + ecdsa_free(key); + + return true; } -static meshlink_handle_t *meshlink_setup(meshlink_handle_t *mesh) { - set_mesh(mesh); - return mesh; +static bool try_bind(int port) { + struct addrinfo *ai = NULL; + struct addrinfo hint = { + .ai_flags = AI_PASSIVE, + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM, + .ai_protocol = IPPROTO_TCP, + }; + + char portstr[16]; + snprintf(portstr, sizeof portstr, "%d", port); + + if(getaddrinfo(NULL, portstr, &hint, &ai) || !ai) + return false; + + while(ai) { + int fd = socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP); + if(!fd) + return false; + int result = bind(fd, ai->ai_addr, ai->ai_addrlen); + closesocket(fd); + if(result) + return false; + ai = ai->ai_next; + } + + return true; +} + +static int check_port(meshlink_handle_t *mesh) { + if(try_bind(655)) + return 655; + + fprintf(stderr, "Warning: could not bind to port 655.\n"); + + for(int i = 0; i < 100; i++) { + int port = 0x1000 + (rand() & 0x7fff); + if(try_bind(port)) { + char filename[PATH_MAX]; + snprintf(filename, sizeof filename, "%s" SLASH "hosts" SLASH "%s", mesh->confbase, mesh->name); + FILE *f = fopen(filename, "a"); + if(!f) { + fprintf(stderr, "Please change MeshLink's Port manually.\n"); + return 0; + } + + fprintf(f, "Port = %d\n", port); + fclose(f); + fprintf(stderr, "MeshLink will instead listen on port %d.\n", port); + return port; + } + } + + fprintf(stderr, "Please change MeshLink's Port manually.\n"); + return 0; +} + +static bool meshlink_setup(meshlink_handle_t *mesh) { + char meshlink_conf[PATH_MAX]; + char hosts_dir[PATH_MAX]; + + if(mkdir(mesh->confbase, 0777) && errno != EEXIST) { + fprintf(stderr, "Could not create directory %s: %s\n", mesh->confbase, strerror(errno)); + return false; + } + + snprintf(hosts_dir, sizeof hosts_dir, "%s" SLASH "hosts", mesh->confbase); + + if(mkdir(hosts_dir, 0777) && errno != EEXIST) { + fprintf(stderr, "Could not create directory %s: %s\n", hosts_dir, strerror(errno)); + return false; + } + + snprintf(meshlink_conf, sizeof meshlink_conf, "%s" SLASH "meshlink.conf", mesh->confbase); + + if(!access(meshlink_conf, F_OK)) { + fprintf(stderr, "Configuration file %s already exists!\n", meshlink_conf); + return false; + } + + FILE *f = fopen(meshlink_conf, "w"); + if(!f) { + fprintf(stderr, "Could not create file %s: %s\n", meshlink_conf, strerror(errno)); + return 1; + } + + fprintf(f, "Name = %s\n", mesh->name); + fclose(f); + + if(!ecdsa_keygen(mesh)) + return false; + + check_port(mesh); + + return true; } meshlink_handle_t *meshlink_open(const char *confbase, const char *name) { + // Validate arguments provided by the application + if(!confbase || !*confbase) { fprintf(stderr, "No confbase given!\n"); return NULL; @@ -62,73 +205,84 @@ meshlink_handle_t *meshlink_open(const char *confbase, const char *name) { meshlink_handle_t *mesh = xzalloc(sizeof *mesh); mesh->confbase = xstrdup(confbase); mesh->name = xstrdup(name); + event_loop_init(&mesh->loop); + mesh->loop.data = mesh; + + // TODO: should be set by a function. + mesh->debug_level = 5; + + // Check whether meshlink.conf already exists char filename[PATH_MAX]; snprintf(filename, sizeof filename, "%s" SLASH "meshlink.conf", confbase); - FILE *f = fopen(filename, "r"); + if(access(filename, R_OK)) { + if(errno == ENOENT) { + // If not, create it + meshlink_setup(mesh); + } else { + fprintf(stderr, "Cannot not read from %s: %s\n", filename, strerror(errno)); + return meshlink_close(mesh), NULL; + } + } - if(!f && errno == ENOENT) - return meshlink_setup(mesh); + // Read the configuration - if(!f) { - fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno)); - return meshlink_close(mesh), NULL; - } + init_configuration(&mesh->config); - char buf[1024] = ""; - if(!fgets(buf, sizeof buf, f)) { - fprintf(stderr, "Could not read line from %s: %s\n", filename, strerror(errno)); - fclose(f); + if(!read_server_config(mesh)) return meshlink_close(mesh), NULL; - } - fclose(f); + // Setup up everything + // TODO: we should not open listening sockets yet - size_t len = strlen(buf); - if(len && buf[len - 1] == '\n') - buf[--len] = 0; - if(len && buf[len - 1] == '\r') - buf[--len] = 0; - - if(strncmp(buf, "Name = ", 7) || !check_id(buf + 7)) { - fprintf(stderr, "Could not read Name from %s\n", filename); + if(!setup_network(mesh)) return meshlink_close(mesh), NULL; - } - if(strcmp(buf + 7, name)) { - fprintf(stderr, "Name in %s is %s, not the same as %s\n", filename, buf + 7, name); - free(mesh->name); - mesh->name = xstrdup(buf + 7); - } + return mesh; +} - snprintf(filename, sizeof filename, "%s" SLASH "ed25519_key.priv", mesh->confbase); - f = fopen(filename, "r"); - if(!f) { - fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno)); - return meshlink_close(mesh), NULL; - } +void *meshlink_main_loop(void *arg) { + meshlink_handle_t *mesh = arg; - mesh->self->ecdsa = ecdsa_read_pem_private_key(f); - fclose(f); + try_outgoing_connections(mesh); - if(!mesh->self->ecdsa) { - fprintf(stderr, "Could not read keypair!\n"); - return meshlink_close(mesh), NULL; - } + main_loop(mesh); - set_mesh(mesh); - return mesh; + return NULL; } bool meshlink_start(meshlink_handle_t *mesh) { - return false; + // TODO: open listening sockets first + + // Start the main thread + + if(pthread_create(&mesh->thread, NULL, meshlink_main_loop, mesh) != 0) { + fprintf(stderr, "Could not start thread: %s\n", strerror(errno)); + memset(&mesh->thread, 0, sizeof mesh->thread); + return false; + } + + return true; } void meshlink_stop(meshlink_handle_t *mesh) { + // TODO: close the listening sockets to signal the main thread to shut down + + // Wait for the main thread to finish + + pthread_join(mesh->thread, NULL); } void meshlink_close(meshlink_handle_t *mesh) { + // Close and free all resources used. + + close_network_connections(mesh); + + logger(DEBUG_ALWAYS, LOG_NOTICE, "Terminating"); + + exit_configuration(&mesh->config); + event_loop_exit(&mesh->loop); } void meshlink_set_receive_cb(meshlink_handle_t *mesh, meshlink_receive_cb_t cb) { @@ -145,10 +299,29 @@ void meshlink_set_log_cb(meshlink_handle_t *mesh, meshlink_log_level_t level, me } bool meshlink_send(meshlink_handle_t *mesh, meshlink_node_t *destination, const void *data, unsigned int len) { + vpn_packet_t packet; + meshlink_packethdr_t *hdr = (meshlink_packethdr_t *)packet.data; + if (sizeof(meshlink_packethdr_t) + len > MAXSIZE) { + //log something + return false; + } + + packet.probe = false; + memset(hdr, 0, sizeof *hdr); + memcpy(hdr->destination, destination->name, sizeof hdr->destination); + memcpy(hdr->source, mesh->self->name, sizeof hdr->source); + + packet.len = sizeof *hdr + len; + memcpy(packet.data + sizeof *hdr, data, len); + + mesh->self->in_packets++; + mesh->self->in_bytes += packet.len; + route(mesh, mesh->self, &packet); return false; } meshlink_node_t *meshlink_get_node(meshlink_handle_t *mesh, const char *name) { + return (meshlink_node_t *)lookup_node(mesh, name); return NULL; } @@ -183,3 +356,10 @@ bool meshlink_import(meshlink_handle_t *mesh, const char *data) { void meshlink_blacklist(meshlink_handle_t *mesh, meshlink_node_t *node) { } +static void __attribute__((constructor)) meshlink_init(void) { + crypto_init(); +} + +static void __attribute__((destructor)) meshlink_exit(void) { + crypto_exit(); +}