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