RFC 8656
Traversal Using Relays around NAT (TURN): Relay Extensions to Session Traversal Utilities for NAT (STUN)
RFC 8656 ๐ Part 1 of 21
Traversal Using Relays around NAT (TURN): Relay Extensions to Session Traversal Utilities for NAT (STUN) ๐
Request for Comments: 8656 ๐ Category: Standards Track โจ ISSN: 2070-1721 Date: February 2020 ๐ธ Obsoletes: RFCs 5766 and 6156 ๐
Authors: T. Reddy, Ed. (McAfee), A. Johnston, Ed. (Villanova University), P. Matthews (Alcatel-Lucent), and J. Rosenberg (jdrosen.net) ๐
Published by: the Internet Engineering Task Force (IETF) ๐ฆ
Abstract ๐
okay so if a host is stuck behind a NAT, it can be literally impossible for that host to talk directly to other hosts (called peers) in some situations ๐ญ. In those cases, the host needs to use an intermediate node that acts as a communication relay. This spec defines a protocol called "Traversal Using Relays around NAT" (TURN) that lets the host control the relay and swap packets with its peers through it. TURN is iconic because it lets a client talk to multiple peers using one single relay address ๐ฅ.
TURN was designed to be used as part of the Interactive Connectivity Establishment (ICE) approach to NAT traversal, though it can also be used without ICE โจ.
This document obsoletes RFCs 5766 and 6156 ๐ซถ.
Status of This Memo ๐
This is an Internet Standards Track document ๐.
This document is a product of the Internet Engineering Task Force (IETF). It represents the consensus of the IETF community, and it has received public review and been approved for publication by the Internet Engineering Steering Group (IESG). For more on Internet Standards, check Section 2 of RFC 7841 ๐ง.
For the current status, any errata, and how to send feedback, go to https://www.rfc-editor.org/info/rfc8656 ๐.
Copyright Notice ๐
Copyright (c) 2020 IETF Trust and the persons identified as the document authors. All rights reserved ๐ .
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication. Please read these carefully, because they describe your rights and restrictions with respect to this document ๐. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions, and they are provided without warranty as described in the Simplified BSD License โญ.
Table of Contents ๐ฆ
1. Introduction
2. Terminology
3. Overview of Operation
3.1. Transports
3.2. Allocations
3.3. Permissions
3.4. Send Mechanism
3.5. Channels
3.6. Unprivileged TURN Servers
3.7. Avoiding IP Fragmentation
3.8. RTP Support
3.9. Happy Eyeballs for TURN
4. Discovery of TURN Server
4.1. TURN URI Scheme Semantics
5. General Behavior
6. Allocations
7. Creating an Allocation
7.1. Sending an Allocate Request
7.2. Receiving an Allocate Request
7.3. Receiving an Allocate Success Response
7.4. Receiving an Allocate Error Response
8. Refreshing an Allocation
8.1. Sending a Refresh Request
8.2. Receiving a Refresh Request
8.3. Receiving a Refresh Response
9. Permissions
10. CreatePermission
10.1. Forming a CreatePermission Request
10.2. Receiving a CreatePermission Request
10.3. Receiving a CreatePermission Response
11. Send and Data Methods
11.1. Forming a Send Indication
11.2. Receiving a Send Indication
11.3. Receiving a UDP Datagram
11.4. Receiving a Data Indication
11.5. Receiving an ICMP Packet
11.6. Receiving a Data Indication with an ICMP Attribute
12. Channels
12.1. Sending a ChannelBind Request
12.2. Receiving a ChannelBind Request
12.3. Receiving a ChannelBind Response
12.4. The ChannelData Message
12.5. Sending a ChannelData Message
12.6. Receiving a ChannelData Message
12.7. Relaying Data from the Peer
13. Packet Translations
13.1. IPv4-to-IPv6 Translations
13.2. IPv6-to-IPv6 Translations
13.3. IPv6-to-IPv4 Translations
14. UDP-to-UDP Relay
15. TCP-to-UDP Relay
16. UDP-to-TCP Relay
17. STUN Methods
18. STUN Attributes
18.1. CHANNEL-NUMBER
18.2. LIFETIME
18.3. XOR-PEER-ADDRESS
18.4. DATA
18.5. XOR-RELAYED-ADDRESS
18.6. REQUESTED-ADDRESS-FAMILY
18.7. EVEN-PORT
18.8. REQUESTED-TRANSPORT
18.9. DONT-FRAGMENT
18.10. RESERVATION-TOKEN
18.11. ADDITIONAL-ADDRESS-FAMILY
18.12. ADDRESS-ERROR-CODE
18.13. ICMP
19. STUN Error Response Codes
20. Detailed Example
21. Security Considerations
21.1. Outsider Attacks
21.1.1. Obtaining Unauthorized Allocations
21.1.2. Offline Dictionary Attacks
21.1.3. Faked Refreshes and Permissions
21.1.4. Fake Data
21.1.5. Impersonating a Server
21.1.6. Eavesdropping Traffic
21.1.7. TURN Loop Attack
21.2. Firewall Considerations
21.2.1. Faked Permissions
21.2.2. Blacklisted IP Addresses
21.2.3. Running Servers on Well-Known Ports
21.3. Insider Attacks
21.3.1. DoS against TURN Server
21.3.2. Anonymous Relaying of Malicious Traffic
21.3.3. Manipulating Other Allocations
21.4. Tunnel Amplification Attack
21.5. Other Considerations
22. IANA Considerations
23. IAB Considerations
24. Changes since RFC 5766
25. Updates to RFC 6156
26. References
26.1. Normative References
26.2. Informative References
Acknowledgements
Authors' Addresses
1. Introduction โจ
okay so a host behind a NAT might want to swap packets with other hosts, and some of those might be behind NATs too ๐. To make that work, the hosts can try "hole punching" techniques (see [RFC5128]) to find a direct path, which is a route from one host to another through the NATs and routers in between that doesn't touch any relays ๐ฆ.
As described in [RFC5128] and [RFC4787], hole punching will fail if both hosts are behind NATs that aren't well behaved ๐. For example, if both hosts are behind NATs with a mapping behavior of "address-dependent mapping" or "address- and port-dependent mapping" (see Section 4.1 of [RFC4787]), hole punching generally fails ๐ญ.
When a direct path can't be found, you need an intermediate host that acts as a relay for the packets ๐ซถ. This relay usually lives on the public Internet and relays packets between two hosts that are both sitting behind NATs ๐ธ.
In many enterprise networks, direct UDP traffic between clients on the internal network and external IP addresses isn't allowed ๐ โโ๏ธ. To let media sessions use UDP without being forced over TCP, an Enterprise Firewall can be set up to allow UDP traffic relayed through an Enterprise relay server ๐. WebRTC requires support for this scenario (see Section 2.3.5.1 of [RFC7478]) ๐ฅ. Some SIP or WebRTC users also want IP location privacy from the remote peer. In that case, the client can pick a relay server that offers IP location privacy and only share the relayed candidates with the peer for ICE connectivity checks (see Section 4.2.4 of [SEC-WEBRTC]) ๐ง.
This specification defines a protocol called "TURN" that lets a host behind a NAT (called the "TURN client") ask another host (called the "TURN server") to act as a relay ๐. The client can set things up so the server relays packets to and from certain other hosts (called "peers"), and it can control aspects of how that relaying happens ๐. The client does this by getting an IP address and port on the server, called the "relayed transport address" ๐. When a peer sends a packet to the relayed transport address, the server relays the transport protocol data from that packet to the client. The data is wrapped in a message header that lets the client know which peer the data was relayed from ๐ฆ. If the server receives an ICMP error packet, it also relays certain Layer 3 and 4 header fields from the ICMP header to the client โญ. When the client sends a message to the server, the server figures out the remote peer from the message header and relays the message data to the intended peer ๐.
A client using TURN has to find some way to tell its peers the relayed transport address, and it has to learn each peer's IP address and port (more precisely, each peer's server-reflexive transport address; see Section 3) ๐. How that happens is out of scope for the TURN protocol ๐. One option is for the client and peers to swap email messages ๐ . Another is for them to use a special-purpose "introduction" or "rendezvous" protocol (see [RFC5128] for more details) ๐ซถ.
If TURN is used with ICE [RFC8445], then the relayed transport address and the IP addresses and ports of the peers get included in the ICE candidate information that the rendezvous protocol has to carry ๐ฅ. For example, if TURN and ICE are part of a multimedia solution using SIP [RFC3261], then SIP is the rendezvous protocol, carrying the ICE candidate information inside the body of SIP messages [SDP-ICE] โจ. If TURN and ICE are used with some other rendezvous protocol, then ICE gives guidance on the services that rendezvous protocol needs to perform ๐ง.
Using a TURN server to get two hosts behind NATs talking is very likely to work, but it costs the TURN server provider a lot ๐ธ, since the server usually needs a high-bandwidth Internet connection ๐ญ. So it's best to use a TURN server only when a direct path can't be found ๐. When the client and a peer use ICE to pick the communication path, ICE tries hole punching to look for a direct path first, and it only uses a TURN server when no direct path can be found ๐.
TURN was originally invented to support multimedia sessions signaled using SIP ๐. Since SIP supports forking, TURN supports multiple peers per relayed transport address, which other approaches don't do (e.g., SOCKS [RFC1928]) ๐. Even so, care has been taken to make sure TURN is suitable for other kinds of applications too ๐ธ.
TURN was designed as one piece of the bigger ICE approach to NAT traversal ๐ฆ. Implementors of TURN are urged to look into ICE and seriously consider using it for their application ๐ . It is still possible to use TURN without ICE, though ๐ซถ.
TURN is an extension to the Session Traversal Utilities for NAT (STUN) protocol [RFC8489] ๐ง. Most TURN messages are STUN-formatted messages, though not all of them are ๐. If you're reading this document, you should already be familiar with STUN ๐.
The TURN specification was originally published as [RFC5766], which was updated by [RFC6156] to add IPv6 support ๐. This document supersedes and obsoletes both [RFC5766] and [RFC6156] ๐.
2. Terminology โจ
okay bestie, let's get into the vocab, because TURN has a LOT of terms and we need them locked in ๐๐
The big requirement keywords first: "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" mean what they mean in BCP 14 [RFC2119] [RFC8174] but only when they show up in ALL CAPITALS, just like here ๐ . Lowercase "must" is just a regular word, no cap ๐
Also, you're expected to already know [RFC8489] and the terms it defines. It's the STUN spec, so if you're new to that, go read it first ๐ง
Here are the terms we use in this doc:
TURN: The protocol spoken between a TURN client and a TURN server. It's an extension to the STUN protocol [RFC8489]. The protocol lets a client allocate and use a relayed transport address ๐ฆ
TURN client: A STUN client that implements this specification. โจ
TURN server: A STUN server that implements this specification. It relays data between a TURN client and its peer(s). ๐ซถ
Peer: A host the TURN client wants to talk to. The TURN server relays traffic between the TURN client and its peer(s). The peer does NOT speak the TURN protocol ๐ โโ๏ธ It just receives data sent by the TURN server, and it sends data toward the TURN server. Lowkey the peer is just living its best life ๐
Transport Address: The combo of an IP address and a port. ๐ธ
Host Transport Address: A transport address on a client or a peer. ๐
Server-Reflexive Transport Address: A transport address on the "external side" of a NAT. The NAT allocates this address to match up with a specific host transport address. It's giving "NAT mapping" energy ๐
Relayed Transport Address: A transport address on the TURN server that's used to relay packets between the client and a peer. A peer sends to this address on the TURN server, and then the packet gets relayed to the client. โจ
TURN Server Transport Address: A transport address on the TURN server that's used to send TURN messages to the server. This is the address the client uses to talk to the server. ๐ง
Peer Transport Address: The transport address of the peer as seen by the server. When the peer is behind a NAT, this is the peer's server-reflexive transport address. ๐ฆ
Allocation: The relayed transport address granted to a client through an Allocate request, plus related state like permissions and expiration timers. It's the whole package, main character energy ๐
5-tuple: The combo of (client IP address and port, server IP address and port, and transport protocol). The transport protocol is currently one of UDP, TCP, DTLS/UDP, or TLS/TCP. This is used to communicate between the client and the server. The 5-tuple uniquely identifies this communication stream, and it also uniquely identifies the Allocation on the server. Iconic, honestly ๐ฅ
Transport Protocol: The protocol above IP that carries TURN Requests, Responses, and Indications, and that provides identifiable flows using a 5-tuple. In this spec, UDP and TCP are defined as transport protocols. This doc also describes using UDP and TCP together with a security layer using DTLS and TLS, respectively. ๐
Channel: A channel number plus an associated peer transport address. Once a channel number is bound to a peer's transport address, the client and server can use the more bandwidth-efficient ChannelData message to exchange data. Bandwidth-efficient = slay ๐
Permission: The IP address and transport protocol (but NOT the port) of a peer that's allowed to send traffic to the TURN server and have that traffic relayed to the TURN client. The TURN server will only forward traffic to its client from peers that match an existing permission. Not the port, bestie, just the IP and protocol ๐
Realm: A string used to describe the server or a context within the server. The realm tells the client which username and password combination to use to authenticate requests. ๐
Nonce: A string chosen at random by the server and included in the server response. To prevent replay attacks, the server SHOULD change the nonce regularly. ๐ธ
(D)TLS: This term is used for statements that apply to both Transport Layer Security [RFC8446] and Datagram Transport Layer Security [RFC6347]. Two protocols, one term, zero stress ๐ญโจ
3. Overview of Operation ๐ฆ
okay so this section gives an overview of how TURN works. It is non-normative, which means it's just the vibes and not the rules ๐
In a typical setup, a TURN client is connected to a private network [RFC1918] and, through one or more NATs, to the public Internet. Out on the public Internet is a TURN server. Elsewhere on the Internet are one or more peers that the TURN client wants to talk to. These peers may or may not be behind one or more NATs. The client uses the server as a relay to send packets to these peers and to receive packets from them ๐ง
Peer A
Server-Reflexive +---------+
Transport Address | |
192.0.2.150:32102 | |
| /| |
TURN | / ^| Peer A |
Client's Server | / || |
Host Transport Transport | // || |
Address Address | // |+---------+
198.51.100.2:49721 192.0.2.15:3478 |+-+ // Peer A
| | ||N| / Host Transport
| +-+ | ||A|/ Address
| | | | v|T| 203.0.113.2:49582
| | | | /+-+
+---------+| | | |+---------+ / +---------+
| || |N| || | // | |
| TURN |v | | v| TURN |/ | |
| Client |----|A|-------| Server |------------------| Peer B |
| | | |^ | |^ ^| |
| | |T|| | || || |
+---------+ | || +---------+| |+---------+
| || | |
| || | |
+-+| | |
| | |
| | |
Client's | Peer B
Server-Reflexive Relayed Transport
Transport Address Transport Address Address
192.0.2.1:7000 192.0.2.15:50000 192.0.2.210:49191
Figure 1
Figure 1 shows a typical deployment. In this figure, the TURN client and the TURN server are separated by a NAT, with the client on the private side and the server on the public side of the NAT. This NAT is assumed to be a "bad" NAT. For example, it might have a mapping property of "address-and-port-dependent mapping" (see [RFC4787]). Yikes, bad NAT ๐ญ
The client talks to the server from a (IP address, port) combo called the client's "host transport address". (The combo of an IP address and port is called a "transport address".) ๐ธ
The client sends TURN messages from its host transport address to a transport address on the TURN server that's known as the "TURN server transport address". The client learns the TURN server transport address through some unspecified means (e.g., configuration), and this address is typically used by many clients at the same time ๐
Since the client is behind a NAT, the server sees packets from the client as coming from a transport address on the NAT itself. This address is known as the client's "server-reflexive transport address". Packets the server sends to the client's server-reflexive transport address will be forwarded by the NAT to the client's host transport address ๐ฆ
The client uses TURN commands to create and manipulate an ALLOCATION on the server. An allocation is a data structure on the server. This data structure contains, amongst other things, the relayed transport address for the allocation. The relayed transport address is the transport address on the server that peers can use to have the server relay data to the client. An allocation is uniquely identified by its relayed transport address. โจ
Once an allocation exists, the client can send application data to the server along with an indication of which peer the data should go to, and the server will relay it to that peer. The client sends the application data to the server inside a TURN message; at the server, the data is pulled out of the TURN message and sent to the peer in a UDP datagram. In the other direction, a peer can send application data in a UDP datagram to the relayed transport address for the allocation. The server then wraps this data inside a TURN message and sends it to the client, along with an indication of which peer sent it. Since the TURN message always says which peer the client is talking to, the client can use a single allocation to talk to multiple peers. Multitasking queen ๐
When the peer is behind a NAT, the client MUST identify the peer using its server-reflexive transport address rather than its host transport address. For example, to send application data to Peer A in the example above, the client MUST specify 192.0.2.150:32102 (Peer A's server-reflexive transport address) rather than 203.0.113.2:49582 (Peer A's host transport address). Not the host address, bestie ๐ โโ๏ธ
Each allocation on the server belongs to a single client and has either one or two relayed transport addresses that are used only by that allocation. So when a packet arrives at a relayed transport address on the server, the server knows which client the data is meant for. Iconic routing ๐
The client MAY have multiple allocations on a server at the same time. ๐
3.1. Transports ๐
okay so TURN, as defined in this spec, always uses UDP between the server and the peer ๐ฆ but the spec lets you pick any one of UDP, TCP, TLS over TCP, or DTLS over UDP to carry the TURN messages between the client and the server โจ
+----------------------------+---------------------+
| TURN client to TURN server | TURN server to peer |
+============================+=====================+
| UDP | UDP |
+----------------------------+---------------------+
| TCP | UDP |
+----------------------------+---------------------+
| TLS-over-TCP | UDP |
+----------------------------+---------------------+
| DTLS-over-UDP | UDP |
+----------------------------+---------------------+
Table 1
if TCP or TLS-over-TCP is used between the client and the server, the server will convert between those transports and UDP when it relays data to and from the peer ๐
since this version of TURN only supports UDP between the server and the peer, most clients are expected to prefer UDP between the client and the server too ๐ so you might be wondering: why bother supporting TCP and TLS-over-TCP at all? ๐ค
TURN supports TCP between the client and the server because some firewalls are set up to block UDP entirely ๐งฑ those firewalls block UDP but not TCP, partly because TCP has properties that make the intention of the protected nodes way more obvious to the firewall ๐ for example, TCP has a three-way handshake, which makes it clear that the protected node really wants that connection set up. with UDP, the firewall can only guess which flows are wanted by using filtering rules ๐ฒ TCP also has explicit connection teardown, whereas with UDP the firewall has to use timers to guess when a flow is done โฐ
TURN supports TLS-over-TCP and DTLS-over-UDP between the client and the server because (D)TLS gives you extra security properties that TURN's default digest authentication doesn't, and some clients want to use those ๐ most importantly, (D)TLS lets the client check that it's really talking to the right server, and it keeps TURN control messages confidential ๐ซถ if you use (D)TLS transport between the TURN client and the TURN server, check out Section 6.2.3 of [RFC8489] for the details on cipher suites, server certificate validation, and authenticating TURN servers ๐ the guidance given in [RFC7525] MUST be followed to avoid attacks on (D)TLS, no exceptions ๐จ TURN doesn't require (D)TLS, though, because the overhead is higher than digest authentication's. for example, with (D)TLS, most application data ends up doubly encrypted: once by (D)TLS, and once more so it's still encrypted inside the UDP datagram ๐ฅด
there's an extension to TURN for TCP transport between the server and the peers, described in [RFC6062] ๐งฉ because of that, allocations that use UDP between the server and the peers are called "UDP allocations", and allocations that use TCP between the server and the peers are called "TCP allocations". this specification only describes UDP allocations ๐
in some TURN applications, the client may send and receive packets that aren't TURN packets on the same host transport address it uses to talk to the server ๐ง this can happen when you use TURN with ICE, for example ๐ in those cases, the client can tell TURN packets apart from everything else by looking at the source address of the arriving packet: anything arriving from the TURN server is a TURN packet ๐ the algorithm for demultiplexing packets received from multiple protocols on the host transport address is discussed in [RFC7983] ๐ง
3.2. Allocations ๐
to create an allocation on the server, the client runs an Allocate transaction ๐ธ the client sends an Allocate request to the server, and the server replies with an Allocate success response that contains the allocated relayed transport address ๐ the client can include attributes in the Allocate request that describe the kind of allocation it wants (for example, the lifetime of the allocation) โณ relaying data has security implications, so the server requires the client to authenticate itself, typically using STUN's long-term credential mechanism or the STUN Extension for Third-Party Authorization [RFC7635], to show it's allowed to use the server ๐
once a relayed transport address is allocated, a client must keep that allocation alive ๐ซ to do this, the client periodically sends a Refresh request to the server ๐ TURN deliberately uses a different method (Refresh rather than Allocate) for refreshes, so the client is told if the allocation vanishes for some reason ๐
how often the Refresh transaction happens is determined by the lifetime of the allocation ๐ฐ๏ธ the default lifetime is 10 minutes. that number was picked to be long enough that refreshing isn't usually a burden on the client, while still expiring allocations promptly when a client has unexpectedly quit ๐งธ the client can ask for a longer lifetime in the Allocate request and may change its request in a Refresh request, and the server always reports the actual lifetime in its response ๐ the client must issue a new Refresh transaction within "lifetime" seconds of the previous Allocate or Refresh transaction ๐โโ๏ธ once a client no longer wants an allocation, it should delete it with a Refresh request that has a requested lifetime of zero ๐๏ธ
both the server and the client keep track of something called the "5-tuple" ๐งฎ at the client, the 5-tuple is made up of the client's host transport address, the server transport address, and the transport protocol the client uses to talk to the server ๐ฐ๏ธ at the server, the 5-tuple is the same except the client's host transport address gets swapped for the client's server-reflexive address, since that's the address the server sees the client using ๐๏ธ
both the client and the server remember the 5-tuple from the Allocate request, and later messages between them use that same 5-tuple ๐ค that's how they both know which allocation is being talked about ๐ if the client wants a second relayed transport address, it has to create a second allocation using a different 5-tuple (for example, a different client host address or port) ๐ฆ
NOTE: okay, even though this document talks about 5-tuples, the TURN server can store whatever identifier it likes, as long as the results come out identical ๐ง for instance, an implementation can use a file descriptor in place of a 5-tuple to represent a TCP connection ๐งฉ
here's the Allocate flow in action ๐
TURN TURN Peer Peer
client server A B
|-- Allocate request --------------->| | |
| (invalid or missing credentials) | | |
| | | |
|<--------------- Allocate failure --| | |
| (401 Unauthenticated) | | |
| | | |
|-- Allocate request --------------->| | |
| (valid credentials) | | |
| | | |
|<---------- Allocate success resp --| | |
| (192.0.2.15:50000) | | |
// // // //
| | | |
|-- Refresh request ---------------->| | |
| | | |
|<----------- Refresh success resp --| | |
| | | |
Figure 2
in Figure 2, the client sends an Allocate request to the server with invalid or missing credentials ๐ since the server requires every request to be authenticated with STUN's long-term credential mechanism, it rejects the request with a 401 (Unauthorized) error code ๐ซ the client then tries again, this time with credentials ๐ this time the server accepts the Allocate request and returns an Allocate success response containing (among other things) the relayed transport address assigned to the allocation ๐ a while later, the client decides to refresh the allocation, so it sends a Refresh request to the server โจ the refresh is accepted, and the server replies with a Refresh success response ๐ฅฐ
3.3. Permissions ๐
okay, so enterprise IT admins were worried that TURN could be used to get around corporate firewall security ๐ค to ease those concerns, TURN includes the notion of permissions ๐ TURN permissions copy the address-restricted filtering mechanism of NATs that comply with [RFC4787] ๐ช
an allocation can have zero or more permissions ๐๏ธ each permission consists of an IP address and a lifetime ๐ when the server gets a UDP datagram on the allocation's relayed transport address, it checks the permission list first ๐ if the datagram's source IP address matches a permission, the application data is relayed to the client; otherwise, the UDP datagram is silently discarded ๐ซฅ
a permission expires after 5 minutes if it isn't refreshed, and there's no way to explicitly delete a permission ๐ โโ๏ธ that behavior was chosen to match a NAT that complies with [RFC4787] ๐ฆ
the client can install or refresh a permission using either a CreatePermission request or a ChannelBind request ๐ท with CreatePermission, you can install or refresh several permissions in one single request, which matters a lot for apps that use ICE ๐ง for security reasons, permissions can only be installed or refreshed by transactions that can be authenticated ๐ก๏ธ so Send indications and ChannelData messages (the ones used to send data to peers) don't install or refresh any permissions ๐ซ
one more thing: permissions live within the context of an allocation, so adding or expiring a permission in one allocation doesn't affect any other allocations ๐
3.4. Send Mechanism โจ
okay so there are two ways the client and its peers can swap app data through the TURN server ๐ The first one uses Send and Data methods, and the second one uses channels. Both give the client a way to chat with multiple peers through one relayed transport address ๐ฆ So both need a way for the client to say which peer should get the data, and for the server to say which peer the data came from ๐ซถ
The Send mechanism uses Send and Data indications. Send indications carry app data from the client to the server, and Data indications carry it from the server back to the client ๐จ
when the client is using Send, it sends a Send indication to the TURN server with (a) an XOR-PEER-ADDRESS attribute that holds the peer's (server-reflexive) transport address and (b) a DATA attribute with the actual app data ๐
When the server gets that Send indication, it pulls the data out of DATA and sends it to the peer in a UDP datagram, using the allocated relay address as the source address ๐ ngl, there's no need to specify the relayed transport address, because the 5-tuple used for the Send indication already implies it ๐
going the other way, UDP datagrams that land on the relayed transport address are turned into Data indications and sent to the client ๐ธ The peer's server-reflexive transport address goes in an XOR-PEER-ADDRESS attribute, and the data itself goes in a DATA attribute. Since the relayed transport address uniquely identifies the allocation, the server always knows which client should get the data ๐
some ICMP (Internet Control Message Protocol) packets that arrive at the relayed transport address may also be turned into Data indications and sent to the client ๐ง They carry the peer's transport address in an XOR-PEER-ADDRESS attribute, and the ICMP type and code go in an ICMP attribute. ICMP attribute forwarding always uses Data indications with the XOR-PEER-ADDRESS and ICMP attributes, even when the channel mechanism is being used to forward UDP data ๐ฅ
Send and Data indications can't be authenticated, because STUN's long-term credential mechanism doesn't support authenticating indications ๐ The good news is that this isn't as big a deal as it sounds, since the client-to-server leg is only half of the whole path to the peer ๐ซถ Apps that want true end-to-end security should encrypt the data they send between the client and a peer ๐
because Send indications aren't authenticated, an attacker could send bogus Send indications to the server, and the server would then relay them to a peer ๐ญ To partly stop this, TURN requires the client to install a permission towards a peer before sending it data with a Send indication ๐ก๏ธ The technique for fully stopping the attack is covered in Section 21.1.4 โจ
Figure 3 shows what that looks like in a call flow ๐
TURN TURN Peer Peer
client server A B
| | | |
|-- CreatePermission req (Peer A) ->| | |
|<- CreatePermission success resp --| | |
| | | |
|--- Send ind (Peer A)------------->| | |
| |=== data ===>| |
| | | |
| |<== data ====| |
|<------------- Data ind (Peer A) --| | |
| | | |
| | | |
|--- Send ind (Peer B)------------->| | |
| | dropped | |
| | | |
| |<== data ==================|
| dropped | | |
| | | |
Figure 3
in Figure 3, the client has already made an allocation and now wants to send data to its peers ๐ฆ First it creates a permission by sending the server a CreatePermission request with Peer A's (server-reflexive) IP address in the XOR-PEER-ADDRESS attribute. If that step got skipped, the server wouldn't relay data between the client and the server ๐
โโ๏ธ Next, the client sends data to Peer A with a Send indication. The server pulls out the app data and forwards it to Peer A in a UDP datagram, using the relayed transport address as the source ๐ When a UDP datagram from Peer A shows up at the relayed transport address, its contents go into a Data indication and get forwarded to the client โจ Then the client tries to talk to Peer B, but there's no permission for Peer B yet, so the server drops both the Send indication from the client and the UDP datagram from the peer ๐ bestie, that's the permission system doing its job ๐ฅ
3.5. Channels
for some apps (like Voice over IP (VoIP)), the 36 bytes of overhead that a Send indication or Data indication adds to the app data can really eat up the bandwidth between the client and the server ๐ญ To fix that, TURN gives us a second way for the client and server to tie data to a specific peer ๐
this second way uses a different packet format called the "ChannelData message" ๐ A ChannelData message doesn't use the STUN header that the other TURN messages use. Instead, it has a 4-byte header with a number called a "channel number" ๐ Each channel number in use is bound to one specific peer, so it works as a shorthand for that peer's host transport address ๐ง
to bind a channel to a peer, the client sends a ChannelBind request to the server, including an unbound channel number and the peer's transport address ๐ Once the channel is bound, the client can use a ChannelData message to send data to that peer through the server. The server can also relay data from that peer back to the client in a ChannelData message ๐
channel bindings last for 10 minutes unless they get refreshed, and that lifetime was picked to be longer than the permission lifetime โฐ To refresh a binding, the client sends another ChannelBind request that rebinds the channel to the peer ๐ Like permissions (but unlike allocations), there's no way to explicitly delete a channel binding. The client just has to wait for it to time out ๐
Figure 4 shows the channel mechanism in action ๐
TURN TURN Peer Peer
client server A B
| | | |
|-- ChannelBind req --------------->| | |
| (Peer A to 0x4001) | | |
| | | |
|<---------- ChannelBind succ resp -| | |
| | | |
|-- (0x4001) data ----------------->| | |
| |=== data ===>| |
| | | |
| |<== data ====| |
|<------------------ (0x4001) data -| | |
| | | |
|--- Send ind (Peer A)------------->| | |
| |=== data ===>| |
| | | |
| |<== data ====| |
|<------------------ (0x4001) data -| | |
| | | |
Figure 4
in Figure 4, the client has already made an allocation and now wants to bind a channel to Peer A ๐ธ It sends a ChannelBind request to the server with Peer A's transport address and a channel number (0x4001) ๐ฏ After that, the client can send app data wrapped in ChannelData messages to Peer A, shown as "(0x4001) data" where 0x4001 is the channel number ๐ When the ChannelData message reaches the server, the server moves the data into a UDP datagram and sends it to Peer A, since Peer A is the peer bound to channel 0x4001 โจ
going the other way, when Peer A sends a UDP datagram to the relayed transport address, that datagram arrives at the server on the relayed transport address assigned to the allocation ๐ฌ Because Peer A has a channel number assigned to it, the server wraps the data in a ChannelData message when it sends it to the client ๐ซถ
once a channel is bound, the client is free to mix ChannelData messages and Send indications ๐ In the figure, the client later decides to use a Send indication instead of a ChannelData message to send more data to Peer A. It might do that, for example, so it can use the DONT-FRAGMENT attribute (see the next section) ๐ Still, once a channel is bound, the server will always use a ChannelData message, as shown in the call flow ๐
one important thing: ChannelData messages can only be used with peers the client has bound a channel to ๐จ In the example above, Peer A has a channel bound, but Peer B doesn't, so app data to and from Peer B would use the Send mechanism ๐ง
3.6. Unprivileged TURN Servers
this version of TURN is built so the server can run as a normal app in user space on commonly available operating systems, without needing special privileges ๐ Why? Because it makes TURN servers super easy to deploy ๐ For example, a TURN server can be built right into a peer-to-peer app, so one peer can offer NAT traversal services to another peer. It also means (D)TLS can be used to secure the TURN connection ๐
this design decision has some consequences for data relayed by a TURN server ๐
- The value of the Diffserv field may not be preserved across the server ๐
- The Time to Live (TTL) field may be reset, rather than decremented, across the server โณ
- The Explicit Congestion Notification (ECN) field may be reset by the server ๐ง๏ธ
- There is no end-to-end fragmentation, since the packet is reassembled at the server ๐งฉ
future work may specify alternate TURN semantics that tackle these limitations ๐ฎ
3.7. Avoiding IP Fragmentation โจ
okay bestie, this section is literally about not letting your packets get chopped up into pieces ๐ช๐ For reasons described in [FRAG-HARMFUL], applications, especially the ones sending huge amounts of data, should avoid having their packets fragmented. [FRAG-FRAGILE] talks about the issues with IP fragmentation and suggests alternatives to it ๐ฆ Applications using TCP can, more or less, ignore this because fragmentation avoidance is already a standard part of TCP ๐ But applications using UDP (and that means any application using this version of TURN) need to avoid IP fragmentation by sending messages that are small enough, or by using UDP fragmentation [UDP-OPT] ๐ซถ Note that the UDP fragmentation option needs to be supported by both endpoints, and when this document was written, UDP fragmentation support was still under discussion and was not deployed ๐ญ
The application running on the client and the peer can take one of two approaches to avoid IP fragmentation until UDP fragmentation support is available ๐ธ The first uses messages that are limited to a predetermined fixed maximum, and the second relies on network feedback to adapt that maximum ๐
The first approach is to avoid sending large amounts of application data in the TURN messages/UDP datagrams exchanged between the client and the peer. This is the approach most VoIP applications take ๐โจ In this approach, the application MUST assume a Path MTU (PMTU) of 1280 bytes, because IPv6 requires that every link in the Internet has an MTU of 1280 octets or greater as specified in [RFC8200] ๐ If IPv4 support on legacy or otherwise unusual networks is a consideration, the application MAY assume an effective MTU of 576 bytes for IPv4 datagrams, as every IPv4 host must be capable of receiving a packet with a length equal to 576 bytes, as discussed in [RFC0791] and [RFC1122] ๐
The exact amount of application data that can be included while avoiding fragmentation depends on the details of the TURN session between the client and the server: whether UDP, TCP, or (D)TLS transport is used, whether ChannelData messages or Send/Data indications are used, and whether any additional attributes (such as the DONT-FRAGMENT attribute) are included. Another factor, which is hard to determine, is whether the MTU gets reduced somewhere along the path for other reasons, such as the use of IP-in-IP tunneling ๐
As a guideline, sending a maximum of 500 bytes of application data in a single TURN message (by the client on the client-to-server leg) or a UDP datagram (by the peer on the peer-to-server leg) will generally avoid IP fragmentation ๐ง To further reduce the chance of fragmentation, it is recommended that the client use ChannelData messages when transferring significant volumes of data, since the overhead of the ChannelData message is less than that of Send and Data indications ๐
The second approach the client and peer can take to avoid fragmentation is to use a path MTU discovery algorithm to determine the maximum amount of application data that can be sent without fragmentation ๐ฅ The classic path MTU discovery algorithm defined in [RFC1191] may not be able to discover the MTU of the transmission path between the client and the peer, since:
- A probe packet with a Don't Fragment (DF) bit in the IPv4 header set to test a path for a larger MTU can be dropped by routers, or
- ICMP error messages can be dropped by middleboxes.
As a result, the client and server need to use a path MTU discovery algorithm that does not require ICMP messages. The Packetized Path MTU Discovery algorithm defined in [RFC4821] is one such algorithm, and a set of algorithms is defined in [MTU-DATAGRAM] ๐
[MTU-STUN] is an implementation of [RFC4821] that uses STUN to discover the path MTU, so it might be a suitable approach to use in conjunction with a TURN server that supports the DONT-FRAGMENT attribute ๐ฆ When the client includes the DONT-FRAGMENT attribute in a Send indication, this tells the server to set the DF bit in the resulting UDP datagram that it sends to the peer. Since some servers may be unable to set the DF bit, the client SHOULD also include this attribute in the Allocate request; any server that does not support the DONT-FRAGMENT attribute will indicate this by rejecting the Allocate request. If the TURN server carrying out packet translation from IPv4-to-IPv6 is unable to access the state of the Don't Fragment (DF) bit in the IPv4 header, it MUST reject the Allocate request with the DONT-FRAGMENT attribute ๐ โโ๏ธ๐
3.8. RTP Support ๐
One of the envisioned uses of TURN is as a relay for clients and peers that want to exchange real-time data (e.g., voice or video) using RTP ๐ค๐น To make TURN work well for this, it includes some special support for older versions of RTP ๐ซถ
Old versions of RTP [RFC3550] required that the RTP stream be on an even port number, and the associated RTP Control Protocol (RTCP) stream, if present, be on the next highest port ๐ข To let clients work with peers that still require this, TURN allows the client to request that the server allocate a relayed transport address with an even port number, and optionally request that the server reserve the next-highest port number for a subsequent allocation ๐
3.9. Happy Eyeballs for TURN ๐๐
If an IPv4 path to reach a TURN server is found, but the TURN server's IPv6 path isn't working, a dual-stack TURN client can experience a significant connection delay compared to an IPv4-only TURN client ๐ญ To overcome these connection setup problems, the TURN client needs to query both A and AAAA records for the TURN server specified using a domain name, and try connecting to the TURN server using both IPv6 and IPv4 addresses in a fashion similar to the Happy Eyeballs mechanism defined in [RFC8305] ๐ฆ The TURN client performs the following steps based on the transport protocol being used to connect to the TURN server:
- For TCP or TLS-over-TCP, the results of the Happy Eyeballs procedure [RFC8305] are used by the TURN client for sending its TURN messages to the server.
- For clear text UDP, send TURN Allocate requests to both IP address families as discussed in [RFC8305] without authentication information. If the TURN server requires authentication, it will send back a 401 unauthenticated response; the TURN client will use the first UDP connection on which a 401 error response is received. If a 401 error response is received from both IP address families, then the TURN client can silently abandon the UDP connection on the IP address family with lower precedence. If the TURN server does not require authentication (as described in Section 9 of [RFC8155]), it is possible for both Allocate requests to succeed. In this case, the TURN client sends a Refresh with a LIFETIME value of zero on the allocation using the IP address family with lower precedence to delete the allocation ๐งน
- For DTLS over UDP, initiate a DTLS handshake to both IP address families as discussed in [RFC8305], and use the first DTLS session that is established. If the DTLS session is established on both IP address families, then the client sends a DTLS close_notify alert to terminate the DTLS session using the IP address family with lower precedence. If the TURN over DTLS server has been configured to require a cookie exchange (Section 4.2 of [RFC6347]) and a HelloVerifyRequest is received from the TURN servers on both IP address families, then the client can silently abandon the connection on the IP address family with lower precedence ๐
4. Discovery of TURN Server ๐โจ
Methods of TURN server discovery, including using anycast, are described in [RFC8155]. If a host with multiple interfaces discovers a TURN server on each interface, the mechanism described in [RFC7982] can be used by the TURN client to influence the TURN server selection ๐งญ The syntax of the "turn" and "turns" URIs is defined in Section 3.1 of [RFC7065]. DTLS as a transport protocol for TURN is defined in [RFC7350] ๐
4.1. TURN URI Scheme Semantics ๐ง
The "turn" and "turns" URI schemes are used to designate a TURN server (also known as a "relay") on Internet hosts accessible using the TURN protocol ๐ธ The TURN protocol supports sending messages over UDP, TCP, TLS-over-TCP, or DTLS-over-UDP. The "turns" URI scheme MUST be used when TURN is run over TLS-over-TCP or in DTLS-over-UDP, and the "turn" scheme MUST be used otherwise ๐ The required <host> part of the "turn" URI denotes the TURN server host. The <port> part, if present, denotes the port on which the TURN server is awaiting connection requests. If it is absent, the default port is 3478 for both UDP and TCP. The default port for TURN over TLS and TURN over DTLS is 5349 ๐ฅฐ
5. General Behavior ๐
okay so this section is all the general TURN rules that apply to every single TURN message ๐ซถ
TURN is an extension to STUN. All TURN messages, except for the ChannelData message, are STUN-formatted messages ๐ All the base processing rules in [RFC8489] apply to STUN-formatted messages, so every message-forming and message-processing description in this document is implicitly prefixed with the rules of [RFC8489] โจ
[RFC8489] specifies an authentication mechanism called the "long-term credential mechanism". TURN servers and clients MUST implement this mechanism, and Section 7.2 talks about the authentication options ๐
Note that the long-term credential mechanism applies only to requests and cannot be used to authenticate indications. So indications in TURN are never authenticated, no exceptions ๐ If the server requires requests to be authenticated, then the server's administrator MUST choose a realm value that uniquely identifies the username and password combination the client must use, even if the client uses multiple servers under different administrations ๐ The administrator MAY choose to give each client a unique username, or it MAY give the same username to more than one client (for example, to all the clients from the same department or company) ๐ธ For each Allocate request, the server SHOULD generate a new random nonce when the allocation is first attempted, following the randomness recommendations in [RFC4086], and SHOULD expire the nonce at least once every hour during the lifetime of the allocation โฐ The server uses the mechanism described in Section 9.2 of [RFC8489] to indicate that it supports [RFC8489] ๐ฆ
All requests after the initial Allocate must use the same username that was used to create the allocation. This is how we stop attackers from hijacking the client's allocation ๐ซ
Specifically, if:
- the server requires the use of the long-term credential mechanism, and;
- a non-Allocate request passes authentication under this mechanism, and;
- the 5-tuple identifies an existing allocation, but;
- the request does not use the same username as used to create the allocation,
then the request MUST be rejected with a 441 (Wrong Credentials) error ๐ค
When a TURN message arrives at the server from the client, the server uses the 5-tuple in the message to find the associated allocation ๐ For all TURN messages (including ChannelData) EXCEPT an Allocate request, if the 5-tuple does not identify an existing allocation, then the message MUST either be rejected with a 437 Allocation Mismatch error (if it is a request) or be silently ignored (if it is an indication or a ChannelData message). A client that receives a 437 error response to a request other than Allocate MUST assume the allocation no longer exists ๐
[RFC8489] defines a number of attributes, including the SOFTWARE and FINGERPRINT attributes. The client SHOULD include the SOFTWARE attribute in all Allocate and Refresh requests, and MAY include it in any other requests or indications. The server SHOULD include the SOFTWARE attribute in all Allocate and Refresh responses (either success or failure), and MAY include it in other responses or indications. The client and the server MAY include the FINGERPRINT attribute in any STUN-formatted messages defined in this document โจ
TURN does not use the backwards-compatibility mechanism described in [RFC8489] ๐ โโ๏ธ
TURN, as defined in this specification, supports both IPv4 and IPv6 ๐ IPv6 support in TURN includes IPv4-to-IPv6, IPv6-to-IPv6, and IPv6-to-IPv4 relaying. When only a single address type is desired, the REQUESTED-ADDRESS-FAMILY attribute is used to explicitly request the address type the TURN server will allocate (for example, an IPv4-only node may request the TURN server to allocate an IPv6 address) ๐ง If both IPv4 and IPv6 are desired, the single ADDITIONAL-ADDRESS-FAMILY attribute indicates a request to the server to allocate one IPv4 and one IPv6 relay address in a single Allocate request. This saves local ports on the client and reduces the number of messages sent between the client and the TURN server ๐
By default, TURN runs on the same ports as STUN: 3478 for TURN over UDP and TCP, and 5349 for TURN over (D)TLS. TURN also has its own set of Service Record (SRV) names: "turn" for UDP and TCP, and "turns" for (D)TLS ๐ก Either the DNS resolution procedures or the ALTERNATE-SERVER procedures, both described in Section 7, can be used to run TURN on a different port ๐
To ensure interoperability, a TURN server MUST support the use of UDP transport between the client and the server. It SHOULD also support the use of TCP, TLS-over-TCP, and DTLS-over-UDP transports ๐ซถ
When UDP or DTLS-over-UDP transport is used between the client and the server, the client will retransmit a request if it does not receive a response within a certain timeout period. Because of this, the server may receive two (or more) requests with the same 5-tuple and the same transaction id. STUN requires that the server recognize this case and treat the request as idempotent (see [RFC8489]) ๐ Some implementations may choose to meet this requirement by remembering all received requests and the corresponding responses for 40 seconds (Section 6.3.1 of [RFC8489]). Other implementations may choose to reprocess the request and arrange for that reprocessing to return essentially the same response. To help implementors who pick the latter approach (the so-called "stateless stack approach"), this specification includes some implementation notes on how this might be done. Implementations are free to choose either approach, or some other approach that gives the same results ๐ง
To mitigate either intentional or unintentional denial-of-service attacks against the server by clients with valid usernames and passwords, it is RECOMMENDED that the server impose limits on both the number of allocations active at one time for a given username and the amount of bandwidth those allocations can use ๐ก๏ธ The server should reject new allocations that would exceed the limit on the allowed number of allocations active at one time with a 486 (Allocation Quota Exceeded) (see Section 7.2). And since UDP does not include a congestion control mechanism, it should discard application data traffic that exceeds the bandwidth quota ๐ง
6. Allocations ๐
All TURN operations revolve around allocations, and all TURN messages are associated with either a single or a dual allocation ๐ An allocation conceptually consists of the following state data:
- the relayed transport address or addresses;
- the 5-tuple: (client's IP address, client's port, server IP address, server port, and transport protocol);
- the authentication information;
- the time-to-expiry for each relayed transport address;
- a list of permissions for each relayed transport address;
- a list of channel-to-peer bindings for each relayed transport address.
The relayed transport address is the transport address the server allocates for communicating with peers. The 5-tuple describes the communication path between the client and the server ๐ค๏ธ On the client, the 5-tuple uses the client's host transport address. On the server, the 5-tuple uses the client's server-reflexive transport address. The relayed transport address MUST be unique across all allocations so it can be used to uniquely identify the allocation, and in this context an allocation can be either a single or a dual allocation ๐
The authentication information (for example, username, password, realm, and nonce) is used both to verify subsequent requests and to compute the message integrity of responses ๐ The username, realm, and nonce values are initially the ones used in the authenticated Allocate request that creates the allocation, though the server can change the nonce value during the lifetime of the allocation using a 438 (Stale Nonce) reply. For security reasons, the server MUST NOT store the password explicitly. It MUST store the key value instead, which is a cryptographic hash over the username, realm, and password (see Section 16.1.3 of [RFC8489]) ๐
Note that if the response contains a PASSWORD-ALGORITHMS attribute, and this attribute contains both MD5 and SHA-256 algorithms, and the client also supports both algorithms, then the request MUST contain a PASSWORD-ALGORITHM attribute with the SHA-256 algorithm ๐ง
The time-to-expiry is the time in seconds left until the allocation expires. Each Allocate or Refresh transaction sets this timer, which then ticks down towards zero โณ By default, each Allocate or Refresh transaction resets this timer to the default lifetime value of 600 seconds (10 minutes), but the client can request a different value in the Allocate and Refresh request. Allocations can only be refreshed using the Refresh request. Sending data to a peer does NOT refresh an allocation, so don't be fooled bestie ๐ญ When an allocation expires, the state data associated with it can be freed ๐๏ธ
The list of permissions is described in Section 9, and the list of channels is described in Section 12 ๐ฆ
7. Creating an Allocation ๐
An allocation on the server is created using an Allocate transaction โจ
7.1. Sending an Allocate Request ๐จ
okay bestie, here's how the client builds an Allocate request ๐
First, the client picks a host transport address. It is RECOMMENDED that the client pick a currently unused transport address, usually by letting the OS choose a port nobody else is using ๐ธ
Then it picks a transport protocol to use between itself and the server, based on which protocols the server supports. Since this spec only allows UDP between the server and the peers, it is RECOMMENDED that the client pick UDP unless it has a reason to use something else ๐ฆ One reason would be if the client believes, through configuration, discovery, or just trying it out, that it can't reach any TURN server over UDP. See Section 3.1 for more on that.
The client also picks a server transport address, and it SHOULD do this part like so โจ It uses one or more procedures described in [RFC8155] to discover a TURN server, then uses the TURN server resolution mechanism defined in [RFC5928] and [RFC7350] to get a list of server transport addresses that can be tried to create a TURN allocation.
The client MUST include a REQUESTED-TRANSPORT attribute in the request. This attribute says which transport protocol to use between the server and the peers. (Note that this is not the transport protocol that shows up in the 5-tuple, so don't mix them up ๐) In this specification, the REQUESTED-TRANSPORT type is always UDP. The attribute is only there so future extensions can name other protocols ๐ง
If the client wants a relayed transport address of a specific address type, it includes a REQUESTED-ADDRESS-FAMILY attribute in the request. This tells the TURN server which address type the client wants it to allocate. Clients MUST NOT include more than one REQUESTED-ADDRESS-FAMILY attribute in an Allocate request. Clients MUST NOT include a REQUESTED-ADDRESS-FAMILY attribute in an Allocate request that contains a RESERVATION-TOKEN attribute. The reason is that the server uses the previously reserved transport address tied to the token, so the client can't get a relayed transport address of a specific address type in that case ๐
If the client wants one IPv6 and one IPv4 relayed transport address, it includes an ADDITIONAL-ADDRESS-FAMILY attribute in the request. This says the server must allocate both address types ๐ The attribute value in the ADDITIONAL-ADDRESS-FAMILY MUST be set to 0x02 (IPv6 address family). Clients MUST NOT include REQUESTED-ADDRESS-FAMILY and ADDITIONAL-ADDRESS-FAMILY attributes in the same request. Clients MUST NOT include the ADDITIONAL-ADDRESS-FAMILY attribute in an Allocate request that contains a RESERVATION-TOKEN attribute. Clients MUST NOT include the ADDITIONAL-ADDRESS-FAMILY attribute in an Allocate request that contains an EVEN-PORT attribute with the R (Reserved) bit set to 1. The reason for that last one: if EVEN-PORT with the R bit set to 1 were allowed alongside ADDITIONAL-ADDRESS-FAMILY, the success response would need two tokens, and the way RESERVATION-TOKEN gets handled would have to change. Too much drama ๐ญ
If the client wants the server to set the time-to-expiry of the allocation to something other than the default lifetime, it MAY include a LIFETIME attribute with its desired value. This is just a hint, so the server can pick a different value. Also, the server will ignore any request to set it to less than the default value ๐ซถ
If the client plans to use the DONT-FRAGMENT attribute in one or more Send indications on this allocation later, it SHOULD include the DONT-FRAGMENT attribute in the Allocate request. That way it can test whether the server supports this attribute โจ
If the client needs the port number of the relayed transport address to be even, it includes the EVEN-PORT attribute. If that attribute isn't included, the port can be even or odd. Setting the R bit in EVEN-PORT to 1 lets the client ask the server to reserve the next highest port number (on the same IP address) for a later allocation. If the R bit is 0, no such request is made ๐
The client MAY also include a RESERVATION-TOKEN attribute in the request to ask the server to use a port it reserved earlier for this allocation. If the RESERVATION-TOKEN attribute is included, then the client MUST omit the EVEN-PORT attribute ๐ฆ
Once it's all built, the client sends the Allocate request on the 5-tuple ๐
7.2. Receiving an Allocate Request ๐
okay so when the server gets an Allocate request, it runs through a bunch of checks, like a bouncer at the club ๐ชฉ
- The TURN server provided by the local or access network MAY allow an unauthenticated request, so it can accept Allocation requests from new or guest users on the network who don't have long-term credentials for STUN authentication. The security implications of STUN and making STUN authentication optional are covered in [RFC8155]. Otherwise, the server MUST require that the request be authenticated. If the request is authenticated, the authentication MUST be done either with the long-term credential mechanism of [RFC8489] or with the STUN Extension for Third-Party Authorization [RFC7635], unless the client and server agree to use another mechanism through some procedure outside the scope of this document ๐
- The server checks if the 5-tuple is already in use by an existing allocation. If yes, the server rejects the request with a 437 (Allocation Mismatch) error ๐ โโ๏ธ
- The server checks if the request contains a
REQUESTED-TRANSPORTattribute. If theREQUESTED-TRANSPORTattribute is missing or malformed, the server rejects the request with a 400 (Bad Request) error. Otherwise, if the attribute is there but names a protocol the server doesn't support, the server rejects the request with a 442 (Unsupported Transport Protocol) error ๐ - The request may contain a
DONT-FRAGMENTattribute. If it does, but the server doesn't support sending UDP datagrams with the DF bit set to 1 (see Sections 14 and 15), then the server treats theDONT-FRAGMENTattribute in the Allocate request as an unknown comprehension-required attribute ๐ง - The server checks if the request contains a
RESERVATION-TOKENattribute. If yes, and the request also contains anEVEN-PORT,REQUESTED-ADDRESS-FAMILY, orADDITIONAL-ADDRESS-FAMILYattribute, the server rejects the request with a 400 (Bad Request) error. Otherwise, it checks whether the token is valid (meaning the token is in range, hasn't expired, and the corresponding relayed transport address is still available). If the token isn't valid for some reason, the server rejects the request with a 508 (Insufficient Capacity) error ๐๏ธ - The server checks if the request contains both
REQUESTED-ADDRESS-FAMILYandADDITIONAL-ADDRESS-FAMILYattributes. If yes, the server rejects the request with a 400 (Bad Request) error ๐ - If the server doesn't support the address family the client asked for in
REQUESTED-ADDRESS-FAMILY, or if allocating that address family is turned off by local policy, it MUST generate an Allocate error response, and it MUST include anERROR-CODEattribute with the 440 (Address Family not Supported) response code. If theREQUESTED-ADDRESS-FAMILYattribute is absent and the server doesn't support the IPv4 address family, the server MUST include anERROR-CODEattribute with the 440 (Address Family not Supported) response code. If theREQUESTED-ADDRESS-FAMILYattribute is absent and the server does support the IPv4 address family, the server MUST allocate an IPv4 relayed transport address for the TURN client ๐ - The server checks if the request contains an
EVEN-PORTattribute with the R bit set to 1. If yes, and the request also contains anADDITIONAL-ADDRESS-FAMILYattribute, the server rejects the request with a 400 (Bad Request) error. Otherwise, the server checks whether it can satisfy the request (meaning it can allocate a relayed transport address as described below). If it can't, the server rejects the request with a 508 (Insufficient Capacity) error ๐ - The server checks if the request contains an
ADDITIONAL-ADDRESS-FAMILYattribute. If yes, and the attribute value is 0x01 (IPv4 address family), the server rejects the request with a 400 (Bad Request) error. Otherwise, the server checks whether it can allocate relayed transport addresses of both address types. If it can't satisfy the request, the server rejects it with a 508 (Insufficient Capacity) error. If the server can only partly meet the request, meaning it can allocate just one relayed transport address of one specific address type, it includes anADDRESS-ERROR-CODEattribute in the success response to tell the client why the request was only partly fulfilled. The error code value signaled in theADDRESS-ERROR-CODEattribute could be 440 (Address Family not Supported) or 508 (Insufficient Capacity). If the server can fully meet the request, then it allocates one IPv4 and one IPv6 relay address and returns an Allocate success response containing the relayed transport addresses assigned to the dual allocation in twoXOR-RELAYED-ADDRESSattributes ๐ฏโโ๏ธ - At any point, the server MAY choose to reject the request with a 486 (Allocation Quota Reached) error if it feels the client is trying to go over some locally defined allocation quota. The server is free to define this quota any way it likes, but it SHOULD define it based on the username used to authenticate the request, and not on the client's transport address ๐ซ
- Also, at any point, the server MAY choose to reject the request with a 300 (Try Alternate) error if it wants to redirect the client to a different server. The use of this error code and attribute follows the specification in [RFC8489] ๐
If all the checks pass, the server creates the allocation โจ The 5-tuple is set to the 5-tuple from the Allocate request, while the list of permissions and the list of channels both start out empty ๐ฅฐ
The server chooses a relayed transport address for the allocation as follows:
- If the request has a RESERVATION-TOKEN attribute, the server uses the previously reserved transport address that matches the token, as long as it's still available. โจ The reservation is server-wide, not tied to one allocation, because the Allocate request carrying the
RESERVATION-TOKENuses a different 5-tuple than the request that made the reservation. That 5-tuple can be any allowed one: a different client IP address and port, a different transport protocol, or even a different server IP address and port (as long as that server address and port are ones where the server is listening for TURN requests) ๐ฆ - If the request has an EVEN-PORT attribute with the R bit set to 0, the server allocates a relayed transport address with an even port number. ๐ธ
- If the request has an EVEN-PORT attribute with the R bit set to 1, the server looks for a pair of port numbers N and N+1 on the same IP address, where N is even. Port N is used in the current allocation, and the relayed transport address with port N+1 gets a token and is reserved for a future allocation. The server MUST hold this reservation for at least 30 seconds and MAY choose to hold longer (for example, until the allocation with port N expires). Then the server puts the token in a
RESERVATION-TOKENattribute in the success response. ๐ - Otherwise, the server allocates any available relayed transport address. ๐
In all cases, the server SHOULD only allocate ports from the range 49152 - 65535 (the Dynamic and/or Private Port range [PORT-NUMBERS]), unless the TURN server application knows, through some means not specified here, that other applications on the same host as the TURN server application won't be affected by allocating ports outside that range. This is often true when the TURN server runs on a dedicated machine, or when any other apps on the machine allocate their ports before the TURN server starts. Either way, the TURN server SHOULD NOT allocate ports in the range 0 - 1023 (the Well-Known Port range), to discourage clients from using TURN to run standard services. ๐
NOTE: The use of randomized port assignments to avoid certain types of attacks is described in [RFC6056]. It is RECOMMENDED that a TURN server implement a randomized port assignment algorithm from [RFC6056]. This is especially applicable to servers that choose to pre-allocate a number of ports from the underlying OS and then later assign them to allocations; for example, a server may choose this technique to implement the EVEN-PORT attribute. ๐
The server works out the starting value of the time-to-expiry field like this. If the request has a LIFETIME attribute, the server computes the minimum of the client's proposed lifetime and the server's maximum allowed lifetime. If that computed value is greater than the default lifetime, the server uses the computed lifetime as the starting value of the time-to-expiry field. Otherwise, the server uses the default lifetime. It is RECOMMENDED that the server use a maximum allowed lifetime value of no more than 3600 seconds (1 hour). Servers that implement allocation quotas or charge users for allocations in some way may want a smaller maximum allowed lifetime (maybe as small as the default lifetime), so they can clear out orphaned allocations faster. Orphaned allocations are ones where the client has crashed or terminated, or the client connection has been lost for some reason. Also, the time-to-expiry gets recomputed with each successful Refresh request, so the value computed here only applies until the first refresh. โณ
Once the allocation is created, the server sends back a success response. The success response contains:
- An
XOR-RELAYED-ADDRESSattribute containing the relayed transport address, or twoXOR-RELAYED-ADDRESSattributes containing the relayed transport addresses. ๐ฆ - A
LIFETIMEattribute containing the current value of the time-to-expiry timer. โฐ - A
RESERVATION-TOKENattribute (if a second relayed transport address was reserved). ๐๏ธ - An
XOR-MAPPED-ADDRESSattribute containing the client's IP address and port (from the 5-tuple). ๐
NOTE: The XOR-MAPPED-ADDRESS attribute is included in the response as a convenience to the client. TURN itself doesn't use this value, but clients running ICE often need it, so they can skip doing an extra Binding transaction with some STUN server to find it out. ๐ง
The response (success or error) goes back to the client on the 5-tuple. ๐ฌ
NOTE: When the Allocate request is sent over UDP, [RFC8489] requires that the server handle the possible retransmissions of the request, so retransmissions don't cause multiple allocations to be created. Implementations may do this using the so-called "stateless stack approach" as follows. To detect retransmissions when the original request was successful in creating an allocation, the server can store the transaction id that created the request with the allocation data, and compare it with incoming Allocate requests on the same 5-tuple. Once such a request is detected, the server can stop parsing the request and immediately generate a success response. When building this response, the value of theLIFETIMEattribute can be taken from the time-to-expiry field in the allocate state data, even though this value may differ slightly from theLIFETIMEvalue originally returned. In addition, the server may need to store an indication of any reservation token returned in the original response, so that it can be returned in any retransmitted responses. For the case where the original request was unsuccessful in creating an allocation, the server may choose to do nothing special. Note, however, that there is a rare case where the server rejects the original request but accepts the retransmitted request (because conditions have changed in the brief time in between). If the client receives the first failure response, it will ignore the second (success) response and believe that an allocation was not created. An allocation created in this manner will eventually time out, since the client won't refresh it. Furthermore, if the client later retries with the same 5-tuple but a different transaction id, it will receive a 437 (Allocation Mismatch) error response, which will cause it to retry with a different 5-tuple. The server may use a smaller maximum lifetime value to minimize the lifetime of allocations "orphaned" in this manner. ๐ญ
7.3. Receiving an Allocate Success Response
If the client receives an Allocate success response, then it MUST check that the mapped address and the relayed transport address or addresses are part of an address family or families that the client understands and is prepared to handle. If these addresses aren't part of an address family or families the client is prepared to handle, then the client MUST delete the allocation (Section 8) and MUST NOT attempt to create another allocation on that server until it believes the mismatch has been fixed. ๐จ
Otherwise, the client creates its own copy of the allocation data structure to track what's happening on the server. In particular, the client needs to remember the actual lifetime received back from the server, rather than the value it sent in the request. The client must also remember the 5-tuple used for the request, and the username and password it used to authenticate the request, so it reuses them for subsequent messages. The client also needs to track the channels and permissions it sets up on the server. ๐๏ธ
If the client receives an Allocate success response but with an ADDRESS-ERROR-CODE attribute in the response, and the error code value in that attribute is 440 (Address Family not Supported), the client MUST NOT retry its request for the rejected address type. If the client receives an ADDRESS-ERROR-CODE attribute in the response, and the error code value in it is 508 (Insufficient Capacity), the client SHOULD wait at least 1 minute before trying to request any more allocations on this server for the rejected address type. โธ๏ธ
The client will probably want to send the relayed transport address to peers (using some method not specified here), so the peers can communicate with it. ๐ The client may also want to use the server-reflexive address it gets in the XOR-MAPPED-ADDRESS attribute in its ICE processing. โจ
7.4. Receiving an Allocate Error Response ๐จ
okay so this is the part where the server says "no bestie" and we have to figure out what to do next ๐ the vibe is totally different for every error code, so let's go one by one ๐
If the client gets an Allocate error response, what it does next depends on the exact error code it got back:
408 (Request timed out): ugh, the server is either having a moment or the client can't reach it over the transport it picked ๐ญ the client calls this transaction a fail, BUT it MAY totally try the Allocate request again over a different transport (like TCP instead of UDP) ๐ฆ
300 (Try Alternate): the server is basically like "hey, go ask THIS other server instead" ๐ง the client calls the current transaction a fail, but it SHOULD try the Allocate request with the alternate server before trying any other servers (like the ones found through DNS resolution procedures) โจ when it does, it follows the ALTERNATE-SERVER procedures from [RFC8489] ๐ธ
400 (Bad Request): the server thinks the request is malformed, rude ๐ the client calls the transaction a fail. The client MAY tell the user or operator, and it SHOULD NOT retry with this server until it believes the problem has been fixed ๐
401 (Unauthorized): okay so if the client already followed the long-term credential mechanism and STILL gets this, the server is straight up not accepting its credentials ๐ the client calls the transaction a fail and SHOULD notify the user or operator ๐ฃ it SHOULD NOT send any more requests to this server until it believes the problem is fixed ๐
403 (Forbidden): the request is valid, but the server is refusing to do it, probably because of admin restrictions ๐ โโ๏ธ the client calls the transaction a fail. It MAY notify the user or operator and SHOULD NOT retry the same request with this server until the problem is fixed ๐
420 (Unknown Attribute): so the client put a DONT-FRAGMENT attribute in the request, and the server said "idk what that is" and listed DONT-FRAGMENT in the UNKNOWN-ATTRIBUTES attribute ๐คทโโ๏ธ now the client knows this server doesn't support DONT-FRAGMENT ๐ซถ the client calls the transaction a fail, but it MAY retry the Allocate request without the DONT-FRAGMENT attribute ๐
437 (Allocation Mismatch): this one is giving "that 5-tuple is already taken" ๐ one way this happens is if a NAT gave out a mapped transport address that was used by another client that recently crashed ๐ the client calls the transaction a fail and SHOULD pick another client transport address and retry the Allocate request (with a different transaction id) ๐ it SHOULD try three different client transport addresses before giving up on this server ๐ once it gives up, it SHOULD NOT try to create another allocation on the server for 2 minutes โฐ
438 (Stale Nonce): the nonce is expired, so go check the long-term credential mechanism procedures in [RFC8489] ๐
440 (Address Family not Supported): the server doesn't support the address family the client asked for ๐ค if the client gets this, it MUST NOT retry the request. Period. ๐๐
441 (Wrong Credentials): the client shouldn't ever get this one for an Allocate request, weird ๐คจ the client MAY notify the user or operator and SHOULD NOT retry the same request with this server until the problem is fixed ๐ง
442 (Unsupported Transport Address): the client shouldn't get this for a UDP allocation request either ๐ the client MAY notify the user or operator and SHOULD NOT reattempt the request with this server until it believes the problem is fixed ๐ ๏ธ
486 (Allocation Quota Reached): the server is too full right now and can't make any more allocations with this username ๐ฉ the client calls the transaction a fail and SHOULD wait at least 1 minute before trying to make more allocations on the server โณ
508 (Insufficient Capacity): the server has no relayed transport addresses left, or none with the properties the client wants, or the one that got reserved isn't available anymore ๐ต the client calls the current operation a fail. If the client is using the EVEN-PORT or RESERVATION-TOKEN attribute, it MAY remove or change that attribute and try again right away ๐โโ๏ธ otherwise it SHOULD wait at least 1 minute before trying to make more allocations on this server ๐
Note that the error code values 486 and 508 tell an eavesdropper that a bunch of other users are on the server right now, kind of like the HTTP 503 response code ๐ but they don't reveal anything about who those users actually are ๐ซฃ
An unknown error response MUST be handled as described in [RFC8489]. ๐
- Refreshing an Allocation โจ
okay this section is all about the Refresh transaction ๐ it can do one of two things: (a) refresh an existing allocation and update its time-to-expiry, or (b) delete an existing allocation ๐
If a client wants to keep using an allocation, it MUST refresh it before it expires ๐ฑ It is suggested that the client refresh roughly 1 minute before expiry ๐ If a client is done with an allocation, it SHOULD explicitly delete it ๐งน A client MAY refresh an allocation at any time for other reasons ๐ธ
8.1. Sending a Refresh Request ๐ค
If the client wants to delete an allocation right now, it includes a LIFETIME attribute with a value of zero ๐ every other form of the request refreshes the allocation ๐
When refreshing a dual allocation, the client includes a REQUESTED-ADDRESS-FAMILY attribute for the address family type that should be refreshed ๐ If there's no REQUESTED-ADDRESS-FAMILY attribute, the request should be treated as applying to all current allocations ๐ซถ The client MUST only include a family type it previously allocated and hasn't deleted yet ๐ โโ๏ธ You can also delete just one allocation type by setting that Refresh request's lifetime to zero ๐ Deleting a single allocation destroys any permissions or channels tied to that particular allocation, and it MUST NOT affect any permissions or channels tied to allocations for the other address family ๐ฆ
The Refresh transaction updates the time-to-expiry timer of an allocation โฐ If the client wants the server to set the timer to something other than the default lifetime, it includes a LIFETIME attribute with the requested value ๐ The server then computes a new time-to-expiry value the same way it does for an Allocate transaction, except that a requested lifetime of zero makes the server delete the allocation right away ๐
8.2. Receiving a Refresh Request ๐ฅ
When the server gets a Refresh request, it processes it as per Section 5 plus the specific rules mentioned here ๐ง
If the server gets a Refresh request with a REQUESTED-ADDRESS-FAMILY attribute and the attribute value doesn't match the address family of the allocation, the server MUST reply with a 443 (Peer Address Family Mismatch) Refresh error response ๐ซ
The server computes a value called the "desired lifetime" like this: if the request has a LIFETIME attribute and its value is zero, then the "desired lifetime" is zero ๐ซ Otherwise, if the request has a LIFETIME attribute, the server computes the minimum of the client's requested lifetime and the server's maximum allowed lifetime โ๏ธ If that computed value is greater than the default lifetime, then the "desired lifetime" is the computed value ๐ Otherwise, the "desired lifetime" is the default lifetime ๐ฏ
What happens next depends on the "desired lifetime" value:
- If the "desired lifetime" is zero, then the request succeeds and the allocation is deleted ๐๐๏ธ
- If the "desired lifetime" is non-zero, then the request succeeds and the allocation's time-to-expiry is set to the "desired lifetime" โณโจ
If the request succeeds, the server sends a success response containing:
- A LIFETIME attribute containing the current value of the time-to-expiry timer ๐
NOTE: A server doesn't need to do anything special to make Refresh requests idempotent over UDP using the "stateless stack approach" ๐ง Retransmitted Refresh requests with a non-zero "desired lifetime" will just refresh the allocation ๐ A retransmitted Refresh request with a zero "desired lifetime" will cause a 437 (Allocation Mismatch) response if the allocation has already been deleted, but the client will treat this as equivalent to a success response (see below) ๐
8.3. Receiving a Refresh Response ๐ฌ
If the client gets a success response to its Refresh request with a non-zero lifetime, it updates its copy of the allocation data structure with the time-to-expiry value in the response โ If the client gets a 437 (Allocation Mismatch) error response to its request to refresh the allocation, it SHOULD consider the allocation no longer exists ๐ป If the client gets a 438 (Stale Nonce) error to its request to refresh the allocation, it SHOULD reattempt the request with the new nonce value ๐
If the client gets a 437 (Allocation Mismatch) error response to a request to delete the allocation, then the allocation no longer exists and it SHOULD consider its request as having effectively succeeded ๐ฅณ๐
9. Permissions โจ
Okay bestie, so here's the permission system, and it's giving bouncer at the club ๐ For each allocation, the server keeps a list of zero or more permissions. Each permission is made of an IP address plus a time-to-expiry. While a permission exists, every peer using that IP address is allowed to send data to the client ๐ฆ The time-to-expiry is just the number of seconds left until the permission expires. Within an allocation, a permission is uniquely identified by its IP address, so no duplicates, periodt ๐ซถ
The client can make the server install or refresh a permission for an IP address by sending either CreatePermission requests or ChannelBind requests ๐ This can go one of two ways:
- If there's no permission for that IP address yet, a permission gets created with that IP address and a time-to-expiry equal to Permission Lifetime.
- If a permission for that IP address already exists, its time-to-expiry gets reset to Permission Lifetime.
The Permission Lifetime MUST be 300 seconds (= 5 minutes) โฐ
Each permission's time-to-expiry ticks down once per second until it hits zero. At that point the permission expires and gets deleted ๐
CreatePermission and ChannelBind requests can be freely intermixed on a permission ๐ A permission might get installed and/or refreshed with a CreatePermission request and then later refreshed with a ChannelBind request, or the other way around. Totally valid, no cap โจ
Here's how incoming traffic gets checked ๐ When a UDP datagram arrives at the relayed transport address for the allocation, the server pulls the source IP address out of the IP header. Then it compares that address with the IP address tied to each permission in the allocation's list. Only the addresses are compared, port numbers are not considered at all ๐ If there's no match, relaying is not permitted and the server silently discards the UDP datagram. If there's an exact match, the permission check counts as passed and the server keeps processing the datagram as specified elsewhere (Section 11.3).
Permissions for one allocation are totally unrelated to permissions for a different allocation, so they don't cross over ๐ง And if an allocation expires, all of its permissions expire right along with it ๐ญ
NOTE: Though TURN permissions expire after 5 minutes, many NATs deployed at the time of publication expire their UDP bindings considerably faster. Thus, an application using TURN will probably wish to send some sort of keep-alive traffic at a much faster rate. Applications using ICE should follow the keep-alive guidelines of ICE [RFC8445], and applications not using ICE are advised to do something similar. ๐ธ
10. CreatePermission โจ
Bestie, this section covers one of the two ways the client can install or refresh permissions on the server. This section describes one way: the CreatePermission request ๐
A CreatePermission request may be used together with either the Send mechanism in Section 11 or the Channel mechanism in Section 12 ๐ฆ
10.1. Forming a CreatePermission Request
The client who wants to install or refresh one or more permissions can send a CreatePermission request to the server ๐
When forming a CreatePermission request, the client MUST include at least one XOR-PEER-ADDRESS attribute and MAY include more than one such attribute. The IP address portion of each XOR-PEER-ADDRESS attribute holds the IP address that should get a permission installed or refreshed. The port portion of each XOR-PEER-ADDRESS attribute will be ignored, so it can be any arbitrary value ๐ The various XOR-PEER-ADDRESS attributes MAY appear in any order. The client MUST only include XOR-PEER-ADDRESS attributes with addresses of the same address family as the relayed transport address for the allocation. For dual allocations obtained using the ADDITIONAL-ADDRESS-FAMILY attribute, the client MAY include XOR-PEER-ADDRESS attributes with addresses of IPv4 and IPv6 address families ๐
10.2. Receiving a CreatePermission Request
When the server gets a CreatePermission request, it processes it as per Section 5 plus the specific rules mentioned here โจ
The message gets checked for validity first. The CreatePermission request MUST contain at least one XOR-PEER-ADDRESS attribute and MAY contain multiple such attributes. If no such attribute exists, or if any of these attributes are invalid, a 400 (Bad Request) error is returned. If the request is valid but the server can't satisfy it because of some capacity limit or similar, a 508 (Insufficient Capacity) error is returned ๐
If an XOR-PEER-ADDRESS attribute contains an address of an address family that's not the same as the relayed transport address's family for the allocation, the server MUST generate an error response with the 443 (Peer Address Family Mismatch) response code ๐ โโ๏ธ
The server MAY impose restrictions on the IP address allowed in the XOR-PEER-ADDRESS attribute. If a value isn't allowed, the server rejects the request with a 403 (Forbidden) error ๐ฅ
If the message is valid and the server is capable of carrying out the request, the server installs or refreshes a permission for the IP address in each XOR-PEER-ADDRESS attribute, as described in Section 9. The port portion of each attribute is ignored and may be any arbitrary value ๐ซถ
Then the server responds with a CreatePermission success response. There are no mandatory attributes in the success response ๐
NOTE: A server need not do anything special to implement idempotency of CreatePermission requests over UDP using the "stateless stack approach". Retransmitted CreatePermission requests will simply refresh the permissions. ๐
10.3. Receiving a CreatePermission Response
If the client receives a valid CreatePermission success response, it updates its data structures to indicate that the permissions have been installed or refreshed ๐ธ
11. Send and Data Methods ๐
TURN supports two mechanisms for sending and receiving data from peers. This section describes the use of the Send and Data mechanisms, while Section 12 describes the use of the Channel mechanism ๐ฆ
11.1. Forming a Send Indication
The client can use a Send indication to pass data to the server for relaying to a peer. A client may use a Send indication even if a channel is bound to that peer. However, the client MUST ensure that there is a permission installed for the IP address of the peer that the Send indication is being sent to. This stops a third party from using a TURN server to send data to arbitrary destinations ๐ซ
When forming a Send indication, the client MUST include an XOR-PEER-ADDRESS attribute and a DATA attribute. The XOR-PEER-ADDRESS attribute contains the transport address of the peer the data is going to, and the DATA attribute contains the actual application data to send to that peer ๐ฆ
The client MAY include a DONT-FRAGMENT attribute in the Send indication if it wants the server to set the DF bit on the UDP datagram sent to the peer ๐
11.2. Receiving a Send Indication
When the server receives a Send indication, it processes it as per Section 5 plus the specific rules mentioned here ๐
The message is checked for validity first. The Send indication MUST contain both an XOR-PEER-ADDRESS attribute and a DATA attribute. If one of these attributes is missing or invalid, the message is discarded. Note that the DATA attribute is allowed to contain zero bytes of data ๐
The Send indication may also contain the DONT-FRAGMENT attribute. If the server is unable to set the DF bit on outgoing UDP datagrams when this attribute is present, then the server acts as if the DONT-FRAGMENT attribute is an unknown comprehension-required attribute (and thus the Send indication is discarded) ๐
The server also checks that there is a permission installed for the IP address in the XOR-PEER-ADDRESS attribute. If no such permission exists, the message is discarded. Note that a Send indication never causes the server to refresh the permission โณ
The server MAY impose restrictions on the IP address and port values allowed in the XOR-PEER-ADDRESS attribute. If a value isn't allowed, the server silently discards the Send indication ๐คซ
If everything is OK, the server forms a UDP datagram as follows:
- the source transport address is the relayed transport address of the allocation, where the allocation is determined by the 5-tuple on which the Send indication arrived;
- the destination transport address is taken from the XOR-PEER-ADDRESS attribute;
- the data following the UDP header is the contents of the value field of the DATA attribute.
The handling of the DONT-FRAGMENT attribute (if present) is described in Sections 14 and 15 ๐ง
The resulting UDP datagram is then sent to the peer ๐ฆ
11.3. Receiving a UDP Datagram
When the server receives a UDP datagram at a currently allocated relayed transport address, it looks up the allocation associated with that relayed transport address. The server then checks whether the set of permissions for the allocation allows relaying the UDP datagram, as described in Section 9 ๐
If relaying is permitted, the server checks whether there is a channel bound to the peer that sent the UDP datagram (see Section 12). If a channel is bound, processing proceeds as described in Section 12.7 ๐
If relaying is permitted but no channel is bound to the peer, the server forms and sends a Data indication. The Data indication MUST contain both an XOR-PEER-ADDRESS and a DATA attribute. The DATA attribute is set to the value of the "data octets" field from the datagram, and the XOR-PEER-ADDRESS attribute is set to the source transport address of the received UDP datagram. The Data indication is then sent on the 5-tuple associated with the allocation ๐จ
11.4. Receiving a Data Indication
When the client receives a Data indication, it checks that the Data indication contains an XOR-PEER-ADDRESS attribute and discards the indication if it doesn't. The client SHOULD also check that the XOR-PEER-ADDRESS attribute value contains an IP address with which the client believes there is an active permission, and discard the Data indication otherwise ๐ก๏ธ
NOTE: The latter check protects the client against an attacker who somehow manages to trick the server into installing permissions not desired by the client. ๐จ
If the XOR-PEER-ADDRESS is present and valid, the client checks that the Data indication contains either a DATA attribute or an ICMP attribute, and discards the indication if it doesn't. Note that a DATA attribute is allowed to contain zero bytes of data. Processing of Data indications with an ICMP attribute is described in Section 11.6 ๐ซ
If the Data indication passes the above checks, the client delivers the data octets inside the DATA attribute to the application, along with an indication that they were received from the peer whose transport address is given by the XOR-PEER-ADDRESS attribute ๐
11.5. Receiving an ICMP Packet โจ
okay so when the server gets an ICMP packet, it first has to check two things ๐. The type has to be 3 or 11 for an ICMPv4 [RFC0792] packet, or 1, 2, or 3 for an ICMPv6 [RFC4443] packet. It also has to make sure the IP packet inside the ICMP payload has a UDP header. If either of those fails, the packet is silently dropped ๐ซฅ. If the UDP header is there, the server pulls out the source and destination IP address and UDP port info.
Next, the server looks for the allocation whose relayed transport address matches the encapsulated packet's source IP address and UDP port. No match? Silently dropped, bye ๐. If there is one, the server checks whether that allocation's permissions allow relaying this ICMP packet. Here's the twist ๐: for ICMP packets, the source IP address MUST NOT be checked against the permissions list the way it would be for UDP packets. Instead, the server grabs the destination IP address from the encapsulated IP header and compares it to the IP address of each permission on the allocation. No match means relaying isn't permitted, and the server silently discards the ICMP packet. Also, only addresses get compared. Port numbers don't count here ๐ .
If relaying is permitted, the server forms and sends a Data indication. This indication MUST contain both an XOR-PEER-ADDRESS and an ICMP attribute. The ICMP attribute gets set to the type and code field values from the ICMP packet. The IP address part of XOR-PEER-ADDRESS is set to the destination IP address in the encapsulated IP header. Now, at the time this spec was written, socket APIs on some operating systems don't hand the destination port in the encapsulated UDP header to apps without superuser privileges ๐ญ. So if the server can see that destination port, the port part of XOR-PEER-ADDRESS gets set to it. If not, the port part is set to zero. Finally, the Data indication gets sent on the 5-tuple tied to the allocation ๐.
๐ซถ Implementation Note: New ICMP types or codes can be defined in future specifications. If the server receives an ICMP error packet, and the new type or code field can help the client make use of the ICMP error notification and generate feedback to the application layer, the server sends the Data indication with an ICMP attribute conveying the new ICMP type or code.
11.6. Receiving a Data Indication with an ICMP Attribute ๐
when the client gets a Data indication carrying an ICMP attribute, it first checks that the indication has an XOR-PEER-ADDRESS attribute. No XOR-PEER-ADDRESS? The client discards the indication. The client SHOULD also check that the IP address in the XOR-PEER-ADDRESS value has an active permission, and discard the Data indication if it doesn't ๐.
If the Data indication passes those checks, the client tells the application about the error condition ๐จ. It also says the error came from the peer whose transport address is in the XOR-PEER-ADDRESS attribute. The app can figure out what the type and code values in the ICMP attribute mean by looking at the family field in XOR-PEER-ADDRESS ๐ง .
12. Channels ๐ฆ
Channels are a way for the client and server to send application data using ChannelData messages, which have way less overhead than Send and Data indications. Lowkey the glow-up you want ๐.
The ChannelData message (see Section 12.4) starts with a two-byte field that carries the channel number. Here's how the values of that field get allocated ๐:
+------------------------+--------------------------------------+
| 0x0000 through 0x3FFF: | These values can never be used for |
| | channel numbers. |
+------------------------+--------------------------------------+
| 0x4000 through 0x4FFF: | These values are the allowed channel |
| | numbers (4096 possible values). |
+------------------------+--------------------------------------+
| 0x5000 through 0xFFFF: | Reserved (For DTLS-SRTP multiplexing |
| | collision avoidance, see [RFC7983]). |
+------------------------+--------------------------------------+
Table 2
Note that the channel number range is not backwards compatible with [RFC5766]. That could block a client that follows RFC 5766 from setting up channel bindings with a TURN server that follows this spec ๐.
According to [RFC7983], you can tell ChannelData messages apart from other multiplexed protocols by looking at the first byte of the message ๐:
+------------+------------------------------------------------------+
| [0..3] | STUN |
+------------+------------------------------------------------------+
| [16..19] | ZRTP |
+------------+------------------------------------------------------+
| [20..63] | DTLS |
+------------+------------------------------------------------------+
| [64..79] | TURN Channel |
+------------+------------------------------------------------------+
| [128..191] | RTP/RTCP |
+------------+------------------------------------------------------+
| Others | Reserved; MUST be dropped |
| | and an alert MAY be logged |
+------------+------------------------------------------------------+
Table 3
Reserved values might get used by other protocols in the future ๐ฎ. When the client uses channel binding, it MUST comply with the demultiplexing scheme we just talked about.
Channel bindings are always started by the client ๐. The client can bind a channel to a peer at any time during the allocation's lifetime. It can bind before exchanging data with that peer, or after trading some data with it (using Send and Data indications) for a while. It can also just never bind a channel to that peer, totally valid. And it can bind channels to some peers while skipping others ๐ .
Channel bindings are specific to an allocation. So using a channel number or peer transport address in one allocation has zero impact on using it in a different one โจ. If an allocation expires, all of its channel bindings expire with it.
A channel binding has three parts:
- a channel number;
- a transport address (of the peer); and
- A time-to-expiry timer.
Inside an allocation, a channel binding is uniquely identified by either its channel number or the peer's transport address. So the same channel can't be bound to two different transport addresses, and the same transport address can't be bound to two different channels ๐ โโ๏ธ.
A channel binding lasts 10 minutes unless it gets refreshed. Refreshing means the server receives a ChannelBind request that rebinds the channel to the same peer, and that resets the time-to-expiry timer back to 10 minutes โฐ.
When a channel binding expires, the channel becomes unbound ๐. Once it's unbound, the channel number can be bound to a different transport address, and the transport address can be bound to a different channel number. To avoid race conditions, the client MUST wait 5 minutes after the binding expires before it tries to bind the channel number to a different transport address, or the transport address to a different channel number. Patience is a whole vibe ๐งโโ๏ธ.
When the client binds a channel to a peer, it SHOULD be ready to receive ChannelData messages on that channel from the server as soon as it has sent the ChannelBind request. Over UDP, the client can even get ChannelData messages from the server before it gets a ChannelBind success response ๐ฌ.
Going the other way, the client MAY choose to send ChannelData messages before it gets the ChannelBind success response. But that's risky ๐ฌ. If the ChannelBind request doesn't succeed for some reason (like a packet getting lost if the request went over UDP, or the server being unable to fulfill the request), the server might drop those ChannelData messages. A client that wants to play it safe should either queue the data or use Send indications until the channel binding is confirmed ๐ก๏ธ.
12.1. Sending a ChannelBind Request ๐
A channel binding gets created or refreshed using a ChannelBind transaction. A ChannelBind transaction also creates or refreshes a permission towards the peer (see Section 9) ๐.
To kick off the ChannelBind transaction, the client forms a ChannelBind request. The channel to be bound goes in a CHANNEL-NUMBER attribute, and the peer's transport address goes in an XOR-PEER-ADDRESS attribute. Section 12.2 explains the restrictions on these attributes ๐. The client MUST only include an XOR-PEER-ADDRESS attribute with an address from the same address family as the relayed transport address for the allocation. No mixing families, bestie ๐ โโ๏ธ.
Rebinding a channel to the same transport address it's already bound to is a way to refresh both the channel binding and the matching permission, and you don't have to send any data to the peer to do it ๐ธ. Just keep in mind that permissions need refreshing more often than channels do โ ๏ธ.
12.2. Receiving a ChannelBind Request โจ
okay so when the server gets a ChannelBind request, it runs through everything in Section 5 first, plus the extra rules I'm about to spill ๐
The server checks these things:
- the request has both a CHANNEL-NUMBER and an XOR-PEER-ADDRESS attribute ๐
- the channel number sits somewhere in
0x4000through0x4FFF(inclusive) ๐ฆ - the channel number isn't already bound to a different transport address (the same transport address is totally fine ๐ซถ)
- the transport address isn't already bound to a different channel number
If any of those fail, the server replies with a 400 (Bad Request) error. If the XOR-PEER-ADDRESS attribute has an address family that doesn't match the relayed transport address for the allocation, the server MUST generate an error response with the 443 (Peer Address Family Mismatch) response code. not the vibe ๐
The server MAY put limits on the IP address and port values allowed in XOR-PEER-ADDRESS. If a value isn't allowed, the server rejects the request with a 403 (Forbidden) error ๐
If the request is valid but the server can't handle it because of a capacity limit or something similar, it replies with a 508 (Insufficient Capacity) error.
Otherwise, the server sends back a ChannelBind success response. A successful ChannelBind response has no required attributes, so it's giving minimalism ๐ธ
When the server can satisfy the request, it creates or refreshes the channel binding using the channel number in CHANNEL-NUMBER and the transport address in XOR-PEER-ADDRESS. It also installs or refreshes a permission for the IP address in XOR-PEER-ADDRESS, as described in Section 9 โจ
NOTE: A server doesn't need to do anything special to make ChannelBind requests idempotent over UDP using the "stateless stack approach." ๐ง Retransmitted ChannelBind requests just refresh the channel binding and the matching permission. Also, the client must wait 5 minutes before binding a channel number or peer address that was previously bound to a different channel. That way, a transaction can't fail at first and then succeed on a retransmission. iykyk ๐
12.3. Receiving a ChannelBind Response ๐
When the client gets a ChannelBind success response, it updates its data structures to say the channel binding is now active. It also records that the matching permission has been installed or refreshed. so organized ๐
If the client gets a ChannelBind failure response that says the channel info is out of sync between client and server (like an unexpected 400 "Bad Request" response), then it is RECOMMENDED that the client immediately delete the allocation and start fresh with a new one. bestie, that's a hard reset, and it's honestly the healthiest move ๐ซถ
12.4. The ChannelData Message ๐ฆ
The ChannelData message carries application data between the client and the server. Here's the format:
0 1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Channel Number | Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
/ Application Data /
/ /
| |
| +-------------------------------+
| |
+-------------------------------+
Figure 5
The Channel Number field says which channel the data is traveling on, which also tells you the address of the peer sending or receiving it. Main character info ๐
The Length field is the number of bytes in the application data field. It doesn't count the ChannelData header. Also, 0 is a valid length, so an empty payload is legit ๐ง
The Application Data field holds the data the client is sending to the peer, or the data the peer is sending back to the client. ๐
12.5. Sending a ChannelData Message ๐
Once a client has bound a channel to a peer, whenever the client has data for that peer, it can use either a ChannelData message or a Send indication. The client isn't obligated to use the channel even when it exists, and it can freely mix the two message types when sending data to the peer. Total flexibility, no cap โจ The server, on the other hand, MUST use the ChannelData message if a channel has been bound to the peer. And the server uses a Data indication to signal the XOR-PEER-ADDRESS and ICMP attributes to the client, even if a channel is bound to the peer. Different rules for the server, lowkey ๐
The fields of the ChannelData message get filled in as described in Section 12.4.
Over TCP and TLS-over-TCP, the ChannelData message MUST be padded to a multiple of four bytes so that the following messages stay aligned. The padding isn't counted in the ChannelData length field, so the actual size of a ChannelData message (padding included) is (4 + Length) rounded up to the nearest multiple of 4 (see Section 14 of [RFC8489]). Over UDP, padding isn't required, but it MAY be included ๐ธ
The ChannelData message is then sent on the 5-tuple associated with the allocation. ๐ซถ
12.6. Receiving a ChannelData Message ๐
The receiver uses the first byte to tell ChannelData apart from other multiplexed protocols, as described in Table 3. If the message uses a value in the reserved range (0x5000 through 0xFFFF), it gets silently discarded ๐
If a ChannelData message arrives in a UDP datagram, and that datagram is too short to hold the claimed length of the ChannelData message (meaning the UDP header length field value is less than the ChannelData header length field value + 4 + 8), the message is silently discarded ๐
If the ChannelData message is received over TCP or TLS-over-TCP, its actual length is as described in Section 12.5.
If the ChannelData message is received on a channel that isn't bound to any peer, it gets silently discarded.
On the client, it is RECOMMENDED that the client discard the ChannelData message if it believes there's no active permission towards the peer. On the server, receiving a ChannelData message MUST NOT refresh either the channel binding or the permission towards the peer. no refreshing off the vibes alone ๐ฆ
On the server, if no errors are detected, the server relays the application data to the peer by forming a UDP datagram like this:
- the source transport address is the relayed transport address of the allocation. The allocation is determined by the 5-tuple the ChannelData message arrived on. ๐ง
- the destination transport address is the transport address the channel is bound to.
- the data after the UDP header is the contents of the ChannelData message's data field.
The resulting UDP datagram then gets sent to the peer. If the Length field in the ChannelData message is 0, there's no data in the UDP datagram, but the datagram still gets formed and sent (Section 4.1 of [RFC6263]) ๐
12.7. Relaying Data from the Peer ๐
When the server receives a UDP datagram on the relayed transport address for an allocation, it processes it as described in Section 11.3. If that section says a ChannelData message should be sent (because a channel is bound to the peer that sent the UDP datagram), then the server forms and sends a ChannelData message as described in Section 12.5 โจ
When the server receives an ICMP packet, it processes it as described in Section 11.5. ๐
13. Packet Translations ๐ฆ
This section covers IPv4-to-IPv6, IPv6-to-IPv4, and IPv6-to-IPv6 translations. The requirements for translating the IP addresses and port numbers of packets are described above. The following sections say how to translate the other header fields ๐ซถ
As discussed in Section 3.6, translations in TURN are designed so that a TURN server can run as an application in user space under commonly available operating systems, without needing special privileges. The translations in the following sections follow that principle ๐
The descriptions below have two parts: a preferred behavior and an alternate behavior. The server SHOULD implement the preferred behavior. But if that's not possible for a particular field, the server MUST implement the alternate behavior and MUST NOT do anything else, for the reasons detailed in [RFC7915]. The TURN server relies only on the DF bit in the IPv4 header and the Fragment header in the IPv6 header to handle fragmentation, using the approach described in [RFC7915]. It does not rely on the DONT-FRAGMENT attribute. Ignoring the DONT-FRAGMENT attribute only applies to UDP-to-UDP relay, not TCP-to-UDP relay ๐ธ
13.1. IPv4-to-IPv6 Translations ๐
Time to Live (TTL) field
Preferred Behavior: As specified in Section 4 of [RFC7915].
Alternate Behavior: Set the outgoing value to the default for outgoing packets. ๐ง
Traffic Class
Preferred behavior: As specified in Section 4 of [RFC7915].
Alternate behavior: The TURN server sets the Traffic Class to the default value for outgoing packets. ๐
Flow Label
Preferred behavior: The TURN server can use the 5-tuple of relayed transport address, peer transport address, and UDP protocol number to identify each flow. It can then generate and set the flow label value in the IPv6 packet, as discussed in Section 3 of [RFC6437]. If the TURN server can't generate the flow label value from the IPv6 packet's 5-tuple, it sets the Flow label to zero. ๐ฆ
Alternate behavior: The alternate behavior is the same as the preferred behavior for a TURN server that doesn't support flow labels. ๐
Hop Limit
Preferred behavior: As specified in Section 4 of [RFC7915].
Alternate behavior: The TURN server sets the Hop Limit to the default value for outgoing packets. ๐
Fragmentation
Preferred behavior: As specified in Section 4 of [RFC7915].
Alternate behavior: The TURN server assembles incoming fragments. The TURN server follows its default behavior to send outgoing packets.
For both preferred and alternate behavior, the DONT-FRAGMENT attribute MUST be ignored by the server. ๐
Extension Headers
Preferred behavior: The outgoing packet uses the system defaults for IPv6 extension headers, except for the Fragment header as described above.
Alternate behavior: Same as preferred. โจ
13.2. IPv6-to-IPv6 Translations
Flow Label
NOTE: Okay bestie, the TURN server needs to remember that it's juggling two different IPv6 flows ๐ฆ So the Flow label [RFC6437] SHOULD NOT get copied over during the translation ๐
โโ๏ธ
Preferred behavior: The TURN server can use the 5-tuple of the relayed transport address, the peer transport address, and the UDP protocol number to tell each flow apart. Then it can generate and set the Flow label in the IPv6 packet, as discussed in Section 3 of [RFC6437] โจ If the TURN server can't generate the Flow label value from the IPv6 packet's 5-tuple, it sets the Flow label to zero ๐ธ
Alternate behavior: This is the same as the preferred behavior, but for a TURN server that doesn't support flow labels ๐ซถ
Hop Limit
Preferred behavior: The TURN server acts like a regular router here. It decrements the Hop Limit and generates an ICMPv6 error if the value reaches zero ๐
Alternate behavior: The TURN server sets the Hop Limit to the default value for outgoing packets ๐
Fragmentation
Preferred behavior: Okay, this one has a few scenarios, so let's go one by one ๐ง
If the incoming packet didn't include a Fragment header and the outgoing packet size doesn't exceed the outgoing link's MTU, the TURN server sends the outgoing packet without a Fragment header ๐
If the incoming packet didn't include a Fragment header and the outgoing packet size does exceed the outgoing link's MTU, the TURN server drops the outgoing packet. Then it sends an ICMP message of type 2 code 0 ("Packet too big") back to the sender of the incoming packet ๐ญ If that ICMPv6 "Packet too big" message is being sent to the peer, the TURN server SHOULD reduce the MTU reported in the ICMP message by 48 bytes, to make room for the overhead of a Data indication ๐
If the incoming packet included a Fragment header and the outgoing packet size (with a Fragment header included) doesn't exceed the outgoing link's MTU, the TURN server sends the outgoing packet with a Fragment header. It sets the fields of the Fragment header as appropriate for a packet originating from the server โจ
If the incoming packet included a Fragment header and the outgoing packet size exceeds the outgoing link's MTU, the TURN server MUST fragment the outgoing packet into fragments of no more than 1280 bytes ๐ฅ It also sets the fields of the Fragment header as appropriate for a packet originating from the server ๐
Alternate behavior: The TURN server assembles incoming fragments, then follows its default behavior to send outgoing packets ๐ฆ
For both preferred and alternate behavior, the DONT-FRAGMENT attribute MUST be ignored by the server. ๐
Extension Headers
Preferred behavior: The outgoing packet uses the system defaults for IPv6 extension headers, except for the Fragment header as described above ๐
Alternate behavior: Same as preferred ๐ธ
13.3. IPv6-to-IPv4 Translations
Type of Service and Precedence
Preferred behavior: As specified in Section 5 of [RFC7915] ๐
Alternate behavior: The TURN server sets the Type of Service and Precedence to the default value for outgoing packets ๐
Time to Live
Preferred behavior: As specified in Section 5 of [RFC7915] ๐ฆ
Alternate behavior: The TURN server sets the Time to Live to the default value for outgoing packets ๐ซถ
Fragmentation
Preferred behavior: As specified in Section 5 of [RFC7915] โจ On top of that, when the outgoing packet's size exceeds the outgoing link's MTU, the TURN server needs to generate an ICMP error (ICMPv6 "Packet too big") that reports the MTU size ๐ญ If the ICMPv4 packet (Destination Unreachable (Type 3) with Code 4) is being sent to the peer, the TURN server SHOULD reduce the MTU reported in the ICMP message by 48 bytes, to make room for the overhead of a Data indication ๐
Alternate behavior: The TURN server assembles incoming fragments, then follows its default behavior to send outgoing packets ๐ง
For both preferred and alternate behavior, the DONT-FRAGMENT attribute MUST be ignored by the server. ๐
14. UDP-to-UDP Relay โจ
This section is all about how the server sets various fields in the IP header for UDP-to-UDP relay, going from the client to the peer or the other way around ๐ These descriptions apply (a) when the server sends a UDP datagram to the peer, or (b) when the server sends a Data indication or ChannelData message to the client over UDP transport. They do not apply to TURN messages sent over TCP or TLS transport from the server to the client ๐
โโ๏ธ
The descriptions below come in two parts: a preferred behavior and an alternate behavior. The server SHOULD implement the preferred behavior ๐ But if that isn't possible for a particular field, then it SHOULD implement the alternative behavior instead ๐ซถ
Differentiated Services Code Point (DSCP) field [RFC2474]
Preferred Behavior: Set the outgoing value to the incoming value, unless the server includes a differentiated services classifier and marker [RFC2474] ๐
Alternate Behavior: Set the outgoing value to a fixed value, which is Best Effort by default unless it's configured otherwise ๐ธ
In both cases, if the server is immediately adjacent to a differentiated services classifier and marker, then DSCP MAY be set to any arbitrary value in the direction towards the classifier ๐ฆ
Explicit Congestion Notification (ECN) field [RFC3168]
Preferred Behavior: Set the outgoing value to the incoming value. The server may perform Active Queue Management, and in that case it SHOULD behave as an ECN-aware router [RFC3168] and can mark traffic with Congestion Experienced (CE) instead of dropping the packet ๐ง The use of ECT(1) is subject to experimental usage [RFC8311] ๐ฌ
Alternate Behavior: Set the outgoing value to Not-ECT (=0b00) ๐
IPv4 Fragmentation fields (applicable only for IPv4-to-IPv4 relay)
Preferred Behavior: When the server sends a packet to a peer in response to a Send indication containing the DONT-FRAGMENT attribute, set the outgoing UDP packet to not fragment โจ In all other cases, when sending an outgoing packet containing application data (for example a Data indication, a ChannelData message, or a Send indication that doesn't include the DONT-FRAGMENT attribute), copy the DF bit from the DF bit of the incoming packet that contained the application data ๐
Set the other fragmentation fields (Identification, More Fragments, Fragment Offset) as appropriate for a packet originating from the server ๐
Alternate Behavior: Same as the preferred behavior, except that it always assumes the incoming DF bit is 0 ๐
In both the preferred and alternate behaviors, the resulting packet may be too large for the outgoing link. If that happens, then the normal fragmentation rules apply [RFC1122] ๐ญ
IPv4 Options
Preferred Behavior: The outgoing packet uses the system defaults for IPv4 options ๐
Alternate Behavior: Same as preferred โจ
15. TCP-to-UDP Relay โจ
This section describes how the server sets various fields in the IP header for TCP-to-UDP relay from the client to the peer ๐ฆ These descriptions apply when the server sends a UDP datagram to the peer. Heads up, the server does not do per-packet translation for TCP-to-UDP relaying ๐
Multipath TCP [TCP-EXT] is not supported by this version of TURN, because TCP multipath isn't used by either SIP or WebRTC [RFC7478] for media or non-media data ๐ โโ๏ธ A TCP connection between the TURN client and server can use the TCP Authentication Option (TCP-AO) [RFC5925], but UDP doesn't offer a similar type of authentication, though it might be added in the future [UDP-OPT] ๐ Even if both TCP-AO and UDP authentication were used between the TURN client and server, it wouldn't change the end-to-end security properties of the application payload being relayed ๐ญ So applications using TURN will need to secure their application data end to end, for example with Secure Real-time Transport Protocol (SRTP) for RTP applications ๐ซถ Also, the TCP-AO option obsoletes the TCP MD5 option ๐
Unlike UDP, TCP without the TCP Fast Open extension [RFC7413] doesn't support 0-RTT session resumption ๐ธ The TCP user timeout [RFC5482] equivalent for application data relayed by TURN is the use of the RTP control protocol (RTCP) ๐ง As a reminder, RTCP is a fundamental and integral part of RTP ๐
The descriptions below come in two parts: a preferred behavior and an alternate behavior. The server SHOULD implement the preferred behavior ๐ But if that isn't possible for a particular field, then it SHOULD implement the alternative behavior instead ๐ซถ
For the UDP datagram sent to the peer based on a Send Indication or ChannelData message arriving at the TURN server over a TCP transport, the server sets various fields in the IP header as follows ๐
Differentiated Services Code Point (DSCP) field [RFC2474]
Preferred Behavior: The TCP connection can only use a single DSCP, so inter-flow differentiation isn't possible (see Section 5.1 of [RFC7657]) ๐ฆ The server sets the outgoing value to the DSCP used by the TCP connection, unless the server includes a differentiated services classifier and marker [RFC2474] โจ
Alternate Behavior: Set the outgoing value to a fixed value, which is Best Effort by default unless it's configured otherwise ๐ธ
In both cases, if the server is immediately adjacent to a differentiated services classifier and marker, then DSCP MAY be set to any arbitrary value in the direction towards the classifier ๐
Explicit Congestion Notification (ECN) field [RFC3168]
Preferred Behavior: No mechanism is defined to indicate what ECN value should be used for the outgoing UDP datagrams of an allocation, so set the outgoing value to Not-ECT (=0b00) ๐
Alternate Behavior: Same as preferred ๐
IPv4 Fragmentation fields (applicable only for IPv4-to-IPv4 relay)
Preferred Behavior: When the server sends a packet to a peer in response to a Send indication containing the DONT-FRAGMENT attribute, set the outgoing UDP packet to not fragment ๐ฅ In all other cases, when sending an outgoing UDP packet containing application data (for example a Data indication, a ChannelData message, or a Send indication without the DONT-FRAGMENT attribute), set the DF bit in the outgoing IP header to 0 ๐
Alternate Behavior: Same as preferred ๐
IPv6 Fragmentation fields
Preferred Behavior: If the TCP traffic arrives over IPv6, the server relies on the presence of the DONT-FRAGMENT attribute in the Send indication to set the outgoing UDP packet to not fragment ๐ง
Alternate Behavior: Same as preferred ๐
IPv4 Options
Preferred Behavior: The outgoing packet uses the system defaults for IPv4 options ๐ฆ
Alternate Behavior: Same as preferred ๐
16. UDP-to-TCP Relay ๐ธ
okay so this section is about how the server sets the IP header fields when it relays stuff from the peer to the client, but only when the client is on TCP or TLS ๐ the server does NOT do per-packet translation for UDP-to-TCP relaying, so it's not rewriting every single packet, bestie ๐
the descriptions below come in two flavors: a preferred behavior and an alternate behavior. the server SHOULD do the preferred one ๐ but if that's not possible for a given field, then it SHOULD do the alternate one instead โจ
the TURN server sets the IP header fields in the TCP packets on a per-connection basis for that TCP connection, like this:
Differentiated Services Code Point (DSCP) field [RFC2474]
- Preferred Behavior: Ignore the incoming DSCP value. When TCP is used between the client and the server, a single DSCP should be used for all traffic on that TCP connection. Note, TURN/ICE occurs before application data is exchanged. ๐ฆ
- Alternate Behavior: Same as preferred.
Explicit Congestion Notification (ECN) field [RFC3168]
- Preferred Behavior: Ignore; ECN signals are dropped in the TURN server for the incoming UDP datagrams from the peer. ๐
- Alternate Behavior: Same as preferred.
Fragmentation
- Preferred Behavior: Any fragmented packets are reassembled in the server and then forwarded to the client over the TCP connection. ICMP messages resulting from the UDP datagrams sent to the peer are processed by the server as described in Section 11.5 and forwarded to the client using TURN's mechanism for relevant ICMP types and codes. ๐ง
- Alternate Behavior: Same as preferred.
Extension Headers
- Preferred behavior: The outgoing packet uses the system defaults for IPv6 extension headers. ๐
- Alternate behavior: Same as preferred.
IPv4 Options
- Preferred Behavior: The outgoing packet uses the system defaults for IPv4 options. โญ
- Alternate Behavior: Same as preferred.
17. STUN Methods ๐
this section is the list of code points for the STUN methods defined in this spec ๐ the actual semantics live elsewhere in the document, so go look there if you want the juicy details ๐
+-------+------------------+------------------------+
| 0x003 | Allocate | (only request/response |
| | | semantics defined) |
+-------+------------------+------------------------+
| 0x004 | Refresh | (only request/response |
| | | semantics defined) |
+-------+------------------+------------------------+
| 0x006 | Send | (only indication |
| | | semantics defined) |
+-------+------------------+------------------------+
| 0x007 | Data | (only indication |
| | | semantics defined) |
+-------+------------------+------------------------+
| 0x008 | CreatePermission | (only request/response |
| | | semantics defined) |
+-------+------------------+------------------------+
| 0x009 | ChannelBind | (only request/response |
| | | semantics defined) |
+-------+------------------+------------------------+
Table 4
18. STUN Attributes ๐
this STUN extension defines the following attributes, and honestly the table is giving everything ๐ญ
+--------+---------------------------+
| 0x000C | CHANNEL-NUMBER |
+--------+---------------------------+
| 0x000D | LIFETIME |
+--------+---------------------------+
| 0x0010 | Reserved (was BANDWIDTH) |
+--------+---------------------------+
| 0x0012 | XOR-PEER-ADDRESS |
+--------+---------------------------+
| 0x0013 | DATA |
+--------+---------------------------+
| 0x0016 | XOR-RELAYED-ADDRESS |
+--------+---------------------------+
| 0x0017 | REQUESTED-ADDRESS-FAMILY |
+--------+---------------------------+
| 0x0018 | EVEN-PORT |
+--------+---------------------------+
| 0x0019 | REQUESTED-TRANSPORT |
+--------+---------------------------+
| 0x001A | DONT-FRAGMENT |
+--------+---------------------------+
| 0x0021 | Reserved (was TIMER-VAL) |
+--------+---------------------------+
| 0x0022 | RESERVATION-TOKEN |
+--------+---------------------------+
| 0x8000 | ADDITIONAL-ADDRESS-FAMILY |
+--------+---------------------------+
| 0x8001 | ADDRESS-ERROR-CODE |
+--------+---------------------------+
| 0x8004 | ICMP |
+--------+---------------------------+
Table 5
some of these attributes have lengths that aren't multiples of 4 ๐ฅบ and by the STUN rules, any attribute whose length isn't a multiple of 4 bytes MUST be immediately followed by 1 to 3 padding bytes, so the next attribute (if there is one) starts on a 4-byte boundary (see [RFC8489]). padding is not optional drama, it's a must ๐
18.1. CHANNEL-NUMBER ๐ฆ
the CHANNEL-NUMBER attribute holds the number of the channel. its value is 4 bytes long and is made of a 16-bit unsigned integer followed by a two-octet RFFU (Reserved For Future Use) field. the RFFU field MUST be set to 0 on transmission and MUST be ignored on reception ๐ซถ
0 1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Channel Number | RFFU = 0 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 6
18.2. LIFETIME โณ
the LIFETIME attribute is how long the server will keep an allocation alive if nobody refreshes it. the TURN client can include LIFETIME with the lifetime it wants in Allocate and Refresh requests. its value is 4 bytes long and is a 32-bit unsigned integral value, the number of seconds left until expiration ๐ฐ๏ธ
18.3. XOR-PEER-ADDRESS ๐ธ
the XOR-PEER-ADDRESS attribute specifies the address and port of the peer as the TURN server sees it. (for example, the peer's server-reflexive transport address if the peer is behind a NAT.) it's encoded the same way as the XOR-MAPPED-ADDRESS attribute [RFC8489] โจ
18.4. DATA ๐
the DATA attribute is present in all Send indications. if the ICMP attribute is not present in a Data indication, it contains a DATA attribute. its value is variable length and holds the application data (aka the data that would come right after the UDP header if the data went straight between the client and the peer) ๐ the application data is equivalent to the "UDP user data" and does NOT include the "surplus area" defined in Section 4 of [UDP-OPT]. if the length of this attribute isn't a multiple of 4, then padding must be added after this attribute ๐ง
18.5. XOR-RELAYED-ADDRESS ๐
the XOR-RELAYED-ADDRESS attribute shows up in Allocate responses. it specifies the address and port that the server allocated to the client. it's encoded the same way as the XOR-MAPPED-ADDRESS attribute [RFC8489] ๐
18.6. REQUESTED-ADDRESS-FAMILY ๐
this attribute is used in Allocate and Refresh requests to specify the address type the client wants. its value is 4 bytes with the following format:
0 1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Family | Reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 7
Family: There are two values defined for this field, specified in Section 14.1 of [RFC8489]: 0x01 for IPv4 addresses and 0x02 for IPv6 addresses. ๐
Reserved: At this point, the 24 bits in the Reserved field MUST be set to zero by the client and MUST be ignored by the server. ๐ โโ๏ธ
18.7. EVEN-PORT ๐
this attribute lets the client ask that the port in the relayed transport address be even, and (optionally) that the server reserve the next-higher port number. its value is 1 byte long, formatted like this:
0
0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
|R| RFFU |
+-+-+-+-+-+-+-+-+
Figure 8
the value contains a single 1-bit flag:
R: If 1, the server is requested to reserve the next-higher port number (on the same IP address) for a subsequent allocation. If 0, no such reservation is requested. ๐ฅ
RFFU: Reserved For Future Use.
the RFFU field must be set to zero on transmission and ignored on reception.
since the length of this attribute is not a multiple of 4, padding must immediately follow this attribute. ๐ซ
18.8. REQUESTED-TRANSPORT ๐
this attribute is how the client requests a specific transport protocol for the allocated transport address. its value is 4 bytes with the following format:
0 1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Protocol | RFFU |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 9
the Protocol field specifies the desired protocol. the code points used in this field are taken from the ones allowed in the Protocol field of the IPv4 header and the NextHeader field of the IPv6 header [PROTOCOL-NUMBERS]. this spec only allows code point 17 (User Datagram Protocol) ๐ฆ
the RFFU field MUST be set to zero on transmission and MUST be ignored on reception. it's reserved for future uses ๐ท
18.9. DONT-FRAGMENT ๐
this attribute is how the client asks the server to set the DF (Don't Fragment) bit in the IP header when it relays the application data onward to the peer. it's also used for figuring out the server's capability in Allocate requests. this attribute has no value part, so the attribute length field is 0 ๐ง
18.10. RESERVATION-TOKEN ๐
the RESERVATION-TOKEN attribute holds a token that uniquely identifies a relayed transport address that the server is holding in reserve. the server includes this attribute in a success response to tell the client about the token, and then the client includes this attribute in a later Allocate request to ask the server to use that relayed transport address for the allocation ๐ฅน
its value is 8 bytes and contains the token value. โจ
18.11. ADDITIONAL-ADDRESS-FAMILY โจ
Okay bestie, this one is all about asking for a second address family ๐ฆ. Clients use it to request an IPv4 and IPv6 address type from a server. It's encoded the exact same way as REQUESTED-ADDRESS-FAMILY, so go peek at Section 18.6 ๐ซถ. The ADDITIONAL-ADDRESS-FAMILY attribute MAY be present in the Allocate request. In an Allocate request, the only valid value is 0x02 (IPv6 address), periodt ๐ .
18.12. ADDRESS-ERROR-CODE ๐
Servers use this attribute to explain why they didn't allocate the address family you asked for ๐. The value portion is variable length and looks like this:
0 1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Family | Reserved |Class| Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Reason Phrase (variable) ..
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 10
Family: There are two values for this field, defined in Section 14.1 of [RFC8489]: 0x01 for IPv4 addresses and 0x02 for IPv6 addresses. ๐
Reserved: At this point, the 13 bits in the Reserved field MUST be set to zero by the server and MUST be ignored by the client. ๐ง
Class: The Class represents the hundreds digit of the error code and is defined in Section 14.8 of [RFC8489]. ๐
Number: This 8-bit field contains the reason the server cannot allocate one of the requested address types. The error code values could be either 440 (Address Family not Supported) or 508 (Insufficient Capacity). The number representation is defined in Section 14.8 of [RFC8489]. ๐
Reason Phrase: The recommended reason phrases for error codes 440 and 508 are explained in Section 19. The reason phrase MUST be a UTF-8 [RFC3629] encoded sequence of less than 128 characters (which can be as long as 509 bytes when encoding them or 763 bytes when decoding them). โจ
18.13. ICMP ๐ธ
This attribute is used by servers to tell you why a UDP packet got dropped ๐ฆ. Here's the format of the ICMP attribute:
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Reserved | ICMP Type | ICMP Code |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Error Data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 11
Reserved: This field MUST be set to 0 when sent and MUST be ignored when received. ๐ซถ
ICMP Type: The field contains the value of the ICMP type. Its interpretation depends on whether the ICMP was received over IPv4 or IPv6. ๐
ICMP Code: The field contains the value of the ICMP code. Its interpretation depends on whether the ICMP was received over IPv4 or IPv6. ๐ฅ
Error Data: This field size is 4 bytes long. If the ICMPv6 type is 2 ("Packet too big" message) or ICMPv4 type is 3 (Destination Unreachable) and Code is 4 (fragmentation needed and DF set), the Error Data field will be set to the Maximum Transmission Unit of the next-hop link (Section 3.2 of [RFC4443] and Section 4 of [RFC1191]). For other ICMPv6 types and ICMPv4 types and codes, the Error Data field MUST be set to zero. ๐ญ
19. STUN Error Response Codes โจ
This document defines the following error response codes, and they're giving main character energy ๐
403 (Forbidden): The request was valid but cannot be performed due to administrative or similar restrictions. ๐
437 (Allocation Mismatch): A request was received by the server that requires an allocation to be in place, but no allocation exists, or a request was received that requires no allocation, but an allocation exists. ๐
440 (Address Family not Supported): The server does not support the address family requested by the client. ๐
441 (Wrong Credentials): (Wrong Credentials): The credentials in the (non-Allocate) request do not match those used to create the allocation. ๐ซฃ
442 (Unsupported Transport Protocol): The Allocate request asked the server to use a transport protocol between the server and the peer that the server does not support. NOTE: This does NOT refer to the transport protocol used in the 5-tuple. ๐ง
443 (Peer Address Family Mismatch): A peer address is part of a different address family than that of the relayed transport address of the allocation. ๐
486 (Allocation Quota Reached): No more allocations using this username can be created at the present time. ๐
508 (Insufficient Capacity): The server is unable to carry out the request due to some capacity limit being reached. In an Allocate response, this could be due to the server having no more relayed transport addresses available at that time, having none with the requested properties, or the one that corresponds to the specified reservation token is not available. ๐ฅบ
20. Detailed Example ๐
This section gives an example of the use of TURN, showing in detail the contents of the messages exchanged. The example uses the network diagram shown in the Overview (Figure 1). ๐ฆ
For each message, the attributes included in the message and their values are shown. For convenience, values are shown in a human-readable format rather than showing the actual octets; for example, "XOR-RELAYED-ADDRESS=192.0.2.15:9000" shows that the XOR-RELAYED-ADDRESS attribute is included with an address of 192.0.2.15 and a port of 9000; here, the address and port are shown before the xor-ing is done. For attributes with string-like values (e.g., SOFTWARE="Example client, version 1.03" and NONCE="obMatJos2gAAAadl7W7PeDU4hKE72jda"), the value of the attribute is shown in quotes for readability, but these quotes do not appear in the actual value. ๐ซถ
TURN TURN Peer Peer
client server A B
| | | |
|--- Allocate request -------------->| | |
| Transaction-Id=0xA56250D3F17ABE679422DE85 | |
| SOFTWARE="Example client, version 1.03" | |
| LIFETIME=3600 (1 hour) | | |
| REQUESTED-TRANSPORT=17 (UDP) | | |
| DONT-FRAGMENT | | |
| | | |
|<-- Allocate error response --------| | |
| Transaction-Id=0xA56250D3F17ABE679422DE85 | |
| SOFTWARE="Example server, version 1.17" | |
| ERROR-CODE=401 (Unauthorized) | | |
| REALM="example.com" | | |
| NONCE="obMatJos2gAAAadl7W7PeDU4hKE72jda" | |
| PASSWORD-ALGORITHMS=MD5 and SHA256 | |
| | | |
|--- Allocate request -------------->| | |
| Transaction-Id=0xC271E932AD7446A32C234492 | |
| SOFTWARE="Example client 1.03" | | |
| LIFETIME=3600 (1 hour) | | |
| REQUESTED-TRANSPORT=17 (UDP) | | |
| DONT-FRAGMENT | | |
| USERNAME="George" | | |
| REALM="example.com" | | |
| NONCE="obMatJos2gAAAadl7W7PeDU4hKE72jda" | |
| PASSWORD-ALGORITHMS=MD5 and SHA256 | |
| PASSWORD-ALGORITHM=SHA256 | | |
| MESSAGE-INTEGRITY=... | | |
| MESSAGE-INTEGRITY-SHA256=... | | |
| | | |
|<-- Allocate success response ------| | |
| Transaction-Id=0xC271E932AD7446A32C234492 | |
| SOFTWARE="Example server, version 1.17" | |
| LIFETIME=1200 (20 minutes) | | |
| XOR-RELAYED-ADDRESS=192.0.2.15:50000 | |
| XOR-MAPPED-ADDRESS=192.0.2.1:7000 | |
| MESSAGE-INTEGRITY-SHA256=... | | |
Figure 12
The client begins by selecting a host transport address to use for the TURN session; in this example, the client has selected 198.51.100.2:49721 as shown in Figure 1. ๐งญ The client then sends an Allocate request to the server at the server transport address. The client randomly selects a 96-bit transaction id of 0xA56250D3F17ABE679422DE85 for this transaction; this is encoded in the transaction id field in the fixed header. ๐ฒ The client includes a SOFTWARE attribute that gives information about the client's software; here, the value is "Example client, version 1.03" to indicate that this is version 1.03 of something called the "Example client". ๐
The client includes the LIFETIME attribute because it wishes the allocation to have a longer lifetime than the default of 10 minutes; the value of this attribute is 3600 seconds, which corresponds to 1 hour. โฐ The client must always include a REQUESTED-TRANSPORT attribute in an Allocate request, and the only value allowed by this specification is 17, which indicates UDP transport between the server and the peers. ๐ฆ The client also includes the DONT-FRAGMENT attribute because it wishes to use the DONT-FRAGMENT attribute later in Send indications; this attribute consists of only an attribute header; there is no value part. ๐ธ
We assume the client has not recently interacted with the server; thus, the client does not include the USERNAME, USERHASH, REALM, NONCE, PASSWORD-ALGORITHMS, PASSWORD-ALGORITHM, MESSAGE-INTEGRITY, or MESSAGE-INTEGRITY-SHA256 attribute. ๐ Finally, note that the order of attributes in a message is arbitrary (except for the MESSAGE-INTEGRITY, MESSAGE-INTEGRITY-SHA256 and FINGERPRINT attributes), and the client could have used a different order. ๐ซถ
Okay, servers are SO picky ๐ They require every single request to be authenticated ๐ So when the server gets the first Allocate request and it has no auth attributes, it's like "nope, not you" and rejects it ๐ โโ๏ธ Following the long-term credential mechanism of STUN [RFC8489] ๐, the server sends back an ERROR-CODE with a value of 401 (Unauthorized) ๐ญ It also includes a REALM attribute that says which authentication realm it's using (here it's the server's domain "example.com" ๐ธ) and a nonce in a NONCE attribute. The NONCE starts with the "nonce cookie", with the STUN Security Feature "Password algorithm" bit set to 1 โจ The server adds a PASSWORD-ALGORITHMS attribute listing the algorithms it can use to derive the long-term password ๐ง If the server sets the STUN Security Feature "Username anonymity" bit to 1, then the client uses the USERHASH attribute instead of USERNAME in the Allocate request so the username stays anonymized ๐ And the server throws in a SOFTWARE attribute with info about its software ๐
The client gets the 401 and reattempts the Allocate request, this time with the auth attributes ๐ฆ It picks a new transaction id, then fills the new request with the same attributes as before. It includes a USERNAME attribute, and it uses the realm value from the server to figure out which username to use. Here the client is set up to use the username "George" for the realm "example.com" ๐ซถ It also includes the PASSWORD-ALGORITHM attribute, which tells the server which algorithm to use to derive the long-term password ๐ฅ The REALM, PASSWORD-ALGORITHMS, and NONCE attributes are just copied from the 401 error response ๐ Last but not least, the client adds a MESSAGE-INTEGRITY-SHA256 attribute as the very last attribute in the message. Its value is a Hashed Message Authentication Code - Secure Hash Algorithm 2 (HMAC-SHA2) hash over the contents of the message (shown as just "..." above) ๐ This HMAC-SHA2 computation includes a password value, so an attacker can't compute the message integrity value without somehow knowing the secret password ๐ค
The server gets the authenticated Allocate request, checks that everything is OK, and then creates an allocation โจ It replies with an Allocate success response. It includes a LIFETIME attribute with the lifetime of the allocation. Here the client asked for 1 hour, but the server cut it down to just 20 minutes because this particular server doesn't allow lifetimes longer than that โฐ๐ It includes an XOR-RELAYED-ADDRESS attribute with the relayed transport address of the allocation ๐ฆ It also includes an XOR-MAPPED-ADDRESS attribute with the client's server-reflexive address. TURN doesn't use this value otherwise, but it's handed back as a convenience to the client ๐ The server adds a MESSAGE-INTEGRITY-SHA256 attribute to authenticate the response and make sure it hasn't been tampered with. Note that the response does NOT contain USERNAME, REALM, or NONCE attributes ๐ And the server adds a SOFTWARE attribute too ๐
TURN TURN Peer Peer
client server A B
|--- CreatePermission request ------>| | |
| Transaction-Id=0xE5913A8F460956CA277D3319 | |
| XOR-PEER-ADDRESS=192.0.2.150:0 | | |
| USERNAME="George" | | |
| REALM="example.com" | | |
| NONCE="obMatJos2gAAAadl7W7PeDU4hKE72jda" | |
| PASSWORD-ALGORITHMS=MD5 and SHA256 | |
| PASSWORD-ALGORITHM=SHA256 | | |
| MESSAGE-INTEGRITY-SHA256=... | | |
| | | |
|<-- CreatePermission success resp.--| | |
| Transaction-Id=0xE5913A8F460956CA277D3319 | |
| MESSAGE-INTEGRITY-SHA256=... | | |
Figure 13
Now the client makes a permission towards Peer A so it can send it some application data ๐ง That's done with a CreatePermission request. The XOR-PEER-ADDRESS attribute holds the IP address the permission is set up for (Peer A's IP address) ๐ฏ The port number in that attribute gets ignored in a CreatePermission request, so here it's set to 0 โจ Also, notice that the client uses Peer A's server-reflexive IP address and NOT its (private) host address ๐ The client uses the same username, realm, and nonce values as the previous request on the allocation. It's allowed to include a SOFTWARE attribute, but this time it chooses not to ๐ธ
The server gets the CreatePermission request, creates the matching permission, and replies with a CreatePermission success response ๐ฆ Like the client, the server skips the SOFTWARE attribute in its reply. Again, success responses carry a MESSAGE-INTEGRITY-SHA256 attribute (assuming the server uses the long-term credential mechanism) but NO USERNAME, REALM, or NONCE attributes ๐
TURN TURN Peer Peer
client server A B
|--- ChannelBind request ----------->| | |
| Transaction-Id=0x6490D3BC175AFF3D84513212 | |
| CHANNEL-NUMBER=0x4000 | | |
| XOR-PEER-ADDRESS=192.0.2.210:49191 | |
| USERNAME="George" | | |
| REALM="example.com" | | |
| NONCE="obMatJos2gAAAadl7W7PeDU4hKE72jda" | |
| PASSWORD-ALGORITHMS=MD5 and SHA256 | |
| PASSWORD-ALGORITHM=SHA256 | | |
| MESSAGE-INTEGRITY-SHA256=... | | |
| | | |
|<-- ChannelBind success response ---| | |
| Transaction-Id=0x6490D3BC175AFF3D84513212 | |
| MESSAGE-INTEGRITY-SHA256=... | | |
Figure 15
(I've put Figure 15 here by mistake above, so here's the correct order. Ignore that; see the figure block just below.)
Okay so Peer B sends a UDP datagram back to the relayed transport address ๐ฆ The server knows exactly which client to send it to because of the relayed transport address the datagram arrived at ๐ And since channel 0x4000 is bound to 192.0.2.210:49191, the server uses that channel for the ChannelData message ๐ง BUT if there's no channel number bound to that address, the server falls back to a Data indication instead ๐
TURN TURN Peer Peer
client server A B
|--- ChannelBind request ----------->| | |
| Transaction-Id=0xE5913A8F46091637EF7D3328 | |
| CHANNEL-NUMBER=0x4000 | | |
| XOR-PEER-ADDRESS=192.0.2.210:49191 | |
| USERNAME="George" | | |
| REALM="example.com" | | |
| NONCE="obMatJos2gAAAadl7W7PeDU4hKE72jda" | |
| PASSWORD-ALGORITHMS=MD5 and SHA256 | |
| PASSWORD-ALGORITHM=SHA256 | | |
| MESSAGE-INTEGRITY-SHA256=... | | |
| | | |
|<-- ChannelBind success response ---| | |
| Transaction-Id=0xE5913A8F46091637EF7D3328 | |
| MESSAGE-INTEGRITY-SHA256=... | | |
Figure 17
The channel binding lasts for 10 minutes unless it gets refreshed โฐ To refresh it, the TURN client sends a ChannelBind request that rebinds the channel to the same peer (Peer B's IP address) ๐ธ The server handles that request, rebinds the channel to the same peer, and resets the time-to-expiry timer back to 10 minutes โจ
TURN TURN Peer Peer
client server A B
|--- Refresh request --------------->| | |
| Transaction-Id=0x0864B3C27ADE9354B4312414 | |
| SOFTWARE="Example client 1.03" | | |
| USERNAME="George" | | |
| REALM="example.com" | | |
| NONCE="oobMatJos2gAAAadl7W7PeDU4hKE72jda" | |
| PASSWORD-ALGORITHMS=MD5 and SHA256 | |
| PASSWORD-ALGORITHM=SHA256 | | |
| MESSAGE-INTEGRITY-SHA256=... | | |
| | | |
|<-- Refresh error response ---------| | |
| Transaction-Id=0x0864B3C27ADE9354B4312414 | |
| SOFTWARE="Example server, version 1.17" | |
| ERROR-CODE=438 (Stale Nonce) | | |
| REALM="example.com" | | |
| NONCE="obMatJos2gAAAadl7W7PeDU4hKE72jda" | |
| PASSWORD-ALGORITHMS=MD5 and SHA256 | |
| | | |
|--- Refresh request --------------->| | |
| Transaction-Id=0x427BD3E625A85FC731DC4191 | |
| SOFTWARE="Example client 1.03" | | |
| USERNAME="George" | | |
| REALM="example.com" | | |
| NONCE="obMatJos2gAAAadl7W7PeDU4hKE72jda" | |
| PASSWORD-ALGORITHMS=MD5 and SHA256 | |
| PASSWORD-ALGORITHM=SHA256 | | |
| MESSAGE-INTEGRITY-SHA256=... | | |
| | | |
|<-- Refresh success response -------| | |
| Transaction-Id=0x427BD3E625A85FC731DC4191 | |
| SOFTWARE="Example server, version 1.17" | |
| LIFETIME=600 (10 minutes) | | |
| MESSAGE-INTEGRITY=... | | |
Figure 18
Sometime before the 20-minute lifetime is up, the client refreshes the allocation with a Refresh request ๐ซถ Same as before, the client includes the latest username, realm, and nonce values, and it also includes the SOFTWARE attribute, because that's the recommended practice for Allocate and Refresh messages ๐ When the server gets the Refresh request, it notices the nonce has expired, so it replies with a 438 (Stale Nonce) error and hands over a new nonce value ๐ญ The client tries again with the new nonce, the server accepts it this time, and the server sends a success response ๐ Oh, and the client didn't include a LIFETIME attribute, so the server refreshes the allocation for the default lifetime of 10 minutes. You can see that in the LIFETIME attribute of the success response ๐
21. Security Considerations ๐
This section looks at the attacks that are possible in a TURN deployment and explains how they get mitigated, either by mechanisms in the protocol or by recommended practices in the implementation ๐ต๏ธโโ๏ธ
Most attacks on TURN are stopped by the server requiring requests to be authenticated, which is why this specification requires the use of authentication ๐ The mandatory-to-implement mechanism is the long-term credential mechanism of STUN. Other authentication mechanisms with equal or stronger security properties may be used, but it's important to make sure they can be invoked in an interoperable way ๐
21.1. Outsider Attacks
Outsider attacks are the ones where the attacker has no credentials in the system and is trying to disrupt the service seen by the client or the server ๐
21.1.1. Obtaining Unauthorized Allocations
An attacker might want to obtain allocations on a TURN server for all kinds of nefarious purposes ๐ A TURN server gives a mechanism for sending and receiving packets while cloaking the actual IP address of the client, so TURN servers are an extremely attractive target for attackers who want to use them to mask their true identity ๐ฅธ
An attacker might also just want to use a TURN server's services without paying for them ๐ TURN services require resources from the provider, so it's anticipated that their usage will come with a cost ๐ธ
These attacks are prevented using the long-term credential mechanism, which lets the TURN server figure out the identity of the requestor and whether that requestor is allowed to obtain the allocation ๐ก๏ธ
21.1.2. Offline Dictionary Attacks
The long-term credential mechanism used by TURN is subject to offline dictionary attacks ๐ An attacker who can eavesdrop on a message exchange between a client and server can work out the password by trying a bunch of candidate passwords and seeing if one of them is correct ๐ This attack works when the passwords are low entropy, like a plain word from the dictionary ๐ It can be mitigated by using strong passwords with large entropy ๐ช In situations where even stronger mitigation is required, (D)TLS transport between the client and the server can be used ๐
21.1.3. Faked Refreshes and Permissions
An attacker might want to attack an active allocation by sending it a Refresh request with an immediate expiration, just to delete it and disrupt service to the client ๐๏ธ Authentication of refreshes prevents this ๐ โโ๏ธ Similarly, an attacker who wants to send CreatePermission requests to create permissions to undesirable destinations is stopped by authentication too ๐ซ The motivations for that kind of attack are described in Section 21.2 ๐ง
21.1.4. Fake Data
An attacker might want to send data to the client or the peer as if it came from the peer or client, respectively ๐ญ To do that, the attacker can send the client a faked Data indication or ChannelData message, or send the TURN server a faked Send indication or ChannelData message ๐ซฃ
Indications and ChannelData messages are not authenticated, so TURN doesn't prevent this attack ๐ฌ BUT this attack is generally present in IP-based communications and TURN doesn't substantially make it worse ๐คทโโ๏ธ Picture a normal, non-TURN IP session between hosts A and B. An attacker can send packets to B as if they came from A by sending packets towards B with a spoofed IP address of A ๐ช This attack requires the attacker to know the IP addresses of A and B. With TURN, an attacker who wants to send packets towards a client using a Data indication needs to know its IP address (and port), the IP address and port of the TURN server, and the IP address and port of the peer (for inclusion in the XOR-PEER-ADDRESS attribute) ๐ To send a fake ChannelData message to a client, an attacker needs to know the IP address and port of the client, the IP address and port of the TURN server, and the channel number ๐ข This particular combination is mildly more guessable than in the non-TURN case ๐
These attacks are more properly mitigated by application-layer authentication techniques โจ For real-time traffic, using SRTP [RFC3711] prevents these attacks ๐ง
In some situations, the TURN server may be sitting in the network in a way that lets it send to hosts the client can't directly reach ๐ฐ This can happen, for example, if the server is behind a firewall that allows packets from outside the firewall to be delivered to the server, but not to other hosts behind the firewall ๐งฑ In these situations, an attacker could send the server a Send indication with an XOR-PEER-ADDRESS attribute containing the transport address of one of the other hosts behind the firewall ๐ฑ If the server allowed relaying of traffic to arbitrary peers, that would give the attacker a way to attack arbitrary hosts behind the firewall ๐จ
To mitigate this attack, TURN requires that the client establish a permission to a host before sending it data ๐ So an attacker can only attack hosts the client is already communicating with, unless the attacker is able to create authenticated requests ๐ On top of that, the server administrator may configure the server to restrict the range of IP addresses and ports it will relay data to ๐บ๏ธ For even greater security, the server administrator can require that the client use (D)TLS for all communication between the client and the server ๐
21.1.5. Impersonating a Server
When a client learns a relayed address from a TURN server, it uses that relayed address in application protocols to receive traffic ๐ฌ So an attacker who wants to intercept or redirect that traffic might try to impersonate a TURN server and give the client a faked relayed address ๐ฅท
This attack is prevented through the long-term credential mechanism, which provides message integrity for responses as well as verifying that they came from the server ๐ก๏ธ Furthermore, an attacker can't replay old server responses, because the transaction id in the STUN header prevents this ๐ โโ๏ธ Replay attacks are further thwarted through frequent changes to the nonce value ๐
21.1.6. Eavesdropping Traffic โจ
okay so bestie, this one is about who can peek at your TURN traffic ๐ and what you can do about it ๐
If the TURN client and server use the STUN Extension for Third-Party Authorization [RFC7635] (it's a big deal in WebRTC ๐), the username doesn't spill the real user's identity ๐. The USERNAME attribute carries an ephemeral and unique key identifier ๐ฆ. But if the client and server use the STUN long-term credential mechanism and the username DOES reveal who the real user is, the client MUST either use the USERHASH attribute instead of the USERNAME attribute to anonymize the username ๐ซถ, or use (D)TLS transport between the client and the server ๐. No skipping this one, periodt ๐.
If the TURN client and server use the STUN long-term credential mechanism and realm info is privacy sensitive, TURN can be run over (D)TLS ๐ธ. Quick reminder: the STUN Extension for Third-Party Authorization does not use realm ๐.
The SOFTWARE attribute can reveal the exact software version of the TURN client and server to an eavesdropper ๐, and that might let someone attack software that's known to have security holes ๐ญ. So if the software version is known to contain security vulnerabilities, TURN SHOULD be run over (D)TLS so the SOFTWARE attribute doesn't leak in clear text ๐ง. And if zero-day vulnerabilities turn up in the software version, the endpoint policy can be changed to mandate (D)TLS until a patch fixes the flaw ๐ฅ.
Here's the big picture: TURN mainly cares about authentication and message integrity ๐. Confidentiality is only a secondary concern, because TURN control messages don't carry anything super sensitive, except USERNAME, REALM, and SOFTWARE ๐. The main content is the IP address of the peer ๐ฆ. If you really don't want an eavesdropper learning that, TURN can be run over (D)TLS โจ.
Now, confidentiality for the application data relayed by TURN is best handled by the application protocol itself ๐ , because running TURN over (D)TLS does NOT protect application data between the server and the peer ๐. So if your data needs to stay private, the application should encrypt or otherwise protect it ๐. For real-time media, for example, you can get confidentiality by using SRTP ๐.
21.1.7. TURN Loop Attack ๐
Okay this one is kind of wild ๐ญ. An attacker might try to make data packets loop forever between two TURN servers ๐. Here's how it goes: first, the attacker sends an Allocate request to server A but uses server B's source address ๐ญ. Server A sends its response to server B, and for this to work, the attacker has to be able to view or guess the contents of that response so they can learn the allocated relayed transport address ๐. Then the attacker sends an Allocate request to server B using server A's source address, and again they need to see or guess the response to learn that relayed transport address ๐. Using the same spoofed source address trick, the attacker binds a channel number on server A to the relayed transport address on server B, and binds the same channel number on server B to the relayed transport address on server A ๐. Finally, the attacker sends a ChannelData message to server A ๐.
The result is a data packet that bounces from the relayed transport address on server A to the relayed transport address on server B, then from server B's transport address to server A's transport address, and then around the loop again and again ๐๐ต.
Good news though: this attack gets mitigated ๐ก๏ธ. By requiring all requests to be authenticated and/or by randomizing the port number allocated for the relayed transport address, the server forces the attacker to either intercept or view responses sent to a third party (in this case, the other server) ๐, so the attacker can authenticate the requests and learn the relayed transport address. Without one of those two measures, an attacker can guess the contents of the responses without ever seeing them, which makes the attack way easier to pull off ๐ค. Plus, by requiring authenticated requests, the server forces the attacker to have credentials the server accepts ๐ซ. That turns this from an outsider attack into an insider attack and lets the attack be traced back to the client starting it ๐ต๏ธโโ๏ธ.
The attack can be further mitigated by putting a per-username limit on the bandwidth used to relay data by allocations owned by that username ๐ , so the impact on other allocations stays small โจ. More mitigation can come from decrementing the TTL when relaying data packets, if the underlying OS allows it ๐ง.
21.2. Firewall Considerations ๐งฑ
A key security consideration of TURN is that TURN should not weaken the protections that firewalls deployed between a client and a TURN server provide ๐ก๏ธ. TURN servers will often be on the public Internet ๐, and clients may often be inside enterprise networks with corporate firewalls ๐ข. If TURN servers gave a "backdoor" into the enterprise, TURN would just get blocked by those firewalls ๐ซ. Bestie, nobody wants that ๐ญ.
So TURN servers emulate the behavior of NAT devices that implement address-dependent filtering [RFC4787] ๐ฆ, which is a property common in many firewalls too ๐ฅ. With that behavior, packets from an outside IP address are only allowed to reach an internal IP address and port if that internal address and port recently sent a packet to that outside IP address ๐. TURN servers introduce the concept of permissions, which give you exactly this same behavior on the TURN server ๐. So an attacker cannot send a packet to a TURN server and expect it to be relayed toward the client, unless the client tried to contact the attacker first ๐ โโ๏ธ.
Some firewalls are even MORE restrictive than address-dependent filtering ๐. Firewalls can also be set up with address- and port-dependent filtering, or they can be configured to disallow inbound traffic entirely ๐งฑ. In those cases, if a client is allowed to connect to the TURN server, communications to the client will be less restrictive than what the firewall would normally allow ๐ฌ.
21.2.1. Faked Permissions ๐ญ
In firewalls and NAT devices, permissions are granted implicitly when a packet goes from the inside of the network toward the outside peer โ๏ธ. So a permission can, by definition, only be created by an entity inside the firewall or NAT ๐ . With TURN, this restriction no longer holds ๐ฑ. Since the TURN server sits outside the firewall, an attacker outside the firewall can now send a message to the TURN server and try to create a permission for itself ๐.
This attack is prevented because all messages that create permissions (i.e., ChannelBind and CreatePermission) are authenticated ๐โจ.
21.2.2. Blacklisted IP Addresses ๐ซ
Lots of firewalls can be configured with blacklists that stop a client behind the firewall from sending packets to, or receiving packets from, ranges of blacklisted IP addresses ๐งฑ. This works by inspecting the source and destination addresses of packets entering and exiting the firewall, respectively ๐.
This feature is also present in TURN, since TURN servers are allowed to arbitrarily restrict the range of addresses of peers they will relay to ๐ โจ.
21.2.3. Running Servers on Well-Known Ports ๐
A malicious client behind a firewall might try to connect to a TURN server and obtain an allocation that it then uses to run a server ๐ค. For example, a client might try to run a DNS server or an FTP server ๐.
This is NOT possible in TURN ๐ โโ๏ธ. A TURN server will never accept traffic from a peer for which the client has not installed a permission ๐. So peers can't just connect to the allocated port to get the service ๐.
21.3. Insider Attacks ๐
In insider attacks, a client has legitimate credentials but defies the trust relationship that comes with those credentials ๐. These attacks cannot be prevented by cryptographic means, so they need to be considered in the design of the protocol ๐ง .
21.3.1. DoS against TURN Server ๐ฅ
A client wishing to disrupt service to other clients might obtain an allocation and then flood it with traffic, trying to swamp the server and stop it from serving other legit clients ๐ค. This is mitigated by the recommendation that the server limit the amount of bandwidth it will relay for a given username ๐ก๏ธ. This won't stop a client from sending a huge amount of traffic, but it lets the server immediately discard the excess ๐๏ธโจ.
Since each allocation uses a port number on the IP address of the TURN server, the number of allocations on a server is finite ๐ข. An attacker might try to eat all of them by requesting a ton of allocations ๐ฝ๏ธ. This is prevented by the recommendation that the server impose a limit on the number of allocations active at a time for a given username ๐.
21.3.2. Anonymous Relaying of Malicious Traffic ๐ถ๏ธ
TURN servers provide a degree of anonymization ๐ญ. A client can send data to peers without revealing its own IP address ๐ป. Which means TURN servers may become attractive vehicles for attackers to launch attacks against targets without fear of detection ๐. Indeed, it's possible for a client to chain together multiple TURN servers so that any number of relays get used before a target receives a packet ๐๐ต.
Administrators who are worried about this can keep logs that capture the actual source IP and port of the client, and maybe even every permission that client installs ๐. That will allow for forensic tracing to figure out the original source if it's discovered that an attack is being relayed through a TURN server ๐ต๏ธโโ๏ธ๐.
21.3.3. Manipulating Other Allocations ๐งฉ
An attacker might try to disrupt service to other users of the TURN server by sending Refresh requests or CreatePermission requests that (through source address spoofing) look like they're coming from another user of the TURN server ๐ญ. TURN prevents this by requiring that the credentials used in CreatePermission, Refresh, and ChannelBind messages match the ones used to create the initial allocation ๐. So the fake requests from the attacker get rejected ๐ โโ๏ธโจ.
21.4. Tunnel Amplification Attack ๐
okay so this one is giving "amplification gone wild" ๐ญ An attacker might try to make data packets loop over and over between a TURN server and a tunnel running between IPv4 and IPv6. Here's how it goes:
Suppose he knows that a tunnel endpoint will forward encapsulated packets from a given IPv6 address (this doesn't necessarily need to be the tunnel endpoint's address). Then he spoofs two packets from that address:
- An Allocate request asking for a v4 address, and
- A ChannelBind request establishing a channel to the IPv4 address of the tunnel endpoint.
And just like that, he has set up an amplification attack ๐ฅ
- The TURN server will re-encapsulate IPv6 UDP data in v4 and send it to the tunnel endpoint.
- The tunnel endpoint will de-encapsulate packets from the v4 interface and send them to v6.
So if the attacker sends a packet of the following form:
IPv6: src=2001:DB8:1::1 dst=2001:DB8::2
UDP: <ports>
TURN: <channel id>
IPv6: src=2001:DB8:1::1 dst=2001:DB8::2
UDP: <ports>
TURN: <channel id>
IPv6: src=2001:DB8:1::1 dst=2001:DB8::2
UDP: <ports>
TURN: <channel id>
...
Figure 19
then the TURN server and the tunnel endpoint will keep sending it back and forth until the last TURN header is consumed ๐. At that point the TURN server sends an empty packet, and the tunnel endpoint drops it ๐ซถ
The amplification potential here is limited by the MTU, so it's not huge ๐ IPv6+UDP+TURN takes 334 bytes, so a four-to-one amplification out of a 1500-byte packet is possible. BUT the attacker could still crank up the traffic volume by sending multiple packets or by establishing multiple channels spoofed from different addresses behind the same tunnel endpoint. not ideal, bestie ๐
The attack is mitigated as follows. It is RECOMMENDED that TURN servers not accept allocation or channel-binding requests from addresses known to be tunneled, and that they not forward data to such addresses. In particular, a TURN server MUST NOT accept Teredo or 6to4 addresses in these requests. main character energy: blocked ๐
21.5. Other Considerations ๐งฉ
Any relay addresses learned through an Allocate request will not operate properly with IPsec Authentication Header (AH) [RFC4302] in transport or tunnel mode. However, tunnel-mode IPsec Encapsulating Security Payload (ESP) [RFC4303] should still operate โจ
22. IANA Considerations ๐
The code points for the STUN methods defined in this specification are listed in Section 17. IANA has updated the references from [RFC5766] to this document (for the STUN methods listed in Section 17).
The code points for the STUN attributes defined in this specification are listed in Section 18. IANA has updated the references from [RFC5766] to this document (for the STUN attributes CHANNEL-NUMBER, LIFETIME, Reserved (was BANDWIDTH), XOR-PEER-ADDRESS, DATA, XOR-RELAYED-ADDRESS, REQUESTED-ADDRESS-FAMILY, EVEN-PORT, REQUESTED-TRANSPORT, DONT-FRAGMENT, Reserved (was TIMER-VAL), and RESERVATION-TOKEN listed in Section 18).
The code points for the STUN error codes defined in this specification are listed in Section 19. IANA has updated the references from [RFC5766] and [RFC6156] to this document (for the STUN error codes listed in Section 19).
IANA has updated the references to [RFC5766] to this document for the SRV service name of "turn" for TURN over UDP or TCP and the service name of "turns" for TURN over (D)TLS.
IANA has created a registry for TURN channel numbers (the "Traversal Using Relays around NAT (TURN) Channel Numbers" registry), initially populated as follows:
+------------------------+------------------------------------------+
| 0x0000 through | Reserved and not available for use since |
| 0x3FFF: | they conflict with the STUN header. |
+------------------------+------------------------------------------+
| 0x4000 through | A TURN implementation is free to use |
| 0x4FFF: | channel numbers in this range. |
+------------------------+------------------------------------------+
| 0x5000 through | Reserved (For DTLS-SRTP multiplexing |
| 0xFFFF: | collision avoidance, see [RFC7983]) |
+------------------------+------------------------------------------+
Table 6
Any change to this registry must be made through an IETF Standards Action. ๐
23. IAB Considerations ๐๏ธ
The IAB has studied the problem of Unilateral Self-Address Fixing (UNSAF), which is the general process by which a client attempts to determine its address in another realm on the other side of a NAT through a collaborative protocol reflection mechanism [RFC3424]. The TURN extension is an example of a protocol that performs this type of function. The IAB has mandated that any protocols developed for this purpose document a specific set of considerations. These considerations and the responses for TURN are documented in this section.
Consideration 1: Precise definition of a specific, limited-scope problem that is to be solved with the UNSAF proposal. A short-term fix should not be generalized to solve other problems. Such generalizations lead to the prolonged dependence on and usage of the supposed short-term fix, meaning that it is no longer accurate to call it "short-term" ๐
Response: TURN is a protocol for communication between a relay (= TURN server) and its client. The protocol allows a client that is behind a NAT to obtain and use a public IP address on the relay. As a convenience to the client, TURN also allows the client to determine its server-reflexive transport address.
Consideration 2: Description of an exit strategy/transition plan. The better short-term fixes are the ones that will naturally see less and less use as the appropriate technology is deployed.
Response: TURN will no longer be needed once there are no longer any NATs. Unfortunately, as of the date of publication of this document, it no longer seems very likely that NATs will go away any time soon ๐ญ However, the need for TURN will also decrease as the number of NATs with the mapping property of Endpoint-Independent Mapping [RFC4787] increases.
Consideration 3: Discussion of specific issues that may render systems more "brittle". For example, approaches that involve using data at multiple network layers create more dependencies, increase debugging challenges, and make it harder to transition.
Response: TURN is "brittle" in that it requires the NAT bindings between the client and the server to be maintained unchanged for the lifetime of the allocation. This is typically done using keep-alives. If this is not done, then the client will lose its allocation and can no longer exchange data with its peers ๐ฅ
Consideration 4: Identify requirements for longer-term, sound technical solutions; contribute to the process of finding the right longer-term solution.
Response: The need for TURN will be reduced once NATs implement the recommendations for NAT UDP behavior documented in [RFC4787]. Applications are also strongly urged to use ICE [RFC8445] to communicate with peers; though ICE uses TURN, it does so only as a last resort, and it uses it in a controlled manner ๐
Consideration 5: Discussion of the impact of the noted practical issues with existing deployed NATs and experience reports.
Response: Some NATs deployed today exhibit a mapping behavior other than Endpoint-Independent mapping. These NATs are difficult to work with, as they make it difficult or impossible for protocols like ICE to use server-reflexive transport addresses on those NATs. A client behind such a NAT is often forced to use a relay protocol like TURN because "UDP hole punching" techniques [RFC5128] do not work. the NAT really said no ๐ โโ๏ธ
24. Changes since RFC 5766 ๐
This section lists the major changes in the TURN protocol from the original [RFC5766] specification.
- IPv6 support.
- REQUESTED-ADDRESS-FAMILY attribute.
- Description of the tunnel amplification attack.
- DTLS support.
- Add support for receiving ICMP packets.
- Updates PMTUD.
- Discovery of TURN server.
- TURN URI Scheme Semantics.
- Happy Eyeballs for TURN.
- Align with the changes in STUN [RFC8489].
25. Updates to RFC 6156 ๐
This section lists the major updates to [RFC6156] in this specification.
- ADDITIONAL-ADDRESS-FAMILY and ADDRESS-ERROR-CODE attributes.
- 440 (Address Family not Supported) and 443 (Peer Address Family Mismatch) responses.
- More details on packet translation.
- TCP-to-UDP and UDP-to-TCP relaying.
26. References ๐
26.1. Normative References โจ
okay so this is the list of docs that RFC 8656 totally leans on, bestie ๐๐ the "normative" ones are the stuff you NEED to know to get the spec right, so these are the main character references ๐
[PROTOCOL-NUMBERS]
IANA, "Protocol Numbers",
<https://www.iana.org/assignments/protocol-numbers>.
[RFC0792] Postel, J., "Internet Control Message Protocol", STD 5,
RFC 792, DOI 10.17487/RFC0792, September 1981,
<https://www.rfc-editor.org/info/rfc792>.
[RFC1122] Braden, R., Ed., "Requirements for Internet Hosts -
Communication Layers", STD 3, RFC 1122,
DOI 10.17487/RFC1122, October 1989,
<https://www.rfc-editor.org/info/rfc1122>.
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119,
DOI 10.17487/RFC2119, March 1997,
<https://www.rfc-editor.org/info/rfc2119>.
[RFC2474] Nichols, K., Blake, S., Baker, F., and D. Black,
"Definition of the Differentiated Services Field (DS
Field) in the IPv4 and IPv6 Headers", RFC 2474,
DOI 10.17487/RFC2474, December 1998,
<https://www.rfc-editor.org/info/rfc2474>.
[RFC3168] Ramakrishnan, K., Floyd, S., and D. Black, "The Addition
of Explicit Congestion Notification (ECN) to IP",
RFC 3168, DOI 10.17487/RFC3168, September 2001,
<https://www.rfc-editor.org/info/rfc3168>.
[RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO
10646", STD 63, RFC 3629, DOI 10.17487/RFC3629, November
2003, <https://www.rfc-editor.org/info/rfc3629>.
[RFC4443] Conta, A., Deering, S., and M. Gupta, Ed., "Internet
Control Message Protocol (ICMPv6) for the Internet
Protocol Version 6 (IPv6) Specification", STD 89,
RFC 4443, DOI 10.17487/RFC4443, March 2006,
<https://www.rfc-editor.org/info/rfc4443>.
[RFC6347] Rescorla, E. and N. Modadugu, "Datagram Transport Layer
Security Version 1.2", RFC 6347, DOI 10.17487/RFC6347,
January 2012, <https://www.rfc-editor.org/info/rfc6347>.
[RFC6437] Amante, S., Carpenter, B., Jiang, S., and J. Rajahalme,
"IPv6 Flow Label Specification", RFC 6437,
DOI 10.17487/RFC6437, November 2011,
<https://www.rfc-editor.org/info/rfc6437>.
[RFC7065] Petit-Huguenin, M., Nandakumar, S., Salgueiro, G., and P.
Jones, "Traversal Using Relays around NAT (TURN) Uniform
Resource Identifiers", RFC 7065, DOI 10.17487/RFC7065,
November 2013, <https://www.rfc-editor.org/info/rfc7065>.
[RFC7350] Petit-Huguenin, M. and G. Salgueiro, "Datagram Transport
Layer Security (DTLS) as Transport for Session Traversal
Utilities for NAT (STUN)", RFC 7350, DOI 10.17487/RFC7350,
August 2014, <https://www.rfc-editor.org/info/rfc7350>.
[RFC7525] Sheffer, Y., Holz, R., and P. Saint-Andre,
"Recommendations for Secure Use of Transport Layer
Security (TLS) and Datagram Transport Layer Security
(DTLS)", BCP 195, RFC 7525, DOI 10.17487/RFC7525, May
2015, <https://www.rfc-editor.org/info/rfc7525>.
[RFC7915] Bao, C., Li, X., Baker, F., Anderson, T., and F. Gont,
"IP/ICMP Translation Algorithm", RFC 7915,
DOI 10.17487/RFC7915, June 2016,
<https://www.rfc-editor.org/info/rfc7915>.
[RFC7982] Martinsen, P., Reddy, T., Wing, D., and V. Singh,
"Measurement of Round-Trip Time and Fractional Loss Using
Session Traversal Utilities for NAT (STUN)", RFC 7982,
DOI 10.17487/RFC7982, September 2016,
<https://www.rfc-editor.org/info/rfc7982>.
[RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
May 2017, <https://www.rfc-editor.org/info/rfc8174>.
[RFC8200] Deering, S. and R. Hinden, "Internet Protocol, Version 6
(IPv6) Specification", STD 86, RFC 8200,
DOI 10.17487/RFC8200, July 2017,
<https://www.rfc-editor.org/info/rfc8200>.
[RFC8305] Schinazi, D. and T. Pauly, "Happy Eyeballs Version 2:
Better Connectivity Using Concurrency", RFC 8305,
DOI 10.17487/RFC8305, December 2017,
<https://www.rfc-editor.org/info/rfc8305>.
[RFC8446] Rescorla, E., "The Transport Layer Security (TLS) Protocol
Version 1.3", RFC 8446, DOI 10.17487/RFC8446, August 2018,
<https://www.rfc-editor.org/info/rfc8446>.
[RFC8489] Petit-Huguenin, M., Salgueiro, G., Rosenberg, J., Wing,
D., Mahy, R., and P. Matthews, "Session Traversal
Utilities for NAT (STUN)", RFC 8489, DOI 10.17487/RFC8489,
February 2020, <https://www.rfc-editor.org/info/rfc8489>.
26.2. Informative References โจ
okay bestie, this is the reading list for the "for context" stuff ๐๐ซถ none of these are strictly required to use TURN, but they're the receipts behind the vibes.
- [FRAG-FRAGILE] Bonica, R., Baker, F., Huston, G., Hinden, R., Troan, O., and F. Gont, "IP Fragmentation Considered Fragile", Work in Progress, Internet-Draft, draft-ietf-intarea-frag-fragile-17, 30 September 2019,
https://tools.ietf.org/html/draft-ietf-intarea-frag-fragile-17. ๐งฉ - [FRAG-HARMFUL] Kent, C. and J. Mogul, "Fragmentation Considered Harmful", December 1987,
https://www.hpl.hp.com/techreports/Compaq-DEC/WRL-87-3.pdf. ๐ - [MTU-DATAGRAM] Fairhurst, G., Jones, T., Tuexen, M., Ruengeler, I., and T. Voelker, "Packetization Layer Path MTU Discovery for Datagram Transports", Work in Progress, Internet-Draft, draft-ietf-tsvwg-datagram-plpmtud-14, 12 February 2020,
https://tools.ietf.org/html/draft-ietf-tsvwg-datagram-plpmtud-14. ๐ฆ - [MTU-STUN] Petit-Huguenin, M., Salgueiro, G., and F. Garrido, "Packetization Layer Path MTU Discovery (PLMTUD) For UDP Transports Using Session Traversal Utilities for NAT (STUN)", Work in Progress, Internet-Draft, draft-ietf-tram-stun-pmtud-15, 17 December 2019,
https://tools.ietf.org/html/draft-ietf-tram-stun-pmtud-15. ๐ - [PORT-NUMBERS] IANA, "Service Name and Transport Protocol Port Number Registry",
https://www.iana.org/assignments/port-numbers. ๐ข - [RFC0791] Postel, J., "Internet Protocol", STD 5, RFC 791, DOI 10.17487/RFC0791, September 1981,
https://www.rfc-editor.org/info/rfc791. ๐ - [RFC1191] Mogul, J. and S. Deering, "Path MTU discovery", RFC 1191, DOI 10.17487/RFC1191, November 1990,
https://www.rfc-editor.org/info/rfc1191. ๐ฃ๏ธ - [RFC1918] Rekhter, Y., Moskowitz, B., Karrenberg, D., de Groot, G. J., and E. Lear, "Address Allocation for Private Internets", BCP 5, RFC 1918, DOI 10.17487/RFC1918, February 1996,
https://www.rfc-editor.org/info/rfc1918. ๐ - [RFC1928] Leech, M., Ganis, M., Lee, Y., Kuris, R., Koblas, D., and L. Jones, "SOCKS Protocol Version 5", RFC 1928, DOI 10.17487/RFC1928, March 1996,
https://www.rfc-editor.org/info/rfc1928. ๐งฆ - [RFC3261] Rosenberg, J., Schulzrinne, H., Camarillo, G., Johnston, A., Peterson, J., Sparks, R., Handley, M., and E. Schooler, "SIP: Session Initiation Protocol", RFC 3261, DOI 10.17487/RFC3261, June 2002,
https://www.rfc-editor.org/info/rfc3261. ๐ - [RFC3424] Daigle, L., Ed. and IAB, "IAB Considerations for UNilateral Self-Address Fixing (UNSAF) Across Network Address Translation", RFC 3424, DOI 10.17487/RFC3424, November 2002,
https://www.rfc-editor.org/info/rfc3424. ๐ง - [RFC3550] Schulzrinne, H., Casner, S., Frederick, R., and V. Jacobson, "RTP: A Transport Protocol for Real-Time Applications", STD 64, RFC 3550, DOI 10.17487/RFC3550, July 2003,
https://www.rfc-editor.org/info/rfc3550. ๐๏ธ - [RFC3711] Baugher, M., McGrew, D., Naslund, M., Carrara, E., and K. Norrman, "The Secure Real-time Transport Protocol (SRTP)", RFC 3711, DOI 10.17487/RFC3711, March 2004,
https://www.rfc-editor.org/info/rfc3711. ๐ - [RFC4086] Eastlake 3rd, D., Schiller, J., and S. Crocker, "Randomness Requirements for Security", BCP 106, RFC 4086, DOI 10.17487/RFC4086, June 2005,
https://www.rfc-editor.org/info/rfc4086. ๐ฒ - [RFC4302] Kent, S., "IP Authentication Header", RFC 4302, DOI 10.17487/RFC4302, December 2005,
https://www.rfc-editor.org/info/rfc4302. ๐ชช - [RFC4303] Kent, S., "IP Encapsulating Security Payload (ESP)", RFC 4303, DOI 10.17487/RFC4303, December 2005,
https://www.rfc-editor.org/info/rfc4303. ๐ก๏ธ - [RFC4787] Audet, F., Ed. and C. Jennings, "Network Address Translation (NAT) Behavioral Requirements for Unicast UDP", BCP 127, RFC 4787, DOI 10.17487/RFC4787, January 2007,
https://www.rfc-editor.org/info/rfc4787. ๐ - [RFC4821] Mathis, M. and J. Heffner, "Packetization Layer Path MTU Discovery", RFC 4821, DOI 10.17487/RFC4821, March 2007,
https://www.rfc-editor.org/info/rfc4821. ๐งช - [RFC5128] Srisuresh, P., Ford, B., and D. Kegel, "State of Peer-to-Peer (P2P) Communication across Network Address Translators (NATs)", RFC 5128, DOI 10.17487/RFC5128, March 2008,
https://www.rfc-editor.org/info/rfc5128. ๐ค - [RFC5482] Eggert, L. and F. Gont, "TCP User Timeout Option", RFC 5482, DOI 10.17487/RFC5482, March 2009,
https://www.rfc-editor.org/info/rfc5482. โฑ๏ธ - [RFC5766] Mahy, R., Matthews, P., and J. Rosenberg, "Traversal Using Relays around NAT (TURN): Relay Extensions to Session Traversal Utilities for NAT (STUN)", RFC 5766, DOI 10.17487/RFC5766, April 2010,
https://www.rfc-editor.org/info/rfc5766. ๐ - [RFC5925] Touch, J., Mankin, A., and R. Bonica, "The TCP Authentication Option", RFC 5925, DOI 10.17487/RFC5925, June 2010,
https://www.rfc-editor.org/info/rfc5925. ๐ - [RFC5928] Petit-Huguenin, M., "Traversal Using Relays around NAT (TURN) Resolution Mechanism", RFC 5928, DOI 10.17487/RFC5928, August 2010,
https://www.rfc-editor.org/info/rfc5928. ๐บ๏ธ - [RFC6056] Larsen, M. and F. Gont, "Recommendations for Transport-Protocol Port Randomization", BCP 156, RFC 6056, DOI 10.17487/RFC6056, January 2011,
https://www.rfc-editor.org/info/rfc6056. ๐ฐ - [RFC6062] Perreault, S., Ed. and J. Rosenberg, "Traversal Using Relays around NAT (TURN) Extensions for TCP Allocations", RFC 6062, DOI 10.17487/RFC6062, November 2010,
https://www.rfc-editor.org/info/rfc6062. ๐งต - [RFC6156] Camarillo, G., Novo, O., and S. Perreault, Ed., "Traversal Using Relays around NAT (TURN) Extension for IPv6", RFC 6156, DOI 10.17487/RFC6156, April 2011,
https://www.rfc-editor.org/info/rfc6156. 6๏ธโฃ - [RFC6263] Marjou, X. and A. Sollaud, "Application Mechanism for Keeping Alive the NAT Mappings Associated with RTP / RTP Control Protocol (RTCP) Flows", RFC 6263, DOI 10.17487/RFC6263, June 2011,
https://www.rfc-editor.org/info/rfc6263. ๐ - [RFC7413] Cheng, Y., Chu, J., Radhakrishnan, S., and A. Jain, "TCP Fast Open", RFC 7413, DOI 10.17487/RFC7413, December 2014,
https://www.rfc-editor.org/info/rfc7413. โก - [RFC7478] Holmberg, C., Hakansson, S., and G. Eriksson, "Web Real-Time Communication Use Cases and Requirements", RFC 7478, DOI 10.17487/RFC7478, March 2015,
https://www.rfc-editor.org/info/rfc7478. ๐น - [RFC7635] Reddy, T., Patil, P., Ravindranath, R., and J. Uberti, "Session Traversal Utilities for NAT (STUN) Extension for Third-Party Authorization", RFC 7635, DOI 10.17487/RFC7635, August 2015,
https://www.rfc-editor.org/info/rfc7635. ๐๏ธ - [RFC7657] Black, D., Ed. and P. Jones, "Differentiated Services (Diffserv) and Real-Time Communication", RFC 7657, DOI 10.17487/RFC7657, November 2015,
https://www.rfc-editor.org/info/rfc7657. ๐ท๏ธ - [RFC7983] Petit-Huguenin, M. and G. Salgueiro, "Multiplexing Scheme Updates for Secure Real-time Transport Protocol (SRTP) Extension for Datagram Transport Layer Security (DTLS)", RFC 7983, DOI 10.17487/RFC7983, September 2016,
https://www.rfc-editor.org/info/rfc7983. ๐งถ - [RFC8155] Patil, P., Reddy, T., and D. Wing, "Traversal Using Relays around NAT (TURN) Server Auto Discovery", RFC 8155, DOI 10.17487/RFC8155, April 2017,
https://www.rfc-editor.org/info/rfc8155. ๐ - [RFC8311] Black, D., "Relaxing Restrictions on Explicit Congestion Notification (ECN) Experimentation", RFC 8311, DOI 10.17487/RFC8311, January 2018,
https://www.rfc-editor.org/info/rfc8311. ๐ฆ - [RFC8445] Keranen, A., Holmberg, C., and J. Rosenberg, "Interactive Connectivity Establishment (ICE): A Protocol for Network Address Translator (NAT) Traversal", RFC 8445, DOI 10.17487/RFC8445, July 2018,
https://www.rfc-editor.org/info/rfc8445. ๐งญ - [SDP-ICE] Petit-Huguenin, M., Nandakumar, S., Holmberg, C., Keranen, A., and R. Shpount, "Session Description Protocol (SDP) Offer/Answer procedures for Interactive Connectivity Establishment (ICE)", Work in Progress, Internet-Draft, draft-ietf-mmusic-ice-sip-sdp-39, 13 August 2019,
https://tools.ietf.org/html/draft-ietf-mmusic-ice-sip-sdp-39. ๐ - [SEC-WEBRTC] Rescorla, E., "Security Considerations for WebRTC", Work in Progress, Internet-Draft, draft-ietf-rtcweb-security-12, 5 July 2019,
https://tools.ietf.org/html/draft-ietf-rtcweb-security-12. ๐ต๏ธโโ๏ธ - [TCP-EXT] Ford, A., Raiciu, C., Handley, M., Bonaventure, O., and C. Paasch, "TCP Extensions for Multipath Operation with Multiple Addresses", Work in Progress, Internet-Draft, draft-ietf-mptcp-rfc6824bis-18, 8 June 2019,
https://tools.ietf.org/html/draft-ietf-mptcp-rfc6824bis-18. ๐ค๏ธ - [UDP-OPT] Touch, J., "Transport Options for UDP", Work in Progress, Internet-Draft, draft-ietf-tsvwg-udp-options-08, 12 September 2019,
https://tools.ietf.org/html/draft-ietf-tsvwg-udp-options-08. ๐๏ธ
Acknowledgements
okay the credits era ๐ซถโจ most of the words in this doc are lifted from the original TURN spec, [RFC5766], and we're SO grateful to Rohan Mahy, who co-wrote that original, plus everyone who helped on it ๐. The authors also want to shout out that this doc inherits some material from [RFC6156] ๐.
Huge thanks to Justin Uberti, Pal Martinsen, Oleg Moskalenko, Aijun Wang, and Simon Perreault for helping out with the ADDITIONAL-ADDRESS-FAMILY mechanism ๐ธ. Thank you also to Gonzalo Salgueiro, Simon Perreault, Jonathan Lennox, Brandon Williams, Karl Stahl, Noriyuki Torii, Nils Ohlmeier, Dan Wing, Vijay Gurbani, Joseph Touch, Justin Uberti, Christopher Wood, Roman Danyliw, Eric Vyncke, Adam Roach, Suresh Krishnan, Mirja Kuehlewind, Benjamin Kaduk, and Oleg Moskalenko for their comments and reviews ๐. The authors also thank Marc Petit-Huguenin for his contributions to the text ๐
.
Special thanks to Magnus Westerlund for the detailed AD review ๐
Authors' Addresses
Tirumaleswar Reddy (editor) ๐
McAfee, Inc.
Embassy Golf Link Business Park
Bangalore 560071
Karnataka
India
Email: kondtir@gmail.com
Alan Johnston (editor) ๐ฆ
Villanova University
Villanova, PA
United States of America
Email: alan.b.johnston@gmail.com
Philip Matthews ๐
Alcatel-Lucent
600 March Road
Ottawa Ontario
Canada
Email: philip_matthews@magma.ca
Jonathan Rosenberg ๐
jdrosen.net
Edison, NJ
United States of America
Email: jdrosen@jdrosen.net URI: http://www.jdrosen.net
That's the whole spec, bestie! ๐๐ TURN is officially a wrap โจ
๐ฆ where this page comes from
- ietf: rfc8656 2020-02
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms