]> git.meshlink.io Git - meshlink/blob - test/blacklist.c
5fa0f98deebd442c825eb384e3dbe7a14a53de7f
[meshlink] / test / blacklist.c
1 #define _GNU_SOURCE
2
3 #ifdef NDEBUG
4 #undef NDEBUG
5 #endif
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <errno.h>
12 #include <assert.h>
13 #include <sys/time.h>
14 #include <dirent.h>
15
16 #include "meshlink.h"
17 #include "devtools.h"
18 #include "utils.h"
19
20 static struct sync_flag bar_connected;
21 static struct sync_flag bar_disconnected;
22 static struct sync_flag bar_blacklisted;
23 static struct sync_flag baz_connected;
24
25 static void foo_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable) {
26         (void)mesh;
27         (void)reachable;
28
29         if(!strcmp(node->name, "bar")) {
30                 if(reachable) {
31                         set_sync_flag(&bar_connected, true);
32                 } else {
33                         set_sync_flag(&bar_disconnected, true);
34                 }
35         }
36 }
37
38 static void baz_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable) {
39         (void)mesh;
40         (void)reachable;
41
42         if(!strcmp(node->name, "bar")) {
43                 if(reachable) {
44                         set_sync_flag(&baz_connected, true);
45                 }
46         }
47 }
48
49 static void bar_blacklisted_cb(meshlink_handle_t *mesh, meshlink_node_t *node) {
50         (void)mesh;
51
52         if(!strcmp(node->name, "foo")) {
53                 set_sync_flag(&bar_blacklisted, true);
54         }
55 }
56
57 int main(void) {
58         init_sync_flag(&bar_connected);
59         init_sync_flag(&bar_disconnected);
60         init_sync_flag(&baz_connected);
61
62         meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_cb);
63
64         // Create three instances.
65
66         const char *name[3] = {"foo", "bar", "baz"};
67         meshlink_handle_t *mesh[3];
68         char *data[3];
69
70         for(int i = 0; i < 3; i++) {
71                 char *path = NULL;
72                 assert(asprintf(&path, "blacklist_conf.%d", i) != -1 && path);
73
74                 assert(meshlink_destroy(path));
75                 mesh[i] = meshlink_open(path, name[i], "blacklist", DEV_CLASS_BACKBONE);
76                 assert(mesh[i]);
77                 free(path);
78
79                 assert(meshlink_set_canonical_address(mesh[i], meshlink_get_self(mesh[i]), "localhost", NULL));
80
81                 data[i] = meshlink_export(mesh[i]);
82                 assert(data[i]);
83
84                 // Enable default blacklist on all nodes.
85                 meshlink_set_default_blacklist(mesh[i], true);
86         }
87
88         // The first node knows the two other nodes.
89
90         for(int i = 1; i < 3; i++) {
91                 assert(meshlink_import(mesh[i], data[0]));
92                 assert(meshlink_import(mesh[0], data[i]));
93
94                 assert(meshlink_get_node(mesh[i], name[0]));
95                 assert(meshlink_get_node(mesh[0], name[i]));
96
97         }
98
99         for(int i = 0; i < 3; i++) {
100                 free(data[i]);
101         }
102
103         // Second and third node should not know each other yet.
104
105         assert(!meshlink_get_node(mesh[1], name[2]));
106         assert(!meshlink_get_node(mesh[2], name[1]));
107
108         // Check default blacklist status
109
110         assert(!meshlink_get_node_blacklisted(mesh[0], meshlink_get_self(mesh[0])));
111         assert(!meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], name[1])));
112         assert(meshlink_get_node_blacklisted(mesh[1], meshlink_get_node(mesh[1], name[2])));
113         assert(meshlink_get_node_blacklisted(mesh[2], meshlink_get_node(mesh[2], name[1])));
114
115         // Generate an invitation for a node that is about to be blacklisted
116
117         char *invitation = meshlink_invite(mesh[0], NULL, "xyzzy");
118         assert(invitation);
119         free(invitation);
120
121         // Whitelisting and blacklisting by name should work.
122
123         assert(meshlink_whitelist_by_name(mesh[0], "quux"));
124         assert(meshlink_blacklist_by_name(mesh[0], "xyzzy"));
125         assert(meshlink_get_node(mesh[0], "quux"));
126         assert(!meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], "quux")));
127         assert(meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], "xyzzy")));
128
129         meshlink_node_t **nodes = NULL;
130         size_t nnodes = 0;
131         nodes = meshlink_get_all_nodes_by_blacklisted(mesh[0], true, nodes, &nnodes);
132         assert(nnodes == 1);
133         assert(!strcmp(nodes[0]->name, "xyzzy"));
134
135         nodes = meshlink_get_all_nodes_by_blacklisted(mesh[0], false, nodes, &nnodes);
136         assert(nnodes == 4);
137         assert(!strcmp(nodes[0]->name, "bar"));
138         assert(!strcmp(nodes[1]->name, "baz"));
139         assert(!strcmp(nodes[2]->name, "foo"));
140         assert(!strcmp(nodes[3]->name, "quux"));
141
142         free(nodes);
143
144         // Check that blacklisted nodes are not allowed to be invited, and no invitations are left on disk.
145
146         assert(!meshlink_invite(mesh[0], NULL, "xyzzy"));
147
148         DIR *dir = opendir("blacklist_conf.0/current/invitations");
149         assert(dir);
150         struct dirent *ent;
151
152         while((ent = readdir(dir))) {
153                 assert(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."));
154         }
155
156         closedir(dir);
157
158         // Since these nodes now exist we should be able to forget them.
159
160         assert(meshlink_forget_node(mesh[0], meshlink_get_node(mesh[0], "quux")));
161         assert(meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], "quux"))); // default blacklisted again
162
163         // Start the nodes.
164
165         meshlink_set_node_status_cb(mesh[0], foo_status_cb);
166         meshlink_set_node_status_cb(mesh[2], baz_status_cb);
167
168         for(int i = 0; i < 3; i++) {
169                 assert(meshlink_start(mesh[i]));
170         }
171
172         // Wait for them to connect.
173
174         assert(wait_sync_flag(&bar_connected, 5));
175
176         // Blacklist bar
177
178         meshlink_set_blacklisted_cb(mesh[1], bar_blacklisted_cb);
179
180         set_sync_flag(&bar_disconnected, false);
181         assert(meshlink_blacklist(mesh[0], meshlink_get_node(mesh[0], name[1])));
182         assert(wait_sync_flag(&bar_disconnected, 5));
183         assert(meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], name[1])));
184
185         assert(wait_sync_flag(&bar_blacklisted, 10));
186
187         // Whitelist bar
188
189         set_sync_flag(&bar_connected, false);
190         assert(meshlink_whitelist(mesh[0], meshlink_get_node(mesh[0], name[1])));
191         assert(wait_sync_flag(&bar_connected, 15));
192         assert(!meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], name[1])));
193
194         // Bar should not connect to baz
195
196         assert(wait_sync_flag(&baz_connected, 5) == false);
197
198         // But it should know about baz by now
199
200         meshlink_node_t *bar = meshlink_get_node(mesh[2], "bar");
201         meshlink_node_t *baz = meshlink_get_node(mesh[1], "baz");
202         assert(bar);
203         assert(baz);
204
205         // Have bar and baz whitelist each other
206
207         assert(meshlink_whitelist(mesh[1], baz));
208         assert(meshlink_whitelist(mesh[2], bar));
209         assert(!meshlink_get_node_blacklisted(mesh[1], baz));
210         assert(!meshlink_get_node_blacklisted(mesh[2], bar));
211
212         // They should connect to each other
213
214         assert(wait_sync_flag(&baz_connected, 15));
215
216         // Trying to forget an active node should fail.
217
218         assert(!meshlink_forget_node(mesh[1], baz));
219
220         // We need to re-acquire the handle to baz
221
222         baz = meshlink_get_node(mesh[1], "baz");
223         assert(baz);
224
225         // Stop the mesh.
226
227         for(int i = 0; i < 3; i++) {
228                 meshlink_stop(mesh[i]);
229         }
230
231         // Forgetting a node should work now.
232
233         assert(meshlink_forget_node(mesh[1], baz));
234
235         // Clean up.
236
237         for(int i = 0; i < 3; i++) {
238                 meshlink_close(mesh[i]);
239         }
240
241         // Check that foo has a config file for xyzzy but not quux
242         assert(access("blacklist_conf.0/current/hosts/xyzzy", F_OK) == 0);
243         assert(access("blacklist_conf.0/current/hosts/quux", F_OK) != 0 && errno == ENOENT);
244
245         // Check that bar has no config file for baz
246         assert(access("blacklist_conf.2/current/hosts/bar", F_OK) == 0);
247         assert(access("blacklist_conf.1/current/hosts/baz", F_OK) != 0 && errno == ENOENT);
248
249         // Check that we remember xyzzy but not quux after reopening the mesh
250         mesh[0] = meshlink_open("blacklist_conf.0", "foo", "blacklist", DEV_CLASS_BACKBONE);
251         assert(mesh[0]);
252         assert(meshlink_get_node(mesh[0], "xyzzy"));
253         assert(!meshlink_get_node(mesh[0], "quux"));
254
255         meshlink_close(mesh[0]);
256 }