RFC 8656

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

๐Ÿ“… published February 2020, from ietf

RFC 8656 ๐Ÿ’– Part 1 of 21

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

Request for Comments: 8656 ๐Ÿ“„ Category: Standards Track โœจ ISSN: 2070-1721 Date: February 2020 ๐ŸŒธ Obsoletes: RFCs 5766 and 6156 ๐Ÿ’…

Authors: T. Reddy, Ed. (McAfee), A. Johnston, Ed. (Villanova University), P. Matthews (Alcatel-Lucent), and J. Rosenberg (jdrosen.net) ๐Ÿ‘‘

Published by: the Internet Engineering Task Force (IETF) ๐Ÿฆ‹


Abstract ๐Ÿ’–

okay so if a host is stuck behind a NAT, it can be literally impossible for that host to talk directly to other hosts (called peers) in some situations ๐Ÿ˜ญ. In those cases, the host needs to use an intermediate node that acts as a communication relay. This spec defines a protocol called "Traversal Using Relays around NAT" (TURN) that lets the host control the relay and swap packets with its peers through it. TURN is iconic because it lets a client talk to multiple peers using one single relay address ๐Ÿ”ฅ.

TURN was designed to be used as part of the Interactive Connectivity Establishment (ICE) approach to NAT traversal, though it can also be used without ICE โœจ.

This document obsoletes RFCs 5766 and 6156 ๐Ÿซถ.

Status of This Memo ๐ŸŒˆ

This is an Internet Standards Track document ๐Ÿ’œ.

This document is a product of the Internet Engineering Task Force (IETF). It represents the consensus of the IETF community, and it has received public review and been approved for publication by the Internet Engineering Steering Group (IESG). For more on Internet Standards, check Section 2 of RFC 7841 ๐Ÿงš.

For the current status, any errata, and how to send feedback, go to https://www.rfc-editor.org/info/rfc8656 ๐Ÿ“.

Copyright (c) 2020 IETF Trust and the persons identified as the document authors. All rights reserved ๐Ÿ’….

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication. Please read these carefully, because they describe your rights and restrictions with respect to this document ๐Ÿ™ˆ. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions, and they are provided without warranty as described in the Simplified BSD License โญ.

Table of Contents ๐Ÿฆ‹

   1.  Introduction
   2.  Terminology
   3.  Overview of Operation
     3.1.  Transports
     3.2.  Allocations
     3.3.  Permissions
     3.4.  Send Mechanism
     3.5.  Channels
     3.6.  Unprivileged TURN Servers
     3.7.  Avoiding IP Fragmentation
     3.8.  RTP Support
     3.9.  Happy Eyeballs for TURN
   4.  Discovery of TURN Server
     4.1.  TURN URI Scheme Semantics
   5.  General Behavior
   6.  Allocations
   7.  Creating an Allocation
     7.1.  Sending an Allocate Request
     7.2.  Receiving an Allocate Request
     7.3.  Receiving an Allocate Success Response
     7.4.  Receiving an Allocate Error Response
   8.  Refreshing an Allocation
     8.1.  Sending a Refresh Request
     8.2.  Receiving a Refresh Request
     8.3.  Receiving a Refresh Response
   9.  Permissions
   10. CreatePermission
     10.1.  Forming a CreatePermission Request
     10.2.  Receiving a CreatePermission Request
     10.3.  Receiving a CreatePermission Response
   11. Send and Data Methods
     11.1.  Forming a Send Indication
     11.2.  Receiving a Send Indication
     11.3.  Receiving a UDP Datagram
     11.4.  Receiving a Data Indication
     11.5.  Receiving an ICMP Packet
     11.6.  Receiving a Data Indication with an ICMP Attribute
   12. Channels
     12.1.  Sending a ChannelBind Request
     12.2.  Receiving a ChannelBind Request
     12.3.  Receiving a ChannelBind Response
     12.4.  The ChannelData Message
     12.5.  Sending a ChannelData Message
     12.6.  Receiving a ChannelData Message
     12.7.  Relaying Data from the Peer
   13. Packet Translations
     13.1.  IPv4-to-IPv6 Translations
     13.2.  IPv6-to-IPv6 Translations
     13.3.  IPv6-to-IPv4 Translations
   14. UDP-to-UDP Relay
   15. TCP-to-UDP Relay
   16. UDP-to-TCP Relay
   17. STUN Methods
   18. STUN Attributes
     18.1.  CHANNEL-NUMBER
     18.2.  LIFETIME
     18.3.  XOR-PEER-ADDRESS
     18.4.  DATA
     18.5.  XOR-RELAYED-ADDRESS
     18.6.  REQUESTED-ADDRESS-FAMILY
     18.7.  EVEN-PORT
     18.8.  REQUESTED-TRANSPORT
     18.9.  DONT-FRAGMENT
     18.10. RESERVATION-TOKEN
     18.11. ADDITIONAL-ADDRESS-FAMILY
     18.12. ADDRESS-ERROR-CODE
     18.13. ICMP
   19. STUN Error Response Codes
   20. Detailed Example
   21. Security Considerations
     21.1.  Outsider Attacks
       21.1.1.  Obtaining Unauthorized Allocations
       21.1.2.  Offline Dictionary Attacks
       21.1.3.  Faked Refreshes and Permissions
       21.1.4.  Fake Data
       21.1.5.  Impersonating a Server
       21.1.6.  Eavesdropping Traffic
       21.1.7.  TURN Loop Attack
     21.2.  Firewall Considerations
       21.2.1.  Faked Permissions
       21.2.2.  Blacklisted IP Addresses
       21.2.3.  Running Servers on Well-Known Ports
     21.3.  Insider Attacks
       21.3.1.  DoS against TURN Server
       21.3.2.  Anonymous Relaying of Malicious Traffic
       21.3.3.  Manipulating Other Allocations
     21.4.  Tunnel Amplification Attack
     21.5.  Other Considerations
   22. IANA Considerations
   23. IAB Considerations
   24. Changes since RFC 5766
   25. Updates to RFC 6156
   26. References
     26.1.  Normative References
     26.2.  Informative References
   Acknowledgements
   Authors' Addresses

1. Introduction โœจ

okay so a host behind a NAT might want to swap packets with other hosts, and some of those might be behind NATs too ๐Ÿ™ˆ. To make that work, the hosts can try "hole punching" techniques (see [RFC5128]) to find a direct path, which is a route from one host to another through the NATs and routers in between that doesn't touch any relays ๐Ÿฆ‹.

As described in [RFC5128] and [RFC4787], hole punching will fail if both hosts are behind NATs that aren't well behaved ๐Ÿ’€. For example, if both hosts are behind NATs with a mapping behavior of "address-dependent mapping" or "address- and port-dependent mapping" (see Section 4.1 of [RFC4787]), hole punching generally fails ๐Ÿ˜ญ.

When a direct path can't be found, you need an intermediate host that acts as a relay for the packets ๐Ÿซถ. This relay usually lives on the public Internet and relays packets between two hosts that are both sitting behind NATs ๐ŸŒธ.

In many enterprise networks, direct UDP traffic between clients on the internal network and external IP addresses isn't allowed ๐Ÿ™…โ€โ™€๏ธ. To let media sessions use UDP without being forced over TCP, an Enterprise Firewall can be set up to allow UDP traffic relayed through an Enterprise relay server ๐Ÿ’œ. WebRTC requires support for this scenario (see Section 2.3.5.1 of [RFC7478]) ๐Ÿ”ฅ. Some SIP or WebRTC users also want IP location privacy from the remote peer. In that case, the client can pick a relay server that offers IP location privacy and only share the relayed candidates with the peer for ICE connectivity checks (see Section 4.2.4 of [SEC-WEBRTC]) ๐Ÿงš.

This specification defines a protocol called "TURN" that lets a host behind a NAT (called the "TURN client") ask another host (called the "TURN server") to act as a relay ๐Ÿ’–. The client can set things up so the server relays packets to and from certain other hosts (called "peers"), and it can control aspects of how that relaying happens ๐Ÿ‘‘. The client does this by getting an IP address and port on the server, called the "relayed transport address" ๐ŸŽ€. When a peer sends a packet to the relayed transport address, the server relays the transport protocol data from that packet to the client. The data is wrapped in a message header that lets the client know which peer the data was relayed from ๐Ÿฆ‹. If the server receives an ICMP error packet, it also relays certain Layer 3 and 4 header fields from the ICMP header to the client โญ. When the client sends a message to the server, the server figures out the remote peer from the message header and relays the message data to the intended peer ๐Ÿ“.

A client using TURN has to find some way to tell its peers the relayed transport address, and it has to learn each peer's IP address and port (more precisely, each peer's server-reflexive transport address; see Section 3) ๐ŸŒˆ. How that happens is out of scope for the TURN protocol ๐Ÿ™ˆ. One option is for the client and peers to swap email messages ๐Ÿ’…. Another is for them to use a special-purpose "introduction" or "rendezvous" protocol (see [RFC5128] for more details) ๐Ÿซถ.

If TURN is used with ICE [RFC8445], then the relayed transport address and the IP addresses and ports of the peers get included in the ICE candidate information that the rendezvous protocol has to carry ๐Ÿ”ฅ. For example, if TURN and ICE are part of a multimedia solution using SIP [RFC3261], then SIP is the rendezvous protocol, carrying the ICE candidate information inside the body of SIP messages [SDP-ICE] โœจ. If TURN and ICE are used with some other rendezvous protocol, then ICE gives guidance on the services that rendezvous protocol needs to perform ๐Ÿงš.

Using a TURN server to get two hosts behind NATs talking is very likely to work, but it costs the TURN server provider a lot ๐Ÿ’ธ, since the server usually needs a high-bandwidth Internet connection ๐Ÿ˜ญ. So it's best to use a TURN server only when a direct path can't be found ๐Ÿ™. When the client and a peer use ICE to pick the communication path, ICE tries hole punching to look for a direct path first, and it only uses a TURN server when no direct path can be found ๐Ÿ’–.

TURN was originally invented to support multimedia sessions signaled using SIP ๐Ÿ“ž. Since SIP supports forking, TURN supports multiple peers per relayed transport address, which other approaches don't do (e.g., SOCKS [RFC1928]) ๐Ÿ‘‘. Even so, care has been taken to make sure TURN is suitable for other kinds of applications too ๐ŸŒธ.

TURN was designed as one piece of the bigger ICE approach to NAT traversal ๐Ÿฆ‹. Implementors of TURN are urged to look into ICE and seriously consider using it for their application ๐Ÿ’…. It is still possible to use TURN without ICE, though ๐Ÿซถ.

TURN is an extension to the Session Traversal Utilities for NAT (STUN) protocol [RFC8489] ๐Ÿงš. Most TURN messages are STUN-formatted messages, though not all of them are ๐Ÿ™ˆ. If you're reading this document, you should already be familiar with STUN ๐ŸŽ€.

The TURN specification was originally published as [RFC5766], which was updated by [RFC6156] to add IPv6 support ๐ŸŒˆ. This document supersedes and obsoletes both [RFC5766] and [RFC6156] ๐Ÿ’œ.

2. Terminology โœจ

okay bestie, let's get into the vocab, because TURN has a LOT of terms and we need them locked in ๐Ÿ”๐Ÿ’–

The big requirement keywords first: "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" mean what they mean in BCP 14 [RFC2119] [RFC8174] but only when they show up in ALL CAPITALS, just like here ๐Ÿ’…. Lowercase "must" is just a regular word, no cap ๐Ÿ™ˆ

Also, you're expected to already know [RFC8489] and the terms it defines. It's the STUN spec, so if you're new to that, go read it first ๐Ÿงš

Here are the terms we use in this doc:

TURN: The protocol spoken between a TURN client and a TURN server. It's an extension to the STUN protocol [RFC8489]. The protocol lets a client allocate and use a relayed transport address ๐Ÿฆ‹

TURN client: A STUN client that implements this specification. โœจ

TURN server: A STUN server that implements this specification. It relays data between a TURN client and its peer(s). ๐Ÿซถ

Peer: A host the TURN client wants to talk to. The TURN server relays traffic between the TURN client and its peer(s). The peer does NOT speak the TURN protocol ๐Ÿ™…โ€โ™€๏ธ It just receives data sent by the TURN server, and it sends data toward the TURN server. Lowkey the peer is just living its best life ๐Ÿ’œ

Transport Address: The combo of an IP address and a port. ๐ŸŒธ

Host Transport Address: A transport address on a client or a peer. ๐ŸŽ€

Server-Reflexive Transport Address: A transport address on the "external side" of a NAT. The NAT allocates this address to match up with a specific host transport address. It's giving "NAT mapping" energy ๐ŸŒˆ

Relayed Transport Address: A transport address on the TURN server that's used to relay packets between the client and a peer. A peer sends to this address on the TURN server, and then the packet gets relayed to the client. โœจ

TURN Server Transport Address: A transport address on the TURN server that's used to send TURN messages to the server. This is the address the client uses to talk to the server. ๐Ÿงš

Peer Transport Address: The transport address of the peer as seen by the server. When the peer is behind a NAT, this is the peer's server-reflexive transport address. ๐Ÿฆ‹

Allocation: The relayed transport address granted to a client through an Allocate request, plus related state like permissions and expiration timers. It's the whole package, main character energy ๐Ÿ‘‘

5-tuple: The combo of (client IP address and port, server IP address and port, and transport protocol). The transport protocol is currently one of UDP, TCP, DTLS/UDP, or TLS/TCP. This is used to communicate between the client and the server. The 5-tuple uniquely identifies this communication stream, and it also uniquely identifies the Allocation on the server. Iconic, honestly ๐Ÿ”ฅ

Transport Protocol: The protocol above IP that carries TURN Requests, Responses, and Indications, and that provides identifiable flows using a 5-tuple. In this spec, UDP and TCP are defined as transport protocols. This doc also describes using UDP and TCP together with a security layer using DTLS and TLS, respectively. ๐Ÿ”

Channel: A channel number plus an associated peer transport address. Once a channel number is bound to a peer's transport address, the client and server can use the more bandwidth-efficient ChannelData message to exchange data. Bandwidth-efficient = slay ๐Ÿ’–

Permission: The IP address and transport protocol (but NOT the port) of a peer that's allowed to send traffic to the TURN server and have that traffic relayed to the TURN client. The TURN server will only forward traffic to its client from peers that match an existing permission. Not the port, bestie, just the IP and protocol ๐Ÿ™ˆ

Realm: A string used to describe the server or a context within the server. The realm tells the client which username and password combination to use to authenticate requests. ๐ŸŽ€

Nonce: A string chosen at random by the server and included in the server response. To prevent replay attacks, the server SHOULD change the nonce regularly. ๐ŸŒธ

(D)TLS: This term is used for statements that apply to both Transport Layer Security [RFC8446] and Datagram Transport Layer Security [RFC6347]. Two protocols, one term, zero stress ๐Ÿ˜ญโœจ


3. Overview of Operation ๐Ÿฆ‹

okay so this section gives an overview of how TURN works. It is non-normative, which means it's just the vibes and not the rules ๐Ÿ’…

In a typical setup, a TURN client is connected to a private network [RFC1918] and, through one or more NATs, to the public Internet. Out on the public Internet is a TURN server. Elsewhere on the Internet are one or more peers that the TURN client wants to talk to. These peers may or may not be behind one or more NATs. The client uses the server as a relay to send packets to these peers and to receive packets from them ๐Ÿงš

                                   Peer A
                                   Server-Reflexive    +---------+
                                   Transport Address   |         |
                                   192.0.2.150:32102   |         |
                                       |              /|         |
                     TURN              |            / ^|  Peer A |
  Client's           Server            |           /  ||         |
  Host Transport     Transport         |         //   ||         |
  Address            Address           |       //     |+---------+
198.51.100.2:49721  192.0.2.15:3478     |+-+  //     Peer A
          |            |               ||N| /       Host Transport
          |   +-+      |               ||A|/        Address
          |   | |      |               v|T|     203.0.113.2:49582
          |   | |      |               /+-+
+---------+|   | |      |+---------+   /              +---------+
|         ||   |N|      ||         | //               |         |
| TURN    |v   | |      v| TURN    |/                 |         |
| Client  |----|A|-------| Server  |------------------|  Peer B |
|         |    | |^      |         |^                ^|         |
|         |    |T||      |         ||                ||         |
+---------+    | ||      +---------+|                |+---------+
              | ||                 |                |
              | ||                 |                |
              +-+|                 |                |
                 |                 |                |
                 |                 |                |
        Client's                   |             Peer B
        Server-Reflexive     Relayed             Transport
        Transport Address    Transport Address   Address
        192.0.2.1:7000       192.0.2.15:50000    192.0.2.210:49191

                              Figure 1

Figure 1 shows a typical deployment. In this figure, the TURN client and the TURN server are separated by a NAT, with the client on the private side and the server on the public side of the NAT. This NAT is assumed to be a "bad" NAT. For example, it might have a mapping property of "address-and-port-dependent mapping" (see [RFC4787]). Yikes, bad NAT ๐Ÿ˜ญ

The client talks to the server from a (IP address, port) combo called the client's "host transport address". (The combo of an IP address and port is called a "transport address".) ๐ŸŒธ

The client sends TURN messages from its host transport address to a transport address on the TURN server that's known as the "TURN server transport address". The client learns the TURN server transport address through some unspecified means (e.g., configuration), and this address is typically used by many clients at the same time ๐Ÿ’œ

Since the client is behind a NAT, the server sees packets from the client as coming from a transport address on the NAT itself. This address is known as the client's "server-reflexive transport address". Packets the server sends to the client's server-reflexive transport address will be forwarded by the NAT to the client's host transport address ๐Ÿฆ‹

The client uses TURN commands to create and manipulate an ALLOCATION on the server. An allocation is a data structure on the server. This data structure contains, amongst other things, the relayed transport address for the allocation. The relayed transport address is the transport address on the server that peers can use to have the server relay data to the client. An allocation is uniquely identified by its relayed transport address. โœจ

Once an allocation exists, the client can send application data to the server along with an indication of which peer the data should go to, and the server will relay it to that peer. The client sends the application data to the server inside a TURN message; at the server, the data is pulled out of the TURN message and sent to the peer in a UDP datagram. In the other direction, a peer can send application data in a UDP datagram to the relayed transport address for the allocation. The server then wraps this data inside a TURN message and sends it to the client, along with an indication of which peer sent it. Since the TURN message always says which peer the client is talking to, the client can use a single allocation to talk to multiple peers. Multitasking queen ๐Ÿ‘‘

When the peer is behind a NAT, the client MUST identify the peer using its server-reflexive transport address rather than its host transport address. For example, to send application data to Peer A in the example above, the client MUST specify 192.0.2.150:32102 (Peer A's server-reflexive transport address) rather than 203.0.113.2:49582 (Peer A's host transport address). Not the host address, bestie ๐Ÿ™…โ€โ™€๏ธ

Each allocation on the server belongs to a single client and has either one or two relayed transport addresses that are used only by that allocation. So when a packet arrives at a relayed transport address on the server, the server knows which client the data is meant for. Iconic routing ๐ŸŽ€

The client MAY have multiple allocations on a server at the same time. ๐ŸŒˆ

3.1. Transports ๐Ÿš€

okay so TURN, as defined in this spec, always uses UDP between the server and the peer ๐Ÿฆ‹ but the spec lets you pick any one of UDP, TCP, TLS over TCP, or DTLS over UDP to carry the TURN messages between the client and the server โœจ

        +----------------------------+---------------------+
        | TURN client to TURN server | TURN server to peer |
        +============================+=====================+
        |            UDP             |         UDP         |
        +----------------------------+---------------------+
        |            TCP             |         UDP         |
        +----------------------------+---------------------+
        |        TLS-over-TCP        |         UDP         |
        +----------------------------+---------------------+
        |       DTLS-over-UDP        |         UDP         |
        +----------------------------+---------------------+

                              Table 1

if TCP or TLS-over-TCP is used between the client and the server, the server will convert between those transports and UDP when it relays data to and from the peer ๐Ÿ”„

since this version of TURN only supports UDP between the server and the peer, most clients are expected to prefer UDP between the client and the server too ๐Ÿ’– so you might be wondering: why bother supporting TCP and TLS-over-TCP at all? ๐Ÿค”

TURN supports TCP between the client and the server because some firewalls are set up to block UDP entirely ๐Ÿงฑ those firewalls block UDP but not TCP, partly because TCP has properties that make the intention of the protected nodes way more obvious to the firewall ๐Ÿ‘€ for example, TCP has a three-way handshake, which makes it clear that the protected node really wants that connection set up. with UDP, the firewall can only guess which flows are wanted by using filtering rules ๐ŸŽฒ TCP also has explicit connection teardown, whereas with UDP the firewall has to use timers to guess when a flow is done โฐ

TURN supports TLS-over-TCP and DTLS-over-UDP between the client and the server because (D)TLS gives you extra security properties that TURN's default digest authentication doesn't, and some clients want to use those ๐Ÿ” most importantly, (D)TLS lets the client check that it's really talking to the right server, and it keeps TURN control messages confidential ๐Ÿซถ if you use (D)TLS transport between the TURN client and the TURN server, check out Section 6.2.3 of [RFC8489] for the details on cipher suites, server certificate validation, and authenticating TURN servers ๐Ÿ“œ the guidance given in [RFC7525] MUST be followed to avoid attacks on (D)TLS, no exceptions ๐Ÿšจ TURN doesn't require (D)TLS, though, because the overhead is higher than digest authentication's. for example, with (D)TLS, most application data ends up doubly encrypted: once by (D)TLS, and once more so it's still encrypted inside the UDP datagram ๐Ÿฅด

there's an extension to TURN for TCP transport between the server and the peers, described in [RFC6062] ๐Ÿงฉ because of that, allocations that use UDP between the server and the peers are called "UDP allocations", and allocations that use TCP between the server and the peers are called "TCP allocations". this specification only describes UDP allocations ๐Ÿ’…

in some TURN applications, the client may send and receive packets that aren't TURN packets on the same host transport address it uses to talk to the server ๐Ÿงš this can happen when you use TURN with ICE, for example ๐ŸŒˆ in those cases, the client can tell TURN packets apart from everything else by looking at the source address of the arriving packet: anything arriving from the TURN server is a TURN packet ๐ŸŽ€ the algorithm for demultiplexing packets received from multiple protocols on the host transport address is discussed in [RFC7983] ๐Ÿง 


3.2. Allocations ๐ŸŽ€

to create an allocation on the server, the client runs an Allocate transaction ๐ŸŒธ the client sends an Allocate request to the server, and the server replies with an Allocate success response that contains the allocated relayed transport address ๐Ÿ’œ the client can include attributes in the Allocate request that describe the kind of allocation it wants (for example, the lifetime of the allocation) โณ relaying data has security implications, so the server requires the client to authenticate itself, typically using STUN's long-term credential mechanism or the STUN Extension for Third-Party Authorization [RFC7635], to show it's allowed to use the server ๐Ÿ”‘

once a relayed transport address is allocated, a client must keep that allocation alive ๐Ÿ’ซ to do this, the client periodically sends a Refresh request to the server ๐Ÿ” TURN deliberately uses a different method (Refresh rather than Allocate) for refreshes, so the client is told if the allocation vanishes for some reason ๐Ÿ‘€

how often the Refresh transaction happens is determined by the lifetime of the allocation ๐Ÿ•ฐ๏ธ the default lifetime is 10 minutes. that number was picked to be long enough that refreshing isn't usually a burden on the client, while still expiring allocations promptly when a client has unexpectedly quit ๐Ÿงธ the client can ask for a longer lifetime in the Allocate request and may change its request in a Refresh request, and the server always reports the actual lifetime in its response ๐Ÿ“ the client must issue a new Refresh transaction within "lifetime" seconds of the previous Allocate or Refresh transaction ๐Ÿƒโ€โ™€๏ธ once a client no longer wants an allocation, it should delete it with a Refresh request that has a requested lifetime of zero ๐Ÿ—‘๏ธ

both the server and the client keep track of something called the "5-tuple" ๐Ÿงฎ at the client, the 5-tuple is made up of the client's host transport address, the server transport address, and the transport protocol the client uses to talk to the server ๐Ÿ›ฐ๏ธ at the server, the 5-tuple is the same except the client's host transport address gets swapped for the client's server-reflexive address, since that's the address the server sees the client using ๐Ÿ‘๏ธ

both the client and the server remember the 5-tuple from the Allocate request, and later messages between them use that same 5-tuple ๐Ÿค that's how they both know which allocation is being talked about ๐Ÿ’– if the client wants a second relayed transport address, it has to create a second allocation using a different 5-tuple (for example, a different client host address or port) ๐Ÿฆ‹

NOTE: okay, even though this document talks about 5-tuples, the TURN server can store whatever identifier it likes, as long as the results come out identical ๐Ÿง  for instance, an implementation can use a file descriptor in place of a 5-tuple to represent a TCP connection ๐Ÿงฉ

here's the Allocate flow in action ๐Ÿ‘‡

TURN                                 TURN          Peer         Peer
client                               server         A            B
  |-- Allocate request --------------->|            |            |
  |   (invalid or missing credentials) |            |            |
  |                                    |            |            |
  |<--------------- Allocate failure --|            |            |
  |              (401 Unauthenticated) |            |            |
  |                                    |            |            |
  |-- Allocate request --------------->|            |            |
  |               (valid credentials)  |            |            |
  |                                    |            |            |
  |<---------- Allocate success resp --|            |            |
  |            (192.0.2.15:50000)      |            |            |
  //                                   //           //           //
  |                                    |            |            |
  |-- Refresh request ---------------->|            |            |
  |                                    |            |            |
  |<----------- Refresh success resp --|            |            |
  |                                    |            |            |

                               Figure 2

in Figure 2, the client sends an Allocate request to the server with invalid or missing credentials ๐Ÿ™ˆ since the server requires every request to be authenticated with STUN's long-term credential mechanism, it rejects the request with a 401 (Unauthorized) error code ๐Ÿšซ the client then tries again, this time with credentials ๐Ÿ” this time the server accepts the Allocate request and returns an Allocate success response containing (among other things) the relayed transport address assigned to the allocation ๐ŸŽ‰ a while later, the client decides to refresh the allocation, so it sends a Refresh request to the server โœจ the refresh is accepted, and the server replies with a Refresh success response ๐Ÿฅฐ


3.3. Permissions ๐Ÿ’…

okay, so enterprise IT admins were worried that TURN could be used to get around corporate firewall security ๐Ÿ˜ค to ease those concerns, TURN includes the notion of permissions ๐Ÿ”’ TURN permissions copy the address-restricted filtering mechanism of NATs that comply with [RFC4787] ๐Ÿชž

an allocation can have zero or more permissions ๐ŸŽŸ๏ธ each permission consists of an IP address and a lifetime ๐Ÿ•’ when the server gets a UDP datagram on the allocation's relayed transport address, it checks the permission list first ๐Ÿ” if the datagram's source IP address matches a permission, the application data is relayed to the client; otherwise, the UDP datagram is silently discarded ๐Ÿซฅ

a permission expires after 5 minutes if it isn't refreshed, and there's no way to explicitly delete a permission ๐Ÿ™…โ€โ™€๏ธ that behavior was chosen to match a NAT that complies with [RFC4787] ๐Ÿฆ‹

the client can install or refresh a permission using either a CreatePermission request or a ChannelBind request ๐ŸŒท with CreatePermission, you can install or refresh several permissions in one single request, which matters a lot for apps that use ICE ๐Ÿงš for security reasons, permissions can only be installed or refreshed by transactions that can be authenticated ๐Ÿ›ก๏ธ so Send indications and ChannelData messages (the ones used to send data to peers) don't install or refresh any permissions ๐Ÿšซ

one more thing: permissions live within the context of an allocation, so adding or expiring a permission in one allocation doesn't affect any other allocations ๐ŸŒˆ

3.4. Send Mechanism โœจ

okay so there are two ways the client and its peers can swap app data through the TURN server ๐Ÿ’Œ The first one uses Send and Data methods, and the second one uses channels. Both give the client a way to chat with multiple peers through one relayed transport address ๐Ÿฆ‹ So both need a way for the client to say which peer should get the data, and for the server to say which peer the data came from ๐Ÿซถ

The Send mechanism uses Send and Data indications. Send indications carry app data from the client to the server, and Data indications carry it from the server back to the client ๐Ÿ“จ

when the client is using Send, it sends a Send indication to the TURN server with (a) an XOR-PEER-ADDRESS attribute that holds the peer's (server-reflexive) transport address and (b) a DATA attribute with the actual app data ๐Ÿ’… When the server gets that Send indication, it pulls the data out of DATA and sends it to the peer in a UDP datagram, using the allocated relay address as the source address ๐ŸŽ€ ngl, there's no need to specify the relayed transport address, because the 5-tuple used for the Send indication already implies it ๐Ÿ™ˆ

going the other way, UDP datagrams that land on the relayed transport address are turned into Data indications and sent to the client ๐ŸŒธ The peer's server-reflexive transport address goes in an XOR-PEER-ADDRESS attribute, and the data itself goes in a DATA attribute. Since the relayed transport address uniquely identifies the allocation, the server always knows which client should get the data ๐Ÿ‘‘

some ICMP (Internet Control Message Protocol) packets that arrive at the relayed transport address may also be turned into Data indications and sent to the client ๐Ÿงš They carry the peer's transport address in an XOR-PEER-ADDRESS attribute, and the ICMP type and code go in an ICMP attribute. ICMP attribute forwarding always uses Data indications with the XOR-PEER-ADDRESS and ICMP attributes, even when the channel mechanism is being used to forward UDP data ๐Ÿ”ฅ

Send and Data indications can't be authenticated, because STUN's long-term credential mechanism doesn't support authenticating indications ๐Ÿ’€ The good news is that this isn't as big a deal as it sounds, since the client-to-server leg is only half of the whole path to the peer ๐Ÿซถ Apps that want true end-to-end security should encrypt the data they send between the client and a peer ๐Ÿ”

because Send indications aren't authenticated, an attacker could send bogus Send indications to the server, and the server would then relay them to a peer ๐Ÿ˜ญ To partly stop this, TURN requires the client to install a permission towards a peer before sending it data with a Send indication ๐Ÿ›ก๏ธ The technique for fully stopping the attack is covered in Section 21.1.4 โœจ

Figure 3 shows what that looks like in a call flow ๐Ÿ‘‡

TURN                                TURN           Peer          Peer
client                              server          A             B
  |                                   |             |             |
  |-- CreatePermission req (Peer A) ->|             |             |
  |<- CreatePermission success resp --|             |             |
  |                                   |             |             |
  |--- Send ind (Peer A)------------->|             |             |
  |                                   |=== data ===>|             |
  |                                   |             |             |
  |                                   |<== data ====|             |
  |<------------- Data ind (Peer A) --|             |             |
  |                                   |             |             |
  |                                   |             |             |
  |--- Send ind (Peer B)------------->|             |             |
  |                                   | dropped     |             |
  |                                   |             |             |
  |                                   |<== data ==================|
  |                           dropped |             |             |
  |                                   |             |             |

Figure 3

in Figure 3, the client has already made an allocation and now wants to send data to its peers ๐Ÿฆ‹ First it creates a permission by sending the server a CreatePermission request with Peer A's (server-reflexive) IP address in the XOR-PEER-ADDRESS attribute. If that step got skipped, the server wouldn't relay data between the client and the server ๐Ÿ™…โ€โ™€๏ธ Next, the client sends data to Peer A with a Send indication. The server pulls out the app data and forwards it to Peer A in a UDP datagram, using the relayed transport address as the source ๐Ÿ’– When a UDP datagram from Peer A shows up at the relayed transport address, its contents go into a Data indication and get forwarded to the client โœจ Then the client tries to talk to Peer B, but there's no permission for Peer B yet, so the server drops both the Send indication from the client and the UDP datagram from the peer ๐Ÿ’€ bestie, that's the permission system doing its job ๐Ÿ”ฅ

3.5. Channels

for some apps (like Voice over IP (VoIP)), the 36 bytes of overhead that a Send indication or Data indication adds to the app data can really eat up the bandwidth between the client and the server ๐Ÿ˜ญ To fix that, TURN gives us a second way for the client and server to tie data to a specific peer ๐ŸŒˆ

this second way uses a different packet format called the "ChannelData message" ๐ŸŽ€ A ChannelData message doesn't use the STUN header that the other TURN messages use. Instead, it has a 4-byte header with a number called a "channel number" ๐Ÿ“ Each channel number in use is bound to one specific peer, so it works as a shorthand for that peer's host transport address ๐Ÿงš

to bind a channel to a peer, the client sends a ChannelBind request to the server, including an unbound channel number and the peer's transport address ๐Ÿ’… Once the channel is bound, the client can use a ChannelData message to send data to that peer through the server. The server can also relay data from that peer back to the client in a ChannelData message ๐Ÿ’œ

channel bindings last for 10 minutes unless they get refreshed, and that lifetime was picked to be longer than the permission lifetime โฐ To refresh a binding, the client sends another ChannelBind request that rebinds the channel to the peer ๐Ÿ”„ Like permissions (but unlike allocations), there's no way to explicitly delete a channel binding. The client just has to wait for it to time out ๐Ÿ˜Œ

Figure 4 shows the channel mechanism in action ๐Ÿ‘‡

TURN                                TURN           Peer          Peer
client                              server          A             B
  |                                   |             |             |
  |-- ChannelBind req --------------->|             |             |
  | (Peer A to 0x4001)                |             |             |
  |                                   |             |             |
  |<---------- ChannelBind succ resp -|             |             |
  |                                   |             |             |
  |-- (0x4001) data ----------------->|             |             |
  |                                   |=== data ===>|             |
  |                                   |             |             |
  |                                   |<== data ====|             |
  |<------------------ (0x4001) data -|             |             |
  |                                   |             |             |
  |--- Send ind (Peer A)------------->|             |             |
  |                                   |=== data ===>|             |
  |                                   |             |             |
  |                                   |<== data ====|             |
  |<------------------ (0x4001) data -|             |             |
  |                                   |             |             |

Figure 4

in Figure 4, the client has already made an allocation and now wants to bind a channel to Peer A ๐ŸŒธ It sends a ChannelBind request to the server with Peer A's transport address and a channel number (0x4001) ๐ŸŽฏ After that, the client can send app data wrapped in ChannelData messages to Peer A, shown as "(0x4001) data" where 0x4001 is the channel number ๐Ÿ’– When the ChannelData message reaches the server, the server moves the data into a UDP datagram and sends it to Peer A, since Peer A is the peer bound to channel 0x4001 โœจ

going the other way, when Peer A sends a UDP datagram to the relayed transport address, that datagram arrives at the server on the relayed transport address assigned to the allocation ๐Ÿ“ฌ Because Peer A has a channel number assigned to it, the server wraps the data in a ChannelData message when it sends it to the client ๐Ÿซถ

once a channel is bound, the client is free to mix ChannelData messages and Send indications ๐Ÿ”€ In the figure, the client later decides to use a Send indication instead of a ChannelData message to send more data to Peer A. It might do that, for example, so it can use the DONT-FRAGMENT attribute (see the next section) ๐Ÿ™ˆ Still, once a channel is bound, the server will always use a ChannelData message, as shown in the call flow ๐Ÿ‘‘

one important thing: ChannelData messages can only be used with peers the client has bound a channel to ๐Ÿšจ In the example above, Peer A has a channel bound, but Peer B doesn't, so app data to and from Peer B would use the Send mechanism ๐Ÿงš

3.6. Unprivileged TURN Servers

this version of TURN is built so the server can run as a normal app in user space on commonly available operating systems, without needing special privileges ๐Ÿ”“ Why? Because it makes TURN servers super easy to deploy ๐Ÿš€ For example, a TURN server can be built right into a peer-to-peer app, so one peer can offer NAT traversal services to another peer. It also means (D)TLS can be used to secure the TURN connection ๐Ÿ”

this design decision has some consequences for data relayed by a TURN server ๐Ÿ‘‡

  • The value of the Diffserv field may not be preserved across the server ๐Ÿ’…
  • The Time to Live (TTL) field may be reset, rather than decremented, across the server โณ
  • The Explicit Congestion Notification (ECN) field may be reset by the server ๐ŸŒง๏ธ
  • There is no end-to-end fragmentation, since the packet is reassembled at the server ๐Ÿงฉ

future work may specify alternate TURN semantics that tackle these limitations ๐Ÿ”ฎ

3.7. Avoiding IP Fragmentation โœจ

okay bestie, this section is literally about not letting your packets get chopped up into pieces ๐Ÿ”ช๐Ÿ’… For reasons described in [FRAG-HARMFUL], applications, especially the ones sending huge amounts of data, should avoid having their packets fragmented. [FRAG-FRAGILE] talks about the issues with IP fragmentation and suggests alternatives to it ๐Ÿฆ‹ Applications using TCP can, more or less, ignore this because fragmentation avoidance is already a standard part of TCP ๐ŸŽ€ But applications using UDP (and that means any application using this version of TURN) need to avoid IP fragmentation by sending messages that are small enough, or by using UDP fragmentation [UDP-OPT] ๐Ÿซถ Note that the UDP fragmentation option needs to be supported by both endpoints, and when this document was written, UDP fragmentation support was still under discussion and was not deployed ๐Ÿ˜ญ

The application running on the client and the peer can take one of two approaches to avoid IP fragmentation until UDP fragmentation support is available ๐ŸŒธ The first uses messages that are limited to a predetermined fixed maximum, and the second relies on network feedback to adapt that maximum ๐Ÿ’œ

The first approach is to avoid sending large amounts of application data in the TURN messages/UDP datagrams exchanged between the client and the peer. This is the approach most VoIP applications take ๐Ÿ“žโœจ In this approach, the application MUST assume a Path MTU (PMTU) of 1280 bytes, because IPv6 requires that every link in the Internet has an MTU of 1280 octets or greater as specified in [RFC8200] ๐Ÿ‘‘ If IPv4 support on legacy or otherwise unusual networks is a consideration, the application MAY assume an effective MTU of 576 bytes for IPv4 datagrams, as every IPv4 host must be capable of receiving a packet with a length equal to 576 bytes, as discussed in [RFC0791] and [RFC1122] ๐Ÿ“

The exact amount of application data that can be included while avoiding fragmentation depends on the details of the TURN session between the client and the server: whether UDP, TCP, or (D)TLS transport is used, whether ChannelData messages or Send/Data indications are used, and whether any additional attributes (such as the DONT-FRAGMENT attribute) are included. Another factor, which is hard to determine, is whether the MTU gets reduced somewhere along the path for other reasons, such as the use of IP-in-IP tunneling ๐Ÿ™ˆ

As a guideline, sending a maximum of 500 bytes of application data in a single TURN message (by the client on the client-to-server leg) or a UDP datagram (by the peer on the peer-to-server leg) will generally avoid IP fragmentation ๐Ÿงš To further reduce the chance of fragmentation, it is recommended that the client use ChannelData messages when transferring significant volumes of data, since the overhead of the ChannelData message is less than that of Send and Data indications ๐Ÿ’–

The second approach the client and peer can take to avoid fragmentation is to use a path MTU discovery algorithm to determine the maximum amount of application data that can be sent without fragmentation ๐Ÿ”ฅ The classic path MTU discovery algorithm defined in [RFC1191] may not be able to discover the MTU of the transmission path between the client and the peer, since:

  • A probe packet with a Don't Fragment (DF) bit in the IPv4 header set to test a path for a larger MTU can be dropped by routers, or
  • ICMP error messages can be dropped by middleboxes.

As a result, the client and server need to use a path MTU discovery algorithm that does not require ICMP messages. The Packetized Path MTU Discovery algorithm defined in [RFC4821] is one such algorithm, and a set of algorithms is defined in [MTU-DATAGRAM] ๐ŸŒˆ

[MTU-STUN] is an implementation of [RFC4821] that uses STUN to discover the path MTU, so it might be a suitable approach to use in conjunction with a TURN server that supports the DONT-FRAGMENT attribute ๐Ÿฆ‹ When the client includes the DONT-FRAGMENT attribute in a Send indication, this tells the server to set the DF bit in the resulting UDP datagram that it sends to the peer. Since some servers may be unable to set the DF bit, the client SHOULD also include this attribute in the Allocate request; any server that does not support the DONT-FRAGMENT attribute will indicate this by rejecting the Allocate request. If the TURN server carrying out packet translation from IPv4-to-IPv6 is unable to access the state of the Don't Fragment (DF) bit in the IPv4 header, it MUST reject the Allocate request with the DONT-FRAGMENT attribute ๐Ÿ™…โ€โ™€๏ธ๐Ÿ’€


3.8. RTP Support ๐ŸŽ€

One of the envisioned uses of TURN is as a relay for clients and peers that want to exchange real-time data (e.g., voice or video) using RTP ๐ŸŽค๐Ÿ“น To make TURN work well for this, it includes some special support for older versions of RTP ๐Ÿซถ

Old versions of RTP [RFC3550] required that the RTP stream be on an even port number, and the associated RTP Control Protocol (RTCP) stream, if present, be on the next highest port ๐Ÿ”ข To let clients work with peers that still require this, TURN allows the client to request that the server allocate a relayed transport address with an even port number, and optionally request that the server reserve the next-highest port number for a subsequent allocation ๐ŸŒŸ


3.9. Happy Eyeballs for TURN ๐Ÿ‘€๐Ÿ’–

If an IPv4 path to reach a TURN server is found, but the TURN server's IPv6 path isn't working, a dual-stack TURN client can experience a significant connection delay compared to an IPv4-only TURN client ๐Ÿ˜ญ To overcome these connection setup problems, the TURN client needs to query both A and AAAA records for the TURN server specified using a domain name, and try connecting to the TURN server using both IPv6 and IPv4 addresses in a fashion similar to the Happy Eyeballs mechanism defined in [RFC8305] ๐Ÿฆ‹ The TURN client performs the following steps based on the transport protocol being used to connect to the TURN server:

  • For TCP or TLS-over-TCP, the results of the Happy Eyeballs procedure [RFC8305] are used by the TURN client for sending its TURN messages to the server.
  • For clear text UDP, send TURN Allocate requests to both IP address families as discussed in [RFC8305] without authentication information. If the TURN server requires authentication, it will send back a 401 unauthenticated response; the TURN client will use the first UDP connection on which a 401 error response is received. If a 401 error response is received from both IP address families, then the TURN client can silently abandon the UDP connection on the IP address family with lower precedence. If the TURN server does not require authentication (as described in Section 9 of [RFC8155]), it is possible for both Allocate requests to succeed. In this case, the TURN client sends a Refresh with a LIFETIME value of zero on the allocation using the IP address family with lower precedence to delete the allocation ๐Ÿงน
  • For DTLS over UDP, initiate a DTLS handshake to both IP address families as discussed in [RFC8305], and use the first DTLS session that is established. If the DTLS session is established on both IP address families, then the client sends a DTLS close_notify alert to terminate the DTLS session using the IP address family with lower precedence. If the TURN over DTLS server has been configured to require a cookie exchange (Section 4.2 of [RFC6347]) and a HelloVerifyRequest is received from the TURN servers on both IP address families, then the client can silently abandon the connection on the IP address family with lower precedence ๐Ÿ’…

4. Discovery of TURN Server ๐Ÿ”โœจ

Methods of TURN server discovery, including using anycast, are described in [RFC8155]. If a host with multiple interfaces discovers a TURN server on each interface, the mechanism described in [RFC7982] can be used by the TURN client to influence the TURN server selection ๐Ÿงญ The syntax of the "turn" and "turns" URIs is defined in Section 3.1 of [RFC7065]. DTLS as a transport protocol for TURN is defined in [RFC7350] ๐ŸŒˆ

4.1. TURN URI Scheme Semantics ๐Ÿงš

The "turn" and "turns" URI schemes are used to designate a TURN server (also known as a "relay") on Internet hosts accessible using the TURN protocol ๐ŸŒธ The TURN protocol supports sending messages over UDP, TCP, TLS-over-TCP, or DTLS-over-UDP. The "turns" URI scheme MUST be used when TURN is run over TLS-over-TCP or in DTLS-over-UDP, and the "turn" scheme MUST be used otherwise ๐Ÿ” The required <host> part of the "turn" URI denotes the TURN server host. The <port> part, if present, denotes the port on which the TURN server is awaiting connection requests. If it is absent, the default port is 3478 for both UDP and TCP. The default port for TURN over TLS and TURN over DTLS is 5349 ๐Ÿฅฐ

5. General Behavior ๐Ÿ’–

okay so this section is all the general TURN rules that apply to every single TURN message ๐Ÿซถ

TURN is an extension to STUN. All TURN messages, except for the ChannelData message, are STUN-formatted messages ๐Ÿ’… All the base processing rules in [RFC8489] apply to STUN-formatted messages, so every message-forming and message-processing description in this document is implicitly prefixed with the rules of [RFC8489] โœจ

[RFC8489] specifies an authentication mechanism called the "long-term credential mechanism". TURN servers and clients MUST implement this mechanism, and Section 7.2 talks about the authentication options ๐Ÿ”

Note that the long-term credential mechanism applies only to requests and cannot be used to authenticate indications. So indications in TURN are never authenticated, no exceptions ๐Ÿ™ˆ If the server requires requests to be authenticated, then the server's administrator MUST choose a realm value that uniquely identifies the username and password combination the client must use, even if the client uses multiple servers under different administrations ๐ŸŽ€ The administrator MAY choose to give each client a unique username, or it MAY give the same username to more than one client (for example, to all the clients from the same department or company) ๐ŸŒธ For each Allocate request, the server SHOULD generate a new random nonce when the allocation is first attempted, following the randomness recommendations in [RFC4086], and SHOULD expire the nonce at least once every hour during the lifetime of the allocation โฐ The server uses the mechanism described in Section 9.2 of [RFC8489] to indicate that it supports [RFC8489] ๐Ÿฆ‹

All requests after the initial Allocate must use the same username that was used to create the allocation. This is how we stop attackers from hijacking the client's allocation ๐Ÿšซ

Specifically, if:

  • the server requires the use of the long-term credential mechanism, and;
  • a non-Allocate request passes authentication under this mechanism, and;
  • the 5-tuple identifies an existing allocation, but;
  • the request does not use the same username as used to create the allocation,

then the request MUST be rejected with a 441 (Wrong Credentials) error ๐Ÿ˜ค

When a TURN message arrives at the server from the client, the server uses the 5-tuple in the message to find the associated allocation ๐Ÿ” For all TURN messages (including ChannelData) EXCEPT an Allocate request, if the 5-tuple does not identify an existing allocation, then the message MUST either be rejected with a 437 Allocation Mismatch error (if it is a request) or be silently ignored (if it is an indication or a ChannelData message). A client that receives a 437 error response to a request other than Allocate MUST assume the allocation no longer exists ๐Ÿ’€

[RFC8489] defines a number of attributes, including the SOFTWARE and FINGERPRINT attributes. The client SHOULD include the SOFTWARE attribute in all Allocate and Refresh requests, and MAY include it in any other requests or indications. The server SHOULD include the SOFTWARE attribute in all Allocate and Refresh responses (either success or failure), and MAY include it in other responses or indications. The client and the server MAY include the FINGERPRINT attribute in any STUN-formatted messages defined in this document โœจ

TURN does not use the backwards-compatibility mechanism described in [RFC8489] ๐Ÿ™…โ€โ™€๏ธ

TURN, as defined in this specification, supports both IPv4 and IPv6 ๐ŸŒˆ IPv6 support in TURN includes IPv4-to-IPv6, IPv6-to-IPv6, and IPv6-to-IPv4 relaying. When only a single address type is desired, the REQUESTED-ADDRESS-FAMILY attribute is used to explicitly request the address type the TURN server will allocate (for example, an IPv4-only node may request the TURN server to allocate an IPv6 address) ๐Ÿงš If both IPv4 and IPv6 are desired, the single ADDITIONAL-ADDRESS-FAMILY attribute indicates a request to the server to allocate one IPv4 and one IPv6 relay address in a single Allocate request. This saves local ports on the client and reduces the number of messages sent between the client and the TURN server ๐Ÿ“

By default, TURN runs on the same ports as STUN: 3478 for TURN over UDP and TCP, and 5349 for TURN over (D)TLS. TURN also has its own set of Service Record (SRV) names: "turn" for UDP and TCP, and "turns" for (D)TLS ๐Ÿ“ก Either the DNS resolution procedures or the ALTERNATE-SERVER procedures, both described in Section 7, can be used to run TURN on a different port ๐Ÿ”€

To ensure interoperability, a TURN server MUST support the use of UDP transport between the client and the server. It SHOULD also support the use of TCP, TLS-over-TCP, and DTLS-over-UDP transports ๐Ÿซถ

When UDP or DTLS-over-UDP transport is used between the client and the server, the client will retransmit a request if it does not receive a response within a certain timeout period. Because of this, the server may receive two (or more) requests with the same 5-tuple and the same transaction id. STUN requires that the server recognize this case and treat the request as idempotent (see [RFC8489]) ๐Ÿ” Some implementations may choose to meet this requirement by remembering all received requests and the corresponding responses for 40 seconds (Section 6.3.1 of [RFC8489]). Other implementations may choose to reprocess the request and arrange for that reprocessing to return essentially the same response. To help implementors who pick the latter approach (the so-called "stateless stack approach"), this specification includes some implementation notes on how this might be done. Implementations are free to choose either approach, or some other approach that gives the same results ๐Ÿง 

To mitigate either intentional or unintentional denial-of-service attacks against the server by clients with valid usernames and passwords, it is RECOMMENDED that the server impose limits on both the number of allocations active at one time for a given username and the amount of bandwidth those allocations can use ๐Ÿ›ก๏ธ The server should reject new allocations that would exceed the limit on the allowed number of allocations active at one time with a 486 (Allocation Quota Exceeded) (see Section 7.2). And since UDP does not include a congestion control mechanism, it should discard application data traffic that exceeds the bandwidth quota ๐Ÿšง


6. Allocations ๐ŸŽ€

All TURN operations revolve around allocations, and all TURN messages are associated with either a single or a dual allocation ๐Ÿ‘‘ An allocation conceptually consists of the following state data:

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

The relayed transport address is the transport address the server allocates for communicating with peers. The 5-tuple describes the communication path between the client and the server ๐Ÿ›ค๏ธ On the client, the 5-tuple uses the client's host transport address. On the server, the 5-tuple uses the client's server-reflexive transport address. The relayed transport address MUST be unique across all allocations so it can be used to uniquely identify the allocation, and in this context an allocation can be either a single or a dual allocation ๐Ÿ”‘

The authentication information (for example, username, password, realm, and nonce) is used both to verify subsequent requests and to compute the message integrity of responses ๐Ÿ” The username, realm, and nonce values are initially the ones used in the authenticated Allocate request that creates the allocation, though the server can change the nonce value during the lifetime of the allocation using a 438 (Stale Nonce) reply. For security reasons, the server MUST NOT store the password explicitly. It MUST store the key value instead, which is a cryptographic hash over the username, realm, and password (see Section 16.1.3 of [RFC8489]) ๐Ÿ™ˆ

Note that if the response contains a PASSWORD-ALGORITHMS attribute, and this attribute contains both MD5 and SHA-256 algorithms, and the client also supports both algorithms, then the request MUST contain a PASSWORD-ALGORITHM attribute with the SHA-256 algorithm ๐Ÿง

The time-to-expiry is the time in seconds left until the allocation expires. Each Allocate or Refresh transaction sets this timer, which then ticks down towards zero โณ By default, each Allocate or Refresh transaction resets this timer to the default lifetime value of 600 seconds (10 minutes), but the client can request a different value in the Allocate and Refresh request. Allocations can only be refreshed using the Refresh request. Sending data to a peer does NOT refresh an allocation, so don't be fooled bestie ๐Ÿ˜ญ When an allocation expires, the state data associated with it can be freed ๐Ÿ—‘๏ธ

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


7. Creating an Allocation ๐Ÿš€

An allocation on the server is created using an Allocate transaction โœจ

7.1. Sending an Allocate Request ๐Ÿ“จ

okay bestie, here's how the client builds an Allocate request ๐Ÿ’–

First, the client picks a host transport address. It is RECOMMENDED that the client pick a currently unused transport address, usually by letting the OS choose a port nobody else is using ๐ŸŒธ

Then it picks a transport protocol to use between itself and the server, based on which protocols the server supports. Since this spec only allows UDP between the server and the peers, it is RECOMMENDED that the client pick UDP unless it has a reason to use something else ๐Ÿฆ‹ One reason would be if the client believes, through configuration, discovery, or just trying it out, that it can't reach any TURN server over UDP. See Section 3.1 for more on that.

The client also picks a server transport address, and it SHOULD do this part like so โœจ It uses one or more procedures described in [RFC8155] to discover a TURN server, then uses the TURN server resolution mechanism defined in [RFC5928] and [RFC7350] to get a list of server transport addresses that can be tried to create a TURN allocation.

The client MUST include a REQUESTED-TRANSPORT attribute in the request. This attribute says which transport protocol to use between the server and the peers. (Note that this is not the transport protocol that shows up in the 5-tuple, so don't mix them up ๐Ÿ™ˆ) In this specification, the REQUESTED-TRANSPORT type is always UDP. The attribute is only there so future extensions can name other protocols ๐Ÿงš

If the client wants a relayed transport address of a specific address type, it includes a REQUESTED-ADDRESS-FAMILY attribute in the request. This tells the TURN server which address type the client wants it to allocate. Clients MUST NOT include more than one REQUESTED-ADDRESS-FAMILY attribute in an Allocate request. Clients MUST NOT include a REQUESTED-ADDRESS-FAMILY attribute in an Allocate request that contains a RESERVATION-TOKEN attribute. The reason is that the server uses the previously reserved transport address tied to the token, so the client can't get a relayed transport address of a specific address type in that case ๐Ÿ’…

If the client wants one IPv6 and one IPv4 relayed transport address, it includes an ADDITIONAL-ADDRESS-FAMILY attribute in the request. This says the server must allocate both address types ๐Ÿ‘‘ The attribute value in the ADDITIONAL-ADDRESS-FAMILY MUST be set to 0x02 (IPv6 address family). Clients MUST NOT include REQUESTED-ADDRESS-FAMILY and ADDITIONAL-ADDRESS-FAMILY attributes in the same request. Clients MUST NOT include the ADDITIONAL-ADDRESS-FAMILY attribute in an Allocate request that contains a RESERVATION-TOKEN attribute. Clients MUST NOT include the ADDITIONAL-ADDRESS-FAMILY attribute in an Allocate request that contains an EVEN-PORT attribute with the R (Reserved) bit set to 1. The reason for that last one: if EVEN-PORT with the R bit set to 1 were allowed alongside ADDITIONAL-ADDRESS-FAMILY, the success response would need two tokens, and the way RESERVATION-TOKEN gets handled would have to change. Too much drama ๐Ÿ˜ญ

If the client wants the server to set the time-to-expiry of the allocation to something other than the default lifetime, it MAY include a LIFETIME attribute with its desired value. This is just a hint, so the server can pick a different value. Also, the server will ignore any request to set it to less than the default value ๐Ÿซถ

If the client plans to use the DONT-FRAGMENT attribute in one or more Send indications on this allocation later, it SHOULD include the DONT-FRAGMENT attribute in the Allocate request. That way it can test whether the server supports this attribute โœจ

If the client needs the port number of the relayed transport address to be even, it includes the EVEN-PORT attribute. If that attribute isn't included, the port can be even or odd. Setting the R bit in EVEN-PORT to 1 lets the client ask the server to reserve the next highest port number (on the same IP address) for a later allocation. If the R bit is 0, no such request is made ๐ŸŽ€

The client MAY also include a RESERVATION-TOKEN attribute in the request to ask the server to use a port it reserved earlier for this allocation. If the RESERVATION-TOKEN attribute is included, then the client MUST omit the EVEN-PORT attribute ๐Ÿฆ‹

Once it's all built, the client sends the Allocate request on the 5-tuple ๐Ÿš€


7.2. Receiving an Allocate Request ๐Ÿ”

okay so when the server gets an Allocate request, it runs through a bunch of checks, like a bouncer at the club ๐Ÿชฉ

  1. The TURN server provided by the local or access network MAY allow an unauthenticated request, so it can accept Allocation requests from new or guest users on the network who don't have long-term credentials for STUN authentication. The security implications of STUN and making STUN authentication optional are covered in [RFC8155]. Otherwise, the server MUST require that the request be authenticated. If the request is authenticated, the authentication MUST be done either with the long-term credential mechanism of [RFC8489] or with the STUN Extension for Third-Party Authorization [RFC7635], unless the client and server agree to use another mechanism through some procedure outside the scope of this document ๐Ÿ”
  2. The server checks if the 5-tuple is already in use by an existing allocation. If yes, the server rejects the request with a 437 (Allocation Mismatch) error ๐Ÿ™…โ€โ™€๏ธ
  3. The server checks if the request contains a REQUESTED-TRANSPORT attribute. If the REQUESTED-TRANSPORT attribute is missing or malformed, the server rejects the request with a 400 (Bad Request) error. Otherwise, if the attribute is there but names a protocol the server doesn't support, the server rejects the request with a 442 (Unsupported Transport Protocol) error ๐Ÿ’€
  4. The request may contain a DONT-FRAGMENT attribute. If it does, but the server doesn't support sending UDP datagrams with the DF bit set to 1 (see Sections 14 and 15), then the server treats 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, REQUESTED-ADDRESS-FAMILY, or ADDITIONAL-ADDRESS-FAMILY attribute, the server rejects the request with a 400 (Bad Request) error. Otherwise, it checks whether the token is valid (meaning the token is in range, hasn't expired, and the corresponding relayed transport address is still available). If the token isn't valid for some reason, the server rejects the request with a 508 (Insufficient Capacity) error ๐ŸŽŸ๏ธ
  6. The server checks if the request contains both REQUESTED-ADDRESS-FAMILY and ADDITIONAL-ADDRESS-FAMILY attributes. If yes, the server rejects the request with a 400 (Bad Request) error ๐Ÿ™ƒ
  7. If the server doesn't support the address family the client asked for in REQUESTED-ADDRESS-FAMILY, or if allocating that address family is turned off by local policy, it MUST generate an Allocate error response, and it MUST include an ERROR-CODE attribute with the 440 (Address Family not Supported) response code. If the REQUESTED-ADDRESS-FAMILY attribute is absent and the server doesn't support the IPv4 address family, the server MUST include an ERROR-CODE attribute with the 440 (Address Family not Supported) response code. If the REQUESTED-ADDRESS-FAMILY attribute is absent and the server does support the IPv4 address family, the server MUST allocate an IPv4 relayed transport address for the TURN client ๐ŸŒˆ
  8. The server checks if the request contains an EVEN-PORT attribute with the R bit set to 1. If yes, and the request also contains an ADDITIONAL-ADDRESS-FAMILY attribute, the server rejects the request with a 400 (Bad Request) error. Otherwise, the server checks whether it can satisfy the request (meaning it can allocate a relayed transport address as described below). If it can't, the server rejects the request with a 508 (Insufficient Capacity) error ๐Ÿ“
  9. The server checks if the request contains an ADDITIONAL-ADDRESS-FAMILY attribute. If yes, and the attribute value is 0x01 (IPv4 address family), the server rejects the request with a 400 (Bad Request) error. Otherwise, the server checks whether it can allocate relayed transport addresses of both address types. If it can't satisfy the request, the server rejects it with a 508 (Insufficient Capacity) error. If the server can only partly meet the request, meaning it can allocate just one relayed transport address of one specific address type, it includes an ADDRESS-ERROR-CODE attribute in the success response to tell the client why the request was only partly fulfilled. The error code value signaled in the ADDRESS-ERROR-CODE attribute could be 440 (Address Family not Supported) or 508 (Insufficient Capacity). If the server can fully meet the request, then it allocates one IPv4 and one IPv6 relay address and returns an Allocate success response containing the relayed transport addresses assigned to the dual allocation in two XOR-RELAYED-ADDRESS attributes ๐Ÿ‘ฏโ€โ™€๏ธ
  10. At any point, the server MAY choose to reject the request with a 486 (Allocation Quota Reached) error if it feels the client is trying to go over some locally defined allocation quota. The server is free to define this quota any way it likes, but it SHOULD define it based on the username used to authenticate the request, and not on the client's transport address ๐Ÿšซ
  11. Also, at any point, the server MAY choose to reject the request with a 300 (Try Alternate) error if it wants to redirect the client to a different server. The use of this error code and attribute follows the specification in [RFC8489] ๐Ÿ”€

If all the checks pass, the server creates the allocation โœจ The 5-tuple is set to the 5-tuple from the Allocate request, while the list of permissions and the list of channels both start out empty ๐Ÿฅฐ

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

  • If the request has a RESERVATION-TOKEN attribute, the server uses the previously reserved transport address that matches the token, as long as it's still available. โœจ The reservation is server-wide, not tied to one allocation, because the Allocate request carrying the RESERVATION-TOKEN uses a different 5-tuple than the request that made the reservation. That 5-tuple can be any allowed one: a different client IP address and port, a different transport protocol, or even a different server IP address and port (as long as that server address and port are ones where the server is listening for TURN requests) ๐Ÿฆ‹
  • If the request has an EVEN-PORT attribute with the R bit set to 0, the server allocates a relayed transport address with an even port number. ๐ŸŒธ
  • If the request has an EVEN-PORT attribute with the R bit set to 1, the server looks for a pair of port numbers N and N+1 on the same IP address, where N is even. Port N is used in the current allocation, and the relayed transport address with port N+1 gets a token and is reserved for a future allocation. The server MUST hold this reservation for at least 30 seconds and MAY choose to hold longer (for example, until the allocation with port N expires). Then the server puts the token in a RESERVATION-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 on the same host as the TURN server application won't be affected by allocating ports outside that range. This is often true when the TURN server runs on a dedicated machine, or when any other apps on the machine allocate their ports before the TURN server starts. Either way, the TURN server SHOULD NOT allocate ports in the range 0 - 1023 (the Well-Known Port range), to discourage clients from using TURN to run standard services. ๐Ÿ™ˆ

NOTE: The use of randomized port assignments to avoid certain types of attacks is described in [RFC6056]. It is RECOMMENDED that a TURN server implement a randomized port assignment algorithm from [RFC6056]. This is especially applicable to servers that choose to pre-allocate a number of ports from the underlying OS and then later assign them to allocations; for example, a server may choose this technique to implement the EVEN-PORT attribute. ๐Ÿ”

The server works out the starting value of the time-to-expiry field like this. If the request has a LIFETIME attribute, the server computes the minimum of the client's proposed lifetime and the server's maximum allowed lifetime. If that computed value is greater than the default lifetime, the server uses the computed lifetime as the starting value of the time-to-expiry field. Otherwise, the server uses the default lifetime. It is RECOMMENDED that the server use a maximum allowed lifetime value of no more than 3600 seconds (1 hour). Servers that implement allocation quotas or charge users for allocations in some way may want a smaller maximum allowed lifetime (maybe as small as the default lifetime), so they can clear out orphaned allocations faster. Orphaned allocations are ones where the client has crashed or terminated, or the client connection has been lost for some reason. Also, the time-to-expiry gets recomputed with each successful Refresh request, so the value computed here only applies until the first refresh. โณ

Once the allocation is created, the server sends back a success response. The success response contains:

  • An XOR-RELAYED-ADDRESS attribute containing the relayed transport address, or two XOR-RELAYED-ADDRESS attributes containing the relayed transport addresses. ๐Ÿฆ‹
  • 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 doesn't use this value, but clients running ICE often need it, so they can skip doing an extra Binding transaction with some STUN server to find it out. ๐Ÿงš

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

NOTE: When the Allocate request is sent over UDP, [RFC8489] requires that the server handle the possible retransmissions of the request, so retransmissions don't cause multiple allocations to be created. Implementations may do this using the so-called "stateless stack approach" as follows. To detect retransmissions when the original request was successful in creating an allocation, the server can store the transaction id that created the request with the allocation data, and compare it with incoming Allocate requests on the same 5-tuple. Once such a request is detected, the server can stop parsing the request and immediately generate a success response. When building this response, the value of 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 it can be returned in any retransmitted responses. For the case where the original request was unsuccessful in creating an allocation, the server may choose to do nothing special. Note, however, that there is a rare case where the server rejects the original request but accepts the retransmitted request (because conditions have changed in the brief time in between). If the client receives the first failure response, it will ignore the second (success) response and believe that an allocation was not created. An allocation created in this manner will eventually time out, since the client won't refresh it. Furthermore, if the client later retries with the same 5-tuple but a different transaction id, it will receive a 437 (Allocation Mismatch) error response, which will cause it to retry with a different 5-tuple. The server may use a smaller maximum lifetime value to minimize the lifetime of allocations "orphaned" in this manner. ๐Ÿ˜ญ

7.3. Receiving an Allocate Success Response

If the client receives an Allocate success response, then it MUST check that the mapped address and the relayed transport address or addresses are part of an address family or families that the client understands and is prepared to handle. If these addresses aren't part of an address family or families the client is prepared to handle, then the client MUST delete the allocation (Section 8) and MUST NOT attempt to create another allocation on that server until it believes the mismatch has been fixed. ๐Ÿšจ

Otherwise, the client creates its own copy of the allocation data structure to track what's happening on the server. In particular, the client needs to remember the actual lifetime received back from the server, rather than the value it sent in the request. The client must also remember the 5-tuple used for the request, and the username and password it used to authenticate the request, so it reuses them for subsequent messages. The client also needs to track the channels and permissions it sets up on the server. ๐Ÿ—‚๏ธ

If the client receives an Allocate success response but with an ADDRESS-ERROR-CODE attribute in the response, and the error code value in that attribute is 440 (Address Family not Supported), the client MUST NOT retry its request for the rejected address type. If the client receives an ADDRESS-ERROR-CODE attribute in the response, and the error code value in it is 508 (Insufficient Capacity), the client SHOULD wait at least 1 minute before trying to request any more allocations on this server for the rejected address type. โธ๏ธ

The client will probably want to send the relayed transport address to peers (using some method not specified here), so the peers can communicate with it. ๐Ÿ’Œ The client may also want to use the server-reflexive address it gets in the XOR-MAPPED-ADDRESS attribute in its ICE processing. โœจ

7.4. Receiving an Allocate Error Response ๐Ÿšจ

okay so this is the part where the server says "no bestie" and we have to figure out what to do next ๐Ÿ’€ the vibe is totally different for every error code, so let's go one by one ๐Ÿ’…

If the client gets an Allocate error response, what it does next depends on the exact error code it got back:

408 (Request timed out): ugh, the server is either having a moment or the client can't reach it over the transport it picked ๐Ÿ˜ญ the client calls this transaction a fail, BUT it MAY totally try the Allocate request again over a different transport (like TCP instead of UDP) ๐Ÿฆ‹

300 (Try Alternate): the server is basically like "hey, go ask THIS other server instead" ๐Ÿงš the client calls the current transaction a fail, but it SHOULD try the Allocate request with the alternate server before trying any other servers (like the ones found through DNS resolution procedures) โœจ when it does, it follows the ALTERNATE-SERVER procedures from [RFC8489] ๐ŸŒธ

400 (Bad Request): the server thinks the request is malformed, rude ๐Ÿ™„ the client calls the transaction a fail. The client MAY tell the user or operator, and it SHOULD NOT retry with this server until it believes the problem has been fixed ๐Ÿ›‘

401 (Unauthorized): okay so if the client already followed the long-term credential mechanism and STILL gets this, the server is straight up not accepting its credentials ๐Ÿ’€ the client calls the transaction a fail and SHOULD notify the user or operator ๐Ÿ“ฃ it SHOULD NOT send any more requests to this server until it believes the problem is fixed ๐Ÿ”’

403 (Forbidden): the request is valid, but the server is refusing to do it, probably because of admin restrictions ๐Ÿ™…โ€โ™€๏ธ the client calls the transaction a fail. It MAY notify the user or operator and SHOULD NOT retry the same request with this server until the problem is fixed ๐Ÿ’œ

420 (Unknown Attribute): so the client put a DONT-FRAGMENT attribute in the request, and the server said "idk what that is" and listed DONT-FRAGMENT in the UNKNOWN-ATTRIBUTES attribute ๐Ÿคทโ€โ™€๏ธ now the client knows this server doesn't support DONT-FRAGMENT ๐Ÿซถ the client calls the transaction a fail, but it MAY retry the Allocate request without the DONT-FRAGMENT attribute ๐ŸŽ€

437 (Allocation Mismatch): this one is giving "that 5-tuple is already taken" ๐Ÿ‘€ one way this happens is if a NAT gave out a mapped transport address that was used by another client that recently crashed ๐Ÿ’€ the client calls the transaction a fail and SHOULD pick another client transport address and retry the Allocate request (with a different transaction id) ๐ŸŒˆ it SHOULD try three different client transport addresses before giving up on this server ๐Ÿ™ˆ once it gives up, it SHOULD NOT try to create another allocation on the server for 2 minutes โฐ

438 (Stale Nonce): the nonce is expired, so go check the long-term credential mechanism procedures in [RFC8489] ๐Ÿ’…

440 (Address Family not Supported): the server doesn't support the address family the client asked for ๐Ÿ˜ค if the client gets this, it MUST NOT retry the request. Period. ๐Ÿ›‘๐Ÿ‘‘

441 (Wrong Credentials): the client shouldn't ever get this one for an Allocate request, weird ๐Ÿคจ the client MAY notify the user or operator and SHOULD NOT retry the same request with this server until the problem is fixed ๐Ÿ”ง

442 (Unsupported Transport Address): the client shouldn't get this for a UDP allocation request either ๐Ÿ™ƒ the client MAY notify the user or operator and SHOULD NOT reattempt the request with this server until it believes the problem is fixed ๐Ÿ› ๏ธ

486 (Allocation Quota Reached): the server is too full right now and can't make any more allocations with this username ๐Ÿ˜ฉ the client calls the transaction a fail and SHOULD wait at least 1 minute before trying to make more allocations on the server โณ

508 (Insufficient Capacity): the server has no relayed transport addresses left, or none with the properties the client wants, or the one that got reserved isn't available anymore ๐Ÿ˜ต the client calls the current operation a fail. If the client is using the EVEN-PORT or RESERVATION-TOKEN attribute, it MAY remove or change that attribute and try again right away ๐Ÿƒโ€โ™€๏ธ otherwise it SHOULD wait at least 1 minute before trying to make more allocations on this server ๐Ÿ•

Note that the error code values 486 and 508 tell an eavesdropper that a bunch of other users are on the server right now, kind of like the HTTP 503 response code ๐Ÿ‘€ but they don't reveal anything about who those users actually are ๐Ÿซฃ

An unknown error response MUST be handled as described in [RFC8489]. ๐Ÿ“–

  1. Refreshing an Allocation โœจ

okay this section is all about the Refresh transaction ๐ŸŽ€ it can do one of two things: (a) refresh an existing allocation and update its time-to-expiry, or (b) delete an existing allocation ๐Ÿ’–

If a client wants to keep using an allocation, it MUST refresh it before it expires ๐Ÿ˜ฑ It is suggested that the client refresh roughly 1 minute before expiry ๐Ÿ•‘ If a client is done with an allocation, it SHOULD explicitly delete it ๐Ÿงน A client MAY refresh an allocation at any time for other reasons ๐ŸŒธ

8.1. Sending a Refresh Request ๐Ÿ“ค

If the client wants to delete an allocation right now, it includes a LIFETIME attribute with a value of zero ๐Ÿ’€ every other form of the request refreshes the allocation ๐Ÿ”„

When refreshing a dual allocation, the client includes a REQUESTED-ADDRESS-FAMILY attribute for the address family type that should be refreshed ๐ŸŒˆ If there's no REQUESTED-ADDRESS-FAMILY attribute, the request should be treated as applying to all current allocations ๐Ÿซถ The client MUST only include a family type it previously allocated and hasn't deleted yet ๐Ÿ™…โ€โ™€๏ธ You can also delete just one allocation type by setting that Refresh request's lifetime to zero ๐Ÿ’… Deleting a single allocation destroys any permissions or channels tied to that particular allocation, and it MUST NOT affect any permissions or channels tied to allocations for the other address family ๐Ÿฆ‹

The Refresh transaction updates the time-to-expiry timer of an allocation โฐ If the client wants the server to set the timer to something other than the default lifetime, it includes a LIFETIME attribute with the requested value ๐Ÿ’– The server then computes a new time-to-expiry value the same way it does for an Allocate transaction, except that a requested lifetime of zero makes the server delete the allocation right away ๐Ÿ’€

8.2. Receiving a Refresh Request ๐Ÿ“ฅ

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

If the server gets a Refresh request with a REQUESTED-ADDRESS-FAMILY attribute and the attribute value doesn't match the address family of the allocation, the server MUST reply with a 443 (Peer Address Family Mismatch) Refresh error response ๐Ÿšซ

The server computes a value called the "desired lifetime" like this: if the request has a LIFETIME attribute and its value is zero, then the "desired lifetime" is zero ๐Ÿซ  Otherwise, if the request has a LIFETIME attribute, the server computes the minimum of the client's requested lifetime and the server's maximum allowed lifetime โš–๏ธ If that computed value is greater than the default lifetime, then the "desired lifetime" is the computed value ๐Ÿ“ˆ Otherwise, the "desired lifetime" is the default lifetime ๐ŸŽฏ

What happens next depends on the "desired lifetime" value:

  • If the "desired lifetime" is zero, then the request succeeds and the allocation is deleted ๐Ÿ’€๐Ÿ—‘๏ธ
  • If the "desired lifetime" is non-zero, then the request succeeds and the allocation's time-to-expiry is set to the "desired lifetime" โณโœจ

If the request succeeds, the server sends a success response containing:

  • A LIFETIME attribute containing the current value of the time-to-expiry timer ๐ŸŽ€
NOTE: A server doesn't need to do anything special to make Refresh requests idempotent over UDP using the "stateless stack approach" ๐Ÿงš Retransmitted Refresh requests with a non-zero "desired lifetime" will just refresh the allocation ๐Ÿ”„ A retransmitted Refresh request with a zero "desired lifetime" will cause a 437 (Allocation Mismatch) response if the allocation has already been deleted, but the client will treat this as equivalent to a success response (see below) ๐Ÿ’…

8.3. Receiving a Refresh Response ๐Ÿ“ฌ

If the client gets a success response to its Refresh request with a non-zero lifetime, it updates its copy of the allocation data structure with the time-to-expiry value in the response โœ… If the client gets a 437 (Allocation Mismatch) error response to its request to refresh the allocation, it SHOULD consider the allocation no longer exists ๐Ÿ‘ป If the client gets a 438 (Stale Nonce) error to its request to refresh the allocation, it SHOULD reattempt the request with the new nonce value ๐Ÿ”

If the client gets a 437 (Allocation Mismatch) error response to a request to delete the allocation, then the allocation no longer exists and it SHOULD consider its request as having effectively succeeded ๐Ÿฅณ๐Ÿ’–

9. Permissions โœจ

Okay bestie, so here's the permission system, and it's giving bouncer at the club ๐Ÿ’… For each allocation, the server keeps a list of zero or more permissions. Each permission is made of an IP address plus a time-to-expiry. While a permission exists, every peer using that IP address is allowed to send data to the client ๐Ÿฆ‹ The time-to-expiry is just the number of seconds left until the permission expires. Within an allocation, a permission is uniquely identified by its IP address, so no duplicates, periodt ๐Ÿซถ

The client can make the server install or refresh a permission for an IP address by sending either CreatePermission requests or ChannelBind requests ๐ŸŽ€ This can go one of two ways:

  • If there's no permission for that IP address yet, a permission gets created with that IP address and a time-to-expiry equal to Permission Lifetime.
  • If a permission for that IP address already exists, its time-to-expiry gets reset to Permission Lifetime.

The Permission Lifetime MUST be 300 seconds (= 5 minutes) โฐ

Each permission's time-to-expiry ticks down once per second until it hits zero. At that point the permission expires and gets deleted ๐Ÿ’€

CreatePermission and ChannelBind requests can be freely intermixed on a permission ๐ŸŒˆ A permission might get installed and/or refreshed with a CreatePermission request and then later refreshed with a ChannelBind request, or the other way around. Totally valid, no cap โœจ

Here's how incoming traffic gets checked ๐Ÿ‘€ When a UDP datagram arrives at the relayed transport address for the allocation, the server pulls the source IP address out of the IP header. Then it compares that address with the IP address tied to each permission in the allocation's list. Only the addresses are compared, port numbers are not considered at all ๐Ÿ™ˆ If there's no match, relaying is not permitted and the server silently discards the UDP datagram. If there's an exact match, the permission check counts as passed and the server keeps processing the datagram as specified elsewhere (Section 11.3).

Permissions for one allocation are totally unrelated to permissions for a different allocation, so they don't cross over ๐Ÿงš And if an allocation expires, all of its permissions expire right along with it ๐Ÿ˜ญ

NOTE: Though TURN permissions expire after 5 minutes, many NATs deployed at the time of publication expire their UDP bindings considerably faster. Thus, an application using TURN will probably wish to send some sort of keep-alive traffic at a much faster rate. Applications using ICE should follow the keep-alive guidelines of ICE [RFC8445], and applications not using ICE are advised to do something similar. ๐ŸŒธ

10. CreatePermission โœจ

Bestie, this section covers one of the two ways the client can install or refresh permissions on the server. This section describes one way: the CreatePermission request ๐Ÿ’–

A CreatePermission request may be used together with either the Send mechanism in Section 11 or the Channel mechanism in Section 12 ๐Ÿฆ‹

10.1. Forming a CreatePermission Request

The client who wants to install or refresh one or more permissions can send a CreatePermission request to the server ๐ŸŽ€

When forming a CreatePermission request, the client MUST include at least one XOR-PEER-ADDRESS attribute and MAY include more than one such attribute. The IP address portion of each XOR-PEER-ADDRESS attribute holds the IP address that should get a permission installed or refreshed. The port portion of each XOR-PEER-ADDRESS attribute will be ignored, so it can be any arbitrary value ๐Ÿ™ˆ The various XOR-PEER-ADDRESS attributes MAY appear in any order. The client MUST only include XOR-PEER-ADDRESS attributes with addresses of the same address family as the relayed transport address for the allocation. For dual allocations obtained using the ADDITIONAL-ADDRESS-FAMILY attribute, the client MAY include XOR-PEER-ADDRESS attributes with addresses of IPv4 and IPv6 address families ๐ŸŒˆ

10.2. Receiving a CreatePermission Request

When the server gets a CreatePermission request, it processes it as per Section 5 plus the specific rules mentioned here โœจ

The message gets checked for validity first. The CreatePermission request MUST contain at least one XOR-PEER-ADDRESS attribute and MAY contain multiple such attributes. If no such attribute exists, or if any of these attributes are invalid, a 400 (Bad Request) error is returned. If the request is valid but the server can't satisfy it because of some capacity limit or similar, a 508 (Insufficient Capacity) error is returned ๐Ÿ’€

If an XOR-PEER-ADDRESS attribute contains an address of an address family that's not the same as the relayed transport address's family for the allocation, the server MUST generate an error response with the 443 (Peer Address Family Mismatch) response code ๐Ÿ™…โ€โ™€๏ธ

The server MAY impose restrictions on the IP address allowed in the XOR-PEER-ADDRESS attribute. If a value isn't allowed, the server rejects the request with a 403 (Forbidden) error ๐Ÿ”ฅ

If the message is valid and the server is capable of carrying out the request, the server installs or refreshes a permission for the IP address in each XOR-PEER-ADDRESS attribute, as described in Section 9. The port portion of each attribute is ignored and may be any arbitrary value ๐Ÿซถ

Then the server responds with a CreatePermission success response. There are no mandatory attributes in the success response ๐Ÿ’…

NOTE: A server need not do anything special to implement idempotency of CreatePermission requests over UDP using the "stateless stack approach". Retransmitted CreatePermission requests will simply refresh the permissions. ๐Ÿ”

10.3. Receiving a CreatePermission Response

If the client receives a valid CreatePermission success response, it updates its data structures to indicate that the permissions have been installed or refreshed ๐ŸŒธ

11. Send and Data Methods ๐Ÿ’œ

TURN supports two mechanisms for sending and receiving data from peers. This section describes the use of the Send and Data mechanisms, while Section 12 describes the use of the Channel mechanism ๐Ÿฆ‹

11.1. Forming a Send Indication

The client can use a Send indication to pass data to the server for relaying to a peer. A client may use a Send indication even if a channel is bound to that peer. However, the client MUST ensure that there is a permission installed for the IP address of the peer that the Send indication is being sent to. This stops a third party from using a TURN server to send data to arbitrary destinations ๐Ÿšซ

When forming a Send indication, the client MUST include an XOR-PEER-ADDRESS attribute and a DATA attribute. The XOR-PEER-ADDRESS attribute contains the transport address of the peer the data is going to, and the DATA attribute contains the actual application data to send to that peer ๐Ÿ“ฆ

The client MAY include a DONT-FRAGMENT attribute in the Send indication if it wants the server to set the DF bit on the UDP datagram sent to the peer ๐ŸŽ€

11.2. Receiving a Send Indication

When the server receives a Send indication, it processes it as per Section 5 plus the specific rules mentioned here ๐Ÿ’–

The message is checked for validity first. The Send indication MUST contain both an XOR-PEER-ADDRESS attribute and a DATA attribute. If one of these attributes is missing or invalid, the message is discarded. Note that the DATA attribute is allowed to contain zero bytes of data ๐Ÿ“

The Send indication may also contain the DONT-FRAGMENT attribute. If the server is unable to set the DF bit on outgoing UDP datagrams when this attribute is present, then the server acts as if the DONT-FRAGMENT attribute is an unknown comprehension-required attribute (and thus the Send indication is discarded) ๐Ÿ™ƒ

The server also checks that there is a permission installed for the IP address in the XOR-PEER-ADDRESS attribute. If no such permission exists, the message is discarded. Note that a Send indication never causes the server to refresh the permission โณ

The server MAY impose restrictions on the IP address and port values allowed in the XOR-PEER-ADDRESS attribute. If a value isn't allowed, the server silently discards the Send indication ๐Ÿคซ

If everything is OK, the server forms a UDP datagram as follows:

  • the source transport address is the relayed transport address of the allocation, where the allocation is determined by the 5-tuple on which the Send indication arrived;
  • the destination transport address is taken from the XOR-PEER-ADDRESS attribute;
  • the data following the UDP header is the contents of the value field of the DATA attribute.

The handling of the DONT-FRAGMENT attribute (if present) is described in Sections 14 and 15 ๐Ÿงš

The resulting UDP datagram is then sent to the peer ๐Ÿฆ‹

11.3. Receiving a UDP Datagram

When the server receives a UDP datagram at a currently allocated relayed transport address, it looks up the allocation associated with that relayed transport address. The server then checks whether the set of permissions for the allocation allows relaying the UDP datagram, as described in Section 9 ๐Ÿ‘€

If relaying is permitted, the server checks whether there is a channel bound to the peer that sent the UDP datagram (see Section 12). If a channel is bound, processing proceeds as described in Section 12.7 ๐ŸŒˆ

If relaying is permitted but no channel is bound to the peer, the server forms and sends a Data indication. The Data indication MUST contain both an XOR-PEER-ADDRESS and a DATA attribute. The DATA attribute is set to the value of the "data octets" field from the datagram, and the XOR-PEER-ADDRESS attribute is set to the source transport address of the received UDP datagram. The Data indication is then sent on the 5-tuple associated with the allocation ๐Ÿ“จ

11.4. Receiving a Data Indication

When the client receives a Data indication, it checks that the Data indication contains an XOR-PEER-ADDRESS attribute and discards the indication if it doesn't. The client SHOULD also check that the XOR-PEER-ADDRESS attribute value contains an IP address with which the client believes there is an active permission, and discard the Data indication otherwise ๐Ÿ›ก๏ธ

NOTE: The latter check protects the client against an attacker who somehow manages to trick the server into installing permissions not desired by the client. ๐Ÿšจ

If the XOR-PEER-ADDRESS is present and valid, the client checks that the Data indication contains either a DATA attribute or an ICMP attribute, and discards the indication if it doesn't. Note that a DATA attribute is allowed to contain zero bytes of data. Processing of Data indications with an ICMP attribute is described in Section 11.6 ๐Ÿ’ซ

If the Data indication passes the above checks, the client delivers the data octets inside the DATA attribute to the application, along with an indication that they were received from the peer whose transport address is given by the XOR-PEER-ADDRESS attribute ๐ŸŽ‰

11.5. Receiving an ICMP Packet โœจ

okay so when the server gets an ICMP packet, it first has to check two things ๐Ÿ‘€. The type has to be 3 or 11 for an ICMPv4 [RFC0792] packet, or 1, 2, or 3 for an ICMPv6 [RFC4443] packet. It also has to make sure the IP packet inside the ICMP payload has a UDP header. If either of those fails, the packet is silently dropped ๐Ÿซฅ. If the UDP header is there, the server pulls out the source and destination IP address and UDP port info.

Next, the server looks for the allocation whose relayed transport address matches the encapsulated packet's source IP address and UDP port. No match? Silently dropped, bye ๐Ÿ‘‹. If there is one, the server checks whether that allocation's permissions allow relaying this ICMP packet. Here's the twist ๐ŸŒ€: for ICMP packets, the source IP address MUST NOT be checked against the permissions list the way it would be for UDP packets. Instead, the server grabs the destination IP address from the encapsulated IP header and compares it to the IP address of each permission on the allocation. No match means relaying isn't permitted, and the server silently discards the ICMP packet. Also, only addresses get compared. Port numbers don't count here ๐Ÿ’….

If relaying is permitted, the server forms and sends a Data indication. This indication MUST contain both an XOR-PEER-ADDRESS and an ICMP attribute. The ICMP attribute gets set to the type and code field values from the ICMP packet. The IP address part of XOR-PEER-ADDRESS is set to the destination IP address in the encapsulated IP header. Now, at the time this spec was written, socket APIs on some operating systems don't hand the destination port in the encapsulated UDP header to apps without superuser privileges ๐Ÿ˜ญ. So if the server can see that destination port, the port part of XOR-PEER-ADDRESS gets set to it. If not, the port part is set to zero. Finally, the Data indication gets sent on the 5-tuple tied to the allocation ๐Ÿš€.

๐Ÿซถ Implementation Note: New ICMP types or codes can be defined in future specifications. If the server receives an ICMP error packet, and the new type or code field can help the client make use of the ICMP error notification and generate feedback to the application layer, the server sends the Data indication with an ICMP attribute conveying the new ICMP type or code.

11.6. Receiving a Data Indication with an ICMP Attribute ๐ŸŽ€

when the client gets a Data indication carrying an ICMP attribute, it first checks that the indication has an XOR-PEER-ADDRESS attribute. No XOR-PEER-ADDRESS? The client discards the indication. The client SHOULD also check that the IP address in the XOR-PEER-ADDRESS value has an active permission, and discard the Data indication if it doesn't ๐Ÿ”’.

If the Data indication passes those checks, the client tells the application about the error condition ๐Ÿšจ. It also says the error came from the peer whose transport address is in the XOR-PEER-ADDRESS attribute. The app can figure out what the type and code values in the ICMP attribute mean by looking at the family field in XOR-PEER-ADDRESS ๐Ÿง .

12. Channels ๐Ÿฆ‹

Channels are a way for the client and server to send application data using ChannelData messages, which have way less overhead than Send and Data indications. Lowkey the glow-up you want ๐Ÿ’–.

The ChannelData message (see Section 12.4) starts with a two-byte field that carries the channel number. Here's how the values of that field get allocated ๐ŸŒˆ:

  +------------------------+--------------------------------------+
  | 0x0000 through 0x3FFF: | These values can never be used for   |
  |                        | channel numbers.                     |
  +------------------------+--------------------------------------+
  | 0x4000 through 0x4FFF: | These values are the allowed channel |
  |                        | numbers (4096 possible values).      |
  +------------------------+--------------------------------------+
  | 0x5000 through 0xFFFF: | Reserved (For DTLS-SRTP multiplexing |
  |                        | collision avoidance, see [RFC7983]). |
  +------------------------+--------------------------------------+

                               Table 2

Note that the channel number range is not backwards compatible with [RFC5766]. That could block a client that follows RFC 5766 from setting up channel bindings with a TURN server that follows this spec ๐Ÿ™ˆ.

According to [RFC7983], you can tell ChannelData messages apart from other multiplexed protocols by looking at the first byte of the message ๐Ÿ”:

+------------+------------------------------------------------------+
| [0..3]     |                         STUN                         |
+------------+------------------------------------------------------+
| [16..19]   |                         ZRTP                         |
+------------+------------------------------------------------------+
| [20..63]   |                         DTLS                         |
+------------+------------------------------------------------------+
| [64..79]   |                     TURN Channel                     |
+------------+------------------------------------------------------+
| [128..191] |                       RTP/RTCP                       |
+------------+------------------------------------------------------+
| Others     |              Reserved; MUST be dropped               |
|            |              and an alert MAY be logged              |
+------------+------------------------------------------------------+

                               Table 3

Reserved values might get used by other protocols in the future ๐Ÿ”ฎ. When the client uses channel binding, it MUST comply with the demultiplexing scheme we just talked about.

Channel bindings are always started by the client ๐Ÿ™Œ. The client can bind a channel to a peer at any time during the allocation's lifetime. It can bind before exchanging data with that peer, or after trading some data with it (using Send and Data indications) for a while. It can also just never bind a channel to that peer, totally valid. And it can bind channels to some peers while skipping others ๐Ÿ’….

Channel bindings are specific to an allocation. So using a channel number or peer transport address in one allocation has zero impact on using it in a different one โœจ. If an allocation expires, all of its channel bindings expire with it.

A channel binding has three parts:

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

Inside an allocation, a channel binding is uniquely identified by either its channel number or the peer's transport address. So the same channel can't be bound to two different transport addresses, and the same transport address can't be bound to two different channels ๐Ÿ™…โ€โ™€๏ธ.

A channel binding lasts 10 minutes unless it gets refreshed. Refreshing means the server receives a ChannelBind request that rebinds the channel to the same peer, and that resets the time-to-expiry timer back to 10 minutes โฐ.

When a channel binding expires, the channel becomes unbound ๐Ÿ˜Œ. Once it's unbound, the channel number can be bound to a different transport address, and the transport address can be bound to a different channel number. To avoid race conditions, the client MUST wait 5 minutes after the binding expires before it tries to bind the channel number to a different transport address, or the transport address to a different channel number. Patience is a whole vibe ๐Ÿง˜โ€โ™€๏ธ.

When the client binds a channel to a peer, it SHOULD be ready to receive ChannelData messages on that channel from the server as soon as it has sent the ChannelBind request. Over UDP, the client can even get ChannelData messages from the server before it gets a ChannelBind success response ๐Ÿ“ฌ.

Going the other way, the client MAY choose to send ChannelData messages before it gets the ChannelBind success response. But that's risky ๐Ÿ˜ฌ. If the ChannelBind request doesn't succeed for some reason (like a packet getting lost if the request went over UDP, or the server being unable to fulfill the request), the server might drop those ChannelData messages. A client that wants to play it safe should either queue the data or use Send indications until the channel binding is confirmed ๐Ÿ›ก๏ธ.

12.1. Sending a ChannelBind Request ๐Ÿ’Œ

A channel binding gets created or refreshed using a ChannelBind transaction. A ChannelBind transaction also creates or refreshes a permission towards the peer (see Section 9) ๐Ÿ”.

To kick off the ChannelBind transaction, the client forms a ChannelBind request. The channel to be bound goes in a CHANNEL-NUMBER attribute, and the peer's transport address goes in an XOR-PEER-ADDRESS attribute. Section 12.2 explains the restrictions on these attributes ๐Ÿ“‹. The client MUST only include an XOR-PEER-ADDRESS attribute with an address from the same address family as the relayed transport address for the allocation. No mixing families, bestie ๐Ÿ™…โ€โ™€๏ธ.

Rebinding a channel to the same transport address it's already bound to is a way to refresh both the channel binding and the matching permission, and you don't have to send any data to the peer to do it ๐ŸŒธ. Just keep in mind that permissions need refreshing more often than channels do โš ๏ธ.

12.2. Receiving a ChannelBind Request โœจ

okay so when the server gets a ChannelBind request, it runs through everything in Section 5 first, plus the extra rules I'm about to spill ๐Ÿ’…

The server checks these things:

  • the request has both a CHANNEL-NUMBER and an XOR-PEER-ADDRESS attribute ๐ŸŽ€
  • the channel number sits somewhere in 0x4000 through 0x4FFF (inclusive) ๐Ÿฆ‹
  • the channel number isn't already bound to a different transport address (the same transport address is totally fine ๐Ÿซถ)
  • the transport address isn't already bound to a different channel number

If any of those fail, the server replies with a 400 (Bad Request) error. If the XOR-PEER-ADDRESS attribute has an address family that doesn't match the relayed transport address for the allocation, the server MUST generate an error response with the 443 (Peer Address Family Mismatch) response code. not the vibe ๐Ÿ’€

The server MAY put limits on the IP address and port values allowed in XOR-PEER-ADDRESS. If a value isn't allowed, the server rejects the request with a 403 (Forbidden) error ๐Ÿ™ˆ

If the request is valid but the server can't handle it because of a capacity limit or something similar, it replies with a 508 (Insufficient Capacity) error.

Otherwise, the server sends back a ChannelBind success response. A successful ChannelBind response has no required attributes, so it's giving minimalism ๐ŸŒธ

When the server can satisfy the request, it creates or refreshes the channel binding using the channel number in CHANNEL-NUMBER and the transport address in XOR-PEER-ADDRESS. It also installs or refreshes a permission for the IP address in XOR-PEER-ADDRESS, as described in Section 9 โœจ

NOTE: A server doesn't need to do anything special to make ChannelBind requests idempotent over UDP using the "stateless stack approach." ๐Ÿงš Retransmitted ChannelBind requests just refresh the channel binding and the matching permission. Also, the client must wait 5 minutes before binding a channel number or peer address that was previously bound to a different channel. That way, a transaction can't fail at first and then succeed on a retransmission. iykyk ๐Ÿ™ˆ

12.3. Receiving a ChannelBind Response ๐ŸŒˆ

When the client gets a ChannelBind success response, it updates its data structures to say the channel binding is now active. It also records that the matching permission has been installed or refreshed. so organized ๐Ÿ“

If the client gets a ChannelBind failure response that says the channel info is out of sync between client and server (like an unexpected 400 "Bad Request" response), then it is RECOMMENDED that the client immediately delete the allocation and start fresh with a new one. bestie, that's a hard reset, and it's honestly the healthiest move ๐Ÿซถ

12.4. The ChannelData Message ๐Ÿฆ‹

The ChannelData message carries application data between the client and the server. Here's the format:

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |         Channel Number        |            Length             |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                                                               |
   /                       Application Data                        /
   /                                                               /
   |                                                               |
   |                               +-------------------------------+
   |                               |
   +-------------------------------+

                                  Figure 5

The Channel Number field says which channel the data is traveling on, which also tells you the address of the peer sending or receiving it. Main character info ๐Ÿ‘‘

The Length field is the number of bytes in the application data field. It doesn't count the ChannelData header. Also, 0 is a valid length, so an empty payload is legit ๐Ÿงš

The Application Data field holds the data the client is sending to the peer, or the data the peer is sending back to the client. ๐Ÿ’œ

12.5. Sending a ChannelData Message ๐Ÿ’…

Once a client has bound a channel to a peer, whenever the client has data for that peer, it can use either a ChannelData message or a Send indication. The client isn't obligated to use the channel even when it exists, and it can freely mix the two message types when sending data to the peer. Total flexibility, no cap โœจ The server, on the other hand, MUST use the ChannelData message if a channel has been bound to the peer. And the server uses a Data indication to signal the XOR-PEER-ADDRESS and ICMP attributes to the client, even if a channel is bound to the peer. Different rules for the server, lowkey ๐Ÿ™ˆ

The fields of the ChannelData message get filled in as described in Section 12.4.

Over TCP and TLS-over-TCP, the ChannelData message MUST be padded to a multiple of four bytes so that the following messages stay aligned. The padding isn't counted in the ChannelData length field, so the actual size of a ChannelData message (padding included) is (4 + Length) rounded up to the nearest multiple of 4 (see Section 14 of [RFC8489]). Over UDP, padding isn't required, but it MAY be included ๐ŸŒธ

The ChannelData message is then sent on the 5-tuple associated with the allocation. ๐Ÿซถ

12.6. Receiving a ChannelData Message ๐ŸŽ€

The receiver uses the first byte to tell ChannelData apart from other multiplexed protocols, as described in Table 3. If the message uses a value in the reserved range (0x5000 through 0xFFFF), it gets silently discarded ๐Ÿ’€

If a ChannelData message arrives in a UDP datagram, and that datagram is too short to hold the claimed length of the ChannelData message (meaning the UDP header length field value is less than the ChannelData header length field value + 4 + 8), the message is silently discarded ๐Ÿ™ˆ

If the ChannelData message is received over TCP or TLS-over-TCP, its actual length is as described in Section 12.5.

If the ChannelData message is received on a channel that isn't bound to any peer, it gets silently discarded.

On the client, it is RECOMMENDED that the client discard the ChannelData message if it believes there's no active permission towards the peer. On the server, receiving a ChannelData message MUST NOT refresh either the channel binding or the permission towards the peer. no refreshing off the vibes alone ๐Ÿฆ‹

On the server, if no errors are detected, the server relays the application data to the peer by forming a UDP datagram like this:

  • the source transport address is the relayed transport address of the allocation. The allocation is determined by the 5-tuple the ChannelData message arrived on. ๐Ÿงš
  • the destination transport address is the transport address the channel is bound to.
  • the data after the UDP header is the contents of the ChannelData message's data field.

The resulting UDP datagram then gets sent to the peer. If the Length field in the ChannelData message is 0, there's no data in the UDP datagram, but the datagram still gets formed and sent (Section 4.1 of [RFC6263]) ๐ŸŒˆ

12.7. Relaying Data from the Peer ๐Ÿ’–

When the server receives a UDP datagram on the relayed transport address for an allocation, it processes it as described in Section 11.3. If that section says a ChannelData message should be sent (because a channel is bound to the peer that sent the UDP datagram), then the server forms and sends a ChannelData message as described in Section 12.5 โœจ

When the server receives an ICMP packet, it processes it as described in Section 11.5. ๐Ÿ’œ

13. Packet Translations ๐Ÿฆ‹

This section covers IPv4-to-IPv6, IPv6-to-IPv4, and IPv6-to-IPv6 translations. The requirements for translating the IP addresses and port numbers of packets are described above. The following sections say how to translate the other header fields ๐Ÿซถ

As discussed in Section 3.6, translations in TURN are designed so that a TURN server can run as an application in user space under commonly available operating systems, without needing special privileges. The translations in the following sections follow that principle ๐Ÿ‘‘

The descriptions below have two parts: a preferred behavior and an alternate behavior. The server SHOULD implement the preferred behavior. But if that's not possible for a particular field, the server MUST implement the alternate behavior and MUST NOT do anything else, for the reasons detailed in [RFC7915]. The TURN server relies only on the DF bit in the IPv4 header and the Fragment header in the IPv6 header to handle fragmentation, using the approach described in [RFC7915]. It does not rely on the DONT-FRAGMENT attribute. Ignoring the DONT-FRAGMENT attribute only applies to UDP-to-UDP relay, not TCP-to-UDP relay ๐ŸŒธ

13.1. IPv4-to-IPv6 Translations ๐ŸŒˆ

Time to Live (TTL) field

Preferred Behavior: As specified in Section 4 of [RFC7915].

Alternate Behavior: Set the outgoing value to the default for outgoing packets. ๐Ÿงš

Traffic Class

Preferred behavior: As specified in Section 4 of [RFC7915].

Alternate behavior: The TURN server sets the Traffic Class to the default value for outgoing packets. ๐Ÿ’…

Flow Label

Preferred behavior: The TURN server can use the 5-tuple of relayed transport address, peer transport address, and UDP protocol number to identify each flow. It can then generate and set the flow label value in the IPv6 packet, as discussed in Section 3 of [RFC6437]. If the TURN server can't generate the flow label value from the IPv6 packet's 5-tuple, it sets the Flow label to zero. ๐Ÿฆ‹

Alternate behavior: The alternate behavior is the same as the preferred behavior for a TURN server that doesn't support flow labels. ๐ŸŽ€

Hop Limit

Preferred behavior: As specified in Section 4 of [RFC7915].

Alternate behavior: The TURN server sets the Hop Limit to the default value for outgoing packets. ๐Ÿ’œ

Fragmentation

Preferred behavior: As specified in Section 4 of [RFC7915].

Alternate behavior: The TURN server assembles incoming fragments. The TURN server follows its default behavior to send outgoing packets.

For both preferred and alternate behavior, the DONT-FRAGMENT attribute MUST be ignored by the server. ๐Ÿ™ˆ

Extension Headers

Preferred behavior: The outgoing packet uses the system defaults for IPv6 extension headers, except for the Fragment header as described above.

Alternate behavior: Same as preferred. โœจ

13.2. IPv6-to-IPv6 Translations

Flow Label

NOTE: Okay bestie, the TURN server needs to remember that it's juggling two different IPv6 flows ๐Ÿฆ‹ So the Flow label [RFC6437] SHOULD NOT get copied over during the translation ๐Ÿ™…โ€โ™€๏ธ

Preferred behavior: The TURN server can use the 5-tuple of the relayed transport address, the peer transport address, and the UDP protocol number to tell each flow apart. Then it can generate and set the Flow label in the IPv6 packet, as discussed in Section 3 of [RFC6437] โœจ If the TURN server can't generate the Flow label value from the IPv6 packet's 5-tuple, it sets the Flow label to zero ๐ŸŒธ

Alternate behavior: This is the same as the preferred behavior, but for a TURN server that doesn't support flow labels ๐Ÿซถ

Hop Limit

Preferred behavior: The TURN server acts like a regular router here. It decrements the Hop Limit and generates an ICMPv6 error if the value reaches zero ๐Ÿ‘‘

Alternate behavior: The TURN server sets the Hop Limit to the default value for outgoing packets ๐Ÿ’…

Fragmentation

Preferred behavior: Okay, this one has a few scenarios, so let's go one by one ๐Ÿงš

If the incoming packet didn't include a Fragment header and the outgoing packet size doesn't exceed the outgoing link's MTU, the TURN server sends the outgoing packet without a Fragment header ๐Ÿ’–

If the incoming packet didn't include a Fragment header and the outgoing packet size does exceed the outgoing link's MTU, the TURN server drops the outgoing packet. Then it sends an ICMP message of type 2 code 0 ("Packet too big") back to the sender of the incoming packet ๐Ÿ˜ญ If that ICMPv6 "Packet too big" message is being sent to the peer, the TURN server SHOULD reduce the MTU reported in the ICMP message by 48 bytes, to make room for the overhead of a Data indication ๐Ÿ“

If the incoming packet included a Fragment header and the outgoing packet size (with a Fragment header included) doesn't exceed the outgoing link's MTU, the TURN server sends the outgoing packet with a Fragment header. It sets the fields of the Fragment header as appropriate for a packet originating from the server โœจ

If the incoming packet included a Fragment header and the outgoing packet size exceeds the outgoing link's MTU, the TURN server MUST fragment the outgoing packet into fragments of no more than 1280 bytes ๐Ÿ”ฅ It also sets the fields of the Fragment header as appropriate for a packet originating from the server ๐ŸŽ€

Alternate behavior: The TURN server assembles incoming fragments, then follows its default behavior to send outgoing packets ๐Ÿฆ‹

For both preferred and alternate behavior, the DONT-FRAGMENT attribute MUST be ignored by the server. ๐ŸŒˆ

Extension Headers

Preferred behavior: The outgoing packet uses the system defaults for IPv6 extension headers, except for the Fragment header as described above ๐Ÿ’œ

Alternate behavior: Same as preferred ๐ŸŒธ


13.3. IPv6-to-IPv4 Translations

Type of Service and Precedence

Preferred behavior: As specified in Section 5 of [RFC7915] ๐ŸŽ€

Alternate behavior: The TURN server sets the Type of Service and Precedence to the default value for outgoing packets ๐Ÿ’…

Time to Live

Preferred behavior: As specified in Section 5 of [RFC7915] ๐Ÿฆ‹

Alternate behavior: The TURN server sets the Time to Live to the default value for outgoing packets ๐Ÿซถ

Fragmentation

Preferred behavior: As specified in Section 5 of [RFC7915] โœจ On top of that, when the outgoing packet's size exceeds the outgoing link's MTU, the TURN server needs to generate an ICMP error (ICMPv6 "Packet too big") that reports the MTU size ๐Ÿ˜ญ If the ICMPv4 packet (Destination Unreachable (Type 3) with Code 4) is being sent to the peer, the TURN server SHOULD reduce the MTU reported in the ICMP message by 48 bytes, to make room for the overhead of a Data indication ๐Ÿ“

Alternate behavior: The TURN server assembles incoming fragments, then follows its default behavior to send outgoing packets ๐Ÿงš

For both preferred and alternate behavior, the DONT-FRAGMENT attribute MUST be ignored by the server. ๐ŸŒˆ


14. UDP-to-UDP Relay โœจ

This section is all about how the server sets various fields in the IP header for UDP-to-UDP relay, going from the client to the peer or the other way around ๐Ÿ’– These descriptions apply (a) when the server sends a UDP datagram to the peer, or (b) when the server sends a Data indication or ChannelData message to the client over UDP transport. They do not apply to TURN messages sent over TCP or TLS transport from the server to the client ๐Ÿ™…โ€โ™€๏ธ

The descriptions below come in two parts: a preferred behavior and an alternate behavior. The server SHOULD implement the preferred behavior ๐Ÿ‘‘ But if that isn't possible for a particular field, then it SHOULD implement the alternative behavior instead ๐Ÿซถ

Differentiated Services Code Point (DSCP) field [RFC2474]

Preferred Behavior: Set the outgoing value to the incoming value, unless the server includes a differentiated services classifier and marker [RFC2474] ๐Ÿ’…

Alternate Behavior: Set the outgoing value to a fixed value, which is Best Effort by default unless it's configured otherwise ๐ŸŒธ

In both cases, if the server is immediately adjacent to a differentiated services classifier and marker, then DSCP MAY be set to any arbitrary value in the direction towards the classifier ๐Ÿฆ‹

Explicit Congestion Notification (ECN) field [RFC3168]

Preferred Behavior: Set the outgoing value to the incoming value. The server may perform Active Queue Management, and in that case it SHOULD behave as an ECN-aware router [RFC3168] and can mark traffic with Congestion Experienced (CE) instead of dropping the packet ๐Ÿงš The use of ECT(1) is subject to experimental usage [RFC8311] ๐Ÿ”ฌ

Alternate Behavior: Set the outgoing value to Not-ECT (=0b00) ๐Ÿ’œ

IPv4 Fragmentation fields (applicable only for IPv4-to-IPv4 relay)

Preferred Behavior: When the server sends a packet to a peer in response to a Send indication containing the DONT-FRAGMENT attribute, set the outgoing UDP packet to not fragment โœจ In all other cases, when sending an outgoing packet containing application data (for example a Data indication, a ChannelData message, or a Send indication that doesn't include the DONT-FRAGMENT attribute), copy the DF bit from the DF bit of the incoming packet that contained the application data ๐ŸŽ€

Set the other fragmentation fields (Identification, More Fragments, Fragment Offset) as appropriate for a packet originating from the server ๐ŸŒˆ

Alternate Behavior: Same as the preferred behavior, except that it always assumes the incoming DF bit is 0 ๐Ÿ“

In both the preferred and alternate behaviors, the resulting packet may be too large for the outgoing link. If that happens, then the normal fragmentation rules apply [RFC1122] ๐Ÿ˜ญ

IPv4 Options

Preferred Behavior: The outgoing packet uses the system defaults for IPv4 options ๐Ÿ’–

Alternate Behavior: Same as preferred โœจ


15. TCP-to-UDP Relay โœจ

This section describes how the server sets various fields in the IP header for TCP-to-UDP relay from the client to the peer ๐Ÿฆ‹ These descriptions apply when the server sends a UDP datagram to the peer. Heads up, the server does not do per-packet translation for TCP-to-UDP relaying ๐Ÿ™ˆ

Multipath TCP [TCP-EXT] is not supported by this version of TURN, because TCP multipath isn't used by either SIP or WebRTC [RFC7478] for media or non-media data ๐Ÿ™…โ€โ™€๏ธ A TCP connection between the TURN client and server can use the TCP Authentication Option (TCP-AO) [RFC5925], but UDP doesn't offer a similar type of authentication, though it might be added in the future [UDP-OPT] ๐Ÿ” Even if both TCP-AO and UDP authentication were used between the TURN client and server, it wouldn't change the end-to-end security properties of the application payload being relayed ๐Ÿ˜ญ So applications using TURN will need to secure their application data end to end, for example with Secure Real-time Transport Protocol (SRTP) for RTP applications ๐Ÿซถ Also, the TCP-AO option obsoletes the TCP MD5 option ๐Ÿ’…

Unlike UDP, TCP without the TCP Fast Open extension [RFC7413] doesn't support 0-RTT session resumption ๐ŸŒธ The TCP user timeout [RFC5482] equivalent for application data relayed by TURN is the use of the RTP control protocol (RTCP) ๐Ÿงš As a reminder, RTCP is a fundamental and integral part of RTP ๐Ÿ’œ

The descriptions below come in two parts: a preferred behavior and an alternate behavior. The server SHOULD implement the preferred behavior ๐Ÿ‘‘ But if that isn't possible for a particular field, then it SHOULD implement the alternative behavior instead ๐Ÿซถ

For the UDP datagram sent to the peer based on a Send Indication or ChannelData message arriving at the TURN server over a TCP transport, the server sets various fields in the IP header as follows ๐ŸŽ€

Differentiated Services Code Point (DSCP) field [RFC2474]

Preferred Behavior: The TCP connection can only use a single DSCP, so inter-flow differentiation isn't possible (see Section 5.1 of [RFC7657]) ๐Ÿฆ‹ The server sets the outgoing value to the DSCP used by the TCP connection, unless the server includes a differentiated services classifier and marker [RFC2474] โœจ

Alternate Behavior: Set the outgoing value to a fixed value, which is Best Effort by default unless it's configured otherwise ๐ŸŒธ

In both cases, if the server is immediately adjacent to a differentiated services classifier and marker, then DSCP MAY be set to any arbitrary value in the direction towards the classifier ๐Ÿ’–

Explicit Congestion Notification (ECN) field [RFC3168]

Preferred Behavior: No mechanism is defined to indicate what ECN value should be used for the outgoing UDP datagrams of an allocation, so set the outgoing value to Not-ECT (=0b00) ๐Ÿ™ˆ

Alternate Behavior: Same as preferred ๐Ÿ’œ

IPv4 Fragmentation fields (applicable only for IPv4-to-IPv4 relay)

Preferred Behavior: When the server sends a packet to a peer in response to a Send indication containing the DONT-FRAGMENT attribute, set the outgoing UDP packet to not fragment ๐Ÿ”ฅ In all other cases, when sending an outgoing UDP packet containing application data (for example a Data indication, a ChannelData message, or a Send indication without the DONT-FRAGMENT attribute), set the DF bit in the outgoing IP header to 0 ๐Ÿ“

Alternate Behavior: Same as preferred ๐ŸŽ€

IPv6 Fragmentation fields

Preferred Behavior: If the TCP traffic arrives over IPv6, the server relies on the presence of the DONT-FRAGMENT attribute in the Send indication to set the outgoing UDP packet to not fragment ๐Ÿงš

Alternate Behavior: Same as preferred ๐ŸŒˆ

IPv4 Options

Preferred Behavior: The outgoing packet uses the system defaults for IPv4 options ๐Ÿฆ‹

Alternate Behavior: Same as preferred ๐Ÿ’…

16. UDP-to-TCP Relay ๐ŸŒธ

okay so this section is about how the server sets the IP header fields when it relays stuff from the peer to the client, but only when the client is on TCP or TLS ๐ŸŽ€ the server does NOT do per-packet translation for UDP-to-TCP relaying, so it's not rewriting every single packet, bestie ๐Ÿ’…

the descriptions below come in two flavors: a preferred behavior and an alternate behavior. the server SHOULD do the preferred one ๐Ÿ’– but if that's not possible for a given field, then it SHOULD do the alternate one instead โœจ

the TURN server sets the IP header fields in the TCP packets on a per-connection basis for that TCP connection, like this:

Differentiated Services Code Point (DSCP) field [RFC2474]

  • Preferred Behavior: Ignore the incoming DSCP value. When TCP is used between the client and the server, a single DSCP should be used for all traffic on that TCP connection. Note, TURN/ICE occurs before application data is exchanged. ๐Ÿฆ‹
  • Alternate Behavior: Same as preferred.

Explicit Congestion Notification (ECN) field [RFC3168]

  • Preferred Behavior: Ignore; ECN signals are dropped in the TURN server for the incoming UDP datagrams from the peer. ๐Ÿ™ˆ
  • Alternate Behavior: Same as preferred.

Fragmentation

  • Preferred Behavior: Any fragmented packets are reassembled in the server and then forwarded to the client over the TCP connection. ICMP messages resulting from the UDP datagrams sent to the peer are processed by the server as described in Section 11.5 and forwarded to the client using TURN's mechanism for relevant ICMP types and codes. ๐Ÿงš
  • Alternate Behavior: Same as preferred.

Extension Headers

  • Preferred behavior: The outgoing packet uses the system defaults for IPv6 extension headers. ๐ŸŒˆ
  • Alternate behavior: Same as preferred.

IPv4 Options

  • Preferred Behavior: The outgoing packet uses the system defaults for IPv4 options. โญ
  • Alternate Behavior: Same as preferred.

17. STUN Methods ๐ŸŽ€

this section is the list of code points for the STUN methods defined in this spec ๐Ÿ“ the actual semantics live elsewhere in the document, so go look there if you want the juicy details ๐Ÿ‘€

        +-------+------------------+------------------------+
        | 0x003 | Allocate         | (only request/response |
        |       |                  | semantics defined)     |
        +-------+------------------+------------------------+
        | 0x004 | Refresh          | (only request/response |
        |       |                  | semantics defined)     |
        +-------+------------------+------------------------+
        | 0x006 | Send             | (only indication       |
        |       |                  | semantics defined)     |
        +-------+------------------+------------------------+
        | 0x007 | Data             | (only indication       |
        |       |                  | semantics defined)     |
        +-------+------------------+------------------------+
        | 0x008 | CreatePermission | (only request/response |
        |       |                  | semantics defined)     |
        +-------+------------------+------------------------+
        | 0x009 | ChannelBind      | (only request/response |
        |       |                  | semantics defined)     |
        +-------+------------------+------------------------+

                               Table 4

18. STUN Attributes ๐Ÿ’œ

this STUN extension defines the following attributes, and honestly the table is giving everything ๐Ÿ˜ญ

               +--------+---------------------------+
               | 0x000C | CHANNEL-NUMBER            |
               +--------+---------------------------+
               | 0x000D | LIFETIME                  |
               +--------+---------------------------+
               | 0x0010 | Reserved (was BANDWIDTH)  |
               +--------+---------------------------+
               | 0x0012 | XOR-PEER-ADDRESS          |
               +--------+---------------------------+
               | 0x0013 | DATA                      |
               +--------+---------------------------+
               | 0x0016 | XOR-RELAYED-ADDRESS       |
               +--------+---------------------------+
               | 0x0017 | REQUESTED-ADDRESS-FAMILY  |
               +--------+---------------------------+
               | 0x0018 | EVEN-PORT                 |
               +--------+---------------------------+
               | 0x0019 | REQUESTED-TRANSPORT       |
               +--------+---------------------------+
               | 0x001A | DONT-FRAGMENT             |
               +--------+---------------------------+
               | 0x0021 | Reserved (was TIMER-VAL)  |
               +--------+---------------------------+
               | 0x0022 | RESERVATION-TOKEN         |
               +--------+---------------------------+
               | 0x8000 | ADDITIONAL-ADDRESS-FAMILY |
               +--------+---------------------------+
               | 0x8001 | ADDRESS-ERROR-CODE        |
               +--------+---------------------------+
               | 0x8004 | ICMP                      |
               +--------+---------------------------+

                              Table 5

some of these attributes have lengths that aren't multiples of 4 ๐Ÿฅบ and by the STUN rules, any attribute whose length isn't a multiple of 4 bytes MUST be immediately followed by 1 to 3 padding bytes, so the next attribute (if there is one) starts on a 4-byte boundary (see [RFC8489]). padding is not optional drama, it's a must ๐Ÿ’…

18.1. CHANNEL-NUMBER ๐Ÿฆ‹

the CHANNEL-NUMBER attribute holds the number of the channel. its value is 4 bytes long and is made of a 16-bit unsigned integer followed by a two-octet RFFU (Reserved For Future Use) field. the RFFU field MUST be set to 0 on transmission and MUST be ignored on reception ๐Ÿซถ

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|        Channel Number         |         RFFU = 0              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                               Figure 6

18.2. LIFETIME โณ

the LIFETIME attribute is how long the server will keep an allocation alive if nobody refreshes it. the TURN client can include LIFETIME with the lifetime it wants in Allocate and Refresh requests. its value is 4 bytes long and is a 32-bit unsigned integral value, the number of seconds left until expiration ๐Ÿ•ฐ๏ธ

18.3. XOR-PEER-ADDRESS ๐ŸŒธ

the XOR-PEER-ADDRESS attribute specifies the address and port of the peer as the TURN server sees it. (for example, the peer's server-reflexive transport address if the peer is behind a NAT.) it's encoded the same way as the XOR-MAPPED-ADDRESS attribute [RFC8489] โœจ

18.4. DATA ๐Ÿ’–

the DATA attribute is present in all Send indications. if the ICMP attribute is not present in a Data indication, it contains a DATA attribute. its value is variable length and holds the application data (aka the data that would come right after the UDP header if the data went straight between the client and the peer) ๐Ÿ“ the application data is equivalent to the "UDP user data" and does NOT include the "surplus area" defined in Section 4 of [UDP-OPT]. if the length of this attribute isn't a multiple of 4, then padding must be added after this attribute ๐Ÿงš

18.5. XOR-RELAYED-ADDRESS ๐ŸŒˆ

the XOR-RELAYED-ADDRESS attribute shows up in Allocate responses. it specifies the address and port that the server allocated to the client. it's encoded the same way as the XOR-MAPPED-ADDRESS attribute [RFC8489] ๐ŸŽ€

18.6. REQUESTED-ADDRESS-FAMILY ๐Ÿ‘‘

this attribute is used in Allocate and Refresh requests to specify the address type the client wants. its value is 4 bytes with the following format:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Family    |            Reserved                           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                               Figure 7

Family: There are two values defined for this field, specified in Section 14.1 of [RFC8489]: 0x01 for IPv4 addresses and 0x02 for IPv6 addresses. ๐ŸŒ

Reserved: At this point, the 24 bits in the Reserved field MUST be set to zero by the client and MUST be ignored by the server. ๐Ÿ™…โ€โ™€๏ธ

18.7. EVEN-PORT ๐Ÿ‘

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

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

                               Figure 8

the value contains a single 1-bit flag:

R: If 1, the server is requested to reserve the next-higher port number (on the same IP address) for a subsequent allocation. If 0, no such reservation is requested. ๐Ÿ”ฅ

RFFU: Reserved For Future Use.

the RFFU field must be set to zero on transmission and ignored on reception.

since the length of this attribute is not a multiple of 4, padding must immediately follow this attribute. ๐Ÿซ 

18.8. REQUESTED-TRANSPORT ๐Ÿš€

this attribute is how the client requests a specific transport protocol for the allocated transport address. its value is 4 bytes with the following format:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|    Protocol   |                    RFFU                       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                               Figure 9

the Protocol field specifies the desired protocol. the code points used in this field are taken from the ones allowed in the Protocol field of the IPv4 header and the NextHeader field of the IPv6 header [PROTOCOL-NUMBERS]. this spec only allows code point 17 (User Datagram Protocol) ๐Ÿฆ‹

the RFFU field MUST be set to zero on transmission and MUST be ignored on reception. it's reserved for future uses ๐ŸŒท

18.9. DONT-FRAGMENT ๐Ÿ™ƒ

this attribute is how the client asks the server to set the DF (Don't Fragment) bit in the IP header when it relays the application data onward to the peer. it's also used for figuring out the server's capability in Allocate requests. this attribute has no value part, so the attribute length field is 0 ๐Ÿง

18.10. RESERVATION-TOKEN ๐Ÿ”‘

the RESERVATION-TOKEN attribute holds a token that uniquely identifies a relayed transport address that the server is holding in reserve. the server includes this attribute in a success response to tell the client about the token, and then the client includes this attribute in a later Allocate request to ask the server to use that relayed transport address for the allocation ๐Ÿฅน

its value is 8 bytes and contains the token value. โœจ

18.11. ADDITIONAL-ADDRESS-FAMILY โœจ

Okay bestie, this one is all about asking for a second address family ๐Ÿฆ‹. Clients use it to request an IPv4 and IPv6 address type from a server. It's encoded the exact same way as REQUESTED-ADDRESS-FAMILY, so go peek at Section 18.6 ๐Ÿซถ. The ADDITIONAL-ADDRESS-FAMILY attribute MAY be present in the Allocate request. In an Allocate request, the only valid value is 0x02 (IPv6 address), periodt ๐Ÿ’….

18.12. ADDRESS-ERROR-CODE ๐Ÿ™ˆ

Servers use this attribute to explain why they didn't allocate the address family you asked for ๐Ÿ’€. The value portion is variable length and looks like this:

       0                   1                   2                   3
       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |  Family       |    Reserved             |Class|     Number    |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |      Reason Phrase (variable)                                ..
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                                 Figure 10

Family: There are two values for this field, defined in Section 14.1 of [RFC8489]: 0x01 for IPv4 addresses and 0x02 for IPv6 addresses. ๐ŸŒˆ

Reserved: At this point, the 13 bits in the Reserved field MUST be set to zero by the server and MUST be ignored by the client. ๐Ÿงš

Class: The Class represents the hundreds digit of the error code and is defined in Section 14.8 of [RFC8489]. ๐Ÿ“

Number: This 8-bit field contains the reason the server cannot allocate one of the requested address types. The error code values could be either 440 (Address Family not Supported) or 508 (Insufficient Capacity). The number representation is defined in Section 14.8 of [RFC8489]. ๐Ÿ’œ

Reason Phrase: The recommended reason phrases for error codes 440 and 508 are explained in Section 19. The reason phrase MUST be a UTF-8 [RFC3629] encoded sequence of less than 128 characters (which can be as long as 509 bytes when encoding them or 763 bytes when decoding them). โœจ

18.13. ICMP ๐ŸŒธ

This attribute is used by servers to tell you why a UDP packet got dropped ๐Ÿฆ‹. Here's the format of the ICMP attribute:

       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |  Reserved                     |  ICMP Type  |  ICMP Code      |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                          Error Data                           |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                                 Figure 11

Reserved: This field MUST be set to 0 when sent and MUST be ignored when received. ๐Ÿซถ

ICMP Type: The field contains the value of the ICMP type. Its interpretation depends on whether the ICMP was received over IPv4 or IPv6. ๐Ÿ‘‘

ICMP Code: The field contains the value of the ICMP code. Its interpretation depends on whether the ICMP was received over IPv4 or IPv6. ๐Ÿ”ฅ

Error Data: This field size is 4 bytes long. If the ICMPv6 type is 2 ("Packet too big" message) or ICMPv4 type is 3 (Destination Unreachable) and Code is 4 (fragmentation needed and DF set), the Error Data field will be set to the Maximum Transmission Unit of the next-hop link (Section 3.2 of [RFC4443] and Section 4 of [RFC1191]). For other ICMPv6 types and ICMPv4 types and codes, the Error Data field MUST be set to zero. ๐Ÿ˜ญ


19. STUN Error Response Codes โœจ

This document defines the following error response codes, and they're giving main character energy ๐Ÿ‘‘

403 (Forbidden): The request was valid but cannot be performed due to administrative or similar restrictions. ๐Ÿ”’

437 (Allocation Mismatch): A request was received by the server that requires an allocation to be in place, but no allocation exists, or a request was received that requires no allocation, but an allocation exists. ๐Ÿ™ˆ

440 (Address Family not Supported): The server does not support the address family requested by the client. ๐Ÿ’€

441 (Wrong Credentials): (Wrong Credentials): The credentials in the (non-Allocate) request do not match those used to create the allocation. ๐Ÿซฃ

442 (Unsupported Transport Protocol): The Allocate request asked the server to use a transport protocol between the server and the peer that the server does not support. NOTE: This does NOT refer to the transport protocol used in the 5-tuple. ๐Ÿงš

443 (Peer Address Family Mismatch): A peer address is part of a different address family than that of the relayed transport address of the allocation. ๐ŸŒˆ

486 (Allocation Quota Reached): No more allocations using this username can be created at the present time. ๐Ÿ“

508 (Insufficient Capacity): The server is unable to carry out the request due to some capacity limit being reached. In an Allocate response, this could be due to the server having no more relayed transport addresses available at that time, having none with the requested properties, or the one that corresponds to the specified reservation token is not available. ๐Ÿฅบ


20. Detailed Example ๐ŸŽ€

This section gives an example of the use of TURN, showing in detail the contents of the messages exchanged. The example uses the network diagram shown in the Overview (Figure 1). ๐Ÿฆ‹

For each message, the attributes included in the message and their values are shown. For convenience, values are shown in a human-readable format rather than showing the actual octets; for example, "XOR-RELAYED-ADDRESS=192.0.2.15:9000" shows that the XOR-RELAYED-ADDRESS attribute is included with an address of 192.0.2.15 and a port of 9000; here, the address and port are shown before the xor-ing is done. For attributes with string-like values (e.g., SOFTWARE="Example client, version 1.03" and NONCE="obMatJos2gAAAadl7W7PeDU4hKE72jda"), the value of the attribute is shown in quotes for readability, but these quotes do not appear in the actual value. ๐Ÿซถ

   TURN                                 TURN          Peer         Peer
   client                               server         A            B
     |                                    |            |            |
     |--- Allocate request -------------->|            |            |
     |    Transaction-Id=0xA56250D3F17ABE679422DE85    |            |
     |    SOFTWARE="Example client, version 1.03"      |            |
     |    LIFETIME=3600 (1 hour)          |            |            |
     |    REQUESTED-TRANSPORT=17 (UDP)    |            |            |
     |    DONT-FRAGMENT                   |            |            |
     |                                    |            |            |
     |<-- Allocate error response --------|            |            |
     |    Transaction-Id=0xA56250D3F17ABE679422DE85    |            |
     |    SOFTWARE="Example server, version 1.17"      |            |
     |    ERROR-CODE=401 (Unauthorized)   |            |            |
     |    REALM="example.com"             |            |            |
     |    NONCE="obMatJos2gAAAadl7W7PeDU4hKE72jda"     |            |
     |    PASSWORD-ALGORITHMS=MD5 and SHA256           |            |
     |                                    |            |            |
     |--- Allocate request -------------->|            |            |
     |    Transaction-Id=0xC271E932AD7446A32C234492    |            |
     |    SOFTWARE="Example client 1.03"  |            |            |
     |    LIFETIME=3600 (1 hour)          |            |            |
     |    REQUESTED-TRANSPORT=17 (UDP)    |            |            |
     |    DONT-FRAGMENT                   |            |            |
     |    USERNAME="George"               |            |            |
     |    REALM="example.com"             |            |            |
     |    NONCE="obMatJos2gAAAadl7W7PeDU4hKE72jda"     |            |
     |    PASSWORD-ALGORITHMS=MD5 and SHA256           |            |
     |    PASSWORD-ALGORITHM=SHA256       |            |            |
     |    MESSAGE-INTEGRITY=...           |            |            |
     |    MESSAGE-INTEGRITY-SHA256=...    |            |            |
     |                                    |            |            |
     |<-- Allocate success response ------|            |            |
     |    Transaction-Id=0xC271E932AD7446A32C234492    |            |
     |    SOFTWARE="Example server, version 1.17"      |            |
     |    LIFETIME=1200 (20 minutes)      |            |            |
     |    XOR-RELAYED-ADDRESS=192.0.2.15:50000         |            |
     |    XOR-MAPPED-ADDRESS=192.0.2.1:7000            |            |
     |    MESSAGE-INTEGRITY-SHA256=...    |            |            |

                                 Figure 12

The client begins by selecting a host transport address to use for the TURN session; in this example, the client has selected 198.51.100.2:49721 as shown in Figure 1. ๐Ÿงญ The client then sends an Allocate request to the server at the server transport address. The client randomly selects a 96-bit transaction id of 0xA56250D3F17ABE679422DE85 for this transaction; this is encoded in the transaction id field in the fixed header. ๐ŸŽฒ The client includes a SOFTWARE attribute that gives information about the client's software; here, the value is "Example client, version 1.03" to indicate that this is version 1.03 of something called the "Example client". ๐Ÿ’…

The client includes the LIFETIME attribute because it wishes the allocation to have a longer lifetime than the default of 10 minutes; the value of this attribute is 3600 seconds, which corresponds to 1 hour. โฐ The client must always include a REQUESTED-TRANSPORT attribute in an Allocate request, and the only value allowed by this specification is 17, which indicates UDP transport between the server and the peers. ๐Ÿฆ‹ The client also includes the DONT-FRAGMENT attribute because it wishes to use the DONT-FRAGMENT attribute later in Send indications; this attribute consists of only an attribute header; there is no value part. ๐ŸŒธ

We assume the client has not recently interacted with the server; thus, the client does not include the USERNAME, USERHASH, REALM, NONCE, PASSWORD-ALGORITHMS, PASSWORD-ALGORITHM, MESSAGE-INTEGRITY, or MESSAGE-INTEGRITY-SHA256 attribute. ๐Ÿ™ˆ Finally, note that the order of attributes in a message is arbitrary (except for the MESSAGE-INTEGRITY, MESSAGE-INTEGRITY-SHA256 and FINGERPRINT attributes), and the client could have used a different order. ๐Ÿซถ

Okay, servers are SO picky ๐Ÿ’… They require every single request to be authenticated ๐Ÿ” So when the server gets the first Allocate request and it has no auth attributes, it's like "nope, not you" and rejects it ๐Ÿ™…โ€โ™€๏ธ Following the long-term credential mechanism of STUN [RFC8489] ๐ŸŽ€, the server sends back an ERROR-CODE with a value of 401 (Unauthorized) ๐Ÿ˜ญ It also includes a REALM attribute that says which authentication realm it's using (here it's the server's domain "example.com" ๐ŸŒธ) and a nonce in a NONCE attribute. The NONCE starts with the "nonce cookie", with the STUN Security Feature "Password algorithm" bit set to 1 โœจ The server adds a PASSWORD-ALGORITHMS attribute listing the algorithms it can use to derive the long-term password ๐Ÿง If the server sets the STUN Security Feature "Username anonymity" bit to 1, then the client uses the USERHASH attribute instead of USERNAME in the Allocate request so the username stays anonymized ๐Ÿ™ˆ And the server throws in a SOFTWARE attribute with info about its software ๐Ÿ’œ

The client gets the 401 and reattempts the Allocate request, this time with the auth attributes ๐Ÿฆ‹ It picks a new transaction id, then fills the new request with the same attributes as before. It includes a USERNAME attribute, and it uses the realm value from the server to figure out which username to use. Here the client is set up to use the username "George" for the realm "example.com" ๐Ÿซถ It also includes the PASSWORD-ALGORITHM attribute, which tells the server which algorithm to use to derive the long-term password ๐Ÿ”ฅ The REALM, PASSWORD-ALGORITHMS, and NONCE attributes are just copied from the 401 error response ๐Ÿ’… Last but not least, the client adds a MESSAGE-INTEGRITY-SHA256 attribute as the very last attribute in the message. Its value is a Hashed Message Authentication Code - Secure Hash Algorithm 2 (HMAC-SHA2) hash over the contents of the message (shown as just "..." above) ๐Ÿ” This HMAC-SHA2 computation includes a password value, so an attacker can't compute the message integrity value without somehow knowing the secret password ๐Ÿ˜ค

The server gets the authenticated Allocate request, checks that everything is OK, and then creates an allocation โœจ It replies with an Allocate success response. It includes a LIFETIME attribute with the lifetime of the allocation. Here the client asked for 1 hour, but the server cut it down to just 20 minutes because this particular server doesn't allow lifetimes longer than that โฐ๐Ÿ’€ It includes an XOR-RELAYED-ADDRESS attribute with the relayed transport address of the allocation ๐Ÿฆ‹ It also includes an XOR-MAPPED-ADDRESS attribute with the client's server-reflexive address. TURN doesn't use this value otherwise, but it's handed back as a convenience to the client ๐ŸŽ The server adds a MESSAGE-INTEGRITY-SHA256 attribute to authenticate the response and make sure it hasn't been tampered with. Note that the response does NOT contain USERNAME, REALM, or NONCE attributes ๐Ÿ‘€ And the server adds a SOFTWARE attribute too ๐Ÿ’–

   TURN                                 TURN          Peer         Peer
   client                               server         A            B
     |--- CreatePermission request ------>|            |            |
     |    Transaction-Id=0xE5913A8F460956CA277D3319    |            |
     |    XOR-PEER-ADDRESS=192.0.2.150:0  |            |            |
     |    USERNAME="George"               |            |            |
     |    REALM="example.com"             |            |            |
     |    NONCE="obMatJos2gAAAadl7W7PeDU4hKE72jda"     |            |
     |    PASSWORD-ALGORITHMS=MD5 and SHA256           |            |
     |    PASSWORD-ALGORITHM=SHA256       |            |            |
     |    MESSAGE-INTEGRITY-SHA256=...    |            |            |
     |                                    |            |            |
     |<-- CreatePermission success resp.--|            |            |
     |    Transaction-Id=0xE5913A8F460956CA277D3319    |            |
     |    MESSAGE-INTEGRITY-SHA256=...    |            |            |

                                 Figure 13

Now the client makes a permission towards Peer A so it can send it some application data ๐Ÿงš That's done with a CreatePermission request. The XOR-PEER-ADDRESS attribute holds the IP address the permission is set up for (Peer A's IP address) ๐ŸŽฏ The port number in that attribute gets ignored in a CreatePermission request, so here it's set to 0 โœจ Also, notice that the client uses Peer A's server-reflexive IP address and NOT its (private) host address ๐Ÿ‘‘ The client uses the same username, realm, and nonce values as the previous request on the allocation. It's allowed to include a SOFTWARE attribute, but this time it chooses not to ๐ŸŒธ

The server gets the CreatePermission request, creates the matching permission, and replies with a CreatePermission success response ๐Ÿฆ‹ Like the client, the server skips the SOFTWARE attribute in its reply. Again, success responses carry a MESSAGE-INTEGRITY-SHA256 attribute (assuming the server uses the long-term credential mechanism) but NO USERNAME, REALM, or NONCE attributes ๐Ÿ™ˆ

   TURN                                 TURN          Peer          Peer
   client                               server         A             B
     |--- ChannelBind request ----------->|            |             |
     |    Transaction-Id=0x6490D3BC175AFF3D84513212    |             |
     |    CHANNEL-NUMBER=0x4000           |            |             |
     |    XOR-PEER-ADDRESS=192.0.2.210:49191           |             |
     |    USERNAME="George"               |            |             |
     |    REALM="example.com"             |            |             |
     |    NONCE="obMatJos2gAAAadl7W7PeDU4hKE72jda"     |             |
     |    PASSWORD-ALGORITHMS=MD5 and SHA256           |             |
     |    PASSWORD-ALGORITHM=SHA256       |            |             |
     |    MESSAGE-INTEGRITY-SHA256=...    |            |             |
     |                                    |            |             |
     |<-- ChannelBind success response ---|            |             |
     |    Transaction-Id=0x6490D3BC175AFF3D84513212    |             |
     |    MESSAGE-INTEGRITY-SHA256=...    |            |             |

                                 Figure 15

(I've put Figure 15 here by mistake above, so here's the correct order. Ignore that; see the figure block just below.)

Okay so Peer B sends a UDP datagram back to the relayed transport address ๐Ÿฆ‹ The server knows exactly which client to send it to because of the relayed transport address the datagram arrived at ๐Ÿ’– And since channel 0x4000 is bound to 192.0.2.210:49191, the server uses that channel for the ChannelData message ๐Ÿงš BUT if there's no channel number bound to that address, the server falls back to a Data indication instead ๐Ÿ™ˆ

   TURN                                 TURN          Peer         Peer
   client                               server         A            B
     |--- ChannelBind request ----------->|            |            |
     |    Transaction-Id=0xE5913A8F46091637EF7D3328    |            |
     |    CHANNEL-NUMBER=0x4000           |            |            |
     |    XOR-PEER-ADDRESS=192.0.2.210:49191           |            |
     |    USERNAME="George"               |            |            |
     |    REALM="example.com"             |            |            |
     |    NONCE="obMatJos2gAAAadl7W7PeDU4hKE72jda"     |            |
     |    PASSWORD-ALGORITHMS=MD5 and SHA256           |            |
     |    PASSWORD-ALGORITHM=SHA256       |            |            |
     |    MESSAGE-INTEGRITY-SHA256=...    |            |            |
     |                                    |            |            |
     |<-- ChannelBind success response ---|            |            |
     |    Transaction-Id=0xE5913A8F46091637EF7D3328    |            |
     |    MESSAGE-INTEGRITY-SHA256=...    |            |            |

Figure 17

The channel binding lasts for 10 minutes unless it gets refreshed โฐ To refresh it, the TURN client sends a ChannelBind request that rebinds the channel to the same peer (Peer B's IP address) ๐ŸŒธ The server handles that request, rebinds the channel to the same peer, and resets the time-to-expiry timer back to 10 minutes โœจ

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

Figure 18

Sometime before the 20-minute lifetime is up, the client refreshes the allocation with a Refresh request ๐Ÿซถ Same as before, the client includes the latest username, realm, and nonce values, and it also includes the SOFTWARE attribute, because that's the recommended practice for Allocate and Refresh messages ๐Ÿ’… When the server gets the Refresh request, it notices the nonce has expired, so it replies with a 438 (Stale Nonce) error and hands over a new nonce value ๐Ÿ˜ญ The client tries again with the new nonce, the server accepts it this time, and the server sends a success response ๐ŸŽ€ Oh, and the client didn't include a LIFETIME attribute, so the server refreshes the allocation for the default lifetime of 10 minutes. You can see that in the LIFETIME attribute of the success response ๐Ÿ‘‘


21. Security Considerations ๐Ÿ”

This section looks at the attacks that are possible in a TURN deployment and explains how they get mitigated, either by mechanisms in the protocol or by recommended practices in the implementation ๐Ÿ•ต๏ธโ€โ™€๏ธ

Most attacks on TURN are stopped by the server requiring requests to be authenticated, which is why this specification requires the use of authentication ๐Ÿ”’ The mandatory-to-implement mechanism is the long-term credential mechanism of STUN. Other authentication mechanisms with equal or stronger security properties may be used, but it's important to make sure they can be invoked in an interoperable way ๐Ÿ’œ

21.1. Outsider Attacks

Outsider attacks are the ones where the attacker has no credentials in the system and is trying to disrupt the service seen by the client or the server ๐Ÿ˜ˆ

21.1.1. Obtaining Unauthorized Allocations

An attacker might want to obtain allocations on a TURN server for all kinds of nefarious purposes ๐Ÿ’€ A TURN server gives a mechanism for sending and receiving packets while cloaking the actual IP address of the client, so TURN servers are an extremely attractive target for attackers who want to use them to mask their true identity ๐Ÿฅธ

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

These attacks are prevented using the long-term credential mechanism, which lets the TURN server figure out the identity of the requestor and whether that requestor is allowed to obtain the allocation ๐Ÿ›ก๏ธ

21.1.2. Offline Dictionary Attacks

The long-term credential mechanism used by TURN is subject to offline dictionary attacks ๐Ÿ“– An attacker who can eavesdrop on a message exchange between a client and server can work out the password by trying a bunch of candidate passwords and seeing if one of them is correct ๐Ÿ‘€ This attack works when the passwords are low entropy, like a plain word from the dictionary ๐Ÿ™ƒ It can be mitigated by using strong passwords with large entropy ๐Ÿ’ช In situations where even stronger mitigation is required, (D)TLS transport between the client and the server can be used ๐Ÿ”

21.1.3. Faked Refreshes and Permissions

An attacker might want to attack an active allocation by sending it a Refresh request with an immediate expiration, just to delete it and disrupt service to the client ๐Ÿ—‘๏ธ Authentication of refreshes prevents this ๐Ÿ™…โ€โ™€๏ธ Similarly, an attacker who wants to send CreatePermission requests to create permissions to undesirable destinations is stopped by authentication too ๐Ÿšซ The motivations for that kind of attack are described in Section 21.2 ๐Ÿง

21.1.4. Fake Data

An attacker might want to send data to the client or the peer as if it came from the peer or client, respectively ๐ŸŽญ To do that, the attacker can send the client a faked Data indication or ChannelData message, or send the TURN server a faked Send indication or ChannelData message ๐Ÿซฃ

Indications and ChannelData messages are not authenticated, so TURN doesn't prevent this attack ๐Ÿ˜ฌ BUT this attack is generally present in IP-based communications and TURN doesn't substantially make it worse ๐Ÿคทโ€โ™€๏ธ Picture a normal, non-TURN IP session between hosts A and B. An attacker can send packets to B as if they came from A by sending packets towards B with a spoofed IP address of A ๐ŸŽช This attack requires the attacker to know the IP addresses of A and B. With TURN, an attacker who wants to send packets towards a client using a Data indication needs to know its IP address (and port), the IP address and port of the TURN server, and the IP address and port of the peer (for inclusion in the XOR-PEER-ADDRESS attribute) ๐Ÿ“ To send a fake ChannelData message to a client, an attacker needs to know the IP address and port of the client, the IP address and port of the TURN server, and the channel number ๐Ÿ”ข This particular combination is mildly more guessable than in the non-TURN case ๐Ÿ‘€

These attacks are more properly mitigated by application-layer authentication techniques โœจ For real-time traffic, using SRTP [RFC3711] prevents these attacks ๐ŸŽง

In some situations, the TURN server may be sitting in the network in a way that lets it send to hosts the client can't directly reach ๐Ÿฐ This can happen, for example, if the server is behind a firewall that allows packets from outside the firewall to be delivered to the server, but not to other hosts behind the firewall ๐Ÿงฑ In these situations, an attacker could send the server a Send indication with an XOR-PEER-ADDRESS attribute containing the transport address of one of the other hosts behind the firewall ๐Ÿ˜ฑ If the server allowed relaying of traffic to arbitrary peers, that would give the attacker a way to attack arbitrary hosts behind the firewall ๐Ÿšจ

To mitigate this attack, TURN requires that the client establish a permission to a host before sending it data ๐Ÿ™Œ So an attacker can only attack hosts the client is already communicating with, unless the attacker is able to create authenticated requests ๐Ÿ”‘ On top of that, the server administrator may configure the server to restrict the range of IP addresses and ports it will relay data to ๐Ÿ—บ๏ธ For even greater security, the server administrator can require that the client use (D)TLS for all communication between the client and the server ๐Ÿ’–

21.1.5. Impersonating a Server

When a client learns a relayed address from a TURN server, it uses that relayed address in application protocols to receive traffic ๐Ÿ“ฌ So an attacker who wants to intercept or redirect that traffic might try to impersonate a TURN server and give the client a faked relayed address ๐Ÿฅท

This attack is prevented through the long-term credential mechanism, which provides message integrity for responses as well as verifying that they came from the server ๐Ÿ›ก๏ธ Furthermore, an attacker can't replay old server responses, because the transaction id in the STUN header prevents this ๐Ÿ™…โ€โ™€๏ธ Replay attacks are further thwarted through frequent changes to the nonce value ๐Ÿ”„

21.1.6. Eavesdropping Traffic โœจ

okay so bestie, this one is about who can peek at your TURN traffic ๐Ÿ‘€ and what you can do about it ๐Ÿ’…

If the TURN client and server use the STUN Extension for Third-Party Authorization [RFC7635] (it's a big deal in WebRTC ๐ŸŽ€), the username doesn't spill the real user's identity ๐Ÿ™ˆ. The USERNAME attribute carries an ephemeral and unique key identifier ๐Ÿฆ‹. But if the client and server use the STUN long-term credential mechanism and the username DOES reveal who the real user is, the client MUST either use the USERHASH attribute instead of the USERNAME attribute to anonymize the username ๐Ÿซถ, or use (D)TLS transport between the client and the server ๐Ÿ”’. No skipping this one, periodt ๐Ÿ’€.

If the TURN client and server use the STUN long-term credential mechanism and realm info is privacy sensitive, TURN can be run over (D)TLS ๐ŸŒธ. Quick reminder: the STUN Extension for Third-Party Authorization does not use realm ๐Ÿ’œ.

The SOFTWARE attribute can reveal the exact software version of the TURN client and server to an eavesdropper ๐Ÿ‘€, and that might let someone attack software that's known to have security holes ๐Ÿ˜ญ. So if the software version is known to contain security vulnerabilities, TURN SHOULD be run over (D)TLS so the SOFTWARE attribute doesn't leak in clear text ๐Ÿงš. And if zero-day vulnerabilities turn up in the software version, the endpoint policy can be changed to mandate (D)TLS until a patch fixes the flaw ๐Ÿ”ฅ.

Here's the big picture: TURN mainly cares about authentication and message integrity ๐Ÿ’–. Confidentiality is only a secondary concern, because TURN control messages don't carry anything super sensitive, except USERNAME, REALM, and SOFTWARE ๐Ÿ“. The main content is the IP address of the peer ๐Ÿฆ‹. If you really don't want an eavesdropper learning that, TURN can be run over (D)TLS โœจ.

Now, confidentiality for the application data relayed by TURN is best handled by the application protocol itself ๐Ÿ’…, because running TURN over (D)TLS does NOT protect application data between the server and the peer ๐Ÿ™ˆ. So if your data needs to stay private, the application should encrypt or otherwise protect it ๐Ÿ”. For real-time media, for example, you can get confidentiality by using SRTP ๐ŸŽ€.


21.1.7. TURN Loop Attack ๐Ÿ”

Okay this one is kind of wild ๐Ÿ˜ญ. An attacker might try to make data packets loop forever between two TURN servers ๐ŸŒ€. Here's how it goes: first, the attacker sends an Allocate request to server A but uses server B's source address ๐ŸŽญ. Server A sends its response to server B, and for this to work, the attacker has to be able to view or guess the contents of that response so they can learn the allocated relayed transport address ๐Ÿ‘€. Then the attacker sends an Allocate request to server B using server A's source address, and again they need to see or guess the response to learn that relayed transport address ๐Ÿ’€. Using the same spoofed source address trick, the attacker binds a channel number on server A to the relayed transport address on server B, and binds the same channel number on server B to the relayed transport address on server A ๐Ÿ”—. Finally, the attacker sends a ChannelData message to server A ๐Ÿš€.

The result is a data packet that bounces from the relayed transport address on server A to the relayed transport address on server B, then from server B's transport address to server A's transport address, and then around the loop again and again ๐ŸŒ€๐Ÿ˜ต.

Good news though: this attack gets mitigated ๐Ÿ›ก๏ธ. By requiring all requests to be authenticated and/or by randomizing the port number allocated for the relayed transport address, the server forces the attacker to either intercept or view responses sent to a third party (in this case, the other server) ๐Ÿ‘€, so the attacker can authenticate the requests and learn the relayed transport address. Without one of those two measures, an attacker can guess the contents of the responses without ever seeing them, which makes the attack way easier to pull off ๐Ÿ˜ค. Plus, by requiring authenticated requests, the server forces the attacker to have credentials the server accepts ๐ŸŽซ. That turns this from an outsider attack into an insider attack and lets the attack be traced back to the client starting it ๐Ÿ•ต๏ธโ€โ™€๏ธ.

The attack can be further mitigated by putting a per-username limit on the bandwidth used to relay data by allocations owned by that username ๐Ÿ’…, so the impact on other allocations stays small โœจ. More mitigation can come from decrementing the TTL when relaying data packets, if the underlying OS allows it ๐Ÿงš.


21.2. Firewall Considerations ๐Ÿงฑ

A key security consideration of TURN is that TURN should not weaken the protections that firewalls deployed between a client and a TURN server provide ๐Ÿ›ก๏ธ. TURN servers will often be on the public Internet ๐ŸŒ, and clients may often be inside enterprise networks with corporate firewalls ๐Ÿข. If TURN servers gave a "backdoor" into the enterprise, TURN would just get blocked by those firewalls ๐Ÿšซ. Bestie, nobody wants that ๐Ÿ˜ญ.

So TURN servers emulate the behavior of NAT devices that implement address-dependent filtering [RFC4787] ๐Ÿฆ‹, which is a property common in many firewalls too ๐Ÿ”ฅ. With that behavior, packets from an outside IP address are only allowed to reach an internal IP address and port if that internal address and port recently sent a packet to that outside IP address ๐Ÿ’œ. TURN servers introduce the concept of permissions, which give you exactly this same behavior on the TURN server ๐ŸŽ€. So an attacker cannot send a packet to a TURN server and expect it to be relayed toward the client, unless the client tried to contact the attacker first ๐Ÿ™…โ€โ™€๏ธ.

Some firewalls are even MORE restrictive than address-dependent filtering ๐Ÿ”’. Firewalls can also be set up with address- and port-dependent filtering, or they can be configured to disallow inbound traffic entirely ๐Ÿงฑ. In those cases, if a client is allowed to connect to the TURN server, communications to the client will be less restrictive than what the firewall would normally allow ๐Ÿ˜ฌ.


21.2.1. Faked Permissions ๐ŸŽญ

In firewalls and NAT devices, permissions are granted implicitly when a packet goes from the inside of the network toward the outside peer โœˆ๏ธ. So a permission can, by definition, only be created by an entity inside the firewall or NAT ๐Ÿ . With TURN, this restriction no longer holds ๐Ÿ˜ฑ. Since the TURN server sits outside the firewall, an attacker outside the firewall can now send a message to the TURN server and try to create a permission for itself ๐Ÿ’€.

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


21.2.2. Blacklisted IP Addresses ๐Ÿšซ

Lots of firewalls can be configured with blacklists that stop a client behind the firewall from sending packets to, or receiving packets from, ranges of blacklisted IP addresses ๐Ÿงฑ. This works by inspecting the source and destination addresses of packets entering and exiting the firewall, respectively ๐Ÿ‘€.

This feature is also present in TURN, since TURN servers are allowed to arbitrarily restrict the range of addresses of peers they will relay to ๐Ÿ’…โœจ.


21.2.3. Running Servers on Well-Known Ports ๐Ÿ”Œ

A malicious client behind a firewall might try to connect to a TURN server and obtain an allocation that it then uses to run a server ๐Ÿ˜ค. For example, a client might try to run a DNS server or an FTP server ๐Ÿ™ˆ.

This is NOT possible in TURN ๐Ÿ™…โ€โ™€๏ธ. A TURN server will never accept traffic from a peer for which the client has not installed a permission ๐Ÿ›‘. So peers can't just connect to the allocated port to get the service ๐Ÿ’–.


21.3. Insider Attacks ๐Ÿ˜ˆ

In insider attacks, a client has legitimate credentials but defies the trust relationship that comes with those credentials ๐Ÿ’”. These attacks cannot be prevented by cryptographic means, so they need to be considered in the design of the protocol ๐Ÿง .


21.3.1. DoS against TURN Server ๐Ÿ’ฅ

A client wishing to disrupt service to other clients might obtain an allocation and then flood it with traffic, trying to swamp the server and stop it from serving other legit clients ๐Ÿ˜ค. This is mitigated by the recommendation that the server limit the amount of bandwidth it will relay for a given username ๐Ÿ›ก๏ธ. This won't stop a client from sending a huge amount of traffic, but it lets the server immediately discard the excess ๐Ÿ—‘๏ธโœจ.

Since each allocation uses a port number on the IP address of the TURN server, the number of allocations on a server is finite ๐Ÿ”ข. An attacker might try to eat all of them by requesting a ton of allocations ๐Ÿฝ๏ธ. This is prevented by the recommendation that the server impose a limit on the number of allocations active at a time for a given username ๐ŸŽ€.


21.3.2. Anonymous Relaying of Malicious Traffic ๐Ÿ•ถ๏ธ

TURN servers provide a degree of anonymization ๐ŸŽญ. A client can send data to peers without revealing its own IP address ๐Ÿ‘ป. Which means TURN servers may become attractive vehicles for attackers to launch attacks against targets without fear of detection ๐Ÿ˜ˆ. Indeed, it's possible for a client to chain together multiple TURN servers so that any number of relays get used before a target receives a packet ๐Ÿ”—๐Ÿ˜ต.

Administrators who are worried about this can keep logs that capture the actual source IP and port of the client, and maybe even every permission that client installs ๐Ÿ“. That will allow for forensic tracing to figure out the original source if it's discovered that an attack is being relayed through a TURN server ๐Ÿ•ต๏ธโ€โ™€๏ธ๐Ÿ’œ.


21.3.3. Manipulating Other Allocations ๐Ÿงฉ

An attacker might try to disrupt service to other users of the TURN server by sending Refresh requests or CreatePermission requests that (through source address spoofing) look like they're coming from another user of the TURN server ๐ŸŽญ. TURN prevents this by requiring that the credentials used in CreatePermission, Refresh, and ChannelBind messages match the ones used to create the initial allocation ๐Ÿ”. So the fake requests from the attacker get rejected ๐Ÿ™…โ€โ™€๏ธโœจ.

21.4. Tunnel Amplification Attack ๐ŸŒ€

okay so this one is giving "amplification gone wild" ๐Ÿ˜ญ An attacker might try to make data packets loop over and over between a TURN server and a tunnel running between IPv4 and IPv6. Here's how it goes:

Suppose he knows that a tunnel endpoint will forward encapsulated packets from a given IPv6 address (this doesn't necessarily need to be the tunnel endpoint's address). Then he spoofs two packets from that address:

  1. An Allocate request asking for a v4 address, and
  2. A ChannelBind request establishing a channel to the IPv4 address of the tunnel endpoint.

And just like that, he has set up an amplification attack ๐Ÿ’ฅ

  • The TURN server will re-encapsulate IPv6 UDP data in v4 and send it to the tunnel endpoint.
  • The tunnel endpoint will de-encapsulate packets from the v4 interface and send them to v6.

So if the attacker sends a packet of the following form:

  IPv6: src=2001:DB8:1::1 dst=2001:DB8::2
  UDP:  <ports>
  TURN: <channel id>
  IPv6: src=2001:DB8:1::1 dst=2001:DB8::2
  UDP:  <ports>
  TURN: <channel id>
  IPv6: src=2001:DB8:1::1 dst=2001:DB8::2
  UDP:  <ports>
  TURN: <channel id>
  ...

Figure 19

then the TURN server and the tunnel endpoint will keep sending it back and forth until the last TURN header is consumed ๐Ÿ”. At that point the TURN server sends an empty packet, and the tunnel endpoint drops it ๐Ÿซถ

The amplification potential here is limited by the MTU, so it's not huge ๐Ÿ™ˆ IPv6+UDP+TURN takes 334 bytes, so a four-to-one amplification out of a 1500-byte packet is possible. BUT the attacker could still crank up the traffic volume by sending multiple packets or by establishing multiple channels spoofed from different addresses behind the same tunnel endpoint. not ideal, bestie ๐Ÿ’€

The attack is mitigated as follows. It is RECOMMENDED that TURN servers not accept allocation or channel-binding requests from addresses known to be tunneled, and that they not forward data to such addresses. In particular, a TURN server MUST NOT accept Teredo or 6to4 addresses in these requests. main character energy: blocked ๐ŸŒˆ


21.5. Other Considerations ๐Ÿงฉ

Any relay addresses learned through an Allocate request will not operate properly with IPsec Authentication Header (AH) [RFC4302] in transport or tunnel mode. However, tunnel-mode IPsec Encapsulating Security Payload (ESP) [RFC4303] should still operate โœจ


22. IANA Considerations ๐Ÿ“‹

The code points for the STUN methods defined in this specification are listed in Section 17. IANA has updated the references from [RFC5766] to this document (for the STUN methods listed in Section 17).

The code points for the STUN attributes defined in this specification are listed in Section 18. IANA has updated the references from [RFC5766] to this document (for the STUN attributes CHANNEL-NUMBER, LIFETIME, Reserved (was BANDWIDTH), XOR-PEER-ADDRESS, DATA, XOR-RELAYED-ADDRESS, REQUESTED-ADDRESS-FAMILY, EVEN-PORT, REQUESTED-TRANSPORT, DONT-FRAGMENT, Reserved (was TIMER-VAL), and RESERVATION-TOKEN listed in Section 18).

The code points for the STUN error codes defined in this specification are listed in Section 19. IANA has updated the references from [RFC5766] and [RFC6156] to this document (for the STUN error codes listed in Section 19).

IANA has updated the references to [RFC5766] to this document for the SRV service name of "turn" for TURN over UDP or TCP and the service name of "turns" for TURN over (D)TLS.

IANA has created a registry for TURN channel numbers (the "Traversal Using Relays around NAT (TURN) Channel Numbers" registry), initially populated as follows:

+------------------------+------------------------------------------+
| 0x0000 through         | Reserved and not available for use since |
| 0x3FFF:                | they conflict with the STUN header.      |
+------------------------+------------------------------------------+
| 0x4000 through         | A TURN implementation is free to use     |
| 0x4FFF:                | channel numbers in this range.           |
+------------------------+------------------------------------------+
| 0x5000 through         | Reserved (For DTLS-SRTP multiplexing     |
| 0xFFFF:                | collision avoidance, see [RFC7983])      |
+------------------------+------------------------------------------+

Table 6

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


23. IAB Considerations ๐Ÿ›๏ธ

The IAB has studied the problem of Unilateral Self-Address Fixing (UNSAF), which is the general process by which a client attempts to determine its address in another realm on the other side of a NAT through a collaborative protocol reflection mechanism [RFC3424]. The TURN extension is an example of a protocol that performs this type of function. The IAB has mandated that any protocols developed for this purpose document a specific set of considerations. These considerations and the responses for TURN are documented in this section.

Consideration 1: Precise definition of a specific, limited-scope problem that is to be solved with the UNSAF proposal. A short-term fix should not be generalized to solve other problems. Such generalizations lead to the prolonged dependence on and usage of the supposed short-term fix, meaning that it is no longer accurate to call it "short-term" ๐Ÿ™ƒ

Response: TURN is a protocol for communication between a relay (= TURN server) and its client. The protocol allows a client that is behind a NAT to obtain and use a public IP address on the relay. As a convenience to the client, TURN also allows the client to determine its server-reflexive transport address.

Consideration 2: Description of an exit strategy/transition plan. The better short-term fixes are the ones that will naturally see less and less use as the appropriate technology is deployed.

Response: TURN will no longer be needed once there are no longer any NATs. Unfortunately, as of the date of publication of this document, it no longer seems very likely that NATs will go away any time soon ๐Ÿ˜ญ However, the need for TURN will also decrease as the number of NATs with the mapping property of Endpoint-Independent Mapping [RFC4787] increases.

Consideration 3: Discussion of specific issues that may render systems more "brittle". For example, approaches that involve using data at multiple network layers create more dependencies, increase debugging challenges, and make it harder to transition.

Response: TURN is "brittle" in that it requires the NAT bindings between the client and the server to be maintained unchanged for the lifetime of the allocation. This is typically done using keep-alives. If this is not done, then the client will lose its allocation and can no longer exchange data with its peers ๐Ÿฅ€

Consideration 4: Identify requirements for longer-term, sound technical solutions; contribute to the process of finding the right longer-term solution.

Response: The need for TURN will be reduced once NATs implement the recommendations for NAT UDP behavior documented in [RFC4787]. Applications are also strongly urged to use ICE [RFC8445] to communicate with peers; though ICE uses TURN, it does so only as a last resort, and it uses it in a controlled manner ๐Ÿ’–

Consideration 5: Discussion of the impact of the noted practical issues with existing deployed NATs and experience reports.

Response: Some NATs deployed today exhibit a mapping behavior other than Endpoint-Independent mapping. These NATs are difficult to work with, as they make it difficult or impossible for protocols like ICE to use server-reflexive transport addresses on those NATs. A client behind such a NAT is often forced to use a relay protocol like TURN because "UDP hole punching" techniques [RFC5128] do not work. the NAT really said no ๐Ÿ™…โ€โ™€๏ธ


24. Changes since RFC 5766 ๐Ÿ†•

This section lists the major changes in the TURN protocol from the original [RFC5766] specification.

  • IPv6 support.
  • REQUESTED-ADDRESS-FAMILY attribute.
  • Description of the tunnel amplification attack.
  • DTLS support.
  • Add support for receiving ICMP packets.
  • Updates PMTUD.
  • Discovery of TURN server.
  • TURN URI Scheme Semantics.
  • Happy Eyeballs for TURN.
  • Align with the changes in STUN [RFC8489].

25. Updates to RFC 6156 ๐Ÿ”„

This section lists the major updates to [RFC6156] in this specification.

  • ADDITIONAL-ADDRESS-FAMILY and ADDRESS-ERROR-CODE attributes.
  • 440 (Address Family not Supported) and 443 (Peer Address Family Mismatch) responses.
  • More details on packet translation.
  • TCP-to-UDP and UDP-to-TCP relaying.

26. References ๐Ÿ“š

26.1. Normative References โœจ

okay so this is the list of docs that RFC 8656 totally leans on, bestie ๐Ÿ“š๐Ÿ’– the "normative" ones are the stuff you NEED to know to get the spec right, so these are the main character references ๐Ÿ‘‘

   [PROTOCOL-NUMBERS]
              IANA, "Protocol Numbers",
              <https://www.iana.org/assignments/protocol-numbers>.

   [RFC0792]  Postel, J., "Internet Control Message Protocol", STD 5,
              RFC 792, DOI 10.17487/RFC0792, September 1981,
              <https://www.rfc-editor.org/info/rfc792>.

   [RFC1122]  Braden, R., Ed., "Requirements for Internet Hosts -
              Communication Layers", STD 3, RFC 1122,
              DOI 10.17487/RFC1122, October 1989,
              <https://www.rfc-editor.org/info/rfc1122>.

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119,
              DOI 10.17487/RFC2119, March 1997,
              <https://www.rfc-editor.org/info/rfc2119>.

   [RFC2474]  Nichols, K., Blake, S., Baker, F., and D. Black,
              "Definition of the Differentiated Services Field (DS
              Field) in the IPv4 and IPv6 Headers", RFC 2474,
              DOI 10.17487/RFC2474, December 1998,
              <https://www.rfc-editor.org/info/rfc2474>.

   [RFC3168]  Ramakrishnan, K., Floyd, S., and D. Black, "The Addition
              of Explicit Congestion Notification (ECN) to IP",
              RFC 3168, DOI 10.17487/RFC3168, September 2001,
              <https://www.rfc-editor.org/info/rfc3168>.

   [RFC3629]  Yergeau, F., "UTF-8, a transformation format of ISO
              10646", STD 63, RFC 3629, DOI 10.17487/RFC3629, November
              2003, <https://www.rfc-editor.org/info/rfc3629>.

   [RFC4443]  Conta, A., Deering, S., and M. Gupta, Ed., "Internet
              Control Message Protocol (ICMPv6) for the Internet
              Protocol Version 6 (IPv6) Specification", STD 89,
              RFC 4443, DOI 10.17487/RFC4443, March 2006,
              <https://www.rfc-editor.org/info/rfc4443>.

   [RFC6347]  Rescorla, E. and N. Modadugu, "Datagram Transport Layer
              Security Version 1.2", RFC 6347, DOI 10.17487/RFC6347,
              January 2012, <https://www.rfc-editor.org/info/rfc6347>.

   [RFC6437]  Amante, S., Carpenter, B., Jiang, S., and J. Rajahalme,
              "IPv6 Flow Label Specification", RFC 6437,
              DOI 10.17487/RFC6437, November 2011,
              <https://www.rfc-editor.org/info/rfc6437>.

   [RFC7065]  Petit-Huguenin, M., Nandakumar, S., Salgueiro, G., and P.
              Jones, "Traversal Using Relays around NAT (TURN) Uniform
              Resource Identifiers", RFC 7065, DOI 10.17487/RFC7065,
              November 2013, <https://www.rfc-editor.org/info/rfc7065>.

   [RFC7350]  Petit-Huguenin, M. and G. Salgueiro, "Datagram Transport
              Layer Security (DTLS) as Transport for Session Traversal
              Utilities for NAT (STUN)", RFC 7350, DOI 10.17487/RFC7350,
              August 2014, <https://www.rfc-editor.org/info/rfc7350>.

   [RFC7525]  Sheffer, Y., Holz, R., and P. Saint-Andre,
              "Recommendations for Secure Use of Transport Layer
              Security (TLS) and Datagram Transport Layer Security
              (DTLS)", BCP 195, RFC 7525, DOI 10.17487/RFC7525, May
              2015, <https://www.rfc-editor.org/info/rfc7525>.

   [RFC7915]  Bao, C., Li, X., Baker, F., Anderson, T., and F. Gont,
              "IP/ICMP Translation Algorithm", RFC 7915,
              DOI 10.17487/RFC7915, June 2016,
              <https://www.rfc-editor.org/info/rfc7915>.

   [RFC7982]  Martinsen, P., Reddy, T., Wing, D., and V. Singh,
              "Measurement of Round-Trip Time and Fractional Loss Using
              Session Traversal Utilities for NAT (STUN)", RFC 7982,
              DOI 10.17487/RFC7982, September 2016,
              <https://www.rfc-editor.org/info/rfc7982>.

   [RFC8174]  Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
              2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
              May 2017, <https://www.rfc-editor.org/info/rfc8174>.

   [RFC8200]  Deering, S. and R. Hinden, "Internet Protocol, Version 6
              (IPv6) Specification", STD 86, RFC 8200,
              DOI 10.17487/RFC8200, July 2017,
              <https://www.rfc-editor.org/info/rfc8200>.

   [RFC8305]  Schinazi, D. and T. Pauly, "Happy Eyeballs Version 2:
              Better Connectivity Using Concurrency", RFC 8305,
              DOI 10.17487/RFC8305, December 2017,
              <https://www.rfc-editor.org/info/rfc8305>.

   [RFC8446]  Rescorla, E., "The Transport Layer Security (TLS) Protocol
              Version 1.3", RFC 8446, DOI 10.17487/RFC8446, August 2018,
              <https://www.rfc-editor.org/info/rfc8446>.

   [RFC8489]  Petit-Huguenin, M., Salgueiro, G., Rosenberg, J., Wing,
              D., Mahy, R., and P. Matthews, "Session Traversal
              Utilities for NAT (STUN)", RFC 8489, DOI 10.17487/RFC8489,
              February 2020, <https://www.rfc-editor.org/info/rfc8489>.

26.2. Informative References โœจ

okay bestie, this is the reading list for the "for context" stuff ๐Ÿ“š๐Ÿซถ none of these are strictly required to use TURN, but they're the receipts behind the vibes.


Acknowledgements

okay the credits era ๐Ÿซถโœจ most of the words in this doc are lifted from the original TURN spec, [RFC5766], and we're SO grateful to Rohan Mahy, who co-wrote that original, plus everyone who helped on it ๐Ÿ’œ. The authors also want to shout out that this doc inherits some material from [RFC6156] ๐Ÿ™Œ.

Huge thanks to Justin Uberti, Pal Martinsen, Oleg Moskalenko, Aijun Wang, and Simon Perreault for helping out with the ADDITIONAL-ADDRESS-FAMILY mechanism ๐ŸŒธ. Thank you also to Gonzalo Salgueiro, Simon Perreault, Jonathan Lennox, Brandon Williams, Karl Stahl, Noriyuki Torii, Nils Ohlmeier, Dan Wing, Vijay Gurbani, Joseph Touch, Justin Uberti, Christopher Wood, Roman Danyliw, Eric Vyncke, Adam Roach, Suresh Krishnan, Mirja Kuehlewind, Benjamin Kaduk, and Oleg Moskalenko for their comments and reviews ๐Ÿ“. The authors also thank Marc Petit-Huguenin for his contributions to the text ๐Ÿ’….

Special thanks to Magnus Westerlund for the detailed AD review ๐ŸŽ€


Authors' Addresses

Tirumaleswar Reddy (editor) ๐Ÿ‘‘

McAfee, Inc.
Embassy Golf Link Business Park
Bangalore 560071
Karnataka
India

Email: kondtir@gmail.com

Alan Johnston (editor) ๐Ÿฆ‹

Villanova University
Villanova, PA
United States of America

Email: alan.b.johnston@gmail.com

Philip Matthews ๐ŸŒˆ

Alcatel-Lucent
600 March Road
Ottawa Ontario
Canada

Email: philip_matthews@magma.ca

Jonathan Rosenberg ๐Ÿ’œ

jdrosen.net
Edison, NJ
United States of America

Email: jdrosen@jdrosen.net URI: http://www.jdrosen.net

That's the whole spec, bestie! ๐ŸŽ‰๐Ÿ’– TURN is officially a wrap โœจ

๐Ÿ“ฆ where this page comes from