1SYNCTHING-RELAY(7) Syncthing SYNCTHING-RELAY(7)
2
3
4
6 syncthing-relay - Relay Protocol v1
7
9 Relay is a service which relays data between two devices which are not
10 able to connect to each other directly otherwise. This is usually due
11 to both devices being behind a NAT and neither side being able to open
12 a port which would be directly accessible from the internet.
13
14 A relay was designed to relay BEP protocol, hence the reliance on
15 device ID’s in the protocol spec, but at the same time it is general
16 enough that could be reused by other protocols or applications, as the
17 data transferred between two devices which use a relay is completely
18 obscure and does not affect the relaying.
19
21 Relay listens on a single TCP socket, but has two different connection
22 modes, where a connection mode is a predefined set of messages which
23 the relay and the device are expecting to exchange.
24
25 The first mode is the protocol mode which allows a client to interact
26 with the relay, for example join the relay, or request to connect to a
27 device, given it is available on the relay. Similarly to BEP, protocol
28 mode requires the device to connect via TLS using a strong suite of
29 ciphers (same as BEP), which allows the relay to verify and derive the
30 identity (Device ID) of the device.
31
32 The second mode is the session mode which after a few initial messages
33 connects two devices directly to each other via the relay, and is a
34 plain-text protocol, which for every byte written by one device, sends
35 the same set of bytes to the other device and vica versa.
36
38 Because both connection modes operate over the same single socket, a
39 method of detecting the connection mode is required.
40
41 When a new client connects to the relay, the relay checks the first
42 byte that the client has sent, and if that matches 0x16, that implies
43 to us that the connection is a protocol mode connection, due to 0x16
44 being the first byte in the TLS handshake, and only protocol mode con‐
45 nections use TLS.
46
47 If the first byte is not 0x16, then we assume that the connection is a
48 session mode connection.
49
51 Protocol mode uses TLS and protocol name defined by the TLS header
52 should be bep-relay.
53
54 Protocol mode has two submodes: 1. Permanent protocol submode - Joining
55 the relay, and waiting for messages from the relay asking to connect to
56 some device which is interested in having a session with you. 2. Tem‐
57 porary protocol submode - Only used to request a session with a device
58 which is connected to the relay using the permanent protocol submode.
59
60 Permanent protocol submode
61 A permanent protocol submode begins with the client sending a JoinRe‐
62 layRequest message, which the relay responds to with either a Respons‐
63 eSuccess or ResponseAlreadyConnected message if a client with the same
64 device ID already exists.
65
66 After the client has joined, no more messages are exchanged apart from
67 Ping/Pong messages for general connection keep alive checking.
68
69 From this point onwards, the client stand-by’s and waits for SessionIn‐
70 vitation messages from the relay, which implies that some other device
71 is trying to connect with you. SessionInvitation message contains the
72 unique session key which then can be used to establish a connection in
73 session mode.
74
75 If the client fails to send a JoinRelayRequest message within the first
76 ping interval, the connection is terminated. If the client fails to
77 send a message (even if it’s a ping message) every minute (by default),
78 the connection is terminated.
79
80 Temporary protocol submode
81 A temporary protocol submode begins with ConnectRequest message, to
82 which the relay responds with either ResponseNotFound if the device the
83 client it is after is not available, or with a SessionInvitation, which
84 contains the unique session key which then can be used to establish a
85 connection in session mode.
86
87 The connection is terminated immediately after that.
88
89 Example Exchange
90 Client A - Permanent protocol submode Client B - Temporary protocol
91 submode
92
93 ┌───┬──────────────┬──────────────────┬───────────────┐
94 │# │ Client (A) │ Relay │ Client (B) │
95 ├───┼──────────────┼──────────────────┼───────────────┤
96 │1 │ JoinRelayRe‐ │ │ │
97 │ │ quest-> │ │ │
98 ├───┼──────────────┼──────────────────┼───────────────┤
99 │2 │ │ <-ResponseSuc‐ │ │
100 │ │ │ cess │ │
101 ├───┼──────────────┼──────────────────┼───────────────┤
102 │3 │ Ping-> │ │ │
103 ├───┼──────────────┼──────────────────┼───────────────┤
104 │4 │ │ <-Pong │ │
105 ├───┼──────────────┼──────────────────┼───────────────┤
106 │5 │ │ │ <-ConnectRe‐ │
107 │ │ │ │ quest(A) │
108 ├───┼──────────────┼──────────────────┼───────────────┤
109 │6 │ │ SessionInvita‐ │ │
110 │ │ │ tion(A)-> │ │
111 ├───┼──────────────┼──────────────────┼───────────────┤
112 │7 │ │ <-SessionInvita‐ │ │
113 │ │ │ tion(B) │ │
114 ├───┼──────────────┼──────────────────┼───────────────┤
115 │8 │ │ │ (Disconnects) │
116 ├───┼──────────────┼──────────────────┼───────────────┤
117 │9 │ Ping-> │ │ │
118 ├───┼──────────────┼──────────────────┼───────────────┤
119 │10 │ │ <-Pong │ │
120 ├───┼──────────────┼──────────────────┼───────────────┤
121 │11 │ Ping-> │ │ │
122 ├───┼──────────────┼──────────────────┼───────────────┤
123 │12 │ │ <-Pong │ │
124 └───┴──────────────┴──────────────────┴───────────────┘
125
127 The first and only message the client sends in the session mode is the
128 JoinSessionRequest message which contains the session key identifying
129 which session you are trying to join. The relay responds with one of
130 the following Response messages:
131
132 1. ResponseNotFound - Session key is invalid
133
134 2. ResponseAlreadyConnected - Session is full (both sides already con‐
135 nected)
136
137 3. ResponseSuccess - You have successfully joined the session
138
139 After the successful response, all the bytes written and received will
140 be relayed between the two devices in the session directly.
141
142 Example Exchange
143 Client A - Permanent protocol mode Client B - Temporary protocol mode
144
145 ┌──┬────────────────┬────────────────┬──────────────────┐
146 │# │ Client (A) │ Relay │ Client (B) │
147 ├──┼────────────────┼────────────────┼──────────────────┤
148 │1 │ JoinSessionRe‐ │ │ │
149 │ │ quest(A)-> │ │ │
150 ├──┼────────────────┼────────────────┼──────────────────┤
151 │2 │ │ <-ResponseSuc‐ │ │
152 │ │ │ cess │ │
153 ├──┼────────────────┼────────────────┼──────────────────┤
154 │3 │ Data-> │ (Buffers data) │ │
155 ├──┼────────────────┼────────────────┼──────────────────┤
156 │4 │ Data-> │ (Buffers data) │ │
157 ├──┼────────────────┼────────────────┼──────────────────┤
158 │5 │ │ │ <-JoinSessionRe‐ │
159 │ │ │ │ quest(B) │
160 ├──┼────────────────┼────────────────┼──────────────────┤
161 │6 │ │ ResponseSuc‐ │ │
162 │ │ │ cess-> │ │
163 ├──┼────────────────┼────────────────┼──────────────────┤
164 │7 │ │ Relays data -> │ │
165 ├──┼────────────────┼────────────────┼──────────────────┤
166 │8 │ │ Relays data -> │ │
167 ├──┼────────────────┼────────────────┼──────────────────┤
168 │9 │ │ <-Relays data │ <-Data │
169 └──┴────────────────┴────────────────┴──────────────────┘
170
172 All messages are preceded by a header message. Header message contains
173 the magic value 0x9E79BC40, message type integer, and message length.
174
175 WARNING:
176 Some messages have no content, apart from the implied header which
177 allows us to identify what type of message it is.
178
179 Header structure
180 0 1 2 3
181 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
182 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
183 | Magic |
184 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
185 | Message Type |
186 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
187 | Message Length |
188 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
189
190
191 struct Header {
192 unsigned int Magic;
193 int MessageType;
194 int MessageLength;
195 }
196
197 Ping message (Type = 0)
198 0 1 2 3
199 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
200 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
201
202
203 struct Ping {
204 }
205
206 Pong message (Type = 1)
207 0 1 2 3
208 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
209 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
210
211
212 struct Pong {
213 }
214
215 JoinRelayRequest message (Type = 2)
216 0 1 2 3
217 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
218 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
219
220
221 struct JoinRelayRequest {
222 }
223
224 JoinSessionRequest message (Type = 3)
225 0 1 2 3
226 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
227 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
228 | Length of Key |
229 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
230 / /
231 \ Key (variable length) \
232 / /
233 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
234
235
236 struct JoinSessionRequest {
237 opaque Key<32>;
238 }
239
240 : Key This is a unique random session key generated by the relay
241 server. It is used to identify which session you are trying to
242 connect to.
243
244 Response message (Type = 4)
245 0 1 2 3
246 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
247 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
248 | Code |
249 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
250 | Length of Message |
251 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
252 / /
253 \ Message (variable length) \
254 / /
255 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
256
257
258 struct Response {
259 int Code;
260 string Message<>;
261 }
262
263 : Code An integer representing the status code.
264
265 : Message
266 Message associated with the code.
267
268 ConnectRequest message (Type = 5)
269 0 1 2 3
270 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
271 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
272 | Length of ID |
273 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
274 / /
275 \ ID (variable length) \
276 / /
277 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
278
279
280 struct ConnectRequest {
281 opaque ID<32>;
282 }
283
284 : ID Device ID to which the client would like to connect.
285
286 SessionInvitation message (Type = 6)
287 0 1 2 3
288 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
289 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
290 | Length of From |
291 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
292 / /
293 \ From (variable length) \
294 / /
295 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
296 | Length of Key |
297 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
298 / /
299 \ Key (variable length) \
300 / /
301 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
302 | Length of Address |
303 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
304 / /
305 \ Address (variable length) \
306 / /
307 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
308 | 0x0000 | Port |
309 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
310 | Server Socket (V=0 or 1) |V|
311 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
312
313
314 struct SessionInvitation {
315 opaque From<32>;
316 opaque Key<32>;
317 opaque Address<32>;
318 unsigned int Port;
319 bool ServerSocket;
320 }
321
322 : From Device ID identifying who you will be connecting with.
323
324 : Key A unique random session key generated by the relay server. It is
325 used to identify which session you are trying to connect to.
326
327 : Address
328 An optional IP address on which the relay server is expecting
329 you to connect, in order to start a connection in session mode.
330 Empty/all zero IP should be replaced with the relay’s public IP
331 address that was used when establishing the protocol mode con‐
332 nection.
333
334 : Port The port on which the relay server is expecting you to connect,
335 in order to start a connection in session mode.
336
337 : Server Socket
338 Because both sides connecting to the relay use the client side
339 of the socket, and some protocols behave differently depending
340 if the connection starts on the server side or the client side,
341 this boolean indicates which side of the connection this client
342 should assume it’s getting. The value is inverted in the invita‐
343 tion which is sent to the other device, so that there is always
344 one client socket, and one server socket.
345
347 In the case of Syncthing and BEP, when two devices connect via relay,
348 they start their standard TLS connection encapsulated within the
349 relay’s plain-text session connection, effectively upgrading the
350 plain-text connection to a TLS connection.
351
352 Even though the relay could be used for man-in-the-middle attack, using
353 TLS at the application/BEP level ensures that all the traffic is safely
354 encrypted, and is completely meaningless to the relay. Furthermore, the
355 secure suite of ciphers used by BEP provides forward secrecy, meaning
356 that even if the relay did capture all the traffic, and even if the
357 attacker did get their hands on the device keys, they would still not
358 be able to recover/decrypt any traffic which was transported via the
359 relay.
360
361 After establishing a relay session, Syncthing looks at the SessionInvi‐
362 tation message, and depending which side it has received, wraps the raw
363 socket in either a TLS client socket or a TLS server socket depending
364 on the ServerSocket boolean value in the SessionInvitation, and starts
365 the TLS handshake.
366
367 From that point onwards it functions exactly the same way as if Sync‐
368 thing was establishing a direct connection with the other device over
369 the internet, performing device ID validation, and full TLS encryption,
370 and provides the same security properties as it would provide when con‐
371 necting over the internet.
372
374 ┌───────┬─────────────────────────────┬─────────────────────┐
375 │ID │ Name │ Description │
376 ├───────┼─────────────────────────────┼─────────────────────┤
377 │0x009F │ DHE-RSA-AES256-GCM-SHA384 │ TLSv1.2 DH RSA AES‐ │
378 │ │ │ GCM(256) AEAD │
379 ├───────┼─────────────────────────────┼─────────────────────┤
380 │0x006B │ DHE-RSA-AES256-SHA256 │ TLSv1.2 DH RSA │
381 │ │ │ AES(256) SHA256 │
382 ├───────┼─────────────────────────────┼─────────────────────┤
383 │0xC030 │ ECDHE-RSA-AES256-GCM-SHA384 │ TLSv1.2 ECDH RSA │
384 │ │ │ AESGCM(256) AEAD │
385 ├───────┼─────────────────────────────┼─────────────────────┤
386 │0xC028 │ ECDHE-RSA-AES256-SHA384 │ TLSv1.2 ECDH RSA │
387 │ │ │ AES(256) SHA384 │
388 ├───────┼─────────────────────────────┼─────────────────────┤
389 │0x009E │ DHE-RSA-AES128-GCM-SHA256 │ TLSv1.2 DH RSA AES‐ │
390 │ │ │ GCM(128) AEAD │
391 ├───────┼─────────────────────────────┼─────────────────────┤
392 │0x0067 │ DHE-RSA-AES128-SHA256 │ TLSv1.2 DH RSA │
393 │ │ │ AES(128) SHA256 │
394 ├───────┼─────────────────────────────┼─────────────────────┤
395 │0xC02F │ ECDHE-RSA-AES128-GCM-SHA256 │ TLSv1.2 ECDH RSA │
396 │ │ │ AESGCM(128) AEAD │
397 ├───────┼─────────────────────────────┼─────────────────────┤
398 │0xC027 │ ECDHE-RSA-AES128-SHA256 │ TLSv1.2 ECDH RSA │
399 │ │ │ AES(128) SHA256 │
400 └───────┴─────────────────────────────┴─────────────────────┘
401
403 The Syncthing Authors
404
406 2014-2019, The Syncthing Authors
407
408
409
410
411v1 Feb 17, 2021 SYNCTHING-RELAY(7)