diff options
Diffstat (limited to 'toxcore/DHT.c')
-rw-r--r-- | toxcore/DHT.c | 153 |
1 files changed, 113 insertions, 40 deletions
diff --git a/toxcore/DHT.c b/toxcore/DHT.c index 2b8ec5b5..1089e2ff 100644 --- a/toxcore/DHT.c +++ b/toxcore/DHT.c | |||
@@ -44,7 +44,7 @@ | |||
44 | #define KILL_NODE_TIMEOUT 300 | 44 | #define KILL_NODE_TIMEOUT 300 |
45 | 45 | ||
46 | /* Ping interval in seconds for each random sending of a get nodes request. */ | 46 | /* Ping interval in seconds for each random sending of a get nodes request. */ |
47 | #define GET_NODE_INTERVAL 5 | 47 | #define GET_NODE_INTERVAL 20 |
48 | 48 | ||
49 | #define MAX_PUNCHING_PORTS 48 | 49 | #define MAX_PUNCHING_PORTS 48 |
50 | 50 | ||
@@ -56,6 +56,9 @@ | |||
56 | #define NAT_PING_REQUEST 0 | 56 | #define NAT_PING_REQUEST 0 |
57 | #define NAT_PING_RESPONSE 1 | 57 | #define NAT_PING_RESPONSE 1 |
58 | 58 | ||
59 | /* Number of get node requests to send to quickly find close nodes. */ | ||
60 | #define MAX_BOOTSTRAP_TIMES 10 | ||
61 | |||
59 | /* Used in the comparison function for sorting lists of Client_data. */ | 62 | /* Used in the comparison function for sorting lists of Client_data. */ |
60 | typedef struct { | 63 | typedef struct { |
61 | Client_data c1; | 64 | Client_data c1; |
@@ -111,6 +114,72 @@ static int client_id_cmp(ClientPair p1, ClientPair p2) | |||
111 | return c; | 114 | return c; |
112 | } | 115 | } |
113 | 116 | ||
117 | /* Shared key generations are costly, it is therefor smart to store commonly used | ||
118 | * ones so that they can re used later without being computed again. | ||
119 | * | ||
120 | * If shared key is already in shared_keys, copy it to shared_key. | ||
121 | * else generate it into shared_key and copy it to shared_keys | ||
122 | */ | ||
123 | void get_shared_key(Shared_Keys *shared_keys, uint8_t *shared_key, uint8_t *secret_key, uint8_t *client_id) | ||
124 | { | ||
125 | uint32_t i, num = ~0, curr = 0; | ||
126 | |||
127 | for (i = 0; i < MAX_KEYS_PER_SLOT; ++i) { | ||
128 | int index = client_id[30] * MAX_KEYS_PER_SLOT + i; | ||
129 | |||
130 | if (shared_keys->keys[index].stored) { | ||
131 | if (memcmp(client_id, shared_keys->keys[index].client_id, CLIENT_ID_SIZE) == 0) { | ||
132 | memcpy(shared_key, shared_keys->keys[index].shared_key, crypto_box_BEFORENMBYTES); | ||
133 | ++shared_keys->keys[index].times_requested; | ||
134 | shared_keys->keys[index].time_last_requested = unix_time(); | ||
135 | return; | ||
136 | } | ||
137 | |||
138 | if (num != 0) { | ||
139 | if (is_timeout(shared_keys->keys[index].time_last_requested, KEYS_TIMEOUT)) { | ||
140 | num = 0; | ||
141 | curr = index; | ||
142 | } else if (num > shared_keys->keys[index].times_requested) { | ||
143 | num = shared_keys->keys[index].times_requested; | ||
144 | curr = index; | ||
145 | } | ||
146 | } | ||
147 | } else { | ||
148 | if (num != 0) { | ||
149 | num = 0; | ||
150 | curr = index; | ||
151 | } | ||
152 | } | ||
153 | } | ||
154 | |||
155 | encrypt_precompute(client_id, secret_key, shared_key); | ||
156 | |||
157 | if (num != (uint32_t)~0) { | ||
158 | shared_keys->keys[curr].stored = 1; | ||
159 | shared_keys->keys[curr].times_requested = 1; | ||
160 | memcpy(shared_keys->keys[curr].client_id, client_id, CLIENT_ID_SIZE); | ||
161 | memcpy(shared_keys->keys[curr].shared_key, shared_key, crypto_box_BEFORENMBYTES); | ||
162 | shared_keys->keys[curr].time_last_requested = unix_time(); | ||
163 | } | ||
164 | } | ||
165 | |||
166 | /* Copy shared_key to decrypt DHT packet from client_id into shared_key | ||
167 | * for packets that we recieve. | ||
168 | */ | ||
169 | void DHT_get_shared_key_recv(DHT *dht, uint8_t *shared_key, uint8_t *client_id) | ||
170 | { | ||
171 | return get_shared_key(&dht->shared_keys_recv, shared_key, dht->self_secret_key, client_id); | ||
172 | } | ||
173 | |||
174 | /* Copy shared_key to decrypt DHT packet from client_id into shared_key | ||
175 | * for packets that we send. | ||
176 | */ | ||
177 | void DHT_get_shared_key_sent(DHT *dht, uint8_t *shared_key, uint8_t *client_id) | ||
178 | { | ||
179 | return get_shared_key(&dht->shared_keys_sent, shared_key, dht->self_secret_key, client_id); | ||
180 | } | ||
181 | |||
182 | |||
114 | /* Check if client with client_id is already in list of length length. | 183 | /* Check if client with client_id is already in list of length length. |
115 | * If it is then set its corresponding timestamp to current time. | 184 | * If it is then set its corresponding timestamp to current time. |
116 | * If the id is already in the list with a different ip_port, update it. | 185 | * If the id is already in the list with a different ip_port, update it. |
@@ -819,12 +888,13 @@ static int getnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *cli | |||
819 | memcpy(plain, client_id, CLIENT_ID_SIZE); | 888 | memcpy(plain, client_id, CLIENT_ID_SIZE); |
820 | memcpy(plain + CLIENT_ID_SIZE, encrypted_message, NODES_ENCRYPTED_MESSAGE_LENGTH); | 889 | memcpy(plain + CLIENT_ID_SIZE, encrypted_message, NODES_ENCRYPTED_MESSAGE_LENGTH); |
821 | 890 | ||
822 | int len = encrypt_data( public_key, | 891 | uint8_t shared_key[crypto_box_BEFORENMBYTES]; |
823 | dht->self_secret_key, | 892 | DHT_get_shared_key_sent(dht, shared_key, public_key); |
824 | nonce, | 893 | int len = encrypt_data_fast( shared_key, |
825 | plain, | 894 | nonce, |
826 | CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH, | 895 | plain, |
827 | encrypt ); | 896 | CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH, |
897 | encrypt ); | ||
828 | 898 | ||
829 | if (len != CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES) | 899 | if (len != CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES) |
830 | return -1; | 900 | return -1; |
@@ -841,7 +911,8 @@ static int getnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *cli | |||
841 | /* because of BINARY compatibility, the Node_format MUST BE Node4_format, | 911 | /* because of BINARY compatibility, the Node_format MUST BE Node4_format, |
842 | * IPv6 nodes are sent in a different message | 912 | * IPv6 nodes are sent in a different message |
843 | * encrypted_data must be of size NODES_ENCRYPTED_MESSAGE_LENGTH */ | 913 | * encrypted_data must be of size NODES_ENCRYPTED_MESSAGE_LENGTH */ |
844 | static int sendnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *client_id, uint8_t *encrypted_data) | 914 | static int sendnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *client_id, uint8_t *encrypted_data, |
915 | uint8_t *shared_encryption_key) | ||
845 | { | 916 | { |
846 | /* Check if packet is going to be sent to ourself. */ | 917 | /* Check if packet is going to be sent to ourself. */ |
847 | if (id_equal(public_key, dht->self_public_key)) | 918 | if (id_equal(public_key, dht->self_public_key)) |
@@ -888,12 +959,11 @@ static int sendnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *cl | |||
888 | } | 959 | } |
889 | 960 | ||
890 | memcpy(plain + num_nodes * Node4_format_size, encrypted_data, NODES_ENCRYPTED_MESSAGE_LENGTH); | 961 | memcpy(plain + num_nodes * Node4_format_size, encrypted_data, NODES_ENCRYPTED_MESSAGE_LENGTH); |
891 | int len = encrypt_data( public_key, | 962 | int len = encrypt_data_fast( shared_encryption_key, |
892 | dht->self_secret_key, | 963 | nonce, |
893 | nonce, | 964 | plain, |
894 | plain, | 965 | num_nodes * Node4_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH, |
895 | num_nodes * Node4_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH, | 966 | encrypt ); |
896 | encrypt ); | ||
897 | 967 | ||
898 | if ((unsigned int)len != num_nodes * Node4_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH + | 968 | if ((unsigned int)len != num_nodes * Node4_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH + |
899 | crypto_box_MACBYTES) | 969 | crypto_box_MACBYTES) |
@@ -927,7 +997,8 @@ void to_host_family(IP *ip) | |||
927 | ip->family = AF_INET6; | 997 | ip->family = AF_INET6; |
928 | } | 998 | } |
929 | /* Send a send nodes response: message for IPv6 nodes */ | 999 | /* Send a send nodes response: message for IPv6 nodes */ |
930 | static int sendnodes_ipv6(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *client_id, uint8_t *encrypted_data) | 1000 | static int sendnodes_ipv6(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *client_id, uint8_t *encrypted_data, |
1001 | uint8_t *shared_encryption_key) | ||
931 | { | 1002 | { |
932 | /* Check if packet is going to be sent to ourself. */ | 1003 | /* Check if packet is going to be sent to ourself. */ |
933 | if (id_equal(public_key, dht->self_public_key)) | 1004 | if (id_equal(public_key, dht->self_public_key)) |
@@ -955,12 +1026,11 @@ static int sendnodes_ipv6(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_ | |||
955 | 1026 | ||
956 | memcpy(plain, nodes_list, num_nodes * Node_format_size); | 1027 | memcpy(plain, nodes_list, num_nodes * Node_format_size); |
957 | memcpy(plain + num_nodes * Node_format_size, encrypted_data, NODES_ENCRYPTED_MESSAGE_LENGTH); | 1028 | memcpy(plain + num_nodes * Node_format_size, encrypted_data, NODES_ENCRYPTED_MESSAGE_LENGTH); |
958 | int len = encrypt_data( public_key, | 1029 | int len = encrypt_data_fast( shared_encryption_key, |
959 | dht->self_secret_key, | 1030 | nonce, |
960 | nonce, | 1031 | plain, |
961 | plain, | 1032 | num_nodes * Node_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH, |
962 | num_nodes * Node_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH, | 1033 | encrypt ); |
963 | encrypt ); | ||
964 | 1034 | ||
965 | if ((unsigned int)len != num_nodes * Node_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES) | 1035 | if ((unsigned int)len != num_nodes * Node_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES) |
966 | return -1; | 1036 | return -1; |
@@ -986,22 +1056,23 @@ static int handle_getnodes(void *object, IP_Port source, uint8_t *packet, uint32 | |||
986 | return 1; | 1056 | return 1; |
987 | 1057 | ||
988 | uint8_t plain[CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH]; | 1058 | uint8_t plain[CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH]; |
1059 | uint8_t shared_key[crypto_box_BEFORENMBYTES]; | ||
989 | 1060 | ||
990 | int len = decrypt_data( packet + 1, | 1061 | DHT_get_shared_key_recv(dht, shared_key, packet + 1); |
991 | dht->self_secret_key, | 1062 | int len = decrypt_data_fast( shared_key, |
992 | packet + 1 + CLIENT_ID_SIZE, | 1063 | packet + 1 + CLIENT_ID_SIZE, |
993 | packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, | 1064 | packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, |
994 | CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES, | 1065 | CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES, |
995 | plain ); | 1066 | plain ); |
996 | 1067 | ||
997 | if (len != CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH) | 1068 | if (len != CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH) |
998 | return 1; | 1069 | return 1; |
999 | 1070 | ||
1000 | sendnodes(dht, source, packet + 1, plain, plain + CLIENT_ID_SIZE); | 1071 | sendnodes(dht, source, packet + 1, plain, plain + CLIENT_ID_SIZE, shared_key); |
1001 | sendnodes_ipv6(dht, source, packet + 1, plain, | 1072 | sendnodes_ipv6(dht, source, packet + 1, plain, |
1002 | plain + CLIENT_ID_SIZE); /* TODO: prevent possible amplification attacks */ | 1073 | plain + CLIENT_ID_SIZE, shared_key); /* TODO: prevent possible amplification attacks */ |
1003 | 1074 | ||
1004 | add_toping(dht->ping, packet + 1, source); | 1075 | add_to_ping(dht->ping, packet + 1, source); |
1005 | //send_ping_request(dht, source, packet + 1); /* TODO: make this smarter? */ | 1076 | //send_ping_request(dht, source, packet + 1); /* TODO: make this smarter? */ |
1006 | 1077 | ||
1007 | return 0; | 1078 | return 0; |
@@ -1062,9 +1133,10 @@ static int handle_sendnodes_core(void *object, IP_Port source, uint8_t *packet, | |||
1062 | if (num_nodes > MAX_SENT_NODES) /* too long */ | 1133 | if (num_nodes > MAX_SENT_NODES) /* too long */ |
1063 | return 1; | 1134 | return 1; |
1064 | 1135 | ||
1065 | int len = decrypt_data( | 1136 | uint8_t shared_key[crypto_box_BEFORENMBYTES]; |
1066 | packet + 1, | 1137 | DHT_get_shared_key_sent(dht, shared_key, packet + 1); |
1067 | dht->self_secret_key, | 1138 | int len = decrypt_data_fast( |
1139 | shared_key, | ||
1068 | packet + 1 + CLIENT_ID_SIZE, | 1140 | packet + 1 + CLIENT_ID_SIZE, |
1069 | packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, | 1141 | packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, |
1070 | num_nodes * node_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES, | 1142 | num_nodes * node_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES, |
@@ -1311,7 +1383,7 @@ int DHT_getfriendip(DHT *dht, uint8_t *client_id, IP_Port *ip_port) | |||
1311 | 1383 | ||
1312 | /* returns number of nodes not in kill-timeout */ | 1384 | /* returns number of nodes not in kill-timeout */ |
1313 | static uint8_t do_ping_and_sendnode_requests(DHT *dht, uint64_t *lastgetnode, uint8_t *client_id, | 1385 | static uint8_t do_ping_and_sendnode_requests(DHT *dht, uint64_t *lastgetnode, uint8_t *client_id, |
1314 | Client_data *list, uint32_t list_count) | 1386 | Client_data *list, uint32_t list_count, uint32_t *bootstrap_times) |
1315 | { | 1387 | { |
1316 | uint32_t i; | 1388 | uint32_t i; |
1317 | uint8_t not_kill = 0; | 1389 | uint8_t not_kill = 0; |
@@ -1345,11 +1417,12 @@ static uint8_t do_ping_and_sendnode_requests(DHT *dht, uint64_t *lastgetnode, ui | |||
1345 | } | 1417 | } |
1346 | } | 1418 | } |
1347 | 1419 | ||
1348 | if ((num_nodes != 0) && is_timeout(*lastgetnode, GET_NODE_INTERVAL)) { | 1420 | if ((num_nodes != 0) && (is_timeout(*lastgetnode, GET_NODE_INTERVAL) || *bootstrap_times < MAX_BOOTSTRAP_TIMES)) { |
1349 | uint32_t rand_node = rand() % num_nodes; | 1421 | uint32_t rand_node = rand() % num_nodes; |
1350 | getnodes(dht, assoc_list[rand_node]->ip_port, client_list[rand_node]->client_id, | 1422 | getnodes(dht, assoc_list[rand_node]->ip_port, client_list[rand_node]->client_id, |
1351 | client_id, NULL); | 1423 | client_id, NULL); |
1352 | *lastgetnode = temp_time; | 1424 | *lastgetnode = temp_time; |
1425 | ++*bootstrap_times; | ||
1353 | } | 1426 | } |
1354 | 1427 | ||
1355 | return not_kill; | 1428 | return not_kill; |
@@ -1364,7 +1437,7 @@ static void do_DHT_friends(DHT *dht) | |||
1364 | 1437 | ||
1365 | for (i = 0; i < dht->num_friends; ++i) | 1438 | for (i = 0; i < dht->num_friends; ++i) |
1366 | do_ping_and_sendnode_requests(dht, &dht->friends_list[i].lastgetnode, dht->friends_list[i].client_id, | 1439 | do_ping_and_sendnode_requests(dht, &dht->friends_list[i].lastgetnode, dht->friends_list[i].client_id, |
1367 | dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS); | 1440 | dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, &dht->friends_list[i].bootstrap_times); |
1368 | } | 1441 | } |
1369 | 1442 | ||
1370 | /* Ping each client in the close nodes list every PING_INTERVAL seconds. | 1443 | /* Ping each client in the close nodes list every PING_INTERVAL seconds. |
@@ -1373,7 +1446,7 @@ static void do_DHT_friends(DHT *dht) | |||
1373 | static void do_Close(DHT *dht) | 1446 | static void do_Close(DHT *dht) |
1374 | { | 1447 | { |
1375 | uint8_t not_killed = do_ping_and_sendnode_requests(dht, &dht->close_lastgetnodes, dht->self_public_key, | 1448 | uint8_t not_killed = do_ping_and_sendnode_requests(dht, &dht->close_lastgetnodes, dht->self_public_key, |
1376 | dht->close_clientlist, LCLIENT_LIST); | 1449 | dht->close_clientlist, LCLIENT_LIST, &dht->close_bootstrap_times); |
1377 | 1450 | ||
1378 | if (!not_killed) { | 1451 | if (!not_killed) { |
1379 | /* all existing nodes are at least KILL_NODE_TIMEOUT, | 1452 | /* all existing nodes are at least KILL_NODE_TIMEOUT, |
@@ -1970,8 +2043,8 @@ static uint32_t have_nodes_closelist(DHT *dht, Node_format *nodes, uint16_t num) | |||
1970 | } | 2043 | } |
1971 | 2044 | ||
1972 | /* Interval in seconds between hardening checks */ | 2045 | /* Interval in seconds between hardening checks */ |
1973 | #define HARDENING_INTERVAL 20 | 2046 | #define HARDENING_INTERVAL 120 |
1974 | #define HARDEN_TIMEOUT 600 | 2047 | #define HARDEN_TIMEOUT 1200 |
1975 | 2048 | ||
1976 | /* Handle a received hardening packet */ | 2049 | /* Handle a received hardening packet */ |
1977 | static int handle_hardening(void *object, IP_Port source, uint8_t *source_pubkey, uint8_t *packet, uint32_t length) | 2050 | static int handle_hardening(void *object, IP_Port source, uint8_t *source_pubkey, uint8_t *packet, uint32_t length) |
@@ -2289,7 +2362,7 @@ void do_DHT(DHT *dht) | |||
2289 | do_Close(dht); | 2362 | do_Close(dht); |
2290 | do_DHT_friends(dht); | 2363 | do_DHT_friends(dht); |
2291 | do_NAT(dht); | 2364 | do_NAT(dht); |
2292 | do_toping(dht->ping); | 2365 | do_to_ping(dht->ping); |
2293 | do_hardening(dht); | 2366 | do_hardening(dht); |
2294 | #ifdef ENABLE_ASSOC_DHT | 2367 | #ifdef ENABLE_ASSOC_DHT |
2295 | 2368 | ||