From: Guus Sliepen Date: Tue, 26 Jun 2018 14:42:57 +0000 (+0200) Subject: Add meshlink_set_invitation_timeout(). X-Git-Url: https://git.meshlink.io/?a=commitdiff_plain;h=34a52e6e69be085ee99755c2890268d2ce11f9b4;p=meshlink Add meshlink_set_invitation_timeout(). This sets a global timeout for invitation files. If a node tries to join with an invitation whose file is older than the timeout, the invitation is rejected. --- diff --git a/src/meshlink++.h b/src/meshlink++.h index 4cea8cfa..413534ea 100644 --- a/src/meshlink++.h +++ b/src/meshlink++.h @@ -474,6 +474,16 @@ public: return meshlink_set_port(handle, port); } + /// Set the timeout for invitations. + /** This function sets the timeout for invitations. + * The timeout is retroactively applied to all outstanding invitations. + * + * @param timeout The timeout for invitations in seconds. + */ + void set_invitation_timeout(int timeout) { + meshlink_set_invitation_timeout(handle, timeout); + } + /// 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 1c81ad22..52a4389a 100644 --- a/src/meshlink.c +++ b/src/meshlink.c @@ -1033,6 +1033,7 @@ meshlink_handle_t *meshlink_open(const char *confbase, const char *name, const c mesh->appname = xstrdup(appname); mesh->devclass = devclass; mesh->discovery = true; + mesh->invitation_timeout = 604800; // 1 week if(usingname) { mesh->name = xstrdup(name); @@ -1832,6 +1833,10 @@ done: return rval; } +void meshlink_set_invitation_timeout(meshlink_handle_t *mesh, int timeout) { + mesh->invitation_timeout = timeout; +} + char *meshlink_invite(meshlink_handle_t *mesh, const char *name) { if(!mesh) { meshlink_errno = MESHLINK_EINVAL; diff --git a/src/meshlink.h b/src/meshlink.h index 26d0dfce..a0cb1187 100644 --- a/src/meshlink.h +++ b/src/meshlink.h @@ -520,6 +520,16 @@ extern int meshlink_get_port(meshlink_handle_t *mesh); extern bool meshlink_set_port(meshlink_handle_t *mesh, int port); +/// Set the timeout for invitations. +/** This function sets the timeout for invitations. + * Note that timeouts are only checked at the time a node tries to join using an invitation. + * The default timeout for invitations is 1 week. + * + * @param mesh A handle which represents an instance of MeshLink. + * @param timeout The timeout for invitations in seconds. + */ +extern void meshlink_set_invitation_timeout(meshlink_handle_t *mesh, int timeout); + /// 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_internal.h b/src/meshlink_internal.h index d7d4910b..c6c99541 100644 --- a/src/meshlink_internal.h +++ b/src/meshlink_internal.h @@ -120,6 +120,7 @@ struct meshlink_handle { hash_t *node_udp_cache; struct connection_t *everyone; struct ecdsa *invitation_key; + int invitation_timeout; int pinginterval; /* seconds between pings */ int pingtimeout; /* seconds to wait for response */ diff --git a/src/protocol_auth.c b/src/protocol_auth.c index b11acaef..4ba3ebe4 100644 --- a/src/protocol_auth.c +++ b/src/protocol_auth.c @@ -239,6 +239,24 @@ static bool receive_invitation_sptps(void *handle, uint8_t type, const void *dat if(!f) { logger(mesh, MESHLINK_ERROR, "Error trying to open invitation %s\n", cookie); + unlink(usedname); + return false; + } + + // Check the timestamp + struct stat st; + + if(fstat(fileno(f), &st)) { + logger(mesh, MESHLINK_ERROR, "Could not stat invitation file %s\n", usedname); + fclose(f); + unlink(usedname); + return false; + } + + if(time(NULL) > st.st_mtime + mesh->invitation_timeout) { + logger(mesh, MESHLINK_ERROR, "Peer %s tried to use an outdated invitation file %s\n", c->name, usedname); + fclose(f); + unlink(usedname); return false; } diff --git a/test/invite-join.c b/test/invite-join.c index 90326a0d..03e16917 100644 --- a/test/invite-join.c +++ b/test/invite-join.c @@ -32,12 +32,20 @@ int main() { return 1; } + meshlink_handle_t *mesh3 = meshlink_open("invite_join_conf.3", "quux", "invite-join", DEV_CLASS_BACKBONE); + + if(!mesh3) { + fprintf(stderr, "Could not initialize configuration for quux\n"); + return 1; + } + // Disable local discovery. meshlink_enable_discovery(mesh1, false); meshlink_enable_discovery(mesh2, false); + meshlink_enable_discovery(mesh3, false); - // Start the first instance and have it generate an invitation. + // Start the first instance and have it generate invitations. meshlink_set_node_status_cb(mesh1, status_cb); @@ -47,21 +55,28 @@ int main() { } meshlink_add_address(mesh1, "localhost"); - char *url = meshlink_invite(mesh1, "baz"); + char *baz_url = meshlink_invite(mesh1, "baz"); - if(!url) { + if(!baz_url) { fprintf(stderr, "Foo could not generate an invitation for baz\n"); return 1; } + char *quux_url = meshlink_invite(mesh1, "quux"); + + if(!quux_url) { + fprintf(stderr, "Foo could not generate an invitation for quux\n"); + return 1; + } + // Have the second instance join the first. - if(!meshlink_join(mesh2, url)) { + if(!meshlink_join(mesh2, baz_url)) { fprintf(stderr, "Baz could not join foo's mesh\n"); return 1; } - free(url); + free(baz_url); if(!meshlink_start(mesh2)) { fprintf(stderr, "Baz could not start\n"); @@ -95,6 +110,17 @@ int main() { return 1; } + // Check that nodes cannot join with expired invitations + + meshlink_set_invitation_timeout(mesh1, 0); + + if(meshlink_join(mesh3, quux_url)) { + fprintf(stderr, "Quux could join foo's mesh using an outdated invitation\n"); + return 1; + } + + free(quux_url); + // Clean up. meshlink_stop(mesh2);