From afea9096fa708b2a2e6e24c308c0f1a80eefa5cc Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Fri, 29 Jan 2021 22:59:57 +0100 Subject: [PATCH] Add meshlink_set_storage_policy(). This allows control over when MeshLink stores configuration files: - MESHLINK_STORAGE_ENABLED: on all updates - MESHLINK_STORAGE_KEYS_ONLY: only on new keys and black/whitelist updates - MESHLINK_STORAGE_DISABLED: never --- src/conf.c | 2 +- src/graph.c | 2 +- src/meshlink++.h | 13 ++++++++++ src/meshlink.c | 53 ++++++++++++++++++++++++++++++++--------- src/meshlink.h | 30 +++++++++++++++++++++++ src/meshlink.sym | 2 ++ src/meshlink_internal.h | 2 ++ src/net.c | 4 +--- src/net.h | 2 +- src/net_setup.c | 18 +++++++++++++- src/protocol_auth.c | 2 +- 11 files changed, 111 insertions(+), 19 deletions(-) diff --git a/src/conf.c b/src/conf.c index dd076170..af080384 100644 --- a/src/conf.c +++ b/src/conf.c @@ -405,7 +405,7 @@ bool config_rename(meshlink_handle_t *mesh, const char *old_conf_subdir, const c bool config_sync(meshlink_handle_t *mesh, const char *conf_subdir) { assert(conf_subdir); - if(!mesh->confbase) { + if(!mesh->confbase || mesh->storage_policy == MESHLINK_STORAGE_DISABLED) { return true; } diff --git a/src/graph.c b/src/graph.c index b73a35e6..c7401b6a 100644 --- a/src/graph.c +++ b/src/graph.c @@ -177,7 +177,7 @@ static void check_reachability(meshlink_handle_t *mesh) { n->last_reachable = time(NULL); if(first_time_reachable) { - if(!node_write_config(mesh, n)) { + if(!node_write_config(mesh, n, false)) { logger(mesh, MESHLINK_WARNING, "Could not write host config file for node %s!\n", n->name); } diff --git a/src/meshlink++.h b/src/meshlink++.h index 51bc5e37..1f109849 100644 --- a/src/meshlink++.h +++ b/src/meshlink++.h @@ -705,6 +705,19 @@ public: meshlink_set_scheduling_granularity(handle, granularity); } + /// Sets the storage policy used by MeshLink + /** This sets the policy MeshLink uses when it has new information about nodes. + * By default, all udpates will be stored to disk (unless an ephemeral instance has been opened). + * Setting the policy to MESHLINK_STORAGE_KEYS_ONLY, only updates that contain new keys for nodes + * are stored, as well as blacklist/whitelist settings. + * By setting the policy to MESHLINK_STORAGE_DISABLED, no updates will be stored. + * + * @param policy The storage policy to use. + */ + void set_storage_policy(meshlink_storage_policy_t policy) { + meshlink_set_storage_policy(handle, policy); + } + /// Invite another node into the mesh. /** This function generates an invitation that can be used by another node to join the same mesh as the local node. * The generated invitation is a string containing a URL. diff --git a/src/meshlink.c b/src/meshlink.c index 1540df37..26bcada7 100644 --- a/src/meshlink.c +++ b/src/meshlink.c @@ -689,7 +689,7 @@ static bool write_main_config_files(meshlink_handle_t *mesh) { } /* Write our own host config file */ - if(!node_write_config(mesh, mesh->self)) { + if(!node_write_config(mesh, mesh->self, true)) { return false; } @@ -823,7 +823,7 @@ static bool finalize_join(join_state_t *state, const void *buf, uint16_t len) { n->last_reachable = 0; n->last_unreachable = 0; - if(!node_write_config(mesh, n)) { + if(!node_write_config(mesh, n, true)) { free_node(n); return false; } @@ -1262,6 +1262,17 @@ bool meshlink_open_params_set_storage_key(meshlink_open_params_t *params, const return true; } +bool meshlink_open_params_set_storage_policy(meshlink_open_params_t *params, meshlink_storage_policy_t policy) { + if(!params) { + meshlink_errno = MESHLINK_EINVAL; + return false; + } + + params->storage_policy = policy; + + return true; +} + bool meshlink_encrypted_key_rotate(meshlink_handle_t *mesh, const void *new_key, size_t new_keylen) { if(!mesh || !new_key || !new_keylen) { logger(mesh, MESHLINK_ERROR, "Invalid arguments given!\n"); @@ -1544,6 +1555,8 @@ meshlink_handle_t *meshlink_open_ex(const meshlink_open_params_t *params) { // If no configuration exists yet, create it. + bool new_configuration = false; + if(!meshlink_confbase_exists(mesh)) { if(!mesh->name) { logger(NULL, MESHLINK_ERROR, "No configuration files found!\n"); @@ -1557,6 +1570,8 @@ meshlink_handle_t *meshlink_open_ex(const meshlink_open_params_t *params) { meshlink_close(mesh); return NULL; } + + new_configuration = true; } else { if(!meshlink_read_config(mesh)) { logger(NULL, MESHLINK_ERROR, "Cannot read main configuration\n"); @@ -1565,6 +1580,8 @@ meshlink_handle_t *meshlink_open_ex(const meshlink_open_params_t *params) { } } + mesh->storage_policy = params->storage_policy; + #ifdef HAVE_MINGW struct WSAData wsa_state; WSAStartup(MAKEWORD(2, 2), &wsa_state); @@ -1601,7 +1618,7 @@ meshlink_handle_t *meshlink_open_ex(const meshlink_open_params_t *params) { add_local_addresses(mesh); - if(!node_write_config(mesh, mesh->self)) { + if(!node_write_config(mesh, mesh->self, new_configuration)) { logger(NULL, MESHLINK_ERROR, "Cannot update configuration\n"); return NULL; } @@ -1829,7 +1846,7 @@ void meshlink_stop(meshlink_handle_t *mesh) { if(mesh->nodes) { for splay_each(node_t, n, mesh->nodes) { if(n->status.dirty) { - n->status.dirty = !node_write_config(mesh, n); + n->status.dirty = !node_write_config(mesh, n, false); } } } @@ -2645,7 +2662,7 @@ bool meshlink_set_canonical_address(meshlink_handle_t *mesh, meshlink_node_t *no free(n->canonical_address); n->canonical_address = canonical_address; - if(!node_write_config(mesh, n)) { + if(!node_write_config(mesh, n, false)) { pthread_mutex_unlock(&mesh->mutex); return false; } @@ -2669,7 +2686,7 @@ bool meshlink_clear_canonical_address(meshlink_handle_t *mesh, meshlink_node_t * free(n->canonical_address); n->canonical_address = NULL; - if(!node_write_config(mesh, n)) { + if(!node_write_config(mesh, n, false)) { pthread_mutex_unlock(&mesh->mutex); return false; } @@ -2919,7 +2936,7 @@ char *meshlink_invite_ex(meshlink_handle_t *mesh, meshlink_submesh_t *submesh, c // If we changed our own host config file, write it out now if(mesh->self->status.dirty) { - if(!node_write_config(mesh, mesh->self)) { + if(!node_write_config(mesh, mesh->self, false)) { logger(mesh, MESHLINK_ERROR, "Could not write our own host config file!\n"); pthread_mutex_unlock(&mesh->mutex); return NULL; @@ -3415,7 +3432,7 @@ bool meshlink_import(meshlink_handle_t *mesh, const char *data) { n->last_reachable = 0; n->last_unreachable = 0; - if(!node_write_config(mesh, n)) { + if(!node_write_config(mesh, n, true)) { free_node(n); return false; } @@ -3489,7 +3506,7 @@ static bool blacklist(meshlink_handle_t *mesh, node_t *n) { /* Remove any outstanding invitations */ invitation_purge_node(mesh, n->name); - return node_write_config(mesh, n) && config_sync(mesh, "current"); + return node_write_config(mesh, n, true) && config_sync(mesh, "current"); } bool meshlink_blacklist(meshlink_handle_t *mesh, meshlink_node_t *node) { @@ -3561,7 +3578,7 @@ static bool whitelist(meshlink_handle_t *mesh, node_t *n) { update_node_status(mesh, n); } - return node_write_config(mesh, n) && config_sync(mesh, "current"); + return node_write_config(mesh, n, true) && config_sync(mesh, "current"); } bool meshlink_whitelist(meshlink_handle_t *mesh, meshlink_node_t *node) { @@ -3695,7 +3712,7 @@ void meshlink_hint_address(meshlink_handle_t *mesh, meshlink_node_t *node, const node_t *n = (node_t *)node; if(node_add_recent_address(mesh, n, (sockaddr_t *)addr)) { - if(!node_write_config(mesh, n)) { + if(!node_write_config(mesh, n, false)) { logger(mesh, MESHLINK_DEBUG, "Could not update %s\n", n->name); } } @@ -4644,6 +4661,20 @@ void meshlink_set_scheduling_granularity(struct meshlink_handle *mesh, long gran utcp_set_clock_granularity(granularity); } +void meshlink_set_storage_policy(struct meshlink_handle *mesh, meshlink_storage_policy_t policy) { + if(!mesh) { + meshlink_errno = EINVAL; + return; + } + + if(pthread_mutex_lock(&mesh->mutex) != 0) { + abort(); + } + + mesh->storage_policy = policy; + pthread_mutex_unlock(&mesh->mutex); +} + void handle_network_change(meshlink_handle_t *mesh, bool online) { (void)online; diff --git a/src/meshlink.h b/src/meshlink.h index 822e314b..3be94710 100644 --- a/src/meshlink.h +++ b/src/meshlink.h @@ -83,6 +83,13 @@ typedef enum { DEV_CLASS_COUNT } dev_class_t; +/// Storage policy +typedef enum { + MESHLINK_STORAGE_ENABLED, ///< Store all updates. + MESHLINK_STORAGE_DISABLED, ///< Don't store any updates. + MESHLINK_STORAGE_KEYS_ONLY, ///< Only store updates when a node's key has changed. +} meshlink_storage_policy_t; + /// Invitation flags static const uint32_t MESHLINK_INVITE_LOCAL = 1; // Only use local addresses in the URL static const uint32_t MESHLINK_INVITE_PUBLIC = 2; // Only use public or canonical addresses in the URL @@ -189,6 +196,16 @@ bool meshlink_open_params_set_netns(meshlink_open_params_t *params, int netns) _ */ bool meshlink_open_params_set_storage_key(meshlink_open_params_t *params, const void *key, size_t keylen) __attribute__((__warn_unused_result__)); +/// Set the encryption key MeshLink should use for local storage. +/** This function changes the open parameters to use the given storage policy. + * + * @param params A pointer to a meshlink_open_params_t which must have been created earlier with meshlink_open_params_init(). + * @param policy The storage policy to use. + * + * @return This function will return true if the open parameters have been successfully updated, false otherwise. + */ +bool meshlink_open_params_set_storage_policy(meshlink_open_params_t *params, meshlink_storage_policy_t policy) __attribute__((__warn_unused_result__)); + /// Open or create a MeshLink instance. /** This function opens or creates a MeshLink instance. * All parameters needed by MeshLink are passed via a meshlink_open_params_t struct, @@ -1780,6 +1797,19 @@ void meshlink_set_external_address_discovery_url(struct meshlink_handle *mesh, c */ void meshlink_set_scheduling_granularity(struct meshlink_handle *mesh, long granularity); +/// Sets the storage policy used by MeshLink +/** This sets the policy MeshLink uses when it has new information about nodes. + * By default, all udpates will be stored to disk (unless an ephemeral instance has been opened). + * Setting the policy to MESHLINK_STORAGE_KEYS_ONLY, only updates that contain new keys for nodes + * are stored, as well as blacklist/whitelist settings. + * By setting the policy to MESHLINK_STORAGE_DISABLED, no updates will be stored. + * + * \memberof meshlink_handle + * @param mesh A handle which represents an instance of MeshLink. + * @param policy The storage policy to use. + */ +void meshlink_set_storage_policy(struct meshlink_handle *mesh, meshlink_storage_policy_t policy); + #ifdef __cplusplus } #endif diff --git a/src/meshlink.sym b/src/meshlink.sym index 6c29df36..f8df23e1 100644 --- a/src/meshlink.sym +++ b/src/meshlink.sym @@ -67,6 +67,7 @@ meshlink_open_params_free meshlink_open_params_init meshlink_open_params_set_netns meshlink_open_params_set_storage_key +meshlink_open_params_set_storage_policy meshlink_reset_timers meshlink_send meshlink_set_blacklisted_cb @@ -100,6 +101,7 @@ meshlink_set_scheduling_granularity meshlink_sign meshlink_start meshlink_stop +meshlink_set_storage_policy meshlink_strerror meshlink_submesh_open meshlink_verify diff --git a/src/meshlink_internal.h b/src/meshlink_internal.h index 01107507..6cbe6093 100644 --- a/src/meshlink_internal.h +++ b/src/meshlink_internal.h @@ -67,6 +67,7 @@ struct meshlink_open_params { const void *key; size_t keylen; + meshlink_storage_policy_t storage_policy; }; /// Device class traits @@ -170,6 +171,7 @@ struct meshlink_handle { void *config_key; char *external_address_url; struct list_t *invitation_addresses; + meshlink_storage_policy_t storage_policy; // Thread management pthread_t thread; diff --git a/src/net.c b/src/net.c index 99c29c94..9a062f41 100644 --- a/src/net.c +++ b/src/net.c @@ -620,11 +620,9 @@ static void periodic_handler(event_loop_t *loop, void *data) { for splay_each(node_t, n, mesh->nodes) { if(n->status.dirty) { - if(!node_write_config(mesh, n)) { + if(!node_write_config(mesh, n, false)) { logger(mesh, MESHLINK_DEBUG, "Could not update %s", n->name); } - - n->status.dirty = false; } if(n->status.reachable && n->status.validkey && n->last_req_key + 3600 < mesh->loop.now.tv_sec) { diff --git a/src/net.h b/src/net.h index 5ad27979..9994fac6 100644 --- a/src/net.h +++ b/src/net.h @@ -106,7 +106,7 @@ bool node_read_public_key(struct meshlink_handle *mesh, struct node_t *) __attri bool node_read_from_config(struct meshlink_handle *mesh, struct node_t *, const config_t *config) __attribute__((__warn_unused_result__)); bool read_ecdsa_public_key(struct meshlink_handle *mesh, struct connection_t *) __attribute__((__warn_unused_result__)); bool read_ecdsa_private_key(struct meshlink_handle *mesh) __attribute__((__warn_unused_result__)); -bool node_write_config(struct meshlink_handle *mesh, struct node_t *) __attribute__((__warn_unused_result__)); +bool node_write_config(struct meshlink_handle *mesh, struct node_t *, bool new_key) __attribute__((__warn_unused_result__)); void send_mtu_probe(struct meshlink_handle *mesh, struct node_t *); void handle_meta_connection_data(struct meshlink_handle *mesh, struct connection_t *); void retry(struct meshlink_handle *mesh); diff --git a/src/net_setup.c b/src/net_setup.c index 6168c4ca..a7a538f0 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -218,11 +218,26 @@ bool node_read_from_config(meshlink_handle_t *mesh, node_t *n, const config_t *c return packmsg_done(&in); } -bool node_write_config(meshlink_handle_t *mesh, node_t *n) { +bool node_write_config(meshlink_handle_t *mesh, node_t *n, bool new_key) { if(!mesh->confbase) { return true; } + switch(mesh->storage_policy) { + case MESHLINK_STORAGE_KEYS_ONLY: + if(!new_key) { + return true; + } + + break; + + case MESHLINK_STORAGE_DISABLED: + return true; + + default: + break; + } + uint8_t buf[4096]; packmsg_output_t out = {buf, sizeof(buf)}; @@ -271,6 +286,7 @@ bool node_write_config(meshlink_handle_t *mesh, node_t *n) { return false; } + n->status.dirty = false; return true; } diff --git a/src/protocol_auth.c b/src/protocol_auth.c index 1f2e24a2..5f2fc1c3 100644 --- a/src/protocol_auth.c +++ b/src/protocol_auth.c @@ -71,7 +71,7 @@ static bool commit_invitation(meshlink_handle_t *mesh, connection_t *c, const vo // Remember its current address node_add_recent_address(mesh, n, &c->address); - if(!node_write_config(mesh, n) || !config_sync(mesh, "current")) { + if(!node_write_config(mesh, n, true) || !config_sync(mesh, "current")) { logger(mesh, MESHLINK_ERROR, "Error writing configuration file for invited node %s!\n", c->name); free_node(n); return false; -- 2.39.2