RFC 8016

Mobility with Traversal Using Relays around NAT (TURN)

πŸ“… published November 2016, from ietf

RFC 8016: Mobility with Traversal Using Relays around NAT (TURN) πŸ¦‹

  • RFC number: 8016
  • Category: Standards Track, which means it's an official Internet Standards Track doc that the IESG approved after public review πŸ”₯
  • Date: November 2016
  • ISSN: 2070-1721
  • Authors: T. Reddy, D. Wing, P. Patil, and P. Martinsen, all from Cisco πŸ’…
  • Obsoletes / Updates: the header doesn't list either one, so this doc doesn't obsolete or update anything 🌸

Abstract

Okay so minimizing traffic disruption when your IP address changes during a mobility event is a HUGE deal 😭 One way to do it is to expose a shorter network path to the mobility event, so only the local network elements know the IP address changed and the remote peer stays totally unaware 🫢

This document gives you an IP address mobility solution using Traversal Using Relays around NAT (TURN). The main move is letting a client keep its allocation on the TURN server even after its IP address changes ✨

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 got public review before the Internet Engineering Steering Group (IESG) approved it for publication πŸ‘‘ If you want more info on Internet Standards, check out Section 2 of RFC 7841.

For the current status, any errata, and how to send feedback, go to http://www.rfc-editor.org/info/rfc8016 πŸ’œ

Copyright (c) 2016 IETF Trust and the persons identified as the document authors. All rights reserved. 🌈

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) as they were in effect on the date of publication. Please read these carefully, bestie, because they spell out your rights and restrictions for 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 come without warranty as described in the Simplified BSD License πŸ“œ

Table of Contents

1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   3
2.  Notational Conventions  . . . . . . . . . . . . . . . . . . .   4
3.  Mobility Using TURN . . . . . . . . . . . . . . . . . . . . .   4
  3.1.  Creating an Allocation  . . . . . . . . . . . . . . . . .   5
    3.1.1.  Sending an Allocate Request . . . . . . . . . . . . .   5
    3.1.2.  Receiving an Allocate Request . . . . . . . . . . . .   6
    3.1.3.  Receiving an Allocate Success Response  . . . . . . .   6
    3.1.4.  Receiving an Allocate Error Response  . . . . . . . .   7
  3.2.  Refreshing an Allocation  . . . . . . . . . . . . . . . .   7
    3.2.1.  Sending a Refresh Request . . . . . . . . . . . . . .   7
    3.2.2.  Receiving a Refresh Request . . . . . . . . . . . . .   7
    3.2.3.  Receiving a Refresh Response  . . . . . . . . . . . .   9
  3.3.  New STUN Attribute MOBILITY-TICKET  . . . . . . . . . . .   9
  3.4.  New STUN Error Response Code  . . . . . . . . . . . . . .   9
4.  IANA Considerations . . . . . . . . . . . . . . . . . . . . .   9
5.  Security Considerations . . . . . . . . . . . . . . . . . . .   9
6.  References  . . . . . . . . . . . . . . . . . . . . . . . . .  10
  6.1.  Normative References  . . . . . . . . . . . . . . . . . .  10
  6.2.  Informative References  . . . . . . . . . . . . . . . . .  11
Appendix A.  Example of Ticket Construction . . . . . . . . . . .  12
Acknowledgements  . . . . . . . . . . . . . . . . . . . . . . . .  13
Authors' Addresses  . . . . . . . . . . . . . . . . . . . . . . .  13

1. Introduction ✨

When you move between networks, the endpoint's IP address can change. Or, because of NAT, the endpoint's public IP address can change. Either way, that IP address change breaks upper-layer protocols like TCP and RTP 😭 There are a bunch of techniques to stop that breakage, and they all work by making the endpoint's IP address static (for example, Mobile IP, Proxy Mobile IP, and Locator/ID Separation Protocol (LISP)). Other techniques make the IP address change invisible to the upper-layer protocol (for example, Stream Control Transmission Protocol (SCTP)). The mechanism in this document belongs to that last group πŸ¦‹

A server using Traversal Using Relays around NAT (TURN) [RFC5766] relays media packets, and it's used for lots of things, including getting past NAT and firewall traversal issues 🌸 The existing TURN spec doesn't let a TURN client reuse an allocation across client IP address changes, which is kind of a lot of drama πŸ’€ So when the client's IP address changes, the TURN client has to request a brand-new allocation, create permissions for the remote peer, create channels, and so on. On top of that, the client has to re-establish communication with its signaling server and send an updated offer to the remote peer that carries the newly relayed candidate address. Then the remote side has to re-gather all candidates and signal them to the client, and the endpoints have to perform Interactive Connectivity Establishment (ICE) [RFC5245] checks. If the ICE continuous nomination procedure [NOMBIS] is used, the newly relayed candidate address has to be "trickled" (that means incrementally provisioned as described in [TRICKLE-SIP]), and ICE checks have to be performed according to [TRICKLE-ICE] by the endpoints so they can nominate pairs for ICE to select 😩

This specification describes a way to seamlessly reuse allocations across client IP address changes without any of the hassles above πŸŽ€ The big benefit is that the remote peer doesn't have to support mobility or deal with any of the address changes. The client, which is the one dealing with IP address changes, does all the work πŸ’… The technique works across and between network types (for example, between 3G and wired Internet access), as long as the client can still reach the TURN server. The technique should also work seamlessly when (D)TLS is used as a transport protocol for Session Traversal Utilities for NAT (STUN) [RFC5389]. When the IP address changes, the client uses (D)TLS Session Resumption without Server-Side State, as described in [RFC5077], to resume secure communication with the TURN server using the changed client IP address πŸ”

2. Notational Conventions πŸ“š

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

This document uses terminology defined in [RFC5245], plus the following extra terms 🧚

Break Before Make: The old communication path gets broken ("break") before the new one can be created ("make"). This usually happens when a network's physical cable gets unplugged, radio transmission gets turned off, or a client moves out of radio range πŸ“΄

Make Before Break: A new communication path gets created ("make") before the old one gets broken ("break"). This usually happens when a network gets plugged back in with a physical cable, radio transmission gets turned on, or a client moves into radio range πŸ“Ά

3. Mobility Using TURN πŸ¦‹

To get mobility, a TURN client should be able to keep an allocation on the TURN server while the client IP address changes as a result of moving to other networks. Main character energy πŸ‘‘

When the client sends the initial Allocate request to the TURN server, it includes a new STUN attribute called MOBILITY-TICKET with a zero length value. That tells the server the client can handle mobility and wants a ticket 🎫 The TURN server then provisions a ticket and sends it back inside the new MOBILITY-TICKET STUN attribute in the Allocate success response. The client uses that ticket when it wants to refresh the allocation with a new client IP address and port. This makes sure only the same client that got the relayed transport address can refresh that allocation πŸ”’ When the client's IP address changes because of mobility, it sends the ticket it got earlier in a Refresh request to the TURN server. If the ticket checks out as valid, the TURN server keeps the same relayed address and port for the new IP address and port. The client can keep using its previous channel bindings, so the TURN client doesn't have to get new channel bindings at all πŸ™Œ Any data from the external peer gets delivered by the TURN server to the client's new IP address and port. The TURN client keeps sending application data to its peers over the previously allocated channelBind Requests ✨

      TURN                                 TURN           Peer
      client                               server          A
        |-- Allocate request --------------->|             |
        |   + MOBILITY-TICKET (length=0)     |             |
        |                                    |             |
        |<--------------- Allocate failure --|             |
        |                 (401 Unauthorized) |             |
        |                                    |             |
        |-- Allocate request --------------->|             |
        |   + MOBILITY-TICKET (length=0)     |             |
        |                                    |             |
        |<---------- Allocate success resp --|             |
        |            + MOBILITY-TICKET       |             |
       ...                                  ...           ...
    (changes IP address)
        |                                    |             |
        |-- Refresh request ---------------->|             |
        |   + MOBILITY-TICKET                |             |
        |                                    |             |
        |<----------- Refresh success resp --|             |
        |   + MOBILITY-TICKET                |             |
        |                                    |             |

Figure 1: Mobility Using TURN

Okay, so in Figure 1, the client sends an Allocate request with a MOBILITY-TICKET attribute to the server without credentials πŸ™ˆ The server requires that every request be authenticated using STUN's long-term credential mechanism, so it rejects the request with a 401 (Unauthorized) error code. The client then tries again, this time with credentials (not shown in the figure). This time the server accepts the Allocate request and returns an Allocate success response with a ticket inside the MOBILITY-TICKET attribute. Later on, the client's IP address changes, and the client decides to refresh the allocation. So it sends a Refresh request to the server with a MOBILITY-TICKET attribute holding the ticket it got from the server. The refresh gets accepted, and the server replies with a Refresh success response and a new ticket inside the MOBILITY-TICKET attribute πŸ₯Ή

3.1. Creating an Allocation πŸ“

3.1.1. Sending an Allocate Request πŸ“€

In addition to the process described in Section 6.1 of [RFC5766], the client includes the MOBILITY-TICKET attribute with a length of zero. That signals the client is a mobile node and wants a ticket πŸŽ€

3.1.2. Receiving an Allocate Request ✨

Okay so, on top of everything in Section 6.2 of [RFC5766], the server has some extra stuff to check πŸ’…

If the MOBILITY-TICKET attribute is included with a length of zero, but local policy forbids TURN session mobility, the server will reject the request with the new error code 405 (Mobility Forbidden). 🚫 If the MOBILITY-TICKET attribute is included and has a non-zero length, the server will send back an error response with error code 400 (Bad Request). πŸ™…β€β™€οΈ And following the rules in [RFC5389], if the server doesn't understand the MOBILITY-TICKET attribute, it just ignores it. Chill, no drama 🫢

If the server can process the request and create an allocation, it replies with a success response that includes a STUN MOBILITY-TICKET attribute. πŸŽ€ The TURN server can stash system-internal data in the ticket, encrypted with a key that only the TURN server knows, and then sends that ticket back in the STUN MOBILITY-TICKET attribute as part of the Allocate success response. Appendix A has an example of how a ticket gets built ✨ The ticket is opaque to the client, so its structure isn't an interoperability concern, and implementations may diverge from this format. πŸ¦‹

Here's why this matters: the client could be roaming across networks with a different path MTU, and it could even hop from one address family to another (for example, IPv6 to IPv4). 🌈 So a TURN server that supports mobility must assume that the path MTU is unknown, and it uses a ticket length that follows the published guidance on STUN UDP fragmentation (Section 7.1 of [RFC5389]). It's giving "plan for the worst" energy πŸ’œ

Note: There is no guarantee that the fields in the ticket are going to be decodable to a client, and therefore attempts by a client to examine the ticket are unlikely to be useful. πŸ™ˆ

3.1.3. Receiving an Allocate Success Response 🌸

On top of the process in Section 6.3 of [RFC5766], the client stores the MOBILITY-TICKET attribute if it's present in the response. πŸ’– The client then presents this attribute to the server during a later Refresh request to help with mobility. Main character energy for the ticket, honestly πŸ‘‘

3.1.4. Receiving an Allocate Error Response πŸ™ˆ

If the client gets an Allocate error response with error code 405 (Mobility Forbidden), it handles the error like this:

405 (Mobility Forbidden): The request is valid, but the server is refusing to perform it, likely due to administrative restrictions. The client considers the current transaction as having failed. The client can notify the user or operator. The client SHOULD NOT retry sending the Allocate request containing the MOBILITY-TICKET with this server until it believes the problem has been fixed. πŸ™…β€β™€οΈ

Every other error response gets handled the way [RFC5766] describes 🧚


3.2. Refreshing an Allocation πŸ”₯

3.2.1. Sending a Refresh Request πŸ“

If a client wants to refresh an existing allocation (update its time-to-expiry) or delete one, it sends a Refresh request as described in Section 7.1 of [RFC5766]. πŸ’… If the client's IP address or source port has changed and it still wants to keep the existing allocation, it includes the MOBILITY-TICKET attribute it got in the Allocate success response inside the Refresh request. πŸ¦‹ But if the IP address and source port haven't changed, the client MUST NOT include a MOBILITY-TICKET attribute. Why? Because the server would reject it, and then the client would have to retransmit the Refresh request without the MOBILITY-TICKET attribute anyway. Extra step, zero reason 😭

3.2.2. Receiving a Refresh Request 🌈

On top of the process in Section 7.2 of [RFC5766], the server does the following:

If the STUN MOBILITY-TICKET attribute is in the Refresh request, and the server configuration has changed to forbid mobility, or the server quietly fails over to another server instance that forbids mobility, then the server rejects the Refresh request with a 405 (Mobility Forbidden) error. The client then starts afresh with a new allocation. πŸ’€

If the STUN MOBILITY-TICKET attribute is in the Refresh request, the server does NOT look at the 5-tuple from the packet to find the matching allocation. πŸ™ƒ Instead, the TURN server decrypts the received ticket, verifies that it's valid, and uses the ticket to retrieve the 5-tuple allocation. If that 5-tuple doesn't identify an existing allocation, the server MUST reject the request with a 437 (Allocation Mismatch) error. And if the ticket is invalid, the server MUST reject the request with a 400 (Bad Request) error. 🚫

If the source IP address and port of the Refresh request with the STUN MOBILITY-TICKET attribute match the stored 5-tuple allocation, the TURN server rejects the request with a 400 (Bad Request) error. πŸ™…β€β™€οΈ If the source IP address and port are different from the stored 5-tuple allocation, the TURN server runs a MESSAGE-INTEGRITY validation to confirm it's the same user who created the TURN allocation. If that check fails, the server MUST reject the request with a 441 (Wrong Credentials) error. πŸ”

If all of the above checks pass, the TURN server understands that the client has either moved to a new network and picked up a new IP address (Break Before Make), or it's in the middle of switching to a new interface (Make Before Break). ✨ The source IP address of the request could be either the host transport address or the server-reflexive transport address. The server then updates its state data with the new client IP address and port, but it does NOT throw away the old 5-tuple from its state data yet. 🫢 The TURN server calculates the ticket using the new 5-tuple and sends the new ticket in the STUN MOBILITY-TICKET attribute as part of the Refresh success response. The new ticket sent in the refresh response MUST be different from the old ticket. πŸ¦‹

The TURN server MUST continue receiving and processing data on the old 5-tuple, and MUST continue transmitting data on the old 5-tuple, until it gets either a Send Indication or ChannelData message from the client on the new 5-tuple, or a message from the client closing the old connection (for example, a TLS fatal alert or TCP RST). 🌸 Once it gets any of those messages, the TURN server discards the old ticket and the old 5-tuple associated with that ticket from its state data. 🧹 Data the client sends to the peer is accepted on the new 5-tuple, and data received from the peer is forwarded to the new 5-tuple. πŸ’œ If the refresh request containing the MOBILITY-TICKET attribute doesn't succeed (for example, the packet gets lost if the request is sent over UDP, or the server can't fulfill the request), then the client can keep exchanging data on the old 5-tuple until it receives the Refresh success response. πŸ™

The old ticket can only be used for retransmission. πŸ” If the client wants to refresh its allocation with a new server-reflexive transport address, it MUST use the new ticket. And if the TURN server hasn't received a Refresh request with the STUN MOBILITY-TICKET attribute but still gets Send indications or ChannelData messages from a client, the TURN server MAY discard or queue those Send indications or ChannelData messages, at its discretion. πŸ€·β€β™€οΈ So, it is RECOMMENDED that the client avoid transmitting a Send indication or ChannelData message until it has received an acknowledgement for the Refresh request with the STUN MOBILITY-TICKET attribute. Patience is a vibe πŸ§˜β€β™€οΈ

To handle the possibility of Refresh responses getting lost, a server must retain the old STUN MOBILITY-TICKET attribute for a period of at least 30 seconds, so it can recognize a retransmission of the Refresh request carrying the old STUN MOBILITY-TICKET attribute from the client. ⏳

3.2.3. Receiving a Refresh Response πŸŽ€

On top of the process in Section 7.3 of [RFC5766], the client stores the MOBILITY-TICKET attribute if it's present in the response. πŸ’– The client then presents this attribute to the server during a later Refresh request to help with mobility. Same ticket energy, every single time 😌

3.3. New STUN Attribute MOBILITY-TICKET πŸ¦‹

This attribute is used to retain an allocation on the TURN server. πŸ”’ It's exchanged between the client and server to help with mobility. The value of the MOBILITY-TICKET is encrypted and has variable length. πŸŒ™

3.4. New STUN Error Response Code 🚫

This document defines the following new error response code:

405 (Mobility Forbidden): Mobility request was valid but cannot be performed due to administrative or similar restrictions. πŸ’…

4. IANA Considerations 🌷

IANA has added the following attribute to the "STUN Attributes" registry [IANA-STUN]:

  • MOBILITY-TICKET (0x8030, in the comprehension-optional range)

IANA has also added a new STUN error code, "Mobility Forbidden" with the value 405, to the "STUN Error Codes" registry [IANA-STUN]. πŸŽ‰

5. Security Considerations πŸ”

This part is serious, bestie, so pay attention 😀 The TURN server MUST always ensure that the ticket is authenticated and encrypted using strong cryptographic algorithms, so an attacker can't modify it or eavesdrop on it. The ticket MUST be constructed so that it has strong entropy, which means nothing can be gleaned just by looking at the ticket alone. πŸ›‘οΈ

An attacker who monitors the traffic between the TURN client and server can impersonate the client and refresh the allocation, using the ticket that was issued to the client, with the attacker's IP address and port. πŸ‘€ To stop malicious users from impersonating the client, the TURN client and server MUST use the STUN long-term credential mechanism [RFC5389], the STUN Extension for Third-Party Authorization [RFC7635], or a (D)TLS connection. With any of those three mechanisms, when the server receives the Refresh request with the STUN MOBILITY-TICKET attribute from the client, it can tell that it really is the same client, just with a new IP address and port, by using the ticket it had previously issued to refresh the allocation. βœ… If (D)TLS isn't used, or the (D)TLS handshake fails, and authentication also fails, then the TURN client and server MUST fail and NOT proceed with TURN mobility. 🚨

Security considerations described in [RFC5766] also apply to this mechanism. πŸ’œ

6. References πŸ“š

6.1. Normative References 🌈

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

[RFC5077]  Salowey, J., Zhou, H., Eronen, P., and H. Tschofenig,
           "Transport Layer Security (TLS) Session Resumption without
           Server-Side State", RFC 5077, DOI 10.17487/RFC5077,
           January 2008, <http://www.rfc-editor.org/info/rfc5077>.

[RFC5245]  Rosenberg, J., "Interactive Connectivity Establishment
           (ICE): A Protocol for Network Address Translator (NAT)
           Traversal for Offer/Answer Protocols", RFC 5245,
           DOI 10.17487/RFC5245, April 2010,
           <http://www.rfc-editor.org/info/rfc5245>.

[RFC5389]  Rosenberg, J., Mahy, R., Matthews, P., and D. Wing,
           "Session Traversal Utilities for NAT (STUN)", RFC 5389,
           DOI 10.17487/RFC5389, October 2008,
           <http://www.rfc-editor.org/info/rfc5389>.

[RFC5766]  Mahy, R., Matthews, P., and J. Rosenberg, "Traversal Using
           Relays around NAT (TURN): Relay Extensions to Session
           Traversal Utilities for NAT (STUN)", RFC 5766,
           DOI 10.17487/RFC5766, April 2010,
           <http://www.rfc-editor.org/info/rfc5766>.

6.2. Informative References πŸ“šβœ¨

okay so these are the informative references, aka the extra reading that's good to know about but isn't required to build the thing πŸ€“ bestie, I'm obsessed with how the IANA registry is right here for STUN parameters πŸ¦‹

[IANA-STUN] IANA, "Session Traversal Utilities for NAT (STUN) Parameters", http://www.iana.org/assignments/stun-parameters.

[NOMBIS] Uberti, J. and J. Lennox, "Improvements to ICE Candidate Nomination", Work in Progress, draft-uberti-mmusic-nombis-00, March 2015.

[RFC7635] Reddy, T., Patil, P., Ravindranath, R., and J. Uberti, "Session Traversal Utilities for NAT (STUN) Extension for Third-Party Authorization", RFC 7635, DOI 10.17487/RFC7635, August 2015, http://www.rfc-editor.org/info/rfc7635. πŸ”₯

[TRICKLE-ICE] Ivov, E., Rescorla, E., Uberti, J., and P. Saint-Andre, "Trickle ICE: Incremental Provisioning of Candidates for the Interactive Connectivity Establishment (ICE) Protocol", Work in Progress, draft-ietf-ice-trickle-04, September 2016. 🌸

[TRICKLE-SIP] Ivov, E., Stach, T., Marocco, E., and C. Holmberg, "A Session Initiation Protocol (SIP) usage for Trickle ICE", Work in Progress, draft-ietf-mmusic-trickle-ice-sip-06, October 2016. πŸ’œ


Appendix A. Example of Ticket Construction πŸŽ€

okay this appendix is where the ticket gets built, and it's giving cryptography with a little bow on top πŸ’… the TURN server uses two different keys: one 128-bit key for Advance Encryption Standard (AES) in Cipher Block Chaining (CBC) mode (AES_128_CBC), and a 256-bit key for HMAC-SHA-256-128 for integrity protection. the ticket can be structured like this:

struct {
    opaque key_name[16];
    opaque iv[16];
    opaque encrypted_state<0..2^16-1>;
    opaque mac[16];
} ticket;

                 Figure 2: Ticket Format

so, key_name is basically the ID badge for a particular set of keys used to protect the ticket πŸͺͺ it lets the TURN server easily recognize tickets it has issued. the key_name should be randomly generated to avoid collisions between servers, and one possibility is to generate new random keys and key_name every time the server is started 🧚

the TURN state information (which is either self-contained or a handle) in encrypted_state is encrypted using 128-bit AES in CBC mode with the given Initialization Vector (IV) ✨ and the Message Authentication Code (MAC) is calculated using HMAC-SHA-256-128 over key_name (16 octets) and IV (16 octets), followed by the length of the encrypted_state field (2 octets) and its contents (variable length). the MAC is the integrity check that keeps everything honest 🫢


Acknowledgements 🫢

thank you to Alfred Heggestad, Lishitao, Sujing Zhou, Martin Thomson, Emil Ivov, Oleg Moskalenko, Dave Waltermire, Pete Resnick, Antoni Przygienda, Alissa Cooper, Ben Campbell, Suresh Krishnan, Mirja Kuehlewind, Jonathan Lennox, and Brandon Williams for reviewing and commenting. you all are literally the real MVPs πŸ‘‘πŸ’–


Authors' Addresses πŸ’Œ

Tirumaleswar Reddy
Cisco Systems, Inc.
Cessna Business Park, Varthur Hobli
Sarjapur Marathalli Outer Ring Road
Bangalore, Karnataka  560103
India

Email: tireddy@cisco.com


Dan Wing

Email: dwing-ietf@fuggles.com


Prashanth Patil
Cisco Systems, Inc.
Bangalore
India

Email: praspati@cisco.com


Paal-Erik Martinsen
Cisco Systems, Inc.
Philip Pedersens vei 22
Lysaker, Akershus  1325
Norway

Email: palmarti@cisco.com
πŸ“¦ where this page comes from