Line | Count | Source |
1 | | /* SPDX-License-Identifier: GPL-3.0-or-later |
2 | | * Copyright © 2016-2026 The TokTok team. |
3 | | * Copyright © 2013 Tox project. |
4 | | */ |
5 | | |
6 | | /** @file |
7 | | * @brief An implementation of the DHT as seen in docs/updates/DHT.md |
8 | | */ |
9 | | #ifndef C_TOXCORE_TOXCORE_DHT_H |
10 | | #define C_TOXCORE_TOXCORE_DHT_H |
11 | | |
12 | | #include <stdbool.h> |
13 | | #include <stdint.h> |
14 | | |
15 | | #include "attributes.h" |
16 | | #include "crypto_core.h" |
17 | | #include "logger.h" |
18 | | #include "mem.h" |
19 | | #include "mono_time.h" |
20 | | #include "net.h" |
21 | | #include "network.h" |
22 | | #include "ping_array.h" |
23 | | #include "rng.h" |
24 | | |
25 | | #ifdef __cplusplus |
26 | | extern "C" { |
27 | | #endif |
28 | | |
29 | | /* Maximum size of a signature (may be smaller) */ |
30 | 4.24k | #define SIGNATURE_SIZE CRYPTO_SIGNATURE_SIZE |
31 | | /** Maximum number of clients stored per friend. */ |
32 | 19.4M | #define MAX_FRIEND_CLIENTS 8 |
33 | | |
34 | 18.0M | #define LCLIENT_NODES MAX_FRIEND_CLIENTS |
35 | 14.9M | #define LCLIENT_LENGTH 128 |
36 | | |
37 | | /** A list of the clients mathematically closest to ours. */ |
38 | 14.3M | #define LCLIENT_LIST (LCLIENT_LENGTH * LCLIENT_NODES) |
39 | | |
40 | 40.3k | #define MAX_CLOSE_TO_BOOTSTRAP_NODES 8 |
41 | | |
42 | | /** The max number of nodes to send with nodes response. */ |
43 | 5.23M | #define MAX_SENT_NODES 4 |
44 | | |
45 | | /** Ping timeout in seconds */ |
46 | 4.09k | #define PING_TIMEOUT 5 |
47 | | |
48 | | /** size of DHT ping arrays. */ |
49 | 2.03k | #define DHT_PING_ARRAY_SIZE 512 |
50 | | |
51 | | /** Ping interval in seconds for each node in our lists. */ |
52 | 336M | #define PING_INTERVAL 60 |
53 | | |
54 | | /** The number of seconds for a non responsive node to become bad. */ |
55 | 161M | #define PINGS_MISSED_NODE_GOES_BAD 1 |
56 | 161M | #define PING_ROUNDTRIP 2 |
57 | 161M | #define BAD_NODE_TIMEOUT (PING_INTERVAL + PINGS_MISSED_NODE_GOES_BAD * (PING_INTERVAL + PING_ROUNDTRIP)) |
58 | | |
59 | | /** |
60 | | * The number of "fake" friends to add. |
61 | | * |
62 | | * (for optimization purposes and so our paths for the onion part are more random) |
63 | | */ |
64 | 61.9k | #define DHT_FAKE_FRIEND_NUMBER 2 |
65 | | |
66 | | /** Maximum packet size for a DHT request packet. */ |
67 | 16.0k | #define MAX_CRYPTO_REQUEST_SIZE 1024 |
68 | | |
69 | 18.5k | #define CRYPTO_PACKET_FRIEND_REQ 32 // Friend request crypto packet ID. |
70 | 17.6k | #define CRYPTO_PACKET_DHTPK 156 |
71 | 4.59k | #define CRYPTO_PACKET_NAT_PING 254 // NAT ping crypto packet ID. |
72 | | |
73 | | /* Max size of a packed node for IPV4 and IPV6 respectively */ |
74 | 2.98k | #define PACKED_NODE_SIZE_IP4 (1 + SIZE_IP4 + sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE) |
75 | 86.8k | #define PACKED_NODE_SIZE_IP6 (1 + SIZE_IP6 + sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE) |
76 | | |
77 | | /** |
78 | | * This define can eventually be removed; it is necessary if a significant |
79 | | * proportion of dht nodes do not implement the dht announcements protocol. |
80 | | */ |
81 | | #define CHECK_ANNOUNCE_NODE |
82 | | |
83 | | /** |
84 | | * @brief Create a request to peer. |
85 | | * |
86 | | * Packs the data and sender public key and encrypts the packet. |
87 | | * |
88 | | * @param[in] send_public_key public key of the sender. |
89 | | * @param[in] send_secret_key secret key of the sender. |
90 | | * @param[out] packet an array of @ref MAX_CRYPTO_REQUEST_SIZE big. |
91 | | * @param[in] recv_public_key public key of the receiver. |
92 | | * @param[in] data represents the data we send with the request. |
93 | | * @param[in] data_length the length of the data. |
94 | | * @param[in] request_id the id of the request (32 = friend request, 254 = ping request). |
95 | | * |
96 | | * @attention Constraints: |
97 | | * @code |
98 | | * sizeof(packet) >= MAX_CRYPTO_REQUEST_SIZE |
99 | | * @endcode |
100 | | * |
101 | | * @retval -1 on failure. |
102 | | * @return the length of the created packet on success. |
103 | | */ |
104 | | int create_request(const Memory *_Nonnull mem, const Random *_Nonnull rng, const uint8_t *_Nonnull send_public_key, const uint8_t *_Nonnull send_secret_key, uint8_t *_Nonnull packet, |
105 | | const uint8_t *_Nonnull recv_public_key, const uint8_t *_Nonnull data, uint32_t data_length, uint8_t request_id); |
106 | | |
107 | | /** |
108 | | * @brief Decrypts and unpacks a DHT request packet. |
109 | | * |
110 | | * Puts the senders public key in the request in @p public_key, the data from |
111 | | * the request in @p data. |
112 | | * |
113 | | * @param[in] self_public_key public key of the receiver (us). |
114 | | * @param[in] self_secret_key secret key of the receiver (us). |
115 | | * @param[out] public_key public key of the sender, copied from the input packet. |
116 | | * @param[out] data decrypted request data, copied from the input packet, must |
117 | | * have room for @ref MAX_CRYPTO_REQUEST_SIZE bytes. |
118 | | * @param[in] packet is the request packet. |
119 | | * @param[in] packet_length length of the packet. |
120 | | * |
121 | | * @attention Constraints: |
122 | | * @code |
123 | | * sizeof(data) >= MAX_CRYPTO_REQUEST_SIZE |
124 | | * @endcode |
125 | | * |
126 | | * @retval -1 if not valid request. |
127 | | * @return the length of the unpacked data. |
128 | | */ |
129 | | int handle_request(const Memory *_Nonnull mem, const uint8_t *_Nonnull self_public_key, const uint8_t *_Nonnull self_secret_key, uint8_t *_Nonnull public_key, uint8_t *_Nonnull data, |
130 | | uint8_t *_Nonnull request_id, const uint8_t *_Nonnull packet, uint16_t packet_length); |
131 | | |
132 | | typedef struct IPPTs { |
133 | | IP_Port ip_port; |
134 | | uint64_t timestamp; |
135 | | } IPPTs; |
136 | | |
137 | | typedef struct IPPTsPng { |
138 | | IP_Port ip_port; |
139 | | uint64_t timestamp; |
140 | | uint64_t last_pinged; |
141 | | |
142 | | /* Returned by this node */ |
143 | | IP_Port ret_ip_port; |
144 | | uint64_t ret_timestamp; |
145 | | /* true if this ip_port is ours */ |
146 | | bool ret_ip_self; |
147 | | } IPPTsPng; |
148 | | |
149 | | typedef struct Client_data { |
150 | | uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; |
151 | | IPPTsPng assoc4; |
152 | | IPPTsPng assoc6; |
153 | | |
154 | | #ifdef CHECK_ANNOUNCE_NODE |
155 | | /* Responded to data search? */ |
156 | | bool announce_node; |
157 | | #endif /* CHECK_ANNOUNCE_NODE */ |
158 | | } Client_data; |
159 | | |
160 | | /*----------------------------------------------------------------------------------*/ |
161 | | |
162 | | typedef struct Node_format { |
163 | | uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; |
164 | | IP_Port ip_port; |
165 | | } Node_format; |
166 | | |
167 | | extern const Node_format empty_node_format; |
168 | | |
169 | | typedef struct DHT_Friend DHT_Friend; |
170 | | |
171 | | const uint8_t *_Nonnull dht_friend_public_key(const DHT_Friend *_Nonnull dht_friend); |
172 | | const Client_data *_Nonnull dht_friend_client(const DHT_Friend *_Nonnull dht_friend, size_t index); |
173 | | |
174 | | /** @return packet size of packed node with ip_family on success. |
175 | | * @retval -1 on failure. |
176 | | */ |
177 | | int packed_node_size(Family ip_family); |
178 | | |
179 | | /** @brief Encrypt plain and write resulting DHT packet into packet with max size length. |
180 | | * |
181 | | * @return size of packet on success. |
182 | | * @retval -1 on failure. |
183 | | */ |
184 | | int dht_create_packet(const Memory *_Nonnull mem, const Random *_Nonnull rng, const uint8_t public_key[_Nonnull CRYPTO_PUBLIC_KEY_SIZE], const uint8_t *_Nonnull shared_key, uint8_t type, |
185 | | const uint8_t *_Nonnull plain, size_t plain_length, uint8_t *_Nonnull packet, size_t length); |
186 | | |
187 | | /** @brief Pack number of nodes into data of maxlength length. |
188 | | * |
189 | | * @return length of packed nodes on success. |
190 | | * @retval -1 on failure. |
191 | | */ |
192 | | int pack_nodes(const Logger *_Nonnull logger, uint8_t *_Nonnull data, uint16_t length, const Node_format *_Nonnull nodes, uint16_t number); |
193 | | |
194 | | /** @brief Unpack data of length into nodes of size max_num_nodes. |
195 | | * Put the length of the data processed in processed_data_len. |
196 | | * tcp_enabled sets if TCP nodes are expected (true) or not (false). |
197 | | * |
198 | | * @return number of unpacked nodes on success. |
199 | | * @retval -1 on failure. |
200 | | */ |
201 | | int unpack_nodes(Node_format *_Nonnull nodes, uint16_t max_num_nodes, uint16_t *_Nullable processed_data_len, const uint8_t *_Nonnull data, |
202 | | uint16_t length, bool tcp_enabled); |
203 | | /*----------------------------------------------------------------------------------*/ |
204 | | |
205 | | typedef int cryptopacket_handler_cb(void *_Nullable object, const IP_Port *_Nonnull source, const uint8_t *_Nonnull source_pubkey, |
206 | | const uint8_t *_Nonnull packet, uint16_t length, void *_Nullable userdata); |
207 | | |
208 | | typedef struct DHT DHT; |
209 | | |
210 | | const uint8_t *_Nonnull dht_get_self_public_key(const DHT *_Nonnull dht); |
211 | | const uint8_t *_Nonnull dht_get_self_secret_key(const DHT *_Nonnull dht); |
212 | | void dht_set_self_public_key(DHT *_Nonnull dht, const uint8_t *_Nonnull key); |
213 | | void dht_set_self_secret_key(DHT *_Nonnull dht, const uint8_t *_Nonnull key); |
214 | | |
215 | | struct Ping *_Nonnull dht_get_ping(const DHT *_Nonnull dht); |
216 | | const Client_data *_Nonnull dht_get_close_clientlist(const DHT *_Nonnull dht); |
217 | | const Client_data *_Nonnull dht_get_close_client(const DHT *_Nonnull dht, uint32_t client_num); |
218 | | uint16_t dht_get_num_friends(const DHT *_Nonnull dht); |
219 | | |
220 | | DHT_Friend *_Nonnull dht_get_friend(DHT *_Nonnull dht, uint32_t friend_num); |
221 | | const uint8_t *_Nonnull dht_get_friend_public_key(const DHT *_Nonnull dht, uint32_t friend_num); |
222 | | |
223 | | /*----------------------------------------------------------------------------------*/ |
224 | | |
225 | | /** |
226 | | * Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key |
227 | | * for packets that we receive. |
228 | | */ |
229 | | const uint8_t *_Nullable dht_get_shared_key_recv(DHT *_Nonnull dht, const uint8_t *_Nonnull public_key); |
230 | | |
231 | | /** |
232 | | * Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key |
233 | | * for packets that we send. |
234 | | */ |
235 | | const uint8_t *_Nullable dht_get_shared_key_sent(DHT *_Nonnull dht, const uint8_t *_Nonnull public_key); |
236 | | |
237 | | /** |
238 | | * Sends a nodes request to `ip_port` with the public key `public_key` for nodes |
239 | | * that are close to `client_id`. |
240 | | * |
241 | | * @retval true on success. |
242 | | */ |
243 | | bool dht_send_nodes_request(DHT *_Nonnull dht, const IP_Port *_Nonnull ip_port, const uint8_t *_Nonnull public_key, const uint8_t *_Nonnull client_id); |
244 | | |
245 | | typedef void dht_ip_cb(void *_Nullable object, int32_t number, const IP_Port *_Nonnull ip_port); |
246 | | |
247 | | typedef void dht_nodes_response_cb(const DHT *_Nonnull dht, const Node_format *_Nonnull node, void *_Nullable user_data); |
248 | | |
249 | | /** Sets the callback to be triggered on a nodes response. */ |
250 | | void dht_callback_nodes_response(DHT *_Nonnull dht, dht_nodes_response_cb *_Nullable function); |
251 | | /** @brief Add a new friend to the friends list. |
252 | | * @param public_key must be CRYPTO_PUBLIC_KEY_SIZE bytes long. |
253 | | * |
254 | | * @param ip_callback is the callback of a function that will be called when the ip address |
255 | | * is found along with arguments data and number. |
256 | | * @param data User data for the callback |
257 | | * @param number Will be passed to ip_callback |
258 | | * |
259 | | * @param lock_token will be set to a non zero number that must be passed to `dht_delfriend()` |
260 | | * to properly remove the callback. |
261 | | * |
262 | | * @retval 0 if success. |
263 | | * @retval -1 if failure (friends list is full). |
264 | | */ |
265 | | int dht_addfriend(DHT *_Nonnull dht, const uint8_t *_Nonnull public_key, dht_ip_cb *_Nullable ip_callback, |
266 | | void *_Nullable data, int32_t number, uint32_t *_Nonnull lock_token); |
267 | | /** @brief Delete a friend from the friends list. |
268 | | * public_key must be CRYPTO_PUBLIC_KEY_SIZE bytes long. |
269 | | * @param dht The DHT object |
270 | | * @param public_key The public key of the friend |
271 | | * @param lock_token The token received by dht_addfriend(...) |
272 | | * |
273 | | * @retval 0 if success. |
274 | | * @retval -1 if failure (public_key not in friends list). |
275 | | */ |
276 | | int dht_delfriend(DHT *_Nonnull dht, const uint8_t *_Nonnull public_key, uint32_t lock_token); |
277 | | |
278 | | /** @brief Get ip of friend. |
279 | | * |
280 | | * @param public_key must be CRYPTO_PUBLIC_KEY_SIZE bytes long. |
281 | | * |
282 | | * @retval -1 if public_key does NOT refer to a friend |
283 | | * @retval 0 if public_key refers to a friend and we failed to find the friend (yet) |
284 | | * @retval 1 if public_key refers to a friend and we found him |
285 | | */ |
286 | | int dht_getfriendip(const DHT *_Nonnull dht, const uint8_t *_Nonnull public_key, IP_Port *_Nonnull ip_port); |
287 | | |
288 | | /** @brief Compares pk1 and pk2 with pk. |
289 | | * |
290 | | * @retval 0 if both are same distance. |
291 | | * @retval 1 if pk1 is closer. |
292 | | * @retval 2 if pk2 is closer. |
293 | | */ |
294 | | int id_closest(const uint8_t *_Nonnull pk, const uint8_t *_Nonnull pk1, const uint8_t *_Nonnull pk2); |
295 | | |
296 | | /** Return index of first unequal bit number between public keys pk1 and pk2. */ |
297 | | unsigned int bit_by_bit_cmp(const uint8_t *_Nonnull pk1, const uint8_t *_Nonnull pk2); |
298 | | |
299 | | /** |
300 | | * Add node to the node list making sure only the nodes closest to cmp_pk are in the list. |
301 | | * |
302 | | * @return true iff the node was added to the list. |
303 | | */ |
304 | | bool add_to_list(Node_format *_Nonnull nodes_list, uint32_t length, const uint8_t pk[_Nonnull CRYPTO_PUBLIC_KEY_SIZE], const IP_Port *_Nonnull ip_port, |
305 | | const uint8_t cmp_pk[_Nonnull CRYPTO_PUBLIC_KEY_SIZE]); |
306 | | |
307 | | /** Return 1 if node can be added to close list, 0 if it can't. */ |
308 | | bool node_addable_to_close_list(DHT *_Nonnull dht, const uint8_t *_Nonnull public_key, const IP_Port *_Nonnull ip_port); |
309 | | |
310 | | #ifdef CHECK_ANNOUNCE_NODE |
311 | | /** Set node as announce node. */ |
312 | | void set_announce_node(DHT *_Nonnull dht, const uint8_t *_Nonnull public_key); |
313 | | #endif /* CHECK_ANNOUNCE_NODE */ |
314 | | |
315 | | /** |
316 | | * @brief Get the (maximum MAX_SENT_NODES) closest nodes to public_key we know |
317 | | * and put them in nodes_list (must be MAX_SENT_NODES big). |
318 | | * |
319 | | * @param sa_family family (IPv4 or IPv6) (0 if we don't care)? |
320 | | * @param is_lan return some LAN ips (true or false). |
321 | | * @param want_announce return only nodes which implement the dht announcements protocol. |
322 | | * |
323 | | * @return the number of nodes returned. |
324 | | */ |
325 | | int get_close_nodes(const DHT *_Nonnull dht, const uint8_t *_Nonnull public_key, Node_format nodes_list[_Nonnull MAX_SENT_NODES], Family sa_family, bool is_lan, bool want_announce); |
326 | | |
327 | | /** @brief Put up to max_num nodes in nodes from the random friends. |
328 | | * |
329 | | * Important: this function relies on the first two DHT friends *not* being real |
330 | | * friends to avoid leaking information about real friends into the onion paths. |
331 | | * |
332 | | * @return the number of nodes. |
333 | | */ |
334 | | uint16_t randfriends_nodes(const DHT *_Nonnull dht, Node_format *_Nonnull nodes, uint16_t max_num); |
335 | | |
336 | | /** @brief Put up to max_num nodes in nodes from the closelist. |
337 | | * |
338 | | * @return the number of nodes. |
339 | | */ |
340 | | uint16_t closelist_nodes(const DHT *_Nonnull dht, Node_format *_Nonnull nodes, uint16_t max_num); |
341 | | |
342 | | /** Run this function at least a couple times per second (It's the main loop). */ |
343 | | void do_dht(DHT *_Nonnull dht); |
344 | | |
345 | | /* |
346 | | * Use these two functions to bootstrap the client. |
347 | | */ |
348 | | /** |
349 | | * @brief Sends a "nodes request" to the given node with ip, port and public_key |
350 | | * to setup connections |
351 | | */ |
352 | | bool dht_bootstrap(DHT *_Nonnull dht, const IP_Port *_Nonnull ip_port, const uint8_t *_Nonnull public_key); |
353 | | |
354 | | /** @brief Resolves address into an IP address. |
355 | | * |
356 | | * If successful, sends a "nodes request" to the given node with ip, port |
357 | | * and public_key to setup connections |
358 | | * |
359 | | * @param address can be a hostname or an IP address (IPv4 or IPv6). |
360 | | * @param ipv6enabled if false, the resolving sticks STRICTLY to IPv4 addresses. |
361 | | * Otherwise, the resolving looks for IPv6 addresses first, then IPv4 addresses. |
362 | | * @param dns_enabled if false, the resolving does not use DNS, only IP addresses are supported. |
363 | | * |
364 | | * @retval true if the address could be converted into an IP address |
365 | | * @retval false otherwise |
366 | | */ |
367 | | bool dht_bootstrap_from_address(DHT *_Nonnull dht, const char *_Nonnull address, bool ipv6enabled, bool dns_enabled, uint16_t port, const uint8_t *_Nonnull public_key); |
368 | | |
369 | | /** @brief Start sending packets after DHT loaded_nodes_list is set. |
370 | | * |
371 | | * @retval 0 if successful |
372 | | * @retval -1 otherwise |
373 | | */ |
374 | | int dht_connect_after_load(DHT *_Nonnull dht); |
375 | | |
376 | | /* ROUTING FUNCTIONS */ |
377 | | |
378 | | /** @brief Send the given packet to node with public_key. |
379 | | * |
380 | | * @return number of bytes sent. |
381 | | * @retval -1 if failure. |
382 | | */ |
383 | | int route_packet(const DHT *_Nonnull dht, const uint8_t *_Nonnull public_key, const uint8_t *_Nonnull packet, uint16_t length); |
384 | | |
385 | | /** |
386 | | * Send the following packet to everyone who tells us they are connected to friend_id. |
387 | | * Only works if more than (MAX_FRIEND_CLIENTS / 4) return an ip for friend. |
388 | | * |
389 | | * @return number of nodes the packet was sent to. |
390 | | */ |
391 | | uint32_t route_to_friend(const DHT *_Nonnull dht, const uint8_t *_Nonnull friend_id, const Net_Packet *_Nonnull packet); |
392 | | |
393 | | /** Function to handle crypto packets. */ |
394 | | void cryptopacket_registerhandler(DHT *_Nonnull dht, uint8_t byte, cryptopacket_handler_cb *_Nullable cb, void *_Nullable object); |
395 | | /* SAVE/LOAD functions */ |
396 | | |
397 | | /** Get the size of the DHT (for saving). */ |
398 | | uint32_t dht_size(const DHT *_Nonnull dht); |
399 | | |
400 | | /** Save the DHT in data where data is an array of size `dht_size()`. */ |
401 | | void dht_save(const DHT *_Nonnull dht, uint8_t *_Nonnull data); |
402 | | |
403 | | /** @brief Load the DHT from data of size size. |
404 | | * |
405 | | * @retval -1 if failure. |
406 | | * @retval 0 if success. |
407 | | */ |
408 | | int dht_load(DHT *_Nonnull dht, const uint8_t *_Nonnull data, uint32_t length); |
409 | | |
410 | | /** Initialize DHT. */ |
411 | | DHT *_Nullable new_dht(const Logger *_Nonnull log, const Memory *_Nonnull mem, const Random *_Nonnull rng, const Network *_Nonnull ns, Mono_Time *_Nonnull mono_time, Networking_Core *_Nonnull net, |
412 | | bool hole_punching_enabled, bool lan_discovery_enabled); |
413 | | |
414 | | void kill_dht(DHT *_Nullable dht); |
415 | | /** |
416 | | * @retval false if we are not connected to the DHT. |
417 | | * @retval true if we are. |
418 | | */ |
419 | | bool dht_isconnected(const DHT *_Nonnull dht); |
420 | | |
421 | | /** |
422 | | * @retval false if we are not connected or only connected to lan peers with the DHT. |
423 | | * @retval true if we are. |
424 | | */ |
425 | | bool dht_non_lan_connected(const DHT *_Nonnull dht); |
426 | | |
427 | | /** |
428 | | * This function returns the ratio of close dht nodes that are known to support announce/store. |
429 | | * This function returns the number of DHT nodes in the closelist. |
430 | | * |
431 | | * @return number |
432 | | */ |
433 | | uint16_t dht_get_num_closelist(const DHT *_Nonnull dht); |
434 | | |
435 | | /** |
436 | | * This function returns the number of DHT nodes in the closelist, |
437 | | * that are capable to store annouce data (introduced in version 0.2.18). |
438 | | * |
439 | | * @return number |
440 | | */ |
441 | | uint16_t dht_get_num_closelist_announce_capable(const DHT *_Nonnull dht); |
442 | | |
443 | | /** @brief Attempt to add client with ip_port and public_key to the friends client list |
444 | | * and close_clientlist. |
445 | | * |
446 | | * @return 1+ if the item is used in any list, 0 else |
447 | | */ |
448 | | uint32_t addto_lists(DHT *_Nonnull dht, const IP_Port *_Nonnull ip_port, const uint8_t *_Nonnull public_key); |
449 | | |
450 | | /** @brief Copies our own ip_port structure to `dest`. |
451 | | * |
452 | | * WAN addresses take priority over LAN addresses. |
453 | | * |
454 | | * This function will zero the `dest` buffer before use. |
455 | | * |
456 | | * @retval 0 if our ip port can't be found (this usually means we're not connected to the DHT). |
457 | | * @retval 1 if IP is a WAN address. |
458 | | * @retval 2 if IP is a LAN address. |
459 | | */ |
460 | | unsigned int ipport_self_copy(const DHT *_Nonnull dht, IP_Port *_Nonnull dest); |
461 | | |
462 | | #ifdef __cplusplus |
463 | | } /* extern "C" */ |
464 | | #endif |
465 | | |
466 | | #endif /* C_TOXCORE_TOXCORE_DHT_H */ |