Skip to content

Commit 8d4a375

Browse files
committed
implement forwarding protocol
1 parent 33bcbb7 commit 8d4a375

22 files changed

+1071
-5
lines changed

CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,9 @@ set(toxcore_SOURCES ${toxcore_SOURCES}
208208
toxcore/onion_announce.c
209209
toxcore/onion_announce.h
210210
toxcore/onion_client.c
211-
toxcore/onion_client.h)
211+
toxcore/onion_client.h
212+
toxcore/forwarding.c
213+
toxcore/forwarding.h)
212214

213215
# LAYER 5: Friend requests and connections
214216
# ----------------------------------------
@@ -407,6 +409,7 @@ auto_test(dht MSVC_DONT_BUILD)
407409
auto_test(encryptsave)
408410
auto_test(file_transfer)
409411
auto_test(file_saving)
412+
auto_test(forwarding)
410413
auto_test(friend_connection)
411414
auto_test(friend_request)
412415
auto_test(invalid_tcp_proxy)

auto_tests/Makefile.inc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ TESTS = \
1212
encryptsave_test \
1313
file_saving_test \
1414
file_transfer_test \
15+
forwarding_test \
1516
friend_connection_test \
1617
friend_request_test \
1718
invalid_tcp_proxy_test \
@@ -107,6 +108,10 @@ file_transfer_test_SOURCES = ../auto_tests/file_transfer_test.c
107108
file_transfer_test_CFLAGS = $(AUTOTEST_CFLAGS)
108109
file_transfer_test_LDADD = $(AUTOTEST_LDADD)
109110

111+
forwarding_test_SOURCES = ../auto_tests/forwarding_test.c
112+
forwarding_test_CFLAGS = $(AUTOTEST_CFLAGS)
113+
forwarding_test_LDADD = $(AUTOTEST_LDADD)
114+
110115
friend_connection_test_SOURCES = ../auto_tests/friend_connection_test.c
111116
friend_connection_test_CFLAGS = $(AUTOTEST_CFLAGS)
112117
friend_connection_test_LDADD = $(AUTOTEST_LDADD)

auto_tests/forwarding_test.c

Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
/*
2+
* Copyright © 2019 The TokTok team.
3+
*
4+
* This file is part of Tox, the free peer to peer instant messenger.
5+
*
6+
* Tox is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* Tox is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
#ifdef HAVE_CONFIG_H
21+
#include "config.h"
22+
#endif
23+
24+
#include <assert.h>
25+
#include <stdlib.h>
26+
#include <string.h>
27+
28+
#include "../toxcore/tox.h"
29+
#include "../testing/misc_tools.h"
30+
#include "../toxcore/mono_time.h"
31+
#include "../toxcore/forwarding.h"
32+
#include "../toxcore/net_crypto.h"
33+
#include "../toxcore/util.h"
34+
#include "check_compat.h"
35+
36+
#ifndef USE_IPV6
37+
#define USE_IPV6 1
38+
#endif
39+
40+
static inline IP get_loopback(void)
41+
{
42+
IP ip;
43+
#if USE_IPV6
44+
ip.family = net_family_ipv6;
45+
ip.ip.v6 = get_ip6_loopback();
46+
#else
47+
ip.family = net_family_ipv4;
48+
ip.ip.v4 = get_ip4_loopback();
49+
#endif
50+
return ip;
51+
}
52+
53+
#define NUM_FORWARDER 16
54+
#define NUM_FORWARDER_TCP 4
55+
#define NUM_FORWARDER_DHT (NUM_FORWARDER - NUM_FORWARDER_TCP)
56+
#define NUM_FORWARDING_ITERATIONS 1
57+
#define FORWARD_SEND_INTERVAL 1
58+
#define FORWARDER_TCP_RELAY_PORT 36570
59+
#define FORWARDING_BASE_PORT 36571
60+
61+
typedef struct Test_Data {
62+
Networking_Core *net;
63+
uint32_t send_back;
64+
uint64_t sent;
65+
bool returned;
66+
} Test_Data;
67+
68+
static void test_forwarded_cb(void *object, IP_Port forwarder,
69+
const uint8_t *sendback, uint16_t sendback_length,
70+
const uint8_t *data, uint16_t length, void *userdata)
71+
{
72+
Test_Data *test_data = (Test_Data *)object;
73+
uint8_t *index = (uint8_t *)userdata;
74+
75+
if (length == 12 && memcmp("hello: ", data, 8) == 0) {
76+
uint8_t reply[12];
77+
memcpy(reply, "reply: ", 8);
78+
memcpy(reply + 8, data + 8, 4);
79+
ck_assert_msg(forward_reply(test_data->net, forwarder, sendback, sendback_length, reply, 12),
80+
"[%u] forward_reply failed", *index);
81+
return;
82+
}
83+
84+
if (length == 12 && memcmp("reply: ", data, 8) == 0) {
85+
ck_assert_msg(sendback_length == 0, "sendback of positive length %d in reply", sendback_length);
86+
87+
if (memcmp(&test_data->send_back, data + 8, 4) == 0) {
88+
test_data->returned = true;
89+
}
90+
91+
return;
92+
}
93+
94+
printf("[%u] got unexpected data of length %d\n", *index, length);
95+
}
96+
97+
static void test_tcp_forwarded_cb(void *object, IP_Port forwarder,
98+
const uint8_t *data, uint16_t length, void *userdata)
99+
{
100+
test_forwarded_cb(object, forwarder, nullptr, 0, data, length, userdata);
101+
}
102+
103+
static bool all_returned(Test_Data *test_data)
104+
{
105+
for (uint32_t i = 0; i < NUM_FORWARDER; ++i) {
106+
if (!test_data[i].returned) {
107+
return false;
108+
}
109+
}
110+
111+
return true;
112+
}
113+
114+
static void test_forwarding(void)
115+
{
116+
assert(sizeof(char) == 1);
117+
118+
uint32_t index[NUM_FORWARDER];
119+
Logger *logs[NUM_FORWARDER];
120+
Mono_Time *mono_times[NUM_FORWARDER];
121+
Networking_Core *nets[NUM_FORWARDER];
122+
DHT *dhts[NUM_FORWARDER];
123+
Net_Crypto *cs[NUM_FORWARDER];
124+
Forwarding *forwardings[NUM_FORWARDER];
125+
126+
Test_Data test_data[NUM_FORWARDER];
127+
128+
IP ip = get_loopback();
129+
TCP_Proxy_Info inf = {{{{0}}}};
130+
131+
for (uint32_t i = 0; i < NUM_FORWARDER; ++i) {
132+
index[i] = i + 1;
133+
logs[i] = logger_new();
134+
logger_callback_log(logs[i], (logger_cb *)print_debug_log, nullptr, &index[i]);
135+
mono_times[i] = mono_time_new();
136+
137+
if (i < NUM_FORWARDER_TCP) {
138+
nets[i] = new_networking_no_udp(logs[i]);
139+
} else {
140+
nets[i] = new_networking(logs[i], ip, FORWARDING_BASE_PORT + i);
141+
}
142+
143+
dhts[i] = new_dht(logs[i], mono_times[i], nets[i], true);
144+
cs[i] = new_net_crypto(logs[i], mono_times[i], dhts[i], &inf);
145+
forwardings[i] = new_forwarding(mono_times[i], dhts[i]);
146+
ck_assert_msg((forwardings[i] != nullptr), "Forwarding failed initializing.");
147+
148+
test_data[i].net = nets[i];
149+
test_data[i].send_back = 0;
150+
test_data[i].sent = 0;
151+
test_data[i].returned = false;
152+
set_callback_forwarded(forwardings[i], test_forwarded_cb, &test_data[i]);
153+
set_forwarding_packet_tcp_connection_callback(nc_get_tcp_c(cs[i]), test_tcp_forwarded_cb, &test_data[i]);
154+
}
155+
156+
printf("testing forwarding via tcp relays and dht\n");
157+
158+
struct Tox_Options *opts = tox_options_new(nullptr);
159+
tox_options_set_tcp_port(opts, FORWARDER_TCP_RELAY_PORT);
160+
IP_Port relay_ipport_tcp = {ip, net_htons(FORWARDER_TCP_RELAY_PORT)};
161+
Tox *relay = tox_new_log(opts, nullptr, nullptr);
162+
tox_options_free(opts);
163+
ck_assert_msg(relay != nullptr, "Failed to create TCP relay");
164+
165+
uint8_t dpk[TOX_PUBLIC_KEY_SIZE];
166+
tox_self_get_dht_id(relay, dpk);
167+
168+
printf("1-%d connected only to TCP server; %d-%d connected only to DHT\n",
169+
NUM_FORWARDER_TCP, NUM_FORWARDER_TCP + 1, NUM_FORWARDER);
170+
171+
for (uint32_t i = 0; i < NUM_FORWARDER_TCP; ++i) {
172+
set_tcp_onion_status(nc_get_tcp_c(cs[i]), 1);
173+
ck_assert_msg(add_tcp_relay(cs[i], relay_ipport_tcp, dpk) == 0,
174+
"Failed to add TCP relay");
175+
};
176+
177+
IP_Port relay_ipport_udp = {ip, net_htons(tox_self_get_udp_port(relay, nullptr))};
178+
179+
for (uint32_t i = NUM_FORWARDER_TCP; i < NUM_FORWARDER; ++i) {
180+
dht_bootstrap(dhts[i], relay_ipport_udp, dpk);
181+
}
182+
183+
printf("allowing DHT to populate\n");
184+
uint16_t dht_establish_iterations = NUM_FORWARDER * 5;
185+
186+
for (uint32_t n = 0; n < NUM_FORWARDING_ITERATIONS; ++n) {
187+
for (uint32_t i = 0; i < NUM_FORWARDER; ++i) {
188+
test_data[i].sent = 0;
189+
test_data[i].returned = false;
190+
}
191+
192+
do {
193+
for (uint32_t i = 0; i < NUM_FORWARDER; ++i) {
194+
mono_time_update(mono_times[i]);
195+
networking_poll(nets[i], &index[i]);
196+
do_net_crypto(cs[i], &index[i]);
197+
do_dht(dhts[i]);
198+
199+
if (dht_establish_iterations ||
200+
test_data[i].returned ||
201+
!mono_time_is_timeout(mono_times[i], test_data[i].sent, FORWARD_SEND_INTERVAL)) {
202+
continue;
203+
}
204+
205+
const uint32_t dest_i = NUM_FORWARDER_TCP + (random_u32() % NUM_FORWARDER_DHT);
206+
const uint8_t *dest_pubkey = dht_get_self_public_key(dhts[dest_i]);
207+
208+
const uint32_t dht_forwarder_i = NUM_FORWARDER_TCP + (random_u32() % NUM_FORWARDER_DHT);
209+
const IP_Port dht_forwarder = {ip, net_htons(FORWARDING_BASE_PORT + dht_forwarder_i)};
210+
211+
const uint16_t length = 12;
212+
uint8_t data[12];
213+
214+
memcpy(data, "hello: ", 8);
215+
test_data[i].send_back = random_u32();
216+
*(uint32_t *)(data + 8) = test_data[i].send_back;
217+
218+
if (i < NUM_FORWARDER_TCP) {
219+
IP_Port tcp_forwarder;
220+
221+
if (!get_random_tcp_conn_ip_port(cs[i], &tcp_forwarder)) {
222+
continue;
223+
}
224+
225+
if (i % 2) {
226+
if (send_tcp_double_forward_request(cs[i], tcp_forwarder, dht_forwarder, dest_pubkey, data, length) == 0) {
227+
printf("%u --> TCPRelay --> %u --> %u\n", i + 1, dht_forwarder_i + 1, dest_i + 1);
228+
test_data[i].sent = mono_time_get(mono_times[i]);
229+
}
230+
} else {
231+
const IP_Port dest = {ip, net_htons(FORWARDING_BASE_PORT + dest_i)};
232+
233+
if (send_tcp_forward_request(cs[i], tcp_forwarder, dest, data, length) == 0) {
234+
printf("%u --> TCPRelay --> %u\n", i + 1, dest_i + 1);
235+
test_data[i].sent = mono_time_get(mono_times[i]);
236+
}
237+
}
238+
} else {
239+
if (request_forwarding(nets[i], dht_forwarder, dest_pubkey, data, length)) {
240+
printf("%u --> %u --> %u\n", i + 1, dht_forwarder_i + 1, dest_i + 1);
241+
test_data[i].sent = mono_time_get(mono_times[i]);
242+
}
243+
}
244+
}
245+
246+
tox_iterate(relay, nullptr);
247+
248+
if (dht_establish_iterations) {
249+
--dht_establish_iterations;
250+
251+
if (!dht_establish_iterations) {
252+
printf("making forward requests and expecting replies\n");
253+
}
254+
}
255+
256+
c_sleep(50);
257+
} while (!all_returned(test_data));
258+
}
259+
260+
261+
for (uint32_t i = 0; i < NUM_FORWARDER; ++i) {
262+
kill_forwarding(forwardings[i]);
263+
kill_net_crypto(cs[i]);
264+
kill_dht(dhts[i]);
265+
kill_networking(nets[i]);
266+
mono_time_free(mono_times[i]);
267+
logger_kill(logs[i]);
268+
}
269+
270+
tox_kill(relay);
271+
}
272+
273+
274+
int main(void)
275+
{
276+
setvbuf(stdout, nullptr, _IONBF, 0);
277+
278+
test_forwarding();
279+
280+
return 0;
281+
}

toxcore/BUILD.bazel

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,16 @@ cc_library(
187187
name = "onion",
188188
srcs = ["onion.c"],
189189
hdrs = ["onion.h"],
190+
deps = [
191+
":DHT",
192+
":forwarding",
193+
],
194+
)
195+
196+
cc_library(
197+
name = "forwarding",
198+
srcs = ["forwarding.c"],
199+
hdrs = ["forwarding.h"],
190200
deps = [":DHT"],
191201
)
192202

toxcore/DHT.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1872,6 +1872,7 @@ int dht_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enable
18721872

18731873
/* Send the given packet to node with public_key
18741874
*
1875+
* return number of bytes sent.
18751876
* return -1 if failure.
18761877
*/
18771878
int route_packet(const DHT *dht, const uint8_t *public_key, const uint8_t *packet, uint16_t length)

toxcore/Makefile.inc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ libtoxcore_la_SOURCES = ../toxcore/ccompat.h \
4848
../toxcore/onion_announce.c \
4949
../toxcore/onion_client.h \
5050
../toxcore/onion_client.c \
51+
../toxcore/forwarding.h \
52+
../toxcore/forwarding.c \
5153
../toxcore/TCP_client.h \
5254
../toxcore/TCP_client.c \
5355
../toxcore/TCP_server.h \

0 commit comments

Comments
 (0)