]> git.meshlink.io Git - meshlink/commitdiff
Add API functions to query the blacklist status of nodes.
authorGuus Sliepen <guus@meshlink.io>
Sun, 25 Oct 2020 21:18:53 +0000 (22:18 +0100)
committerGuus Sliepen <guus@meshlink.io>
Sun, 25 Oct 2020 21:18:53 +0000 (22:18 +0100)
src/meshlink++.h
src/meshlink.c
src/meshlink.h
src/meshlink.sym
test/blacklist.c

index 183544ac99f3c4ebf3819b243457f2044542c06e..c155086558ee4d77b25f95d2920b9133431a157a 100644 (file)
@@ -431,6 +431,17 @@ public:
                return meshlink_get_node_reachability(handle, node, last_reachable, last_unreachable);
        }
 
+       /// Get a node's blacklist status.
+       /** This function returns the current blacklist status of a given node.
+        *
+        *  @param node              A pointer to a meshlink::node describing the node.
+        *
+        *  @return                  This function returns true if the node is currently blacklisted, false otherwise.
+        */
+       bool get_node_blacklisted(node *node) {
+               return meshlink_get_node_blacklisted(handle, node);
+       }
+
        /// Get a handle for a specific submesh.
        /** This function returns a handle for the submesh with the given name.
         *
@@ -465,6 +476,21 @@ public:
                return (node **)meshlink_get_all_nodes(handle, (meshlink_node_t **)nodes, nmemb);
        }
 
+       /// Get a list of all nodes by blacklist status.
+       /** This function returns a list with handles for all the nodes who were either blacklisted or whitelisted.
+        *
+        *  @param nodes        A pointer to an array of pointers to meshlink::node, which should be allocated by the application.
+        *  @param nmemb        The maximum number of pointers that can be stored in the nodes array.
+        *
+        *  @return             A pointer to an array containing pointers to all known nodes with the given blacklist status.
+        *                      If the @a nodes argument was not NULL, then the return value can either be the same value or a different value.
+        *                      If it is a new value, the old value of @a nodes should not be used anymore.
+        *                      If the new value is NULL, then the old array will have been freed by MeshLink.
+        */
+       node **get_all_nodes_by_blacklisted(bool blacklisted, node **nodes, size_t *nmemb) {
+               return (node **)meshlink_get_all_nodes_by_blacklisted(handle, blacklisted, (meshlink_node_t **)nodes, nmemb);
+       }
+
        /// Sign data using the local node's MeshLink key.
        /** This function signs data using the local node's MeshLink key.
         *  The generated signature can be securely verified by other nodes.
index 3f191f9a6579547bf9c0c79a4573e84e5a2892da..4f9c5f407ba93b6680faa8aef5c8c3d6c0a10ede 100644 (file)
@@ -2360,6 +2360,10 @@ static bool search_node_by_dev_class(const node_t *node, const void *condition)
        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;
@@ -2422,6 +2426,15 @@ meshlink_node_t **meshlink_get_all_nodes_by_last_reachable(meshlink_handle_t *me
        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;
@@ -2441,6 +2454,28 @@ dev_class_t meshlink_get_node_dev_class(meshlink_handle_t *mesh, meshlink_node_t
        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;
index 738f8647e5071d3ca815558d942229447fbc3884..5f11607bb161928ede2fbae09d610f3bd5833587 100644 (file)
@@ -739,17 +739,49 @@ struct meshlink_node **meshlink_get_all_nodes_by_submesh(struct meshlink_handle
  */
 struct meshlink_node **meshlink_get_all_nodes_by_last_reachable(struct meshlink_handle *mesh, time_t start, time_t end, struct meshlink_node **nodes, size_t *nmemb) __attribute__((__warn_unused_result__));
 
+/// Get the list of all nodes by blacklist status.
+/** This function returns a list with handles for all the nodes who were either blacklisted or whitelisted.
+ *
+ *  \memberof meshlink_handle
+ *  @param mesh         A handle which represents an instance of MeshLink.
+ *  @param blacklisted  If true, a list of blacklisted nodes will be returned, otherwise whitelisted nodes.
+ *  @param nodes        A pointer to a previously allocated array of pointers to struct meshlink_node, or NULL in which case MeshLink will allocate a new array.
+ *                      The application can supply an array it allocated itself with malloc, or the return value from the previous call to this function (which is the preferred way).
+ *                      The application is allowed to call free() on the array whenever it wishes.
+ *                      The pointers in the array are valid until meshlink_close() is called.
+ *  @param nmemb        A pointer to a variable holding the number of nodes that were reachable within the period given by @a start and @a end.
+ *                      In case the @a nodes argument is not NULL, MeshLink might call realloc() on the array to change its size.
+ *                      The contents of this variable will be changed to reflect the new size of the array.
+ *
+ *  @return             A pointer to an array containing pointers to all known nodes with the given blacklist status.
+ *                      If the @a nodes argument was not NULL, then the return value can either be the same value or a different value.
+ *                      If it is a new value, the old value of @a nodes should not be used anymore.
+ *                      If the new value is NULL, then the old array will have been freed by MeshLink.
+ */
+struct meshlink_node **meshlink_get_all_nodes_by_blacklisted(struct meshlink_handle *mesh, bool blacklisted, struct meshlink_node **nodes, size_t *nmemb) __attribute__((__warn_unused_result__));
+
 /// Get the node's device class.
 /** This function returns the device class of the given node.
  *
  *  \memberof meshlink_node
  *  @param mesh          A handle which represents an instance of MeshLink.
- *  @param node         A pointer to a struct meshlink_node describing the node.
+ *  @param node          A pointer to a struct meshlink_node describing the node.
  *
  *  @return              This function returns the device class of the @a node, or -1 in case of an error.
  */
 dev_class_t meshlink_get_node_dev_class(struct meshlink_handle *mesh, struct meshlink_node *node) __attribute__((__warn_unused_result__));
 
+/// Get the node's blacklist status.
+/** This function returns the given node is blacklisted.
+ *
+ *  \memberof meshlink_node
+ *  @param mesh          A handle which represents an instance of MeshLink.
+ *  @param node          A pointer to a struct meshlink_node describing the node.
+ *
+ *  @return              This function returns true if the node is blacklisted, false otherwise.
+ */
+bool meshlink_get_node_blacklisted(struct meshlink_handle *mesh, struct meshlink_node *node) __attribute__((__warn_unused_result__));
+
 /// Get the node's submesh handle.
 /** This function returns the submesh handle of the given node.
  *
index 08dff729daaa687904dd9a6538796d9c0185d2f4..649eba1d50a008cfb6dce1fc5e456a79a5502fdf 100644 (file)
@@ -36,6 +36,7 @@ meshlink_errno
 meshlink_export
 meshlink_forget_node
 meshlink_get_all_nodes
+meshlink_get_all_nodes_by_blacklisted
 meshlink_get_all_nodes_by_dev_class
 meshlink_get_all_nodes_by_last_reachable
 meshlink_get_all_nodes_by_submesh
@@ -44,6 +45,7 @@ meshlink_get_external_address_for_family
 meshlink_get_fingerprint
 meshlink_get_local_address_for_family
 meshlink_get_node
+meshlink_get_node_blacklisted
 meshlink_get_node_dev_class
 meshlink_get_node_reachability
 meshlink_get_node_submesh
index 1f5cd605e936fafb9d7c076c68c6de8d34f72f89..585c1526cc123c5c23b067ca4d8b3b733e61c429 100644 (file)
@@ -11,6 +11,7 @@
 #include <errno.h>
 #include <assert.h>
 #include <sys/time.h>
+#include <dirent.h>
 
 #include "meshlink.h"
 #include "devtools.h"
@@ -95,14 +96,60 @@ int main(void) {
        assert(!meshlink_get_node(mesh[1], name[2]));
        assert(!meshlink_get_node(mesh[2], name[1]));
 
+       // Check default blacklist status
+
+       assert(!meshlink_get_node_blacklisted(mesh[0], meshlink_get_self(mesh[0])));
+       assert(!meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], name[1])));
+       assert(meshlink_get_node_blacklisted(mesh[1], meshlink_get_node(mesh[1], name[2])));
+       assert(meshlink_get_node_blacklisted(mesh[2], meshlink_get_node(mesh[2], name[1])));
+
+       // Generate an invitation for a node that is about to be blacklisted
+
+       char *invitation = meshlink_invite(mesh[0], NULL, "xyzzy");
+       assert(invitation);
+       free(invitation);
+
        // Whitelisting and blacklisting by name should work.
 
        assert(meshlink_whitelist_by_name(mesh[0], "quux"));
        assert(meshlink_blacklist_by_name(mesh[0], "xyzzy"));
+       assert(meshlink_get_node(mesh[0], "quux"));
+       assert(!meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], "quux")));
+       assert(meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], "xyzzy")));
+
+       meshlink_node_t **nodes = NULL;
+       size_t nnodes = 0;
+       nodes = meshlink_get_all_nodes_by_blacklisted(mesh[0], true, nodes, &nnodes);
+       assert(nnodes == 1);
+       assert(!strcmp(nodes[0]->name, "xyzzy"));
+
+       nodes = meshlink_get_all_nodes_by_blacklisted(mesh[0], false, nodes, &nnodes);
+       assert(nnodes == 4);
+       assert(!strcmp(nodes[0]->name, "bar"));
+       assert(!strcmp(nodes[1]->name, "baz"));
+       assert(!strcmp(nodes[2]->name, "foo"));
+       assert(!strcmp(nodes[3]->name, "quux"));
+
+       free(nodes);
+
+       // Check that blacklisted nodes are not allowed to be invited, and no invitations are left on disk.
+
+       assert(!meshlink_invite(mesh[0], NULL, "xyzzy"));
+
+       DIR *dir = opendir("blacklist_conf.0/current/invitations");
+       assert(dir);
+       struct dirent *ent;
+
+       while((ent = readdir(dir))) {
+               assert(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."));
+       }
+
+       closedir(dir);
 
        // Since these nodes now exist we should be able to forget them.
 
        assert(meshlink_forget_node(mesh[0], meshlink_get_node(mesh[0], "quux")));
+       assert(meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], "quux"))); // default blacklisted again
 
        // Start the nodes.
 
@@ -122,12 +169,14 @@ int main(void) {
        set_sync_flag(&bar_disconnected, false);
        assert(meshlink_blacklist(mesh[0], meshlink_get_node(mesh[0], name[1])));
        assert(wait_sync_flag(&bar_disconnected, 5));
+       assert(meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], name[1])));
 
        // Whitelist bar
 
        set_sync_flag(&bar_connected, false);
        assert(meshlink_whitelist(mesh[0], meshlink_get_node(mesh[0], name[1])));
        assert(wait_sync_flag(&bar_connected, 15));
+       assert(!meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], name[1])));
 
        // Bar should not connect to baz
 
@@ -144,6 +193,8 @@ int main(void) {
 
        assert(meshlink_whitelist(mesh[1], baz));
        assert(meshlink_whitelist(mesh[2], bar));
+       assert(!meshlink_get_node_blacklisted(mesh[1], baz));
+       assert(!meshlink_get_node_blacklisted(mesh[2], bar));
 
        // They should connect to each other