1 /* SPDX-License-Identifier: GPL-3.0-or-later
2 * Copyright © 2016-2018 The TokTok team.
3 * Copyright © 2013 Tox project.
4 * Copyright © 2013 plutooo
5 */
6
7 /*
8 * Buffered pinging using cyclic arrays.
9 */
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
13
14 #include "ping.h"
15
16 #include <stdlib.h>
17 #include <string.h>
18
19 #include "DHT.h"
20 #include "mono_time.h"
21 #include "network.h"
22 #include "ping_array.h"
23 #include "util.h"
24
25 #define PING_NUM_MAX 512
26
27 /* Maximum newly announced nodes to ping per TIME_TO_PING seconds. */
28 #define MAX_TO_PING 32
29
30 /* Ping newly announced nodes to ping per TIME_TO_PING seconds*/
31 #define TIME_TO_PING 2
32
33
34 struct Ping {
35 const Mono_Time *mono_time;
36 DHT *dht;
37
38 Ping_Array *ping_array;
39 Node_format to_ping[MAX_TO_PING];
40 uint64_t last_to_ping;
41 };
42
43
44 #define PING_PLAIN_SIZE (1 + sizeof(uint64_t))
45 #define DHT_PING_SIZE (1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + PING_PLAIN_SIZE + CRYPTO_MAC_SIZE)
46 #define PING_DATA_SIZE (CRYPTO_PUBLIC_KEY_SIZE + sizeof(IP_Port))
47
ping_send_request(Ping * ping,IP_Port ipp,const uint8_t * public_key)48 int32_t ping_send_request(Ping *ping, IP_Port ipp, const uint8_t *public_key)
49 {
50 uint8_t pk[DHT_PING_SIZE];
51 int rc;
52 uint64_t ping_id;
53
54 if (id_equal(public_key, dht_get_self_public_key(ping->dht))) {
55 return 1;
56 }
57
58 uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
59
60 // generate key to encrypt ping_id with recipient privkey
61 dht_get_shared_key_sent(ping->dht, shared_key, public_key);
62 // Generate random ping_id.
63 uint8_t data[PING_DATA_SIZE];
64 id_copy(data, public_key);
65 memcpy(data + CRYPTO_PUBLIC_KEY_SIZE, &ipp, sizeof(IP_Port));
66 ping_id = ping_array_add(ping->ping_array, ping->mono_time, data, sizeof(data));
67
68 if (ping_id == 0) {
69 return 1;
70 }
71
72 uint8_t ping_plain[PING_PLAIN_SIZE];
73 ping_plain[0] = NET_PACKET_PING_REQUEST;
74 memcpy(ping_plain + 1, &ping_id, sizeof(ping_id));
75
76 pk[0] = NET_PACKET_PING_REQUEST;
77 id_copy(pk + 1, dht_get_self_public_key(ping->dht)); // Our pubkey
78 random_nonce(pk + 1 + CRYPTO_PUBLIC_KEY_SIZE); // Generate new nonce
79
80
81 rc = encrypt_data_symmetric(shared_key,
82 pk + 1 + CRYPTO_PUBLIC_KEY_SIZE,
83 ping_plain, sizeof(ping_plain),
84 pk + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE);
85
86 if (rc != PING_PLAIN_SIZE + CRYPTO_MAC_SIZE) {
87 return 1;
88 }
89
90 return sendpacket(dht_get_net(ping->dht), ipp, pk, sizeof(pk));
91 }
92
ping_send_response(Ping * ping,IP_Port ipp,const uint8_t * public_key,uint64_t ping_id,uint8_t * shared_encryption_key)93 static int ping_send_response(Ping *ping, IP_Port ipp, const uint8_t *public_key, uint64_t ping_id,
94 uint8_t *shared_encryption_key)
95 {
96 uint8_t pk[DHT_PING_SIZE];
97 int rc;
98
99 if (id_equal(public_key, dht_get_self_public_key(ping->dht))) {
100 return 1;
101 }
102
103 uint8_t ping_plain[PING_PLAIN_SIZE];
104 ping_plain[0] = NET_PACKET_PING_RESPONSE;
105 memcpy(ping_plain + 1, &ping_id, sizeof(ping_id));
106
107 pk[0] = NET_PACKET_PING_RESPONSE;
108 id_copy(pk + 1, dht_get_self_public_key(ping->dht)); // Our pubkey
109 random_nonce(pk + 1 + CRYPTO_PUBLIC_KEY_SIZE); // Generate new nonce
110
111 // Encrypt ping_id using recipient privkey
112 rc = encrypt_data_symmetric(shared_encryption_key,
113 pk + 1 + CRYPTO_PUBLIC_KEY_SIZE,
114 ping_plain, sizeof(ping_plain),
115 pk + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE);
116
117 if (rc != PING_PLAIN_SIZE + CRYPTO_MAC_SIZE) {
118 return 1;
119 }
120
121 return sendpacket(dht_get_net(ping->dht), ipp, pk, sizeof(pk));
122 }
123
handle_ping_request(void * object,IP_Port source,const uint8_t * packet,uint16_t length,void * userdata)124 static int handle_ping_request(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata)
125 {
126 DHT *dht = (DHT *)object;
127 int rc;
128
129 if (length != DHT_PING_SIZE) {
130 return 1;
131 }
132
133 Ping *ping = dht_get_ping(dht);
134
135 if (id_equal(packet + 1, dht_get_self_public_key(ping->dht))) {
136 return 1;
137 }
138
139 uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
140
141 uint8_t ping_plain[PING_PLAIN_SIZE];
142 // Decrypt ping_id
143 dht_get_shared_key_recv(dht, shared_key, packet + 1);
144 rc = decrypt_data_symmetric(shared_key,
145 packet + 1 + CRYPTO_PUBLIC_KEY_SIZE,
146 packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
147 PING_PLAIN_SIZE + CRYPTO_MAC_SIZE,
148 ping_plain);
149
150 if (rc != sizeof(ping_plain)) {
151 return 1;
152 }
153
154 if (ping_plain[0] != NET_PACKET_PING_REQUEST) {
155 return 1;
156 }
157
158 uint64_t ping_id;
159 memcpy(&ping_id, ping_plain + 1, sizeof(ping_id));
160 // Send response
161 ping_send_response(ping, source, packet + 1, ping_id, shared_key);
162 ping_add(ping, packet + 1, source);
163
164 return 0;
165 }
166
handle_ping_response(void * object,IP_Port source,const uint8_t * packet,uint16_t length,void * userdata)167 static int handle_ping_response(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata)
168 {
169 DHT *dht = (DHT *)object;
170 int rc;
171
172 if (length != DHT_PING_SIZE) {
173 return 1;
174 }
175
176 Ping *ping = dht_get_ping(dht);
177
178 if (id_equal(packet + 1, dht_get_self_public_key(ping->dht))) {
179 return 1;
180 }
181
182 uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
183
184 // generate key to encrypt ping_id with recipient privkey
185 dht_get_shared_key_sent(ping->dht, shared_key, packet + 1);
186
187 uint8_t ping_plain[PING_PLAIN_SIZE];
188 // Decrypt ping_id
189 rc = decrypt_data_symmetric(shared_key,
190 packet + 1 + CRYPTO_PUBLIC_KEY_SIZE,
191 packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
192 PING_PLAIN_SIZE + CRYPTO_MAC_SIZE,
193 ping_plain);
194
195 if (rc != sizeof(ping_plain)) {
196 return 1;
197 }
198
199 if (ping_plain[0] != NET_PACKET_PING_RESPONSE) {
200 return 1;
201 }
202
203 uint64_t ping_id;
204 memcpy(&ping_id, ping_plain + 1, sizeof(ping_id));
205 uint8_t data[PING_DATA_SIZE];
206
207 if (ping_array_check(ping->ping_array, ping->mono_time, data, sizeof(data), ping_id) != sizeof(data)) {
208 return 1;
209 }
210
211 if (!id_equal(packet + 1, data)) {
212 return 1;
213 }
214
215 IP_Port ipp;
216 memcpy(&ipp, data + CRYPTO_PUBLIC_KEY_SIZE, sizeof(IP_Port));
217
218 if (!ipport_equal(&ipp, &source)) {
219 return 1;
220 }
221
222 addto_lists(dht, source, packet + 1);
223 return 0;
224 }
225
226 /* Check if public_key with ip_port is in the list.
227 *
228 * return 1 if it is.
229 * return 0 if it isn't.
230 */
in_list(const Client_data * list,uint16_t length,const Mono_Time * mono_time,const uint8_t * public_key,IP_Port ip_port)231 static int in_list(const Client_data *list, uint16_t length, const Mono_Time *mono_time, const uint8_t *public_key,
232 IP_Port ip_port)
233 {
234 unsigned int i;
235
236 for (i = 0; i < length; ++i) {
237 if (id_equal(list[i].public_key, public_key)) {
238 const IPPTsPng *ipptp;
239
240 if (net_family_is_ipv4(ip_port.ip.family)) {
241 ipptp = &list[i].assoc4;
242 } else {
243 ipptp = &list[i].assoc6;
244 }
245
246 if (!mono_time_is_timeout(mono_time, ipptp->timestamp, BAD_NODE_TIMEOUT) && ipport_equal(&ipptp->ip_port, &ip_port)) {
247 return 1;
248 }
249 }
250 }
251
252 return 0;
253 }
254
255 /* Add nodes to the to_ping list.
256 * All nodes in this list are pinged every TIME_TO_PING seconds
257 * and are then removed from the list.
258 * If the list is full the nodes farthest from our public_key are replaced.
259 * The purpose of this list is to enable quick integration of new nodes into the
260 * network while preventing amplification attacks.
261 *
262 * return 0 if node was added.
263 * return -1 if node was not added.
264 */
ping_add(Ping * ping,const uint8_t * public_key,IP_Port ip_port)265 int32_t ping_add(Ping *ping, const uint8_t *public_key, IP_Port ip_port)
266 {
267 if (!ip_isset(&ip_port.ip)) {
268 return -1;
269 }
270
271 if (!node_addable_to_close_list(ping->dht, public_key, ip_port)) {
272 return -1;
273 }
274
275 if (in_list(dht_get_close_clientlist(ping->dht), LCLIENT_LIST, ping->mono_time, public_key, ip_port)) {
276 return -1;
277 }
278
279 IP_Port temp;
280
281 if (dht_getfriendip(ping->dht, public_key, &temp) == 0) {
282 ping_send_request(ping, ip_port, public_key);
283 return -1;
284 }
285
286 unsigned int i;
287
288 for (i = 0; i < MAX_TO_PING; ++i) {
289 if (!ip_isset(&ping->to_ping[i].ip_port.ip)) {
290 memcpy(ping->to_ping[i].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE);
291 ipport_copy(&ping->to_ping[i].ip_port, &ip_port);
292 return 0;
293 }
294
295 if (public_key_cmp(ping->to_ping[i].public_key, public_key) == 0) {
296 return -1;
297 }
298 }
299
300 if (add_to_list(ping->to_ping, MAX_TO_PING, public_key, ip_port, dht_get_self_public_key(ping->dht))) {
301 return 0;
302 }
303
304 return -1;
305 }
306
307
308 /* Ping all the valid nodes in the to_ping list every TIME_TO_PING seconds.
309 * This function must be run at least once every TIME_TO_PING seconds.
310 */
ping_iterate(Ping * ping)311 void ping_iterate(Ping *ping)
312 {
313 if (!mono_time_is_timeout(ping->mono_time, ping->last_to_ping, TIME_TO_PING)) {
314 return;
315 }
316
317 if (!ip_isset(&ping->to_ping[0].ip_port.ip)) {
318 return;
319 }
320
321 unsigned int i;
322
323 for (i = 0; i < MAX_TO_PING; ++i) {
324 if (!ip_isset(&ping->to_ping[i].ip_port.ip)) {
325 break;
326 }
327
328 if (!node_addable_to_close_list(ping->dht, ping->to_ping[i].public_key, ping->to_ping[i].ip_port)) {
329 continue;
330 }
331
332 ping_send_request(ping, ping->to_ping[i].ip_port, ping->to_ping[i].public_key);
333 ip_reset(&ping->to_ping[i].ip_port.ip);
334 }
335
336 if (i != 0) {
337 ping->last_to_ping = mono_time_get(ping->mono_time);
338 }
339 }
340
341
ping_new(const Mono_Time * mono_time,DHT * dht)342 Ping *ping_new(const Mono_Time *mono_time, DHT *dht)
343 {
344 Ping *ping = (Ping *)calloc(1, sizeof(Ping));
345
346 if (ping == nullptr) {
347 return nullptr;
348 }
349
350 ping->ping_array = ping_array_new(PING_NUM_MAX, PING_TIMEOUT);
351
352 if (ping->ping_array == nullptr) {
353 free(ping);
354 return nullptr;
355 }
356
357 ping->mono_time = mono_time;
358 ping->dht = dht;
359 networking_registerhandler(dht_get_net(ping->dht), NET_PACKET_PING_REQUEST, &handle_ping_request, dht);
360 networking_registerhandler(dht_get_net(ping->dht), NET_PACKET_PING_RESPONSE, &handle_ping_response, dht);
361
362 return ping;
363 }
364
ping_kill(Ping * ping)365 void ping_kill(Ping *ping)
366 {
367 if (ping == nullptr) {
368 return;
369 }
370
371 networking_registerhandler(dht_get_net(ping->dht), NET_PACKET_PING_REQUEST, nullptr, nullptr);
372 networking_registerhandler(dht_get_net(ping->dht), NET_PACKET_PING_RESPONSE, nullptr, nullptr);
373 ping_array_kill(ping->ping_array);
374
375 free(ping);
376 }
377