1 //
2 // Copyright 2021 Staysail Systems, Inc. <info@staysail.tech>
3 // Copyright 2018 Capitar IT Group BV <info@capitar.com>
4 //
5 // This software is supplied under the terms of the MIT License, a
6 // copy of which should be located in the distribution where this
7 // file was obtained (LICENSE.txt).  A copy of the license may also be
8 // found online at https://opensource.org/licenses/MIT.
9 //
10 
11 #include <nng/nng.h>
12 #include <nng/protocol/pair0/pair.h>
13 #include <nng/transport/zerotier/zerotier.h>
14 
15 #include "convey.h"
16 #include "trantest.h"
17 #include "stubs.h"
18 
19 // zerotier tests.
20 
21 // This network is an open network setup exclusively for nng testing.
22 // Do not attach to it in production.
23 #define NWID "a09acf02337b057b"
24 #define NWID_NUM 0xa09acf02337b057bull
25 
26 // This network is a closed network, which nothing can join.  We use it for
27 // testing permission denied.
28 #define CLOSED_NWID "17d709436ce162a3"
29 
30 #ifdef _WIN32
31 
32 int
mkdir(const char * path,int mode)33 mkdir(const char *path, int mode)
34 {
35 	CreateDirectory(path, NULL);
36 	return (0);
37 }
38 #else
39 #include <sys/stat.h>
40 #include <unistd.h>
41 #endif // WIN32
42 
43 static int
check_props(nng_msg * msg)44 check_props(nng_msg *msg)
45 {
46 	nng_pipe p;
47 	p = nng_msg_get_pipe(msg);
48 	So(nng_pipe_id(p) > 0);
49 
50 	// Check local address.
51 	Convey("Local address property works", {
52 		nng_sockaddr la;
53 		So(nng_pipe_getopt_sockaddr(p, NNG_OPT_LOCADDR, &la) == 0);
54 
55 		So(la.s_family == NNG_AF_ZT);
56 		So(la.s_zt.sa_port == (trantest_port - 1));
57 		So(la.s_zt.sa_nwid == NWID_NUM);
58 		So(la.s_zt.sa_nodeid != 0);
59 	});
60 
61 	Convey("Remote address property works", {
62 		// Check remote address.
63 		uint64_t     mynode;
64 		nng_sockaddr ra;
65 
66 		So(nng_pipe_getopt_sockaddr(p, NNG_OPT_REMADDR, &ra) == 0);
67 		So(ra.s_family == NNG_AF_ZT);
68 		So(ra.s_zt.sa_port != 0);
69 		So(ra.s_zt.sa_nwid == NWID_NUM);
70 
71 		So(nng_pipe_getopt_uint64(p, NNG_OPT_ZT_NODE, &mynode) == 0);
72 		So(mynode != 0);
73 		So(ra.s_zt.sa_nodeid == mynode);
74 	});
75 
76 	Convey("NWID property works", {
77 		uint64_t nwid = 0;
78 
79 		So(nng_pipe_getopt_uint64(p, NNG_OPT_ZT_NWID, &nwid) == 0);
80 		So(nwid = 0xa09acf02337b057bull);
81 	});
82 
83 	Convey("Network status property works", {
84 		int s = 0;
85 
86 		So(nng_pipe_getopt_int(p, NNG_OPT_ZT_NETWORK_STATUS, &s) == 0);
87 		So(s == NNG_ZT_STATUS_UP);
88 	});
89 
90 	Convey("Ping properties work", {
91 		int          c = 0;
92 		nng_duration t = 0;
93 
94 		So(nng_pipe_getopt_int(p, NNG_OPT_ZT_PING_TRIES, &c) == 0);
95 		So(c > 0 && c <= 10);
96 
97 		So(nng_pipe_getopt_ms(p, NNG_OPT_ZT_PING_TIME, &t) == 0);
98 		So(t > 1000 && t < 3600000); // 1 sec - 1 hour
99 	});
100 
101 	Convey("Home property works", {
102 		char *v;
103 		So(nng_pipe_getopt_string(p, NNG_OPT_ZT_HOME, &v) == 0);
104 		nng_strfree(v);
105 	});
106 
107 	Convey("MTU property works", {
108 		size_t mtu;
109 
110 		// Check MTU
111 		So(nng_pipe_getopt_size(p, NNG_OPT_ZT_MTU, &mtu) == 0);
112 		So(mtu >= 1000 && mtu <= 10000);
113 	});
114 
115 	Convey("Network name property works", {
116 		char *name;
117 
118 		So(nng_pipe_getopt_string(p, NNG_OPT_ZT_NETWORK_NAME, &name) ==
119 		    0);
120 		So(strcmp(name, "nng_test_open") == 0);
121 		nng_strfree(name);
122 	});
123 
124 	return (0);
125 }
126 
127 TestMain("ZeroTier Transport", {
128 	char     path1[NNG_MAXADDRLEN] = "/tmp/zt_server";
129 	char     path2[NNG_MAXADDRLEN] = "/tmp/zt_client";
130 	unsigned port;
131 
132 	port = 5555;
133 
134 	Convey("We can register the zero tier transport",
135 	    { So(nng_zt_register() == 0); });
136 
137 	Convey("We can create a zt listener", {
138 		nng_listener l;
139 		nng_socket   s;
140 		char         addr[NNG_MAXADDRLEN];
141 
142 		So(nng_zt_register() == 0);
143 
144 		snprintf(addr, sizeof(addr), "zt://*." NWID ":%u", port);
145 
146 		So(nng_pair_open(&s) == 0);
147 		Reset({ nng_close(s); });
148 
149 		So(nng_listener_create(&l, s, addr) == 0);
150 
151 		Convey("And it can be started...", {
152 			mkdir(path1, 0700);
153 
154 			So(nng_listener_setopt(l, NNG_OPT_ZT_HOME, path1,
155 			       strlen(path1) + 1) == 0);
156 
157 			So(nng_listener_start(l, 0) == 0);
158 
159 			Convey("It has the right local address", {
160 				nng_sockaddr sa;
161 				So(nng_listener_getopt_sockaddr(
162 				       l, NNG_OPT_LOCADDR, &sa) == 0);
163 				So(sa.s_zt.sa_family == NNG_AF_ZT);
164 				So(sa.s_zt.sa_nwid == NWID_NUM);
165 				So(sa.s_zt.sa_port == port);
166 				So(sa.s_zt.sa_nodeid != 0);
167 			});
168 			Convey("And we can orbit a moon", {
169 				uint64_t ids[2];
170 				// Provided by Janjaap...
171 				ids[0] = 0x622514484aull;
172 				ids[1] = 0x622514484aull;
173 
174 				So(nng_listener_setopt(l, NNG_OPT_ZT_ORBIT,
175 				       ids, sizeof(ids)) == 0);
176 			});
177 			Convey("And we can deorbit anything", {
178 				uint64_t id;
179 				id = 0x12345678;
180 				So(nng_listener_setopt(l, NNG_OPT_ZT_DEORBIT,
181 				       &id, sizeof(id)) == 0);
182 			});
183 		});
184 	});
185 
186 	Convey("We can create a zt dialer", {
187 		nng_dialer d;
188 		nng_socket s;
189 		char       addr[NNG_MAXADDRLEN];
190 		// uint64_t   node = 0xb000072fa6ull; // my personal host
191 		uint64_t node = 0x2d2f619cccull; // my personal host
192 
193 		So(nng_zt_register() == 0);
194 
195 		snprintf(addr, sizeof(addr), "zt://%llx." NWID ":%u",
196 		    (unsigned long long) node, port);
197 
198 		So(nng_pair_open(&s) == 0);
199 		Reset({ nng_close(s); });
200 
201 		So(nng_dialer_create(&d, s, addr) == 0);
202 	});
203 
204 	Convey("We can create an ephemeral listener", {
205 		nng_dialer   d;
206 		nng_listener l;
207 		nng_socket   s;
208 		char         addr[NNG_MAXADDRLEN];
209 		uint64_t     node1 = 0;
210 		uint64_t     node2 = 0;
211 
212 		So(nng_zt_register() == 0);
213 
214 		snprintf(addr, sizeof(addr), "zt://*." NWID ":%u", port);
215 
216 		So(nng_pair_open(&s) == 0);
217 		Reset({ nng_close(s); });
218 
219 		So(nng_listener_create(&l, s, addr) == 0);
220 
221 		So(nng_listener_getopt_uint64(l, NNG_OPT_ZT_NODE, &node1) ==
222 		    0);
223 		So(node1 != 0);
224 
225 		Convey("Connection refused works", {
226 			snprintf(addr, sizeof(addr), "zt://%llx." NWID ":%u",
227 			    (unsigned long long) node1, 42u);
228 			So(nng_dialer_create(&d, s, addr) == 0);
229 			So(nng_dialer_getopt_uint64(
230 			       d, NNG_OPT_ZT_NODE, &node2) == 0);
231 			So(node2 == node1);
232 			So(nng_dialer_start(d, 0) == NNG_ECONNREFUSED);
233 		});
234 	});
235 
236 	Convey("We can create a zt pair (dialer & listener)", {
237 		nng_dialer   d;
238 		nng_listener l;
239 		nng_socket   s1;
240 		nng_socket   s2;
241 		char         addr1[NNG_MAXADDRLEN];
242 		char         addr2[NNG_MAXADDRLEN];
243 		uint64_t     node;
244 
245 		port = 9944;
246 		So(nng_zt_register() == 0);
247 
248 		snprintf(addr1, sizeof(addr1), "zt://*." NWID ":%u", port);
249 
250 		So(nng_pair_open(&s1) == 0);
251 		So(nng_pair_open(&s2) == 0);
252 		Reset({
253 			nng_close(s1);
254 			// This sleep ensures disconnect messages work.
255 			nng_msleep(500);
256 			nng_close(s2);
257 		});
258 
259 		So(nng_listener_create(&l, s1, addr1) == 0);
260 		So(nng_listener_setopt(
261 		       l, NNG_OPT_ZT_HOME, path1, strlen(path1) + 1) == 0);
262 
263 		So(nng_listener_start(l, 0) == 0);
264 		node = 0;
265 		So(nng_listener_getopt_uint64(l, NNG_OPT_ZT_NODE, &node) == 0);
266 		So(node != 0);
267 		nng_msleep(40);
268 		snprintf(addr2, sizeof(addr2), "zt://%llx." NWID ":%u",
269 		    (unsigned long long) node, port);
270 		So(nng_dialer_create(&d, s2, addr2) == 0);
271 		mkdir(path2, 0700);
272 		So(nng_dialer_setopt(
273 		       d, NNG_OPT_ZT_HOME, path2, strlen(path2) + 1) == 0);
274 		So(nng_dialer_start(d, 0) == 0);
275 		nng_msleep(2000); // to give dialer time to start up
276 	});
277 
278 	// We need to determine our ephemeral ID:
279 
280 	nng_socket   s_test;
281 	nng_listener l_test;
282 	uint64_t     node;
283 	char         fmt[128];
284 
285 	So(nng_pair_open(&s_test) == 0);
286 	So(nng_listener_create(&l_test, s_test, "zt://*." NWID ":0") == 0);
287 	So(nng_listener_start(l_test, 0) == 0);
288 	So(nng_listener_getopt_uint64(l_test, NNG_OPT_ZT_NODE, &node) == 0);
289 	snprintf(fmt, sizeof(fmt), "zt://%llx." NWID ":%%u",
290 	    (unsigned long long) node);
291 	nng_listener_close(l_test);
292 
293 	trantest_test_extended(fmt, check_props);
294 })
295