1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
It has come to our attention that to achieve decent market penetration Tox
must work behind ALL internet connections, may they be behind enterprise NATs
or any other bad network conditions.
The people who have issues with the UDP direct connection approach seem to be a
small minority though it is hard to estimate how many.
This means that routing their packets using good nodes on the network will
probably not take a huge toll on the network and will assure that people
can use Tox regardless of the quality of their internet connection.
How it's going to work:
1. Alice, a Tox client on a TCP only network generates a temporary public key
and connects to a bootstrap node.
2. Using the bootstrap node she finds and connects to a couple (exact number
to be determined later) number of random nodes that have TCP relay support.
3. She uses the onion through the TCP relay connections to send friend requests
or tell online friends which TCP nodes she is connected to and her temporary
public key.
4. Bob receives an onion packet from Alice telling him which nodes she is
connected to. Bob connects to these nodes and establishes a routed connection
with Alice using that temporary public key.
5. That connection is used by both to transmit encrypted Messenger and A/V
packets.
6. If one of the nodes shuts down while it is currently routing traffic, Alice
and bob just switch to one of the other nodes they are both connected to.
Detailed implementation details:
There are two distinct parts for TCP relays, the client part and the server
part.
The server acts as the actual relay. Servers must have fully forwarded TCP
ports (NAT-PMP and uPNP can help here). The first port the server will try
binding to is 443 followed by port 3389 and possibly some others. Onion packets
can be sent/received through the TCP servers.
Server:
The public/private key pair the TCP server uses is the same one he uses for the
DHT.
all crypto for communication with the server uses the crypto_box() function of
NaCl.
TCP doesn't have packets so what we will refer to as packets are sent this way:
[[uint16_t (length of data)][data]]
So if you would inspect the TCP stream you would see:
[[uint16_t (length of data)][data]][[uint16_t (length of
data)][data]][[uint16_t (length of data)][data]]
Note that both handshake packets don't have this format (the length for them is
always the same so we don't need to specify it.)
When the client connects to the server, he sends this packet:
[public key of client (32 bytes)][nonce for the encrypted data [24
bytes]][encrypted with the private key of the client and public key of the
server and the nonce:[public key (32 bytes) and][base nonce we want the server
to use to encrypt the packets sent to us (24 bytes)]]
The server responds with:
[nonce for the encrypted data [24 bytes]][encrypted with the public key of the
client and private key of the server and the nonce:[public key (32 bytes)
and][base nonce we want the client to use to encrypt the packets sent to us (24
bytes)]]
All packets to the server are end to end encrypted with the information
received
(and sent) in the handshake.
(first packet is encrypted with the base nonce the private key for which the
client sent the server the public key and the public key we sent to the client,
the next with base nonce + 1...)
The connection is set to an unconfirmed state until a packet is received and
decrypted correctly using the information in the handshake.
each packet sent to/from the server has an id (the first byte of the plain text
data of the packet.)
ids 0 to 15 are reserved for special packets, ids 16 to 255 are used to denote
who we want the data to be routed to/who the packet is from.
special ids and packets:
0 - Routing request.
[uint8_t id (0)][public key (32 bytes)]
1 - Routing request response.
[uint8_t id (1)][uint8_t (rpid) 0 if refused, packet id if accepted][public key
(32 bytes)]
2 - Connect notification:
[uint8_t id (2)][uint8_t (packet id of connection that got connected)]
3 - Disconnect notification:
[uint8_t id (3)][uint8_t (packet id of connection that got disconnected)]
4 - ping packet
[uint8_t id (4)][uint64_t ping_id (0 is invalid)]
5 - ping response (pong)
[uint8_t id (5)][uint64_t ping_id (0 is invalid)]
6 - OOB send
[uint8_t id (6)][destination public key (32 bytes)][data]
7 - OOB recv
[uint8_t id (7)][senders public key (32 bytes)][data]
8 - onion packet (same format as initial onion packet (See: Prevent
tracking.txt) but packet id is 8 instead of 128)
9 - onion packet response (same format as onion packet with id 142 but id is 9
instead.)
The rest of the special ids are reserved for possible future usage.
If the server receives a routing request he stores server side that the client
wants to connect to the person with that public key and sends back a Routing
request response with the rpid along with the public key sent in the request.
If for some reason the server must refuse the routing request (too many) he
sends the response with a rpid of 0.
If the person who the client wants to connect to is also online and wants to
connect to the client a connect notification is sent to both with the
appropriate packet id.
If either one disconnects, a disconnect notification is sent to the other with
appropriate packet id.
If a client sends a disconnect notification, the entry on the server for that
routed connection is cleared and a disconnect notification is sent to the peer
(if he was online)
If the server receives an onion packet he handles it the same as he would if it
was one received normally via UDP, he must also assure himself that any
responses must be sent to the proper client.
Ping responses must have the same ping_id as the request.
If the server receives a ping packet he must respond with a ping response.
The server will send a ping packet to clients every 30 seconds, they have 30
seconds to respond, if they don't the connection is deleted.
OOB send packets will be sent to the peer connected to the TCP server with the
destination public key as a OOB recv packet. The client sending this packet has
no way of knowing if the packet reached its destination.
Client:
Implementation details coming soon.
|