1SYNCTHING-RELAY(7)                 Syncthing                SYNCTHING-RELAY(7)
2
3
4

NAME

6       syncthing-relay - Relay Protocol v1
7

WHAT IS A RELAY?

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  de‐
15       vice  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

OPERATION MODES

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 ci‐
29       phers (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

IDENTIFYING THE CONNECTION MODE

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

PROTOCOL MODE

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

SESSION MODE

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

MESSAGES

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

HOW SYNCTHING USES RELAYS, AND GENERAL SECURITY

347       In  the  case of Syncthing and BEP, when two devices connect via relay,
348       they start their standard TLS connection encapsulated  within  the  re‐
349       lay’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 at‐
357       tacker  did get their hands on the device keys, they would still not be
358       able to recover/decrypt any traffic which was transported via  the  re‐
359       lay.
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

EXAMPLES OF STRONG CIPHER SUITES

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

AUTHOR

403       The Syncthing Authors
404
406       2014-2019, The Syncthing Authors
407
408
409
410
411v1                               Apr 15, 2021               SYNCTHING-RELAY(7)
Impressum