RFC 5766

Traversal Using Relays around NAT (TURN): Relay Extensions to Session Traversal Utilities for NAT (STUN)

๐Ÿ“… published April 2010, from ietf

RFC 5766: TURN, the relay extensions to STUN ๐Ÿฆ‹

Title: Traversal Using Relays around NAT (TURN): Relay Extensions to Session Traversal Utilities for NAT (STUN)

  • Request for Comments: 5766 ๐ŸŽ€
  • Category: Standards Track
  • Date: April 2010
  • Status: ISSN 2070-1721
  • Authors: R. Mahy (Unaffiliated), P. Matthews (Alcatel-Lucent), J. Rosenberg (jdrosen.net)
  • Publisher: Internet Engineering Task Force (IETF) ๐Ÿ’œ
  • Obsoletes and updates: this title block has no Obsoletes or Updates line, so there's nothing to report here โœจ

Abstract ๐ŸŒธ

okay so picture this: you're a host hiding behind a NAT, and sometimes that NAT means you literally cannot talk directly to the other hosts (peers) you want to reach ๐Ÿ˜ญ in those moments you need help from a middleman node that acts as a communication relay. this spec defines a protocol called TURN (Traversal Using Relays around NAT) ๐Ÿ’… which lets your host control how the relay works and send packets to its peers through it.

what makes TURN iconic is that it lets one client talk to multiple peers using a single relay address. that's not something every relay control protocol can do, so it's a whole main character moment ๐Ÿ‘‘

TURN was built to be part of the ICE (Interactive Connectivity Establishment) approach to NAT traversal ๐Ÿซถ but it can also be used without ICE, which is lowkey so useful.


Status of This Memo ๐Ÿ“

this is an Internet Standards Track document โœจ

it's a product of the Internet Engineering Task Force (IETF) ๐Ÿ’œ and it represents the consensus of the IETF community. it got public review and was approved for publication by the Internet Engineering Steering Group (IESG). if you want more on Internet Standards, check out Section 2 of RFC 5741 ๐Ÿ“š

for the latest on this doc's status, any errata, or how to send feedback, go to http://www.rfc-editor.org/info/rfc5766 ๐Ÿ”ฅ


Copyright (c) 2010 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 (http://trustee.ietf.org/license-info) as they stand on the date this document was published. please read these carefully, because they spell out your rights and restrictions for this document ๐Ÿซถ

if you pull Code Components out of this document, they must include the Simplified BSD License text, as described in Section 4.e of the Trust Legal Provisions. they come without warranty, as described in the Simplified BSD License ๐Ÿ’…


Table of Contents ๐Ÿงš

here's the whole roadmap, copied exactly so you can find every section (the numbers matter, since the text points to them ๐Ÿ‘‘):

   1.  Introduction . . . . . . . . . . . . . . . . . . . . . . . . .  4
   2.  Overview of Operation  . . . . . . . . . . . . . . . . . . . .  5
     2.1.  Transports . . . . . . . . . . . . . . . . . . . . . . . .  8
     2.2.  Allocations  . . . . . . . . . . . . . . . . . . . . . . .  9
     2.3.  Permissions  . . . . . . . . . . . . . . . . . . . . . . . 11
     2.4.  Send Mechanism . . . . . . . . . . . . . . . . . . . . . . 12
     2.5.  Channels . . . . . . . . . . . . . . . . . . . . . . . . . 13
     2.6.  Unprivileged TURN Servers  . . . . . . . . . . . . . . . . 15
     2.7.  Avoiding IP Fragmentation  . . . . . . . . . . . . . . . . 16
     2.8.  RTP Support  . . . . . . . . . . . . . . . . . . . . . . . 17
     2.9.  Anycast Discovery of Servers . . . . . . . . . . . . . . . 17
   3.  Terminology  . . . . . . . . . . . . . . . . . . . . . . . . . 18
   4.  General Behavior . . . . . . . . . . . . . . . . . . . . . . . 19
   5.  Allocations  . . . . . . . . . . . . . . . . . . . . . . . . . 22
   6.  Creating an Allocation . . . . . . . . . . . . . . . . . . . . 23
     6.1.  Sending an Allocate Request  . . . . . . . . . . . . . . . 23
     6.2.  Receiving an Allocate Request  . . . . . . . . . . . . . . 24
     6.3.  Receiving an Allocate Success Response . . . . . . . . . . 28
     6.4.  Receiving an Allocate Error Response . . . . . . . . . . . 29
   7.  Refreshing an Allocation . . . . . . . . . . . . . . . . . . . 31
     7.1.  Sending a Refresh Request  . . . . . . . . . . . . . . . . 31
     7.2.  Receiving a Refresh Request  . . . . . . . . . . . . . . . 31
     7.3.  Receiving a Refresh Response . . . . . . . . . . . . . . . 32
   8.  Permissions  . . . . . . . . . . . . . . . . . . . . . . . . . 32
   9.  CreatePermission . . . . . . . . . . . . . . . . . . . . . . . 34
     9.1.  Forming a CreatePermission Request . . . . . . . . . . . . 34
     9.2.  Receiving a CreatePermission Request . . . . . . . . . . . 34
     9.3.  Receiving a CreatePermission Response  . . . . . . . . . . 35
   10. Send and Data Methods  . . . . . . . . . . . . . . . . . . . . 35
     10.1. Forming a Send Indication  . . . . . . . . . . . . . . . . 35
     10.2. Receiving a Send Indication  . . . . . . . . . . . . . . . 35
     10.3. Receiving a UDP Datagram . . . . . . . . . . . . . . . . . 36
     10.4. Receiving a Data Indication  . . . . . . . . . . . . . . . 37
   11. Channels . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
     11.1. Sending a ChannelBind Request  . . . . . . . . . . . . . . 39
     11.2. Receiving a ChannelBind Request  . . . . . . . . . . . . . 39
     11.3. Receiving a ChannelBind Response . . . . . . . . . . . . . 40
     11.4. The ChannelData Message  . . . . . . . . . . . . . . . . . 41
     11.5. Sending a ChannelData Message  . . . . . . . . . . . . . . 41
     11.6. Receiving a ChannelData Message  . . . . . . . . . . . . . 42
     11.7. Relaying Data from the Peer  . . . . . . . . . . . . . . . 43
   12. IP Header Fields . . . . . . . . . . . . . . . . . . . . . . . 43
   13. New STUN Methods . . . . . . . . . . . . . . . . . . . . . . . 45
   14. New STUN Attributes  . . . . . . . . . . . . . . . . . . . . . 45
     14.1. CHANNEL-NUMBER . . . . . . . . . . . . . . . . . . . . . . 45
     14.2. LIFETIME . . . . . . . . . . . . . . . . . . . . . . . . . 46
     14.3. XOR-PEER-ADDRESS . . . . . . . . . . . . . . . . . . . . . 46
     14.4. DATA . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
     14.5. XOR-RELAYED-ADDRESS  . . . . . . . . . . . . . . . . . . . 46
     14.6. EVEN-PORT  . . . . . . . . . . . . . . . . . . . . . . . . 46
     14.7. REQUESTED-TRANSPORT  . . . . . . . . . . . . . . . . . . . 47
     14.8. DONT-FRAGMENT  . . . . . . . . . . . . . . . . . . . . . . 47
     14.9. RESERVATION-TOKEN  . . . . . . . . . . . . . . . . . . . . 48
   15. New STUN Error Response Codes  . . . . . . . . . . . . . . . . 48
   16. Detailed Example . . . . . . . . . . . . . . . . . . . . . . . 48
   17. Security Considerations  . . . . . . . . . . . . . . . . . . . 55
     17.1. Outsider Attacks . . . . . . . . . . . . . . . . . . . . . 55
       17.1.1.  Obtaining Unauthorized Allocations  . . . . . . . . . 55
       17.1.2.  Offline Dictionary Attacks  . . . . . . . . . . . . . 56
       17.1.3.  Faked Refreshes and Permissions . . . . . . . . . . . 56
       17.1.4.  Fake Data . . . . . . . . . . . . . . . . . . . . . . 56
       17.1.5.  Impersonating a Server  . . . . . . . . . . . . . . . 57
       17.1.6.  Eavesdropping Traffic . . . . . . . . . . . . . . . . 58
       17.1.7.  TURN Loop Attack  . . . . . . . . . . . . . . . . . . 58
     17.2. Firewall Considerations  . . . . . . . . . . . . . . . . . 59
       17.2.1.  Faked Permissions . . . . . . . . . . . . . . . . . . 59
       17.2.2.  Blacklisted IP Addresses  . . . . . . . . . . . . . . 60
       17.2.3.  Running Servers on Well-Known Ports . . . . . . . . . 60
     17.3. Insider Attacks  . . . . . . . . . . . . . . . . . . . . . 60
       17.3.1.  DoS against TURN Server . . . . . . . . . . . . . . . 60
       17.3.2.  Anonymous Relaying of Malicious Traffic . . . . . . . 61
       17.3.3.  Manipulating Other Allocations  . . . . . . . . . . . 61
     17.4. Other Considerations . . . . . . . . . . . . . . . . . . . 61
   18. IANA Considerations  . . . . . . . . . . . . . . . . . . . . . 61
   19. IAB Considerations . . . . . . . . . . . . . . . . . . . . . . 62
   20. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 63
   21. References . . . . . . . . . . . . . . . . . . . . . . . . . . 64
     21.1. Normative References . . . . . . . . . . . . . . . . . . . 64
     21.2. Informative References . . . . . . . . . . . . . . . . . . 64

Part 1 of 17 done ๐Ÿ’– more parts coming, so stay tuned bestie ๐Ÿฆ‹

1. Introduction โœจ

okay so picture this ๐ŸŽ€ a host sitting behind a NAT wants to chat directly with other hosts, and some of those are also behind NATs ๐Ÿ˜ญ the hosts can try "hole punching" techniques (see [RFC5128]) to find a direct path, meaning a route from one host to the other through the NATs and routers in between that doesn't touch any relays ๐Ÿฆ‹

but ngl, hole punching is picky. As described in [RFC5128] and [RFC4787], it 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", hole punching generally fails. not me getting rejected by my own NAT ๐Ÿ™ˆ

so when a direct path can't be found, you need an intermediate host to act as a relay for the packets ๐Ÿงš this relay usually lives out on the public Internet and passes packets between two hosts that are both stuck behind NATs. main character relay energy ๐Ÿ‘‘

this spec defines a protocol called TURN ๐Ÿ’œ it 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 how that relaying actually works โœจ the client gets this going by obtaining an IP address and port on the server, called the relayed transport address ๐ŸŒธ when a peer sends a packet to that relayed transport address, the server forwards it to the client. when the client sends a data packet to the server, the server relays it to the right peer, using the relayed transport address as the source ๐Ÿ’…

a client using TURN must have some way to tell its peers about the relayed transport address, and to learn each peer's IP address and port (more precisely, each peer's server-reflexive transport address, see Section 2) ๐Ÿซถ 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 [RFC5245], then the relayed transport address and the peers' IP addresses and ports go into 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 info inside the body of its messages ๐ŸŽ€ if you're using TURN and ICE with some other rendezvous protocol, [MMUSIC-ICE-NONSIP] has guidance on what that protocol needs to handle ๐ŸŒˆ

okay real talk, a TURN server is expensive to run ๐Ÿ˜ญ it's very likely to get two NATted hosts talking, but the provider usually needs a high-bandwidth Internet connection for it. so it's best to only use a TURN server when a direct path can't be found ๐Ÿซ  when the client and a peer use ICE to pick their path, ICE tries hole punching first to look for a direct route, and only falls back to a TURN server if that doesn't work ๐Ÿฆ‹โœจ

TURN was originally made to support multimedia sessions signaled with SIP ๐Ÿ’– since SIP supports forking, TURN supports multiple peers per relayed transport address, which other approaches (e.g., SOCKS [RFC1928]) don't do ๐Ÿ‘‘ that said, care was taken to make sure TURN works for other kinds of applications too ๐Ÿงš

TURN was designed as one piece of the bigger ICE approach to NAT traversal ๐Ÿ’œ implementors are strongly urged to look into ICE and seriously consider using it for their application ๐Ÿ”ฅ but it's totally possible to use TURN without ICE ๐ŸŒธ

TURN is an extension of the STUN (Session Traversal Utilities for NAT) protocol [RFC5389] ๐Ÿซถ most TURN messages are STUN-formatted messages, though not all of them ๐Ÿ“ if you're reading this doc, you should already be familiar with STUN ๐ŸŽ€


2. Overview of Operation โœจ

this section gives a quick overview of how TURN works ๐Ÿฆ‹ it is non-normative, so think of it as the vibe check, not the rulebook ๐Ÿ’…

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 sits a TURN server ๐Ÿงš somewhere else on the Internet are one or more peers the TURN client wants to talk to ๐Ÿ’œ those peers may or may not be behind NATs too ๐Ÿ‘‘ the client uses the server as a relay to send packets to these peers and 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           |       //     |+---------+
10.1.1.2:49721       192.0.2.15:3478     |+-+  //     Peer A
        |               |               ||N| /       Host Transport
        |   +-+         |               ||A|/        Address
        |   | |         |               v|T|     192.168.100.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 ๐ŸŽ€ here the TURN client and TURN server are separated by a NAT, with the client on the private side and the server on the public side ๐Ÿงš this NAT is assumed to be a "bad" NAT, for example one with a mapping property of "address-and-port-dependent mapping" (see [RFC4787]) ๐Ÿ’€

the client talks to the server from a (IP address, port) combo called the client's HOST TRANSPORT ADDRESS ๐Ÿฆ‹ (an IP address plus a port together is called a TRANSPORT ADDRESS ๐Ÿ’œ)

the client sends TURN messages from its host transport address to a transport address on the TURN server called the TURN SERVER TRANSPORT ADDRESS ๐ŸŒธ the client learns that address through some unspecified means (e.g., configuration), and it's usually shared by lots of clients at once ๐Ÿซถ

since the client is behind a NAT, the server sees the client's packets as coming from a transport address on the NAT itself ๐Ÿ‘€ this is called the client's SERVER-REFLEXIVE transport address ๐Ÿ’… packets the server sends to that server-reflexive address get forwarded by the NAT to the client's host transport address ๐Ÿ“

the client uses TURN commands to create and manage an ALLOCATION on the server โœจ an allocation is a data structure living on the server ๐Ÿงš it holds, among other things, the RELAYED TRANSPORT ADDRESS for that allocation ๐Ÿ‘‘ the relayed transport address is the transport address on the server that peers 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 a note about which peer it's meant for, and the server relays it to that peer ๐ŸŽ€ the data rides inside a TURN message; when it reaches the server, it's pulled out and sent to the peer in a UDP datagram ๐ŸŒˆ going the other way, a peer sends application data in a UDP datagram to the allocation's relayed transport address ๐Ÿ˜ญ the server wraps that data in a TURN message, sends it to the client, and includes which peer sent it ๐Ÿ’… since every TURN message says which peer the client is talking to, one allocation can handle multiple peers at once ๐Ÿ‘‘

when the peer is behind a NAT, the client has to identify it by its server-reflexive transport address, not its host transport address ๐Ÿฆ‹ for example, to send application data to Peer A in the diagram above, the client must specify 192.0.2.150:32102 (Peer A's server-reflexive transport address), not 192.168.100.2:49582 (Peer A's host transport address) ๐Ÿ™ˆ

each allocation on the server belongs to a single client and has exactly one relayed transport address that only that allocation uses ๐Ÿซถ so when a packet shows up at a relayed transport address, the server knows exactly which client it's meant for ๐Ÿ’œ

and the client can have multiple allocations on a server at the same time ๐Ÿงšโœจ

2.1. Transports โœจ

Okay bestie, so TURN as defined in this spec always uses UDP between the server and the peer ๐Ÿฆ‹. The spec does let you pick any one of UDP, TCP, or TLS over TCP to carry 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         |
        +----------------------------+---------------------+

If the client uses TCP or TLS-over-TCP to reach the server, the server converts between those 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 will probably pick UDP between the client and the server too ๐ŸŒธ So you might be like, "wait, why even bother with TCP and TLS-over-TCP?" Valid question, bestie ๐Ÿงš

TURN supports TCP between the client and the server because some firewalls are set up to block UDP entirely ๐Ÿšซ These firewalls block UDP but let TCP through, partly because TCP has traits that make it obvious to the firewall what the protected node actually wants. Like, TCP has a three-way handshake that makes it clearer the protected node really wants that particular connection, whereas with UDP the firewall can only guess which flows are wanted by using filtering rules ๐Ÿคทโ€โ™€๏ธ Also, TCP has explicit connection teardown, while with UDP the firewall has to use timers to guess when a flow is done โฒ๏ธ

TURN supports TLS-over-TCP between the client and the server because TLS gives extra security properties that TURN's default digest authentication doesn't, and some clients might want those ๐Ÿ” Specifically, TLS lets the client check that it's talking to the right server, and it keeps TURN control messages confidential ๐Ÿซถ TURN doesn't require TLS, though, because TLS has more overhead than digest authentication. For example, with TLS, most application data would likely be doubly encrypted (once by TLS, and once to make sure it's still encrypted inside the UDP datagram) ๐Ÿ˜ญ

There's a planned extension to TURN that adds TCP between the server and the peers [TURN-TCP] ๐Ÿ‘€ 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 ๐Ÿ’œ

TURN, as defined in this specification, only supports IPv4. All IP addresses in this specification must be IPv4 addresses. There's a planned extension to add IPv6 support and relaying between IPv4 and IPv6 [TURN-IPv6] ๐ŸŒˆ

In some TURN applications, the client might send and receive packets other than TURN packets on the host transport address it uses to talk to the server. That can happen, for example, when TURN is used with ICE ๐Ÿงš In those cases, the client can tell TURN packets apart from everything else by checking the source address of each arriving packet: anything coming from the TURN server is a TURN packet โœจ

2.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 to describe the kind of allocation it wants (for example, the lifetime). Relaying data has security implications, so the server requires the client to authenticate itself, usually with STUN's long-term credential mechanism, to prove it's allowed to use the server ๐Ÿ”‘

Once a relayed transport address is allocated, the client has to keep the allocation alive. The client must periodically send a Refresh request to the server to do that ๐Ÿ”„ TURN deliberately uses a different method (Refresh instead of Allocate) for refreshes, so the client finds out if the allocation disappears for some reason ๐Ÿ‘€

How often the Refresh transaction happens depends on 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, but short enough that allocations from clients who've unexpectedly quit get cleaned up in a timely manner ๐Ÿ“ The client can ask for a longer lifetime in the Allocate request and may change its request in a Refresh request, but the server always tells you the actual lifetime in the response โณ The client must issue a new Refresh transaction within "lifetime" seconds of the previous Allocate or Refresh transaction. When a client no longer wants an allocation, it should delete it with a Refresh request that has a requested lifetime of 0 ๐Ÿ—‘๏ธ

Both the server and the client keep track of something called the 5-TUPLE. On the client side, 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. On the server side, it's 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 actually sees ๐Ÿ‘‘

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 must create a second allocation using a different 5-tuple (for example, by using a different client host address or port) ๐Ÿ’…

NOTE: While this document talks about 5-tuples, the TURN server can store whatever identifier it likes, as long as the results come out identical. Specifically, an implementation may use a file-descriptor in place of a 5-tuple to represent a TCP connection ๐Ÿง 
  TURN                                 TURN           Peer          Peer
  client                               server          A             B
    |-- Allocate request --------------->|             |             |
    |                                    |             |             |
    |<--------------- Allocate failure --|             |             |
    |                 (401 Unauthorized) |             |             |
    |                                    |             |             |
    |-- Allocate request --------------->|             |             |
    |                                    |             |             |
    |<---------- 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 no credentials ๐Ÿ™ˆ The server requires every request to be authenticated with STUN's long-term credential mechanism, so it rejects the request with a 401 (Unauthorized) error code. The client tries again, this time including credentials (not shown). This time the server accepts the Allocate request and returns an Allocate success response with (among other things) the relayed transport address assigned to the allocation ๐ŸŽ‰ Later, the client decides to refresh the allocation and sends a Refresh request. The refresh is accepted, and the server replies with a Refresh success response ๐Ÿ’œ

2.3. Permissions ๐Ÿ”ฅ

To ease the worries of enterprise IT admins that TURN could be used to sneak past corporate firewalls, TURN includes the idea of permissions ๐Ÿ›ก๏ธ TURN permissions copy the address-restricted filtering behaviour of NATs that comply with [RFC4787] ๐Ÿ˜Œ

An allocation can have zero or more permissions. Each permission is made of an IP address and a lifetime. When the server gets a UDP datagram on the allocation's relayed transport address, it first checks the list of permissions. 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 one. This was chosen to match how a NAT that complies with [RFC4787] behaves ๐Ÿงš

The client can install or refresh a permission using either a CreatePermission request or a ChannelBind request. With CreatePermission, you can install or refresh multiple permissions in a single request, which matters a lot for applications 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) do not install or refresh any permissions ๐Ÿ”

Permissions live within the context of an allocation, so adding or expiring a permission in one allocation doesn't affect any other allocations ๐Ÿฆ‹

2.4. Send Mechanism โœจ

okay so there are two ways the client and its peers can swap application data through the TURN server ๐Ÿ’… The first one uses the Send and Data methods, and the second one uses channels ๐Ÿฆ‹ Both ways let the client chat with multiple peers over one single allocated relayed transport address, so both need a way for the client to tell the server which peer should get the data, and for the server to tell the client which peer sent it ๐Ÿซถ

The Send mechanism uses Send and Data indications ๐Ÿ“จ Send indications carry application data from the client up to the server, and Data indications carry it from the server back down to the client ๐Ÿ’–

When the client is using the Send mechanism, it sends a Send indication to the TURN server that contains (a) an XOR-PEER-ADDRESS attribute with the (server-reflexive) transport address of the peer, and (b) a DATA attribute holding the application data ๐ŸŽ€ When the server gets that Send indication, it pulls the application data out of the DATA attribute and sends it off in a UDP datagram to the peer, using the allocated relay address as the source address ๐Ÿš€ Also, you don't need to specify the relayed transport address, because it's already implied by the 5-tuple used for the Send indication ๐Ÿงš

Going the other way, UDP datagrams that arrive at the relayed transport address on the TURN server get turned into Data indications and sent to the client ๐ŸŒธ The server-reflexive transport address of the peer goes in an XOR-PEER-ADDRESS attribute, and the data itself goes in a DATA attribute ๐Ÿ’œ Since the relayed transport address uniquely identified the allocation, the server knows exactly which client should receive the data ๐Ÿ‘‘

โš ๏ธ Send and Data indications cannot be authenticated, because the long-term credential mechanism of STUN doesn't support authenticating indications. Lowkey this is not as big a deal as it sounds, since the client-to-server leg is only half of the total path to the peer ๐Ÿ™ˆ Applications that want proper security should encrypt the data sent between the client and a peer ๐Ÿ”

Because Send indications aren't authenticated, an attacker can send bogus Send indications to the server, which will then relay them to a peer ๐Ÿ’€ To partly mitigate this attack, TURN requires that the client install a permission towards a peer before sending data to it using a Send indication ๐Ÿ›ก๏ธ

  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

So in Figure 3, the client already has an allocation and now wants to send data to its peers ๐ŸŽฌ First it makes 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 didn't happen, the server wouldn't relay data between the client and the server, so it's a must-do step ๐Ÿ™…โ€โ™€๏ธ Then the client sends data to Peer A with a Send indication, and the server pulls out the application data and forwards it in a UDP datagram to Peer A, using the relayed transport address as the source transport address ๐Ÿ’Œ When a UDP datagram from Peer A shows up at the relayed transport address, its contents get placed into a Data indication and forwarded to the client ๐Ÿฆ‹ Later on, the client tries to chat with Peer B. But no permission has been installed for Peer B, so the server drops both the Send indication from the client and the UDP datagram from the peer ๐Ÿ˜ญ Not the vibe!


2.5. Channels ๐ŸŒˆ

For some apps (like Voice over IP ๐Ÿ“ž), the 36 bytes of overhead that a Send indication or Data indication adds to the application data can really pump up the bandwidth needed between the client and the server ๐Ÿ˜ฉ To fix that, TURN gives us a second way for the client and server to link data to a specific peer ๐Ÿซถ

This second way uses an alternate packet format called the ChannelData message ๐Ÿ“ The ChannelData message doesn't use the STUN header that other TURN messages use. Instead, it has a 4-byte header that includes a number called a channel number ๐Ÿ”ข Each channel number in use is bound to one specific peer, so it acts 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 and includes an unbound channel number and the transport address of the peer ๐ŸŽ€ Once the channel is bound, the client can use a ChannelData message to send the server data meant for that peer ๐Ÿ’… And the server can relay data from that peer back toward the client using a ChannelData message too ๐Ÿ”

Channel bindings last for 10 minutes unless they get refreshed. This lifetime was picked to be longer than the permission lifetime ๐Ÿ•ฐ๏ธ To refresh a channel 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 ๐Ÿ˜ค

  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

Figure 4 shows the channel mechanism in action ๐ŸŽฅ The client already has an allocation and now wants to bind a channel to Peer A. So it sends a ChannelBind request to the server, specifying Peer A's transport address and a channel number (0x4001) ๐ŸŒŸ After that, the client can send application data wrapped up inside ChannelData messages to Peer A. That's the "[0x4001] data" in the figure, 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, which is the peer bound to channel number 0x4001 ๐Ÿšš

Now the reverse direction. When Peer A sends a UDP datagram to the relayed transport address, it arrives at the server on the relayed transport address assigned to the allocation ๐Ÿ“ฌ Since that datagram came from Peer A, and 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 has been bound, the client is free to mix ChannelData messages and Send indications together ๐Ÿน In the figure, the client later decides to use a Send indication instead of a ChannelData message to send more data to Peer A. The client might do this, for example, so it can use the DONT-FRAGMENT attribute (see the next section) ๐Ÿงฉ However, once a channel is bound, the server will always use a ChannelData message, as shown in the call flow ๐Ÿ’ซ

Also, ChannelData messages can only be used for peers that the client has bound a channel to ๐Ÿ™Œ In the example above, Peer A has been bound to a channel but Peer B hasn't, so application data to and from Peer B would use the Send mechanism ๐Ÿ’•


2.6. Unprivileged TURN Servers ๐Ÿฆธโ€โ™€๏ธ

This version of TURN is designed so the server can be built as an application that runs in user space under commonly available operating systems, without needing special privileges ๐ŸŒท This was a deliberate choice to make a TURN server 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 ๐Ÿค

This design decision has the following implications 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 ๐ŸŒฉ๏ธ
  • ICMP messages are not relayed by the server ๐Ÿ™…
  • There is no end-to-end fragmentation, since the packet is re-assembled at the server ๐Ÿงฉ

Future work may specify alternate TURN semantics that address these limitations ๐Ÿ”ฎ

2.7. Avoiding IP Fragmentation โœจ

okay so fragmentation is the thing that can absolutely ruin your whole vibe ๐Ÿ’€. For reasons described in [Frag-Harmful], applications, especially ones sending large volumes of data, should try hard to avoid having their packets fragmented. TCP apps can more or less ignore this because fragmentation avoidance is already a standard part of TCP ๐Ÿ™Œ. But UDP apps (and therefore any app using this version of TURN) have to handle fragmentation avoidance themselves ๐Ÿซถ.

There are two approaches the client and the peer can take to avoid IP fragmentation ๐Ÿฆ‹.

The first approach is to avoid sending large amounts of application data in the TURN messages and UDP datagrams exchanged between the client and the peer. This is what most VoIP (Voice-over-IP) apps do ๐Ÿ“ž. The trick is that the IP specification [RFC0791] says IP packets up to 576 bytes should never need to be fragmented, so the app can use that as its safe zone ๐Ÿงš.

How much application data fits without fragmentation depends on the details of the TURN session between the client and the server. That includes whether UDP, TCP, or TLS transport is used, whether ChannelData messages or Send and Data indications are used, and whether any additional attributes (such as the DONT-FRAGMENT attribute) are included ๐ŸŽ€. Another factor that's hard to figure out is whether the MTU gets reduced somewhere along the path for other reasons, like IP-in-IP tunneling ๐ŸŒ€.

As a guideline, sending a maximum of 500 bytes of application data in a single TURN message (sent by the client on the client-to-server leg) or a UDP datagram (sent by the peer on the peer-to-server leg) will generally avoid IP fragmentation ๐Ÿ“. If you want to lower the chance of fragmentation even more, it is recommended that the client use ChannelData messages when transferring significant volumes of data. The reason is that the overhead of a ChannelData message is less than that of Send and Data indications ๐Ÿ’œ.

The second approach the client and peer can take is to use a path MTU discovery algorithm to find the maximum amount of application data that can be sent without fragmentation ๐Ÿ”ฅ.

Here's the catch: servers implementing this version of TURN do not relay ICMP messages, so the classic path MTU discovery algorithm defined in [RFC1191] can't discover the MTU of the transmission path between the client and the peer ๐Ÿ˜ญ. (Even if servers did relay ICMP messages, the algorithm still wouldn't always work, since combined NAT/firewall devices often filter ICMP messages out ๐Ÿ™ˆ.)

So the client and server need to use a path MTU discovery algorithm that doesn't require ICMP messages. The Packetized Path MTU Discovery algorithm defined in [RFC4821] is one such algorithm ๐Ÿ‘‘.

The details of how to use the algorithm of [RFC4821] with TURN are still under investigation. As a step towards that goal, though, this version of TURN supports a DONT-FRAGMENT attribute โœจ. When the client includes this attribute in a Send indication, it tells the server to set the DF bit in the resulting UDP datagram it sends to the peer. Some servers may be unable to set the DF bit, so the client should also include this attribute in the Allocate request. Any server that doesn't support the DONT-FRAGMENT attribute will indicate this by rejecting the Allocate request ๐Ÿ™…โ€โ™€๏ธ.

2.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 (like 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 the RTP stream to be on an even port number, and the associated RTP Control Protocol (RTCP) stream, if present, to be on the next highest port ๐ŸŒธ. So that clients can work with peers that still need this, TURN lets the client ask the server to allocate a relayed transport address with an even port number. The client can also optionally ask the server to reserve the next-highest port number for a later allocation ๐Ÿง.

2.9. Anycast Discovery of Servers ๐Ÿ“ก

This version of TURN has been designed so that a method of doing anycast discovery of a TURN server over UDP can be specified in the future ๐ŸŒˆ.

Specifically, a TURN server can reject an Allocate request and suggest that the client try an alternate server. To avoid certain types of attacks, the client must use the same credentials with the alternate server that it would have used with the initial server ๐Ÿ”.

3. Terminology ๐Ÿ“–

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 [RFC2119] ๐Ÿ’….

Readers are expected to be familiar with [RFC5389] and the terms defined there ๐Ÿค“.

The following terms are used in this document:

TURN: The protocol spoken between a TURN client and a TURN server. It's an extension to the STUN protocol [RFC5389]. 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 communicate with. The TURN server relays traffic between the TURN client and its peer(s). The peer doesn't interact with the TURN server using the protocol defined in this document. Instead, the peer receives data sent by the TURN server and sends data towards the TURN server ๐Ÿงš.

Transport Address: The combination 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 "public side" of a NAT. The NAT allocates this address to correspond to a specific host transport address ๐ŸŒ.

Relayed Transport Address: A transport address on the TURN server that is used for relaying packets between the client and a peer. A peer sends to this address on the TURN server, and the packet is then relayed to the client ๐ŸŽ€.

TURN Server Transport Address: A transport address on the TURN server that is used for sending TURN messages to the server. This is the transport address the client uses to communicate with 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, along with related state such as permissions and expiration timers ๐Ÿฐ.

5-tuple: The combination (client IP address and port, server IP address and port, and transport protocol, which is currently one of UDP, TCP, or TLS) used to communicate between the client and the server. The 5-tuple uniquely identifies this communication stream. It also uniquely identifies the Allocation on the server ๐Ÿ”‘.

Channel: A channel number and 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 ๐ŸŒŠ.

Permission: The IP address and transport protocol (but not the port) of a peer that is 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 ๐Ÿšช.

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 message-digest. To prevent reply attacks, the server should change the nonce regularly ๐Ÿ”„.

4. General Behavior โœจ

okay so this section is all the general TURN rules that apply to every TURN message ๐Ÿ’…

TURN is an extension to STUN. Every TURN message is STUN-formatted except the ChannelData message ๐Ÿฆ‹ All the base processing rules in [RFC5389] apply to STUN-formatted messages, which means every message-forming and message-processing description in this document is implicitly prefixed with the rules of [RFC5389] ๐Ÿซถ

[RFC5389] specifies an authentication mechanism called the long-term credential mechanism. TURN servers and clients MUST implement this mechanism. The server MUST demand that all requests from the client be authenticated using this mechanism, or that an equally strong or stronger mechanism for client authentication is used ๐Ÿ”

Note that the long-term credential mechanism only applies to requests and can't be used to authenticate indications, so indications in TURN are never authenticated ๐Ÿ™ˆ 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 give each client a unique username, or MAY give the same username to more than one client (like everyone from the same department or company) ๐Ÿ‘ฅ For each allocation, the server SHOULD generate a new random nonce when the allocation is first attempted, following the randomness recommendations in [RFC4086]. It SHOULD also expire the nonce at least once every hour during the lifetime of the allocation โณ

All requests after the initial Allocate must use the same username that created the allocation, so attackers can't hijack the client's allocation ๐Ÿšซ Specifically: if the server requires the long-term credential mechanism, a non-Allocate request passes authentication under it, the 5-tuple identifies an existing allocation, but the request doesn't use the same username that created the allocation, then the request MUST be rejected with a 441 (Wrong Credentials) error. Not it ๐Ÿ˜ค

When a TURN message reaches the server from the client, the server uses the 5-tuple in the message to find the matching allocation ๐Ÿ” For all TURN messages (including ChannelData) except an Allocate request, if the 5-tuple doesn't identify an existing allocation, then the message MUST either be rejected with a 437 Allocation Mismatch error (if it's a request) or silently ignored (if it's an indication or a ChannelData message). A client that gets a 437 error response to a request other than Allocate MUST assume the allocation no longer exists ๐Ÿ’€

[RFC5389] defines a bunch 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 (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 doesn't use the backwards-compatibility mechanism described in [RFC5389] ๐Ÿ™…โ€โ™€๏ธ

TURN, as defined in this spec, only supports IPv4 ๐ŸŒธ The client's IP address, the server's IP address, and all IP addresses appearing in a relayed transport address MUST be IPv4 addresses.

By default, TURN runs on the same ports as STUN: 3478 for TURN over UDP and TCP, and 5349 for TURN over TLS ๐ŸŽ€ TURN also has its own SRV names: "turn" for UDP and TCP, and "turns" for TLS. You can use either the SRV procedures or the ALTERNATE-SERVER procedures (both described in Section 6) to run TURN on a different port ๐Ÿ”€

To keep things interoperable, a TURN server MUST support UDP transport between the client and the server, and SHOULD support TCP and TLS transport ๐Ÿซถ

When UDP is used between the client and the server, the client retransmits a request if it doesn't get 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 the server to recognize this and treat the request as idempotent (see [RFC5389]) ๐Ÿง  Some implementations meet this by remembering all received requests and their responses for 40 seconds. Other implementations reprocess the request and arrange for that reprocessing to return essentially the same response. To help implementors who go with the latter approach (the so-called "stateless stack approach"), this specification includes some implementation notes on how that might work ๐Ÿ“ Implementations are free to pick either approach, or some other approach that gives the same results ๐Ÿ’–

When TCP is used between the client and the server, a bit error can corrupt a length field in a TURN packet, and then the receiver loses sync with the incoming stream of TURN messages ๐Ÿ˜ญ A client or server that detects a long run of invalid TURN messages over TCP SHOULD close the TCP connection, so the other end can notice the situation faster ๐Ÿ”Œ

Denial-of-service is a real threat here. Clients with valid usernames and passwords can attack the server, intentionally or by accident, so guard against it.

To mitigate denial-of-service attacks against the server (intentional or unintentional) 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 on the amount of bandwidth those allocations can use ๐Ÿšง The server should reject new allocations that would exceed the limit on active allocations with a 486 (Allocation Quota Exceeded) error (see Section 6.2), and should discard application data traffic that goes over the bandwidth quota ๐Ÿ›‘


5. Allocations ๐ŸŽ€

All TURN operations revolve around allocations, and every TURN message is associated with an allocation ๐Ÿ’œ An allocation conceptually consists of the following state data:

  • the relayed transport address;
  • the 5-tuple: (client's IP address, client's port, server IP address, server port, transport protocol);
  • the authentication information;
  • the time-to-expiry;
  • a list of permissions;
  • a list of channel to peer bindings.

The relayed transport address is the transport address the server allocates for talking to peers, while 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 ๐Ÿชž

Both the relayed transport address and the 5-tuple MUST be unique across all allocations, so either one can uniquely identify the allocation ๐Ÿ†”

The authentication information (like 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 start out as the ones used in the authenticated Allocate request that created the allocation, though the server can change the nonce value during the allocation's lifetime using a 438 (Stale Nonce) reply ๐Ÿ”„ Also, rather than storing the password explicitly (for security reasons), it may be desirable for the server to store the key value instead. The key value is an MD5 hash over the username, realm, and password (see [RFC5389]) ๐Ÿ™ˆ

The time-to-expiry is the number of seconds left until the allocation expires โฐ Each Allocate or Refresh transaction sets this timer, which then ticks down towards 0. By default, each Allocate or Refresh transaction resets the 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 count on it ๐Ÿšซ When an allocation expires, the state data associated with it can be freed ๐Ÿงน

The list of permissions is described in Section 8, and the list of channels is described in Section 11 ๐Ÿฆ‹


6. Creating an Allocation ๐Ÿš€

An allocation on the server is created using an Allocate transaction.

6.1. Sending an Allocate Request ๐ŸŽ€

okay so first things first, the client has to build its Allocate request, and it's giving very deliberate energy ๐Ÿ’…

The client starts by picking a host transport address. It is RECOMMENDED that the client grab a currently unused one, usually by letting the underlying OS pick a free port for a brand new socket ๐Ÿงš

Then the client picks a transport protocol to use between itself and the server. The transport protocol MUST be one of UDP, TCP, or TLS-over-TCP. Since this spec only allows UDP between the server and the peers, it is RECOMMENDED that the client pick UDP unless it has a real reason to go with something else ๐Ÿฆ‹ One reason would be that the client believes, either from configuration or from experimenting, that it can't reach any TURN server over UDP. More on that in Section 2.1 โœจ

The client also picks a server transport address, and it SHOULD do this part as follows ๐Ÿซถ The client gets a domain name for a TURN server, maybe through configuration. Then it uses the DNS procedures from [RFC5389], except it swaps the SRV service name from "stun" to "turn" (or "turns" for TURN over TLS) ๐ŸŒˆ For example, to find servers in the example.com domain, the client looks up _turn._udp.example.com if it wants UDP, _turn._tcp.example.com for TCP, or _turns._tcp.example.com for TLS-over-TCP. Main character energy for sure ๐Ÿ‘‘

The client MUST include a REQUESTED-TRANSPORT attribute in the request. This attribute says what transport protocol to use between the server and the peers, and not the one that shows up in the 5-tuple ๐Ÿ’€ In this spec, the REQUESTED-TRANSPORT type is always UDP. It's only there so future extensions can name other protocols, which is so smart ๐Ÿ“

If the client wants the server to set the time-to-expiry field of the allocation to something other than the default lifetime, it MAY include a LIFETIME attribute with the value it wants ๐ŸŒธ That's just a request though, so the server can pick a different value if it wants. Also, the server will ignore any request to set the field to less than the default value. Not me the server being so strict about it ๐Ÿ™ˆ

If the client plans to use the DONT-FRAGMENT attribute later in one or more Send indications on this allocation, it SHOULD include DONT-FRAGMENT in the Allocate request too ๐Ÿ”ฅ That way the client can test whether the server supports this attribute at all. Smart move, bestie ๐Ÿ’œ

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, no drama. Setting the R bit in the EVEN-PORT attribute to 1 asks 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, asking the server to use a port that was reserved earlier for this allocation ๐Ÿฆ‹ If RESERVATION-TOKEN is included, then the client MUST omit the EVEN-PORT attribute. You can't have both, periodt ๐Ÿ›‘

Once everything is built, the client sends the Allocate request on the 5-tuple ๐Ÿš€ And that's the whole vibe!

6.2. Receiving an Allocate Request โœจ

okay so when the server gets an Allocate request, it runs through a little checklist ๐Ÿ’…. Here are the checks, in order:

  1. The server MUST require that the request be authenticated ๐Ÿ”. This authentication MUST be done using the long-term credential mechanism of [RFC5389] unless the client and server agree to use another mechanism through some procedure outside the scope of this document.
  2. The server checks if the 5-tuple is currently in use by an existing allocation. If yes, the server rejects the request with a 437 (Allocation Mismatch) error. ๐Ÿ™…โ€โ™€๏ธ
  3. The server checks if the request contains a REQUESTED-TRANSPORT attribute. If the REQUESTED-TRANSPORT attribute is not included or is malformed, the server rejects the request with a 400 (Bad Request) error. Otherwise, if the attribute is included but specifies a protocol other than UDP, the server rejects the request with a 442 (Unsupported Transport Protocol) error. ๐Ÿšซ
  4. The request may contain a DONT-FRAGMENT attribute. If it does, but the server does not support sending UDP datagrams with the DF bit set to 1 (see Section 12), then the server treats the DONT-FRAGMENT attribute in the Allocate request as an unknown comprehension-required attribute. ๐Ÿงฉ
  5. The server checks if the request contains a RESERVATION-TOKEN attribute. If yes, and the request also contains an EVEN-PORT attribute, then the server rejects the request with a 400 (Bad Request) error. Otherwise, it checks to see if the token is valid (i.e., the token is in range and has not expired and the corresponding relayed transport address is still available). If the token is not valid for some reason, the server rejects the request with a 508 (Insufficient Capacity) error. ๐ŸŽŸ๏ธ
  6. The server checks if the request contains an EVEN-PORT attribute. If yes, then the server checks that it can satisfy the request (i.e., can allocate a relayed transport address as described below). If the server cannot satisfy the request, then the server rejects the request with a 508 (Insufficient Capacity) error. ๐Ÿฅฒ
  7. 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 exceed some locally defined allocation quota. The server is free to define this allocation quota any way it wishes, but the server SHOULD define it based on the username used to authenticate the request, and not on the client's transport address. ๐Ÿ“Š
  8. Also at any point, the server MAY choose to reject the request with a 300 (Try Alternate) error if it wishes to redirect the client to a different server. The use of this error code and attribute follow the specification in [RFC5389]. ๐Ÿ”€

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 are initially empty. ๐ŸŽ‰

The server chooses a relayed transport address for the allocation as follows:

  • If the request contains a RESERVATION-TOKEN, the server uses the previously reserved transport address corresponding to the included token (if it is still available). Note that the reservation is a server-wide reservation and is not specific to a particular allocation, since the Allocate request containing the RESERVATION-TOKEN uses a different 5-tuple than the Allocate request that made the reservation. The 5-tuple for the Allocate request containing the RESERVATION-TOKEN attribute can be any allowed 5-tuple; it can use a different client IP address and port, a different transport protocol, and even different server IP address and port (provided, of course, that the server IP address and port are ones on which the server is listening for TURN requests). ๐Ÿงš
  • If the request contains an EVEN-PORT attribute with the R bit set to 0, then the server allocates a relayed transport address with an even port number. ๐Ÿ“
  • If the request contains an EVEN-PORT attribute with the R bit set to 1, then 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, while the relayed transport address with port N+1 is assigned a token and reserved for a future allocation. The server MUST hold this reservation for at least 30 seconds, and MAY choose to hold longer (e.g., until the allocation with port N expires). The server then includes the token in a RESERVATION-TOKEN attribute 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 running on the same host as the TURN server application will not be impacted by allocating ports outside this range. This condition can often be satisfied by running the TURN server application on a dedicated machine and/or by arranging that any other applications on the machine allocate ports before the TURN server application starts. In any case, 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 IETF is currently investigating the topic of randomized port assignments to avoid certain types of attacks (see [TSVWG-PORT]). It is strongly recommended that a TURN implementor keep abreast of this topic and, if appropriate, implement a randomized port assignment algorithm. 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 determines the initial value of the time-to-expiry field as follows. If the request contains a LIFETIME attribute, then the server computes the minimum of the client's proposed lifetime and the server's maximum allowed lifetime. If this computed value is greater than the default lifetime, then the server uses the computed lifetime as the initial 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 wish to use a smaller maximum allowed lifetime (perhaps as small as the default lifetime) to more quickly remove orphaned allocations (that is, allocations where the corresponding client has crashed or terminated or the client connection has been lost for some reason). Also, note that the time-to-expiry is recomputed with each successful Refresh request, and thus the value computed here applies only until the first refresh. โฐ

Once the allocation is created, the server replies with a success response. The success response contains:

  • An XOR-RELAYED-ADDRESS attribute containing the relayed transport address. ๐Ÿ“ฎ
  • A LIFETIME attribute containing the current value of the time-to-expiry timer. โณ
  • A RESERVATION-TOKEN attribute (if a second relayed transport address was reserved). ๐ŸŽŸ๏ธ
  • An XOR-MAPPED-ADDRESS attribute 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 does not make use of this value, but clients running ICE can often need this value and can thus avoid having to do an extra Binding transaction with some STUN server to learn it. ๐Ÿง 

The response (either success or error) is sent back to the client on the 5-tuple. ๐Ÿ“ฌ

NOTE: When the Allocate request is sent over UDP, section 7.3.1 of [RFC5389] requires that the server handle the possible retransmissions of the request so that retransmissions do not cause multiple allocations to be created. Implementations may achieve 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 the LIFETIME attribute can be taken from the time-to-expiry field in the allocate state data, even though this value may differ slightly from the LIFETIME value originally returned. In addition, the server may need to store an indication of any reservation token returned in the original response, so that this may 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 intervening time period). 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 matter will eventually timeout, since the client will not refresh it. Furthermore, if the client later retries with the same 5-tuple but different transaction id, it will receive a 437 (Allocation Mismatch), 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. ๐ŸŒ€

6.3. Receiving an Allocate Success Response โœจ

okay so if the client gets an Allocate success response, it MUST check that the mapped address and the relayed transport address are in an address family it understands and is ready to handle ๐Ÿซถ this spec only covers the case where both of those addresses are IPv4 addresses ๐ŸŒธ if either one is in an address family the client can't handle, then the client MUST delete the allocation (Section 7) and MUST NOT attempt to create another allocation on that server until it believes the mismatch has been fixed ๐Ÿ’€

The IETF is currently considering transition mechanisms between IPv4 and IPv6 that could result in a client sending an Allocate request over IPv6, but the request would arrive at the server over IPv4, or vice versa. Lowkey a whole plot twist ๐Ÿฆ‹

otherwise, the client makes its own copy of the allocation data structure so it can track what's happening on the server โœจ the big thing is that it needs to remember the actual lifetime the server sent back, not the value it asked for in the request ๐ŸŽ€

the client also has to remember the 5-tuple it used for the request, plus the username and password it used to authenticate, so it can reuse them for later messages ๐Ÿ” it also needs to keep track of the channels and permissions it sets up on the server ๐Ÿงš

the client will probably want to send the relayed transport address to its peers (using some method not specified here) so the peers can talk to it ๐Ÿ’– it may also want to use the server-reflexive address it gets in the XOR-MAPPED-ADDRESS attribute during its ICE processing ๐Ÿ‘‘


6.4. Receiving an Allocate Error Response ๐Ÿ™ˆ

if the client gets an Allocate error response, what it does next depends on the actual error code ๐Ÿ˜ญ

  • (Request timed out): there's either a problem with the server, or a problem reaching the server over the chosen transport ๐Ÿฅฒ the client counts the current transaction as failed, but it MAY choose to retry the Allocate request using a different transport (e.g., TCP instead of UDP) ๐Ÿ”„
  • 300 (Try Alternate): the server wants the client to use the server named in the ALTERNATE-SERVER attribute instead ๐Ÿงญ the client counts this transaction as failed, but it SHOULD try the Allocate request with the alternate server before trying any other servers (e.g., other servers discovered using the SRV procedures) ๐Ÿ’… when it does, it follows the ALTERNATE-SERVER procedures specified in [RFC5389] โœจ
  • 400 (Bad Request): the server thinks the client's request is malformed somehow ๐Ÿ“ the client counts the transaction as failed. It MAY notify the user or operator, and it SHOULD NOT retry the request with this server until it believes the problem has been fixed ๐Ÿ› ๏ธ
  • 401 (Unauthorized): if the client followed the long-term credential mechanism procedures and still gets this error, the server is not accepting its credentials ๐Ÿ˜ค the client counts the transaction as failed and SHOULD notify the user or operator. It SHOULD NOT send any further requests to this server until it believes the problem has been fixed ๐Ÿšซ
  • 403 (Forbidden): the request is valid, but the server is refusing to do it, probably because of administrative restrictions ๐Ÿ”’ the client counts the transaction as failed. It MAY notify the user or operator, and it SHOULD NOT retry the same request with this server until it believes the problem has been fixed ๐Ÿ’œ
  • 420 (Unknown Attribute): if the client put a DONT-FRAGMENT attribute in the request, and the server rejected it with a 420 and listed DONT-FRAGMENT in the UNKNOWN-ATTRIBUTES attribute of the error response, then the client now knows the server doesn't support DONT-FRAGMENT ๐Ÿง the client counts the transaction as failed but MAY choose to retry the Allocate request without the DONT-FRAGMENT attribute ๐ŸŒˆ
  • 437 (Allocation Mismatch): this means the client picked a 5-tuple that the server sees as already in use ๐Ÿ‘€ one way that could happen is if an in-between NAT gave out a mapped transport address that was recently used by another client that crashed ๐Ÿ’€ the client counts the transaction as failed. It SHOULD pick another client transport address and retry the Allocate request (using a different transaction id) โœจ it SHOULD try three different client transport addresses before giving up on this server ๐Ÿฅน once it gives up on the server, it SHOULD NOT try to create another allocation on the server for 2 minutes โณ
  • 438 (Stale Nonce): see the long-term credential mechanism procedures [RFC5389] ๐Ÿ”
  • 441 (Wrong Credentials): the client shouldn't get this error in response to an Allocate request ๐Ÿคจ if it does, it MAY notify the user or operator, and it SHOULD NOT retry the same request with this server until it believes the problem has been fixed ๐Ÿ™…โ€โ™€๏ธ
  • 442 (Unsupported Transport Address): the client shouldn't get this error for a request for a UDP allocation ๐Ÿ˜ต if it does, it MAY notify the user or operator, and it SHOULD NOT reattempt the request with this server until it believes the problem has been fixed ๐Ÿซ 
  • 486 (Allocation Quota Reached): the server can't create any more allocations with this username right now ๐Ÿ“ต the client counts the transaction as failed. It SHOULD wait at least 1 minute before trying to create any more allocations on the server โฐ
  • 508 (Insufficient Capacity): the server has no more relayed transport addresses available, or none with the requested properties, or the one that was reserved isn't available anymore ๐Ÿ˜ฉ the client counts the current operation as failed. If it used either the EVEN-PORT or the RESERVATION-TOKEN attribute, it MAY choose to remove or change that attribute and try again right away ๐Ÿช„ otherwise, it SHOULD wait at least 1 minute before trying to create any more allocations on this server ๐Ÿ•ฐ๏ธ

An unknown error response MUST be handled as described in [RFC5389] ๐Ÿซถ


7. Refreshing an Allocation ๐Ÿ”„

okay this part 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's suggested that the client refresh the allocation roughly 1 minute before it expires โณ if a client doesn't want to use an allocation anymore, it SHOULD explicitly delete it ๐Ÿงน a client MAY refresh an allocation at any time for other reasons ๐ŸŒธ


7.1. Sending a Refresh Request ๐Ÿ“ค

if the client wants to delete an existing allocation right now, it includes a LIFETIME attribute with a value of 0 ๐Ÿ’€ every other form of the request refreshes the allocation โœจ

the Refresh transaction updates the time-to-expiry timer of an allocation ๐Ÿ•ฐ๏ธ if the client wants the server to set that timer to something other than the default lifetime, it includes a LIFETIME attribute with the value it wants ๐ŸŽ€ the server then works out a new time-to-expiry value the same way it does for an Allocate transaction, with one exception: a requested lifetime of 0 makes the server delete the allocation immediately ๐Ÿ™…โ€โ™€๏ธ


7.2. Receiving a Refresh Request ๐Ÿ“ฅ

when the server gets a Refresh request, it processes it as per Section 4, plus the specific rules mentioned here ๐Ÿง 

the server works out a value called the "desired lifetime" like this: if the request has a LIFETIME attribute and its value is 0, then the "desired lifetime" is 0 ๐Ÿ’€ otherwise, if the request has a LIFETIME attribute, the server takes 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 0, the request succeeds and the allocation is deleted ๐Ÿ—‘๏ธ
  • if the "desired lifetime" is non-zero, 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 simply 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) ๐Ÿซถ


7.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 a request to delete the allocation, then the allocation no longer exists, and it should consider its request as having effectively succeeded ๐Ÿฅณ iconic behaviour, honestly ๐Ÿ‘‘

8. Permissions โœจ

okay so every allocation keeps a little list of permissions ๐Ÿ“ each one has an IP address and a time-to-expiry (how many seconds until it poofs). while a permission exists, any peer using that IP address is allowed to send data to the client ๐Ÿ’Œ and inside an allocation, the IP address is the thing that makes a permission unique, so it's basically the permission's ID ๐Ÿ†”

the client can make the server install or refresh a permission for an IP address by sending either a CreatePermission request or a ChannelBind request ๐Ÿซถ and that does one of two things:

  • if there's no permission for that IP address yet, the server makes one with that IP address and a time-to-expiry equal to Permission Lifetime ๐ŸŽ€
  • if there's already a permission for that IP address, its time-to-expiry gets reset to Permission Lifetime ๐Ÿ”„

the Permission Lifetime MUST be 300 seconds (= 5 minutes) โฐ so that's the main number to remember bestie ๐Ÿ’…

each permission's time-to-expiry ticks down once per second until it hits 0 ๐Ÿ’€ then it expires and gets deleted, bye bye ๐Ÿ‘‹

CreatePermission and ChannelBind requests can be freely intermixed on a permission ๐Ÿฆ‹ a permission can get installed and/or refreshed with a CreatePermission request and then later refreshed with a ChannelBind request, or the other way around. it's giving flexible energy โœจ

now the important part ๐Ÿ‘€ when a UDP datagram shows up 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 of every permission in the allocation's list. if nothing matches, relaying isn't allowed and the server silently discards the UDP datagram ๐Ÿ™ˆ if there's an exact match, the permission check passes and the server keeps processing the UDP datagram the way it's described elsewhere (Section 10.3) ๐ŸŒธ and just to be clear, only the addresses get compared. port numbers don't matter at all ๐Ÿซข

the permissions for one allocation are totally unrelated to the permissions for a different allocation ๐ŸŒˆ 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 [RFC5245], and applications not using ICE are advised to do something similar. ๐Ÿšจ

9. CreatePermission

okay so TURN gives the client two ways to install or refresh permissions on the server ๐ŸŽ€ this section is about one of them: the CreatePermission request ๐Ÿ’–

a CreatePermission request can be used together with either the Send mechanism in Section 10 or the Channel mechanism in Section 11 ๐Ÿงš

9.1. Forming a CreatePermission Request

any client who wants to install or refresh one or more permissions can send a CreatePermission request to the server ๐Ÿ’Œ

when you're forming a CreatePermission request, you MUST include at least one XOR-PEER-ADDRESS attribute ๐Ÿซถ and you MAY include more than one of them. the IP address part of each XOR-PEER-ADDRESS attribute is the IP address that should get a permission installed or refreshed ๐ŸŒธ the port part gets ignored, so it can be any arbitrary value ๐Ÿคทโ€โ™€๏ธ and the XOR-PEER-ADDRESS attributes can show up in any order ๐Ÿ”€

9.2. Receiving a CreatePermission Request

when the server gets a CreatePermission request, it follows Section 4 plus the specific rules in this section ๐Ÿ“‹

first the message gets checked for validity โœ… the CreatePermission request MUST contain at least one XOR-PEER-ADDRESS attribute and MAY contain multiple of them. if there aren't any, or if any of them are invalid, the server returns a 400 (Bad Request) error ๐Ÿ’€ and if the request is valid but the server can't satisfy it because of a capacity limit or something similar, the server returns a 508 (Insufficient Capacity) error ๐Ÿ˜ญ

the server MAY impose restrictions on which IP addresses are allowed in the XOR-PEER-ADDRESS attribute ๐Ÿšง if an address isn't allowed, the server rejects the request with a 403 (Forbidden) error ๐Ÿ™…โ€โ™€๏ธ

if the message is valid and the server can actually carry out the request, then the server installs or refreshes a permission for the IP address in each XOR-PEER-ADDRESS attribute, as described in Section 8 ๐Ÿ”ฅ the port part of each attribute is ignored and can be any arbitrary value ๐ŸŽฒ

then the server responds with a CreatePermission success response ๐ŸŽ‰ and there are no mandatory attributes in that success response, so it's pretty chill ๐Ÿ˜Œ

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. ๐Ÿ”

9.3. Receiving a CreatePermission Response

if the client gets a valid CreatePermission success response, then it updates its data structures to show that the permissions have been installed or refreshed ๐Ÿ“โœจ easy peasy ๐Ÿ“


10. Send and Data Methods

okay so TURN has two mechanisms for sending and receiving data from peers ๐Ÿ’œ this section covers the Send and Data mechanisms, and Section 11 covers the Channel mechanism ๐Ÿฆ‹

10.1. Forming a Send Indication

the client can use a Send indication to hand data to the server so it can relay it to a peer ๐Ÿš€ the client can even use a Send indication when a channel is already bound to that peer ๐Ÿค“ BUT the client MUST make sure there's a permission installed for the IP address of the peer that the Send indication is going to ๐Ÿ”’ this is what stops a third party from using a TURN server to send data to random destinations, which would be so not it ๐Ÿ™…โ€โ™€๏ธ

when you're forming a Send indication, you MUST include an XOR-PEER-ADDRESS attribute and a DATA attribute ๐Ÿ’– the XOR-PEER-ADDRESS attribute holds the transport address of the peer the data is going to, and the DATA attribute holds the actual application data being sent ๐Ÿ“ฆ

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 ๐Ÿงฉ

10.2. Receiving a Send Indication

when the server gets a Send indication, it follows Section 4 plus the specific rules here ๐Ÿ“‹

first the message gets checked for validity ๐Ÿ” the Send indication MUST contain both an XOR-PEER-ADDRESS attribute and a DATA attribute. if either one is missing or invalid, the message gets discarded ๐Ÿ—‘๏ธ also, the DATA attribute is allowed to contain zero bytes of data ๐Ÿซง

the Send indication may also contain the DONT-FRAGMENT attribute ๐ŸŽ€ if the server can't set the DF bit on outgoing UDP datagrams when that attribute is present, then the server acts like the DONT-FRAGMENT attribute is an unknown comprehension-required attribute, and so the Send indication gets discarded ๐Ÿ’€

the server also checks that there's a permission installed for the IP address in the XOR-PEER-ADDRESS attribute ๐Ÿ” if there isn't one, the message gets discarded ๐Ÿ™ˆ and a Send indication never makes the server refresh the permission, so it can't keep a permission alive by itself ๐Ÿšซ

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's OK, the server forms a UDP datagram like this ๐Ÿ‘‡

  • the source transport address is the relayed transport address of the allocation, where the allocation is figured out from the 5-tuple the Send indication arrived on ๐ŸŒŸ
  • the destination transport address is taken from the XOR-PEER-ADDRESS attribute ๐ŸŽฏ
  • the data after the UDP header is the contents of the value field of the DATA attribute ๐Ÿ’Œ

the way the DONT-FRAGMENT attribute gets handled (if it's there) is described in Section 12 ๐Ÿง 

then the resulting UDP datagram gets sent to the peer ๐Ÿš€๐Ÿ’–

10.3. Receiving a UDP Datagram

when the server gets a UDP datagram at a currently allocated relayed transport address, it looks up the allocation associated with that relayed transport address ๐Ÿ”Ž then it checks whether the allocation's set of permissions allows the datagram to be relayed, as described in Section 8 โœ…

if relaying is permitted, the server checks whether there's a channel bound to the peer that sent the UDP datagram (see Section 11) ๐Ÿฆ‹ if a channel is bound, processing goes on as described in Section 11.7 ๐ŸŒˆ

if relaying is permitted but no channel is bound to the peer, then 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 ๐ŸŽ then the Data indication gets sent on the 5-tuple associated with the allocation ๐Ÿš€

10.4. Receiving a Data Indication

when the client gets a Data indication, it checks that the Data indication contains both an XOR-PEER-ADDRESS and a DATA attribute, and it discards the indication if it doesn't ๐Ÿ—‘๏ธ the client SHOULD also check that the XOR-PEER-ADDRESS attribute value has an IP address the client believes has an active permission, and discard the Data indication otherwise ๐Ÿ•ต๏ธโ€โ™€๏ธ again, the DATA attribute is allowed to contain zero bytes of data ๐Ÿซง

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 Data indication passes the checks above, the client delivers the data octets inside the DATA attribute to the application ๐ŸŽ‰ along with an indication that they came from the peer whose transport address is given by the XOR-PEER-ADDRESS attribute ๐Ÿ’–โœจ

11. Channels โœจ

Okay so channels are how the client and server send app data using ChannelData messages ๐Ÿ’Œ, which have less overhead than Send and Data indications. Less stuff in the way, more data going through ๐Ÿซถ

The ChannelData message (see Section 11.4) starts with a two-byte field that carries the channel number. Here's how those values are split up ๐Ÿ“

  • 0x0000 through 0x3FFF: these can never be used for channel numbers ๐Ÿ™…โ€โ™€๏ธ
  • 0x4000 through 0x7FFF: these are the allowed channel numbers (16,383 possible values) ๐Ÿ’–
  • 0x8000 through 0xFFFF: these are reserved for future use ๐Ÿ”ฎ

Because of that split, you can tell ChannelData messages apart from STUN-formatted messages (like an Allocate request or a Send indication, etc.) just by checking the first two bits of the message ๐Ÿ‘€

  • 0b00: STUN-formatted message (since the first two bits of a STUN-formatted message are always zero).
  • 0b01: ChannelData message (since the channel number is the first field in the ChannelData message and channel numbers fall in the range 0x4000 - 0x7FFF).
  • 0b10: Reserved
  • 0b11: Reserved

The reserved values may be used in the future to extend the range of channel numbers, so an implementation MUST NOT assume that a TURN message always starts with a 0 bit. Don't hardcode that, bestie ๐Ÿ™…โ€โ™€๏ธ

Channel bindings are always initiated by the client ๐Ÿ’…. The client can bind a channel to a peer at any time during the lifetime of the allocation. It may bind a channel to a peer before exchanging data with it, or after exchanging data with it (using Send and Data indications) for some time, or it may choose never to bind a channel to it. The client can also bind channels to some peers while not binding channels to other peers, which is very much a choose your own adventure situation ๐Ÿฆ‹

Channel bindings are specific to an allocation. That means using a channel number or peer transport address in a channel binding in one allocation has no impact on their use in a different allocation ๐ŸŒธ If an allocation expires, all its channel bindings expire with it ๐Ÿ˜ญ

A channel binding consists of:

  • a channel number;
  • a transport address (of the peer); and
  • a time-to-expiry timer.

Inside an allocation, a channel binding is uniquely identified either by the channel number or by the peer's transport address. So the same channel cannot be bound to two different transport addresses, and the same transport address cannot be bound to two different channels. No sharing the spotlight ๐Ÿ‘‘

A channel binding lasts for 10 minutes unless refreshed. Refreshing the binding (by the server receiving a ChannelBind request rebinding the channel to the same peer) resets the time-to-expiry timer back to 10 minutes โฐ

When the 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 prevent race conditions, the client MUST wait 5 minutes after the channel binding expires before attempting to bind the channel number to a different transport address or the transport address to a different channel number. Patience is a whole aesthetic ๐Ÿงš

When binding a channel to a peer, the client SHOULD be prepared to receive ChannelData messages on the channel from the server as soon as it has sent the ChannelBind request. Over UDP, it's possible for the client to get ChannelData messages from the server before it gets a ChannelBind success response, so stay ready ๐Ÿซฃ

In the other direction, the client MAY elect to send ChannelData messages before receiving the ChannelBind success response. Doing so, however, runs the risk of having the ChannelData messages dropped by the server if the ChannelBind request does not succeed for some reason (e.g., packet lost if the request is sent over UDP, or the server being unable to fulfill the request). A client that wants to be safe should either queue the data or use Send indications until the channel binding is confirmed ๐Ÿ›ก๏ธ


11.1. Sending a ChannelBind Request

A channel binding is created or refreshed using a ChannelBind transaction. A ChannelBind transaction also creates or refreshes a permission towards the peer (see Section 8) โœจ

To start 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 11.2 describes the restrictions on these attributes ๐Ÿ“

Rebinding a channel to the same transport address it's already bound to is a way to refresh a channel binding and the corresponding permission without sending any data to the peer. Just note that permissions need to be refreshed more frequently than channels ๐Ÿ”


11.2. Receiving a ChannelBind Request

When the server receives a ChannelBind request, it processes it as per Section 4, plus the specific rules mentioned here ๐Ÿ–ฅ๏ธ

The server checks the following:

  • the request contains both a CHANNEL-NUMBER and an XOR-PEER-ADDRESS attribute;
  • the channel number is in the range 0x4000 through 0x7FFE (inclusive);
  • the channel number is not currently bound to a different transport address (same transport address is OK);
  • the transport address is not currently bound to a different channel number.

If any of these tests fail, the server replies with a 400 (Bad Request) error ๐Ÿ™ˆ

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 rejects the request with a 403 (Forbidden) error ๐Ÿšซ

If the request is valid but the server can't fulfill it because of some capacity limit or something similar, the server replies with a 508 (Insufficient Capacity) error ๐Ÿ˜ต

Otherwise, the server replies with a ChannelBind success response. There are no required attributes in a successful ChannelBind response ๐ŸŽ‰

If the server can satisfy the request, then it creates or refreshes the channel binding using the channel number in the CHANNEL-NUMBER attribute and the transport address in the XOR-PEER-ADDRESS attribute. It also installs or refreshes a permission for the IP address in the XOR-PEER-ADDRESS attribute, as described in Section 8 ๐Ÿ’…

NOTE: A server need not do anything special to implement idempotency of ChannelBind requests over UDP using the "stateless stack approach". Retransmitted ChannelBind requests will simply refresh the channel binding and the corresponding permission. Furthermore, the client must wait 5 minutes before binding a previously bound channel number or peer address to a different channel, eliminating the possibility that the transaction would initially fail but succeed on a retransmission. ๐Ÿ”

11.3. Receiving a ChannelBind Response

When the client receives a ChannelBind success response, it updates its data structures to record that the channel binding is now active. It also updates them to record that the corresponding permission has been installed or refreshed โœ…

If the client gets a ChannelBind failure response that says the channel information is out-of-sync between the client and the server (e.g., an unexpected 400 "Bad Request" response), it is RECOMMENDED that the client immediately delete the allocation and start afresh with a new allocation. A clean slate is the move ๐Ÿงน๐Ÿ’–


11.4. The ChannelData Message

The ChannelData message carries application data between the client and the server. It has 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
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |         Channel Number        |            Length             |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                                                               |
   /                       Application Data                        /
   /                                                               /
   |                                                               |
   |                               +-------------------------------+
   |                               |
   +-------------------------------+

The Channel Number field specifies the number of the channel the data is traveling on, and thus the address of the peer that is sending or is to receive the data ๐ŸŒˆ

The Length field specifies the length in bytes of the application data field (it does not include the size of the ChannelData header). Note that 0 is a valid length ๐Ÿค

The Application Data field carries the data the client is trying to send to the peer, or that the peer is sending to the client ๐Ÿ’Œ


11.5. Sending a ChannelData Message

Once a client has bound a channel to a peer, then when it has data to send to that peer, it may use either a ChannelData message or a Send indication. In other words, the client isn't obligated to use the channel when it exists, and it can freely mix the two message types when sending data to the peer ๐Ÿ”€ The server, on the other hand, MUST use the ChannelData message if a channel has been bound to the peer. ๐Ÿ–ค

The fields of the ChannelData message are filled in as described in Section 11.4 ๐Ÿ“

Over TCP and TLS-over-TCP, the ChannelData message MUST be padded to a multiple of four bytes in order to ensure the alignment of subsequent messages. The padding is not reflected in the length field of the ChannelData message, so the actual size of a ChannelData message (including padding) is (4 + Length) rounded up to the nearest multiple of 4. Over UDP, the padding is not required but MAY be included. ๐Ÿซง

The ChannelData message is then sent on the 5-tuple associated with the allocation ๐Ÿš€

11.6. Receiving a ChannelData Message ๐Ÿ’Œ

okay so the receiver checks the first two bits to figure out if it's a ChannelData message or a STUN-formatted one, as we talked about above ๐Ÿง . if the message uses a value in the reserved range (0x8000 through 0xFFFF), it gets silently discarded ๐Ÿ™ˆ no drama, just gone.

if a ChannelData message shows up in a UDP datagram but the datagram is too short for the length the message claims, it also gets silently discarded. the UDP header length field has to be at least the ChannelData header length field value + 4 + 8, or it's a no-go ๐Ÿ’€

if the ChannelData message comes in over TCP or over TLS-over-TCP, the actual length is whatever Section 11.5 describes ๐ŸŽ€

if the ChannelData message lands on a channel that isn't bound to any peer, yep, silently discarded ๐Ÿฆ‹

now for the client side: it is RECOMMENDED that the client discard the ChannelData message if it believes there's no active permission towards the peer. and on the server, receiving a ChannelData message MUST NOT refresh either the channel binding or the permission towards the peer. no sneaky refreshes, bestie ๐Ÿ™…โ€โ™€๏ธโœจ

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, where the allocation is determined by the 5-tuple on which the ChannelData message arrived ๐ŸŒธ
  • the destination transport address is the transport address the channel is bound to ๐Ÿ’œ
  • the data right after the UDP header is the contents of the data field of the ChannelData message ๐Ÿ“

the UDP datagram then gets sent to the peer. one thing to note: if the Length field in the ChannelData message is 0, there's no data in the datagram, but the datagram still gets formed and sent anyway ๐Ÿซถ


11.7. Relaying Data from the Peer ๐ŸŒˆ

when the server gets a UDP datagram on the relayed transport address tied to an allocation, it processes it the way Section 10.3 describes. if that section says a ChannelData message should be sent (because there's a channel bound to the peer that sent the datagram), the server forms and sends a ChannelData message as Section 11.5 explains ๐Ÿ“จโœจ


12. IP Header Fields โœจ

this section is all about how the server sets different fields in the IP header when it's relaying between the client and the peer, or the other way around ๐Ÿงš these descriptions apply when (a) the server sends a UDP datagram to the peer, or (b) 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, so chill on those ๐Ÿ’…

each description has 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, then it SHOULD implement the alternative behavior. so it's basically plan A, plan B ๐ŸŽ€


Time to Live (TTL) field โณ

Preferred Behavior: if the incoming value is 0, then drop the incoming packet. otherwise, set the outgoing Time to Live/Hop Count to one less than the incoming value ๐Ÿฆ‹

Alternate Behavior: set the outgoing value to the default for outgoing packets ๐ŸŒธ


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 by default is Best Effort 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, unless the server is doing Active Queue Management, the incoming ECN field is ECT(1) (=0b01) or ECT(0) (=0b10), and the server wants to indicate that congestion has been experienced. in that case, set the outgoing value to CE (=0b11) ๐Ÿ”ฅ

Alternate Behavior: set the outgoing value to Not-ECT (=0b00) ๐Ÿ™ˆ


IPv4 Fragmentation fields ๐Ÿงฉ

Preferred Behavior: when the server sends a packet to a peer in response to a Send indication containing the DONT-FRAGMENT attribute, set the DF bit in the outgoing IP header to 1. 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 always assume 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, the normal fragmentation rules apply [RFC1122] ๐Ÿ’€


IPv4 Options ๐ŸŽ€

Preferred Behavior: the outgoing packet is sent without any IPv4 options ๐Ÿ’œ

Alternate Behavior: same as preferred ๐Ÿฅฐ


13. New STUN Methods ๐Ÿฆ‹

this section lists the codepoints for the new STUN methods defined in this specification. the semantics of these new methods live elsewhere in the document, so go look there ๐Ÿ“š

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)

14. New STUN Attributes ๐Ÿ’…

this STUN extension defines the following new attributes:

  0x000C: CHANNEL-NUMBER
  0x000D: LIFETIME
  0x0010: Reserved (was BANDWIDTH)
  0x0012: XOR-PEER-ADDRESS
  0x0013: DATA
  0x0016: XOR-RELAYED-ADDRESS
  0x0018: EVEN-PORT
  0x0019: REQUESTED-TRANSPORT
  0x001A: DONT-FRAGMENT
  0x0021: Reserved (was TIMER-VAL)
  0x0022: RESERVATION-TOKEN

some of these attributes have lengths that aren't multiples of 4. by the rules of STUN, any attribute whose length is not 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 [RFC5389]). padding is non-negotiable, babe ๐Ÿ™Œ


14.1. CHANNEL-NUMBER ๐Ÿ”ข

the CHANNEL-NUMBER attribute contains the number of the channel. its value portion is 4 bytes long and consists of a 16-bit unsigned integer, followed by a two-octet RFFU (Reserved For Future Use) field, which 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              |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

14.2. LIFETIME โฐ

the LIFETIME attribute represents how long the server will keep an allocation going when there's no refresh. its value portion is 4 bytes long and consists of a 32-bit unsigned integral value representing the number of seconds remaining until expiration ๐Ÿ•ฐ๏ธ


14.3. XOR-PEER-ADDRESS ๐Ÿงญ

the XOR-PEER-ADDRESS specifies the address and port of the peer as seen from the TURN server. (for example, the peer's server-reflexive transport address if the peer is behind a NAT.) it's encoded in the same way as XOR-MAPPED-ADDRESS [RFC5389] ๐Ÿ’–


14.4. DATA ๐Ÿ“ฆ

the DATA attribute is present in all Send and Data indications. its value portion is variable length and holds the application data, meaning the data that would immediately follow the UDP header if the data was been sent directly between the client and the peer ๐Ÿ“ if the length of this attribute is not a multiple of 4, then padding must be added after this attribute ๐Ÿงธ


14.5. XOR-RELAYED-ADDRESS ๐ŸŒˆ

the XOR-RELAYED-ADDRESS is present in Allocate responses. it specifies the address and port that the server allocated to the client. it's encoded in the same way as XOR-MAPPED-ADDRESS [RFC5389] โœจ


14.6. EVEN-PORT ๐Ÿฆ„

this attribute lets the client request that the port in the relayed transport address be even, and (optionally) that the server reserve the next-higher port number. its value portion is 1 byte long, and its format is:

     0
     0 1 2 3 4 5 6 7
    +-+-+-+-+-+-+-+-+
    |R|    RFFU     |
    +-+-+-+-+-+-+-+-+

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 ๐Ÿ’ซ

the other 7 bits of the attribute's value must be set to zero on transmission and ignored on reception. and since the length of this attribute is not a multiple of 4, padding must immediately follow this attribute ๐Ÿ™ƒ


14.7. REQUESTED-TRANSPORT ๐Ÿš€

the client uses this attribute to request 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                       |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

the Protocol field specifies the desired protocol. the codepoints used in this field are taken from those allowed in the Protocol field in the IPv4 header and the NextHeader field in the IPv6 header [Protocol-Numbers]. this specification only allows codepoint 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 ๐Ÿ”’


14.8. DONT-FRAGMENT ๐Ÿ™…

the client uses this attribute to ask the server to set the DF (Don't Fragment) bit in the IP header when it relays the application data onward to the peer. this attribute has no value part, so the attribute length field is 0 ๐Ÿซง


14.9. RESERVATION-TOKEN ๐ŸŽŸ๏ธ

the RESERVATION-TOKEN attribute contains a token that uniquely identifies a relayed transport address being held in reserve by the server. the server includes this attribute in a success response to tell the client about the token, and the client includes this attribute in a subsequent Allocate request to ask the server to use that relayed transport address for the allocation ๐Ÿ”‘

the attribute value is 8 bytes and contains the token value. ๐Ÿฅน

15. New STUN Error Response Codes ๐Ÿšจ

This document adds some brand-new error response codes, so let's go through them. ๐Ÿ’…

  • 403 (Forbidden): The request was totally valid, but the server can't do it because of admin rules or something similar. ๐Ÿ™…โ€โ™€๏ธ
  • 437 (Allocation Mismatch): Either the server wanted an allocation to already exist and there isn't one, or the request needed no allocation and there's already one sitting there. ๐Ÿคจ
  • 441 (Wrong Credentials): The credentials in a non-Allocate request don't match the ones used to make the allocation. ๐Ÿ”‘โŒ
  • 442 (Unsupported Transport Protocol): The Allocate request asked the server to use a transport protocol between itself and the peer that it doesn't support. NOTE: This does NOT refer to the transport protocol used in the 5-tuple. ๐Ÿง
  • 486 (Allocation Quota Reached): This username has hit its limit and can't make any more allocations right now. ๐Ÿ›‘
  • 508 (Insufficient Capacity): The server is at some capacity limit and can't finish the request. In an Allocate response, that could mean there are no more relayed transport addresses free at the moment, none that match the requested properties, or the one tied to the reservation token you sent isn't available. ๐Ÿ˜ญ

16. Detailed Example โœจ

Okay, this section is the fun one, because it walks through a real TURN conversation and shows what's inside every single message. ๐ŸŽ€ It uses the network diagram from the Overview (Figure 1).

For each message, we list the attributes it carries and their values. To keep things readable, values are shown in a human-friendly way instead of the actual octets. For example, XOR-RELAYED-ADDRESS=192.0.2.15:9000 means the XOR-RELAYED-ADDRESS attribute is included with an address of 192.0.2.15 and a port of 9000. The address and port are written before the xor-ing happens. For attributes with string-like values, such as SOFTWARE="Example client, version 1.03" and NONCE="adl7W7PeDU4hKE72jdaQvbAMcr6h39sm", the quotes are just there so you can see where the value starts and ends. They aren't actually part of the 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="adl7W7PeDU4hKE72jdaQvbAMcr6h39sm"      |             |
    |                                    |             |             |
    |--- 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="adl7W7PeDU4hKE72jdaQvbAMcr6h39sm"      |             |
    |    MESSAGE-INTEGRITY=...           |             |             |
    |                                    |             |             |
    |<-- 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=...           |             |             |

First up, the client picks a host transport address to use for the TURN session. In this example it's 10.1.1.2:49721, as you can see in Figure 1. โœจ Then it sends an Allocate request to the server's transport address. The client randomly picks a 96-bit transaction id, 0xA56250D3F17ABE679422DE85, for this exchange, and that goes into the transaction id field of the fixed header. ๐Ÿฆ‹

The client adds a SOFTWARE attribute to say what software it's running. Here it says "Example client, version 1.03," which means version 1.03 of something called the Example client. ๐ŸŽ€ It also includes LIFETIME because it wants the allocation to last longer than the default 10 minutes. The value is 3600 seconds, which is 1 hour. ๐Ÿ•

The client must always include a REQUESTED-TRANSPORT attribute in an Allocate request. The only value this specification allows is 17, which means UDP between the server and the peers. ๐ŸŒธ

The client also throws in DONT-FRAGMENT, since it plans to use that attribute later in Send indications. This one is just an attribute header with no value part, so it's super lightweight. ๐Ÿ“

We're pretending the client hasn't talked to this server recently, so it leaves out USERNAME, REALM, NONCE and MESSAGE-INTEGRITY. ๐Ÿ™ˆ One last thing: the order of attributes in a message doesn't matter, except that MESSAGE-INTEGRITY and FINGERPRINT have to be placed in their special spots. The client could've ordered them differently and been totally fine. ๐Ÿ’…

Servers want every request authenticated, so when the first Allocate request shows up without any auth attributes, the server rejects it. ๐Ÿšซ It follows the long-term credential mechanism from STUN [RFC5389]. It sends back an ERROR-CODE of 401 (Unauthorized), a REALM attribute naming its authentication realm (here it's the server's domain, "example.com"), and a nonce in a NONCE attribute. It also sends a SOFTWARE attribute describing its own software. ๐Ÿ–ฅ๏ธ

When the client gets that 401, it tries again, this time with the auth attributes. It picks a fresh transaction id and copies over all the attributes from before. ๐Ÿ” It adds a USERNAME attribute, using the realm it got from the server to work out which username to use. In this case, the client is set up to use the username "George" for the realm "example.com". It also includes REALM and NONCE, copied straight from the 401 response. ๐Ÿซถ

Last, the client adds MESSAGE-INTEGRITY as the final attribute. Its value is a HMAC-SHA1 hash over the message, which is shown as just "..." above. That HMAC-SHA1 calculation uses a password too, so an attacker can't work out the message integrity value without somehow knowing the secret password. ๐Ÿ” Nice try, bestie. ๐Ÿ˜ค

When the server gets this authenticated Allocate request, it checks that everything looks good and then creates the allocation. Then it sends back an Allocate success response. โœ… The response includes a LIFETIME attribute with the allocation's lifetime. The client asked for an hour, but this server doesn't allow anything longer than 20 minutes, so it cut it down to 20 minutes. Rude, but fair. ๐Ÿ™ƒ

The server also includes an XOR-RELAYED-ADDRESS attribute, which holds the relayed transport address of the allocation. ๐Ÿฆ‹ It includes an XOR-MAPPED-ADDRESS attribute too, which holds the client's server-reflexive address. TURN doesn't use that value for anything else, but the server sends it back as a little bonus for the client. ๐ŸŽ Then it adds MESSAGE-INTEGRITY to authenticate the response and make sure nobody messed with it. Notice that this response doesn't carry USERNAME, REALM or NONCE. Finally, the server includes a SOFTWARE attribute of its own. ๐Ÿ’œ

  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="adl7W7PeDU4hKE72jdaQvbAMcr6h39sm"      |             |
    |    MESSAGE-INTEGRITY=...           |             |             |
    |                                    |             |             |
    |<-- CreatePermission success resp.--|             |             |
    |    Transaction-Id=0xE5913A8F460956CA277D3319     |             |
    |    MESSAGE-INTEGRITY=...           |             |             |

Now the client sets up a permission toward Peer A so it can send some application data. ๐Ÿงš It does this with a CreatePermission request. The XOR-PEER-ADDRESS attribute holds the IP address the permission is for, which is Peer A's IP. The port in that attribute gets ignored in a CreatePermission request, so here it's just set to 0. โญ Also notice that the client uses Peer A's server-reflexive IP address, not its private host address. That's the move. ๐Ÿ‘‘ The client reuses the same username, realm and nonce from the earlier request on this allocation. It's allowed to include a SOFTWARE attribute, but it decides not to. ๐ŸŒˆ

The server takes the CreatePermission request, sets up the matching permission, and replies with a CreatePermission success response. ๐ŸŽ‰ Like the client, the server skips SOFTWARE in its reply. Also, success responses carry a MESSAGE-INTEGRITY attribute (assuming the server is using the long-term credential mechanism), but they don't include USERNAME, REALM or NONCE. Iconic. ๐Ÿ’–

Okay bestie, the Detailed Example is still giving us the big finale ๐Ÿ’… Here's the Send indication flow, where the client sends app data to Peer A ๐Ÿฆ‹

  TURN                                 TURN           Peer          Peer
  client                               server          A             B
    |--- Send indication --------------->|             |             |
    |    Transaction-Id=0x1278E9ACA2711637EF7D3328     |             |
    |    XOR-PEER-ADDRESS=192.0.2.150:32102            |             |
    |    DONT-FRAGMENT                   |             |             |
    |    DATA=...                        |             |             |
    |                                    |-- UDP dgm ->|             |
    |                                    |  data=...   |             |
    |                                    |             |             |
    |                                    |<- UDP dgm --|             |
    |                                    |  data=...   |             |
    |<-- Data indication ----------------|             |             |
    |    Transaction-Id=0x8231AE8F9242DA9FF287FEFF     |             |
    |    XOR-PEER-ADDRESS=192.0.2.150:32102            |             |
    |    DATA=...                        |             |             |

So the client is now sending application data to Peer A using a Send indication ๐ŸŒธ Peer A's server-reflexive transport address goes in the XOR-PEER-ADDRESS attribute, and the app data (shown here as just "...") goes in the DATA attribute โœจ The client is doing a form of path MTU discovery at the application layer, so it includes the DONT-FRAGMENT attribute to ask the server to set the DF bit in the UDP datagram going to the peer ๐Ÿ™ˆ Indications can't be authenticated with the long-term credential mechanism of STUN, so there's no MESSAGE-INTEGRITY attribute in this message. If an app wants its data to be safe from being altered or forged, it has to integrity-protect the data itself at the application level ๐Ÿ”ฅ

When the server gets the Send indication, it pulls out the app data and sends it in a UDP datagram to Peer A. The relayed transport address is the source, and the DF bit is set like the client asked ๐Ÿ’– Heads up though: if the client never set up a permission for Peer A's server-reflexive IP address, the server would've quietly tossed the Send indication instead ๐Ÿ’€

Peer A then replies with its own UDP datagram full of app data. That datagram goes to the relayed transport address on the server. When it arrives, the server makes a Data indication with the source of the UDP datagram in the XOR-PEER-ADDRESS attribute and the data from that datagram in the DATA attribute. Then the Data indication gets sent to the client ๐Ÿงš

  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="adl7W7PeDU4hKE72jdaQvbAMcr6h39sm"      |             |
    |    MESSAGE-INTEGRITY=...           |             |             |
    |                                    |             |             |
    |<-- ChannelBind success response ---|             |             |
    |    Transaction-Id=0x6490D3BC175AFF3D84513212     |             |
    |    MESSAGE-INTEGRITY=...           |             |             |

Now the client binds a channel to Peer B ๐ŸŽ€ It picks a free channel number (0x4000) for the CHANNEL-NUMBER attribute and puts Peer B's transport address in XOR-PEER-ADDRESS. Same as before, the client reuses the username, realm, and nonce from its last request in the message ๐Ÿ’…

When the server gets the request, it binds the channel number to the peer, installs a permission for Peer B's IP address, and then sends back a ChannelBind success response. Iconic behaviour ๐Ÿ‘‘

  TURN                                 TURN           Peer          Peer
  client                               server          A             B
    |--- ChannelData ------------------->|             |             |
    |    Channel-number=0x4000           |--- UDP datagram --------->|
    |    Data=...                        |    Data=...               |
    |                                    |             |             |
    |                                    |<-- UDP datagram ----------|
    |                                    |    Data=... |             |
    |<-- ChannelData --------------------|             |             |
    |    Channel-number=0x4000           |             |             |
    |    Data=...                        |             |             |

Next, the client sends a ChannelData message to the server with data for Peer B โœจ A ChannelData message is not a STUN message, so it doesn't have a transaction id. It only has three fields: a channel number, data, and a data length. Here the channel number is 0x4000, the channel the client just bound to Peer B ๐Ÿฆ‹ When the server gets the ChannelData message, it checks that the channel is currently bound (it is!), then sends the data on to Peer B in a UDP datagram. It uses the relayed transport address as the source and 192.0.2.210:49191 (the XOR-PEER-ADDRESS value from the ChannelBind request) as the destination ๐ŸŒˆ

Later, Peer B sends a UDP datagram back to the relayed transport address. That makes the server send a ChannelData message to the client with the data from the datagram ๐Ÿ˜ญ The server knows which client to send it to because of the relayed transport address the datagram arrived at, and it knows to use channel 0x4000 because that's the channel bound to 192.0.2.210:49191. Also worth noting: if no channel number had been bound to that address, the server would've used a Data indication instead ๐Ÿ™ˆ

  TURN                                 TURN           Peer          Peer
  client                               server          A             B
    |--- Refresh request --------------->|             |             |
    |    Transaction-Id=0x0864B3C27ADE9354B4312414     |             |
    |    SOFTWARE="Example client 1.03"  |             |             |
    |    USERNAME="George"               |             |             |
    |    REALM="example.com"             |             |             |
    |    NONCE="adl7W7PeDU4hKE72jdaQvbAMcr6h39sm"      |             |
    |    MESSAGE-INTEGRITY=...           |             |             |
    |                                    |             |             |
    |<-- Refresh error response ---------|             |             |
    |    Transaction-Id=0x0864B3C27ADE9354B4312414     |             |
    |    SOFTWARE="Example server, version 1.17"       |             |
    |    ERROR-CODE=438 (Stale Nonce)    |             |             |
    |    REALM="example.com"             |             |             |
    |    NONCE="npSw1Xw239bBwGYhjNWgz2yH47sxB2j"       |             |
    |                                    |             |             |
    |--- Refresh request --------------->|             |             |
    |    Transaction-Id=0x427BD3E625A85FC731DC4191     |             |
    |    SOFTWARE="Example client 1.03"  |             |             |
    |    USERNAME="George"               |             |             |
    |    REALM="example.com"             |             |             |
    |    NONCE="npSw1Xw239bBwGYhjNWgz2yH47sxB2j"       |             |
    |    MESSAGE-INTEGRITY=...           |             |             |
    |                                    |             |             |
    |<-- Refresh success response -------|             |             |
    |    Transaction-Id=0x427BD3E625A85FC731DC4191     |             |
    |    SOFTWARE="Example server, version 1.17"       |             |
    |    LIFETIME=600 (10 minutes)       |             |             |

Sometime before the 20 minute lifetime runs out, the client refreshes the allocation with a Refresh request ๐Ÿ•ฐ๏ธ Same as before, it includes the latest username, realm, and nonce. It also adds the SOFTWARE attribute, because the recommended practice is to always include it in 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 a fresh nonce value. The client then retries with the new nonce, and this second try gets accepted with a success response ๐ŸŽ‰ 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 in the success response ๐Ÿ’œ


17. Security Considerations ๐Ÿ”

This section looks at the attacks that are possible in a TURN deployment, and how they get mitigated by mechanisms in the protocol or by recommended practices in the implementation ๐Ÿ˜ค

Most attacks on TURN are stopped by making the server require requests to be authenticated, so 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 too. Just make sure they can be invoked in an inter-operable way, because that matters a lot ๐Ÿซ 

17.1. Outsider Attacks

Outsider attacks are the ones where the attacker has no credentials in the system and is trying to disrupt the service the client or the server sees ๐Ÿ‘€

17.1.1. Obtaining Unauthorized Allocations

An attacker might want to grab allocations on a TURN server for all sorts of shady reasons. A TURN server gives a way to send and receive packets while hiding the client's actual IP address, which makes TURN servers a super attractive target for anyone wanting to mask their true identity ๐Ÿฅท

An attacker might also just want to use a TURN server's services without paying for them. TURN services use up the provider's resources, so it's expected that their usage will come with a cost ๐Ÿ’ธ

These attacks are prevented by the long-term credential mechanism, which lets the TURN server figure out who the requestor is and whether they're allowed to get the allocation ๐Ÿ”’

17.1.2. Offline Dictionary Attacks

The long-term credential mechanism used by TURN is open 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 checking whether one is correct. This works when the passwords have low entropy, like a plain word from the dictionary. You can mitigate it by using strong passwords with large entropy ๐Ÿ’ช And in situations that need even stronger mitigation, TLS transport between the client and the server can be used ๐Ÿ”โœจ

17.1.3. Faked Refreshes and Permissions ๐Ÿ™…โ€โ™€๏ธ

Okay so an attacker could try to hit an active allocation with a Refresh request that has an immediate expiration, which deletes it and wrecks the client's service. Not on my watch ๐Ÿ˜ค Authenticating refreshes stops that. The same goes for an attacker trying to send CreatePermission requests to make permissions toward undesirable destinations, because authentication blocks that too. The reasons someone would pull this kind of move are covered in Section 17.2. ๐Ÿ’…

17.1.4. Fake Data ๐Ÿซฃ

This one is giving sneaky. An attacker might want to send data to the client or the peer while pretending it came from the peer or the client, respectively. To pull that off, they 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 aren't authenticated, so TURN doesn't prevent this attack. Ngl though, this kind of attack is already a thing in regular IP-based communications, and TURN doesn't make it much worse. ๐ŸŒธ Picture a normal, non-TURN IP session between hosts A and B. An attacker can send packets to B that look like they came from A by sending packets toward A with a spoofed IP address of B. That requires the attacker to know the IP addresses of A and B. With TURN, someone who wants to send packets toward 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 (to include in the XOR-PEER-ADDRESS attribute). To send a fake ChannelData message to a client, an attacker needs the IP address and port of the client, the IP address and port of the TURN server, and the channel number. Honestly, that particular combination is a little more guessable than in the non-TURN case. ๐Ÿ™ˆ

The proper fix for these is application-layer authentication. For real-time traffic, using SRTP [RFC3711] stops these attacks. ๐ŸŽ€

Here's the spicy part. Sometimes the TURN server sits somewhere in the network where it can send to hosts that the client can't reach directly. For example, the server might be behind a firewall that lets packets from outside reach the server but not other hosts behind that firewall. In that setup, an attacker could send the server a Send indication with an XOR-PEER-ADDRESS attribute holding the transport address of one of those other hosts behind the firewall. If the server allowed relaying to arbitrary peers, the attacker would then have a way to go after arbitrary hosts behind the firewall. ๐Ÿ˜ฑ

To stop this, TURN requires that the client establish a permission to a host before sending it data. So an attacker can only go after hosts the client is already talking to, unless they're able to create authenticated requests. โœจ On top of that, the server administrator can configure the server to restrict the range of IP addresses and ports it will relay data to. And if they want to go even further for security, the server administrator can require that the client use TLS for all communication between the client and the server. ๐Ÿ”

17.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 hand the client a faked relayed address. Villain arc, honestly. ๐Ÿ˜ค

The long-term credential mechanism prevents this attack. It gives integrity protection for responses, and it also verifies that they came from the server. An attacker also can't replay old server responses, because the transaction id in the STUN header stops that. Replay attacks are further thwarted by frequent changes to the nonce value. ๐Ÿงš

17.1.6. Eavesdropping Traffic ๐Ÿ‘‚

TURN is mainly about authentication and message integrity. Confidentiality is more of a secondary concern, since TURN control messages don't include anything super sensitive. The main thing in them is the IP address of the peer. If it matters to keep an eavesdropper on a TURN connection from learning that, TURN can be run over TLS. ๐Ÿ”’

Confidentiality for the application data relayed by TURN is best handled by the application protocol itself. Running TURN over TLS doesn't protect application data between the server and the peer, so that's not a fix for it. If confidentiality of application data matters, the application should encrypt or otherwise protect its data. For example, for real-time media, SRTP can provide that confidentiality. ๐ŸŽง

17.1.7. TURN Loop Attack ๐Ÿ”

Okay, this one is 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, using the source address of server B. Server A sends its response to server B, and for the attack 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. Next, the attacker sends an Allocate request to server B, using the source address of server A. Again, the attacker needs to view or guess the response contents so they can learn the allocated relayed transport address. Using that same spoofed source address trick, the attacker then binds a channel number on server A to the relayed transport address on server B, and similarly 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 loops 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 that are sent to a third party (in this case, the other server). That's how the attacker gets the credentials to authenticate requests and learn the relayed transport address. Without one of those two measures, an attacker can guess the contents of the responses without needing to see them, which makes the attack way easier to pull off. ๐Ÿ’… Also, 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 that started it. ๐Ÿ•ต๏ธโ€โ™€๏ธ

The attack can be further mitigated by imposing a per-username limit on the bandwidth used to relay data by allocations owned by that username. That limits the impact on other allocations. Even more mitigation comes from decrementing the TTL when relaying data packets, if the underlying OS allows it. ๐Ÿฆ‹


17.2. Firewall Considerations ๐Ÿงฑ

A key security consideration is that TURN should not weaken the protections that firewalls deployed between a client and a TURN server provide. TURN servers are expected to often sit on the public Internet, while clients may often be inside enterprise networks with corporate firewalls. If TURN servers gave a 'backdoor' into the enterprise, these firewalls would block TURN. ๐Ÿšซ

So TURN servers emulate the behavior of NAT devices that implement address-dependent filtering [RFC4787], which is also a property common in many firewalls. When a NAT or firewall does this, packets from an outside IP address are only allowed to reach an internal IP address and port if that internal IP address and port recently sent a packet to that outside IP address. TURN servers introduce the concept of permissions, which give exactly the same behavior on the TURN server. An attacker can't 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 have policies that are even stricter than address-dependent filtering. Firewalls can also be configured with address- and port-dependent filtering, or they can be set to disallow inbound traffic entirely. In these cases, if a client is allowed to connect to the TURN server, communications to the client end up less restricted than what the firewall would normally allow. Hmm, that's a whole plot twist. ๐Ÿ˜ฌ

17.2.1. Faked Permissions ๐ŸŽŸ๏ธ

With firewalls and NAT devices, permissions are granted implicitly when a packet travels from the inside of the network toward the outside peer. So by definition, a permission can only be created by an entity inside the firewall or NAT. With TURN, this restriction no longer holds. The TURN server sits outside the firewall, so an attacker outside the firewall can now send a message to the TURN server and try to create a permission for itself. Bold move. ๐Ÿ˜ค

This attack is prevented because all messages that create permissions (that is, ChannelBind and CreatePermission) are authenticated. ๐Ÿ”

17.2.2. Blacklisted IP Addresses ๐Ÿšท

Many 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. The firewall does this by inspecting the source and destination addresses of packets entering and exiting, respectively. ๐Ÿง

This feature is also present in TURN, since TURN servers are allowed to arbitrarily restrict the range of peer addresses they will relay to. ๐Ÿซถ

17.2.3. Running Servers on Well-Known Ports ๐Ÿ 

A malicious client behind a firewall might try to connect to a TURN server and get 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. Nice try. ๐Ÿ™ƒ

It's not possible in TURN. A TURN server will never accept traffic from a peer for which the client hasn't installed a permission. So peers can't just connect to the allocated port to get the service. ๐Ÿšช๐Ÿ”’


17.3. Insider Attacks ๐Ÿ•ต๏ธโ€โ™€๏ธ

In insider attacks, a client has legitimate credentials but breaks the trust relationship that comes with them. These attacks can't be prevented by cryptographic means, so they need to be considered in the design of the protocol itself. ๐Ÿง 

17.3.1. DoS against TURN Server ๐ŸŒŠ

A client that wants to disrupt service to other clients might obtain an allocation and then flood it with traffic, trying to swamp the server so it can't serve other legitimate clients. This is mitigated by the recommendation that the server limit the amount of bandwidth it will relay for a given username. That won't stop a client from sending a huge amount of traffic, but it lets the server immediately discard the excess. ๐Ÿ—‘๏ธ

Also, each allocation uses a port number on the IP address of the TURN server, so the number of allocations on a server is finite. An attacker might try to eat all of them by requesting a large number 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. ๐Ÿ’–

17.3.2. Anonymous Relaying of Malicious Traffic ๐Ÿฆ‹

okay so TURN servers give you a lil bit of anonymity ๐Ÿ™ˆ A client can send data to its peers without revealing its own IP address. That means TURN servers may become super attractive to attackers who want to hit a target without getting caught ๐Ÿ’€ It's even possible to chain several TURN servers together, so there can be any number of relays before a target gets a packet ๐Ÿ”—

Admins who are worried about this can keep logs that capture the client's actual source IP and port, and maybe even every permission that client installs ๐Ÿ“ If it ever turns out an attack is being relayed through a TURN server, that log trail lets them do forensic tracing to find the original source ๐Ÿ”

17.3.3. Manipulating Other Allocations ๐ŸŽญ

Another sneaky move: an attacker might try to disrupt service for other TURN users by sending Refresh requests or CreatePermission requests that (through source address spoofing) look like they're coming from someone else ๐Ÿ‘€ TURN stops this by requiring that the credentials used in CreatePermission, Refresh, and ChannelBind messages match the ones used to create the initial allocation. So the attacker's fake requests get rejected ๐Ÿšซ

17.4. Other Considerations ๐Ÿ’…

Any relay addresses learned through an Allocate request won't 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 โœจ

18. IANA Considerations ๐ŸŒธ

Since TURN is an extension to STUN [RFC5389], the methods, attributes, and error codes defined in this specification are new methods, attributes, and error codes for STUN. IANA has added these new protocol elements to the IANA registry of STUN protocol elements.

The codepoints for the new STUN methods defined in this specification are listed in Section 13.

The codepoints for the new STUN attributes defined in this specification are listed in Section 14.

The codepoints for the new STUN error codes defined in this specification are listed in Section 15.

IANA has allocated the SRV service name of "turn" for TURN over UDP or TCP, and the service name of "turns" for TURN over TLS.

IANA has created a registry for TURN channel numbers, initially populated as follows:

0x0000 through 0x3FFF: Reserved and not available for use, since
they conflict with the STUN header.

0x4000 through 0x7FFF: A TURN implementation is free to use
channel numbers in this range.

0x8000 through 0xFFFF: Unassigned.

Any change to this registry must be made through an IETF Standards Action ๐Ÿ”’

19. IAB Considerations ๐Ÿง 

The IAB has studied the problem of "Unilateral Self Address Fixing" (UNSAF), which is the general process by which a client tries to figure out its address in another realm on the other side of a NAT through a collaborative protocol-reflection mechanism [RFC3424]. TURN is an example of a protocol that does this kind of job. The IAB has mandated that any protocols developed for this purpose document a specific set of considerations, and the responses for TURN are written up 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. It lets a client that's behind a NAT obtain and use a public IP address on the relay. As a convenience to the client, TURN also lets the client 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 [RFC5245] to communicate with peers. Though ICE uses TURN, it does so only as a last resort, and 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, since 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 ๐Ÿฅฒ

20. Acknowledgements ๐Ÿ’œ

The authors would like to thank the various participants in the BEHAVE working group for their many comments on this document. Marc Petit-Huguenin, Remi Denis-Courmont, Jason Fischl, Derek MacDonald, Scott Godin, Cullen Jennings, Lars Eggert, Magnus Westerlund, Benny Prijono, and Eric Rescorla have been particularly helpful. Eric suggested the channel allocation mechanism, Cullen suggested an earlier version of the EVEN-PORT mechanism, and Marc spent many hours implementing the preliminary versions to look for problems ๐Ÿ™Œ Christian Huitema was an early contributor to this document and was a co-author on the first few versions. Finally, the authors would like to thank Dan Wing for both his contributions to the text and his huge help in restarting progress on this document after work had stalled ๐Ÿฅน

21. References ๐Ÿ“š

21.1. Normative References

[RFC5389]            Rosenberg, J., Mahy, R., Matthews, P., and D.
                     Wing, "Session Traversal Utilities for NAT
                     (STUN)", RFC 5389, October 2008.

[RFC2119]            Bradner, S., "Key words for use in RFCs to
                     Indicate Requirement Levels", BCP 14, RFC 2119,
                     March 1997.

[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, December 1998.

[RFC3168]            Ramakrishnan, K., Floyd, S., and D. Black, "The
                     Addition of Explicit Congestion Notification
                     (ECN) to IP", RFC 3168, September 2001.

[RFC1122]            Braden, R., "Requirements for Internet Hosts -
                     Communication Layers", STD 3, RFC 1122,
                     October 1989.

21.2. Informative References ๐ŸŽ€

okay so these are the extra reads that aren't strictly required but are super useful for context, bestie ๐Ÿ“šโœจ every entry is listed below exactly as it's written, so nothing gets lost ๐Ÿ’…

[RFC1191]            Mogul, J. and S. Deering, "Path MTU discovery",
                     RFC 1191, November 1990.

[RFC0791]            Postel, J., "Internet Protocol", STD 5, RFC 791,
                     September 1981.

[RFC1918]            Rekhter, Y., Moskowitz, R., Karrenberg, D.,
                     Groot, G., and E. Lear, "Address Allocation for
                     Private Internets", BCP 5, RFC 1918,
                     February 1996.

[RFC3424]            Daigle, L. and IAB, "IAB Considerations for
                     UNilateral Self-Address Fixing (UNSAF) Across
                     Network Address Translation", RFC 3424,
                     November 2002.

[RFC4787]            Audet, F. and C. Jennings, "Network Address
                     Translation (NAT) Behavioral Requirements for
                     Unicast UDP", BCP 127, RFC 4787, January 2007.

[RFC5245]            Rosenberg, J., "Interactive Connectivity
                     Establishment (ICE): A Protocol for Network
                     Address Translator (NAT) Traversal for
                     Offer/Answer Protocols", RFC 5245, April 2010.

[TURN-TCP]           Perreault, S. and J. Rosenberg, "Traversal Using
                     Relays around NAT (TURN) Extensions for TCP
                     Allocations", Work in Progress, March 2010.

[TURN-IPv6]          Perreault, S., Camarillo, G., and O. Novo,
                     "Traversal Using Relays around NAT (TURN)
                     Extension for IPv6", Work in Progress, March
                     2010.

[TSVWG-PORT]         Larsen, M. and F. Gont, "Port Randomization",
                     Work in Progress, April 2010.

[RFC5128]            Srisuresh, P., Ford, B., and D. Kegel, "State of
                     Peer-to-Peer (P2P) Communication across Network
                     Address Translators (NATs)", RFC 5128,
                     March 2008.

[RFC1928]            Leech, M., Ganis, M., Lee, Y., Kuris, R.,
                     Koblas, D., and L. Jones, "SOCKS Protocol
                     Version 5", RFC 1928, March 1996.

[RFC3550]            Schulzrinne, H., Casner, S., Frederick, R., and
                     V. Jacobson, "RTP: A Transport Protocol for
                     Real-Time Applications", STD 64, RFC 3550,
                     July 2003.

[RFC3711]            Baugher, M., McGrew, D., Naslund, M., Carrara,
                     E., and K. Norrman, "The Secure Real-time
                     Transport Protocol (SRTP)", RFC 3711,
                     March 2004.

[RFC4302]            Kent, S., "IP Authentication Header", RFC 4302,
                     December 2005.

[RFC4303]            Kent, S., "IP Encapsulating Security Payload
                     (ESP)", RFC 4303, December 2005.

[RFC4821]            Mathis, M. and J. Heffner, "Packetization Layer
                     Path MTU Discovery", RFC 4821, March 2007.

[RFC3261]            Rosenberg, J., Schulzrinne, H., Camarillo, G.,
                     Johnston, A., Peterson, J., Sparks, R., Handley,
                     M., and E. Schooler, "SIP: Session Initiation
                     Protocol", RFC 3261, June 2002.

[MMUSIC-ICE-NONSIP]  Rosenberg, J., "Guidelines for Usage of
                     Interactive Connectivity Establishment (ICE) by
                     non Session Initiation Protocol (SIP)
                     Protocols", Work in Progress, July 2008.

[RFC4086]            Eastlake, D., Schiller, J., and S. Crocker,
                     "Randomness Requirements for Security", BCP 106,
                     RFC 4086, June 2005.

[Frag-Harmful]       Kent and Mogul, "Fragmentation Considered
                     Harmful".  Proc. SIGCOMM '87, vol. 17, No. 5,
                     October 1987

[Port-Numbers]       "IANA Port Numbers Registry",
                     <http://www.iana.org>.

[Protocol-Numbers]   "IANA Protocol Numbers Registry", 2005,
                     <http://www.iana.org>.

Authors' Addresses ๐Ÿ’–

the squad behind this spec, with their contact details ๐Ÿซถ

Rohan Mahy
Unaffiliated

EMail: rohan@ekabal.com


Philip Matthews
Alcatel-Lucent
600 March Road
Ottawa, Ontario
Canada

EMail: philip_matthews@magma.ca


Jonathan Rosenberg
jdrosen.net
Monmouth, NJ
USA

EMail: jdrosen@jdrosen.net
URI:   http://www.jdrosen.net
๐Ÿ“ฆ where this page comes from