summaryrefslogtreecommitdiff
path: root/toxcore
diff options
context:
space:
mode:
Diffstat (limited to 'toxcore')
-rw-r--r--toxcore/DHT.c153
-rw-r--r--toxcore/DHT.h40
-rw-r--r--toxcore/Lossless_UDP.c3
-rw-r--r--toxcore/Messenger.c244
-rw-r--r--toxcore/Messenger.h6
-rw-r--r--toxcore/TCP_server.c494
-rw-r--r--toxcore/TCP_server.h75
-rw-r--r--toxcore/net_crypto.c10
-rw-r--r--toxcore/net_crypto.h3
-rw-r--r--toxcore/network.c14
-rw-r--r--toxcore/network.h6
-rw-r--r--toxcore/onion.c103
-rw-r--r--toxcore/onion.h33
-rw-r--r--toxcore/onion_announce.c56
-rw-r--r--toxcore/onion_announce.h19
-rw-r--r--toxcore/onion_client.c188
-rw-r--r--toxcore/onion_client.h54
-rw-r--r--toxcore/ping.c124
-rw-r--r--toxcore/ping.h6
-rw-r--r--toxcore/tox.c10
-rw-r--r--toxcore/tox.h7
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. */
60typedef struct { 63typedef 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 */
123void 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 */
169void 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 */
177void 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 */
844static int sendnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *client_id, uint8_t *encrypted_data) 914static 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 */
930static int sendnodes_ipv6(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *client_id, uint8_t *encrypted_data) 1000static 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 */
1313static uint8_t do_ping_and_sendnode_requests(DHT *dht, uint64_t *lastgetnode, uint8_t *client_id, 1385static 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)
1373static void do_Close(DHT *dht) 1446static 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 */
1977static int handle_hardening(void *object, IP_Port source, uint8_t *source_pubkey, uint8_t *packet, uint32_t length) 2050static 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
146typedef 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
146typedef struct { 158typedef 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 */
192void 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 */
197void 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 */
202void DHT_get_shared_key_sent(DHT *dht, uint8_t *shared_key, uint8_t *client_id);
203
170void DHT_getnodes(DHT *dht, IP_Port *from_ipp, uint8_t *from_id, uint8_t *which_id); 204void 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
638uint64_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
638int m_set_usertyping(Messenger *m, int32_t friendnumber, uint8_t is_typing) 646int 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
1689int send_custom_user_packet(Messenger *m, int32_t friendnumber, uint8_t *data, uint32_t length) 1698int 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
2399struct 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. */
2415struct 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
2428static uint32_t saved_friendslist_size(Messenger *m)
2429{
2430 return count_friendlist(m) * sizeof(struct SAVED_FRIEND);
2431}
2432
2433static 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
2470static 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) */
2378uint32_t messenger_size(Messenger *m) 2518uint32_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(). */
2399void messenger_save(Messenger *m, uint8_t *data) 2542void 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
2439static int messenger_load_state_callback(void *outer, uint8_t *data, uint32_t length, uint16_t type) 2594static 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
2662static 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. */
2508int messenger_load(Messenger *m, uint8_t *data, uint32_t length) 2723int 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);
414uint8_t m_get_userstatus(Messenger *m, int32_t friendnumber); 414uint8_t m_get_userstatus(Messenger *m, int32_t friendnumber);
415uint8_t m_get_self_userstatus(Messenger *m); 415uint8_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 */
420uint64_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);
786uint32_t copy_chatlist(Messenger *m, int *out_list, uint32_t list_size); 791uint32_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 */
32static 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
47static 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 */
59static 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 */
72static 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 */
88static 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 */
116static 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 */
150static 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 */
178static 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 */
217static 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 */
246static 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 */
255static 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 */
299static 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
312static 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 */
321static 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
345static 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
369TCP_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
411static 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
426static 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
453static 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}
478void do_TCP_server(TCP_Server *TCP_server)
479{
480 do_TCP_accept_new(TCP_server);
481 do_TCP_incomming(TCP_server);
482}
483
484void 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
35enum {
36 TCP_STATUS_NO_STATUS,
37 TCP_STATUS_CONNECTED,
38 TCP_STATUS_UNCONFIRMED,
39 TCP_STATUS_CONFIRMED,
40};
41
42typedef 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
52typedef 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 */
66TCP_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 */
71void do_TCP_server(TCP_Server *TCP_server);
72
73/* Kill the TCP server
74 */
75void 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. */
162static void increment_nonce(uint8_t *nonce) 162void 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 */
133int decrypt_data_symmetric(uint8_t *secret_key, uint8_t *nonce, uint8_t *encrypted, uint32_t length, uint8_t *plain); 133int 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. */
136void increment_nonce(uint8_t *nonce);
137
135/* Fill the given nonce with random bytes. */ 138/* Fill the given nonce with random bytes. */
136void random_nonce(uint8_t *nonce); 139void 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
45static const char *inet_ntop(sa_family_t family, void *addr, char *buf, size_t bufsize) 41static 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
47typedef unsigned int sock_t; 51typedef 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 */
49typedef short sa_family_t; 53typedef 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 */
59int 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 */
58int send_onion_packet(DHT *dht, Node_format *nodes, uint8_t *data, uint32_t length) 96int 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
48typedef 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 */
71int 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 */
53int send_onion_packet(DHT *dht, Node_format *nodes, uint8_t *data, uint32_t length); 80int 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 */
53int send_announce_request(DHT *dht, Node_format *nodes, uint8_t *public_key, uint8_t *secret_key, uint8_t *ping_id, 52int 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 */
91int send_data_request(DHT *dht, Node_format *nodes, uint8_t *public_key, uint8_t *encrypt_public_key, uint8_t *nonce, 90int 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 */
74int send_announce_request(DHT *dht, Node_format *nodes, uint8_t *public_key, uint8_t *secret_key, uint8_t *ping_id, 75int 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 */
91int send_data_request(DHT *dht, Node_format *nodes, uint8_t *public_key, uint8_t *encrypt_public_key, uint8_t *nonce, 92int 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
95Onion_Announce *new_onion_announce(DHT *dht); 96Onion_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 */
42static 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 */
68static 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
101static int client_send_announce_request(Onion_Client *onion_c, uint32_t num, IP_Port dest, uint8_t *dest_pubkey, 160static 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
165static int client_add_to_list(Onion_Client *onion_c, uint32_t num, uint8_t *public_key, IP_Port ip_port, 228static 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
294static 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
230static int client_ping_nodes(Onion_Client *onion_c, uint32_t num, Node_format *nodes, uint16_t num_nodes, 310static 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 */
744int 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
754static void do_friend(Onion_Client *onion_c, uint16_t friendnum) 841static 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
830static void do_announce(Onion_Client *onion_c) 917static 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
36typedef struct { 53typedef 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
48typedef struct { 67typedef 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
73typedef struct {
74 uint8_t client_id[CLIENT_ID_SIZE];
75 uint64_t timestamp;
76} Last_Pinged;
77
78typedef 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
68typedef int (*oniondata_handler_callback)(void *object, uint8_t *source_pubkey, uint8_t *data, uint32_t len); 104typedef 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 */
128int onion_getfriendip(Onion_Client *onion_c, int friend_num, IP_Port *ip_port); 171int 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 */
138int 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
43typedef struct { 46typedef 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
49struct PING { 53struct 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
60static int is_ping_timeout(uint64_t time) 64static 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
89static uint64_t add_ping(PING *ping, IP_Port ipp) // O(n) 93static 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
174static int send_ping_response(PING *ping, IP_Port ipp, uint8_t *client_id, uint64_t ping_id) 182static 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 */
278int add_toping(PING *ping, uint8_t *client_id, IP_Port ip_port) 290int 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 */
308void do_toping(PING *ping) 320void 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
27typedef struct PING PING; 27typedef 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 */
39int add_toping(PING *ping, uint8_t *client_id, IP_Port ip_port); 39int add_to_ping(PING *ping, uint8_t *client_id, IP_Port ip_port);
40void do_toping(PING *ping); 40void do_to_ping(PING *ping);
41 41
42PING *new_ping(DHT *dht); 42PING *new_ping(DHT *dht);
43void kill_ping(PING *ping); 43void 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 */
296uint64_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);
261uint8_t tox_get_user_status(Tox *tox, int32_t friendnumber); 261uint8_t tox_get_user_status(Tox *tox, int32_t friendnumber);
262uint8_t tox_get_self_user_status(Tox *tox); 262uint8_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 */
268uint64_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