diff options
Diffstat (limited to 'toxcore')
-rw-r--r-- | toxcore/DHT.c | 153 | ||||
-rw-r--r-- | toxcore/DHT.h | 40 | ||||
-rw-r--r-- | toxcore/Lossless_UDP.c | 3 | ||||
-rw-r--r-- | toxcore/Messenger.c | 244 | ||||
-rw-r--r-- | toxcore/Messenger.h | 6 | ||||
-rw-r--r-- | toxcore/TCP_server.c | 494 | ||||
-rw-r--r-- | toxcore/TCP_server.h | 75 | ||||
-rw-r--r-- | toxcore/net_crypto.c | 10 | ||||
-rw-r--r-- | toxcore/net_crypto.h | 3 | ||||
-rw-r--r-- | toxcore/network.c | 14 | ||||
-rw-r--r-- | toxcore/network.h | 6 | ||||
-rw-r--r-- | toxcore/onion.c | 103 | ||||
-rw-r--r-- | toxcore/onion.h | 33 | ||||
-rw-r--r-- | toxcore/onion_announce.c | 56 | ||||
-rw-r--r-- | toxcore/onion_announce.h | 19 | ||||
-rw-r--r-- | toxcore/onion_client.c | 188 | ||||
-rw-r--r-- | toxcore/onion_client.h | 54 | ||||
-rw-r--r-- | toxcore/ping.c | 124 | ||||
-rw-r--r-- | toxcore/ping.h | 6 | ||||
-rw-r--r-- | toxcore/tox.c | 10 | ||||
-rw-r--r-- | toxcore/tox.h | 7 |
21 files changed, 1390 insertions, 258 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 | ||
diff --git a/toxcore/DHT.h b/toxcore/DHT.h index b649338a..3d2722f8 100644 --- a/toxcore/DHT.h +++ b/toxcore/DHT.h | |||
@@ -38,9 +38,6 @@ | |||
38 | /* The max number of nodes to send with send nodes. */ | 38 | /* The max number of nodes to send with send nodes. */ |
39 | #define MAX_SENT_NODES 8 | 39 | #define MAX_SENT_NODES 8 |
40 | 40 | ||
41 | /* Maximum newly announced nodes to ping per TIME_TOPING seconds. */ | ||
42 | #define MAX_TOPING 16 | ||
43 | |||
44 | /* Ping timeout in seconds */ | 41 | /* Ping timeout in seconds */ |
45 | #define PING_TIMEOUT 3 | 42 | #define PING_TIMEOUT 3 |
46 | 43 | ||
@@ -124,6 +121,8 @@ typedef struct { | |||
124 | 121 | ||
125 | /* Time at which the last get_nodes request was sent. */ | 122 | /* Time at which the last get_nodes request was sent. */ |
126 | uint64_t lastgetnode; | 123 | uint64_t lastgetnode; |
124 | /* number of times get_node packets were sent. */ | ||
125 | uint32_t bootstrap_times; | ||
127 | 126 | ||
128 | /* Symetric NAT hole punching stuff. */ | 127 | /* Symetric NAT hole punching stuff. */ |
129 | NAT nat; | 128 | NAT nat; |
@@ -141,7 +140,20 @@ typedef struct { | |||
141 | } Node_format; | 140 | } Node_format; |
142 | 141 | ||
143 | /*----------------------------------------------------------------------------------*/ | 142 | /*----------------------------------------------------------------------------------*/ |
143 | /* struct to store some shared keys so we don't have to regenerate them for each request. */ | ||
144 | #define MAX_KEYS_PER_SLOT 4 | ||
145 | #define KEYS_TIMEOUT 600 | ||
146 | typedef struct { | ||
147 | struct { | ||
148 | uint8_t client_id[CLIENT_ID_SIZE]; | ||
149 | uint8_t shared_key[crypto_box_BEFORENMBYTES]; | ||
150 | uint32_t times_requested; | ||
151 | uint8_t stored; /* 0 if not, 1 if is */ | ||
152 | uint64_t time_last_requested; | ||
153 | } keys[256 * MAX_KEYS_PER_SLOT]; | ||
154 | } Shared_Keys; | ||
144 | 155 | ||
156 | /*----------------------------------------------------------------------------------*/ | ||
145 | 157 | ||
146 | typedef struct { | 158 | typedef struct { |
147 | Net_Crypto *c; | 159 | Net_Crypto *c; |
@@ -149,6 +161,7 @@ typedef struct { | |||
149 | 161 | ||
150 | Client_data close_clientlist[LCLIENT_LIST]; | 162 | Client_data close_clientlist[LCLIENT_LIST]; |
151 | uint64_t close_lastgetnodes; | 163 | uint64_t close_lastgetnodes; |
164 | uint32_t close_bootstrap_times; | ||
152 | 165 | ||
153 | /* Note: this key should not be/is not used to transmit any sensitive materials */ | 166 | /* Note: this key should not be/is not used to transmit any sensitive materials */ |
154 | uint8_t secret_symmetric_key[crypto_secretbox_KEYBYTES]; | 167 | uint8_t secret_symmetric_key[crypto_secretbox_KEYBYTES]; |
@@ -159,6 +172,9 @@ typedef struct { | |||
159 | DHT_Friend *friends_list; | 172 | DHT_Friend *friends_list; |
160 | uint16_t num_friends; | 173 | uint16_t num_friends; |
161 | 174 | ||
175 | Shared_Keys shared_keys_recv; | ||
176 | Shared_Keys shared_keys_sent; | ||
177 | |||
162 | struct PING *ping; | 178 | struct PING *ping; |
163 | #ifdef ENABLE_ASSOC_DHT | 179 | #ifdef ENABLE_ASSOC_DHT |
164 | struct Assoc *assoc; | 180 | struct Assoc *assoc; |
@@ -167,6 +183,24 @@ typedef struct { | |||
167 | } DHT; | 183 | } DHT; |
168 | /*----------------------------------------------------------------------------------*/ | 184 | /*----------------------------------------------------------------------------------*/ |
169 | 185 | ||
186 | /* Shared key generations are costly, it is therefor smart to store commonly used | ||
187 | * ones so that they can re used later without being computed again. | ||
188 | * | ||
189 | * If shared key is already in shared_keys, copy it to shared_key. | ||
190 | * else generate it into shared_key and copy it to shared_keys | ||
191 | */ | ||
192 | void get_shared_key(Shared_Keys *shared_keys, uint8_t *shared_key, uint8_t *secret_key, uint8_t *client_id); | ||
193 | |||
194 | /* Copy shared_key to decrypt DHT packet from client_id into shared_key | ||
195 | * for packets that we recieve. | ||
196 | */ | ||
197 | void DHT_get_shared_key_recv(DHT *dht, uint8_t *shared_key, uint8_t *client_id); | ||
198 | |||
199 | /* Copy shared_key to decrypt DHT packet from client_id into shared_key | ||
200 | * for packets that we send. | ||
201 | */ | ||
202 | void DHT_get_shared_key_sent(DHT *dht, uint8_t *shared_key, uint8_t *client_id); | ||
203 | |||
170 | void DHT_getnodes(DHT *dht, IP_Port *from_ipp, uint8_t *from_id, uint8_t *which_id); | 204 | void DHT_getnodes(DHT *dht, IP_Port *from_ipp, uint8_t *from_id, uint8_t *which_id); |
171 | 205 | ||
172 | /* Add a new friend to the friends list. | 206 | /* Add a new friend to the friends list. |
diff --git a/toxcore/Lossless_UDP.c b/toxcore/Lossless_UDP.c index 01f9ccc2..c0db8a10 100644 --- a/toxcore/Lossless_UDP.c +++ b/toxcore/Lossless_UDP.c | |||
@@ -1083,6 +1083,9 @@ static void do_new(Lossless_UDP *ludp) | |||
1083 | 1083 | ||
1084 | if (tmp->status != LUDP_NO_CONNECTION && tmp->killat < temp_time) | 1084 | if (tmp->status != LUDP_NO_CONNECTION && tmp->killat < temp_time) |
1085 | tmp->status = LUDP_TIMED_OUT; | 1085 | tmp->status = LUDP_TIMED_OUT; |
1086 | |||
1087 | if (tmp->inbound == LUDP_CONNECTION_INBOUND && tmp->status == LUDP_TIMED_OUT) | ||
1088 | kill_connection(ludp, tmp_i); | ||
1086 | } | 1089 | } |
1087 | } | 1090 | } |
1088 | 1091 | ||
diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index 7ce6bb3c..94e8d0b4 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c | |||
@@ -276,7 +276,7 @@ int32_t m_addfriend(Messenger *m, uint8_t *address, uint8_t *data, uint16_t leng | |||
276 | memcpy(&(m->friendlist[i].friendrequest_nospam), address + crypto_box_PUBLICKEYBYTES, sizeof(uint32_t)); | 276 | memcpy(&(m->friendlist[i].friendrequest_nospam), address + crypto_box_PUBLICKEYBYTES, sizeof(uint32_t)); |
277 | 277 | ||
278 | if (m->numfriends == i) | 278 | if (m->numfriends == i) |
279 | ++ m->numfriends; | 279 | ++m->numfriends; |
280 | 280 | ||
281 | return i; | 281 | return i; |
282 | } | 282 | } |
@@ -321,7 +321,7 @@ int32_t m_addfriend_norequest(Messenger *m, uint8_t *client_id) | |||
321 | m->friendlist[i].receives_read_receipts = 1; /* Default: YES. */ | 321 | m->friendlist[i].receives_read_receipts = 1; /* Default: YES. */ |
322 | 322 | ||
323 | if (m->numfriends == i) | 323 | if (m->numfriends == i) |
324 | ++ m->numfriends; | 324 | ++m->numfriends; |
325 | 325 | ||
326 | return i; | 326 | return i; |
327 | } | 327 | } |
@@ -635,7 +635,16 @@ uint8_t m_get_self_userstatus(Messenger *m) | |||
635 | return m->userstatus; | 635 | return m->userstatus; |
636 | } | 636 | } |
637 | 637 | ||
638 | uint64_t m_get_last_online(Messenger *m, int32_t friendnumber) | ||
639 | { | ||
640 | if (friend_not_valid(m, friendnumber)) | ||
641 | return -1; | ||
642 | |||
643 | return m->friendlist[friendnumber].ping_lastrecv; | ||
644 | } | ||
645 | |||
638 | int m_set_usertyping(Messenger *m, int32_t friendnumber, uint8_t is_typing) | 646 | int m_set_usertyping(Messenger *m, int32_t friendnumber, uint8_t is_typing) |
647 | |||
639 | { | 648 | { |
640 | if (is_typing != 0 && is_typing != 1) { | 649 | if (is_typing != 0 && is_typing != 1) { |
641 | return -1; | 650 | return -1; |
@@ -1688,6 +1697,12 @@ int custom_user_packet_registerhandler(Messenger *m, int32_t friendnumber, uint8 | |||
1688 | 1697 | ||
1689 | int send_custom_user_packet(Messenger *m, int32_t friendnumber, uint8_t *data, uint32_t length) | 1698 | int send_custom_user_packet(Messenger *m, int32_t friendnumber, uint8_t *data, uint32_t length) |
1690 | { | 1699 | { |
1700 | if (friend_not_valid(m, friendnumber)) | ||
1701 | return -1; | ||
1702 | |||
1703 | if (m->friendlist[friendnumber].status != FRIEND_ONLINE) | ||
1704 | return -1; | ||
1705 | |||
1691 | IP_Port ip_port = get_friend_ipport(m, friendnumber); | 1706 | IP_Port ip_port = get_friend_ipport(m, friendnumber); |
1692 | 1707 | ||
1693 | if (ip_port.port == 0) | 1708 | if (ip_port.port == 0) |
@@ -1967,10 +1982,11 @@ void do_friends(Messenger *m) | |||
1967 | 1982 | ||
1968 | uint8_t typing = data[0]; | 1983 | uint8_t typing = data[0]; |
1969 | 1984 | ||
1985 | set_friend_typing(m, i, typing); | ||
1986 | |||
1970 | if (m->friend_typingchange) | 1987 | if (m->friend_typingchange) |
1971 | m->friend_typingchange(m, i, typing, m->friend_typingchange_userdata); | 1988 | m->friend_typingchange(m, i, typing, m->friend_typingchange_userdata); |
1972 | 1989 | ||
1973 | set_friend_typing(m, i, typing); | ||
1974 | break; | 1990 | break; |
1975 | } | 1991 | } |
1976 | 1992 | ||
@@ -2062,6 +2078,7 @@ void do_friends(Messenger *m) | |||
2062 | break; | 2078 | break; |
2063 | 2079 | ||
2064 | group_newpeer(m->chats[groupnum], data + crypto_box_PUBLICKEYBYTES); | 2080 | group_newpeer(m->chats[groupnum], data + crypto_box_PUBLICKEYBYTES); |
2081 | /* This is just there to speedup joining. */ | ||
2065 | chat_bootstrap(m->chats[groupnum], get_friend_ipport(m, i), data + crypto_box_PUBLICKEYBYTES); | 2082 | chat_bootstrap(m->chats[groupnum], get_friend_ipport(m, i), data + crypto_box_PUBLICKEYBYTES); |
2066 | break; | 2083 | break; |
2067 | } | 2084 | } |
@@ -2179,6 +2196,8 @@ void do_inbound(Messenger *m) | |||
2179 | accept_crypto_inbound(m->net_crypto, inconnection, public_key, secret_nonce, session_key); | 2196 | accept_crypto_inbound(m->net_crypto, inconnection, public_key, secret_nonce, session_key); |
2180 | 2197 | ||
2181 | set_friend_status(m, friend_id, FRIEND_CONFIRMED); | 2198 | set_friend_status(m, friend_id, FRIEND_CONFIRMED); |
2199 | } else { | ||
2200 | kill_connection(m->net_crypto->lossless_udp, inconnection); | ||
2182 | } | 2201 | } |
2183 | } | 2202 | } |
2184 | } | 2203 | } |
@@ -2366,13 +2385,134 @@ int wait_cleanup_messenger(Messenger *m, uint8_t *data) | |||
2366 | 2385 | ||
2367 | /* new messenger format for load/save, more robust and forward compatible */ | 2386 | /* new messenger format for load/save, more robust and forward compatible */ |
2368 | 2387 | ||
2369 | #define MESSENGER_STATE_COOKIE_GLOBAL 0x15ed1b1e | 2388 | #define MESSENGER_STATE_COOKIE_GLOBAL_OLD 0x15ed1b1e |
2389 | #define MESSENGER_STATE_COOKIE_GLOBAL 0x15ed1b1f | ||
2370 | 2390 | ||
2371 | #define MESSENGER_STATE_COOKIE_TYPE 0x01ce | 2391 | #define MESSENGER_STATE_COOKIE_TYPE 0x01ce |
2372 | #define MESSENGER_STATE_TYPE_NOSPAMKEYS 1 | 2392 | #define MESSENGER_STATE_TYPE_NOSPAMKEYS 1 |
2373 | #define MESSENGER_STATE_TYPE_DHT 2 | 2393 | #define MESSENGER_STATE_TYPE_DHT 2 |
2374 | #define MESSENGER_STATE_TYPE_FRIENDS 3 | 2394 | #define MESSENGER_STATE_TYPE_FRIENDS 3 |
2375 | #define MESSENGER_STATE_TYPE_NAME 4 | 2395 | #define MESSENGER_STATE_TYPE_NAME 4 |
2396 | #define MESSENGER_STATE_TYPE_STATUSMESSAGE 5 | ||
2397 | #define MESSENGER_STATE_TYPE_STATUS 6 | ||
2398 | |||
2399 | struct SAVED_FRIEND { | ||
2400 | uint8_t status; | ||
2401 | uint8_t client_id[CLIENT_ID_SIZE]; | ||
2402 | uint8_t info[MAX_DATA_SIZE]; // the data that is sent during the friend requests we do. | ||
2403 | uint16_t info_size; // Length of the info. | ||
2404 | uint8_t name[MAX_NAME_LENGTH]; | ||
2405 | uint16_t name_length; | ||
2406 | uint8_t statusmessage[MAX_STATUSMESSAGE_LENGTH]; | ||
2407 | uint16_t statusmessage_length; | ||
2408 | uint8_t userstatus; | ||
2409 | uint32_t friendrequest_nospam; | ||
2410 | uint64_t ping_lastrecv; | ||
2411 | }; | ||
2412 | |||
2413 | /* for backwards compatibility with last version of SAVED_FRIEND. | ||
2414 | must never be bigger than SAVED_FRIEND. */ | ||
2415 | struct SAVED_FRIEND_OLD { | ||
2416 | uint8_t status; | ||
2417 | uint8_t client_id[CLIENT_ID_SIZE]; | ||
2418 | uint8_t info[MAX_DATA_SIZE]; | ||
2419 | uint16_t info_size; | ||
2420 | uint8_t name[MAX_NAME_LENGTH]; | ||
2421 | uint16_t name_length; | ||
2422 | uint8_t statusmessage[MAX_STATUSMESSAGE_LENGTH]; | ||
2423 | uint16_t statusmessage_length; | ||
2424 | uint8_t userstatus; | ||
2425 | uint32_t friendrequest_nospam; | ||
2426 | }; | ||
2427 | |||
2428 | static uint32_t saved_friendslist_size(Messenger *m) | ||
2429 | { | ||
2430 | return count_friendlist(m) * sizeof(struct SAVED_FRIEND); | ||
2431 | } | ||
2432 | |||
2433 | static uint32_t friends_list_save(Messenger *m, uint8_t *data) | ||
2434 | { | ||
2435 | uint32_t i; | ||
2436 | uint32_t num = 0; | ||
2437 | |||
2438 | for (i = 0; i < m->numfriends; i++) { | ||
2439 | if (m->friendlist[i].status > 0) { | ||
2440 | struct SAVED_FRIEND temp; | ||
2441 | memset(&temp, 0, sizeof(struct SAVED_FRIEND)); | ||
2442 | temp.status = m->friendlist[i].status; | ||
2443 | memcpy(temp.client_id, m->friendlist[i].client_id, CLIENT_ID_SIZE); | ||
2444 | |||
2445 | if (temp.status < 3) { | ||
2446 | memcpy(temp.info, m->friendlist[i].info, m->friendlist[i].info_size); | ||
2447 | temp.info_size = htons(m->friendlist[i].info_size); | ||
2448 | temp.friendrequest_nospam = m->friendlist[i].friendrequest_nospam; | ||
2449 | } else { | ||
2450 | memcpy(temp.name, m->friendlist[i].name, m->friendlist[i].name_length); | ||
2451 | temp.name_length = htons(m->friendlist[i].name_length); | ||
2452 | memcpy(temp.statusmessage, m->friendlist[i].statusmessage, m->friendlist[i].statusmessage_length); | ||
2453 | temp.statusmessage_length = htons(m->friendlist[i].statusmessage_length); | ||
2454 | temp.userstatus = m->friendlist[i].userstatus; | ||
2455 | |||
2456 | uint8_t lastonline[sizeof(uint64_t)]; | ||
2457 | memcpy(lastonline, &m->friendlist[i].ping_lastrecv, sizeof(uint64_t)); | ||
2458 | host_to_net(lastonline, sizeof(uint64_t)); | ||
2459 | memcpy(&temp.ping_lastrecv, lastonline, sizeof(uint64_t)); | ||
2460 | } | ||
2461 | |||
2462 | memcpy(data + num * sizeof(struct SAVED_FRIEND), &temp, sizeof(struct SAVED_FRIEND)); | ||
2463 | num++; | ||
2464 | } | ||
2465 | } | ||
2466 | |||
2467 | return num * sizeof(struct SAVED_FRIEND); | ||
2468 | } | ||
2469 | |||
2470 | static int friends_list_load(Messenger *m, uint8_t *data, uint32_t length) | ||
2471 | { | ||
2472 | int old_data = 0; | ||
2473 | |||
2474 | if (length % sizeof(struct SAVED_FRIEND) != 0) { | ||
2475 | if (length % sizeof(struct SAVED_FRIEND_OLD) != 0) | ||
2476 | return -1; | ||
2477 | |||
2478 | old_data = 1; | ||
2479 | } | ||
2480 | |||
2481 | /* if old data file is being used, offset size of current SAVED_FRIEND struct with size of old one */ | ||
2482 | uint32_t diff = old_data ? sizeof(struct SAVED_FRIEND) - sizeof(struct SAVED_FRIEND_OLD) : 0; | ||
2483 | uint32_t struct_size = sizeof(struct SAVED_FRIEND) - diff; | ||
2484 | uint32_t num = length / struct_size; | ||
2485 | uint32_t i; | ||
2486 | |||
2487 | for (i = 0; i < num; ++i) { | ||
2488 | struct SAVED_FRIEND temp; | ||
2489 | memcpy(&temp, data + i * struct_size, struct_size); | ||
2490 | |||
2491 | if (temp.status >= 3) { | ||
2492 | int fnum = m_addfriend_norequest(m, temp.client_id); | ||
2493 | setfriendname(m, fnum, temp.name, ntohs(temp.name_length)); | ||
2494 | set_friend_statusmessage(m, fnum, temp.statusmessage, ntohs(temp.statusmessage_length)); | ||
2495 | set_friend_userstatus(m, fnum, temp.userstatus); | ||
2496 | |||
2497 | if (!old_data) { | ||
2498 | uint8_t lastonline[sizeof(uint64_t)]; | ||
2499 | memcpy(lastonline, &temp.ping_lastrecv, sizeof(uint64_t)); | ||
2500 | net_to_host(lastonline, sizeof(uint64_t)); | ||
2501 | memcpy(&m->friendlist[fnum].ping_lastrecv, lastonline, sizeof(uint64_t)); | ||
2502 | } | ||
2503 | } else if (temp.status != 0) { | ||
2504 | /* TODO: This is not a good way to do this. */ | ||
2505 | uint8_t address[FRIEND_ADDRESS_SIZE]; | ||
2506 | id_copy(address, temp.client_id); | ||
2507 | memcpy(address + crypto_box_PUBLICKEYBYTES, &(temp.friendrequest_nospam), sizeof(uint32_t)); | ||
2508 | uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum)); | ||
2509 | memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(uint32_t), &checksum, sizeof(checksum)); | ||
2510 | m_addfriend(m, address, temp.info, ntohs(temp.info_size)); | ||
2511 | } | ||
2512 | } | ||
2513 | |||
2514 | return num; | ||
2515 | } | ||
2376 | 2516 | ||
2377 | /* return size of the messenger data (for saving) */ | 2517 | /* return size of the messenger data (for saving) */ |
2378 | uint32_t messenger_size(Messenger *m) | 2518 | uint32_t messenger_size(Messenger *m) |
@@ -2381,8 +2521,10 @@ uint32_t messenger_size(Messenger *m) | |||
2381 | return size32 * 2 // global cookie | 2521 | return size32 * 2 // global cookie |
2382 | + sizesubhead + sizeof(uint32_t) + crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES | 2522 | + sizesubhead + sizeof(uint32_t) + crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES |
2383 | + sizesubhead + DHT_size(m->dht) // DHT | 2523 | + sizesubhead + DHT_size(m->dht) // DHT |
2384 | + sizesubhead + sizeof(Friend) * m->numfriends // Friendlist itself. | 2524 | + sizesubhead + saved_friendslist_size(m) // Friendlist itself. |
2385 | + sizesubhead + m->name_length // Own nickname. | 2525 | + sizesubhead + m->name_length // Own nickname. |
2526 | + sizesubhead + m->statusmessage_length // status message | ||
2527 | + sizesubhead + 1 // status | ||
2386 | ; | 2528 | ; |
2387 | } | 2529 | } |
2388 | 2530 | ||
@@ -2395,6 +2537,7 @@ static uint8_t *z_state_save_subheader(uint8_t *data, uint32_t len, uint16_t typ | |||
2395 | return data; | 2537 | return data; |
2396 | } | 2538 | } |
2397 | 2539 | ||
2540 | |||
2398 | /* Save the messenger in data of size Messenger_size(). */ | 2541 | /* Save the messenger in data of size Messenger_size(). */ |
2399 | void messenger_save(Messenger *m, uint8_t *data) | 2542 | void messenger_save(Messenger *m, uint8_t *data) |
2400 | { | 2543 | { |
@@ -2423,10 +2566,10 @@ void messenger_save(Messenger *m, uint8_t *data) | |||
2423 | DHT_save(m->dht, data); | 2566 | DHT_save(m->dht, data); |
2424 | data += len; | 2567 | data += len; |
2425 | 2568 | ||
2426 | len = sizeof(Friend) * m->numfriends; | 2569 | len = saved_friendslist_size(m); |
2427 | type = MESSENGER_STATE_TYPE_FRIENDS; | 2570 | type = MESSENGER_STATE_TYPE_FRIENDS; |
2428 | data = z_state_save_subheader(data, len, type); | 2571 | data = z_state_save_subheader(data, len, type); |
2429 | memcpy(data, m->friendlist, len); | 2572 | friends_list_save(m, data); |
2430 | data += len; | 2573 | data += len; |
2431 | 2574 | ||
2432 | len = m->name_length; | 2575 | len = m->name_length; |
@@ -2434,9 +2577,21 @@ void messenger_save(Messenger *m, uint8_t *data) | |||
2434 | data = z_state_save_subheader(data, len, type); | 2577 | data = z_state_save_subheader(data, len, type); |
2435 | memcpy(data, m->name, len); | 2578 | memcpy(data, m->name, len); |
2436 | data += len; | 2579 | data += len; |
2580 | |||
2581 | len = m->statusmessage_length; | ||
2582 | type = MESSENGER_STATE_TYPE_STATUSMESSAGE; | ||
2583 | data = z_state_save_subheader(data, len, type); | ||
2584 | memcpy(data, m->statusmessage, len); | ||
2585 | data += len; | ||
2586 | |||
2587 | len = 1; | ||
2588 | type = MESSENGER_STATE_TYPE_STATUS; | ||
2589 | data = z_state_save_subheader(data, len, type); | ||
2590 | *data = m->userstatus; | ||
2591 | data += len; | ||
2437 | } | 2592 | } |
2438 | 2593 | ||
2439 | static int messenger_load_state_callback(void *outer, uint8_t *data, uint32_t length, uint16_t type) | 2594 | static int messenger_load_state_callback_old(void *outer, uint8_t *data, uint32_t length, uint16_t type) |
2440 | { | 2595 | { |
2441 | Messenger *m = outer; | 2596 | Messenger *m = outer; |
2442 | 2597 | ||
@@ -2504,6 +2659,66 @@ static int messenger_load_state_callback(void *outer, uint8_t *data, uint32_t le | |||
2504 | return 0; | 2659 | return 0; |
2505 | } | 2660 | } |
2506 | 2661 | ||
2662 | static int messenger_load_state_callback(void *outer, uint8_t *data, uint32_t length, uint16_t type) | ||
2663 | { | ||
2664 | Messenger *m = outer; | ||
2665 | |||
2666 | switch (type) { | ||
2667 | case MESSENGER_STATE_TYPE_NOSPAMKEYS: | ||
2668 | if (length == crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t)) { | ||
2669 | set_nospam(&(m->fr), *(uint32_t *)data); | ||
2670 | load_keys(m->net_crypto, &data[sizeof(uint32_t)]); | ||
2671 | #ifdef ENABLE_ASSOC_DHT | ||
2672 | |||
2673 | if (m->dht->assoc) | ||
2674 | Assoc_self_client_id_changed(m->dht->assoc, m->net_crypto->self_public_key); | ||
2675 | |||
2676 | #endif | ||
2677 | } else | ||
2678 | return -1; /* critical */ | ||
2679 | |||
2680 | break; | ||
2681 | |||
2682 | case MESSENGER_STATE_TYPE_DHT: | ||
2683 | DHT_load(m->dht, data, length); | ||
2684 | break; | ||
2685 | |||
2686 | case MESSENGER_STATE_TYPE_FRIENDS: | ||
2687 | friends_list_load(m, data, length); | ||
2688 | break; | ||
2689 | |||
2690 | case MESSENGER_STATE_TYPE_NAME: | ||
2691 | if ((length > 0) && (length < MAX_NAME_LENGTH)) { | ||
2692 | setname(m, data, length); | ||
2693 | } | ||
2694 | |||
2695 | break; | ||
2696 | |||
2697 | case MESSENGER_STATE_TYPE_STATUSMESSAGE: | ||
2698 | if ((length > 0) && (length < MAX_STATUSMESSAGE_LENGTH)) { | ||
2699 | m_set_statusmessage(m, data, length); | ||
2700 | } | ||
2701 | |||
2702 | break; | ||
2703 | |||
2704 | case MESSENGER_STATE_TYPE_STATUS: | ||
2705 | if (length == 1) { | ||
2706 | m_set_userstatus(m, *data); | ||
2707 | } | ||
2708 | |||
2709 | break; | ||
2710 | #ifdef DEBUG | ||
2711 | |||
2712 | default: | ||
2713 | fprintf(stderr, "Load state: contains unrecognized part (len %u, type %u)\n", | ||
2714 | length, type); | ||
2715 | break; | ||
2716 | #endif | ||
2717 | } | ||
2718 | |||
2719 | return 0; | ||
2720 | } | ||
2721 | |||
2507 | /* Load the messenger from data of size length. */ | 2722 | /* Load the messenger from data of size length. */ |
2508 | int messenger_load(Messenger *m, uint8_t *data, uint32_t length) | 2723 | int messenger_load(Messenger *m, uint8_t *data, uint32_t length) |
2509 | { | 2724 | { |
@@ -2517,6 +2732,10 @@ int messenger_load(Messenger *m, uint8_t *data, uint32_t length) | |||
2517 | if (!data32[0] && (data32[1] == MESSENGER_STATE_COOKIE_GLOBAL)) | 2732 | if (!data32[0] && (data32[1] == MESSENGER_STATE_COOKIE_GLOBAL)) |
2518 | return load_state(messenger_load_state_callback, m, data + cookie_len, | 2733 | return load_state(messenger_load_state_callback, m, data + cookie_len, |
2519 | length - cookie_len, MESSENGER_STATE_COOKIE_TYPE); | 2734 | length - cookie_len, MESSENGER_STATE_COOKIE_TYPE); |
2735 | |||
2736 | else if (!data32[0] && (data32[1] == MESSENGER_STATE_COOKIE_GLOBAL_OLD)) | ||
2737 | return load_state(messenger_load_state_callback_old, m, data + cookie_len, | ||
2738 | length - cookie_len, MESSENGER_STATE_COOKIE_TYPE); | ||
2520 | else /* old state file */ | 2739 | else /* old state file */ |
2521 | return -1; | 2740 | return -1; |
2522 | } | 2741 | } |
@@ -2724,4 +2943,3 @@ uint32_t copy_chatlist(Messenger *m, int *out_list, uint32_t list_size) | |||
2724 | 2943 | ||
2725 | return ret; | 2944 | return ret; |
2726 | } | 2945 | } |
2727 | |||
diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h index 9e91ccee..f9d723a5 100644 --- a/toxcore/Messenger.h +++ b/toxcore/Messenger.h | |||
@@ -414,6 +414,11 @@ int m_copy_self_statusmessage(Messenger *m, uint8_t *buf, uint32_t maxlen); | |||
414 | uint8_t m_get_userstatus(Messenger *m, int32_t friendnumber); | 414 | uint8_t m_get_userstatus(Messenger *m, int32_t friendnumber); |
415 | uint8_t m_get_self_userstatus(Messenger *m); | 415 | uint8_t m_get_self_userstatus(Messenger *m); |
416 | 416 | ||
417 | /* returns timestamp of last time friendnumber was seen online, or 0 if never seen. | ||
418 | * returns -1 on error. | ||
419 | */ | ||
420 | uint64_t m_get_last_online(Messenger *m, int32_t friendnumber); | ||
421 | |||
417 | /* Set our typing status for a friend. | 422 | /* Set our typing status for a friend. |
418 | * You are responsible for turning it on or off. | 423 | * You are responsible for turning it on or off. |
419 | * | 424 | * |
@@ -786,4 +791,3 @@ uint32_t count_chatlist(Messenger *m); | |||
786 | uint32_t copy_chatlist(Messenger *m, int *out_list, uint32_t list_size); | 791 | uint32_t copy_chatlist(Messenger *m, int *out_list, uint32_t list_size); |
787 | 792 | ||
788 | #endif | 793 | #endif |
789 | |||
diff --git a/toxcore/TCP_server.c b/toxcore/TCP_server.c new file mode 100644 index 00000000..15212d84 --- /dev/null +++ b/toxcore/TCP_server.c | |||
@@ -0,0 +1,494 @@ | |||
1 | /* | ||
2 | * TCP_server.c -- Implementation of the TCP relay server part of Tox. | ||
3 | * | ||
4 | * Copyright (C) 2013 Tox project All Rights Reserved. | ||
5 | * | ||
6 | * This file is part of Tox. | ||
7 | * | ||
8 | * Tox is free software: you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation, either version 3 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * Tox is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with Tox. If not, see <http://www.gnu.org/licenses/>. | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include "TCP_server.h" | ||
24 | |||
25 | #if !defined(_WIN32) && !defined(__WIN32__) && !defined (WIN32) | ||
26 | #include <sys/ioctl.h> | ||
27 | #endif | ||
28 | |||
29 | /* return 1 if valid | ||
30 | * return 0 if not valid | ||
31 | */ | ||
32 | static int sock_valid(sock_t sock) | ||
33 | { | ||
34 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) | ||
35 | |||
36 | if (sock == INVALID_SOCKET) { | ||
37 | #else | ||
38 | |||
39 | if (sock < 0) { | ||
40 | #endif | ||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | return 1; | ||
45 | } | ||
46 | |||
47 | static void kill_sock(sock_t sock) | ||
48 | { | ||
49 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) | ||
50 | closesocket(sock); | ||
51 | #else | ||
52 | close(sock); | ||
53 | #endif | ||
54 | } | ||
55 | |||
56 | /* return 1 on success | ||
57 | * return 0 on failure | ||
58 | */ | ||
59 | static int set_nonblock(sock_t sock) | ||
60 | { | ||
61 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) | ||
62 | u_long mode = 1; | ||
63 | return (ioctlsocket(sock, FIONBIO, &mode) == 0); | ||
64 | #else | ||
65 | return (fcntl(sock, F_SETFL, O_NONBLOCK, 1) == 0); | ||
66 | #endif | ||
67 | } | ||
68 | |||
69 | /* return 1 on success | ||
70 | * return 0 on failure | ||
71 | */ | ||
72 | static int set_dualstack(sock_t sock) | ||
73 | { | ||
74 | char ipv6only = 0; | ||
75 | socklen_t optsize = sizeof(ipv6only); | ||
76 | int res = getsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6only, &optsize); | ||
77 | |||
78 | if ((res == 0) && (ipv6only == 0)) | ||
79 | return 1; | ||
80 | |||
81 | ipv6only = 0; | ||
82 | return (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6only, sizeof(ipv6only)) == 0); | ||
83 | } | ||
84 | |||
85 | /* return 1 on success | ||
86 | * return 0 on failure | ||
87 | */ | ||
88 | static int bind_to_port(sock_t sock, int family, uint16_t port) | ||
89 | { | ||
90 | struct sockaddr_storage addr = {0}; | ||
91 | size_t addrsize; | ||
92 | |||
93 | if (family == AF_INET) { | ||
94 | struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr; | ||
95 | |||
96 | addrsize = sizeof(struct sockaddr_in); | ||
97 | addr4->sin_family = AF_INET; | ||
98 | addr4->sin_port = htons(port); | ||
99 | } else if (family == AF_INET6) { | ||
100 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr; | ||
101 | |||
102 | addrsize = sizeof(struct sockaddr_in6); | ||
103 | addr6->sin6_family = AF_INET6; | ||
104 | addr6->sin6_port = htons(port); | ||
105 | } else { | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | return (bind(sock, (struct sockaddr *)&addr, addrsize) == 0); | ||
110 | } | ||
111 | |||
112 | /* return length on success | ||
113 | * return 0 if nothing has been read from socket. | ||
114 | * return ~0 on failure. | ||
115 | */ | ||
116 | static uint16_t read_length(sock_t sock) | ||
117 | { | ||
118 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) | ||
119 | unsigned long count = 0; | ||
120 | ioctlsocket(sock, FIONREAD, &count); | ||
121 | #else | ||
122 | int count = 0; | ||
123 | ioctl(sock, FIONREAD, &count); | ||
124 | #endif | ||
125 | |||
126 | if ((unsigned int)count >= sizeof(uint16_t)) { | ||
127 | uint16_t length; | ||
128 | int len = recv(sock, (uint8_t *)&length, sizeof(uint16_t), 0); | ||
129 | |||
130 | if (len != sizeof(uint16_t)) { | ||
131 | fprintf(stderr, "FAIL recv packet\n"); | ||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | length = ntohs(length); | ||
136 | |||
137 | if (length > MAX_PACKET_SIZE) { | ||
138 | return ~0; | ||
139 | } | ||
140 | |||
141 | return length; | ||
142 | } | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | /* return length on success | ||
148 | * return -1 on failure | ||
149 | */ | ||
150 | static int read_TCP_packet(sock_t sock, uint8_t *data, uint16_t length) | ||
151 | { | ||
152 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) | ||
153 | unsigned long count = 0; | ||
154 | ioctlsocket(sock, FIONREAD, &count); | ||
155 | #else | ||
156 | int count = 0; | ||
157 | ioctl(sock, FIONREAD, &count); | ||
158 | #endif | ||
159 | |||
160 | if (count >= length) { | ||
161 | int len = recv(sock, data, length, 0); | ||
162 | |||
163 | if (len != length) { | ||
164 | fprintf(stderr, "FAIL recv packet\n"); | ||
165 | return -1; | ||
166 | } | ||
167 | |||
168 | return len; | ||
169 | } | ||
170 | |||
171 | return -1; | ||
172 | } | ||
173 | |||
174 | /* return length of recieved packet on success. | ||
175 | * return 0 if could not read any packet. | ||
176 | * return -1 on failure (connection must be killed). | ||
177 | */ | ||
178 | static int read_packet_TCP_secure_connection(TCP_Secure_Connection *con, uint8_t *data, uint16_t max_len) | ||
179 | { | ||
180 | if (con->next_packet_length == 0) { | ||
181 | uint16_t len = read_length(con->sock); | ||
182 | |||
183 | if (len == (uint16_t)~0) | ||
184 | return -1; | ||
185 | |||
186 | if (len == 0) | ||
187 | return 0; | ||
188 | |||
189 | con->next_packet_length = len; | ||
190 | } | ||
191 | |||
192 | if (max_len + crypto_box_MACBYTES < con->next_packet_length) | ||
193 | return -1; | ||
194 | |||
195 | uint8_t data_encrypted[con->next_packet_length]; | ||
196 | int len_packet = read_TCP_packet(con->sock, data_encrypted, con->next_packet_length); | ||
197 | |||
198 | if (len_packet != con->next_packet_length) | ||
199 | return 0; | ||
200 | |||
201 | con->next_packet_length = 0; | ||
202 | |||
203 | int len = decrypt_data_fast(con->shared_key, con->recv_nonce, data_encrypted, len_packet, data); | ||
204 | |||
205 | if (len + crypto_box_MACBYTES != len_packet) | ||
206 | return -1; | ||
207 | |||
208 | increment_nonce(con->recv_nonce); | ||
209 | |||
210 | return len; | ||
211 | } | ||
212 | |||
213 | /* return 1 on success. | ||
214 | * return 0 if could not send packet. | ||
215 | * return -1 on failure (connection must be killed). | ||
216 | */ | ||
217 | static int write_packet_TCP_secure_connection(TCP_Secure_Connection *con, uint8_t *data, uint16_t length) | ||
218 | { | ||
219 | if (length + crypto_box_MACBYTES > MAX_PACKET_SIZE) | ||
220 | return -1; | ||
221 | |||
222 | uint8_t packet[sizeof(uint16_t) + length + crypto_box_MACBYTES]; | ||
223 | |||
224 | length = htons(length); | ||
225 | memcpy(packet, &length, sizeof(uint16_t)); | ||
226 | uint32_t len = encrypt_data_fast(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t)); | ||
227 | |||
228 | if (len != (sizeof(packet) - sizeof(uint16_t))) | ||
229 | return -1; | ||
230 | |||
231 | increment_nonce(con->sent_nonce); | ||
232 | |||
233 | len = send(con->sock, packet, sizeof(packet), 0); | ||
234 | |||
235 | if (len == sizeof(packet)) | ||
236 | return 1; | ||
237 | |||
238 | if (len <= 0) | ||
239 | return 0; | ||
240 | |||
241 | return -1; | ||
242 | } | ||
243 | |||
244 | /* Kill a TCP_Secure_Connection | ||
245 | */ | ||
246 | static void kill_TCP_connection(TCP_Secure_Connection *con) | ||
247 | { | ||
248 | kill_sock(con->sock); | ||
249 | memset(con, 0, sizeof(TCP_Secure_Connection)); | ||
250 | } | ||
251 | |||
252 | /* return 1 if everything went well. | ||
253 | * return -1 if the connection must be killed. | ||
254 | */ | ||
255 | static int handle_TCP_handshake(TCP_Secure_Connection *con, uint8_t *data, uint16_t length, uint8_t *self_secret_key) | ||
256 | { | ||
257 | if (length != TCP_CLIENT_HANDSHAKE_SIZE) | ||
258 | return -1; | ||
259 | |||
260 | if (con->status != TCP_STATUS_CONNECTED) | ||
261 | return -1; | ||
262 | |||
263 | uint8_t shared_key[crypto_box_BEFORENMBYTES]; | ||
264 | encrypt_precompute(data, self_secret_key, shared_key); | ||
265 | uint8_t plain[TCP_HANDSHAKE_PLAIN_SIZE]; | ||
266 | int len = decrypt_data_fast(shared_key, data + crypto_box_PUBLICKEYBYTES, | ||
267 | data + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, TCP_HANDSHAKE_PLAIN_SIZE + crypto_box_MACBYTES, plain); | ||
268 | |||
269 | if (len != TCP_HANDSHAKE_PLAIN_SIZE) | ||
270 | return -1; | ||
271 | |||
272 | uint8_t temp_secret_key[crypto_box_SECRETKEYBYTES]; | ||
273 | uint8_t resp_plain[TCP_HANDSHAKE_PLAIN_SIZE]; | ||
274 | crypto_box_keypair(resp_plain, temp_secret_key); | ||
275 | random_nonce(con->sent_nonce); | ||
276 | memcpy(resp_plain + crypto_box_PUBLICKEYBYTES, con->sent_nonce, crypto_box_NONCEBYTES); | ||
277 | memcpy(con->recv_nonce, plain + crypto_box_PUBLICKEYBYTES, crypto_box_NONCEBYTES); | ||
278 | |||
279 | uint8_t response[TCP_SERVER_HANDSHAKE_SIZE]; | ||
280 | new_nonce(response); | ||
281 | |||
282 | len = encrypt_data_fast(shared_key, response, resp_plain, TCP_HANDSHAKE_PLAIN_SIZE, response + crypto_box_NONCEBYTES); | ||
283 | |||
284 | if (len != TCP_HANDSHAKE_PLAIN_SIZE + crypto_box_MACBYTES) | ||
285 | return -1; | ||
286 | |||
287 | if (TCP_SERVER_HANDSHAKE_SIZE != send(con->sock, response, TCP_SERVER_HANDSHAKE_SIZE, 0)) | ||
288 | return -1; | ||
289 | |||
290 | encrypt_precompute(plain, temp_secret_key, con->shared_key); | ||
291 | con->status = TCP_STATUS_UNCONFIRMED; | ||
292 | return 1; | ||
293 | } | ||
294 | |||
295 | /* return 1 if connection handshake was handled correctly. | ||
296 | * return 0 if we didn't get it yet. | ||
297 | * return -1 if the connection must be killed. | ||
298 | */ | ||
299 | static int read_connection_handshake(TCP_Secure_Connection *con, uint8_t *self_secret_key) | ||
300 | { | ||
301 | uint8_t data[TCP_CLIENT_HANDSHAKE_SIZE]; | ||
302 | int len = 0; | ||
303 | |||
304 | if ((len = read_TCP_packet(con->sock, data, TCP_CLIENT_HANDSHAKE_SIZE)) != -1) { | ||
305 | return handle_TCP_handshake(con, data, len, self_secret_key); | ||
306 | } | ||
307 | |||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | |||
312 | static int confirm_TCP_connection(TCP_Secure_Connection *con, uint8_t *data, uint16_t length) | ||
313 | { | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | /* return 1 on success | ||
319 | * return 0 on failure | ||
320 | */ | ||
321 | static int accept_connection(TCP_Server *TCP_server, sock_t sock) | ||
322 | { | ||
323 | if (!sock_valid(sock)) | ||
324 | return 0; | ||
325 | |||
326 | if (!set_nonblock(sock)) { | ||
327 | kill_sock(sock); | ||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | TCP_Secure_Connection *conn = | ||
332 | &TCP_server->incomming_connection_queue[TCP_server->incomming_connection_queue_index % MAX_INCOMMING_CONNECTIONS]; | ||
333 | |||
334 | if (conn->status != TCP_STATUS_NO_STATUS) | ||
335 | kill_TCP_connection(conn); | ||
336 | |||
337 | conn->status = TCP_STATUS_CONNECTED; | ||
338 | conn->sock = sock; | ||
339 | conn->next_packet_length = 0; | ||
340 | |||
341 | ++TCP_server->incomming_connection_queue_index; | ||
342 | return 1; | ||
343 | } | ||
344 | |||
345 | static sock_t new_listening_TCP_socket(int family, uint16_t port) | ||
346 | { | ||
347 | sock_t sock = socket(family, SOCK_STREAM, IPPROTO_TCP); | ||
348 | |||
349 | if (!sock_valid(sock)) { | ||
350 | return ~0; | ||
351 | } | ||
352 | |||
353 | int ok = set_nonblock(sock); | ||
354 | |||
355 | if (ok && family == AF_INET6) { | ||
356 | ok = set_dualstack(sock); | ||
357 | } | ||
358 | |||
359 | ok = ok && bind_to_port(sock, family, port) && (listen(sock, TCP_MAX_BACKLOG) == 0); | ||
360 | |||
361 | if (!ok) { | ||
362 | kill_sock(sock); | ||
363 | return ~0; | ||
364 | } | ||
365 | |||
366 | return sock; | ||
367 | } | ||
368 | |||
369 | TCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, uint16_t *ports, uint8_t *public_key, | ||
370 | uint8_t *secret_key) | ||
371 | { | ||
372 | if (num_sockets == 0 || ports == NULL) | ||
373 | return NULL; | ||
374 | |||
375 | TCP_Server *temp = calloc(1, sizeof(TCP_Server)); | ||
376 | |||
377 | if (temp == NULL) | ||
378 | return NULL; | ||
379 | |||
380 | temp->socks_listening = calloc(num_sockets, sizeof(sock_t)); | ||
381 | |||
382 | if (temp->socks_listening == NULL) { | ||
383 | free(temp); | ||
384 | return NULL; | ||
385 | } | ||
386 | |||
387 | uint8_t family; | ||
388 | |||
389 | if (ipv6_enabled) { | ||
390 | family = AF_INET6; | ||
391 | } else { | ||
392 | family = AF_INET; | ||
393 | } | ||
394 | |||
395 | uint32_t i; | ||
396 | |||
397 | for (i = 0; i < num_sockets; ++i) { | ||
398 | sock_t sock = new_listening_TCP_socket(family, ports[i]); | ||
399 | |||
400 | if (sock_valid(sock)) { | ||
401 | temp->socks_listening[temp->num_listening_socks] = sock; | ||
402 | ++temp->num_listening_socks; | ||
403 | } | ||
404 | } | ||
405 | |||
406 | memcpy(temp->public_key, public_key, crypto_box_PUBLICKEYBYTES); | ||
407 | memcpy(temp->secret_key, secret_key, crypto_box_SECRETKEYBYTES); | ||
408 | return temp; | ||
409 | } | ||
410 | |||
411 | static void do_TCP_accept_new(TCP_Server *TCP_server) | ||
412 | { | ||
413 | uint32_t i; | ||
414 | |||
415 | for (i = 0; i < TCP_server->num_listening_socks; ++i) { | ||
416 | struct sockaddr_storage addr; | ||
417 | unsigned int addrlen = sizeof(addr); | ||
418 | sock_t sock; | ||
419 | |||
420 | do { | ||
421 | sock = accept(TCP_server->socks_listening[i], (struct sockaddr *)&addr, &addrlen); | ||
422 | } while (accept_connection(TCP_server, sock)); | ||
423 | } | ||
424 | } | ||
425 | |||
426 | static void do_TCP_incomming(TCP_Server *TCP_server) | ||
427 | { | ||
428 | uint32_t i; | ||
429 | |||
430 | for (i = 0; i < MAX_INCOMMING_CONNECTIONS; ++i) { | ||
431 | if (TCP_server->incomming_connection_queue[i].status != TCP_STATUS_CONNECTED) | ||
432 | continue; | ||
433 | |||
434 | int ret = read_connection_handshake(&TCP_server->incomming_connection_queue[i], TCP_server->secret_key); | ||
435 | |||
436 | if (ret == -1) { | ||
437 | kill_TCP_connection(&TCP_server->incomming_connection_queue[i]); | ||
438 | } else if (ret == 1) { | ||
439 | TCP_Secure_Connection *conn_old = &TCP_server->incomming_connection_queue[i]; | ||
440 | TCP_Secure_Connection *conn_new = | ||
441 | &TCP_server->unconfirmed_connection_queue[TCP_server->unconfirmed_connection_queue_index % MAX_INCOMMING_CONNECTIONS]; | ||
442 | |||
443 | if (conn_new->status != TCP_STATUS_NO_STATUS) | ||
444 | kill_TCP_connection(conn_new); | ||
445 | |||
446 | memcpy(conn_new, conn_old, sizeof(TCP_Secure_Connection)); | ||
447 | memset(conn_old, 0, sizeof(TCP_Secure_Connection)); | ||
448 | ++TCP_server->unconfirmed_connection_queue_index; | ||
449 | } | ||
450 | } | ||
451 | } | ||
452 | |||
453 | static void do_TCP_unconfirmed(TCP_Server *TCP_server) | ||
454 | { | ||
455 | uint32_t i; | ||
456 | |||
457 | for (i = 0; i < MAX_INCOMMING_CONNECTIONS; ++i) { | ||
458 | TCP_Secure_Connection *conn = &TCP_server->unconfirmed_connection_queue[i]; | ||
459 | |||
460 | if (conn->status != TCP_STATUS_UNCONFIRMED) | ||
461 | continue; | ||
462 | |||
463 | uint8_t packet[MAX_PACKET_SIZE]; | ||
464 | int len = read_packet_TCP_secure_connection(conn, packet, sizeof(packet)); | ||
465 | |||
466 | if (len == 0) { | ||
467 | continue; | ||
468 | } else if (len == -1) { | ||
469 | kill_TCP_connection(conn); | ||
470 | continue; | ||
471 | } else { | ||
472 | //TODO | ||
473 | confirm_TCP_connection(conn, packet, len); | ||
474 | kill_TCP_connection(conn); | ||
475 | } | ||
476 | } | ||
477 | } | ||
478 | void do_TCP_server(TCP_Server *TCP_server) | ||
479 | { | ||
480 | do_TCP_accept_new(TCP_server); | ||
481 | do_TCP_incomming(TCP_server); | ||
482 | } | ||
483 | |||
484 | void kill_TCP_server(TCP_Server *TCP_server) | ||
485 | { | ||
486 | uint32_t i; | ||
487 | |||
488 | for (i = 0; i < TCP_server->num_listening_socks; ++i) { | ||
489 | kill_sock(TCP_server->socks_listening[i]); | ||
490 | } | ||
491 | |||
492 | free(TCP_server->socks_listening); | ||
493 | free(TCP_server); | ||
494 | } | ||
diff --git a/toxcore/TCP_server.h b/toxcore/TCP_server.h new file mode 100644 index 00000000..89ccb50f --- /dev/null +++ b/toxcore/TCP_server.h | |||
@@ -0,0 +1,75 @@ | |||
1 | /* | ||
2 | * TCP_server.h -- Implementation of the TCP relay server part of Tox. | ||
3 | * | ||
4 | * Copyright (C) 2013 Tox project All Rights Reserved. | ||
5 | * | ||
6 | * This file is part of Tox. | ||
7 | * | ||
8 | * Tox is free software: you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation, either version 3 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * Tox is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with Tox. If not, see <http://www.gnu.org/licenses/>. | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include "net_crypto.h" | ||
24 | |||
25 | #define MAX_INCOMMING_CONNECTIONS 32 | ||
26 | |||
27 | #define TCP_MAX_BACKLOG MAX_INCOMMING_CONNECTIONS | ||
28 | |||
29 | #define MAX_PACKET_SIZE 8192 | ||
30 | |||
31 | #define TCP_HANDSHAKE_PLAIN_SIZE (crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES) | ||
32 | #define TCP_SERVER_HANDSHAKE_SIZE (crypto_box_NONCEBYTES + TCP_HANDSHAKE_PLAIN_SIZE + crypto_box_MACBYTES) | ||
33 | #define TCP_CLIENT_HANDSHAKE_SIZE (crypto_box_PUBLICKEYBYTES + TCP_SERVER_HANDSHAKE_SIZE) | ||
34 | |||
35 | enum { | ||
36 | TCP_STATUS_NO_STATUS, | ||
37 | TCP_STATUS_CONNECTED, | ||
38 | TCP_STATUS_UNCONFIRMED, | ||
39 | TCP_STATUS_CONFIRMED, | ||
40 | }; | ||
41 | |||
42 | typedef struct { | ||
43 | uint8_t status; | ||
44 | sock_t sock; | ||
45 | uint8_t public_key[crypto_box_PUBLICKEYBYTES]; | ||
46 | uint8_t recv_nonce[crypto_box_NONCEBYTES]; /* Nonce of received packets. */ | ||
47 | uint8_t sent_nonce[crypto_box_NONCEBYTES]; /* Nonce of sent packets. */ | ||
48 | uint8_t shared_key[crypto_box_BEFORENMBYTES]; | ||
49 | uint16_t next_packet_length; | ||
50 | } TCP_Secure_Connection; | ||
51 | |||
52 | typedef struct { | ||
53 | sock_t *socks_listening; | ||
54 | unsigned int num_listening_socks; | ||
55 | |||
56 | uint8_t public_key[crypto_box_PUBLICKEYBYTES]; | ||
57 | uint8_t secret_key[crypto_box_SECRETKEYBYTES]; | ||
58 | TCP_Secure_Connection incomming_connection_queue[MAX_INCOMMING_CONNECTIONS]; | ||
59 | uint16_t incomming_connection_queue_index; | ||
60 | TCP_Secure_Connection unconfirmed_connection_queue[MAX_INCOMMING_CONNECTIONS]; | ||
61 | uint16_t unconfirmed_connection_queue_index; | ||
62 | } TCP_Server; | ||
63 | |||
64 | /* Create new TCP server instance. | ||
65 | */ | ||
66 | TCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, uint16_t *ports, uint8_t *public_key, | ||
67 | uint8_t *secret_key); | ||
68 | |||
69 | /* Run the TCP_server | ||
70 | */ | ||
71 | void do_TCP_server(TCP_Server *TCP_server); | ||
72 | |||
73 | /* Kill the TCP server | ||
74 | */ | ||
75 | void kill_TCP_server(TCP_Server *TCP_server); | ||
diff --git a/toxcore/net_crypto.c b/toxcore/net_crypto.c index 5c2691f3..17d2e8ff 100644 --- a/toxcore/net_crypto.c +++ b/toxcore/net_crypto.c | |||
@@ -159,7 +159,7 @@ int decrypt_data_symmetric(uint8_t *secret_key, uint8_t *nonce, uint8_t *encrypt | |||
159 | } | 159 | } |
160 | 160 | ||
161 | /* Increment the given nonce by 1. */ | 161 | /* Increment the given nonce by 1. */ |
162 | static void increment_nonce(uint8_t *nonce) | 162 | void increment_nonce(uint8_t *nonce) |
163 | { | 163 | { |
164 | uint32_t i; | 164 | uint32_t i; |
165 | 165 | ||
@@ -376,8 +376,8 @@ static int cryptopacket_handle(void *object, IP_Port source, uint8_t *packet, ui | |||
376 | 376 | ||
377 | if (!dht->c->cryptopackethandlers[number].function) return 1; | 377 | if (!dht->c->cryptopackethandlers[number].function) return 1; |
378 | 378 | ||
379 | dht->c->cryptopackethandlers[number].function(dht->c->cryptopackethandlers[number].object, source, public_key, data, | 379 | return dht->c->cryptopackethandlers[number].function(dht->c->cryptopackethandlers[number].object, source, public_key, |
380 | len); | 380 | data, len); |
381 | 381 | ||
382 | } else { /* If request is not for us, try routing it. */ | 382 | } else { /* If request is not for us, try routing it. */ |
383 | int retval = route_packet(dht, packet + 1, packet, length); | 383 | int retval = route_packet(dht, packet + 1, packet, length); |
@@ -573,7 +573,11 @@ int crypto_inbound(Net_Crypto *c, uint8_t *public_key, uint8_t *secret_nonce, ui | |||
573 | 573 | ||
574 | if (handle_cryptohandshake(c, public_key, secret_nonce, session_key, temp_data, len)) { | 574 | if (handle_cryptohandshake(c, public_key, secret_nonce, session_key, temp_data, len)) { |
575 | return incoming_con; | 575 | return incoming_con; |
576 | } else { | ||
577 | kill_connection(c->lossless_udp, incoming_con); | ||
576 | } | 578 | } |
579 | } else { | ||
580 | kill_connection(c->lossless_udp, incoming_con); | ||
577 | } | 581 | } |
578 | } else { | 582 | } else { |
579 | break; | 583 | break; |
diff --git a/toxcore/net_crypto.h b/toxcore/net_crypto.h index 74c3326a..da776527 100644 --- a/toxcore/net_crypto.h +++ b/toxcore/net_crypto.h | |||
@@ -132,6 +132,9 @@ int encrypt_data_symmetric(uint8_t *secret_key, uint8_t *nonce, uint8_t *plain, | |||
132 | */ | 132 | */ |
133 | int decrypt_data_symmetric(uint8_t *secret_key, uint8_t *nonce, uint8_t *encrypted, uint32_t length, uint8_t *plain); | 133 | int decrypt_data_symmetric(uint8_t *secret_key, uint8_t *nonce, uint8_t *encrypted, uint32_t length, uint8_t *plain); |
134 | 134 | ||
135 | /* Increment the given nonce by 1. */ | ||
136 | void increment_nonce(uint8_t *nonce); | ||
137 | |||
135 | /* Fill the given nonce with random bytes. */ | 138 | /* Fill the given nonce with random bytes. */ |
136 | void random_nonce(uint8_t *nonce); | 139 | void random_nonce(uint8_t *nonce); |
137 | 140 | ||
diff --git a/toxcore/network.c b/toxcore/network.c index e2e0bff4..69cc23d8 100644 --- a/toxcore/network.c +++ b/toxcore/network.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* network.h | 1 | /* network.c |
2 | * | 2 | * |
3 | * Functions for the core networking. | 3 | * Functions for the core networking. |
4 | * | 4 | * |
@@ -36,10 +36,6 @@ | |||
36 | #include "network.h" | 36 | #include "network.h" |
37 | #include "util.h" | 37 | #include "util.h" |
38 | 38 | ||
39 | #ifndef IPV6_V6ONLY | ||
40 | #define IPV6_V6ONLY 27 | ||
41 | #endif | ||
42 | |||
43 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) | 39 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) |
44 | 40 | ||
45 | static const char *inet_ntop(sa_family_t family, void *addr, char *buf, size_t bufsize) | 41 | static const char *inet_ntop(sa_family_t family, void *addr, char *buf, size_t bufsize) |
@@ -446,8 +442,14 @@ static int at_startup(void) | |||
446 | return 0; | 442 | return 0; |
447 | 443 | ||
448 | #ifndef VANILLA_NACL | 444 | #ifndef VANILLA_NACL |
445 | |||
446 | #ifdef USE_RANDOMBYTES_STIR | ||
447 | randombytes_stir(); | ||
448 | #else | ||
449 | sodium_init(); | 449 | sodium_init(); |
450 | #endif | 450 | #endif /*USE_RANDOMBYTES_STIR*/ |
451 | |||
452 | #endif/*VANILLA_NACL*/ | ||
451 | 453 | ||
452 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) | 454 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) |
453 | WSADATA wsaData; | 455 | WSADATA wsaData; |
diff --git a/toxcore/network.h b/toxcore/network.h index 97a73014..5845932f 100644 --- a/toxcore/network.h +++ b/toxcore/network.h | |||
@@ -44,6 +44,10 @@ | |||
44 | #include <windows.h> | 44 | #include <windows.h> |
45 | #include <ws2tcpip.h> | 45 | #include <ws2tcpip.h> |
46 | 46 | ||
47 | #ifndef IPV6_V6ONLY | ||
48 | #define IPV6_V6ONLY 27 | ||
49 | #endif | ||
50 | |||
47 | typedef unsigned int sock_t; | 51 | typedef unsigned int sock_t; |
48 | /* sa_family_t is the sockaddr_in / sockaddr_in6 family field */ | 52 | /* sa_family_t is the sockaddr_in / sockaddr_in6 family field */ |
49 | typedef short sa_family_t; | 53 | typedef short sa_family_t; |
@@ -149,7 +153,7 @@ typedef int sock_t; | |||
149 | #define NET_PACKET_ONION_RECV_2 141 | 153 | #define NET_PACKET_ONION_RECV_2 141 |
150 | #define NET_PACKET_ONION_RECV_1 142 | 154 | #define NET_PACKET_ONION_RECV_1 142 |
151 | 155 | ||
152 | /* Only used for bootstrap servers */ | 156 | /* Only used for bootstrap nodes */ |
153 | #define BOOTSTRAP_INFO_PACKET_ID 240 | 157 | #define BOOTSTRAP_INFO_PACKET_ID 240 |
154 | 158 | ||
155 | 159 | ||
diff --git a/toxcore/onion.c b/toxcore/onion.c index 578621cc..292f9309 100644 --- a/toxcore/onion.c +++ b/toxcore/onion.c | |||
@@ -47,48 +47,81 @@ static void change_symmetric_key(Onion *onion) | |||
47 | } | 47 | } |
48 | } | 48 | } |
49 | 49 | ||
50 | /* Create a new onion path. | ||
51 | * | ||
52 | * Create a new onion path out of nodes (nodes is a list of 3 nodes) | ||
53 | * | ||
54 | * new_path must be an empty memory location of atleast Onion_Path size. | ||
55 | * | ||
56 | * return -1 on failure. | ||
57 | * return 0 on success. | ||
58 | */ | ||
59 | int create_onion_path(DHT *dht, Onion_Path *new_path, Node_format *nodes) | ||
60 | { | ||
61 | if (!new_path || !nodes) | ||
62 | return -1; | ||
63 | |||
64 | encrypt_precompute(nodes[0].client_id, dht->self_secret_key, new_path->shared_key1); | ||
65 | memcpy(new_path->public_key1, dht->self_public_key, crypto_box_PUBLICKEYBYTES); | ||
66 | |||
67 | uint8_t random_public_key[crypto_box_PUBLICKEYBYTES]; | ||
68 | uint8_t random_secret_key[crypto_box_SECRETKEYBYTES]; | ||
69 | |||
70 | crypto_box_keypair(random_public_key, random_secret_key); | ||
71 | encrypt_precompute(nodes[1].client_id, random_secret_key, new_path->shared_key2); | ||
72 | memcpy(new_path->public_key2, random_public_key, crypto_box_PUBLICKEYBYTES); | ||
73 | |||
74 | crypto_box_keypair(random_public_key, random_secret_key); | ||
75 | encrypt_precompute(nodes[2].client_id, random_secret_key, new_path->shared_key3); | ||
76 | memcpy(new_path->public_key3, random_public_key, crypto_box_PUBLICKEYBYTES); | ||
77 | |||
78 | new_path->ip_port1 = nodes[0].ip_port; | ||
79 | new_path->ip_port2 = nodes[1].ip_port; | ||
80 | new_path->ip_port3 = nodes[2].ip_port; | ||
81 | |||
82 | /* to_net_family(&new_path->ip_port1.ip); */ | ||
83 | to_net_family(&new_path->ip_port2.ip); | ||
84 | to_net_family(&new_path->ip_port3.ip); | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
50 | /* Create and send a onion packet. | 89 | /* Create and send a onion packet. |
51 | * | 90 | * |
52 | * nodes is a list of 4 nodes, the packet will route through nodes 0, 1, 2 and the data | 91 | * Use Onion_Path path to send data of length to dest. |
53 | * with length length will arrive at 3. | ||
54 | * | 92 | * |
55 | * return -1 on failure. | 93 | * return -1 on failure. |
56 | * return 0 on success. | 94 | * return 0 on success. |
57 | */ | 95 | */ |
58 | int send_onion_packet(DHT *dht, Node_format *nodes, uint8_t *data, uint32_t length) | 96 | int send_onion_packet(Networking_Core *net, Onion_Path *path, IP_Port dest, uint8_t *data, uint32_t length) |
59 | { | 97 | { |
60 | if (1 + length + SEND_1 > MAX_ONION_SIZE || length == 0) | 98 | if (1 + length + SEND_1 > MAX_ONION_SIZE || length == 0) |
61 | return -1; | 99 | return -1; |
62 | 100 | ||
101 | to_net_family(&dest.ip); | ||
63 | uint8_t step1[sizeof(IP_Port) + length]; | 102 | uint8_t step1[sizeof(IP_Port) + length]; |
64 | to_net_family(&nodes[3].ip_port.ip); | 103 | |
65 | memcpy(step1, &nodes[3].ip_port, sizeof(IP_Port)); | 104 | memcpy(step1, &dest, sizeof(IP_Port)); |
66 | memcpy(step1 + sizeof(IP_Port), data, length); | 105 | memcpy(step1 + sizeof(IP_Port), data, length); |
67 | 106 | ||
68 | uint8_t nonce[crypto_box_NONCEBYTES]; | 107 | uint8_t nonce[crypto_box_NONCEBYTES]; |
69 | random_nonce(nonce); | 108 | random_nonce(nonce); |
70 | uint8_t random_public_key[crypto_box_PUBLICKEYBYTES]; | ||
71 | uint8_t random_secret_key[crypto_box_SECRETKEYBYTES]; | ||
72 | crypto_box_keypair(random_public_key, random_secret_key); | ||
73 | 109 | ||
74 | uint8_t step2[sizeof(IP_Port) + SEND_BASE + length]; | 110 | uint8_t step2[sizeof(IP_Port) + SEND_BASE + length]; |
75 | to_net_family(&nodes[2].ip_port.ip); | 111 | memcpy(step2, &path->ip_port3, sizeof(IP_Port)); |
76 | memcpy(step2, &nodes[2].ip_port, sizeof(IP_Port)); | 112 | memcpy(step2 + sizeof(IP_Port), path->public_key3, crypto_box_PUBLICKEYBYTES); |
77 | memcpy(step2 + sizeof(IP_Port), random_public_key, crypto_box_PUBLICKEYBYTES); | ||
78 | 113 | ||
79 | int len = encrypt_data(nodes[2].client_id, random_secret_key, nonce, | 114 | int len = encrypt_data_fast(path->shared_key3, nonce, step1, sizeof(step1), |
80 | step1, sizeof(step1), step2 + sizeof(IP_Port) + crypto_box_PUBLICKEYBYTES); | 115 | step2 + sizeof(IP_Port) + crypto_box_PUBLICKEYBYTES); |
81 | 116 | ||
82 | if ((uint32_t)len != sizeof(IP_Port) + length + crypto_box_MACBYTES) | 117 | if ((uint32_t)len != sizeof(IP_Port) + length + crypto_box_MACBYTES) |
83 | return -1; | 118 | return -1; |
84 | 119 | ||
85 | crypto_box_keypair(random_public_key, random_secret_key); | ||
86 | uint8_t step3[sizeof(IP_Port) + SEND_BASE * 2 + length]; | 120 | uint8_t step3[sizeof(IP_Port) + SEND_BASE * 2 + length]; |
87 | to_net_family(&nodes[1].ip_port.ip); | 121 | memcpy(step3, &path->ip_port2, sizeof(IP_Port)); |
88 | memcpy(step3, &nodes[1].ip_port, sizeof(IP_Port)); | 122 | memcpy(step3 + sizeof(IP_Port), path->public_key2, crypto_box_PUBLICKEYBYTES); |
89 | memcpy(step3 + sizeof(IP_Port), random_public_key, crypto_box_PUBLICKEYBYTES); | 123 | len = encrypt_data_fast(path->shared_key2, nonce, step2, sizeof(step2), |
90 | len = encrypt_data(nodes[1].client_id, random_secret_key, nonce, | 124 | step3 + sizeof(IP_Port) + crypto_box_PUBLICKEYBYTES); |
91 | step2, sizeof(step2), step3 + sizeof(IP_Port) + crypto_box_PUBLICKEYBYTES); | ||
92 | 125 | ||
93 | if ((uint32_t)len != sizeof(IP_Port) + SEND_BASE + length + crypto_box_MACBYTES) | 126 | if ((uint32_t)len != sizeof(IP_Port) + SEND_BASE + length + crypto_box_MACBYTES) |
94 | return -1; | 127 | return -1; |
@@ -96,15 +129,15 @@ int send_onion_packet(DHT *dht, Node_format *nodes, uint8_t *data, uint32_t leng | |||
96 | uint8_t packet[1 + length + SEND_1]; | 129 | uint8_t packet[1 + length + SEND_1]; |
97 | packet[0] = NET_PACKET_ONION_SEND_INITIAL; | 130 | packet[0] = NET_PACKET_ONION_SEND_INITIAL; |
98 | memcpy(packet + 1, nonce, crypto_box_NONCEBYTES); | 131 | memcpy(packet + 1, nonce, crypto_box_NONCEBYTES); |
99 | memcpy(packet + 1 + crypto_box_NONCEBYTES, dht->self_public_key, crypto_box_PUBLICKEYBYTES); | 132 | memcpy(packet + 1 + crypto_box_NONCEBYTES, path->public_key1, crypto_box_PUBLICKEYBYTES); |
100 | 133 | ||
101 | len = encrypt_data(nodes[0].client_id, dht->self_secret_key, nonce, | 134 | len = encrypt_data_fast(path->shared_key1, nonce, step3, sizeof(step3), |
102 | step3, sizeof(step3), packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES); | 135 | packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES); |
103 | 136 | ||
104 | if ((uint32_t)len != sizeof(IP_Port) + SEND_BASE * 2 + length + crypto_box_MACBYTES) | 137 | if ((uint32_t)len != sizeof(IP_Port) + SEND_BASE * 2 + length + crypto_box_MACBYTES) |
105 | return -1; | 138 | return -1; |
106 | 139 | ||
107 | if ((uint32_t)sendpacket(dht->c->lossless_udp->net, nodes[0].ip_port, packet, sizeof(packet)) != sizeof(packet)) | 140 | if ((uint32_t)sendpacket(net, path->ip_port1, packet, sizeof(packet)) != sizeof(packet)) |
108 | return -1; | 141 | return -1; |
109 | 142 | ||
110 | return 0; | 143 | return 0; |
@@ -140,10 +173,10 @@ static int handle_send_initial(void *object, IP_Port source, uint8_t *packet, ui | |||
140 | change_symmetric_key(onion); | 173 | change_symmetric_key(onion); |
141 | 174 | ||
142 | uint8_t plain[MAX_ONION_SIZE]; | 175 | uint8_t plain[MAX_ONION_SIZE]; |
143 | 176 | uint8_t shared_key[crypto_box_BEFORENMBYTES]; | |
144 | int len = decrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion->dht->self_secret_key, packet + 1, | 177 | get_shared_key(&onion->shared_keys_1, shared_key, onion->dht->self_secret_key, packet + 1 + crypto_box_NONCEBYTES); |
145 | packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, | 178 | int len = decrypt_data_fast(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, |
146 | length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES), plain); | 179 | length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES), plain); |
147 | 180 | ||
148 | if ((uint32_t)len != length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES)) | 181 | if ((uint32_t)len != length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES)) |
149 | return 1; | 182 | return 1; |
@@ -186,10 +219,10 @@ static int handle_send_1(void *object, IP_Port source, uint8_t *packet, uint32_t | |||
186 | change_symmetric_key(onion); | 219 | change_symmetric_key(onion); |
187 | 220 | ||
188 | uint8_t plain[MAX_ONION_SIZE]; | 221 | uint8_t plain[MAX_ONION_SIZE]; |
189 | 222 | uint8_t shared_key[crypto_box_BEFORENMBYTES]; | |
190 | int len = decrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion->dht->self_secret_key, packet + 1, | 223 | get_shared_key(&onion->shared_keys_2, shared_key, onion->dht->self_secret_key, packet + 1 + crypto_box_NONCEBYTES); |
191 | packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, | 224 | int len = decrypt_data_fast(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, |
192 | length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_1), plain); | 225 | length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_1), plain); |
193 | 226 | ||
194 | if ((uint32_t)len != length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_1 + crypto_box_MACBYTES)) | 227 | if ((uint32_t)len != length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_1 + crypto_box_MACBYTES)) |
195 | return 1; | 228 | return 1; |
@@ -235,10 +268,10 @@ static int handle_send_2(void *object, IP_Port source, uint8_t *packet, uint32_t | |||
235 | change_symmetric_key(onion); | 268 | change_symmetric_key(onion); |
236 | 269 | ||
237 | uint8_t plain[MAX_ONION_SIZE]; | 270 | uint8_t plain[MAX_ONION_SIZE]; |
238 | 271 | uint8_t shared_key[crypto_box_BEFORENMBYTES]; | |
239 | int len = decrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion->dht->self_secret_key, packet + 1, | 272 | get_shared_key(&onion->shared_keys_3, shared_key, onion->dht->self_secret_key, packet + 1 + crypto_box_NONCEBYTES); |
240 | packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, | 273 | int len = decrypt_data_fast(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, |
241 | length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_2), plain); | 274 | length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_2), plain); |
242 | 275 | ||
243 | if ((uint32_t)len != length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_2 + crypto_box_MACBYTES)) | 276 | if ((uint32_t)len != length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_2 + crypto_box_MACBYTES)) |
244 | return 1; | 277 | return 1; |
diff --git a/toxcore/onion.h b/toxcore/onion.h index a52bcb86..daaec91c 100644 --- a/toxcore/onion.h +++ b/toxcore/onion.h | |||
@@ -30,6 +30,10 @@ typedef struct { | |||
30 | Networking_Core *net; | 30 | Networking_Core *net; |
31 | uint8_t secret_symmetric_key[crypto_secretbox_KEYBYTES]; | 31 | uint8_t secret_symmetric_key[crypto_secretbox_KEYBYTES]; |
32 | uint64_t timestamp; | 32 | uint64_t timestamp; |
33 | |||
34 | Shared_Keys shared_keys_1; | ||
35 | Shared_Keys shared_keys_2; | ||
36 | Shared_Keys shared_keys_3; | ||
33 | } Onion; | 37 | } Onion; |
34 | 38 | ||
35 | #define ONION_RETURN_1 (crypto_secretbox_NONCEBYTES + sizeof(IP_Port) + crypto_secretbox_MACBYTES) | 39 | #define ONION_RETURN_1 (crypto_secretbox_NONCEBYTES + sizeof(IP_Port) + crypto_secretbox_MACBYTES) |
@@ -41,16 +45,39 @@ typedef struct { | |||
41 | #define ONION_SEND_2 (crypto_box_NONCEBYTES + ONION_SEND_BASE*2 + ONION_RETURN_1) | 45 | #define ONION_SEND_2 (crypto_box_NONCEBYTES + ONION_SEND_BASE*2 + ONION_RETURN_1) |
42 | #define ONION_SEND_1 (crypto_box_NONCEBYTES + ONION_SEND_BASE*3) | 46 | #define ONION_SEND_1 (crypto_box_NONCEBYTES + ONION_SEND_BASE*3) |
43 | 47 | ||
48 | typedef struct { | ||
49 | uint8_t shared_key1[crypto_box_BEFORENMBYTES]; | ||
50 | uint8_t shared_key2[crypto_box_BEFORENMBYTES]; | ||
51 | uint8_t shared_key3[crypto_box_BEFORENMBYTES]; | ||
52 | |||
53 | uint8_t public_key1[crypto_box_PUBLICKEYBYTES]; | ||
54 | uint8_t public_key2[crypto_box_PUBLICKEYBYTES]; | ||
55 | uint8_t public_key3[crypto_box_PUBLICKEYBYTES]; | ||
56 | |||
57 | IP_Port ip_port1; | ||
58 | IP_Port ip_port2; | ||
59 | IP_Port ip_port3; | ||
60 | } Onion_Path; | ||
61 | |||
62 | /* Create a new onion path. | ||
63 | * | ||
64 | * Create a new onion path out of nodes (nodes is a list of 3 nodes) | ||
65 | * | ||
66 | * new_path must be an empty memory location of atleast Onion_Path size. | ||
67 | * | ||
68 | * return -1 on failure. | ||
69 | * return 0 on success. | ||
70 | */ | ||
71 | int create_onion_path(DHT *dht, Onion_Path *new_path, Node_format *nodes); | ||
44 | 72 | ||
45 | /* Create and send a onion packet. | 73 | /* Create and send a onion packet. |
46 | * | 74 | * |
47 | * nodes is a list of 4 nodes, the packet will route through nodes 0, 1, 2 and the data | 75 | * Use Onion_Path path to send data of length to dest. |
48 | * with length length will arrive at 3. | ||
49 | * | 76 | * |
50 | * return -1 on failure. | 77 | * return -1 on failure. |
51 | * return 0 on success. | 78 | * return 0 on success. |
52 | */ | 79 | */ |
53 | int send_onion_packet(DHT *dht, Node_format *nodes, uint8_t *data, uint32_t length); | 80 | int send_onion_packet(Networking_Core *net, Onion_Path *path, IP_Port dest, uint8_t *data, uint32_t length); |
54 | 81 | ||
55 | /* Create and send a onion response sent initially to dest with. | 82 | /* Create and send a onion response sent initially to dest with. |
56 | * | 83 | * |
diff --git a/toxcore/onion_announce.c b/toxcore/onion_announce.c index 28e27d91..331e54d8 100644 --- a/toxcore/onion_announce.c +++ b/toxcore/onion_announce.c | |||
@@ -37,8 +37,7 @@ | |||
37 | 37 | ||
38 | /* Create and send an onion announce request packet. | 38 | /* Create and send an onion announce request packet. |
39 | * | 39 | * |
40 | * nodes is a list of 4 nodes, the packet will route through nodes 0, 1, 2 and the announe | 40 | * path is the path the request will take before it is sent to dest. |
41 | * request will be sent to 3. | ||
42 | * | 41 | * |
43 | * public_key and secret_key is the kepair which will be used to encrypt the request. | 42 | * public_key and secret_key is the kepair which will be used to encrypt the request. |
44 | * ping_id is the ping id that will be sent in the request. | 43 | * ping_id is the ping id that will be sent in the request. |
@@ -50,8 +49,8 @@ | |||
50 | * return -1 on failure. | 49 | * return -1 on failure. |
51 | * return 0 on success. | 50 | * return 0 on success. |
52 | */ | 51 | */ |
53 | int send_announce_request(DHT *dht, Node_format *nodes, uint8_t *public_key, uint8_t *secret_key, uint8_t *ping_id, | 52 | int send_announce_request(Networking_Core *net, Onion_Path *path, Node_format dest, uint8_t *public_key, |
54 | uint8_t *client_id, uint8_t *data_public_key, uint8_t *sendback_data) | 53 | uint8_t *secret_key, uint8_t *ping_id, uint8_t *client_id, uint8_t *data_public_key, uint8_t *sendback_data) |
55 | { | 54 | { |
56 | uint8_t plain[ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH]; | 55 | uint8_t plain[ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH]; |
57 | memcpy(plain, ping_id, ONION_PING_ID_SIZE); | 56 | memcpy(plain, ping_id, ONION_PING_ID_SIZE); |
@@ -63,7 +62,7 @@ int send_announce_request(DHT *dht, Node_format *nodes, uint8_t *public_key, uin | |||
63 | packet[0] = NET_PACKET_ANNOUNCE_REQUEST; | 62 | packet[0] = NET_PACKET_ANNOUNCE_REQUEST; |
64 | random_nonce(packet + 1); | 63 | random_nonce(packet + 1); |
65 | 64 | ||
66 | int len = encrypt_data(nodes[3].client_id, secret_key, packet + 1, plain, sizeof(plain), | 65 | int len = encrypt_data(dest.client_id, secret_key, packet + 1, plain, sizeof(plain), |
67 | packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES); | 66 | packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES); |
68 | 67 | ||
69 | if ((uint32_t)len + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES != ANNOUNCE_REQUEST_SIZE) | 68 | if ((uint32_t)len + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES != ANNOUNCE_REQUEST_SIZE) |
@@ -71,13 +70,13 @@ int send_announce_request(DHT *dht, Node_format *nodes, uint8_t *public_key, uin | |||
71 | 70 | ||
72 | memcpy(packet + 1 + crypto_box_NONCEBYTES, public_key, crypto_box_PUBLICKEYBYTES); | 71 | memcpy(packet + 1 + crypto_box_NONCEBYTES, public_key, crypto_box_PUBLICKEYBYTES); |
73 | 72 | ||
74 | return send_onion_packet(dht, nodes, packet, sizeof(packet)); | 73 | return send_onion_packet(net, path, dest.ip_port, packet, sizeof(packet)); |
75 | } | 74 | } |
76 | 75 | ||
77 | /* Create and send an onion data request packet. | 76 | /* Create and send an onion data request packet. |
78 | * | 77 | * |
79 | * nodes is a list of 4 nodes, the packet will route through nodes 0, 1, 2 and the data | 78 | * path is the path the request will take before it is sent to dest. |
80 | * request packet will arrive at 3. (if 3 knows the person with the public_key they should | 79 | * (if dest knows the person with the public_key they should |
81 | * send the packet to that person in the form of a response) | 80 | * send the packet to that person in the form of a response) |
82 | * | 81 | * |
83 | * public_key is the real public key of the node which we want to send the data of length length to. | 82 | * public_key is the real public key of the node which we want to send the data of length length to. |
@@ -88,8 +87,8 @@ int send_announce_request(DHT *dht, Node_format *nodes, uint8_t *public_key, uin | |||
88 | * return -1 on failure. | 87 | * return -1 on failure. |
89 | * return 0 on success. | 88 | * return 0 on success. |
90 | */ | 89 | */ |
91 | int send_data_request(DHT *dht, Node_format *nodes, uint8_t *public_key, uint8_t *encrypt_public_key, uint8_t *nonce, | 90 | int send_data_request(Networking_Core *net, Onion_Path *path, IP_Port dest, uint8_t *public_key, |
92 | uint8_t *data, uint16_t length) | 91 | uint8_t *encrypt_public_key, uint8_t *nonce, uint8_t *data, uint16_t length) |
93 | { | 92 | { |
94 | uint8_t packet[DATA_REQUEST_MIN_SIZE + length]; | 93 | uint8_t packet[DATA_REQUEST_MIN_SIZE + length]; |
95 | packet[0] = NET_PACKET_ONION_DATA_REQUEST; | 94 | packet[0] = NET_PACKET_ONION_DATA_REQUEST; |
@@ -108,7 +107,7 @@ int send_data_request(DHT *dht, Node_format *nodes, uint8_t *public_key, uint8_t | |||
108 | if (1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + (uint32_t)len != sizeof(packet)) | 107 | if (1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + (uint32_t)len != sizeof(packet)) |
109 | return -1; | 108 | return -1; |
110 | 109 | ||
111 | return send_onion_packet(dht, nodes, packet, sizeof(packet)); | 110 | return send_onion_packet(net, path, dest, packet, sizeof(packet)); |
112 | } | 111 | } |
113 | 112 | ||
114 | /* Generate a ping_id and put it in ping_id */ | 113 | /* Generate a ping_id and put it in ping_id */ |
@@ -217,26 +216,30 @@ static int handle_announce_request(void *object, IP_Port source, uint8_t *packet | |||
217 | if (length != ANNOUNCE_REQUEST_SIZE_RECV) | 216 | if (length != ANNOUNCE_REQUEST_SIZE_RECV) |
218 | return 1; | 217 | return 1; |
219 | 218 | ||
219 | uint8_t *packet_public_key = packet + 1 + crypto_box_NONCEBYTES; | ||
220 | uint8_t shared_key[crypto_box_BEFORENMBYTES]; | ||
221 | get_shared_key(&onion_a->shared_keys_recv, shared_key, onion_a->dht->self_secret_key, packet_public_key); | ||
222 | |||
220 | uint8_t plain[ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH]; | 223 | uint8_t plain[ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH]; |
221 | int len = decrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion_a->dht->self_secret_key, packet + 1, | 224 | int len = decrypt_data_fast(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, |
222 | packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, | 225 | ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + |
223 | ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + | 226 | crypto_box_MACBYTES, plain); |
224 | crypto_box_MACBYTES, plain); | ||
225 | 227 | ||
226 | if ((uint32_t)len != sizeof(plain)) | 228 | if ((uint32_t)len != sizeof(plain)) |
227 | return 1; | 229 | return 1; |
228 | 230 | ||
229 | uint8_t ping_id1[ONION_PING_ID_SIZE]; | 231 | uint8_t ping_id1[ONION_PING_ID_SIZE]; |
230 | generate_ping_id(onion_a, unix_time(), packet + 1 + crypto_box_NONCEBYTES, source, ping_id1); | 232 | generate_ping_id(onion_a, unix_time(), packet_public_key, source, ping_id1); |
231 | 233 | ||
232 | uint8_t ping_id2[ONION_PING_ID_SIZE]; | 234 | uint8_t ping_id2[ONION_PING_ID_SIZE]; |
233 | generate_ping_id(onion_a, unix_time() + PING_ID_TIMEOUT, packet + 1 + crypto_box_NONCEBYTES, source, ping_id2); | 235 | generate_ping_id(onion_a, unix_time() + PING_ID_TIMEOUT, packet_public_key, source, ping_id2); |
234 | 236 | ||
235 | int index = -1; | 237 | int index = -1; |
236 | 238 | ||
239 | uint8_t *data_public_key = plain + ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES; | ||
240 | |||
237 | if (memcmp(ping_id1, plain, ONION_PING_ID_SIZE) == 0 || memcmp(ping_id2, plain, ONION_PING_ID_SIZE) == 0) { | 241 | if (memcmp(ping_id1, plain, ONION_PING_ID_SIZE) == 0 || memcmp(ping_id2, plain, ONION_PING_ID_SIZE) == 0) { |
238 | index = add_to_entries(onion_a, source, packet + 1 + crypto_box_NONCEBYTES, | 242 | index = add_to_entries(onion_a, source, packet_public_key, data_public_key, |
239 | plain + ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES, | ||
240 | packet + (ANNOUNCE_REQUEST_SIZE_RECV - ONION_RETURN_3)); | 243 | packet + (ANNOUNCE_REQUEST_SIZE_RECV - ONION_RETURN_3)); |
241 | } else { | 244 | } else { |
242 | index = in_entries(onion_a, plain + ONION_PING_ID_SIZE); | 245 | index = in_entries(onion_a, plain + ONION_PING_ID_SIZE); |
@@ -261,16 +264,21 @@ static int handle_announce_request(void *object, IP_Port source, uint8_t *packet | |||
261 | pl[0] = 0; | 264 | pl[0] = 0; |
262 | memcpy(pl + 1, ping_id2, ONION_PING_ID_SIZE); | 265 | memcpy(pl + 1, ping_id2, ONION_PING_ID_SIZE); |
263 | } else { | 266 | } else { |
264 | pl[0] = 1; | 267 | if (memcmp(onion_a->entries[index].public_key, packet_public_key, crypto_box_PUBLICKEYBYTES) == 0 |
265 | memcpy(pl + 1, onion_a->entries[index].data_public_key, crypto_box_PUBLICKEYBYTES); | 268 | && memcmp(onion_a->entries[index].data_public_key, data_public_key, crypto_box_PUBLICKEYBYTES) != 0) { |
269 | pl[0] = 0; | ||
270 | memcpy(pl + 1, ping_id2, ONION_PING_ID_SIZE); | ||
271 | } else { | ||
272 | pl[0] = 1; | ||
273 | memcpy(pl + 1, onion_a->entries[index].data_public_key, crypto_box_PUBLICKEYBYTES); | ||
274 | } | ||
266 | } | 275 | } |
267 | 276 | ||
268 | memcpy(pl + 1 + ONION_PING_ID_SIZE, nodes_list, num_nodes * sizeof(Node_format)); | 277 | memcpy(pl + 1 + ONION_PING_ID_SIZE, nodes_list, num_nodes * sizeof(Node_format)); |
269 | 278 | ||
270 | uint8_t data[ONION_ANNOUNCE_RESPONSE_MAX_SIZE]; | 279 | uint8_t data[ONION_ANNOUNCE_RESPONSE_MAX_SIZE]; |
271 | len = encrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion_a->dht->self_secret_key, nonce, pl, | 280 | len = encrypt_data_fast(shared_key, nonce, pl, 1 + ONION_PING_ID_SIZE + num_nodes * sizeof(Node_format), |
272 | 1 + ONION_PING_ID_SIZE + num_nodes * sizeof(Node_format), | 281 | data + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_NONCEBYTES); |
273 | data + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_NONCEBYTES); | ||
274 | 282 | ||
275 | if ((uint32_t)len != 1 + ONION_PING_ID_SIZE + num_nodes * sizeof(Node_format) + crypto_box_MACBYTES) | 283 | if ((uint32_t)len != 1 + ONION_PING_ID_SIZE + num_nodes * sizeof(Node_format) + crypto_box_MACBYTES) |
276 | return 1; | 284 | return 1; |
diff --git a/toxcore/onion_announce.h b/toxcore/onion_announce.h index 27b25bd4..b7e08363 100644 --- a/toxcore/onion_announce.h +++ b/toxcore/onion_announce.h | |||
@@ -25,7 +25,7 @@ | |||
25 | 25 | ||
26 | #include "onion.h" | 26 | #include "onion.h" |
27 | 27 | ||
28 | #define ONION_ANNOUNCE_MAX_ENTRIES 32 | 28 | #define ONION_ANNOUNCE_MAX_ENTRIES 48 |
29 | #define ONION_ANNOUNCE_TIMEOUT 300 | 29 | #define ONION_ANNOUNCE_TIMEOUT 300 |
30 | #define ONION_PING_ID_SIZE crypto_hash_sha256_BYTES | 30 | #define ONION_PING_ID_SIZE crypto_hash_sha256_BYTES |
31 | 31 | ||
@@ -54,12 +54,13 @@ typedef struct { | |||
54 | Onion_Announce_Entry entries[ONION_ANNOUNCE_MAX_ENTRIES]; | 54 | Onion_Announce_Entry entries[ONION_ANNOUNCE_MAX_ENTRIES]; |
55 | /* This is crypto_secretbox_KEYBYTES long just so we can use new_symmetric_key() to fill it */ | 55 | /* This is crypto_secretbox_KEYBYTES long just so we can use new_symmetric_key() to fill it */ |
56 | uint8_t secret_bytes[crypto_secretbox_KEYBYTES]; | 56 | uint8_t secret_bytes[crypto_secretbox_KEYBYTES]; |
57 | |||
58 | Shared_Keys shared_keys_recv; | ||
57 | } Onion_Announce; | 59 | } Onion_Announce; |
58 | 60 | ||
59 | /* Create and send an onion announce request packet. | 61 | /* Create and send an onion announce request packet. |
60 | * | 62 | * |
61 | * nodes is a list of 4 nodes, the packet will route through nodes 0, 1, 2 and the announe | 63 | * path is the path the request will take before it is sent to dest. |
62 | * request will be sent to 3. | ||
63 | * | 64 | * |
64 | * public_key and secret_key is the kepair which will be used to encrypt the request. | 65 | * public_key and secret_key is the kepair which will be used to encrypt the request. |
65 | * ping_id is the ping id that will be sent in the request. | 66 | * ping_id is the ping id that will be sent in the request. |
@@ -71,13 +72,13 @@ typedef struct { | |||
71 | * return -1 on failure. | 72 | * return -1 on failure. |
72 | * return 0 on success. | 73 | * return 0 on success. |
73 | */ | 74 | */ |
74 | int send_announce_request(DHT *dht, Node_format *nodes, uint8_t *public_key, uint8_t *secret_key, uint8_t *ping_id, | 75 | int send_announce_request(Networking_Core *net, Onion_Path *path, Node_format dest, uint8_t *public_key, |
75 | uint8_t *client_id, uint8_t *data_public_key, uint8_t *sendback_data); | 76 | uint8_t *secret_key, uint8_t *ping_id, uint8_t *client_id, uint8_t *data_public_key, uint8_t *sendback_data); |
76 | 77 | ||
77 | /* Create and send an onion data request packet. | 78 | /* Create and send an onion data request packet. |
78 | * | 79 | * |
79 | * nodes is a list of 4 nodes, the packet will route through nodes 0, 1, 2 and the data | 80 | * path is the path the request will take before it is sent to dest. |
80 | * request packet will arrive at 3. (if 3 knows the person with the public_key they should | 81 | * (if dest knows the person with the public_key they should |
81 | * send the packet to that person in the form of a response) | 82 | * send the packet to that person in the form of a response) |
82 | * | 83 | * |
83 | * public_key is the real public key of the node which we want to send the data of length length to. | 84 | * public_key is the real public key of the node which we want to send the data of length length to. |
@@ -88,8 +89,8 @@ int send_announce_request(DHT *dht, Node_format *nodes, uint8_t *public_key, uin | |||
88 | * return -1 on failure. | 89 | * return -1 on failure. |
89 | * return 0 on success. | 90 | * return 0 on success. |
90 | */ | 91 | */ |
91 | int send_data_request(DHT *dht, Node_format *nodes, uint8_t *public_key, uint8_t *encrypt_public_key, uint8_t *nonce, | 92 | int send_data_request(Networking_Core *net, Onion_Path *path, IP_Port dest, uint8_t *public_key, |
92 | uint8_t *data, uint16_t length); | 93 | uint8_t *encrypt_public_key, uint8_t *nonce, uint8_t *data, uint16_t length); |
93 | 94 | ||
94 | 95 | ||
95 | Onion_Announce *new_onion_announce(DHT *dht); | 96 | Onion_Announce *new_onion_announce(DHT *dht); |
diff --git a/toxcore/onion_client.c b/toxcore/onion_client.c index b3c665b7..329b1d13 100644 --- a/toxcore/onion_client.c +++ b/toxcore/onion_client.c | |||
@@ -30,6 +30,65 @@ | |||
30 | 30 | ||
31 | #define ANNOUNCE_TIMEOUT 10 | 31 | #define ANNOUNCE_TIMEOUT 10 |
32 | 32 | ||
33 | /* Create a new path or use an old suitable one (if pathnum is valid) | ||
34 | * or a rondom one from onion_paths. | ||
35 | * | ||
36 | * return -1 on failure | ||
37 | * return 0 on success | ||
38 | * | ||
39 | * TODO: Make this function better, it currently probably is vulnerable to some attacks that | ||
40 | * could de anonimize us. | ||
41 | */ | ||
42 | static int random_path(DHT *dht, Onion_Client_Paths *onion_paths, uint32_t pathnum, Onion_Path *path) | ||
43 | { | ||
44 | if (pathnum >= NUMBER_ONION_PATHS) | ||
45 | pathnum = rand() % NUMBER_ONION_PATHS; | ||
46 | |||
47 | if (is_timeout(onion_paths->last_path_success[pathnum], ONION_PATH_TIMEOUT) | ||
48 | || is_timeout(onion_paths->path_creation_time[pathnum], ONION_PATH_MAX_LIFETIME)) { | ||
49 | Node_format nodes[3]; | ||
50 | |||
51 | if (random_nodes_path(dht, nodes, 3) != 3) | ||
52 | return -1; | ||
53 | |||
54 | if (create_onion_path(dht, &onion_paths->paths[pathnum], nodes) == -1) | ||
55 | return -1; | ||
56 | |||
57 | onion_paths->last_path_success[pathnum] = unix_time() + ONION_PATH_FIRST_TIMEOUT - ONION_PATH_TIMEOUT; | ||
58 | onion_paths->path_creation_time[pathnum] = unix_time(); | ||
59 | } | ||
60 | |||
61 | memcpy(path, &onion_paths->paths[pathnum], sizeof(Onion_Path)); | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | /* Set path timeouts, return the path number. | ||
66 | * | ||
67 | */ | ||
68 | static uint32_t set_path_timeouts(Onion_Client *onion_c, uint32_t num, IP_Port source) | ||
69 | { | ||
70 | if (num > onion_c->num_friends) | ||
71 | return -1; | ||
72 | |||
73 | Onion_Client_Paths *onion_paths; | ||
74 | |||
75 | if (num == 0) { | ||
76 | onion_paths = &onion_c->onion_paths; | ||
77 | } else { | ||
78 | onion_paths = &onion_c->friends_list[num - 1].onion_paths; | ||
79 | } | ||
80 | |||
81 | uint32_t i; | ||
82 | |||
83 | for (i = 0; i < NUMBER_ONION_PATHS; ++i) { | ||
84 | if (ipport_equal(&onion_paths->paths[i].ip_port1, &source)) { | ||
85 | onion_paths->last_path_success[i] = unix_time(); | ||
86 | return i; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | return ~0; | ||
91 | } | ||
33 | 92 | ||
34 | /* Creates a sendback for use in an announce request. | 93 | /* Creates a sendback for use in an announce request. |
35 | * | 94 | * |
@@ -99,7 +158,7 @@ static uint32_t check_sendback(Onion_Client *onion_c, uint8_t *sendback, uint8_t | |||
99 | } | 158 | } |
100 | 159 | ||
101 | static int client_send_announce_request(Onion_Client *onion_c, uint32_t num, IP_Port dest, uint8_t *dest_pubkey, | 160 | static int client_send_announce_request(Onion_Client *onion_c, uint32_t num, IP_Port dest, uint8_t *dest_pubkey, |
102 | uint8_t *ping_id) | 161 | uint8_t *ping_id, uint32_t pathnum) |
103 | { | 162 | { |
104 | if (num > onion_c->num_friends) | 163 | if (num > onion_c->num_friends) |
105 | return -1; | 164 | return -1; |
@@ -114,20 +173,24 @@ static int client_send_announce_request(Onion_Client *onion_c, uint32_t num, IP_ | |||
114 | if (ping_id == NULL) | 173 | if (ping_id == NULL) |
115 | ping_id = zero_ping_id; | 174 | ping_id = zero_ping_id; |
116 | 175 | ||
117 | Node_format nodes[4]; | 176 | Onion_Path path; |
118 | 177 | ||
119 | if (random_path(onion_c, nodes) == -1) | 178 | Node_format dest_node; |
120 | return -1; | 179 | dest_node.ip_port = dest; |
121 | 180 | memcpy(dest_node.client_id, dest_pubkey, crypto_box_PUBLICKEYBYTES); | |
122 | nodes[3].ip_port = dest; | ||
123 | memcpy(nodes[3].client_id, dest_pubkey, crypto_box_PUBLICKEYBYTES); | ||
124 | 181 | ||
125 | if (num == 0) { | 182 | if (num == 0) { |
126 | return send_announce_request(onion_c->dht, nodes, onion_c->dht->c->self_public_key, | 183 | if (random_path(onion_c->dht, &onion_c->onion_paths, pathnum, &path) == -1) |
184 | return -1; | ||
185 | |||
186 | return send_announce_request(onion_c->net, &path, dest_node, onion_c->dht->c->self_public_key, | ||
127 | onion_c->dht->c->self_secret_key, ping_id, | 187 | onion_c->dht->c->self_secret_key, ping_id, |
128 | onion_c->dht->c->self_public_key, onion_c->temp_public_key, sendback); | 188 | onion_c->dht->c->self_public_key, onion_c->temp_public_key, sendback); |
129 | } else { | 189 | } else { |
130 | return send_announce_request(onion_c->dht, nodes, onion_c->friends_list[num - 1].temp_public_key, | 190 | if (random_path(onion_c->dht, &onion_c->friends_list[num - 1].onion_paths, pathnum, &path) == -1) |
191 | return -1; | ||
192 | |||
193 | return send_announce_request(onion_c->net, &path, dest_node, onion_c->friends_list[num - 1].temp_public_key, | ||
131 | onion_c->friends_list[num - 1].temp_secret_key, ping_id, | 194 | onion_c->friends_list[num - 1].temp_secret_key, ping_id, |
132 | onion_c->friends_list[num - 1].real_client_id, zero_ping_id, sendback); | 195 | onion_c->friends_list[num - 1].real_client_id, zero_ping_id, sendback); |
133 | } | 196 | } |
@@ -163,7 +226,7 @@ static int cmp_entry(const void *a, const void *b) | |||
163 | } | 226 | } |
164 | 227 | ||
165 | static int client_add_to_list(Onion_Client *onion_c, uint32_t num, uint8_t *public_key, IP_Port ip_port, | 228 | static int client_add_to_list(Onion_Client *onion_c, uint32_t num, uint8_t *public_key, IP_Port ip_port, |
166 | uint8_t is_stored, uint8_t *pingid_or_key) | 229 | uint8_t is_stored, uint8_t *pingid_or_key, IP_Port source) |
167 | { | 230 | { |
168 | if (num > onion_c->num_friends) | 231 | if (num > onion_c->num_friends) |
169 | return -1; | 232 | return -1; |
@@ -223,10 +286,27 @@ static int client_add_to_list(Onion_Client *onion_c, uint32_t num, uint8_t *publ | |||
223 | 286 | ||
224 | list_nodes[index].is_stored = is_stored; | 287 | list_nodes[index].is_stored = is_stored; |
225 | list_nodes[index].timestamp = unix_time(); | 288 | list_nodes[index].timestamp = unix_time(); |
226 | list_nodes[index].last_pinged = 0; | 289 | list_nodes[index].last_pinged = unix_time(); |
290 | list_nodes[index].path_used = set_path_timeouts(onion_c, num, source); | ||
227 | return 0; | 291 | return 0; |
228 | } | 292 | } |
229 | 293 | ||
294 | static int good_to_ping(Last_Pinged *last_pinged, uint8_t *last_pinged_index, uint8_t *client_id) | ||
295 | { | ||
296 | uint32_t i; | ||
297 | |||
298 | for (i = 0; i < MAX_STORED_PINGED_NODES; ++i) { | ||
299 | if (!is_timeout(last_pinged[i].timestamp, MIN_NODE_PING_TIME)) | ||
300 | if (memcmp(last_pinged[i].client_id, client_id, crypto_box_PUBLICKEYBYTES) == 0) | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | memcpy(last_pinged[*last_pinged_index % MAX_STORED_PINGED_NODES].client_id, client_id, crypto_box_PUBLICKEYBYTES); | ||
305 | last_pinged[*last_pinged_index % MAX_STORED_PINGED_NODES].timestamp = unix_time(); | ||
306 | ++*last_pinged_index; | ||
307 | return 1; | ||
308 | } | ||
309 | |||
230 | static int client_ping_nodes(Onion_Client *onion_c, uint32_t num, Node_format *nodes, uint16_t num_nodes, | 310 | static int client_ping_nodes(Onion_Client *onion_c, uint32_t num, Node_format *nodes, uint16_t num_nodes, |
231 | IP_Port source) | 311 | IP_Port source) |
232 | { | 312 | { |
@@ -238,19 +318,33 @@ static int client_ping_nodes(Onion_Client *onion_c, uint32_t num, Node_format *n | |||
238 | 318 | ||
239 | Onion_Node *list_nodes = NULL; | 319 | Onion_Node *list_nodes = NULL; |
240 | uint8_t *reference_id = NULL; | 320 | uint8_t *reference_id = NULL; |
321 | uint32_t *ping_nodes_sent_second = NULL; | ||
322 | |||
323 | Last_Pinged *last_pinged = NULL; | ||
324 | uint8_t *last_pinged_index = NULL; | ||
241 | 325 | ||
242 | if (num == 0) { | 326 | if (num == 0) { |
243 | list_nodes = onion_c->clients_announce_list; | 327 | list_nodes = onion_c->clients_announce_list; |
244 | reference_id = onion_c->dht->c->self_public_key; | 328 | reference_id = onion_c->dht->c->self_public_key; |
329 | ping_nodes_sent_second = &onion_c->ping_nodes_sent_second; | ||
330 | last_pinged = onion_c->last_pinged; | ||
331 | last_pinged_index = &onion_c->last_pinged_index; | ||
245 | } else { | 332 | } else { |
246 | list_nodes = onion_c->friends_list[num - 1].clients_list; | 333 | list_nodes = onion_c->friends_list[num - 1].clients_list; |
247 | reference_id = onion_c->friends_list[num - 1].real_client_id; | 334 | reference_id = onion_c->friends_list[num - 1].real_client_id; |
335 | ping_nodes_sent_second = &onion_c->friends_list[num - 1].ping_nodes_sent_second; | ||
336 | last_pinged = onion_c->friends_list[num - 1].last_pinged; | ||
337 | last_pinged_index = &onion_c->friends_list[num - 1].last_pinged_index; | ||
248 | } | 338 | } |
249 | 339 | ||
250 | uint32_t i, j; | 340 | uint32_t i, j; |
251 | int lan_ips_accepted = (LAN_ip(source.ip) == 0); | 341 | int lan_ips_accepted = (LAN_ip(source.ip) == 0); |
252 | 342 | ||
253 | for (i = 0; i < num_nodes; ++i) { | 343 | for (i = 0; i < num_nodes; ++i) { |
344 | |||
345 | if (*ping_nodes_sent_second > MAX_PING_NODES_SECOND_PEER) | ||
346 | return 0; | ||
347 | |||
254 | to_host_family(&nodes[i].ip_port.ip); | 348 | to_host_family(&nodes[i].ip_port.ip); |
255 | 349 | ||
256 | if (!lan_ips_accepted) | 350 | if (!lan_ips_accepted) |
@@ -266,8 +360,9 @@ static int client_ping_nodes(Onion_Client *onion_c, uint32_t num, Node_format *n | |||
266 | } | 360 | } |
267 | } | 361 | } |
268 | 362 | ||
269 | if (j == MAX_ONION_CLIENTS) { | 363 | if (j == MAX_ONION_CLIENTS && good_to_ping(last_pinged, last_pinged_index, nodes[i].client_id)) { |
270 | client_send_announce_request(onion_c, num, nodes[i].ip_port, nodes[i].client_id, NULL); | 364 | if (client_send_announce_request(onion_c, num, nodes[i].ip_port, nodes[i].client_id, NULL, ~0) == 0) |
365 | ++*ping_nodes_sent_second; | ||
271 | } | 366 | } |
272 | } | 367 | } |
273 | } | 368 | } |
@@ -315,7 +410,7 @@ static int handle_announce_response(void *object, IP_Port source, uint8_t *packe | |||
315 | return 1; | 410 | return 1; |
316 | 411 | ||
317 | 412 | ||
318 | if (client_add_to_list(onion_c, num, public_key, ip_port, plain[0], plain + 1) == -1) | 413 | if (client_add_to_list(onion_c, num, public_key, ip_port, plain[0], plain + 1, source) == -1) |
319 | return 1; | 414 | return 1; |
320 | 415 | ||
321 | Node_format nodes[MAX_SENT_NODES]; | 416 | Node_format nodes[MAX_SENT_NODES]; |
@@ -447,28 +542,37 @@ int send_onion_data(Onion_Client *onion_c, int friend_num, uint8_t *data, uint32 | |||
447 | if ((uint32_t)len + crypto_box_PUBLICKEYBYTES != sizeof(packet)) | 542 | if ((uint32_t)len + crypto_box_PUBLICKEYBYTES != sizeof(packet)) |
448 | return -1; | 543 | return -1; |
449 | 544 | ||
450 | uint32_t i, good = 0; | 545 | uint32_t i, good_nodes[MAX_ONION_CLIENTS], num_good = 0, num_nodes = 0; |
546 | Onion_Path path[MAX_ONION_CLIENTS]; | ||
451 | Onion_Node *list_nodes = onion_c->friends_list[friend_num].clients_list; | 547 | Onion_Node *list_nodes = onion_c->friends_list[friend_num].clients_list; |
452 | 548 | ||
453 | for (i = 0; i < MAX_ONION_CLIENTS; ++i) { | 549 | for (i = 0; i < MAX_ONION_CLIENTS; ++i) { |
454 | if (is_timeout(list_nodes[i].timestamp, ONION_NODE_TIMEOUT)) | 550 | if (is_timeout(list_nodes[i].timestamp, ONION_NODE_TIMEOUT)) |
455 | continue; | 551 | continue; |
456 | 552 | ||
457 | if (list_nodes[i].is_stored) { | 553 | ++num_nodes; |
458 | Node_format nodes[4]; | ||
459 | 554 | ||
460 | if (random_path(onion_c, nodes) == -1) | 555 | if (list_nodes[i].is_stored) { |
556 | if (random_path(onion_c->dht, &onion_c->friends_list[friend_num].onion_paths, ~0, &path[num_good]) == -1) | ||
461 | continue; | 557 | continue; |
462 | 558 | ||
463 | memcpy(nodes[3].client_id, list_nodes[i].client_id, crypto_box_PUBLICKEYBYTES); | 559 | good_nodes[num_good] = i; |
464 | nodes[3].ip_port = list_nodes[i].ip_port; | 560 | ++num_good; |
465 | |||
466 | if (send_data_request(onion_c->dht, nodes, onion_c->friends_list[friend_num].real_client_id, | ||
467 | list_nodes[i].data_public_key, nonce, packet, sizeof(packet)) == 0) | ||
468 | ++good; | ||
469 | } | 561 | } |
470 | } | 562 | } |
471 | 563 | ||
564 | if (num_good < (num_nodes / 4) + 1) | ||
565 | return -1; | ||
566 | |||
567 | uint32_t good = 0; | ||
568 | |||
569 | for (i = 0; i < num_good; ++i) { | ||
570 | if (send_data_request(onion_c->net, &path[i], list_nodes[good_nodes[i]].ip_port, | ||
571 | onion_c->friends_list[friend_num].real_client_id, list_nodes[good_nodes[i]].data_public_key, nonce, packet, | ||
572 | sizeof(packet)) == 0) | ||
573 | ++good; | ||
574 | } | ||
575 | |||
472 | return good; | 576 | return good; |
473 | } | 577 | } |
474 | 578 | ||
@@ -731,25 +835,8 @@ int onion_set_friend_online(Onion_Client *onion_c, int friend_num, uint8_t is_on | |||
731 | return 0; | 835 | return 0; |
732 | } | 836 | } |
733 | 837 | ||
734 | /* Takes 3 random nodes that we know and puts them in nodes | ||
735 | * | ||
736 | * nodes must be longer than 3. | ||
737 | * | ||
738 | * return -1 on failure | ||
739 | * return 0 on success | ||
740 | * | ||
741 | * TODO: Make this function better, it currently might be vulnerable to some attacks that | ||
742 | * could de anonimize us. | ||
743 | */ | ||
744 | int random_path(Onion_Client *onion_c, Node_format *nodes) | ||
745 | { | ||
746 | if (random_nodes_path(onion_c->dht, nodes, 3) != 3) | ||
747 | return -1; | ||
748 | |||
749 | return 0; | ||
750 | } | ||
751 | 838 | ||
752 | #define ANNOUNCE_FRIEND 30 | 839 | #define ANNOUNCE_FRIEND ONION_NODE_PING_INTERVAL |
753 | 840 | ||
754 | static void do_friend(Onion_Client *onion_c, uint16_t friendnum) | 841 | static void do_friend(Onion_Client *onion_c, uint16_t friendnum) |
755 | { | 842 | { |
@@ -770,7 +857,7 @@ static void do_friend(Onion_Client *onion_c, uint16_t friendnum) | |||
770 | ++count; | 857 | ++count; |
771 | 858 | ||
772 | if (is_timeout(list_nodes[i].last_pinged, ANNOUNCE_FRIEND)) { | 859 | if (is_timeout(list_nodes[i].last_pinged, ANNOUNCE_FRIEND)) { |
773 | if (client_send_announce_request(onion_c, friendnum + 1, list_nodes[i].ip_port, list_nodes[i].client_id, 0) == 0) { | 860 | if (client_send_announce_request(onion_c, friendnum + 1, list_nodes[i].ip_port, list_nodes[i].client_id, 0, ~0) == 0) { |
774 | list_nodes[i].last_pinged = unix_time(); | 861 | list_nodes[i].last_pinged = unix_time(); |
775 | } | 862 | } |
776 | } | 863 | } |
@@ -783,7 +870,7 @@ static void do_friend(Onion_Client *onion_c, uint16_t friendnum) | |||
783 | rand() % 2 ? AF_INET : AF_INET6, 1, 0); | 870 | rand() % 2 ? AF_INET : AF_INET6, 1, 0); |
784 | 871 | ||
785 | for (i = 0; i < num_nodes; ++i) | 872 | for (i = 0; i < num_nodes; ++i) |
786 | client_send_announce_request(onion_c, friendnum + 1, nodes_list[i].ip_port, nodes_list[i].client_id, 0); | 873 | client_send_announce_request(onion_c, friendnum + 1, nodes_list[i].ip_port, nodes_list[i].client_id, 0, ~0); |
787 | } | 874 | } |
788 | } | 875 | } |
789 | 876 | ||
@@ -824,8 +911,8 @@ void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_ha | |||
824 | onion_c->Onion_Data_Handlers[byte].object = object; | 911 | onion_c->Onion_Data_Handlers[byte].object = object; |
825 | } | 912 | } |
826 | 913 | ||
827 | #define ANNOUNCE_INTERVAL_NOT_ANNOUNCED 7 | 914 | #define ANNOUNCE_INTERVAL_NOT_ANNOUNCED 10 |
828 | #define ANNOUNCE_INTERVAL_ANNOUNCED 30 | 915 | #define ANNOUNCE_INTERVAL_ANNOUNCED ONION_NODE_PING_INTERVAL |
829 | 916 | ||
830 | static void do_announce(Onion_Client *onion_c) | 917 | static void do_announce(Onion_Client *onion_c) |
831 | { | 918 | { |
@@ -845,7 +932,7 @@ static void do_announce(Onion_Client *onion_c) | |||
845 | 932 | ||
846 | if (is_timeout(list_nodes[i].last_pinged, interval)) { | 933 | if (is_timeout(list_nodes[i].last_pinged, interval)) { |
847 | if (client_send_announce_request(onion_c, 0, list_nodes[i].ip_port, list_nodes[i].client_id, | 934 | if (client_send_announce_request(onion_c, 0, list_nodes[i].ip_port, list_nodes[i].client_id, |
848 | list_nodes[i].ping_id) == 0) { | 935 | list_nodes[i].ping_id, list_nodes[i].path_used) == 0) { |
849 | list_nodes[i].last_pinged = unix_time(); | 936 | list_nodes[i].last_pinged = unix_time(); |
850 | } | 937 | } |
851 | } | 938 | } |
@@ -857,8 +944,9 @@ static void do_announce(Onion_Client *onion_c) | |||
857 | uint32_t num_nodes = get_close_nodes(onion_c->dht, onion_c->dht->c->self_public_key, nodes_list, | 944 | uint32_t num_nodes = get_close_nodes(onion_c->dht, onion_c->dht->c->self_public_key, nodes_list, |
858 | rand() % 2 ? AF_INET : AF_INET6, 1, 0); | 945 | rand() % 2 ? AF_INET : AF_INET6, 1, 0); |
859 | 946 | ||
860 | for (i = 0; i < num_nodes; ++i) | 947 | for (i = 0; i < num_nodes; ++i) { |
861 | client_send_announce_request(onion_c, 0, nodes_list[i].ip_port, nodes_list[i].client_id, 0); | 948 | client_send_announce_request(onion_c, 0, nodes_list[i].ip_port, nodes_list[i].client_id, 0, ~0); |
949 | } | ||
862 | } | 950 | } |
863 | } | 951 | } |
864 | } | 952 | } |
@@ -875,8 +963,10 @@ void do_onion_client(Onion_Client *onion_c) | |||
875 | for (i = 0; i < onion_c->num_friends; ++i) { | 963 | for (i = 0; i < onion_c->num_friends; ++i) { |
876 | do_friend(onion_c, i); | 964 | do_friend(onion_c, i); |
877 | cleanup_friend(onion_c, i); | 965 | cleanup_friend(onion_c, i); |
966 | onion_c->friends_list[i].ping_nodes_sent_second = 0; | ||
878 | } | 967 | } |
879 | 968 | ||
969 | onion_c->ping_nodes_sent_second = 0; | ||
880 | onion_c->last_run = unix_time(); | 970 | onion_c->last_run = unix_time(); |
881 | } | 971 | } |
882 | 972 | ||
diff --git a/toxcore/onion_client.h b/toxcore/onion_client.h index 36b5b5c3..4045cc0e 100644 --- a/toxcore/onion_client.h +++ b/toxcore/onion_client.h | |||
@@ -27,12 +27,29 @@ | |||
27 | #include "onion_announce.h" | 27 | #include "onion_announce.h" |
28 | 28 | ||
29 | #define MAX_ONION_CLIENTS 8 | 29 | #define MAX_ONION_CLIENTS 8 |
30 | #define ONION_NODE_TIMEOUT 240 | 30 | #define ONION_NODE_PING_INTERVAL 30 |
31 | #define ONION_NODE_TIMEOUT (ONION_NODE_PING_INTERVAL * 4) | ||
31 | 32 | ||
32 | /* The interval in seconds at which to tell our friends where we are */ | 33 | /* The interval in seconds at which to tell our friends where we are */ |
33 | #define ONION_FAKEID_INTERVAL 30 | 34 | #define ONION_FAKEID_INTERVAL 30 |
34 | #define DHT_FAKEID_INTERVAL 20 | 35 | #define DHT_FAKEID_INTERVAL 20 |
35 | 36 | ||
37 | #define NUMBER_ONION_PATHS 3 | ||
38 | |||
39 | /* The timeout the first time the path is added and | ||
40 | then for all the next consecutive times */ | ||
41 | #define ONION_PATH_FIRST_TIMEOUT 5 | ||
42 | #define ONION_PATH_TIMEOUT 30 | ||
43 | #define ONION_PATH_MAX_LIFETIME 600 | ||
44 | |||
45 | /* A cheap way of making it take less bandwidth at startup: | ||
46 | by limiting the number of ping packets we can send per | ||
47 | second per peer. */ | ||
48 | #define MAX_PING_NODES_SECOND_PEER 5 | ||
49 | |||
50 | #define MAX_STORED_PINGED_NODES 9 | ||
51 | #define MIN_NODE_PING_TIME 10 | ||
52 | |||
36 | typedef struct { | 53 | typedef struct { |
37 | uint8_t client_id[CLIENT_ID_SIZE]; | 54 | uint8_t client_id[CLIENT_ID_SIZE]; |
38 | IP_Port ip_port; | 55 | IP_Port ip_port; |
@@ -43,9 +60,22 @@ typedef struct { | |||
43 | uint64_t timestamp; | 60 | uint64_t timestamp; |
44 | 61 | ||
45 | uint64_t last_pinged; | 62 | uint64_t last_pinged; |
63 | |||
64 | uint32_t path_used; | ||
46 | } Onion_Node; | 65 | } Onion_Node; |
47 | 66 | ||
48 | typedef struct { | 67 | typedef struct { |
68 | Onion_Path paths[NUMBER_ONION_PATHS]; | ||
69 | uint64_t last_path_success[NUMBER_ONION_PATHS]; | ||
70 | uint64_t path_creation_time[NUMBER_ONION_PATHS]; | ||
71 | } Onion_Client_Paths; | ||
72 | |||
73 | typedef struct { | ||
74 | uint8_t client_id[CLIENT_ID_SIZE]; | ||
75 | uint64_t timestamp; | ||
76 | } Last_Pinged; | ||
77 | |||
78 | typedef struct { | ||
49 | uint8_t status; /* 0 if friend is not valid, 1 if friend is valid.*/ | 79 | uint8_t status; /* 0 if friend is not valid, 1 if friend is valid.*/ |
50 | uint8_t is_online; /* Set by the onion_set_friend_status function. */ | 80 | uint8_t is_online; /* Set by the onion_set_friend_status function. */ |
51 | 81 | ||
@@ -63,6 +93,12 @@ typedef struct { | |||
63 | uint64_t last_noreplay; | 93 | uint64_t last_noreplay; |
64 | 94 | ||
65 | uint64_t last_seen; | 95 | uint64_t last_seen; |
96 | |||
97 | Onion_Client_Paths onion_paths; | ||
98 | uint32_t ping_nodes_sent_second; | ||
99 | |||
100 | Last_Pinged last_pinged[MAX_STORED_PINGED_NODES]; | ||
101 | uint8_t last_pinged_index; | ||
66 | } Onion_Friend; | 102 | } Onion_Friend; |
67 | 103 | ||
68 | typedef int (*oniondata_handler_callback)(void *object, uint8_t *source_pubkey, uint8_t *data, uint32_t len); | 104 | typedef int (*oniondata_handler_callback)(void *object, uint8_t *source_pubkey, uint8_t *data, uint32_t len); |
@@ -75,11 +111,18 @@ typedef struct { | |||
75 | 111 | ||
76 | Onion_Node clients_announce_list[MAX_ONION_CLIENTS]; | 112 | Onion_Node clients_announce_list[MAX_ONION_CLIENTS]; |
77 | 113 | ||
114 | Onion_Client_Paths onion_paths; | ||
115 | |||
78 | uint8_t secret_symmetric_key[crypto_secretbox_KEYBYTES]; | 116 | uint8_t secret_symmetric_key[crypto_secretbox_KEYBYTES]; |
79 | uint64_t last_run; | 117 | uint64_t last_run; |
80 | 118 | ||
81 | uint8_t temp_public_key[crypto_box_PUBLICKEYBYTES]; | 119 | uint8_t temp_public_key[crypto_box_PUBLICKEYBYTES]; |
82 | uint8_t temp_secret_key[crypto_box_SECRETKEYBYTES]; | 120 | uint8_t temp_secret_key[crypto_box_SECRETKEYBYTES]; |
121 | |||
122 | uint32_t ping_nodes_sent_second; | ||
123 | |||
124 | Last_Pinged last_pinged[MAX_STORED_PINGED_NODES]; | ||
125 | uint8_t last_pinged_index; | ||
83 | struct { | 126 | struct { |
84 | oniondata_handler_callback function; | 127 | oniondata_handler_callback function; |
85 | void *object; | 128 | void *object; |
@@ -127,15 +170,6 @@ int onion_set_friend_online(Onion_Client *onion_c, int friend_num, uint8_t is_on | |||
127 | */ | 170 | */ |
128 | int onion_getfriendip(Onion_Client *onion_c, int friend_num, IP_Port *ip_port); | 171 | int onion_getfriendip(Onion_Client *onion_c, int friend_num, IP_Port *ip_port); |
129 | 172 | ||
130 | /* Takes 3 random nodes that we know and puts them in nodes | ||
131 | * | ||
132 | * nodes must be longer than 3. | ||
133 | * | ||
134 | * return -1 on failure | ||
135 | * return 0 on success | ||
136 | * | ||
137 | */ | ||
138 | int random_path(Onion_Client *onion_c, Node_format *nodes); | ||
139 | 173 | ||
140 | /* Send data of length length to friendnum. | 174 | /* Send data of length length to friendnum. |
141 | * This data will be recieved by the friend using the Onion_Data_Handlers callbacks. | 175 | * This data will be recieved by the friend using the Onion_Data_Handlers callbacks. |
diff --git a/toxcore/ping.c b/toxcore/ping.c index 6b1b906a..649d3fff 100644 --- a/toxcore/ping.c +++ b/toxcore/ping.c | |||
@@ -37,13 +37,17 @@ | |||
37 | 37 | ||
38 | #define PING_NUM_MAX 512 | 38 | #define PING_NUM_MAX 512 |
39 | 39 | ||
40 | /* Ping newly announced nodes to ping per TIME_TOPING seconds*/ | 40 | /* Maximum newly announced nodes to ping per TIME_TO_PING seconds. */ |
41 | #define TIME_TOPING 5 | 41 | #define MAX_TO_PING 16 |
42 | |||
43 | /* Ping newly announced nodes to ping per TIME_TO_PING seconds*/ | ||
44 | #define TIME_TO_PING 5 | ||
42 | 45 | ||
43 | typedef struct { | 46 | typedef struct { |
44 | IP_Port ip_port; | 47 | IP_Port ip_port; |
45 | uint64_t id; | 48 | uint64_t id; |
46 | uint64_t timestamp; | 49 | uint64_t timestamp; |
50 | uint8_t shared_key[crypto_box_BEFORENMBYTES]; | ||
47 | } pinged_t; | 51 | } pinged_t; |
48 | 52 | ||
49 | struct PING { | 53 | struct PING { |
@@ -53,8 +57,8 @@ struct PING { | |||
53 | size_t num_pings; | 57 | size_t num_pings; |
54 | size_t pos_pings; | 58 | size_t pos_pings; |
55 | 59 | ||
56 | Node_format toping[MAX_TOPING]; | 60 | Node_format to_ping[MAX_TO_PING]; |
57 | uint64_t last_toping; | 61 | uint64_t last_to_ping; |
58 | }; | 62 | }; |
59 | 63 | ||
60 | static int is_ping_timeout(uint64_t time) | 64 | static int is_ping_timeout(uint64_t time) |
@@ -86,7 +90,7 @@ static void remove_timeouts(PING *ping) // O(n) | |||
86 | ping->pos_pings = new_pos % PING_NUM_MAX; | 90 | ping->pos_pings = new_pos % PING_NUM_MAX; |
87 | } | 91 | } |
88 | 92 | ||
89 | static uint64_t add_ping(PING *ping, IP_Port ipp) // O(n) | 93 | static uint64_t add_ping(PING *ping, IP_Port ipp, uint8_t *shared_encryption_key) // O(n) |
90 | { | 94 | { |
91 | size_t p; | 95 | size_t p; |
92 | 96 | ||
@@ -104,6 +108,7 @@ static uint64_t add_ping(PING *ping, IP_Port ipp) // O(n) | |||
104 | ping->pings[p].ip_port = ipp; | 108 | ping->pings[p].ip_port = ipp; |
105 | ping->pings[p].timestamp = unix_time(); | 109 | ping->pings[p].timestamp = unix_time(); |
106 | ping->pings[p].id = random_64b(); | 110 | ping->pings[p].id = random_64b(); |
111 | memcpy(ping->pings[p].shared_key, shared_encryption_key, crypto_box_BEFORENMBYTES); | ||
107 | 112 | ||
108 | ping->num_pings++; | 113 | ping->num_pings++; |
109 | return ping->pings[p].id; | 114 | return ping->pings[p].id; |
@@ -151,19 +156,22 @@ int send_ping_request(PING *ping, IP_Port ipp, uint8_t *client_id) | |||
151 | if (is_pinging(ping, ipp, 0) || id_equal(client_id, ping->dht->self_public_key)) | 156 | if (is_pinging(ping, ipp, 0) || id_equal(client_id, ping->dht->self_public_key)) |
152 | return 1; | 157 | return 1; |
153 | 158 | ||
159 | uint8_t shared_key[crypto_box_BEFORENMBYTES]; | ||
160 | |||
161 | // generate key to encrypt ping_id with recipient privkey | ||
162 | DHT_get_shared_key_sent(ping->dht, shared_key, client_id); | ||
154 | // Generate random ping_id. | 163 | // Generate random ping_id. |
155 | ping_id = add_ping(ping, ipp); | 164 | ping_id = add_ping(ping, ipp, shared_key); |
156 | 165 | ||
157 | pk[0] = NET_PACKET_PING_REQUEST; | 166 | pk[0] = NET_PACKET_PING_REQUEST; |
158 | id_copy(pk + 1, ping->dht->self_public_key); // Our pubkey | 167 | id_copy(pk + 1, ping->dht->self_public_key); // Our pubkey |
159 | new_nonce(pk + 1 + CLIENT_ID_SIZE); // Generate new nonce | 168 | new_nonce(pk + 1 + CLIENT_ID_SIZE); // Generate new nonce |
160 | 169 | ||
161 | // Encrypt ping_id using recipient privkey | 170 | |
162 | rc = encrypt_data(client_id, | 171 | rc = encrypt_data_fast(shared_key, |
163 | ping->dht->self_secret_key, | 172 | pk + 1 + CLIENT_ID_SIZE, |
164 | pk + 1 + CLIENT_ID_SIZE, | 173 | (uint8_t *) &ping_id, sizeof(ping_id), |
165 | (uint8_t *) &ping_id, sizeof(ping_id), | 174 | pk + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES); |
166 | pk + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES); | ||
167 | 175 | ||
168 | if (rc != sizeof(ping_id) + crypto_box_MACBYTES) | 176 | if (rc != sizeof(ping_id) + crypto_box_MACBYTES) |
169 | return 1; | 177 | return 1; |
@@ -171,7 +179,8 @@ int send_ping_request(PING *ping, IP_Port ipp, uint8_t *client_id) | |||
171 | return sendpacket(ping->dht->net, ipp, pk, sizeof(pk)); | 179 | return sendpacket(ping->dht->net, ipp, pk, sizeof(pk)); |
172 | } | 180 | } |
173 | 181 | ||
174 | static int send_ping_response(PING *ping, IP_Port ipp, uint8_t *client_id, uint64_t ping_id) | 182 | static int send_ping_response(PING *ping, IP_Port ipp, uint8_t *client_id, uint64_t ping_id, |
183 | uint8_t *shared_encryption_key) | ||
175 | { | 184 | { |
176 | uint8_t pk[DHT_PING_SIZE]; | 185 | uint8_t pk[DHT_PING_SIZE]; |
177 | int rc; | 186 | int rc; |
@@ -184,11 +193,10 @@ static int send_ping_response(PING *ping, IP_Port ipp, uint8_t *client_id, uint6 | |||
184 | new_nonce(pk + 1 + CLIENT_ID_SIZE); // Generate new nonce | 193 | new_nonce(pk + 1 + CLIENT_ID_SIZE); // Generate new nonce |
185 | 194 | ||
186 | // Encrypt ping_id using recipient privkey | 195 | // Encrypt ping_id using recipient privkey |
187 | rc = encrypt_data(client_id, | 196 | rc = encrypt_data_fast(shared_encryption_key, |
188 | ping->dht->self_secret_key, | 197 | pk + 1 + CLIENT_ID_SIZE, |
189 | pk + 1 + CLIENT_ID_SIZE, | 198 | (uint8_t *) &ping_id, sizeof(ping_id), |
190 | (uint8_t *) &ping_id, sizeof(ping_id), | 199 | pk + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES ); |
191 | pk + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES); | ||
192 | 200 | ||
193 | if (rc != sizeof(ping_id) + crypto_box_MACBYTES) | 201 | if (rc != sizeof(ping_id) + crypto_box_MACBYTES) |
194 | return 1; | 202 | return 1; |
@@ -210,20 +218,22 @@ static int handle_ping_request(void *_dht, IP_Port source, uint8_t *packet, uint | |||
210 | if (id_equal(packet + 1, ping->dht->self_public_key)) | 218 | if (id_equal(packet + 1, ping->dht->self_public_key)) |
211 | return 1; | 219 | return 1; |
212 | 220 | ||
221 | uint8_t shared_key[crypto_box_BEFORENMBYTES]; | ||
222 | |||
213 | // Decrypt ping_id | 223 | // Decrypt ping_id |
214 | rc = decrypt_data(packet + 1, | 224 | DHT_get_shared_key_recv(dht, shared_key, packet + 1); |
215 | ping->dht->self_secret_key, | 225 | rc = decrypt_data_fast(shared_key, |
216 | packet + 1 + CLIENT_ID_SIZE, | 226 | packet + 1 + CLIENT_ID_SIZE, |
217 | packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, | 227 | packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, |
218 | sizeof(ping_id) + crypto_box_MACBYTES, | 228 | sizeof(ping_id) + crypto_box_MACBYTES, |
219 | (uint8_t *) &ping_id); | 229 | (uint8_t *) &ping_id ); |
220 | 230 | ||
221 | if (rc != sizeof(ping_id)) | 231 | if (rc != sizeof(ping_id)) |
222 | return 1; | 232 | return 1; |
223 | 233 | ||
224 | // Send response | 234 | // Send response |
225 | send_ping_response(ping, source, packet + 1, ping_id); | 235 | send_ping_response(ping, source, packet + 1, ping_id, shared_key); |
226 | add_toping(ping, packet + 1, source); | 236 | add_to_ping(ping, packet + 1, source); |
227 | 237 | ||
228 | return 0; | 238 | return 0; |
229 | } | 239 | } |
@@ -242,21 +252,23 @@ static int handle_ping_response(void *_dht, IP_Port source, uint8_t *packet, uin | |||
242 | if (id_equal(packet + 1, ping->dht->self_public_key)) | 252 | if (id_equal(packet + 1, ping->dht->self_public_key)) |
243 | return 1; | 253 | return 1; |
244 | 254 | ||
255 | int ping_index = is_pinging(ping, source, 0); | ||
256 | |||
257 | if (!ping_index) | ||
258 | return 1; | ||
259 | |||
260 | --ping_index; | ||
245 | // Decrypt ping_id | 261 | // Decrypt ping_id |
246 | rc = decrypt_data(packet + 1, | 262 | rc = decrypt_data_fast(ping->pings[ping_index].shared_key, |
247 | ping->dht->self_secret_key, | 263 | packet + 1 + CLIENT_ID_SIZE, |
248 | packet + 1 + CLIENT_ID_SIZE, | 264 | packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, |
249 | packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, | 265 | sizeof(ping_id) + crypto_box_MACBYTES, |
250 | sizeof(ping_id) + crypto_box_MACBYTES, | 266 | (uint8_t *) &ping_id); |
251 | (uint8_t *) &ping_id); | ||
252 | 267 | ||
253 | if (rc != sizeof(ping_id)) | 268 | if (rc != sizeof(ping_id)) |
254 | return 1; | 269 | return 1; |
255 | 270 | ||
256 | /* Make sure ping_id is correct. */ | 271 | if (ping->pings[ping_index].id != ping_id) |
257 | int ping_index = is_pinging(ping, source, ping_id); | ||
258 | |||
259 | if (!ping_index) | ||
260 | return 1; | 272 | return 1; |
261 | 273 | ||
262 | addto_lists(dht, source, packet + 1); | 274 | addto_lists(dht, source, packet + 1); |
@@ -265,8 +277,8 @@ static int handle_ping_response(void *_dht, IP_Port source, uint8_t *packet, uin | |||
265 | } | 277 | } |
266 | 278 | ||
267 | 279 | ||
268 | /* Add nodes to the toping list. | 280 | /* Add nodes to the to_ping list. |
269 | * All nodes in this list are pinged every TIME_TOPING seconds | 281 | * All nodes in this list are pinged every TIME_TO_PING seconds |
270 | * and are then removed from the list. | 282 | * and are then removed from the list. |
271 | * If the list is full the nodes farthest from our client_id are replaced. | 283 | * If the list is full the nodes farthest from our client_id are replaced. |
272 | * The purpose of this list is to enable quick integration of new nodes into the | 284 | * The purpose of this list is to enable quick integration of new nodes into the |
@@ -275,25 +287,25 @@ static int handle_ping_response(void *_dht, IP_Port source, uint8_t *packet, uin | |||
275 | * return 0 if node was added. | 287 | * return 0 if node was added. |
276 | * return -1 if node was not added. | 288 | * return -1 if node was not added. |
277 | */ | 289 | */ |
278 | int add_toping(PING *ping, uint8_t *client_id, IP_Port ip_port) | 290 | int add_to_ping(PING *ping, uint8_t *client_id, IP_Port ip_port) |
279 | { | 291 | { |
280 | if (!ip_isset(&ip_port.ip)) | 292 | if (!ip_isset(&ip_port.ip)) |
281 | return -1; | 293 | return -1; |
282 | 294 | ||
283 | uint32_t i; | 295 | uint32_t i; |
284 | 296 | ||
285 | for (i = 0; i < MAX_TOPING; ++i) { | 297 | for (i = 0; i < MAX_TO_PING; ++i) { |
286 | if (!ip_isset(&ping->toping[i].ip_port.ip)) { | 298 | if (!ip_isset(&ping->to_ping[i].ip_port.ip)) { |
287 | memcpy(ping->toping[i].client_id, client_id, CLIENT_ID_SIZE); | 299 | memcpy(ping->to_ping[i].client_id, client_id, CLIENT_ID_SIZE); |
288 | ipport_copy(&ping->toping[i].ip_port, &ip_port); | 300 | ipport_copy(&ping->to_ping[i].ip_port, &ip_port); |
289 | return 0; | 301 | return 0; |
290 | } | 302 | } |
291 | } | 303 | } |
292 | 304 | ||
293 | for (i = 0; i < MAX_TOPING; ++i) { | 305 | for (i = 0; i < MAX_TO_PING; ++i) { |
294 | if (id_closest(ping->dht->self_public_key, ping->toping[i].client_id, client_id) == 2) { | 306 | if (id_closest(ping->dht->self_public_key, ping->to_ping[i].client_id, client_id) == 2) { |
295 | memcpy(ping->toping[i].client_id, client_id, CLIENT_ID_SIZE); | 307 | memcpy(ping->to_ping[i].client_id, client_id, CLIENT_ID_SIZE); |
296 | ipport_copy(&ping->toping[i].ip_port, &ip_port); | 308 | ipport_copy(&ping->to_ping[i].ip_port, &ip_port); |
297 | return 0; | 309 | return 0; |
298 | } | 310 | } |
299 | } | 311 | } |
@@ -302,23 +314,23 @@ int add_toping(PING *ping, uint8_t *client_id, IP_Port ip_port) | |||
302 | } | 314 | } |
303 | 315 | ||
304 | 316 | ||
305 | /* Ping all the valid nodes in the toping list every TIME_TOPING seconds. | 317 | /* Ping all the valid nodes in the to_ping list every TIME_TO_PING seconds. |
306 | * This function must be run at least once every TIME_TOPING seconds. | 318 | * This function must be run at least once every TIME_TO_PING seconds. |
307 | */ | 319 | */ |
308 | void do_toping(PING *ping) | 320 | void do_to_ping(PING *ping) |
309 | { | 321 | { |
310 | if (!is_timeout(ping->last_toping, TIME_TOPING)) | 322 | if (!is_timeout(ping->last_to_ping, TIME_TO_PING)) |
311 | return; | 323 | return; |
312 | 324 | ||
313 | ping->last_toping = unix_time(); | 325 | ping->last_to_ping = unix_time(); |
314 | uint32_t i; | 326 | uint32_t i; |
315 | 327 | ||
316 | for (i = 0; i < MAX_TOPING; ++i) { | 328 | for (i = 0; i < MAX_TO_PING; ++i) { |
317 | if (!ip_isset(&ping->toping[i].ip_port.ip)) | 329 | if (!ip_isset(&ping->to_ping[i].ip_port.ip)) |
318 | return; | 330 | return; |
319 | 331 | ||
320 | send_ping_request(ping, ping->toping[i].ip_port, ping->toping[i].client_id); | 332 | send_ping_request(ping, ping->to_ping[i].ip_port, ping->to_ping[i].client_id); |
321 | ip_reset(&ping->toping[i].ip_port.ip); | 333 | ip_reset(&ping->to_ping[i].ip_port.ip); |
322 | } | 334 | } |
323 | } | 335 | } |
324 | 336 | ||
diff --git a/toxcore/ping.h b/toxcore/ping.h index a0008f3c..168870d7 100644 --- a/toxcore/ping.h +++ b/toxcore/ping.h | |||
@@ -26,7 +26,7 @@ | |||
26 | 26 | ||
27 | typedef struct PING PING; | 27 | typedef struct PING PING; |
28 | 28 | ||
29 | /* Add nodes to the toping list. | 29 | /* Add nodes to the to_ping list. |
30 | * All nodes in this list are pinged every TIME_TOPING seconds | 30 | * All nodes in this list are pinged every TIME_TOPING seconds |
31 | * and are then removed from the list. | 31 | * and are then removed from the list. |
32 | * If the list is full the nodes farthest from our client_id are replaced. | 32 | * If the list is full the nodes farthest from our client_id are replaced. |
@@ -36,8 +36,8 @@ typedef struct PING PING; | |||
36 | * return 0 if node was added. | 36 | * return 0 if node was added. |
37 | * return -1 if node was not added. | 37 | * return -1 if node was not added. |
38 | */ | 38 | */ |
39 | int add_toping(PING *ping, uint8_t *client_id, IP_Port ip_port); | 39 | int add_to_ping(PING *ping, uint8_t *client_id, IP_Port ip_port); |
40 | void do_toping(PING *ping); | 40 | void do_to_ping(PING *ping); |
41 | 41 | ||
42 | PING *new_ping(DHT *dht); | 42 | PING *new_ping(DHT *dht); |
43 | void kill_ping(PING *ping); | 43 | void kill_ping(PING *ping); |
diff --git a/toxcore/tox.c b/toxcore/tox.c index 9a5be0ad..a928f3f9 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c | |||
@@ -290,6 +290,15 @@ uint8_t tox_get_self_user_status(Tox *tox) | |||
290 | return m_get_self_userstatus(m); | 290 | return m_get_self_userstatus(m); |
291 | } | 291 | } |
292 | 292 | ||
293 | /* returns timestamp of last time friendnumber was seen online, or 0 if never seen. | ||
294 | * returns -1 on error. | ||
295 | */ | ||
296 | uint64_t tox_get_last_online(Tox *tox, int32_t friendnumber) | ||
297 | { | ||
298 | Messenger *m = tox; | ||
299 | return m_get_last_online(m, friendnumber); | ||
300 | } | ||
301 | |||
293 | /* Set our typing status for a friend. | 302 | /* Set our typing status for a friend. |
294 | * You are responsible for turning it on or off. | 303 | * You are responsible for turning it on or off. |
295 | * | 304 | * |
@@ -313,7 +322,6 @@ int tox_get_is_typing(Tox *tox, int32_t friendnumber) | |||
313 | return m_get_istyping(m, friendnumber); | 322 | return m_get_istyping(m, friendnumber); |
314 | } | 323 | } |
315 | 324 | ||
316 | |||
317 | /* Sets whether we send read receipts for friendnumber. | 325 | /* Sets whether we send read receipts for friendnumber. |
318 | * This function is not lazy, and it will fail if yesno is not (0 or 1). | 326 | * This function is not lazy, and it will fail if yesno is not (0 or 1). |
319 | */ | 327 | */ |
diff --git a/toxcore/tox.h b/toxcore/tox.h index 41f868dd..256c701a 100644 --- a/toxcore/tox.h +++ b/toxcore/tox.h | |||
@@ -261,6 +261,12 @@ int tox_get_self_status_message(Tox *tox, uint8_t *buf, uint32_t maxlen); | |||
261 | uint8_t tox_get_user_status(Tox *tox, int32_t friendnumber); | 261 | uint8_t tox_get_user_status(Tox *tox, int32_t friendnumber); |
262 | uint8_t tox_get_self_user_status(Tox *tox); | 262 | uint8_t tox_get_self_user_status(Tox *tox); |
263 | 263 | ||
264 | |||
265 | /* returns timestamp of last time friendnumber was seen online, or 0 if never seen. | ||
266 | * returns -1 on error. | ||
267 | */ | ||
268 | uint64_t tox_get_last_online(Tox *tox, int32_t friendnumber); | ||
269 | |||
264 | /* Set our typing status for a friend. | 270 | /* Set our typing status for a friend. |
265 | * You are responsible for turning it on or off. | 271 | * You are responsible for turning it on or off. |
266 | * | 272 | * |
@@ -747,4 +753,3 @@ int tox_load_encrypted(Tox *tox, uint8_t *data, uint32_t length, uint8_t *key, u | |||
747 | #endif | 753 | #endif |
748 | 754 | ||
749 | #endif | 755 | #endif |
750 | |||