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