From d65ff28f38ba779fbd6f970fb3c84b0ed98daa28 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Tue, 11 Feb 2020 22:28:24 +0100 Subject: [PATCH] Make the join commit order configurable. By default, when an invitee joins a mesh, it will commit its configuration to disk first, then the inviter. This adds a function to reverse that order. --- src/meshlink++.h | 11 +++++++++ src/meshlink.c | 51 ++++++++++++++++++++++++++++++---------- src/meshlink.h | 11 +++++++++ src/meshlink.sym | 1 + src/meshlink_internal.h | 2 +- src/protocol_auth.c | 52 ++++++++++++++++++++++++----------------- 6 files changed, 93 insertions(+), 35 deletions(-) diff --git a/src/meshlink++.h b/src/meshlink++.h index 6374a86d..4d900448 100644 --- a/src/meshlink++.h +++ b/src/meshlink++.h @@ -1019,6 +1019,17 @@ public: meshlink_set_dev_class_fast_retry_period(handle, devclass, fast_retry_period); } + /// Set which order invitations are committed + /** This determines in which order configuration files are written to disk during an invitation. + * By default, the invitee saves the configuration to disk first, then the inviter. + * By calling this function with @a inviter_commits_first set to true, the order is reversed. + * + * @param inviter_commits_first If true, then the node that invited a peer will commit data to disk first. + */ + void set_inviter_commits_first(bool inviter_commits_first) { + meshlink_set_inviter_commits_first(handle, inviter_commits_first); + } + private: // non-copyable: mesh(const mesh &) /* TODO: C++11: = delete */; diff --git a/src/meshlink.c b/src/meshlink.c index eb9142cc..903ff09a 100644 --- a/src/meshlink.c +++ b/src/meshlink.c @@ -775,21 +775,44 @@ static bool invitation_receive(void *handle, uint8_t type, const void *msg, uint join_state_t *state = handle; meshlink_handle_t *mesh = state->mesh; - switch(type) { - case SPTPS_HANDSHAKE: - return sptps_send_record(&state->sptps, 0, state->cookie, 18); + if(mesh->inviter_commits_first) { + switch(type) { + case SPTPS_HANDSHAKE: + return sptps_send_record(&state->sptps, 2, state->cookie, 18 + 32); - case 0: - return finalize_join(state, msg, len); + case 1: + break; - case 1: - logger(mesh, MESHLINK_DEBUG, "Invitation successfully accepted.\n"); - shutdown(state->sock, SHUT_RDWR); - state->success = true; - break; + case 0: + if(!finalize_join(state, msg, len)) { + return false; + } - default: - return false; + logger(mesh, MESHLINK_DEBUG, "Invitation successfully accepted.\n"); + shutdown(state->sock, SHUT_RDWR); + state->success = true; + break; + + default: + return false; + } + } else { + switch(type) { + case SPTPS_HANDSHAKE: + return sptps_send_record(&state->sptps, 0, state->cookie, 18); + + case 0: + return finalize_join(state, msg, len); + + case 1: + logger(mesh, MESHLINK_DEBUG, "Invitation successfully accepted.\n"); + shutdown(state->sock, SHUT_RDWR); + state->success = true; + break; + + default: + return false; + } } return true; @@ -2647,6 +2670,10 @@ bool meshlink_join(meshlink_handle_t *mesh, const char *invitation) { goto invalid; } + if(mesh->inviter_commits_first) { + memcpy(state.cookie + 18, ecdsa_get_public_key(mesh->private_key), 32); + } + // Generate a throw-away key for the invitation. key = ecdsa_generate(); diff --git a/src/meshlink.h b/src/meshlink.h index 8a3c1a19..385c12ce 100644 --- a/src/meshlink.h +++ b/src/meshlink.h @@ -1551,6 +1551,17 @@ extern void meshlink_set_dev_class_timeouts(struct meshlink_handle *mesh, dev_cl */ extern void meshlink_set_dev_class_fast_retry_period(struct meshlink_handle *mesh, dev_class_t devclass, int fast_retry_period); +/// Set which order invitations are committed +/** This determines in which order configuration files are written to disk during an invitation. + * By default, the invitee saves the configuration to disk first, then the inviter. + * By calling this function with @a inviter_commits_first set to true, the order is reversed. + * + * \memberof meshlink_handle + * @param mesh A handle which represents an instance of MeshLink. + * @param inviter_commits_first If true, then the node that invited a peer will commit data to disk first. + */ +extern void meshlink_set_inviter_commits_first(struct meshlink_handle *mesh, bool inviter_commits_first); + #ifdef __cplusplus } #endif diff --git a/src/meshlink.sym b/src/meshlink.sym index 9c3d9065..4a89b5ea 100644 --- a/src/meshlink.sym +++ b/src/meshlink.sym @@ -70,6 +70,7 @@ meshlink_set_dev_class_fast_retry_period meshlink_set_dev_class_timeouts meshlink_set_error_cb meshlink_set_invitation_timeout +meshlink_set_inviter_commits_first meshlink_set_log_cb meshlink_set_node_channel_timeout meshlink_set_node_duplicate_cb diff --git a/src/meshlink_internal.h b/src/meshlink_internal.h index 8104ba60..f895e02f 100644 --- a/src/meshlink_internal.h +++ b/src/meshlink_internal.h @@ -168,7 +168,7 @@ struct meshlink_handle { bool default_blacklist; bool discovery; // Whether Catta is enabled or not - + bool inviter_commits_first; // Configuration char *confbase; diff --git a/src/protocol_auth.c b/src/protocol_auth.c index 6517d9ce..1ece41ce 100644 --- a/src/protocol_auth.c +++ b/src/protocol_auth.c @@ -152,12 +152,7 @@ bool send_id(meshlink_handle_t *mesh, connection_t *c) { return send_request(mesh, c, NULL, "%d %s %d.%d %s", ID, mesh->self->name, PROT_MAJOR, PROT_MINOR, mesh->appname); } -static bool finalize_invitation(meshlink_handle_t *mesh, connection_t *c, const void *data, uint16_t len) { - if(len != 32) { - logger(mesh, MESHLINK_ERROR, "Received invalid key from invited node %s!\n", c->name); - return false; - } - +static bool commit_invitation(meshlink_handle_t *mesh, connection_t *c, const void *data) { // Create a new node node_t *n = new_node(); n->name = xstrdup(c->name); @@ -186,22 +181,7 @@ static bool finalize_invitation(meshlink_handle_t *mesh, connection_t *c, const return true; } -static bool receive_invitation_sptps(void *handle, uint8_t type, const void *data, uint16_t len) { - connection_t *c = handle; - meshlink_handle_t *mesh = c->mesh; - - if(type == 128) { - return true; - } - - if(type == 1 && c->status.invitation_used) { - return finalize_invitation(mesh, c, data, len); - } - - if(type != 0 || len != 18 || c->status.invitation_used) { - return false; - } - +static bool process_invitation(meshlink_handle_t *mesh, connection_t *c, const void *data) { // Recover the filename from the cookie and the key char *fingerprint = ecdsa_get_base64_public_key(mesh->invitation_key); char hash[64]; @@ -248,6 +228,10 @@ static bool receive_invitation_sptps(void *handle, uint8_t type, const void *dat } } + if(mesh->inviter_commits_first && !commit_invitation(mesh, c, (const char *)data + 18)) { + return false; + } + // Send the node the contents of the invitation file sptps_send_record(&c->sptps, 0, config.buf, config.len); @@ -259,6 +243,30 @@ static bool receive_invitation_sptps(void *handle, uint8_t type, const void *dat return true; } +static bool receive_invitation_sptps(void *handle, uint8_t type, const void *data, uint16_t len) { + connection_t *c = handle; + meshlink_handle_t *mesh = c->mesh; + + if(type == SPTPS_HANDSHAKE) { + // The peer should send its cookie first. + return true; + } + + if(mesh->inviter_commits_first) { + if(type == 2 && len == 18 + 32 && !c->status.invitation_used) { + return process_invitation(mesh, c, data); + } + } else { + if(type == 0 && len == 18 && !c->status.invitation_used) { + return process_invitation(mesh, c, data); + } else if(type == 1 && len == 32 && c->status.invitation_used) { + return commit_invitation(mesh, c, data); + } + } + + return false; +} + bool id_h(meshlink_handle_t *mesh, connection_t *c, const char *request) { assert(request); assert(*request); -- 2.39.2