/work/toxcore/onion_client.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: GPL-3.0-or-later |
2 | | * Copyright © 2016-2018 The TokTok team. |
3 | | * Copyright © 2013 Tox project. |
4 | | */ |
5 | | |
6 | | /** |
7 | | * Implementation of the client part of docs/Prevent_Tracking.txt (The part that |
8 | | * uses the onion stuff to connect to the friend) |
9 | | */ |
10 | | #include "onion_client.h" |
11 | | |
12 | | #include <assert.h> |
13 | | #include <stdlib.h> |
14 | | #include <string.h> |
15 | | |
16 | | #include "DHT.h" |
17 | | #include "LAN_discovery.h" |
18 | | #include "TCP_connection.h" |
19 | | #include "ccompat.h" |
20 | | #include "crypto_core.h" |
21 | | #include "group_onion_announce.h" |
22 | | #include "logger.h" |
23 | | #include "mem.h" |
24 | | #include "mono_time.h" |
25 | | #include "net_crypto.h" |
26 | | #include "network.h" |
27 | | #include "onion.h" |
28 | | #include "onion_announce.h" |
29 | | #include "ping_array.h" |
30 | | #include "util.h" |
31 | | |
32 | | /** @brief defines for the array size and timeout for onion announce packets. */ |
33 | 3.80k | #define ANNOUNCE_ARRAY_SIZE 256 |
34 | 3.80k | #define ANNOUNCE_TIMEOUT 10 |
35 | | |
36 | | typedef struct Onion_Node { |
37 | | uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; |
38 | | IP_Port ip_port; |
39 | | uint8_t ping_id[ONION_PING_ID_SIZE]; |
40 | | uint8_t data_public_key[CRYPTO_PUBLIC_KEY_SIZE]; |
41 | | uint8_t is_stored; // Tribool. |
42 | | |
43 | | uint64_t added_time; |
44 | | |
45 | | uint64_t timestamp; |
46 | | |
47 | | uint64_t last_pinged; |
48 | | |
49 | | uint8_t pings_since_last_response; |
50 | | |
51 | | uint32_t path_used; |
52 | | } Onion_Node; |
53 | | |
54 | | typedef struct Onion_Client_Paths { |
55 | | Onion_Path paths[NUMBER_ONION_PATHS]; |
56 | | uint64_t last_path_success[NUMBER_ONION_PATHS]; |
57 | | uint64_t last_path_used[NUMBER_ONION_PATHS]; |
58 | | uint64_t path_creation_time[NUMBER_ONION_PATHS]; |
59 | | /* number of times used without success. */ |
60 | | unsigned int last_path_used_times[NUMBER_ONION_PATHS]; |
61 | | } Onion_Client_Paths; |
62 | | |
63 | | typedef struct Last_Pinged { |
64 | | uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; |
65 | | uint64_t timestamp; |
66 | | } Last_Pinged; |
67 | | |
68 | | struct Onion_Friend { |
69 | | bool is_valid; |
70 | | bool is_online; |
71 | | |
72 | | bool know_dht_public_key; |
73 | | uint8_t dht_public_key[CRYPTO_PUBLIC_KEY_SIZE]; |
74 | | uint8_t real_public_key[CRYPTO_PUBLIC_KEY_SIZE]; |
75 | | |
76 | | Onion_Node clients_list[MAX_ONION_CLIENTS]; |
77 | | uint8_t temp_public_key[CRYPTO_PUBLIC_KEY_SIZE]; |
78 | | uint8_t temp_secret_key[CRYPTO_SECRET_KEY_SIZE]; |
79 | | |
80 | | uint64_t last_dht_pk_onion_sent; |
81 | | uint64_t last_dht_pk_dht_sent; |
82 | | |
83 | | uint64_t last_noreplay; |
84 | | |
85 | | uint64_t last_populated; // the last time we had a fully populated client nodes list |
86 | | uint64_t time_last_pinged; // the last time we pinged this friend with any node |
87 | | |
88 | | uint32_t run_count; |
89 | | uint32_t pings; // how many sucessful pings we've made for this friend |
90 | | |
91 | | Last_Pinged last_pinged[MAX_STORED_PINGED_NODES]; |
92 | | uint8_t last_pinged_index; |
93 | | |
94 | | recv_tcp_relay_cb *tcp_relay_node_callback; |
95 | | void *tcp_relay_node_callback_object; |
96 | | uint32_t tcp_relay_node_callback_number; |
97 | | |
98 | | onion_dht_pk_cb *dht_pk_callback; |
99 | | void *dht_pk_callback_object; |
100 | | uint32_t dht_pk_callback_number; |
101 | | |
102 | | uint8_t gc_data[GCA_MAX_DATA_LENGTH]; |
103 | | uint8_t gc_public_key[ENC_PUBLIC_KEY_SIZE]; |
104 | | uint16_t gc_data_length; |
105 | | bool is_groupchat; |
106 | | }; |
107 | | |
108 | | static const Onion_Friend empty_onion_friend = {false}; |
109 | | |
110 | | typedef struct Onion_Data_Handler { |
111 | | oniondata_handler_cb *function; |
112 | | void *object; |
113 | | } Onion_Data_Handler; |
114 | | |
115 | | struct Onion_Client { |
116 | | const Mono_Time *mono_time; |
117 | | const Logger *logger; |
118 | | const Random *rng; |
119 | | const Memory *mem; |
120 | | |
121 | | DHT *dht; |
122 | | Net_Crypto *c; |
123 | | Networking_Core *net; |
124 | | Onion_Friend *friends_list; |
125 | | uint16_t num_friends; |
126 | | |
127 | | Onion_Node clients_announce_list[MAX_ONION_CLIENTS_ANNOUNCE]; |
128 | | uint64_t last_announce; |
129 | | |
130 | | Onion_Client_Paths onion_paths_self; |
131 | | Onion_Client_Paths onion_paths_friends; |
132 | | |
133 | | uint8_t secret_symmetric_key[CRYPTO_SYMMETRIC_KEY_SIZE]; |
134 | | uint64_t last_run; |
135 | | uint64_t first_run; |
136 | | uint64_t last_time_connected; |
137 | | |
138 | | uint8_t temp_public_key[CRYPTO_PUBLIC_KEY_SIZE]; |
139 | | uint8_t temp_secret_key[CRYPTO_SECRET_KEY_SIZE]; |
140 | | |
141 | | Last_Pinged last_pinged[MAX_STORED_PINGED_NODES]; |
142 | | |
143 | | Node_format path_nodes[MAX_PATH_NODES]; |
144 | | uint16_t path_nodes_index; |
145 | | |
146 | | Node_format path_nodes_bs[MAX_PATH_NODES]; |
147 | | uint16_t path_nodes_index_bs; |
148 | | |
149 | | Ping_Array *announce_ping_array; |
150 | | uint8_t last_pinged_index; |
151 | | Onion_Data_Handler onion_data_handlers[256]; |
152 | | |
153 | | uint64_t last_packet_recv; |
154 | | uint64_t last_populated; // the last time we had a fully populated path nodes list |
155 | | |
156 | | unsigned int onion_connected; |
157 | | bool udp_connected; |
158 | | |
159 | | onion_group_announce_cb *group_announce_response; |
160 | | void *group_announce_response_user_data; |
161 | | }; |
162 | | |
163 | | uint16_t onion_get_friend_count(const Onion_Client *const onion_c) |
164 | 212k | { |
165 | 212k | return onion_c->num_friends; |
166 | 212k | } |
167 | | |
168 | | Onion_Friend *onion_get_friend(const Onion_Client *const onion_c, uint16_t friend_num) |
169 | 242k | { |
170 | 242k | return &onion_c->friends_list[friend_num]; |
171 | 242k | } |
172 | | |
173 | | const uint8_t *onion_friend_get_gc_public_key(const Onion_Friend *const onion_friend) |
174 | 6.64k | { |
175 | 6.64k | return onion_friend->gc_public_key; |
176 | 6.64k | } |
177 | | |
178 | | const uint8_t *onion_friend_get_gc_public_key_num(const Onion_Client *const onion_c, uint32_t num) |
179 | 1.53k | { |
180 | 1.53k | return onion_c->friends_list[num].gc_public_key; |
181 | 1.53k | } |
182 | | |
183 | | void onion_friend_set_gc_public_key(Onion_Friend *const onion_friend, const uint8_t *public_key) |
184 | 154 | { |
185 | 154 | memcpy(onion_friend->gc_public_key, public_key, ENC_PUBLIC_KEY_SIZE); |
186 | 154 | } |
187 | | |
188 | | void onion_friend_set_gc_data(Onion_Friend *const onion_friend, const uint8_t *gc_data, uint16_t gc_data_length) |
189 | 430 | { |
190 | 430 | if (gc_data_length > 0 && gc_data != nullptr) { |
191 | 276 | memcpy(onion_friend->gc_data, gc_data, gc_data_length); |
192 | 276 | } |
193 | | |
194 | 430 | onion_friend->gc_data_length = gc_data_length; |
195 | 430 | onion_friend->is_groupchat = true; |
196 | 430 | } |
197 | | |
198 | | bool onion_friend_is_groupchat(const Onion_Friend *const onion_friend) |
199 | 242k | { |
200 | 242k | return onion_friend->is_groupchat; |
201 | 242k | } |
202 | | |
203 | | DHT *onion_get_dht(const Onion_Client *onion_c) |
204 | 3.69k | { |
205 | 3.69k | return onion_c->dht; |
206 | 3.69k | } |
207 | | |
208 | | Net_Crypto *onion_get_net_crypto(const Onion_Client *onion_c) |
209 | 3.74k | { |
210 | 3.74k | return onion_c->c; |
211 | 3.74k | } |
212 | | |
213 | | /** @brief Add a node to the path_nodes bootstrap array. |
214 | | * |
215 | | * If a node with the given public key was already in the bootstrap array, this function has no |
216 | | * effect and returns successfully. There is currently no way to update the IP/port for a bootstrap |
217 | | * node, so if it changes, the Onion_Client must be recreated. |
218 | | * |
219 | | * @param onion_c The onion client object. |
220 | | * @param ip_port IP/port for the bootstrap node. |
221 | | * @param public_key DHT public key for the bootstrap node. |
222 | | * |
223 | | * @retval false on failure |
224 | | * @retval true on success |
225 | | */ |
226 | | bool onion_add_bs_path_node(Onion_Client *onion_c, const IP_Port *ip_port, const uint8_t *public_key) |
227 | 2.90k | { |
228 | 2.90k | if (!net_family_is_ipv4(ip_port->ip.family) && !net_family_is_ipv6(ip_port->ip.family)) { |
229 | 0 | return false; |
230 | 0 | } |
231 | | |
232 | 56.1k | for (unsigned int i = 0; i < MAX_PATH_NODES; ++i) { |
233 | 54.6k | if (pk_equal(public_key, onion_c->path_nodes_bs[i].public_key)) { |
234 | 1.39k | return true; |
235 | 1.39k | } |
236 | 54.6k | } |
237 | | |
238 | 1.51k | onion_c->path_nodes_bs[onion_c->path_nodes_index_bs % MAX_PATH_NODES].ip_port = *ip_port; |
239 | 1.51k | memcpy(onion_c->path_nodes_bs[onion_c->path_nodes_index_bs % MAX_PATH_NODES].public_key, public_key, |
240 | 1.51k | CRYPTO_PUBLIC_KEY_SIZE); |
241 | | |
242 | 1.51k | const uint16_t last = onion_c->path_nodes_index_bs; |
243 | 1.51k | ++onion_c->path_nodes_index_bs; |
244 | | |
245 | 1.51k | if (onion_c->path_nodes_index_bs < last) { |
246 | 0 | onion_c->path_nodes_index_bs = MAX_PATH_NODES + 1; |
247 | 0 | } |
248 | | |
249 | 1.51k | return true; |
250 | 2.90k | } |
251 | | |
252 | | /** @brief Add a node to the path_nodes array. |
253 | | * |
254 | | * return -1 on failure |
255 | | * return 0 on success |
256 | | */ |
257 | | non_null() |
258 | | static int onion_add_path_node(Onion_Client *onion_c, const IP_Port *ip_port, const uint8_t *public_key) |
259 | 327k | { |
260 | 327k | if (!net_family_is_ipv4(ip_port->ip.family) && !net_family_is_ipv6(ip_port->ip.family)) { |
261 | 653 | return -1; |
262 | 653 | } |
263 | | |
264 | 1.56M | for (unsigned int i = 0; i < MAX_PATH_NODES; ++i) { |
265 | 1.55M | if (pk_equal(public_key, onion_c->path_nodes[i].public_key)) { |
266 | 319k | return -1; |
267 | 319k | } |
268 | 1.55M | } |
269 | | |
270 | 6.83k | onion_c->path_nodes[onion_c->path_nodes_index % MAX_PATH_NODES].ip_port = *ip_port; |
271 | 6.83k | memcpy(onion_c->path_nodes[onion_c->path_nodes_index % MAX_PATH_NODES].public_key, public_key, |
272 | 6.83k | CRYPTO_PUBLIC_KEY_SIZE); |
273 | | |
274 | 6.83k | const uint16_t last = onion_c->path_nodes_index; |
275 | 6.83k | ++onion_c->path_nodes_index; |
276 | | |
277 | 6.83k | if (onion_c->path_nodes_index < last) { |
278 | 0 | onion_c->path_nodes_index = MAX_PATH_NODES + 1; |
279 | 0 | } |
280 | | |
281 | 6.83k | return 0; |
282 | 326k | } |
283 | | |
284 | | /** @brief Put up to max_num nodes in nodes. |
285 | | * |
286 | | * return the number of nodes. |
287 | | */ |
288 | | uint16_t onion_backup_nodes(const Onion_Client *onion_c, Node_format *nodes, uint16_t max_num) |
289 | 958 | { |
290 | 958 | if (max_num == 0) { |
291 | 0 | return 0; |
292 | 0 | } |
293 | | |
294 | 958 | const uint16_t num_nodes = min_u16(onion_c->path_nodes_index, MAX_PATH_NODES); |
295 | 958 | uint16_t i = 0; |
296 | | |
297 | 1.11k | while (i < max_num && i < num_nodes) { |
298 | 159 | nodes[i] = onion_c->path_nodes[(onion_c->path_nodes_index - (1 + i)) % num_nodes]; |
299 | 159 | ++i; |
300 | 159 | } |
301 | | |
302 | 1.15k | for (uint16_t j = 0; i < max_num && j < MAX_PATH_NODES && j < onion_c->path_nodes_index_bs; ++j) { |
303 | 192 | bool already_saved = false; |
304 | | |
305 | 201 | for (uint16_t k = 0; k < num_nodes; ++k) { |
306 | 13 | if (pk_equal(nodes[k].public_key, onion_c->path_nodes_bs[j].public_key)) { |
307 | 4 | already_saved = true; |
308 | 4 | break; |
309 | 4 | } |
310 | 13 | } |
311 | | |
312 | 192 | if (!already_saved) { |
313 | 188 | nodes[i] = onion_c->path_nodes_bs[j]; |
314 | 188 | ++i; |
315 | 188 | } |
316 | 192 | } |
317 | | |
318 | 958 | return i; |
319 | 958 | } |
320 | | |
321 | | /** @brief Put up to max_num random nodes in nodes. |
322 | | * |
323 | | * return the number of nodes. |
324 | | */ |
325 | | non_null() |
326 | | static uint16_t random_nodes_path_onion(const Onion_Client *onion_c, Node_format *nodes, uint16_t max_num) |
327 | 26.8k | { |
328 | 26.8k | if (max_num == 0) { |
329 | 0 | return 0; |
330 | 0 | } |
331 | | |
332 | 26.8k | const uint16_t num_nodes = min_u16(onion_c->path_nodes_index, MAX_PATH_NODES); |
333 | | |
334 | | // if (dht_non_lan_connected(onion_c->dht)) { |
335 | 26.8k | if (dht_isconnected(onion_c->dht)) { |
336 | 24.6k | if (num_nodes == 0) { |
337 | 0 | return 0; |
338 | 0 | } |
339 | | |
340 | 98.4k | for (unsigned int i = 0; i < max_num; ++i) { |
341 | 73.8k | const uint32_t rand_idx = random_range_u32(onion_c->rng, num_nodes); |
342 | 73.8k | nodes[i] = onion_c->path_nodes[rand_idx]; |
343 | 73.8k | } |
344 | 24.6k | } else { |
345 | 2.26k | const int random_tcp = get_random_tcp_con_number(onion_c->c); |
346 | | |
347 | 2.26k | if (random_tcp == -1) { |
348 | 1.74k | return 0; |
349 | 1.74k | } |
350 | | |
351 | 519 | if (num_nodes >= 2) { |
352 | 127 | nodes[0] = empty_node_format; |
353 | 127 | nodes[0].ip_port = tcp_connections_number_to_ip_port(random_tcp); |
354 | | |
355 | 381 | for (unsigned int i = 1; i < max_num; ++i) { |
356 | 254 | const uint32_t rand_idx = random_range_u32(onion_c->rng, num_nodes); |
357 | 254 | nodes[i] = onion_c->path_nodes[rand_idx]; |
358 | 254 | } |
359 | 392 | } else { |
360 | 392 | const uint16_t num_nodes_bs = min_u16(onion_c->path_nodes_index_bs, MAX_PATH_NODES); |
361 | | |
362 | 392 | if (num_nodes_bs == 0) { |
363 | 0 | return 0; |
364 | 0 | } |
365 | | |
366 | 392 | nodes[0] = empty_node_format; |
367 | 392 | nodes[0].ip_port = tcp_connections_number_to_ip_port(random_tcp); |
368 | | |
369 | 1.17k | for (unsigned int i = 1; i < max_num; ++i) { |
370 | 784 | const uint32_t rand_idx = random_range_u32(onion_c->rng, num_nodes_bs); |
371 | 784 | nodes[i] = onion_c->path_nodes_bs[rand_idx]; |
372 | 784 | } |
373 | 392 | } |
374 | 519 | } |
375 | | |
376 | 25.1k | return max_num; |
377 | 26.8k | } |
378 | | |
379 | | /** |
380 | | * return -1 if nodes are suitable for creating a new path. |
381 | | * return path number of already existing similar path if one already exists. |
382 | | */ |
383 | | non_null() |
384 | | static int is_path_used(const Mono_Time *mono_time, const Onion_Client_Paths *onion_paths, const Node_format *nodes) |
385 | 25.1k | { |
386 | 113k | for (unsigned int i = 0; i < NUMBER_ONION_PATHS; ++i) { |
387 | 105k | if (mono_time_is_timeout(mono_time, onion_paths->last_path_success[i], ONION_PATH_TIMEOUT)) { |
388 | 64.1k | continue; |
389 | 64.1k | } |
390 | | |
391 | 41.0k | if (mono_time_is_timeout(mono_time, onion_paths->path_creation_time[i], ONION_PATH_MAX_LIFETIME)) { |
392 | 0 | continue; |
393 | 0 | } |
394 | | |
395 | | // TODO(irungentoo): do we really have to check it with the last node? |
396 | 41.0k | if (ipport_equal(&onion_paths->paths[i].ip_port1, &nodes[ONION_PATH_LENGTH - 1].ip_port)) { |
397 | 16.7k | return i; |
398 | 16.7k | } |
399 | 41.0k | } |
400 | | |
401 | 8.42k | return -1; |
402 | 25.1k | } |
403 | | |
404 | | /** is path timed out */ |
405 | | non_null() |
406 | | static bool path_timed_out(const Mono_Time *mono_time, const Onion_Client_Paths *onion_paths, uint32_t pathnum) |
407 | 162k | { |
408 | 162k | pathnum = pathnum % NUMBER_ONION_PATHS; |
409 | | |
410 | 162k | const bool is_new = onion_paths->last_path_success[pathnum] == onion_paths->path_creation_time[pathnum]; |
411 | 162k | const uint64_t timeout = is_new ? ONION_PATH_FIRST_TIMEOUT : ONION_PATH_TIMEOUT; |
412 | | |
413 | 162k | return (onion_paths->last_path_used_times[pathnum] >= ONION_PATH_MAX_NO_RESPONSE_USES |
414 | 162k | && mono_time_is_timeout(mono_time, onion_paths->last_path_used[pathnum], timeout)) |
415 | 162k | || mono_time_is_timeout(mono_time, onion_paths->path_creation_time[pathnum], ONION_PATH_MAX_LIFETIME); |
416 | 162k | } |
417 | | |
418 | | /** should node be considered to have timed out */ |
419 | | non_null() |
420 | | static bool onion_node_timed_out(const Onion_Node *node, const Mono_Time *mono_time) |
421 | 3.25M | { |
422 | 3.25M | return node->timestamp == 0 |
423 | 3.25M | || (node->pings_since_last_response >= ONION_NODE_MAX_PINGS |
424 | 1.15M | && mono_time_is_timeout(mono_time, node->last_pinged, ONION_NODE_TIMEOUT)); |
425 | 3.25M | } |
426 | | |
427 | | /** @brief Create a new path or use an old suitable one (if pathnum is valid) |
428 | | * or a random one from onion_paths. |
429 | | * |
430 | | * return -1 on failure |
431 | | * return 0 on success |
432 | | * |
433 | | * TODO(irungentoo): Make this function better, it currently probably is |
434 | | * vulnerable to some attacks that could deanonimize us. |
435 | | */ |
436 | | non_null() |
437 | | static int random_path(const Onion_Client *onion_c, Onion_Client_Paths *onion_paths, uint32_t pathnum, Onion_Path *path) |
438 | 79.8k | { |
439 | 79.8k | if (pathnum == UINT32_MAX) { |
440 | 71.2k | pathnum = random_range_u32(onion_c->rng, NUMBER_ONION_PATHS); |
441 | 71.2k | } else { |
442 | 8.60k | pathnum = pathnum % NUMBER_ONION_PATHS; |
443 | 8.60k | } |
444 | | |
445 | 79.8k | if (path_timed_out(onion_c->mono_time, onion_paths, pathnum)) { |
446 | 26.8k | Node_format nodes[ONION_PATH_LENGTH]; |
447 | | |
448 | 26.8k | if (random_nodes_path_onion(onion_c, nodes, ONION_PATH_LENGTH) != ONION_PATH_LENGTH) { |
449 | 1.74k | return -1; |
450 | 1.74k | } |
451 | | |
452 | 25.1k | const int n = is_path_used(onion_c->mono_time, onion_paths, nodes); |
453 | | |
454 | 25.1k | if (n == -1) { |
455 | 8.42k | if (create_onion_path(onion_c->rng, onion_c->dht, &onion_paths->paths[pathnum], nodes) == -1) { |
456 | 0 | return -1; |
457 | 0 | } |
458 | | |
459 | 8.42k | onion_paths->path_creation_time[pathnum] = mono_time_get(onion_c->mono_time); |
460 | 8.42k | onion_paths->last_path_success[pathnum] = onion_paths->path_creation_time[pathnum]; |
461 | 8.42k | onion_paths->last_path_used_times[pathnum] = ONION_PATH_MAX_NO_RESPONSE_USES / 2; |
462 | | |
463 | 8.42k | uint32_t path_num = random_u32(onion_c->rng); |
464 | 8.42k | path_num /= NUMBER_ONION_PATHS; |
465 | 8.42k | path_num *= NUMBER_ONION_PATHS; |
466 | 8.42k | path_num += pathnum; |
467 | | |
468 | 8.42k | onion_paths->paths[pathnum].path_num = path_num; |
469 | 16.7k | } else { |
470 | 16.7k | pathnum = n; |
471 | 16.7k | } |
472 | 25.1k | } |
473 | | |
474 | 78.0k | if (onion_paths->last_path_used_times[pathnum] < ONION_PATH_MAX_NO_RESPONSE_USES) { |
475 | 64.5k | onion_paths->last_path_used[pathnum] = mono_time_get(onion_c->mono_time); |
476 | 64.5k | } |
477 | | |
478 | 78.0k | ++onion_paths->last_path_used_times[pathnum]; |
479 | 78.0k | *path = onion_paths->paths[pathnum]; |
480 | 78.0k | return 0; |
481 | 79.8k | } |
482 | | |
483 | | /** Does path with path_num exist. */ |
484 | | non_null() |
485 | | static bool path_exists(const Mono_Time *mono_time, const Onion_Client_Paths *onion_paths, uint32_t path_num) |
486 | 82.6k | { |
487 | 82.6k | if (path_timed_out(mono_time, onion_paths, path_num)) { |
488 | 223 | return false; |
489 | 223 | } |
490 | | |
491 | 82.4k | return onion_paths->paths[path_num % NUMBER_ONION_PATHS].path_num == path_num; |
492 | 82.6k | } |
493 | | |
494 | | /** Set path timeouts, return the path number. */ |
495 | | non_null() |
496 | | static uint32_t set_path_timeouts(Onion_Client *onion_c, uint32_t num, uint32_t path_num) |
497 | 59.7k | { |
498 | 59.7k | if (num > onion_c->num_friends) { |
499 | 0 | return -1; |
500 | 0 | } |
501 | | |
502 | 59.7k | Onion_Client_Paths *onion_paths; |
503 | | |
504 | 59.7k | if (num == 0) { |
505 | 39.7k | onion_paths = &onion_c->onion_paths_self; |
506 | 39.7k | } else { |
507 | 19.9k | onion_paths = &onion_c->onion_paths_friends; |
508 | 19.9k | } |
509 | | |
510 | 59.7k | if (onion_paths->paths[path_num % NUMBER_ONION_PATHS].path_num == path_num) { |
511 | 59.5k | onion_paths->last_path_success[path_num % NUMBER_ONION_PATHS] = mono_time_get(onion_c->mono_time); |
512 | 59.5k | onion_paths->last_path_used_times[path_num % NUMBER_ONION_PATHS] = 0; |
513 | | |
514 | 59.5k | Node_format nodes[ONION_PATH_LENGTH]; |
515 | | |
516 | 59.5k | if (onion_path_to_nodes(nodes, ONION_PATH_LENGTH, &onion_paths->paths[path_num % NUMBER_ONION_PATHS]) == 0) { |
517 | 238k | for (unsigned int i = 0; i < ONION_PATH_LENGTH; ++i) { |
518 | 178k | onion_add_path_node(onion_c, &nodes[i].ip_port, nodes[i].public_key); |
519 | 178k | } |
520 | 59.5k | } |
521 | | |
522 | 59.5k | return path_num; |
523 | 59.5k | } |
524 | | |
525 | 158 | return -1; |
526 | 59.7k | } |
527 | | |
528 | | /** @brief Function to send onion packet via TCP and UDP. |
529 | | * |
530 | | * return -1 on failure. |
531 | | * return 0 on success. |
532 | | */ |
533 | | non_null() |
534 | | static int send_onion_packet_tcp_udp(const Onion_Client *onion_c, const Onion_Path *path, const IP_Port *dest, |
535 | | const uint8_t *data, uint16_t length) |
536 | 77.8k | { |
537 | 77.8k | if (net_family_is_ipv4(path->ip_port1.ip.family) || net_family_is_ipv6(path->ip_port1.ip.family)) { |
538 | 76.8k | uint8_t packet[ONION_MAX_PACKET_SIZE]; |
539 | 76.8k | const int len = create_onion_packet(onion_c->rng, packet, sizeof(packet), path, dest, data, length); |
540 | | |
541 | 76.8k | if (len == -1) { |
542 | 299 | return -1; |
543 | 299 | } |
544 | | |
545 | 76.5k | if (sendpacket(onion_c->net, &path->ip_port1, packet, len) != len) { |
546 | 101 | return -1; |
547 | 101 | } |
548 | | |
549 | 76.4k | return 0; |
550 | 76.5k | } |
551 | | |
552 | 1.02k | unsigned int tcp_connections_number; |
553 | | |
554 | 1.02k | if (ip_port_to_tcp_connections_number(&path->ip_port1, &tcp_connections_number)) { |
555 | 1.02k | uint8_t packet[ONION_MAX_PACKET_SIZE]; |
556 | 1.02k | const int len = create_onion_packet_tcp(onion_c->rng, packet, sizeof(packet), path, dest, data, length); |
557 | | |
558 | 1.02k | if (len == -1) { |
559 | 0 | return -1; |
560 | 0 | } |
561 | | |
562 | 1.02k | return send_tcp_onion_request(onion_c->c, tcp_connections_number, packet, len); |
563 | 1.02k | } |
564 | | |
565 | 0 | return -1; |
566 | 1.02k | } |
567 | | |
568 | | /** @brief Creates a sendback for use in an announce request. |
569 | | * |
570 | | * num is 0 if we used our secret public key for the announce |
571 | | * num is 1 + friendnum if we use a temporary one. |
572 | | * |
573 | | * Public key is the key we will be sending it to. |
574 | | * ip_port is the ip_port of the node we will be sending |
575 | | * it to. |
576 | | * |
577 | | * sendback must be at least ONION_ANNOUNCE_SENDBACK_DATA_LENGTH big |
578 | | * |
579 | | * return -1 on failure |
580 | | * return 0 on success |
581 | | * |
582 | | */ |
583 | | non_null() |
584 | | static int new_sendback(Onion_Client *onion_c, uint32_t num, const uint8_t *public_key, const IP_Port *ip_port, |
585 | | uint32_t path_num, uint64_t *sendback) |
586 | 73.5k | { |
587 | 73.5k | uint8_t data[sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE + sizeof(IP_Port) + sizeof(uint32_t)]; |
588 | 73.5k | memcpy(data, &num, sizeof(uint32_t)); |
589 | 73.5k | memcpy(data + sizeof(uint32_t), public_key, CRYPTO_PUBLIC_KEY_SIZE); |
590 | 73.5k | memcpy(data + sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE, ip_port, sizeof(IP_Port)); |
591 | 73.5k | memcpy(data + sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE + sizeof(IP_Port), &path_num, sizeof(uint32_t)); |
592 | 73.5k | *sendback = ping_array_add(onion_c->announce_ping_array, onion_c->mono_time, onion_c->rng, data, sizeof(data)); |
593 | | |
594 | 73.5k | if (*sendback == 0) { |
595 | 91 | LOGGER_TRACE(onion_c->logger, "generating sendback in announce ping array failed"); |
596 | 91 | return -1; |
597 | 91 | } |
598 | | |
599 | 73.4k | return 0; |
600 | 73.5k | } |
601 | | |
602 | | /** @brief Checks if the sendback is valid and returns the public key contained in it in ret_pubkey and the |
603 | | * ip contained in it in ret_ip_port |
604 | | * |
605 | | * sendback is the sendback ONION_ANNOUNCE_SENDBACK_DATA_LENGTH big |
606 | | * ret_pubkey must be at least CRYPTO_PUBLIC_KEY_SIZE big |
607 | | * ret_ip_port must be at least 1 big |
608 | | * |
609 | | * return -1 on failure |
610 | | * return num (see new_sendback(...)) on success |
611 | | */ |
612 | | non_null() |
613 | | static uint32_t check_sendback(Onion_Client *onion_c, const uint8_t *sendback, uint8_t *ret_pubkey, |
614 | | IP_Port *ret_ip_port, uint32_t *path_num) |
615 | 61.8k | { |
616 | 61.8k | uint64_t sback; |
617 | 61.8k | memcpy(&sback, sendback, sizeof(uint64_t)); |
618 | 61.8k | uint8_t data[sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE + sizeof(IP_Port) + sizeof(uint32_t)]; |
619 | | |
620 | 61.8k | if (ping_array_check(onion_c->announce_ping_array, onion_c->mono_time, data, sizeof(data), sback) != sizeof(data)) { |
621 | 1.81k | return -1; |
622 | 1.81k | } |
623 | | |
624 | 60.0k | memcpy(ret_pubkey, data + sizeof(uint32_t), CRYPTO_PUBLIC_KEY_SIZE); |
625 | 60.0k | memcpy(ret_ip_port, data + sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE, sizeof(IP_Port)); |
626 | 60.0k | memcpy(path_num, data + sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE + sizeof(IP_Port), sizeof(uint32_t)); |
627 | | |
628 | 60.0k | uint32_t num; |
629 | 60.0k | memcpy(&num, data, sizeof(uint32_t)); |
630 | 60.0k | return num; |
631 | 61.8k | } |
632 | | |
633 | | non_null(1, 3, 4) nullable(5) |
634 | | static int client_send_announce_request(Onion_Client *onion_c, uint32_t num, const IP_Port *dest, |
635 | | const uint8_t *dest_pubkey, const uint8_t *ping_id, uint32_t pathnum) |
636 | 75.2k | { |
637 | 75.2k | if (num > onion_c->num_friends) { |
638 | 0 | LOGGER_TRACE(onion_c->logger, "not sending announce to out of bounds friend %u (num friends: %u)", num, onion_c->num_friends); |
639 | 0 | return -1; |
640 | 0 | } |
641 | | |
642 | 75.2k | uint64_t sendback; |
643 | 75.2k | Onion_Path path; |
644 | | |
645 | 75.2k | if (num == 0) { |
646 | 46.8k | if (random_path(onion_c, &onion_c->onion_paths_self, pathnum, &path) == -1) { |
647 | 1.29k | LOGGER_TRACE(onion_c->logger, "cannot find path to self"); |
648 | 1.29k | return -1; |
649 | 1.29k | } |
650 | 46.8k | } else { |
651 | 28.3k | if (random_path(onion_c, &onion_c->onion_paths_friends, pathnum, &path) == -1) { |
652 | 453 | LOGGER_TRACE(onion_c->logger, "cannot find path to friend"); |
653 | 453 | return -1; |
654 | 453 | } |
655 | 28.3k | } |
656 | | |
657 | 73.5k | if (new_sendback(onion_c, num, dest_pubkey, dest, path.path_num, &sendback) == -1) { |
658 | 91 | return -1; |
659 | 91 | } |
660 | | |
661 | 73.4k | uint8_t zero_ping_id[ONION_PING_ID_SIZE] = {0}; |
662 | | |
663 | 73.4k | if (ping_id == nullptr) { |
664 | 64.7k | ping_id = zero_ping_id; |
665 | 64.7k | } |
666 | | |
667 | 73.4k | uint8_t request[ONION_ANNOUNCE_REQUEST_MAX_SIZE]; |
668 | 73.4k | int len; |
669 | | |
670 | 73.4k | if (num == 0) { |
671 | 45.5k | len = create_announce_request( |
672 | 45.5k | onion_c->rng, request, sizeof(request), dest_pubkey, nc_get_self_public_key(onion_c->c), |
673 | 45.5k | nc_get_self_secret_key(onion_c->c), ping_id, nc_get_self_public_key(onion_c->c), |
674 | 45.5k | onion_c->temp_public_key, sendback); |
675 | 45.5k | } else { |
676 | 27.9k | Onion_Friend *onion_friend = &onion_c->friends_list[num - 1]; |
677 | | |
678 | 27.9k | if (onion_friend->gc_data_length == 0) { // contact is a friend |
679 | 26.3k | len = create_announce_request( |
680 | 26.3k | onion_c->rng, request, sizeof(request), dest_pubkey, onion_friend->temp_public_key, |
681 | 26.3k | onion_friend->temp_secret_key, ping_id, onion_friend->real_public_key, |
682 | 26.3k | zero_ping_id, sendback); |
683 | 26.3k | } else { // contact is a gc |
684 | 1.60k | onion_friend->is_groupchat = true; |
685 | | |
686 | 1.60k | len = create_gca_announce_request( |
687 | 1.60k | onion_c->rng, request, sizeof(request), dest_pubkey, onion_friend->temp_public_key, |
688 | 1.60k | onion_friend->temp_secret_key, ping_id, onion_friend->real_public_key, |
689 | 1.60k | zero_ping_id, sendback, onion_friend->gc_data, |
690 | 1.60k | onion_friend->gc_data_length); |
691 | 1.60k | } |
692 | 27.9k | } |
693 | | |
694 | 73.4k | if (len == -1) { |
695 | 92 | LOGGER_TRACE(onion_c->logger, "failed to create announce request"); |
696 | 92 | return -1; |
697 | 92 | } |
698 | | |
699 | 73.3k | Ip_Ntoa ip_str; |
700 | 73.3k | LOGGER_TRACE(onion_c->logger, "sending onion packet to %s:%d (%02x, %d bytes)", |
701 | 73.3k | net_ip_ntoa(&dest->ip, &ip_str), net_ntohs(dest->port), request[0], len); |
702 | 73.3k | return send_onion_packet_tcp_udp(onion_c, &path, dest, request, len); |
703 | 73.4k | } |
704 | | |
705 | | typedef struct Onion_Client_Cmp_Data { |
706 | | const Mono_Time *mono_time; |
707 | | const uint8_t *base_public_key; |
708 | | Onion_Node entry; |
709 | | } Onion_Client_Cmp_Data; |
710 | | |
711 | | non_null() |
712 | | static int onion_client_cmp_entry(const void *a, const void *b) |
713 | 1.09M | { |
714 | 1.09M | const Onion_Client_Cmp_Data *cmp1 = (const Onion_Client_Cmp_Data *)a; |
715 | 1.09M | const Onion_Client_Cmp_Data *cmp2 = (const Onion_Client_Cmp_Data *)b; |
716 | 1.09M | const Onion_Node entry1 = cmp1->entry; |
717 | 1.09M | const Onion_Node entry2 = cmp2->entry; |
718 | 1.09M | const uint8_t *cmp_public_key = cmp1->base_public_key; |
719 | | |
720 | 1.09M | const bool t1 = onion_node_timed_out(&entry1, cmp1->mono_time); |
721 | 1.09M | const bool t2 = onion_node_timed_out(&entry2, cmp2->mono_time); |
722 | | |
723 | 1.09M | if (t1 && t2) { |
724 | 614k | return 0; |
725 | 614k | } |
726 | | |
727 | 480k | if (t1) { |
728 | 94.1k | return -1; |
729 | 94.1k | } |
730 | | |
731 | 386k | if (t2) { |
732 | 63.6k | return 1; |
733 | 63.6k | } |
734 | | |
735 | 322k | const int closest = id_closest(cmp_public_key, entry1.public_key, entry2.public_key); |
736 | | |
737 | 322k | if (closest == 1) { |
738 | 26.8k | return 1; |
739 | 26.8k | } |
740 | | |
741 | 295k | if (closest == 2) { |
742 | 295k | return -1; |
743 | 295k | } |
744 | | |
745 | 0 | return 0; |
746 | 295k | } |
747 | | |
748 | | non_null() |
749 | | static void sort_onion_node_list(const Memory *mem, const Mono_Time *mono_time, |
750 | | Onion_Node *list, unsigned int length, const uint8_t *comp_public_key) |
751 | 59.7k | { |
752 | | // Pass comp_public_key to qsort with each Client_data entry, so the |
753 | | // comparison function can use it as the base of comparison. |
754 | 59.7k | Onion_Client_Cmp_Data *cmp_list = (Onion_Client_Cmp_Data *)mem_valloc(mem, length, sizeof(Onion_Client_Cmp_Data)); |
755 | | |
756 | 59.7k | if (cmp_list == nullptr) { |
757 | 20 | return; |
758 | 20 | } |
759 | | |
760 | 696k | for (uint32_t i = 0; i < length; ++i) { |
761 | 636k | cmp_list[i].mono_time = mono_time; |
762 | 636k | cmp_list[i].base_public_key = comp_public_key; |
763 | 636k | cmp_list[i].entry = list[i]; |
764 | 636k | } |
765 | | |
766 | 59.7k | qsort(cmp_list, length, sizeof(Onion_Client_Cmp_Data), onion_client_cmp_entry); |
767 | | |
768 | 696k | for (uint32_t i = 0; i < length; ++i) { |
769 | 636k | list[i] = cmp_list[i].entry; |
770 | 636k | } |
771 | | |
772 | 59.7k | mem_delete(mem, cmp_list); |
773 | 59.7k | } |
774 | | |
775 | | non_null() |
776 | | static int client_add_to_list(Onion_Client *onion_c, uint32_t num, const uint8_t *public_key, const IP_Port *ip_port, |
777 | | uint8_t is_stored, const uint8_t *pingid_or_key, uint32_t path_used) |
778 | 59.7k | { |
779 | 59.7k | if (num > onion_c->num_friends) { |
780 | 0 | return -1; |
781 | 0 | } |
782 | | |
783 | 59.7k | Onion_Node *node_list = nullptr; |
784 | 59.7k | const uint8_t *reference_id = nullptr; |
785 | 59.7k | unsigned int list_length; |
786 | | |
787 | 59.7k | if (num == 0) { |
788 | 39.7k | node_list = onion_c->clients_announce_list; |
789 | 39.7k | reference_id = nc_get_self_public_key(onion_c->c); |
790 | 39.7k | list_length = MAX_ONION_CLIENTS_ANNOUNCE; |
791 | | |
792 | 39.7k | if (is_stored == 1 && !pk_equal(pingid_or_key, onion_c->temp_public_key)) { |
793 | 0 | is_stored = 0; |
794 | 0 | } |
795 | 39.7k | } else { |
796 | 19.9k | if (is_stored >= 2) { |
797 | 0 | return -1; |
798 | 0 | } |
799 | | |
800 | 19.9k | node_list = onion_c->friends_list[num - 1].clients_list; |
801 | 19.9k | reference_id = onion_c->friends_list[num - 1].real_public_key; |
802 | 19.9k | list_length = MAX_ONION_CLIENTS; |
803 | 19.9k | } |
804 | | |
805 | 59.7k | sort_onion_node_list(onion_c->mem, onion_c->mono_time, node_list, list_length, reference_id); |
806 | | |
807 | 59.7k | int index = -1; |
808 | 59.7k | bool stored = false; |
809 | | |
810 | 59.7k | if (onion_node_timed_out(&node_list[0], onion_c->mono_time) |
811 | 59.7k | || id_closest(reference_id, node_list[0].public_key, public_key) == 2) { |
812 | 58.5k | index = 0; |
813 | 58.5k | } |
814 | | |
815 | 575k | for (unsigned int i = 0; i < list_length; ++i) { |
816 | 561k | if (pk_equal(node_list[i].public_key, public_key)) { |
817 | 45.6k | index = i; |
818 | 45.6k | stored = true; |
819 | 45.6k | break; |
820 | 45.6k | } |
821 | 561k | } |
822 | | |
823 | 59.7k | if (index == -1) { |
824 | 729 | return 0; |
825 | 729 | } |
826 | | |
827 | 59.0k | memcpy(node_list[index].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); |
828 | 59.0k | node_list[index].ip_port = *ip_port; |
829 | | |
830 | | // TODO(irungentoo): remove this and find a better source of nodes to use for paths. |
831 | 59.0k | onion_add_path_node(onion_c, ip_port, public_key); |
832 | | |
833 | 59.0k | if (is_stored == 1) { |
834 | 16.2k | memcpy(node_list[index].data_public_key, pingid_or_key, CRYPTO_PUBLIC_KEY_SIZE); |
835 | 42.7k | } else { |
836 | 42.7k | memcpy(node_list[index].ping_id, pingid_or_key, ONION_PING_ID_SIZE); |
837 | 42.7k | } |
838 | | |
839 | 59.0k | node_list[index].is_stored = is_stored; |
840 | 59.0k | node_list[index].timestamp = mono_time_get(onion_c->mono_time); |
841 | 59.0k | node_list[index].pings_since_last_response = 0; |
842 | | |
843 | 59.0k | if (!stored) { |
844 | 13.3k | node_list[index].last_pinged = 0; |
845 | 13.3k | node_list[index].added_time = mono_time_get(onion_c->mono_time); |
846 | 13.3k | } |
847 | | |
848 | 59.0k | node_list[index].path_used = path_used; |
849 | 59.0k | return 0; |
850 | 59.7k | } |
851 | | |
852 | | non_null() |
853 | | static bool good_to_ping(const Mono_Time *mono_time, Last_Pinged *last_pinged, uint8_t *last_pinged_index, |
854 | | const uint8_t *public_key) |
855 | 35.0k | { |
856 | 173k | for (unsigned int i = 0; i < MAX_STORED_PINGED_NODES; ++i) { |
857 | 164k | if (!mono_time_is_timeout(mono_time, last_pinged[i].timestamp, MIN_NODE_PING_TIME)) { |
858 | 108k | if (pk_equal(last_pinged[i].public_key, public_key)) { |
859 | 26.8k | return false; |
860 | 26.8k | } |
861 | 108k | } |
862 | 164k | } |
863 | | |
864 | 8.25k | memcpy(last_pinged[*last_pinged_index % MAX_STORED_PINGED_NODES].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); |
865 | 8.25k | last_pinged[*last_pinged_index % MAX_STORED_PINGED_NODES].timestamp = mono_time_get(mono_time); |
866 | 8.25k | ++*last_pinged_index; |
867 | 8.25k | return true; |
868 | 35.0k | } |
869 | | |
870 | | non_null() |
871 | | static int client_ping_nodes(Onion_Client *onion_c, uint32_t num, const Node_format *nodes, uint16_t num_nodes, |
872 | | const IP_Port *source) |
873 | 59.0k | { |
874 | 59.0k | if (num > onion_c->num_friends) { |
875 | 0 | return -1; |
876 | 0 | } |
877 | | |
878 | 59.0k | if (num_nodes == 0) { |
879 | 0 | return 0; |
880 | 0 | } |
881 | | |
882 | 59.0k | const Onion_Node *node_list = nullptr; |
883 | 59.0k | const uint8_t *reference_id = nullptr; |
884 | 59.0k | unsigned int list_length; |
885 | | |
886 | 59.0k | Last_Pinged *last_pinged = nullptr; |
887 | 59.0k | uint8_t *last_pinged_index = nullptr; |
888 | | |
889 | 59.0k | if (num == 0) { |
890 | 39.3k | node_list = onion_c->clients_announce_list; |
891 | 39.3k | reference_id = nc_get_self_public_key(onion_c->c); |
892 | 39.3k | list_length = MAX_ONION_CLIENTS_ANNOUNCE; |
893 | 39.3k | last_pinged = onion_c->last_pinged; |
894 | 39.3k | last_pinged_index = &onion_c->last_pinged_index; |
895 | 39.3k | } else { |
896 | 19.7k | node_list = onion_c->friends_list[num - 1].clients_list; |
897 | 19.7k | reference_id = onion_c->friends_list[num - 1].real_public_key; |
898 | 19.7k | list_length = MAX_ONION_CLIENTS; |
899 | 19.7k | last_pinged = onion_c->friends_list[num - 1].last_pinged; |
900 | 19.7k | last_pinged_index = &onion_c->friends_list[num - 1].last_pinged_index; |
901 | 19.7k | } |
902 | | |
903 | 59.0k | const bool lan_ips_accepted = ip_is_lan(&source->ip); |
904 | | |
905 | 209k | for (uint32_t i = 0; i < num_nodes; ++i) { |
906 | 150k | if (!lan_ips_accepted) { |
907 | 33 | if (ip_is_lan(&nodes[i].ip_port.ip)) { |
908 | 33 | continue; |
909 | 33 | } |
910 | 33 | } |
911 | | |
912 | 150k | if (onion_node_timed_out(&node_list[0], onion_c->mono_time) |
913 | 150k | || id_closest(reference_id, node_list[0].public_key, nodes[i].public_key) == 2 |
914 | 150k | || onion_node_timed_out(&node_list[1], onion_c->mono_time) |
915 | 150k | || id_closest(reference_id, node_list[1].public_key, nodes[i].public_key) == 2) { |
916 | 150k | uint32_t j; |
917 | | |
918 | | /* check if node is already in list. */ |
919 | 1.46M | for (j = 0; j < list_length; ++j) { |
920 | 1.42M | if (pk_equal(node_list[j].public_key, nodes[i].public_key)) { |
921 | 115k | break; |
922 | 115k | } |
923 | 1.42M | } |
924 | | |
925 | 150k | if (j == list_length && good_to_ping(onion_c->mono_time, last_pinged, last_pinged_index, nodes[i].public_key)) { |
926 | 8.25k | client_send_announce_request(onion_c, num, &nodes[i].ip_port, nodes[i].public_key, nullptr, -1); |
927 | 8.25k | } |
928 | 150k | } |
929 | 150k | } |
930 | | |
931 | 59.0k | return 0; |
932 | 59.0k | } |
933 | | |
934 | | non_null() |
935 | | static bool handle_group_announce_response(Onion_Client *onion_c, uint32_t num, const uint8_t *plain, size_t plain_size) |
936 | 1.53k | { |
937 | 1.53k | if (onion_c->group_announce_response == nullptr) { |
938 | 0 | return true; |
939 | 0 | } |
940 | | |
941 | 1.53k | return onion_c->group_announce_response(onion_c, num, plain, plain_size, onion_c->group_announce_response_user_data); |
942 | 1.53k | } |
943 | | |
944 | | non_null(1, 2, 3) nullable(5) |
945 | | static int handle_announce_response(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length, |
946 | | void *userdata) |
947 | 1.60k | { |
948 | 1.60k | Onion_Client *onion_c = (Onion_Client *)object; |
949 | | |
950 | 1.60k | if (length < ONION_ANNOUNCE_RESPONSE_MIN_SIZE || length > ONION_ANNOUNCE_RESPONSE_MAX_SIZE) { |
951 | 9 | LOGGER_TRACE(onion_c->logger, "invalid announce response length: %u (min: %u, max: %u)", |
952 | 9 | length, (unsigned int)ONION_ANNOUNCE_RESPONSE_MIN_SIZE, (unsigned int)ONION_ANNOUNCE_RESPONSE_MAX_SIZE); |
953 | 9 | return 1; |
954 | 9 | } |
955 | | |
956 | 1.59k | uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; |
957 | 1.59k | IP_Port ip_port; |
958 | 1.59k | uint32_t path_num; |
959 | 1.59k | const uint32_t num = check_sendback(onion_c, packet + 1, public_key, &ip_port, &path_num); |
960 | | |
961 | 1.59k | if (num > onion_c->num_friends) { |
962 | 41 | return 1; |
963 | 41 | } |
964 | | |
965 | 1.55k | uint8_t plain[1 + ONION_PING_ID_SIZE + ONION_ANNOUNCE_RESPONSE_MAX_SIZE - ONION_ANNOUNCE_RESPONSE_MIN_SIZE]; |
966 | 1.55k | const int plain_size = 1 + ONION_PING_ID_SIZE + length - ONION_ANNOUNCE_RESPONSE_MIN_SIZE; |
967 | 1.55k | int len; |
968 | 1.55k | const uint16_t nonce_start = 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH; |
969 | 1.55k | const uint16_t ciphertext_start = nonce_start + CRYPTO_NONCE_SIZE; |
970 | 1.55k | const uint16_t ciphertext_size = length - ciphertext_start; |
971 | | |
972 | 1.55k | if (num == 0) { |
973 | 0 | len = decrypt_data(public_key, nc_get_self_secret_key(onion_c->c), |
974 | 0 | &packet[nonce_start], &packet[ciphertext_start], ciphertext_size, plain); |
975 | 1.55k | } else { |
976 | 1.55k | if (!onion_c->friends_list[num - 1].is_valid) { |
977 | 0 | LOGGER_TRACE(onion_c->logger, "friend number %lu is invalid", (unsigned long)(num - 1)); |
978 | 0 | return 1; |
979 | 0 | } |
980 | | |
981 | 1.55k | len = decrypt_data(public_key, onion_c->friends_list[num - 1].temp_secret_key, |
982 | 1.55k | &packet[nonce_start], &packet[ciphertext_start], ciphertext_size, plain); |
983 | 1.55k | } |
984 | | |
985 | 1.55k | if (len < 0) { |
986 | | // This happens a lot, so don't log it. |
987 | 2 | return 1; |
988 | 2 | } |
989 | | |
990 | 1.55k | if ((uint32_t)len != plain_size) { |
991 | 0 | LOGGER_WARNING(onion_c->logger, "decrypted size (%lu) is not the expected plain text size (%lu)", (unsigned long)len, (unsigned long)plain_size); |
992 | 0 | return 1; |
993 | 0 | } |
994 | | |
995 | 1.55k | const uint32_t path_used = set_path_timeouts(onion_c, num, path_num); |
996 | | |
997 | 1.55k | if (client_add_to_list(onion_c, num, public_key, &ip_port, plain[0], plain + 1, path_used) == -1) { |
998 | 0 | LOGGER_WARNING(onion_c->logger, "failed to add client to list"); |
999 | 0 | return 1; |
1000 | 0 | } |
1001 | | |
1002 | 1.55k | uint16_t len_nodes = 0; |
1003 | 1.55k | const uint8_t nodes_count = plain[1 + ONION_PING_ID_SIZE]; |
1004 | | |
1005 | 1.55k | if (nodes_count > 0) { |
1006 | 1.55k | if (nodes_count > MAX_SENT_NODES) { |
1007 | 0 | return 1; |
1008 | 0 | } |
1009 | | |
1010 | 1.55k | Node_format nodes[MAX_SENT_NODES]; |
1011 | 1.55k | const int num_nodes = unpack_nodes(nodes, nodes_count, &len_nodes, plain + 2 + ONION_PING_ID_SIZE, |
1012 | 1.55k | plain_size - 2 - ONION_PING_ID_SIZE, false); |
1013 | | |
1014 | 1.55k | if (num_nodes < 0) { |
1015 | 0 | LOGGER_WARNING(onion_c->logger, "no nodes to unpack in onion response"); |
1016 | 0 | return 1; |
1017 | 0 | } |
1018 | | |
1019 | 1.55k | if (client_ping_nodes(onion_c, num, nodes, num_nodes, source) == -1) { |
1020 | 0 | LOGGER_WARNING(onion_c->logger, "pinging %d nodes failed", num_nodes); |
1021 | 0 | return 1; |
1022 | 0 | } |
1023 | 1.55k | } |
1024 | | |
1025 | 1.55k | if (len_nodes + 1 < length - ONION_ANNOUNCE_RESPONSE_MIN_SIZE) { |
1026 | 1.53k | const uint16_t offset = 2 + ONION_PING_ID_SIZE + len_nodes; |
1027 | | |
1028 | 1.53k | if (plain_size < offset) { |
1029 | 0 | return 1; |
1030 | 0 | } |
1031 | | |
1032 | 1.53k | if (!handle_group_announce_response(onion_c, num, plain + offset, plain_size - offset)) { |
1033 | 0 | return 1; |
1034 | 0 | } |
1035 | 1.53k | } |
1036 | | |
1037 | | // TODO(irungentoo): LAN vs non LAN ips?, if we are connected only to LAN, are we offline? |
1038 | 1.55k | onion_c->last_packet_recv = mono_time_get(onion_c->mono_time); |
1039 | 1.55k | LOGGER_TRACE(onion_c->logger, "onion has received a packet at %llu", |
1040 | 1.55k | (unsigned long long)onion_c->last_packet_recv); |
1041 | | |
1042 | 1.55k | return 0; |
1043 | 1.55k | } |
1044 | | |
1045 | | /* TODO(jfreegman): DEPRECATE */ |
1046 | | non_null(1, 2, 3) nullable(5) |
1047 | | static int handle_announce_response_old(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length, |
1048 | | void *userdata) |
1049 | 60.2k | { |
1050 | 60.2k | Onion_Client *onion_c = (Onion_Client *)object; |
1051 | | |
1052 | 60.2k | if (length < ONION_ANNOUNCE_RESPONSE_MIN_SIZE || length > ONION_ANNOUNCE_RESPONSE_MAX_SIZE) { |
1053 | 11 | LOGGER_TRACE(onion_c->logger, "invalid announce response length: %u (min: %u, max: %u)", |
1054 | 11 | length, (unsigned int)ONION_ANNOUNCE_RESPONSE_MIN_SIZE, (unsigned int)ONION_ANNOUNCE_RESPONSE_MAX_SIZE); |
1055 | 11 | return 1; |
1056 | 11 | } |
1057 | | |
1058 | 60.2k | const uint16_t len_nodes = length - ONION_ANNOUNCE_RESPONSE_MIN_SIZE; |
1059 | | |
1060 | 60.2k | uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; |
1061 | 60.2k | IP_Port ip_port; |
1062 | 60.2k | uint32_t path_num; |
1063 | 60.2k | const uint32_t num = check_sendback(onion_c, packet + 1, public_key, &ip_port, &path_num); |
1064 | | |
1065 | 60.2k | if (num > onion_c->num_friends) { |
1066 | 1.78k | return 1; |
1067 | 1.78k | } |
1068 | | |
1069 | 58.4k | const uint16_t plain_size = 1 + ONION_PING_ID_SIZE + len_nodes; |
1070 | 58.4k | VLA(uint8_t, plain, plain_size); |
1071 | 58.4k | int len; |
1072 | 58.4k | const uint16_t nonce_start = 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH; |
1073 | 58.4k | const uint16_t ciphertext_start = nonce_start + CRYPTO_NONCE_SIZE; |
1074 | 58.4k | const uint16_t ciphertext_size = length - ciphertext_start; |
1075 | | |
1076 | 58.4k | if (num == 0) { |
1077 | 39.7k | len = decrypt_data(public_key, nc_get_self_secret_key(onion_c->c), |
1078 | 39.7k | &packet[nonce_start], &packet[ciphertext_start], ciphertext_size, plain); |
1079 | 39.7k | } else { |
1080 | 18.7k | if (!onion_c->friends_list[num - 1].is_valid) { |
1081 | 0 | LOGGER_TRACE(onion_c->logger, "friend number %lu is invalid", (unsigned long)(num - 1)); |
1082 | 0 | return 1; |
1083 | 0 | } |
1084 | | |
1085 | 18.7k | len = decrypt_data(public_key, onion_c->friends_list[num - 1].temp_secret_key, |
1086 | 18.7k | &packet[nonce_start], &packet[ciphertext_start], ciphertext_size, plain); |
1087 | 18.7k | } |
1088 | | |
1089 | 58.4k | if (len < 0) { |
1090 | | // This happens a lot, so don't log it. |
1091 | 295 | return 1; |
1092 | 295 | } |
1093 | | |
1094 | 58.1k | if ((uint32_t)len != plain_size) { |
1095 | 0 | LOGGER_WARNING(onion_c->logger, "decrypted size (%lu) is not the expected plain text size (%u)", (unsigned long)len, plain_size); |
1096 | 0 | return 1; |
1097 | 0 | } |
1098 | | |
1099 | 58.1k | const uint32_t path_used = set_path_timeouts(onion_c, num, path_num); |
1100 | | |
1101 | 58.1k | if (client_add_to_list(onion_c, num, public_key, &ip_port, plain[0], plain + 1, path_used) == -1) { |
1102 | 0 | LOGGER_WARNING(onion_c->logger, "failed to add client to list"); |
1103 | 0 | return 1; |
1104 | 0 | } |
1105 | | |
1106 | 58.1k | if (len_nodes != 0) { |
1107 | 57.4k | Node_format nodes[MAX_SENT_NODES]; |
1108 | 57.4k | const int num_nodes = unpack_nodes(nodes, MAX_SENT_NODES, nullptr, plain + 1 + ONION_PING_ID_SIZE, len_nodes, false); |
1109 | | |
1110 | 57.4k | if (num_nodes <= 0) { |
1111 | 0 | LOGGER_WARNING(onion_c->logger, "no nodes to unpack in onion response"); |
1112 | 0 | return 1; |
1113 | 0 | } |
1114 | | |
1115 | 57.4k | if (client_ping_nodes(onion_c, num, nodes, num_nodes, source) == -1) { |
1116 | 0 | LOGGER_WARNING(onion_c->logger, "pinging %d nodes failed", num_nodes); |
1117 | 0 | return 1; |
1118 | 0 | } |
1119 | 57.4k | } |
1120 | | |
1121 | | // TODO(irungentoo): LAN vs non LAN ips?, if we are connected only to LAN, are we offline? |
1122 | 58.1k | onion_c->last_packet_recv = mono_time_get(onion_c->mono_time); |
1123 | 58.1k | LOGGER_TRACE(onion_c->logger, "onion has received a packet at %llu", |
1124 | 58.1k | (unsigned long long)onion_c->last_packet_recv); |
1125 | | |
1126 | 58.1k | return 0; |
1127 | 58.1k | } |
1128 | | |
1129 | 34.1k | #define DATA_IN_RESPONSE_MIN_SIZE ONION_DATA_IN_RESPONSE_MIN_SIZE |
1130 | | |
1131 | | non_null() |
1132 | | static int handle_data_response(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length, |
1133 | | void *userdata) |
1134 | 4.17k | { |
1135 | 4.17k | Onion_Client *onion_c = (Onion_Client *)object; |
1136 | | |
1137 | 4.17k | if (length <= (ONION_DATA_RESPONSE_MIN_SIZE + DATA_IN_RESPONSE_MIN_SIZE)) { |
1138 | 10 | return 1; |
1139 | 10 | } |
1140 | | |
1141 | 4.16k | if (length > MAX_DATA_REQUEST_SIZE) { |
1142 | 9 | return 1; |
1143 | 9 | } |
1144 | | |
1145 | 4.15k | const uint16_t temp_plain_size = length - ONION_DATA_RESPONSE_MIN_SIZE; |
1146 | 4.15k | VLA(uint8_t, temp_plain, temp_plain_size); |
1147 | 4.15k | int len = decrypt_data(packet + 1 + CRYPTO_NONCE_SIZE, onion_c->temp_secret_key, packet + 1, |
1148 | 4.15k | packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, |
1149 | 4.15k | length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE), temp_plain); |
1150 | | |
1151 | 4.15k | if ((uint32_t)len != temp_plain_size) { |
1152 | 32 | return 1; |
1153 | 32 | } |
1154 | | |
1155 | 4.12k | const uint16_t plain_size = temp_plain_size - DATA_IN_RESPONSE_MIN_SIZE; |
1156 | 4.12k | VLA(uint8_t, plain, plain_size); |
1157 | 4.12k | len = decrypt_data(temp_plain, nc_get_self_secret_key(onion_c->c), |
1158 | 4.12k | packet + 1, temp_plain + CRYPTO_PUBLIC_KEY_SIZE, |
1159 | 4.12k | temp_plain_size - CRYPTO_PUBLIC_KEY_SIZE, plain); |
1160 | | |
1161 | 4.12k | if ((uint32_t)len != plain_size) { |
1162 | 8 | return 1; |
1163 | 8 | } |
1164 | | |
1165 | 4.11k | if (onion_c->onion_data_handlers[plain[0]].function == nullptr) { |
1166 | 20 | return 1; |
1167 | 20 | } |
1168 | | |
1169 | 4.09k | return onion_c->onion_data_handlers[plain[0]].function(onion_c->onion_data_handlers[plain[0]].object, temp_plain, plain, |
1170 | 4.09k | plain_size, userdata); |
1171 | 4.11k | } |
1172 | | |
1173 | 68.3k | #define DHTPK_DATA_MIN_LENGTH (1 + sizeof(uint64_t) + CRYPTO_PUBLIC_KEY_SIZE) |
1174 | 19.3k | #define DHTPK_DATA_MAX_LENGTH (DHTPK_DATA_MIN_LENGTH + sizeof(Node_format)*MAX_SENT_NODES) |
1175 | | non_null(1, 2, 3) nullable(5) |
1176 | | static int handle_dhtpk_announce(void *object, const uint8_t *source_pubkey, const uint8_t *data, uint16_t length, |
1177 | | void *userdata) |
1178 | 4.70k | { |
1179 | 4.70k | Onion_Client *onion_c = (Onion_Client *)object; |
1180 | | |
1181 | 4.70k | if (length < DHTPK_DATA_MIN_LENGTH) { |
1182 | 3 | return 1; |
1183 | 3 | } |
1184 | | |
1185 | 4.70k | if (length > DHTPK_DATA_MAX_LENGTH) { |
1186 | 3 | return 1; |
1187 | 3 | } |
1188 | | |
1189 | 4.69k | const int friend_num = onion_friend_num(onion_c, source_pubkey); |
1190 | | |
1191 | 4.69k | if (friend_num == -1) { |
1192 | 156 | return 1; |
1193 | 156 | } |
1194 | | |
1195 | 4.54k | uint64_t no_replay; |
1196 | 4.54k | net_unpack_u64(data + 1, &no_replay); |
1197 | | |
1198 | 4.54k | if (no_replay <= onion_c->friends_list[friend_num].last_noreplay) { |
1199 | 3.09k | return 1; |
1200 | 3.09k | } |
1201 | | |
1202 | 1.45k | onion_c->friends_list[friend_num].last_noreplay = no_replay; |
1203 | | |
1204 | 1.45k | if (onion_c->friends_list[friend_num].dht_pk_callback != nullptr) { |
1205 | 1.45k | onion_c->friends_list[friend_num].dht_pk_callback(onion_c->friends_list[friend_num].dht_pk_callback_object, |
1206 | 1.45k | onion_c->friends_list[friend_num].dht_pk_callback_number, data + 1 + sizeof(uint64_t), userdata); |
1207 | 1.45k | } |
1208 | | |
1209 | 1.45k | onion_set_friend_dht_pubkey(onion_c, friend_num, data + 1 + sizeof(uint64_t)); |
1210 | | |
1211 | 1.45k | const uint16_t len_nodes = length - DHTPK_DATA_MIN_LENGTH; |
1212 | | |
1213 | 1.45k | if (len_nodes != 0) { |
1214 | 1.45k | Node_format nodes[MAX_SENT_NODES]; |
1215 | 1.45k | const int num_nodes = unpack_nodes(nodes, MAX_SENT_NODES, nullptr, data + 1 + sizeof(uint64_t) + CRYPTO_PUBLIC_KEY_SIZE, |
1216 | 1.45k | len_nodes, true); |
1217 | | |
1218 | 1.45k | if (num_nodes <= 0) { |
1219 | 0 | return 1; |
1220 | 0 | } |
1221 | | |
1222 | 4.71k | for (int i = 0; i < num_nodes; ++i) { |
1223 | 3.26k | const Family family = nodes[i].ip_port.ip.family; |
1224 | | |
1225 | 3.26k | if (net_family_is_ipv4(family) || net_family_is_ipv6(family)) { |
1226 | 3.16k | dht_getnodes(onion_c->dht, &nodes[i].ip_port, nodes[i].public_key, onion_c->friends_list[friend_num].dht_public_key); |
1227 | 3.16k | } else if (net_family_is_tcp_ipv4(family) || net_family_is_tcp_ipv6(family)) { |
1228 | 103 | if (onion_c->friends_list[friend_num].tcp_relay_node_callback != nullptr) { |
1229 | 103 | void *obj = onion_c->friends_list[friend_num].tcp_relay_node_callback_object; |
1230 | 103 | const uint32_t number = onion_c->friends_list[friend_num].tcp_relay_node_callback_number; |
1231 | 103 | onion_c->friends_list[friend_num].tcp_relay_node_callback(obj, number, &nodes[i].ip_port, nodes[i].public_key); |
1232 | 103 | } |
1233 | 103 | } |
1234 | 3.26k | } |
1235 | 1.45k | } |
1236 | | |
1237 | 1.45k | return 0; |
1238 | 1.45k | } |
1239 | | |
1240 | | non_null() |
1241 | | static int handle_tcp_onion(void *object, const uint8_t *data, uint16_t length, void *userdata) |
1242 | 808 | { |
1243 | 808 | if (length == 0) { |
1244 | 0 | return 1; |
1245 | 0 | } |
1246 | | |
1247 | 808 | IP_Port ip_port = {{{0}}}; |
1248 | 808 | ip_port.ip.family = net_family_tcp_server(); |
1249 | | |
1250 | 808 | if (data[0] == NET_PACKET_ANNOUNCE_RESPONSE) { |
1251 | 0 | return handle_announce_response(object, &ip_port, data, length, userdata); |
1252 | 0 | } |
1253 | | |
1254 | 808 | if (data[0] == NET_PACKET_ANNOUNCE_RESPONSE_OLD) { |
1255 | 653 | return handle_announce_response_old(object, &ip_port, data, length, userdata); |
1256 | 653 | } |
1257 | | |
1258 | 155 | if (data[0] == NET_PACKET_ONION_DATA_RESPONSE) { |
1259 | 154 | return handle_data_response(object, &ip_port, data, length, userdata); |
1260 | 154 | } |
1261 | | |
1262 | 1 | return 1; |
1263 | 155 | } |
1264 | | |
1265 | | /** @brief Send data of length length to friendnum. |
1266 | | * Maximum length of data is ONION_CLIENT_MAX_DATA_SIZE. |
1267 | | * This data will be received by the friend using the Onion_Data_Handlers callbacks. |
1268 | | * |
1269 | | * Even if this function succeeds, the friend might not receive any data. |
1270 | | * |
1271 | | * return the number of packets sent on success |
1272 | | * return -1 on failure. |
1273 | | */ |
1274 | | int send_onion_data(Onion_Client *onion_c, int friend_num, const uint8_t *data, uint16_t length) |
1275 | 17.5k | { |
1276 | 17.5k | if ((uint32_t)friend_num >= onion_c->num_friends) { |
1277 | 0 | return -1; |
1278 | 0 | } |
1279 | | |
1280 | 17.5k | if (length + DATA_IN_RESPONSE_MIN_SIZE > MAX_DATA_REQUEST_SIZE) { |
1281 | 0 | return -1; |
1282 | 0 | } |
1283 | | |
1284 | 17.5k | if (length == 0) { |
1285 | 0 | return -1; |
1286 | 0 | } |
1287 | | |
1288 | 17.5k | unsigned int good_nodes[MAX_ONION_CLIENTS]; |
1289 | 17.5k | unsigned int num_good = 0; |
1290 | 17.5k | unsigned int num_nodes = 0; |
1291 | 17.5k | const Onion_Node *node_list = onion_c->friends_list[friend_num].clients_list; |
1292 | | |
1293 | 158k | for (unsigned int i = 0; i < MAX_ONION_CLIENTS; ++i) { |
1294 | 140k | if (onion_node_timed_out(&node_list[i], onion_c->mono_time)) { |
1295 | 128k | continue; |
1296 | 128k | } |
1297 | | |
1298 | 12.5k | ++num_nodes; |
1299 | | |
1300 | 12.5k | if (node_list[i].is_stored != 0) { |
1301 | 4.56k | good_nodes[num_good] = i; |
1302 | 4.56k | ++num_good; |
1303 | 4.56k | } |
1304 | 12.5k | } |
1305 | | |
1306 | 17.5k | if (num_good < (num_nodes - 1) / 4 + 1) { |
1307 | 15.9k | return -1; |
1308 | 15.9k | } |
1309 | | |
1310 | 1.62k | uint8_t nonce[CRYPTO_NONCE_SIZE]; |
1311 | 1.62k | random_nonce(onion_c->rng, nonce); |
1312 | | |
1313 | 1.62k | const uint16_t packet_size = DATA_IN_RESPONSE_MIN_SIZE + length; |
1314 | 1.62k | VLA(uint8_t, packet, packet_size); |
1315 | 1.62k | memcpy(packet, nc_get_self_public_key(onion_c->c), CRYPTO_PUBLIC_KEY_SIZE); |
1316 | 1.62k | int len = encrypt_data(onion_c->friends_list[friend_num].real_public_key, |
1317 | 1.62k | nc_get_self_secret_key(onion_c->c), nonce, data, |
1318 | 1.62k | length, packet + CRYPTO_PUBLIC_KEY_SIZE); |
1319 | | |
1320 | 1.62k | if ((uint32_t)len + CRYPTO_PUBLIC_KEY_SIZE != packet_size) { |
1321 | 9 | return -1; |
1322 | 9 | } |
1323 | | |
1324 | 1.61k | unsigned int good = 0; |
1325 | | |
1326 | 6.14k | for (unsigned int i = 0; i < num_good; ++i) { |
1327 | 4.53k | Onion_Path path; |
1328 | | |
1329 | 4.53k | if (random_path(onion_c, &onion_c->onion_paths_friends, -1, &path) == -1) { |
1330 | 0 | continue; |
1331 | 0 | } |
1332 | | |
1333 | 4.53k | uint8_t o_packet[ONION_MAX_PACKET_SIZE]; |
1334 | 4.53k | len = create_data_request( |
1335 | 4.53k | onion_c->rng, o_packet, sizeof(o_packet), onion_c->friends_list[friend_num].real_public_key, |
1336 | 4.53k | node_list[good_nodes[i]].data_public_key, nonce, packet, packet_size); |
1337 | | |
1338 | 4.53k | if (len == -1) { |
1339 | 8 | continue; |
1340 | 8 | } |
1341 | | |
1342 | 4.52k | if (send_onion_packet_tcp_udp(onion_c, &path, &node_list[good_nodes[i]].ip_port, o_packet, len) == 0) { |
1343 | 4.49k | ++good; |
1344 | 4.49k | } |
1345 | 4.52k | } |
1346 | | |
1347 | 1.61k | return good; |
1348 | 1.62k | } |
1349 | | |
1350 | | /** @brief Try to send the dht public key via the DHT instead of onion |
1351 | | * |
1352 | | * Even if this function succeeds, the friend might not receive any data. |
1353 | | * |
1354 | | * return the number of packets sent on success |
1355 | | * return -1 on failure. |
1356 | | */ |
1357 | | non_null() |
1358 | | static int send_dht_dhtpk(const Onion_Client *onion_c, int friend_num, const uint8_t *data, uint16_t length) |
1359 | 8.96k | { |
1360 | 8.96k | if ((uint32_t)friend_num >= onion_c->num_friends) { |
1361 | 0 | return -1; |
1362 | 0 | } |
1363 | | |
1364 | 8.96k | if (!onion_c->friends_list[friend_num].know_dht_public_key) { |
1365 | 5.22k | return -1; |
1366 | 5.22k | } |
1367 | | |
1368 | 3.73k | uint8_t nonce[CRYPTO_NONCE_SIZE]; |
1369 | 3.73k | random_nonce(onion_c->rng, nonce); |
1370 | | |
1371 | 3.73k | const uint16_t temp_size = DATA_IN_RESPONSE_MIN_SIZE + CRYPTO_NONCE_SIZE + length; |
1372 | 3.73k | VLA(uint8_t, temp, temp_size); |
1373 | 3.73k | memcpy(temp, nc_get_self_public_key(onion_c->c), CRYPTO_PUBLIC_KEY_SIZE); |
1374 | 3.73k | memcpy(temp + CRYPTO_PUBLIC_KEY_SIZE, nonce, CRYPTO_NONCE_SIZE); |
1375 | 3.73k | int len = encrypt_data(onion_c->friends_list[friend_num].real_public_key, |
1376 | 3.73k | nc_get_self_secret_key(onion_c->c), nonce, data, |
1377 | 3.73k | length, temp + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE); |
1378 | | |
1379 | 3.73k | if ((uint32_t)len + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE != temp_size) { |
1380 | 8 | return -1; |
1381 | 8 | } |
1382 | | |
1383 | 3.73k | uint8_t packet_data[MAX_CRYPTO_REQUEST_SIZE]; |
1384 | 3.73k | len = create_request( |
1385 | 3.73k | onion_c->rng, dht_get_self_public_key(onion_c->dht), dht_get_self_secret_key(onion_c->dht), packet_data, |
1386 | 3.73k | onion_c->friends_list[friend_num].dht_public_key, temp, temp_size, CRYPTO_PACKET_DHTPK); |
1387 | 3.73k | assert(len <= UINT16_MAX); |
1388 | 3.73k | const Packet packet = {packet_data, (uint16_t)len}; |
1389 | | |
1390 | 3.73k | if (len == -1) { |
1391 | 8 | return -1; |
1392 | 8 | } |
1393 | | |
1394 | 3.72k | return route_to_friend(onion_c->dht, onion_c->friends_list[friend_num].dht_public_key, &packet); |
1395 | 3.73k | } |
1396 | | |
1397 | | non_null() |
1398 | | static int handle_dht_dhtpk(void *object, const IP_Port *source, const uint8_t *source_pubkey, const uint8_t *packet, |
1399 | | uint16_t length, void *userdata) |
1400 | 970 | { |
1401 | 970 | Onion_Client *onion_c = (Onion_Client *)object; |
1402 | | |
1403 | 970 | if (length < DHTPK_DATA_MIN_LENGTH + DATA_IN_RESPONSE_MIN_SIZE + CRYPTO_NONCE_SIZE) { |
1404 | 1 | return 1; |
1405 | 1 | } |
1406 | | |
1407 | 969 | if (length > DHTPK_DATA_MAX_LENGTH + DATA_IN_RESPONSE_MIN_SIZE + CRYPTO_NONCE_SIZE) { |
1408 | 1 | return 1; |
1409 | 1 | } |
1410 | | |
1411 | 968 | uint8_t plain[DHTPK_DATA_MAX_LENGTH]; |
1412 | 968 | const int len = decrypt_data(packet, nc_get_self_secret_key(onion_c->c), |
1413 | 968 | packet + CRYPTO_PUBLIC_KEY_SIZE, |
1414 | 968 | packet + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, |
1415 | 968 | length - (CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE), plain); |
1416 | | |
1417 | 968 | if (len != length - (DATA_IN_RESPONSE_MIN_SIZE + CRYPTO_NONCE_SIZE)) { |
1418 | 0 | return 1; |
1419 | 0 | } |
1420 | | |
1421 | 968 | if (!pk_equal(source_pubkey, plain + 1 + sizeof(uint64_t))) { |
1422 | 3 | return 1; |
1423 | 3 | } |
1424 | | |
1425 | 965 | return handle_dhtpk_announce(onion_c, packet, plain, len, userdata); |
1426 | 968 | } |
1427 | | |
1428 | | /** @brief Send the packets to tell our friends what our DHT public key is. |
1429 | | * |
1430 | | * if onion_dht_both is 0, use only the onion to send the packet. |
1431 | | * if it is 1, use only the dht. |
1432 | | * if it is something else, use both. |
1433 | | * |
1434 | | * return the number of packets sent on success |
1435 | | * return -1 on failure. |
1436 | | */ |
1437 | | non_null() |
1438 | | static int send_dhtpk_announce(Onion_Client *onion_c, uint16_t friend_num, uint8_t onion_dht_both) |
1439 | 14.5k | { |
1440 | 14.5k | if (friend_num >= onion_c->num_friends) { |
1441 | 0 | return -1; |
1442 | 0 | } |
1443 | | |
1444 | 14.5k | uint8_t data[DHTPK_DATA_MAX_LENGTH]; |
1445 | 14.5k | data[0] = ONION_DATA_DHTPK; |
1446 | 14.5k | const uint64_t no_replay = mono_time_get(onion_c->mono_time); |
1447 | 14.5k | net_pack_u64(data + 1, no_replay); |
1448 | 14.5k | memcpy(data + 1 + sizeof(uint64_t), dht_get_self_public_key(onion_c->dht), CRYPTO_PUBLIC_KEY_SIZE); |
1449 | 14.5k | Node_format nodes[MAX_SENT_NODES]; |
1450 | 14.5k | const uint16_t num_relays = copy_connected_tcp_relays(onion_c->c, nodes, MAX_SENT_NODES / 2); |
1451 | 14.5k | uint16_t num_nodes = closelist_nodes(onion_c->dht, &nodes[num_relays], MAX_SENT_NODES - num_relays); |
1452 | 14.5k | num_nodes += num_relays; |
1453 | 14.5k | int nodes_len = 0; |
1454 | | |
1455 | 14.5k | if (num_nodes != 0) { |
1456 | 13.6k | nodes_len = pack_nodes(onion_c->logger, data + DHTPK_DATA_MIN_LENGTH, DHTPK_DATA_MAX_LENGTH - DHTPK_DATA_MIN_LENGTH, |
1457 | 13.6k | nodes, num_nodes); |
1458 | | |
1459 | 13.6k | if (nodes_len <= 0) { |
1460 | 0 | return -1; |
1461 | 0 | } |
1462 | 13.6k | } |
1463 | | |
1464 | 14.5k | int num1 = -1; |
1465 | 14.5k | int num2 = -1; |
1466 | | |
1467 | 14.5k | if (onion_dht_both != 1) { |
1468 | 5.61k | num1 = send_onion_data(onion_c, friend_num, data, DHTPK_DATA_MIN_LENGTH + nodes_len); |
1469 | 5.61k | } |
1470 | | |
1471 | 14.5k | if (onion_dht_both != 0) { |
1472 | 8.96k | num2 = send_dht_dhtpk(onion_c, friend_num, data, DHTPK_DATA_MIN_LENGTH + nodes_len); |
1473 | 8.96k | } |
1474 | | |
1475 | 14.5k | if (num1 == -1) { |
1476 | 13.1k | return num2; |
1477 | 13.1k | } |
1478 | | |
1479 | 1.47k | if (num2 == -1) { |
1480 | 1.47k | return num1; |
1481 | 1.47k | } |
1482 | | |
1483 | 0 | return num1 + num2; |
1484 | 1.47k | } |
1485 | | |
1486 | | /** @brief Get the friend_num of a friend. |
1487 | | * |
1488 | | * return -1 on failure. |
1489 | | * return friend number on success. |
1490 | | */ |
1491 | | int onion_friend_num(const Onion_Client *onion_c, const uint8_t *public_key) |
1492 | 7.12k | { |
1493 | 16.4k | for (unsigned int i = 0; i < onion_c->num_friends; ++i) { |
1494 | 13.8k | if (!onion_c->friends_list[i].is_valid) { |
1495 | 237 | continue; |
1496 | 237 | } |
1497 | | |
1498 | 13.6k | if (pk_equal(public_key, onion_c->friends_list[i].real_public_key)) { |
1499 | 4.54k | return i; |
1500 | 4.54k | } |
1501 | 13.6k | } |
1502 | | |
1503 | 2.58k | return -1; |
1504 | 7.12k | } |
1505 | | |
1506 | | /** @brief Set the size of the friend list to num. |
1507 | | * |
1508 | | * @retval -1 if mem_vrealloc fails. |
1509 | | * @retval 0 if it succeeds. |
1510 | | */ |
1511 | | non_null() |
1512 | | static int realloc_onion_friends(Onion_Client *onion_c, uint32_t num) |
1513 | 5.91k | { |
1514 | 5.91k | if (num == 0) { |
1515 | 3.41k | mem_delete(onion_c->mem, onion_c->friends_list); |
1516 | 3.41k | onion_c->friends_list = nullptr; |
1517 | 3.41k | return 0; |
1518 | 3.41k | } |
1519 | | |
1520 | 2.49k | Onion_Friend *newonion_friends = (Onion_Friend *)mem_vrealloc(onion_c->mem, onion_c->friends_list, num, sizeof(Onion_Friend)); |
1521 | | |
1522 | 2.49k | if (newonion_friends == nullptr) { |
1523 | 15 | return -1; |
1524 | 15 | } |
1525 | | |
1526 | 2.48k | onion_c->friends_list = newonion_friends; |
1527 | 2.48k | return 0; |
1528 | 2.49k | } |
1529 | | |
1530 | | /** @brief Add a friend who we want to connect to. |
1531 | | * |
1532 | | * return -1 on failure. |
1533 | | * return the friend number on success or if the friend was already added. |
1534 | | */ |
1535 | | int onion_addfriend(Onion_Client *onion_c, const uint8_t *public_key) |
1536 | 2.42k | { |
1537 | 2.42k | const int num = onion_friend_num(onion_c, public_key); |
1538 | | |
1539 | 2.42k | if (num != -1) { |
1540 | 0 | return num; |
1541 | 0 | } |
1542 | | |
1543 | 2.42k | unsigned int index = -1; |
1544 | | |
1545 | 5.46k | for (unsigned int i = 0; i < onion_c->num_friends; ++i) { |
1546 | 3.19k | if (!onion_c->friends_list[i].is_valid) { |
1547 | 154 | index = i; |
1548 | 154 | break; |
1549 | 154 | } |
1550 | 3.19k | } |
1551 | | |
1552 | 2.42k | if (index == (uint32_t) -1) { |
1553 | 2.27k | if (realloc_onion_friends(onion_c, onion_c->num_friends + 1) == -1) { |
1554 | 15 | return -1; |
1555 | 15 | } |
1556 | | |
1557 | 2.25k | index = onion_c->num_friends; |
1558 | 2.25k | onion_c->friends_list[onion_c->num_friends] = empty_onion_friend; |
1559 | 2.25k | ++onion_c->num_friends; |
1560 | 2.25k | } |
1561 | | |
1562 | 2.41k | onion_c->friends_list[index].is_valid = true; |
1563 | 2.41k | memcpy(onion_c->friends_list[index].real_public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); |
1564 | 2.41k | crypto_new_keypair(onion_c->rng, onion_c->friends_list[index].temp_public_key, |
1565 | 2.41k | onion_c->friends_list[index].temp_secret_key); |
1566 | 2.41k | return index; |
1567 | 2.42k | } |
1568 | | |
1569 | | /** @brief Delete a friend. |
1570 | | * |
1571 | | * return -1 on failure. |
1572 | | * return the deleted friend number on success. |
1573 | | */ |
1574 | | int onion_delfriend(Onion_Client *onion_c, int friend_num) |
1575 | 1.69k | { |
1576 | 1.69k | if ((uint32_t)friend_num >= onion_c->num_friends) { |
1577 | 0 | return -1; |
1578 | 0 | } |
1579 | | |
1580 | | #if 0 |
1581 | | |
1582 | | if (onion_c->friends_list[friend_num].know_dht_public_key) { |
1583 | | dht_delfriend(onion_c->dht, onion_c->friends_list[friend_num].dht_public_key, 0); |
1584 | | } |
1585 | | |
1586 | | #endif /* 0 */ |
1587 | | |
1588 | 1.69k | crypto_memzero(&onion_c->friends_list[friend_num], sizeof(Onion_Friend)); |
1589 | 1.69k | unsigned int i; |
1590 | | |
1591 | 3.23k | for (i = onion_c->num_friends; i != 0; --i) { |
1592 | 2.53k | if (onion_c->friends_list[i - 1].is_valid) { |
1593 | 996 | break; |
1594 | 996 | } |
1595 | 2.53k | } |
1596 | | |
1597 | 1.69k | if (onion_c->num_friends != i) { |
1598 | 922 | onion_c->num_friends = i; |
1599 | 922 | realloc_onion_friends(onion_c, onion_c->num_friends); |
1600 | 922 | } |
1601 | | |
1602 | 1.69k | return friend_num; |
1603 | 1.69k | } |
1604 | | |
1605 | | /** @brief Set the function for this friend that will be callbacked with object and number |
1606 | | * when that friend gives us one of the TCP relays they are connected to. |
1607 | | * |
1608 | | * object and number will be passed as argument to this function. |
1609 | | * |
1610 | | * return -1 on failure. |
1611 | | * return 0 on success. |
1612 | | */ |
1613 | | int recv_tcp_relay_handler(Onion_Client *onion_c, int friend_num, |
1614 | | recv_tcp_relay_cb *callback, void *object, uint32_t number) |
1615 | 2.41k | { |
1616 | 2.41k | if ((uint32_t)friend_num >= onion_c->num_friends) { |
1617 | 0 | return -1; |
1618 | 0 | } |
1619 | | |
1620 | 2.41k | onion_c->friends_list[friend_num].tcp_relay_node_callback = callback; |
1621 | 2.41k | onion_c->friends_list[friend_num].tcp_relay_node_callback_object = object; |
1622 | 2.41k | onion_c->friends_list[friend_num].tcp_relay_node_callback_number = number; |
1623 | 2.41k | return 0; |
1624 | 2.41k | } |
1625 | | |
1626 | | /** @brief Set the function for this friend that will be callbacked with object and number |
1627 | | * when that friend gives us their DHT temporary public key. |
1628 | | * |
1629 | | * object and number will be passed as argument to this function. |
1630 | | * |
1631 | | * return -1 on failure. |
1632 | | * return 0 on success. |
1633 | | */ |
1634 | | int onion_dht_pk_callback(Onion_Client *onion_c, int friend_num, |
1635 | | onion_dht_pk_cb *function, void *object, uint32_t number) |
1636 | 2.41k | { |
1637 | 2.41k | if ((uint32_t)friend_num >= onion_c->num_friends) { |
1638 | 0 | return -1; |
1639 | 0 | } |
1640 | | |
1641 | 2.41k | onion_c->friends_list[friend_num].dht_pk_callback = function; |
1642 | 2.41k | onion_c->friends_list[friend_num].dht_pk_callback_object = object; |
1643 | 2.41k | onion_c->friends_list[friend_num].dht_pk_callback_number = number; |
1644 | 2.41k | return 0; |
1645 | 2.41k | } |
1646 | | |
1647 | | /** @brief Set a friend's DHT public key. |
1648 | | * |
1649 | | * return -1 on failure. |
1650 | | * return 0 on success. |
1651 | | */ |
1652 | | int onion_set_friend_dht_pubkey(Onion_Client *onion_c, int friend_num, const uint8_t *dht_key) |
1653 | 3.10k | { |
1654 | 3.10k | if ((uint32_t)friend_num >= onion_c->num_friends) { |
1655 | 0 | return -1; |
1656 | 0 | } |
1657 | | |
1658 | 3.10k | if (!onion_c->friends_list[friend_num].is_valid) { |
1659 | 0 | return -1; |
1660 | 0 | } |
1661 | | |
1662 | 3.10k | if (onion_c->friends_list[friend_num].know_dht_public_key) { |
1663 | 1.40k | if (pk_equal(dht_key, onion_c->friends_list[friend_num].dht_public_key)) { |
1664 | 1.39k | return -1; |
1665 | 1.39k | } |
1666 | 1.40k | } |
1667 | | |
1668 | 1.71k | onion_c->friends_list[friend_num].know_dht_public_key = true; |
1669 | 1.71k | memcpy(onion_c->friends_list[friend_num].dht_public_key, dht_key, CRYPTO_PUBLIC_KEY_SIZE); |
1670 | | |
1671 | 1.71k | return 0; |
1672 | 3.10k | } |
1673 | | |
1674 | | /** @brief Copy friends DHT public key into dht_key. |
1675 | | * |
1676 | | * return 0 on failure (no key copied). |
1677 | | * return 1 on success (key copied). |
1678 | | */ |
1679 | | unsigned int onion_getfriend_dht_pubkey(const Onion_Client *onion_c, int friend_num, uint8_t *dht_key) |
1680 | 1 | { |
1681 | 1 | if ((uint32_t)friend_num >= onion_c->num_friends) { |
1682 | 0 | return 0; |
1683 | 0 | } |
1684 | | |
1685 | 1 | if (!onion_c->friends_list[friend_num].is_valid) { |
1686 | 0 | return 0; |
1687 | 0 | } |
1688 | | |
1689 | 1 | if (!onion_c->friends_list[friend_num].know_dht_public_key) { |
1690 | 0 | return 0; |
1691 | 0 | } |
1692 | | |
1693 | 1 | memcpy(dht_key, onion_c->friends_list[friend_num].dht_public_key, CRYPTO_PUBLIC_KEY_SIZE); |
1694 | 1 | return 1; |
1695 | 1 | } |
1696 | | |
1697 | | /** @brief Get the ip of friend friendnum and put it in ip_port |
1698 | | * |
1699 | | * @retval -1 if public_key does NOT refer to a friend |
1700 | | * @retval 0 if public_key refers to a friend and we failed to find the friend (yet) |
1701 | | * @retval 1 if public_key refers to a friend and we found them |
1702 | | */ |
1703 | | int onion_getfriendip(const Onion_Client *onion_c, int friend_num, IP_Port *ip_port) |
1704 | 1 | { |
1705 | 1 | uint8_t dht_public_key[CRYPTO_PUBLIC_KEY_SIZE]; |
1706 | | |
1707 | 1 | if (onion_getfriend_dht_pubkey(onion_c, friend_num, dht_public_key) == 0) { |
1708 | 0 | return -1; |
1709 | 0 | } |
1710 | | |
1711 | 1 | return dht_getfriendip(onion_c->dht, dht_public_key, ip_port); |
1712 | 1 | } |
1713 | | |
1714 | | |
1715 | | /** @brief Set if friend is online or not. |
1716 | | * |
1717 | | * NOTE: This function is there and should be used so that we don't send |
1718 | | * useless packets to the friend if they are online. |
1719 | | * |
1720 | | * return -1 on failure. |
1721 | | * return 0 on success. |
1722 | | */ |
1723 | | int onion_set_friend_online(Onion_Client *onion_c, int friend_num, bool is_online) |
1724 | 1.77k | { |
1725 | 1.77k | if ((uint32_t)friend_num >= onion_c->num_friends) { |
1726 | 0 | return -1; |
1727 | 0 | } |
1728 | | |
1729 | 1.77k | onion_c->friends_list[friend_num].is_online = is_online; |
1730 | | |
1731 | | /* This should prevent some clock related issues */ |
1732 | 1.77k | if (!is_online) { |
1733 | 105 | onion_c->friends_list[friend_num].last_noreplay = 0; |
1734 | 105 | onion_c->friends_list[friend_num].run_count = 0; |
1735 | 105 | } |
1736 | | |
1737 | 1.77k | return 0; |
1738 | 1.77k | } |
1739 | | |
1740 | | non_null() |
1741 | | static void populate_path_nodes(Onion_Client *onion_c) |
1742 | 34.2k | { |
1743 | 34.2k | Node_format node_list[MAX_FRIEND_CLIENTS]; |
1744 | | |
1745 | 34.2k | const unsigned int num_nodes = randfriends_nodes(onion_c->dht, node_list, MAX_FRIEND_CLIENTS); |
1746 | | |
1747 | 123k | for (unsigned int i = 0; i < num_nodes; ++i) { |
1748 | 89.3k | onion_add_path_node(onion_c, &node_list[i].ip_port, node_list[i].public_key); |
1749 | 89.3k | } |
1750 | 34.2k | } |
1751 | | |
1752 | | /* How often we ping new friends per node */ |
1753 | 34.4k | #define ANNOUNCE_FRIEND_NEW_INTERVAL 3 |
1754 | | |
1755 | | /* How long we consider a friend new based on the value of their run_count */ |
1756 | 36.8k | #define ANNOUNCE_FRIEND_RUN_COUNT_BEGINNING 5 |
1757 | | |
1758 | | /* How often we try to re-populate the nodes lists if we don't meet a minimum threshhold of nodes */ |
1759 | 2.88k | #define ANNOUNCE_POPULATE_TIMEOUT (60 * 10) |
1760 | | |
1761 | | /* The max time between lookup requests for a friend per node */ |
1762 | 2.36k | #define ANNOUNCE_FRIEND_MAX_INTERVAL (60 * 60) |
1763 | | |
1764 | | /* Max exponent when calculating the announce request interval */ |
1765 | 2.36k | #define MAX_RUN_COUNT_EXPONENT 12 |
1766 | | |
1767 | | non_null() |
1768 | | static void do_friend(Onion_Client *onion_c, uint16_t friendnum) |
1769 | 37.0k | { |
1770 | 37.0k | if (friendnum >= onion_c->num_friends) { |
1771 | 0 | return; |
1772 | 0 | } |
1773 | | |
1774 | 37.0k | Onion_Friend *o_friend = &onion_c->friends_list[friendnum]; |
1775 | | |
1776 | 37.0k | if (!o_friend->is_valid) { |
1777 | 245 | return; |
1778 | 245 | } |
1779 | | |
1780 | 36.8k | uint32_t interval; |
1781 | 36.8k | const uint64_t tm = mono_time_get(onion_c->mono_time); |
1782 | 36.8k | const bool friend_is_new = o_friend->run_count <= ANNOUNCE_FRIEND_RUN_COUNT_BEGINNING; |
1783 | | |
1784 | 36.8k | if (!friend_is_new) { |
1785 | | // how often we ping a node for a friend depends on how many times we've already tried. |
1786 | | // the interval increases exponentially, as the longer a friend has been offline, the less |
1787 | | // likely the case is that they're online and failed to find us |
1788 | 2.36k | const uint32_t c = 1 << min_u32(MAX_RUN_COUNT_EXPONENT, o_friend->run_count - 2); |
1789 | 2.36k | interval = min_u32(c, ANNOUNCE_FRIEND_MAX_INTERVAL); |
1790 | 34.4k | } else { |
1791 | 34.4k | interval = ANNOUNCE_FRIEND_NEW_INTERVAL; |
1792 | 34.4k | } |
1793 | | |
1794 | 36.8k | if (o_friend->is_online) { |
1795 | 27.3k | return; |
1796 | 27.3k | } |
1797 | | |
1798 | 9.47k | assert(interval >= ANNOUNCE_FRIEND_NEW_INTERVAL); // an int overflow would be devastating |
1799 | | |
1800 | | /* send packets to friend telling them our DHT public key. */ |
1801 | 9.47k | if (mono_time_is_timeout(onion_c->mono_time, onion_c->friends_list[friendnum].last_dht_pk_onion_sent, |
1802 | 9.47k | ONION_DHTPK_SEND_INTERVAL)) { |
1803 | 5.61k | if (send_dhtpk_announce(onion_c, friendnum, 0) >= 1) { |
1804 | 1.43k | onion_c->friends_list[friendnum].last_dht_pk_onion_sent = tm; |
1805 | 1.43k | } |
1806 | 5.61k | } |
1807 | | |
1808 | 9.47k | if (mono_time_is_timeout(onion_c->mono_time, onion_c->friends_list[friendnum].last_dht_pk_dht_sent, |
1809 | 9.47k | DHT_DHTPK_SEND_INTERVAL)) { |
1810 | 8.96k | if (send_dhtpk_announce(onion_c, friendnum, 1) >= 1) { |
1811 | 229 | onion_c->friends_list[friendnum].last_dht_pk_dht_sent = tm; |
1812 | 229 | } |
1813 | 8.96k | } |
1814 | | |
1815 | 9.47k | uint16_t count = 0; // number of alive path nodes |
1816 | | |
1817 | 9.47k | Onion_Node *node_list = o_friend->clients_list; |
1818 | | |
1819 | 85.3k | for (unsigned i = 0; i < MAX_ONION_CLIENTS; ++i) { |
1820 | 75.8k | if (onion_node_timed_out(&node_list[i], onion_c->mono_time)) { |
1821 | 47.2k | continue; |
1822 | 47.2k | } |
1823 | | |
1824 | 28.5k | ++count; |
1825 | | |
1826 | | // we don't want new nodes to be pinged immediately |
1827 | 28.5k | if (node_list[i].last_pinged == 0) { |
1828 | 5.90k | node_list[i].last_pinged = tm; |
1829 | 5.90k | continue; |
1830 | 5.90k | } |
1831 | | |
1832 | | // node hasn't responded in a while so we skip it |
1833 | 22.6k | if (node_list[i].pings_since_last_response >= ONION_NODE_MAX_PINGS) { |
1834 | 3.62k | continue; |
1835 | 3.62k | } |
1836 | | |
1837 | | // space requests out between nodes |
1838 | 19.0k | if (!mono_time_is_timeout(onion_c->mono_time, o_friend->time_last_pinged, interval / (MAX_ONION_CLIENTS / 2))) { |
1839 | 3.69k | continue; |
1840 | 3.69k | } |
1841 | | |
1842 | 15.3k | if (!mono_time_is_timeout(onion_c->mono_time, node_list[i].last_pinged, interval)) { |
1843 | 11.8k | continue; |
1844 | 11.8k | } |
1845 | | |
1846 | 3.48k | if (client_send_announce_request(onion_c, friendnum + 1, &node_list[i].ip_port, |
1847 | 3.48k | node_list[i].public_key, nullptr, -1) == 0) { |
1848 | 3.43k | node_list[i].last_pinged = tm; |
1849 | 3.43k | o_friend->time_last_pinged = tm; |
1850 | 3.43k | ++node_list[i].pings_since_last_response; |
1851 | 3.43k | ++o_friend->pings; |
1852 | | |
1853 | 3.43k | if (o_friend->pings % (MAX_ONION_CLIENTS / 2) == 0) { |
1854 | 801 | ++o_friend->run_count; |
1855 | 801 | } |
1856 | 3.43k | } |
1857 | 3.48k | } |
1858 | | |
1859 | 9.47k | if (count == MAX_ONION_CLIENTS) { |
1860 | 1.40k | if (!friend_is_new) { |
1861 | 571 | o_friend->last_populated = tm; |
1862 | 571 | } |
1863 | | |
1864 | 1.40k | return; |
1865 | 1.40k | } |
1866 | | |
1867 | | // check if path nodes list for this friend needs to be repopulated |
1868 | 8.07k | if (count <= MAX_ONION_CLIENTS / 2 |
1869 | 8.07k | || mono_time_is_timeout(onion_c->mono_time, o_friend->last_populated, ANNOUNCE_POPULATE_TIMEOUT)) { |
1870 | 6.24k | const uint16_t num_nodes = min_u16(onion_c->path_nodes_index, MAX_PATH_NODES); |
1871 | 6.24k | const uint16_t n = min_u16(num_nodes, MAX_PATH_NODES / 4); |
1872 | | |
1873 | 6.24k | if (n == 0) { |
1874 | 0 | return; |
1875 | 0 | } |
1876 | | |
1877 | 6.24k | o_friend->last_populated = tm; |
1878 | | |
1879 | 26.4k | for (uint16_t i = 0; i < n; ++i) { |
1880 | 20.2k | const uint32_t num = random_range_u32(onion_c->rng, num_nodes); |
1881 | 20.2k | client_send_announce_request(onion_c, friendnum + 1, &onion_c->path_nodes[num].ip_port, |
1882 | 20.2k | onion_c->path_nodes[num].public_key, nullptr, -1); |
1883 | 20.2k | } |
1884 | 6.24k | } |
1885 | 8.07k | } |
1886 | | |
1887 | | |
1888 | | /** Function to call when onion data packet with contents beginning with byte is received. */ |
1889 | | void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_handler_cb *cb, void *object) |
1890 | 10.1k | { |
1891 | 10.1k | onion_c->onion_data_handlers[byte].function = cb; |
1892 | 10.1k | onion_c->onion_data_handlers[byte].object = object; |
1893 | 10.1k | } |
1894 | | |
1895 | | void onion_group_announce_register(Onion_Client *onion_c, onion_group_announce_cb *func, void *user_data) |
1896 | 6.28k | { |
1897 | 6.28k | onion_c->group_announce_response = func; |
1898 | 6.28k | onion_c->group_announce_response_user_data = user_data; |
1899 | 6.28k | } |
1900 | | |
1901 | 88.2k | #define ANNOUNCE_INTERVAL_NOT_ANNOUNCED 3 |
1902 | 82.0k | #define ANNOUNCE_INTERVAL_ANNOUNCED ONION_NODE_PING_INTERVAL |
1903 | | |
1904 | 94.4k | #define TIME_TO_STABLE (ONION_NODE_PING_INTERVAL * 6) |
1905 | 6.13k | #define ANNOUNCE_INTERVAL_STABLE (ONION_NODE_PING_INTERVAL * 8) |
1906 | | |
1907 | | non_null() |
1908 | | static bool key_list_contains(const uint8_t *const *keys, uint16_t keys_size, const uint8_t *public_key) |
1909 | 92.1k | { |
1910 | 143k | for (uint16_t i = 0; i < keys_size; ++i) { |
1911 | 109k | if (memeq(keys[i], CRYPTO_PUBLIC_KEY_SIZE, public_key, CRYPTO_PUBLIC_KEY_SIZE)) { |
1912 | 57.5k | return true; |
1913 | 57.5k | } |
1914 | 109k | } |
1915 | | |
1916 | 34.5k | return false; |
1917 | 92.1k | } |
1918 | | |
1919 | | non_null() |
1920 | | static void do_announce(Onion_Client *onion_c) |
1921 | 34.2k | { |
1922 | 34.2k | unsigned int count = 0; |
1923 | 34.2k | Onion_Node *node_list = onion_c->clients_announce_list; |
1924 | | |
1925 | 445k | for (unsigned int i = 0; i < MAX_ONION_CLIENTS_ANNOUNCE; ++i) { |
1926 | 411k | if (onion_node_timed_out(&node_list[i], onion_c->mono_time)) { |
1927 | 314k | continue; |
1928 | 314k | } |
1929 | | |
1930 | 96.9k | ++count; |
1931 | | |
1932 | | /* Don't announce ourselves the first time this is run to new peers */ |
1933 | 96.9k | if (node_list[i].last_pinged == 0) { |
1934 | 5.08k | node_list[i].last_pinged = 1; |
1935 | 5.08k | continue; |
1936 | 5.08k | } |
1937 | | |
1938 | 91.8k | if (node_list[i].pings_since_last_response >= ONION_NODE_MAX_PINGS) { |
1939 | 3.58k | continue; |
1940 | 3.58k | } |
1941 | | |
1942 | | |
1943 | 88.2k | unsigned int interval = ANNOUNCE_INTERVAL_NOT_ANNOUNCED; |
1944 | | |
1945 | 88.2k | if (node_list[i].is_stored != 0 |
1946 | 88.2k | && path_exists(onion_c->mono_time, &onion_c->onion_paths_self, node_list[i].path_used)) { |
1947 | 82.0k | interval = ANNOUNCE_INTERVAL_ANNOUNCED; |
1948 | | |
1949 | 82.0k | const uint32_t pathnum = node_list[i].path_used % NUMBER_ONION_PATHS; |
1950 | | |
1951 | | /* A node/path is considered "stable", and can be pinged less |
1952 | | * aggressively, if it has survived for at least TIME_TO_STABLE |
1953 | | * and the latest packets sent to it are not timing out. |
1954 | | */ |
1955 | 82.0k | if (mono_time_is_timeout(onion_c->mono_time, node_list[i].added_time, TIME_TO_STABLE) |
1956 | 82.0k | && !(node_list[i].pings_since_last_response > 0 |
1957 | 12.2k | && mono_time_is_timeout(onion_c->mono_time, node_list[i].last_pinged, ONION_NODE_TIMEOUT)) |
1958 | 82.0k | && mono_time_is_timeout(onion_c->mono_time, onion_c->onion_paths_self.path_creation_time[pathnum], TIME_TO_STABLE) |
1959 | 82.0k | && !(onion_c->onion_paths_self.last_path_used_times[pathnum] > 0 |
1960 | 6.41k | && mono_time_is_timeout(onion_c->mono_time, onion_c->onion_paths_self.last_path_used[pathnum], ONION_PATH_TIMEOUT))) { |
1961 | 6.13k | interval = ANNOUNCE_INTERVAL_STABLE; |
1962 | 6.13k | } |
1963 | 82.0k | } |
1964 | | |
1965 | 88.2k | if (mono_time_is_timeout(onion_c->mono_time, node_list[i].last_pinged, interval) |
1966 | 88.2k | || mono_time_is_timeout(onion_c->mono_time, onion_c->last_announce, ONION_NODE_PING_INTERVAL)) { |
1967 | 8.79k | uint32_t path_to_use = node_list[i].path_used; |
1968 | | |
1969 | 8.79k | if (node_list[i].pings_since_last_response == ONION_NODE_MAX_PINGS - 1 |
1970 | 8.79k | && mono_time_is_timeout(onion_c->mono_time, node_list[i].added_time, TIME_TO_STABLE)) { |
1971 | | /* Last chance for a long-lived node - try a random path */ |
1972 | 126 | path_to_use = -1; |
1973 | 126 | } |
1974 | | |
1975 | 8.79k | if (client_send_announce_request(onion_c, 0, &node_list[i].ip_port, node_list[i].public_key, |
1976 | 8.79k | node_list[i].ping_id, path_to_use) == 0) { |
1977 | 8.64k | node_list[i].last_pinged = mono_time_get(onion_c->mono_time); |
1978 | 8.64k | ++node_list[i].pings_since_last_response; |
1979 | 8.64k | onion_c->last_announce = mono_time_get(onion_c->mono_time); |
1980 | 8.64k | } |
1981 | 8.79k | } |
1982 | 88.2k | } |
1983 | | |
1984 | 34.2k | if (count == MAX_ONION_CLIENTS_ANNOUNCE) { |
1985 | 4.86k | onion_c->last_populated = mono_time_get(onion_c->mono_time); |
1986 | 4.86k | return; |
1987 | 4.86k | } |
1988 | | |
1989 | | // check if list needs to be re-populated |
1990 | 29.3k | if (count <= MAX_ONION_CLIENTS_ANNOUNCE / 2 |
1991 | 29.3k | || mono_time_is_timeout(onion_c->mono_time, onion_c->last_populated, ANNOUNCE_POPULATE_TIMEOUT)) { |
1992 | 29.0k | uint16_t num_nodes; |
1993 | 29.0k | const Node_format *path_nodes; |
1994 | | |
1995 | 29.0k | if (onion_c->path_nodes_index == 0) { |
1996 | 14.4k | num_nodes = min_u16(onion_c->path_nodes_index_bs, MAX_PATH_NODES); |
1997 | 14.4k | path_nodes = onion_c->path_nodes_bs; |
1998 | 14.6k | } else { |
1999 | 14.6k | num_nodes = min_u16(onion_c->path_nodes_index, MAX_PATH_NODES); |
2000 | 14.6k | path_nodes = onion_c->path_nodes; |
2001 | 14.6k | } |
2002 | | |
2003 | 29.0k | if (num_nodes == 0) { |
2004 | 13.7k | return; |
2005 | 13.7k | } |
2006 | | |
2007 | | // Don't send announces to the same node twice. If we don't have many nodes, |
2008 | | // the random selection below may have overlaps. This ensures that we deduplicate |
2009 | | // nodes before sending packets to save some bandwidth. |
2010 | | // |
2011 | | // TODO(iphydf): Figure out why on esp32, this is necessary for the onion |
2012 | | // connection to succeed. This is an optimisation and shouldn't be necessary. |
2013 | 15.3k | const uint8_t *targets[MAX_ONION_CLIENTS_ANNOUNCE / 2]; |
2014 | 15.3k | unsigned int targets_count = 0; |
2015 | | |
2016 | 107k | for (unsigned int i = 0; i < MAX_ONION_CLIENTS_ANNOUNCE / 2; ++i) { |
2017 | 92.1k | const uint32_t num = random_range_u32(onion_c->rng, num_nodes); |
2018 | 92.1k | const Node_format *target = &path_nodes[num]; |
2019 | | |
2020 | 92.1k | if (!key_list_contains(targets, targets_count, target->public_key)) { |
2021 | 34.5k | client_send_announce_request(onion_c, 0, &target->ip_port, target->public_key, nullptr, -1); |
2022 | | |
2023 | 34.5k | targets[targets_count] = target->public_key; |
2024 | 34.5k | ++targets_count; |
2025 | 34.5k | assert(targets_count <= MAX_ONION_CLIENTS_ANNOUNCE / 2); |
2026 | 57.5k | } else { |
2027 | 57.5k | Ip_Ntoa ip_str; |
2028 | 57.5k | LOGGER_TRACE(onion_c->logger, "not sending repeated announce request to %s:%d", |
2029 | 57.5k | net_ip_ntoa(&target->ip_port.ip, &ip_str), net_ntohs(target->ip_port.port)); |
2030 | 57.5k | } |
2031 | 92.1k | } |
2032 | 15.3k | } |
2033 | 29.3k | } |
2034 | | |
2035 | | /** |
2036 | | * @retval false if we are not connected to the network. |
2037 | | * @retval true if we are. |
2038 | | */ |
2039 | | non_null() |
2040 | | static bool onion_isconnected(Onion_Client *onion_c) |
2041 | 36.9k | { |
2042 | 36.9k | unsigned int live = 0; |
2043 | 36.9k | unsigned int announced = 0; |
2044 | | |
2045 | 36.9k | if (mono_time_is_timeout(onion_c->mono_time, onion_c->last_packet_recv, ONION_OFFLINE_TIMEOUT)) { |
2046 | 18.5k | LOGGER_TRACE(onion_c->logger, "onion is NOT connected: last packet received at %llu (timeout=%u)", |
2047 | 18.5k | (unsigned long long)onion_c->last_packet_recv, ONION_OFFLINE_TIMEOUT); |
2048 | 18.5k | onion_c->last_populated = 0; |
2049 | 18.5k | return false; |
2050 | 18.5k | } |
2051 | | |
2052 | 18.3k | if (onion_c->path_nodes_index == 0) { |
2053 | 0 | LOGGER_TRACE(onion_c->logger, "onion is NOT connected: no path nodes available"); |
2054 | 0 | onion_c->last_populated = 0; |
2055 | 0 | return false; |
2056 | 0 | } |
2057 | | |
2058 | 238k | for (unsigned int i = 0; i < MAX_ONION_CLIENTS_ANNOUNCE; ++i) { |
2059 | 220k | if (!onion_node_timed_out(&onion_c->clients_announce_list[i], onion_c->mono_time)) { |
2060 | 96.9k | ++live; |
2061 | | |
2062 | 96.9k | if (onion_c->clients_announce_list[i].is_stored != 0) { |
2063 | 86.2k | ++announced; |
2064 | 86.2k | } |
2065 | 96.9k | } |
2066 | 220k | } |
2067 | | |
2068 | 18.3k | unsigned int pnodes = onion_c->path_nodes_index; |
2069 | | |
2070 | 18.3k | if (pnodes > MAX_ONION_CLIENTS_ANNOUNCE) { |
2071 | 5.85k | pnodes = MAX_ONION_CLIENTS_ANNOUNCE; |
2072 | 5.85k | } |
2073 | | |
2074 | | /* Consider ourselves online if we are announced to half or more nodes |
2075 | | * we are connected to */ |
2076 | 18.3k | if (live != 0 && announced != 0) { |
2077 | 15.9k | if ((live / 2) <= announced && (pnodes / 2) <= live) { |
2078 | 15.4k | LOGGER_TRACE(onion_c->logger, "onion is connected: %u live nodes, %u announced, %d path nodes", |
2079 | 15.4k | live, announced, pnodes); |
2080 | 15.4k | return true; |
2081 | 15.4k | } |
2082 | 15.9k | } |
2083 | | |
2084 | 2.93k | onion_c->last_populated = 0; |
2085 | | |
2086 | 2.93k | LOGGER_TRACE(onion_c->logger, "onion is NOT connected: %u live nodes, %u announced, %d path nodes", |
2087 | 2.93k | live, announced, pnodes); |
2088 | 2.93k | return false; |
2089 | 18.3k | } |
2090 | | |
2091 | | non_null() |
2092 | | static void reset_friend_run_counts(Onion_Client *onion_c) |
2093 | 1.13k | { |
2094 | 2.50k | for (uint16_t i = 0; i < onion_c->num_friends; ++i) { |
2095 | 1.36k | Onion_Friend *o_friend = &onion_c->friends_list[i]; |
2096 | | |
2097 | 1.36k | if (o_friend->is_valid) { |
2098 | 1.36k | o_friend->run_count = 0; |
2099 | 1.36k | } |
2100 | 1.36k | } |
2101 | 1.13k | } |
2102 | | |
2103 | 362k | #define ONION_CONNECTION_SECONDS 3 |
2104 | 15.4k | #define ONION_CONNECTED_TIMEOUT 10 |
2105 | | |
2106 | | Onion_Connection_Status onion_connection_status(const Onion_Client *onion_c) |
2107 | 273k | { |
2108 | 273k | if (onion_c->onion_connected >= ONION_CONNECTION_SECONDS) { |
2109 | 104k | if (onion_c->udp_connected) { |
2110 | 0 | return ONION_CONNECTION_STATUS_UDP; |
2111 | 0 | } |
2112 | | |
2113 | 104k | return ONION_CONNECTION_STATUS_TCP; |
2114 | 104k | } |
2115 | | |
2116 | 169k | return ONION_CONNECTION_STATUS_NONE; |
2117 | 273k | } |
2118 | | |
2119 | | void do_onion_client(Onion_Client *onion_c) |
2120 | 218k | { |
2121 | 218k | if (onion_c->last_run == mono_time_get(onion_c->mono_time)) { |
2122 | 181k | return; |
2123 | 181k | } |
2124 | | |
2125 | 36.9k | if (mono_time_is_timeout(onion_c->mono_time, onion_c->first_run, ONION_CONNECTION_SECONDS)) { |
2126 | 34.2k | populate_path_nodes(onion_c); |
2127 | 34.2k | do_announce(onion_c); |
2128 | 34.2k | } |
2129 | | |
2130 | 36.9k | if (onion_isconnected(onion_c)) { |
2131 | 15.4k | if (mono_time_is_timeout(onion_c->mono_time, onion_c->last_time_connected, ONION_CONNECTED_TIMEOUT)) { |
2132 | 1.13k | reset_friend_run_counts(onion_c); |
2133 | 1.13k | } |
2134 | | |
2135 | 15.4k | onion_c->last_time_connected = mono_time_get(onion_c->mono_time); |
2136 | | |
2137 | 15.4k | if (onion_c->onion_connected < ONION_CONNECTION_SECONDS * 2) { |
2138 | 6.40k | ++onion_c->onion_connected; |
2139 | 6.40k | } |
2140 | 21.4k | } else { |
2141 | 21.4k | if (onion_c->onion_connected != 0) { |
2142 | 141 | --onion_c->onion_connected; |
2143 | 141 | } |
2144 | 21.4k | } |
2145 | | |
2146 | 36.9k | onion_c->udp_connected = dht_non_lan_connected(onion_c->dht); |
2147 | | |
2148 | 36.9k | if (mono_time_is_timeout(onion_c->mono_time, onion_c->first_run, ONION_CONNECTION_SECONDS * 2)) { |
2149 | 30.4k | set_tcp_onion_status(nc_get_tcp_c(onion_c->c), !onion_c->udp_connected); |
2150 | 30.4k | } |
2151 | | |
2152 | 36.9k | if (onion_connection_status(onion_c) != ONION_CONNECTION_STATUS_NONE) { |
2153 | 50.2k | for (unsigned i = 0; i < onion_c->num_friends; ++i) { |
2154 | 37.0k | do_friend(onion_c, i); |
2155 | 37.0k | } |
2156 | 13.2k | } |
2157 | | |
2158 | 36.9k | if (onion_c->last_run == 0) { |
2159 | 1.89k | onion_c->first_run = mono_time_get(onion_c->mono_time); |
2160 | 1.89k | } |
2161 | | |
2162 | 36.9k | onion_c->last_run = mono_time_get(onion_c->mono_time); |
2163 | 36.9k | } |
2164 | | |
2165 | | Onion_Client *new_onion_client(const Logger *logger, const Memory *mem, const Random *rng, const Mono_Time *mono_time, Net_Crypto *c) |
2166 | 3.82k | { |
2167 | 3.82k | if (c == nullptr) { |
2168 | 0 | return nullptr; |
2169 | 0 | } |
2170 | | |
2171 | 3.82k | Onion_Client *onion_c = (Onion_Client *)mem_alloc(mem, sizeof(Onion_Client)); |
2172 | | |
2173 | 3.82k | if (onion_c == nullptr) { |
2174 | 23 | return nullptr; |
2175 | 23 | } |
2176 | | |
2177 | 3.80k | onion_c->announce_ping_array = ping_array_new(mem, ANNOUNCE_ARRAY_SIZE, ANNOUNCE_TIMEOUT); |
2178 | | |
2179 | 3.80k | if (onion_c->announce_ping_array == nullptr) { |
2180 | 41 | mem_delete(mem, onion_c); |
2181 | 41 | return nullptr; |
2182 | 41 | } |
2183 | | |
2184 | 3.76k | onion_c->mono_time = mono_time; |
2185 | 3.76k | onion_c->logger = logger; |
2186 | 3.76k | onion_c->rng = rng; |
2187 | 3.76k | onion_c->mem = mem; |
2188 | 3.76k | onion_c->dht = nc_get_dht(c); |
2189 | 3.76k | onion_c->net = dht_get_net(onion_c->dht); |
2190 | 3.76k | onion_c->c = c; |
2191 | 3.76k | new_symmetric_key(rng, onion_c->secret_symmetric_key); |
2192 | 3.76k | crypto_new_keypair(rng, onion_c->temp_public_key, onion_c->temp_secret_key); |
2193 | 3.76k | networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE, &handle_announce_response, onion_c); |
2194 | 3.76k | networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE_OLD, &handle_announce_response_old, onion_c); |
2195 | 3.76k | networking_registerhandler(onion_c->net, NET_PACKET_ONION_DATA_RESPONSE, &handle_data_response, onion_c); |
2196 | 3.76k | oniondata_registerhandler(onion_c, ONION_DATA_DHTPK, &handle_dhtpk_announce, onion_c); |
2197 | 3.76k | cryptopacket_registerhandler(onion_c->dht, CRYPTO_PACKET_DHTPK, &handle_dht_dhtpk, onion_c); |
2198 | 3.76k | set_onion_packet_tcp_connection_callback(nc_get_tcp_c(onion_c->c), &handle_tcp_onion, onion_c); |
2199 | | |
2200 | 3.76k | return onion_c; |
2201 | 3.80k | } |
2202 | | |
2203 | | void kill_onion_client(Onion_Client *onion_c) |
2204 | 2.78k | { |
2205 | 2.78k | if (onion_c == nullptr) { |
2206 | 64 | return; |
2207 | 64 | } |
2208 | | |
2209 | 2.71k | const Memory *mem = onion_c->mem; |
2210 | | |
2211 | 2.71k | ping_array_kill(onion_c->announce_ping_array); |
2212 | 2.71k | realloc_onion_friends(onion_c, 0); |
2213 | 2.71k | networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE, nullptr, nullptr); |
2214 | 2.71k | networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE_OLD, nullptr, nullptr); |
2215 | 2.71k | networking_registerhandler(onion_c->net, NET_PACKET_ONION_DATA_RESPONSE, nullptr, nullptr); |
2216 | 2.71k | oniondata_registerhandler(onion_c, ONION_DATA_DHTPK, nullptr, nullptr); |
2217 | 2.71k | cryptopacket_registerhandler(onion_c->dht, CRYPTO_PACKET_DHTPK, nullptr, nullptr); |
2218 | 2.71k | set_onion_packet_tcp_connection_callback(nc_get_tcp_c(onion_c->c), nullptr, nullptr); |
2219 | 2.71k | crypto_memzero(onion_c, sizeof(Onion_Client)); |
2220 | 2.71k | mem_delete(mem, onion_c); |
2221 | 2.71k | } |