RFC 8445

Interactive Connectivity Establishment (ICE): A Protocol for Network Address Translator (NAT) Traversal

๐Ÿ“… published July 2018, from ietf

โœจ RFC 8445: Interactive Connectivity Establishment (ICE) ๐ŸŽ€

okay bestie, this is the RFC that tells devices how to actually reach each other when they're stuck behind NATs ๐Ÿ’…

  • Number: RFC 8445
  • Title: Interactive Connectivity Establishment (ICE): A Protocol for Network Address Translator (NAT) Traversal
  • Authors: A. Keranen, C. Holmberg (both Ericsson), and J. Rosenberg (jdrosen.net) ๐Ÿซถ
  • Category: Standards Track ๐ŸŒˆ
  • ISSN: 2070-1721
  • Date: July 2018 ๐Ÿฆ‹
  • Obsoletes: RFC 5245 ๐Ÿ’€ (so the old version is out and this one is the new main character ๐Ÿ‘‘)
  • Updates: nothing listed in this title block

Abstract ๐ŸŒธ

ok so this doc is about a protocol for getting through NAT (Network Address Translator) boxes when you're doing UDP communication ๐Ÿ”ฅ it's called Interactive Connectivity Establishment (ICE), and it's giving teamwork, because it uses the Session Traversal Utilities for NAT (STUN) protocol and also its extension, Traversal Using Relay NAT (TURN) ๐Ÿงš

this document obsoletes RFC 5245 ๐Ÿ’… so yeah, this is the upgraded, iconic version

Status of This Memo โœจ

so this is an Internet Standards Track document ๐ŸŽ€

this one is a product of the Internet Engineering Task Force (IETF) ๐Ÿ’œ it represents the consensus of the IETF community, it got public review, and 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 ๐Ÿ“

want the current status, any errata, or a way to send feedback? go to https://www.rfc-editor.org/info/rfc8445 โญ

Copyright (c) 2018 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) as they were on the date this was published ๐Ÿ“œ please actually read those, bestie, because they explain your rights and restrictions for this document ๐Ÿ™ˆ any Code Components pulled out of this document have to include Simplified BSD License text, as described in Section 4.e of the Trust Legal Provisions ๐Ÿซถ and they come without warranty, the same way the Simplified BSD License says ๐Ÿ’…

this doc might include material from IETF Documents or IETF Contributions that were published or made publicly available before November 10, 2008 ๐Ÿ•ฐ๏ธ some of that material's copyright holders might not have given the IETF Trust permission to allow modifications outside the IETF Standards Process ๐Ÿ˜ญ so unless you get a proper license from those copyright holders, this document can't be modified outside the IETF Standards Process, and derivative works can't be made outside it either ๐Ÿšซ the only exceptions are formatting it for publication as an RFC or translating it into languages other than English ๐ŸŒธ

Table of Contents โœจ

okay bestie, here's the whole map of what's coming ๐Ÿ—บ๏ธ๐Ÿ’– every section, subsection, and appendix, numbered exactly how the spec has them so we can find our way around ๐Ÿงš

   1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   5
   2.  Overview of ICE . . . . . . . . . . . . . . . . . . . . . . .   6
     2.1.  Gathering Candidates  . . . . . . . . . . . . . . . . . .   8
     2.2.  Connectivity Checks . . . . . . . . . . . . . . . . . . .  10
     2.3.  Nominating Candidate Pairs and Concluding ICE . . . . . .  12
     2.4.  ICE Restart . . . . . . . . . . . . . . . . . . . . . . .  13
     2.5.  Lite Implementations  . . . . . . . . . . . . . . . . . .  13
   3.  ICE Usage . . . . . . . . . . . . . . . . . . . . . . . . . .  13
   4.  Terminology . . . . . . . . . . . . . . . . . . . . . . . . .  13
   5.  ICE Candidate Gathering and Exchange  . . . . . . . . . . . .  17
     5.1.  Full Implementation . . . . . . . . . . . . . . . . . . .  17
       5.1.1.  Gathering Candidates  . . . . . . . . . . . . . . . .  18
         5.1.1.1.  Host Candidates . . . . . . . . . . . . . . . . .  18
         5.1.1.2.  Server-Reflexive and Relayed Candidates . . . . .  20
         5.1.1.3.  Computing Foundations . . . . . . . . . . . . . .  21
         5.1.1.4.  Keeping Candidates Alive  . . . . . . . . . . . .  21
       5.1.2.  Prioritizing Candidates . . . . . . . . . . . . . . .  22
         5.1.2.1.  Recommended Formula . . . . . . . . . . . . . . .  22
         5.1.2.2.  Guidelines for Choosing Type and Local
                   Preferences . . . . . . . . . . . . . . . . . . .  23
       5.1.3.  Eliminating Redundant Candidates  . . . . . . . . . .  23
     5.2.  Lite Implementation Procedures  . . . . . . . . . . . . .  23
     5.3.  Exchanging Candidate Information  . . . . . . . . . . . .  24
     5.4.  ICE Mismatch  . . . . . . . . . . . . . . . . . . . . . .  26
   6.  ICE Candidate Processing  . . . . . . . . . . . . . . . . . .  26
     6.1.  Procedures for Full Implementation  . . . . . . . . . . .  26
       6.1.1.  Determining Role  . . . . . . . . . . . . . . . . . .  26
       6.1.2.  Forming the Checklists  . . . . . . . . . . . . . . .  28
         6.1.2.1.  Checklist State . . . . . . . . . . . . . . . . .  28
         6.1.2.2.  Forming Candidate Pairs . . . . . . . . . . . . .  28
         6.1.2.3.  Computing Pair Priority and Ordering Pairs  . . .  31
         6.1.2.4.  Pruning the Pairs . . . . . . . . . . . . . . . .  31
         6.1.2.5.  Removing Lower-Priority Pairs . . . . . . . . . .  31
         6.1.2.6.  Computing Candidate Pair States . . . . . . . . .  32
       6.1.3.  ICE State . . . . . . . . . . . . . . . . . . . . . .  36
       6.1.4.  Scheduling Checks . . . . . . . . . . . . . . . . . .  36
         6.1.4.1.  Triggered-Check Queue . . . . . . . . . . . . . .  36
         6.1.4.2.  Performing Connectivity Checks  . . . . . . . . .  36
     6.2.  Lite Implementation Procedures  . . . . . . . . . . . . .  38
   7.  Performing Connectivity Checks  . . . . . . . . . . . . . . .  38
     7.1.  STUN Extensions . . . . . . . . . . . . . . . . . . . . .  38
       7.1.1.  PRIORITY  . . . . . . . . . . . . . . . . . . . . . .  38
       7.1.2.  USE-CANDIDATE . . . . . . . . . . . . . . . . . . . .  38
       7.1.3.  ICE-CONTROLLED and ICE-CONTROLLING  . . . . . . . . .  39
     7.2.  STUN Client Procedures  . . . . . . . . . . . . . . . . .  39
       7.2.1.  Creating Permissions for Relayed Candidates . . . . .  39
       7.2.2.  Forming Credentials . . . . . . . . . . . . . . . . .  39
       7.2.3.  Diffserv Treatment  . . . . . . . . . . . . . . . . .  40
       7.2.4.  Sending the Request . . . . . . . . . . . . . . . . .  40
       7.2.5.  Processing the Response . . . . . . . . . . . . . . .  40
         7.2.5.1.  Role Conflict . . . . . . . . . . . . . . . . . .  40
         7.2.5.2.  Failure . . . . . . . . . . . . . . . . . . . . .  41
           7.2.5.2.1.  Non-Symmetric Transport Addresses . . . . . .  41
           7.2.5.2.2.  ICMP Error  . . . . . . . . . . . . . . . . .  41
           7.2.5.2.3.  Timeout . . . . . . . . . . . . . . . . . . .  41
           7.2.5.2.4.  Unrecoverable STUN Response . . . . . . . . .  41
         7.2.5.3.  Success . . . . . . . . . . . . . . . . . . . . .  42
           7.2.5.3.1.  Discovering Peer-Reflexive Candidates . . . .  42
           7.2.5.3.2.  Constructing a Valid Pair . . . . . . . . . .  43
           7.2.5.3.3.  Updating Candidate Pair States  . . . . . . .  44
           7.2.5.3.4.  Updating the Nominated Flag . . . . . . . . .  44
         7.2.5.4.  Checklist State Updates . . . . . . . . . . . . .  44
     7.3.  STUN Server Procedures  . . . . . . . . . . . . . . . . .  45
       7.3.1.  Additional Procedures for Full Implementations  . . .  45
         7.3.1.1.  Detecting and Repairing Role Conflicts  . . . . .  46
         7.3.1.2.  Computing Mapped Addresses  . . . . . . . . . . .  47
         7.3.1.3.  Learning Peer-Reflexive Candidates  . . . . . . .  47
         7.3.1.4.  Triggered Checks  . . . . . . . . . . . . . . . .  47
         7.3.1.5.  Updating the Nominated Flag . . . . . . . . . . .  49
       7.3.2.  Additional Procedures for Lite Implementations  . . .  49
   8.  Concluding ICE Processing . . . . . . . . . . . . . . . . . .  50
     8.1.  Procedures for Full Implementations . . . . . . . . . . .  50
       8.1.1.  Nominating Pairs  . . . . . . . . . . . . . . . . . .  50
       8.1.2.  Updating Checklist and ICE States . . . . . . . . . .  51
     8.2.  Procedures for Lite Implementations . . . . . . . . . . .  52
     8.3.  Freeing Candidates  . . . . . . . . . . . . . . . . . . .  53
       8.3.1.  Full Implementation Procedures  . . . . . . . . . . .  53
       8.3.2.  Lite Implementation Procedures  . . . . . . . . . . .  53
   9.  ICE Restarts  . . . . . . . . . . . . . . . . . . . . . . . .  53
   10. ICE Option  . . . . . . . . . . . . . . . . . . . . . . . . .  54
   11. Keepalives  . . . . . . . . . . . . . . . . . . . . . . . . .  54
   12. Data Handling . . . . . . . . . . . . . . . . . . . . . . . .  55
     12.1.  Sending Data . . . . . . . . . . . . . . . . . . . . . .  55
       12.1.1.  Procedures for Lite Implementations  . . . . . . . .  56
     12.2.  Receiving Data . . . . . . . . . . . . . . . . . . . . .  56
   13. Extensibility Considerations  . . . . . . . . . . . . . . . .  57
   14. Setting Ta and RTO  . . . . . . . . . . . . . . . . . . . . .  57
     14.1.  General  . . . . . . . . . . . . . . . . . . . . . . . .  57
     14.2.  Ta . . . . . . . . . . . . . . . . . . . . . . . . . . .  58
     14.3.  RTO  . . . . . . . . . . . . . . . . . . . . . . . . . .  58
   15. Examples  . . . . . . . . . . . . . . . . . . . . . . . . . .  59
     15.1.  Example with IPv4 Addresses  . . . . . . . . . . . . . .  60
     15.2.  Example with IPv6 Addresses  . . . . . . . . . . . . . .  65

   16. STUN Extensions . . . . . . . . . . . . . . . . . . . . . . .  69
     16.1.  Attributes . . . . . . . . . . . . . . . . . . . . . . .  69
     16.2.  New Error-Response Codes . . . . . . . . . . . . . . . .  70
   17. Operational Considerations  . . . . . . . . . . . . . . . . .  70
     17.1.  NAT and Firewall Types . . . . . . . . . . . . . . . . .  70
     17.2.  Bandwidth Requirements . . . . . . . . . . . . . . . . .  70
       17.2.1.  STUN and TURN Server-Capacity Planning . . . . . . .  71
       17.2.2.  Gathering and Connectivity Checks  . . . . . . . . .  71
       17.2.3.  Keepalives . . . . . . . . . . . . . . . . . . . . .  72
     17.3.  ICE and ICE-Lite . . . . . . . . . . . . . . . . . . . .  72
     17.4.  Troubleshooting and Performance Management . . . . . . .  72
     17.5.  Endpoint Configuration . . . . . . . . . . . . . . . . .  73
   18. IAB Considerations  . . . . . . . . . . . . . . . . . . . . .  73
     18.1.  Problem Definition . . . . . . . . . . . . . . . . . . .  73
     18.2.  Exit Strategy  . . . . . . . . . . . . . . . . . . . . .  74
     18.3.  Brittleness Introduced by ICE  . . . . . . . . . . . . .  74
     18.4.  Requirements for a Long-Term Solution  . . . . . . . . .  75
     18.5.  Issues with Existing NAPT Boxes  . . . . . . . . . . . .  75
   19. Security Considerations . . . . . . . . . . . . . . . . . . .  76
     19.1.  IP Address Privacy . . . . . . . . . . . . . . . . . . .  76
     19.2.  Attacks on Connectivity Checks . . . . . . . . . . . . .  77
     19.3.  Attacks on Server-Reflexive Address Gathering  . . . . .  80
     19.4.  Attacks on Relayed Candidate Gathering . . . . . . . . .  80
     19.5.  Insider Attacks  . . . . . . . . . . . . . . . . . . . .  81
       19.5.1.  STUN Amplification Attack  . . . . . . . . . . . . .  81
   20. IANA Considerations . . . . . . . . . . . . . . . . . . . . .  82
     20.1.  STUN Attributes  . . . . . . . . . . . . . . . . . . . .  82
     20.2.  STUN Error Responses . . . . . . . . . . . . . . . . . .  82
     20.3.  ICE Options  . . . . . . . . . . . . . . . . . . . . . .  82
   21. Changes from RFC 5245 . . . . . . . . . . . . . . . . . . . .  83
   22. References  . . . . . . . . . . . . . . . . . . . . . . . . .  84
     22.1.  Normative References . . . . . . . . . . . . . . . . . .  84
     22.2.  Informative References . . . . . . . . . . . . . . . . .  85
   Appendix A.  Lite and Full Implementations  . . . . . . . . . . .  89
   Appendix B.  Design Motivations . . . . . . . . . . . . . . . . .  90
     B.1.  Pacing of STUN Transactions . . . . . . . . . . . . . . .  90
     B.2.  Candidates with Multiple Bases  . . . . . . . . . . . . .  92
     B.3.  Purpose of the Related-Address and Related-Port
           Attributes  . . . . . . . . . . . . . . . . . . . . . . .  94
     B.4.  Importance of the STUN Username . . . . . . . . . . . . .  95
     B.5.  The Candidate Pair Priority Formula . . . . . . . . . . .  96
     B.6.  Why Are Keepalives Needed?  . . . . . . . . . . . . . . .  96
     B.7.  Why Prefer Peer-Reflexive Candidates? . . . . . . . . . .  97
     B.8.  Why Are Binding Indications Used for Keepalives?  . . . .  97
     B.9.  Selecting Candidate Type Preference . . . . . . . . . . .  97
   Appendix C.  Connectivity-Check Bandwidth . . . . . . . . . . . .  99
   Acknowledgements  . . . . . . . . . . . . . . . . . . . . . . . . 100
   Authors' Addresses  . . . . . . . . . . . . . . . . . . . . . . . 100

the map is loaded ๐Ÿซถ next up is the real stuff, starting with Section 1 ๐Ÿ’…

1. Introduction โœจ

okay so bestie, let's start with the problem ๐Ÿ˜ญ. Peers that set up a communication session usually swap IP addresses and ports for their data sources and sinks. That's fine on the open internet, but it gets messy when you go through Network Address Translators (NATs) [RFC3235]. These protocols also want the data to flow directly between the two participants, with no application-layer middleman in the way. The payoff is lower data latency, less packet loss, and lower operational costs for the app. Sounds iconic, but NATs make it really hard to pull off. We're not going to go through every reason here, since that's out of scope for this spec ๐Ÿซถ.

People have tried a bunch of fixes. There are Application Layer Gateways (ALGs), the Middlebox Control Protocol [RFC3303], the original Simple Traversal of UDP Through NAT (STUN) spec [RFC3489] (ps, RFC 3489 has been obsoleted by RFC 5389 ๐Ÿ™ˆ), and Realm Specific IP [RFC3102] [RFC3103]. There are also session description extensions to make those work, like the Session Description Protocol (SDP) attribute [RFC4566] for the Real-Time Control Protocol (RTCP) [RFC3605]. The catch is that every one of these has pros and cons. Each is perfect for some network topologies and a total disaster in others. So admins and implementers end up guessing what the networks they deploy into will look like, and that adds complexity and brittleness to the whole system. Not it ๐Ÿ’€.

Enter the main character: Interactive Connectivity Establishment (ICE) ๐Ÿ‘‘. This spec defines ICE as a NAT traversal technique for UDP-based data streams. It has also been extended to handle other transport protocols, like TCP [RFC6544]. The way ICE works is that the peers swap a whole bunch of IP addresses and ports, then test each combo for connectivity with peer-to-peer connectivity checks. The addresses and ports get exchanged through usage-specific mechanisms (for example, an Offer/Answer exchange), and the checks run using STUN [RFC5389]. ICE also uses Traversal Using Relay around NAT (TURN) [RFC5766], which is an extension to STUN ๐Ÿฆ‹. Since ICE trades around multiple IP addresses and ports for every media stream, it can also pick the right address for multihomed and dual-stack hosts. Because of all this, RFC 5245 [RFC5245] deprecated the older solutions from RFC 4091 [RFC4091] and RFC 4092 [RFC4092] ๐Ÿ’–.

If you want the background and the reasoning behind the design choices, Appendix B has you covered ๐Ÿงš.

2. Overview of ICE ๐Ÿฆ‹

okay this is the part where we meet the cast ๐Ÿ’…. In a typical ICE setup, there are two endpoints, called ICE agents, that want to talk to each other. ICE is not meant to traverse NATs for the signaling protocol. Signaling is handled some other way, and ICE just assumes the agents can set up a signaling connection with each other ๐ŸŒธ.

At the start, the agents have no clue what their own network topology looks like. They might be behind NATs, or behind several tiers of NATs, or not behind any at all. ICE helps them learn enough about their topology to find one or more paths they can use for a data session ๐Ÿ”ฅ.

Figure 1 shows a typical ICE deployment. The agents are labeled L and R. Both of them sit behind their own NATs, even if they don't know it yet. We don't know the NAT type or its properties either. L and R can run a candidate exchange, and the goal is to set up a data session between them. This usually happens through a signaling server, like a SIP proxy ๐ŸŽ€.

Besides the agents, the signaling server, and the NATs, ICE is usually used alongside STUN or TURN servers on the network. Each agent can have its own STUN or TURN server, or they can share one ๐Ÿ“.

                               +---------+
             +--------+        |Signaling|         +--------+
             | STUN   |        |Server   |         | STUN   |
             | Server |        +---------+         | Server |
             +--------+       /           \        +--------+
                             /             \
                            /               \
                           / <- Signaling -> \
                          /                   \
                   +--------+               +--------+
                   |  NAT   |               |  NAT   |
                   +--------+               +--------+
                      /                             \
                     /                               \
                 +-------+                       +-------+
                 | Agent |                       | Agent |
                 |   L   |                       |   R   |
                 +-------+                       +-------+

                     Figure 1: ICE Deployment Scenario

Here's the basic idea ๐Ÿ’œ. Each agent has a bunch of candidate transport addresses it could use to reach the other agent. A transport address is an IP address plus a port for a particular transport protocol, and in this spec that's always UDP. The candidates can be:

  • A transport address on a directly attached network interface
  • A translated transport address on the public side of a NAT (a "server-reflexive" address)
  • A transport address allocated from a TURN server (a "relayed address")

Technically, any of L's candidates could talk to any of R's candidates. In real life though, lots of those combos just won't work. For example, if L and R are both behind NATs, their directly attached interface addresses probably can't reach each other directly. (That's literally why ICE exists, lol ๐Ÿ˜ญ.) So ICE's whole job is to figure out which address pairs actually work. It does that by trying every possible pair, in a carefully sorted order, until it finds one or more that succeed โœจ.

2.1. Gathering Candidates ๐Ÿ’…

To run ICE, an ICE agent first has to find and collect one or more address candidates ๐ŸŒˆ. A candidate is a transport address, meaning an IP address and port for a particular transport protocol (and only UDP is specified here). Candidates come in different types. Some come from physical or logical network interfaces, and others are found through STUN and TURN.

The first category is candidates whose transport address comes straight from a local interface. These are called "host candidates" ๐Ÿ . The local interface could be Ethernet or Wi-Fi. It could also be something reached through a tunnel, like a Virtual Private Network (VPN) or Mobile IP (MIP). Either way, the agent sees the interface as a local one that it can allocate ports (and therefore candidates) from ๐Ÿฆ‹.

Next, the agent uses STUN or TURN to pick up more candidates. There are two flavors. One is translated addresses on the public side of a NAT, called server-reflexive candidates. The other is addresses on TURN servers, called relayed candidates. If a TURN server is in use, the agent gets both types from it. If only STUN servers are in use, the agent only gets server-reflexive candidates from them. Figure 2 shows how these candidates relate to the host candidate. In this figure, both types are found using TURN. The notation X:x means IP address X and UDP port x ๐Ÿ’–.

                      To Internet

                          |
                          |
                          |  /------------  Relayed
                      Y:y | /               Address
                      +--------+
                      |        |
                      |  TURN  |
                      | Server |
                      |        |
                      +--------+
                          |
                          |
                          | /------------  Server
                   X1':x1'|/               Reflexive
                    +------------+         Address
                    |    NAT     |
                    +------------+
                          |
                          | /------------  Local
                      X:x |/               Address
                      +--------+
                      |        |
                      | Agent  |
                      |        |
                      +--------+


                     Figure 2: Candidate Relationships

When the agent sends a TURN Allocate request from IP address and port X:x, the NAT (if there is one) creates a binding X1':x1'. That binding maps the server-reflexive candidate to the host candidate X:x. Outgoing packets from the host candidate get translated by the NAT into the server-reflexive candidate. Incoming packets sent to the server-reflexive candidate get translated back to the host candidate and forwarded to the agent. The host candidate linked to a given server-reflexive candidate is called the "base" ๐ŸŒธ.

Note: "Base" refers to the address an agent sends from for a particular candidate. So as a degenerate case, host candidates also have a base, and it's just the same as the host candidate ๐Ÿค“.

When there are multiple NATs between the agent and the TURN server, the TURN request creates a binding on each NAT. But the agent only discovers the outermost server-reflexive candidate, which is the one closest to the TURN server ๐Ÿง. If the agent isn't behind a NAT, the base candidate is the same as the server-reflexive candidate. In that case the server-reflexive candidate is redundant, so it gets eliminated ๐Ÿ™…โ€โ™€๏ธ.

The Allocate request then arrives at the TURN server. The TURN server allocates a port y from its local IP address Y and sends back an Allocate response, which tells the agent about the relayed candidate. The TURN server also tells the agent about the server-reflexive candidate, X1':x1', by copying the source transport address of the Allocate request into the Allocate response. The TURN server acts as a packet relay and forwards traffic between L and R. To send traffic to L, R sends it to the TURN server at Y:y. The TURN server forwards that to X1':x1', the NAT maps it to X:x, and it finally gets delivered to L ๐ŸŽ€.

When only STUN servers are in use, the agent sends a STUN Binding request [RFC5389] to its STUN server. The STUN server tells the agent about the server-reflexive candidate X1':x1' by copying the source transport address of the Binding request into the Binding response ๐Ÿ’….

2.2. Connectivity Checks ๐Ÿ’–

Okay so once L has gathered all of its candidates, it sorts them from highest priority to lowest and sends the list over to R through the signaling channel. When R gets L's candidates, it runs the exact same gathering process and sends back its own list ๐Ÿซถ. By the end of all this, each ICE agent has the full picture: its own candidates and its peer's candidates. It pairs them up into candidate pairs, and then it's time to figure out which pairs actually work ๐Ÿ‘€. Each agent schedules a bunch of connectivity checks, and each check is a STUN request/response transaction. The client does one on a particular candidate pair by sending a STUN request from the local candidate to the remote candidate.

The basic principle is honestly simple:

  1. Sort the candidate pairs in priority order.
  2. Send checks on each candidate pair in priority order.
  3. Acknowledge checks received from the other agent.

When both agents are doing a check on the same candidate pair, you get a 4-way handshake, and it's so iconic ๐Ÿ’…:

                  L                        R
                  -                        -
                  STUN request ->             \  L's
                            <- STUN response  /  check

                             <- STUN request  \  R's
                  STUN response ->            /  check

                    Figure 3: Basic Connectivity Check

Now, this is important, so listen up ๐Ÿ‘‚. STUN requests go to and come from the exact same IP addresses and ports that will be used for data (like RTP, RTCP, or other protocols). Because of that, agents tell STUN and data apart by looking at what's inside the packets, not by which port they showed up on ๐Ÿฆ‹.

Here's another cute detail. A STUN Binding request is what gets used for the connectivity check, so the STUN Binding response will include the agent's translated transport address on the public side of any NATs between the agent and its peer ๐ŸŒ. If that address is different from the other candidates the agent already knows about, it's a brand new candidate, called a peer-reflexive candidate โœจ. And guess what? ICE tests it just like any other candidate. Iconic.

The algorithm searches through all the candidate pairs, so if a working pair exists, it'll eventually find it no matter what order things get tried in ๐Ÿงš. But to get faster (and better!) results, the candidates are sorted in a specified order. That sorted list of candidate pairs is called the "checklist" ๐Ÿ“.

The agent works through the checklist by sending a STUN request for the next candidate pair on the list, periodically. These are called "ordinary checks" โฐ. When a STUN transaction succeeds, one or more candidate pairs become "valid pairs" and get added to a candidate-pair list called the "valid list" ๐Ÿ’œ.

Here's an optimization that's giving main character energy. As soon as R gets L's check message, R schedules a connectivity-check message to go back to L on that same candidate pair. This is called a "triggered check," and it speeds up finding valid pairs a lot ๐Ÿš€.

When this handshake is over, both L and R know they can send (and receive) messages end to end in both directions ๐ŸŽ€.

In general, the priority algorithm is designed so candidates of a similar type get similar priorities. That way, more direct routes (routes without data relays or NATs) are preferred over indirect routes (routes with data relays or NATs) ๐ŸŒธ. Within those guidelines, though, agents have a fair amount of discretion about how they tune their algorithms ๐Ÿคทโ€โ™€๏ธ.

A data stream might be made up of multiple components, which are pieces of a data stream that each need their own set of candidates. RTP and RTCP are the classic example ๐Ÿ“.


2.3. Nominating Candidate Pairs and Concluding ICE ๐Ÿ‘‘

ICE assigns one ICE agent the role of controlling agent and the other the role of controlled agent ๐ŸŽญ. For each component of a data stream, the controlling agent nominates a valid pair (from the valid list) to be used for data. When that nomination happens is up to local policy โญ.

When nominating, the controlling agent lets the checks keep going until at least one valid pair for each component of a data stream is found. Then it picks a valid pair and sends a STUN request on that pair, with an attribute that tells the controlled peer "hey, you've been nominated!" ๐Ÿฅณ. Check out Figure 4:

             L                        R
             -                        -
             STUN request ->             \  L's
                       <- STUN response  /  check

                        <- STUN request  \  R's
             STUN response ->            /  check

             STUN request + attribute -> \  L's
                       <- STUN response  /  check

                           Figure 4: Nomination

Once the controlled agent gets that STUN request with the attribute, it checks the same pair (unless that check was already done) ๐Ÿ”. If the transactions above succeed, the agents set the nominated flag for those pairs and cancel any future checks for that component of the data stream ๐Ÿ›‘. When an agent has set the nominated flag for each component of a data stream, those pairs become the selected pairs. From then on, only the selected pairs get used for sending and receiving data for that data stream ๐Ÿ’…โœจ.

2.4. ICE Restart ๐Ÿ”„

Once ICE has concluded, either ICE agent can restart it at any time, for one or all of the data streams ๐ŸŒˆ. To do that, the agent sends updated candidate information that indicates a restart. Easy.

2.5. Lite Implementations ๐Ÿชถ

Some ICE agents are always connected to the public Internet and have a public IP address where they can receive packets from any correspondent ๐ŸŒ. To make life easier for these devices, ICE defines a special type of implementation called "lite," which is the opposite of the normal full implementation ๐Ÿงธ. Lite agents only use host candidates, and they don't generate connectivity checks or run state machines. They do still need to be able to respond to connectivity checks, though, so they're not totally off the hook ๐Ÿ˜ญ.

3. ICE Usage ๐ŸŽ€

This document specifies generic use of ICE with protocols that provide ways to exchange candidate information between ICE agents ๐Ÿ’Œ. The specific details (how to encode candidate information, plus the actual candidate exchange process) for different protocols using ICE, which are called "using protocols," are described in separate usage documents ๐Ÿ“š.

One mechanism that lets agents exchange candidate information is Offer/Answer semantics (based on [RFC3264]), which is used as part of the SIP protocol [RFC3261] [ICE-SIP-SDP] ๐Ÿ“ž.

[RFC7825] defines an ICE usage for the Real-Time Streaming Protocol (RTSP) ๐ŸŽฅ. Heads up, though: that ICE usage is based on RFC 5245, not the newer spec ๐Ÿ‘€.

4. Terminology ๐ŸŽ€

okay bestie, let's get the vocab down first ๐Ÿ’… The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" mean what BCP 14 [RFC2119] [RFC8174] says they mean, but ONLY when they show up in all capitals like this ๐Ÿ™ˆ

You also need to already know the terms from [RFC5389] and NAT Behavioral requirements for UDP [RFC4787] ๐Ÿฆ‹ no skipping, periodt.

Here's the extra vocab this spec uses ๐ŸŒธ

ICE Session: an ICE session is everything ICE-related, starting with candidate gathering, then all the back-and-forth (candidate exchange, connectivity checks, nominations, and keepalives) between the ICE agents, until all the candidates get released or an ICE restart gets triggered ๐Ÿ’–

ICE Agent, Agent: the protocol implementation that does the ICE candidate exchange. People sometimes just call it an "agent" โœจ A typical candidate exchange has two agents in it, so it's giving duo energy ๐Ÿ‘ฏ

Initiating Peer, Initiating Agent, Initiator: the ICE agent that kicks off the candidate exchange process. It's the one making the first move ๐Ÿซถ

Responding Peer, Responding Agent, Responder: the ICE agent that gets the exchange started by the initiator, and then answers it ๐Ÿ’œ

ICE Candidate Exchange, Candidate Exchange: the process where agents swap the info they need to do ICE, like candidates and passwords ๐ŸŽ€ Offer/Answer with SDP encoding [RFC3264] is one example of a protocol you can use for swapping candidate info ๐Ÿงš

Peer: from one agent's point of view, its peer is the other agent. So from the initiator's side, the peer is the responder, and from the responder's side, the peer is the initiator ๐ŸŒˆ

Transport Address: an IP address combined with a transport protocol port, like UDP or TCP ๐Ÿ“

Data, Data Stream, Data Session: when ICE sets up data sessions, the data goes over some protocol. Media usually goes over RTP, which is a stream of RTP packets ๐ŸŽถ A data session is the data packets flowing between the peers on the path that ICE created and tested ๐Ÿฆ‹

Candidate, Candidate Information: a transport address that could be a point of contact for receiving data โœจ Candidates also have properties: their type (server reflexive, relayed, or host), priority, foundation, and base ๐Ÿ’…

Component: a piece of a data stream. A data stream might need several components, and every one of them has to work for the whole stream to work ๐Ÿ˜ญ For RTP/RTCP streams, unless RTP and RTCP are multiplexed on the same port, you get two components per stream: one for RTP and one for RTCP ๐Ÿ’– A component has a candidate pair, and no other component can use that pair. Not sharing, bestie ๐Ÿ™…

Host Candidate: a candidate you get by binding to a specific port on an IP address from the host itself. That includes IP addresses on physical interfaces AND logical ones, like the ones you get through VPNs ๐ŸŒธ

Server-Reflexive Candidate: a candidate whose IP address and port are a binding a NAT made for an ICE agent after the agent sent a packet through the NAT to a server, like a STUN server ๐Ÿชž

Peer-Reflexive Candidate: same vibe as the server-reflexive one, except the binding is made after the agent sent a packet through the NAT to its peer ๐Ÿฆ‹

Relayed Candidate: a candidate you get from a relay server, like a TURN server ๐ŸŒŠ

Base: the transport address an ICE agent sends from for a particular candidate. For host, server-reflexive, and peer-reflexive candidates, the base is the same as the host candidate. For relayed candidates, the base is the same as the relayed candidate, meaning the transport address the TURN server uses to send from ๐Ÿ“

Related Address and Port: a transport address that goes with a candidate, which is handy for diagnostics and other stuff ๐Ÿ” If a candidate is server or peer reflexive, the related address and port equals the base for that candidate. If it's relayed, they equal the mapped address in the Allocate response that gave the client that relayed candidate. If it's a host candidate, the related address and port are identical to the host candidate ๐Ÿ’œ

Foundation: an arbitrary string used in the freezing algorithm to group similar candidates ๐ŸงŠ Two candidates get the same foundation if they have the same type, base IP address, protocol (UDP, TCP, etc.), and STUN or TURN server. If any of those are different, the foundation is different too ๐Ÿ’…

Local Candidate: a candidate an ICE agent has obtained and might send to its peer ๐Ÿ“ค

Remote Candidate: a candidate an ICE agent received from its peer ๐Ÿ“ฅ

Default Destination/Candidate: the default destination for a component of a data stream is the transport address an agent that isn't ICE aware would use. A default candidate for a component is one whose transport address matches that default destination ๐ŸŽ€

Candidate Pair: a pair made of one local candidate and one remote candidate ๐Ÿ‘ฏ

Check, Connectivity Check, STUN Check: a STUN Binding request sent to verify connectivity ๐Ÿ”Ž A check goes from the base of the local candidate to the remote candidate of a candidate pair ๐Ÿš€

Checklist: an ordered set of candidate pairs that an ICE agent uses to generate checks ๐Ÿ“‹

Ordinary Check: a connectivity check an ICE agent generates because a timer fired periodically, telling it to send a check โฐ

Triggered Check: a connectivity check generated because the agent got a connectivity check from its peer ๐Ÿ””

Valid Pair: a candidate pair whose local candidate equals the mapped address of a successful connectivity-check response, and whose remote candidate equals the destination address the connectivity-check request was sent to โœ…

Valid List: an ordered set of candidate pairs for a data stream that have been validated by a successful STUN transaction ๐ŸŒŸ

Checklist Set: the ordered list of all the checklists. The order is decided by each ICE usage ๐Ÿ—‚๏ธ

Full Implementation: an ICE implementation that does the complete set of functionality this specification defines ๐Ÿ‘‘

Lite Implementation: an ICE implementation that skips certain functions, and only does as much as a peer that isn't a lite implementation needs to get the benefits of ICE ๐Ÿƒ Lite implementations don't maintain any of the state machines and don't generate connectivity checks. Low-key chill ๐Ÿ˜Œ

Controlling Agent: the ICE agent that nominates a candidate pair. In any session there's always exactly one controlling agent and one controlled agent ๐Ÿ‘‘

Controlled Agent: the ICE agent that waits for the controlling agent to nominate a candidate pair ๐Ÿง˜

Nomination: the process where the controlling agent tells the controlled agent which candidate pair the agents will use for sending and receiving data ๐ŸŽฏ The nomination process in this spec used to be called "regular nomination" in RFC 5245. The one that was called "aggressive nomination" in RFC 5245 has been deprecated here ๐Ÿ™…โ€โ™€๏ธ not it, bestie.

Nominated, Nominated Flag: once nomination of a candidate pair succeeds, that pair is nominated, and its nominated flag is set to true ๐Ÿšฉ

Selected Pair, Selected Candidate Pair: the candidate pair used for sending and receiving data for a component of a data stream is called the "selected pair" ๐Ÿ† Before selected pairs exist for a data stream, any valid pair for a component can be used to send and receive data for that component. Once there are nominated pairs for each component of a data stream, the nominated pairs become the selected pairs for that stream. The candidates in the selected pairs are called "selected candidates" ๐Ÿ’–

Using Protocol, ICE Usage: the protocol that uses ICE for NAT traversal ๐Ÿงญ A usage specification defines the protocol-specific details of how the procedures in this document get applied to that protocol ๐Ÿ“–

Timer Ta: the timer for generating new STUN or TURN transactions โฒ๏ธ

Timer RTO (Retransmission Timeout): the retransmission timer for a given STUN or TURN transaction ๐Ÿ”


5. ICE Candidate Gathering and Exchange โœจ

okay so as part of ICE processing, BOTH the initiating and responding agents gather candidates, prioritize them, and get rid of redundant ones ๐Ÿงน Then they exchange candidate info with the peer, the way the using protocol (ICE usage) says to ๐Ÿ’… How the candidates get encoded and what the candidate info exchange actually means is out of scope for this spec, so that's somebody else's problem, not ours ๐Ÿ™ƒ

5.1. Full Implementation ๐Ÿ‘‘

5.1.1. Gathering Candidates ๐ŸŒธ

an ICE agent gathers candidates when it thinks communication is about to happen ๐Ÿ‘€ An initiating agent can do this because of a user interface cue, or because someone explicitly asked it to start a session ๐ŸŽฌ Every candidate has a transport address, and it also has a type and a base ๐Ÿ’œ This spec defines four types and gathers them: host candidates, server-reflexive candidates, peer-reflexive candidates, and relayed candidates ๐Ÿฆ‹ Server-reflexive candidates get gathered using STUN or TURN, and relayed candidates come from TURN ๐ŸŒŠ Peer-reflexive candidates show up later in ICE, as a result of connectivity checks ๐Ÿ”

The responding agent gathers candidates the exact same way the initiating agent does ๐Ÿซถ It is RECOMMENDED that the responding agent starts this process right away when it gets the candidate information, before it alerts the user of the application tied to the ICE session ๐Ÿ”” bestie, that's the move ๐Ÿ’–

5.1.1.1. Host Candidates โœจ

okay bestie, host candidates are the easiest ones ๐Ÿ’– You get them by binding to ports on an IP address that's attached to an interface on the host (physical or virtual, VPN interfaces count too ๐ŸŒธ).

For each component of each data stream the ICE agent wants to use, the agent SHOULD grab a candidate on every IP address the host has, except for the exceptions listed below ๐Ÿฆ‹ It gets each candidate by binding to a UDP port on that specific IP address. Every candidate (host ones included) is always tied to one specific component it's a candidate for ๐Ÿซถ

Each component gets an ID called the "component ID" ๐Ÿงš For RTP/RTCP data streams, unless RTP and RTCP are multiplexed on the same UDP port (RTP/RTCP multiplexing), RTP is component ID 1 and RTCP is component ID 2. When RTP/RTCP multiplexing is in play, component ID 1 covers both RTP and RTCP ๐Ÿ’œ

Now here's the tea ๐Ÿซ– Unless the agent knows for sure that RTP/RTCP multiplexing will be used (meaning it knows the other agent supports it and is willing to use it), or unless the agent only supports RTP/RTCP multiplexing, the agent MUST obtain a separate candidate for RTCP ๐Ÿ˜ญ If it got an RTCP candidate and then ends up multiplexing, it doesn't need to run connectivity checks on that RTCP candidate โœจ And no component ID 2 doesn't automatically mean multiplexing, because RTCP might just not be used at all ๐Ÿ™ˆ

If an agent uses separate candidates for RTP and RTCP and has K IP addresses, it ends up with 2*K host candidates. Math check passed ๐Ÿ’…

The responding agent usually knows whether the other agent supports RTP/RTCP multiplexing while it's gathering, so it won't need a separate RTCP candidate in that case. Same tea though: no component ID 2 still doesn't prove multiplexing, since RTCP could simply be unused ๐ŸŒˆ

Using multiple components for anything other than RTP/RTCP is discouraged, because it makes ICE processing way more complicated ๐Ÿ™ƒ If you really need multiple components, the component IDs SHOULD start at 1 and go up by 1 for each new component ๐Ÿ“

The base of each host candidate is set to the candidate itself ๐ŸŽ€

Host candidates are gathered from all IP addresses, with these exceptions:

  • Addresses from a loopback interface MUST NOT be included in the candidate addresses ๐Ÿšซ
  • Deprecated IPv4-compatible IPv6 addresses [RFC4291] and IPv6 site-local unicast addresses [RFC3879] MUST NOT be included in the address candidates ๐Ÿ’€
  • IPv4-mapped IPv6 addresses SHOULD NOT be included in the address candidates unless the application using ICE doesn't support IPv4 (aka it's an IPv6-only application [RFC4038]) ๐ŸŒธ
  • If you're gathering one or more host candidates for an IPv6 address that was generated using a mechanism that prevents location tracking [RFC7721], then host candidates for IPv6 addresses that DO allow location tracking, which are configured on the same interface and part of the same network prefix, MUST NOT be gathered. Same energy the other way: when host candidates for a location-tracking-proof IPv6 address are gathered, host candidates for IPv6 link-local addresses [RFC4291] MUST NOT be gathered ๐Ÿ”ฅ

The IPv6 default address selection specification [RFC6724] says temporary addresses [RFC4941] are preferred over permanent addresses. Iconic, honestly ๐Ÿ‘‘

5.1.1.2. Server-Reflexive and Relayed Candidates

An ICE agent SHOULD gather server-reflexive and relayed candidates โœจ That said, STUN and TURN servers might be unnecessary on some networks, and TURN servers can be expensive, so some deployments may choose not to use them ๐Ÿ’ธ If an agent doesn't gather server-reflexive or relayed candidates, it is RECOMMENDED that the functionality still gets implemented and is just disabled through configuration. That way it can be switched back on if conditions change later ๐Ÿฆ‹

The agent pairs each host candidate with the STUN or TURN servers it's configured with or has discovered some other way ๐Ÿงš It is RECOMMENDED that a domain name be configured, that the DNS procedures in [RFC5389] (using SRV records with the "stun" service) be used to find the STUN server, and that the DNS procedures in [RFC5766] (using SRV records with the "turn" service) be used to find the TURN server ๐ŸŒˆ

When multiple STUN or TURN servers are available (or when they're learned through DNS records and multiple results come back), the agent MAY gather candidates from all of them and SHOULD gather candidates from at least one of them (one STUN server and one TURN server) ๐Ÿ“ It does this by pairing host candidates with STUN or TURN servers. For each pair, the agent sends a Binding or Allocate request to the server from that host candidate ๐Ÿ’Œ Binding requests to a STUN server aren't authenticated, and any ALTERNATE-SERVER attribute in a response gets ignored ๐Ÿ™ˆ Agents MUST support the backwards-compatibility mode for the Binding request defined in [RFC5389]. Allocate requests SHOULD be authenticated using a long-term credential the client got through some other means ๐Ÿ”

The gathering process is controlled by a timer, Ta. Every time Ta expires, the agent can generate another new STUN or TURN transaction. That transaction can either retry a previous one that failed with a recoverable error (like an authentication failure), or be a brand new transaction for a host candidate and STUN or TURN server pair ๐Ÿ” The agent SHOULD NOT generate transactions more often than once per each ta expiration. Check Section 14 for guidance on setting Ta and the STUN retransmit timer, RTO ๐Ÿ“–

The agent will receive a Binding or Allocate response. A successful Allocate response gives the agent a server-reflexive candidate (from the mapped address) and a relayed candidate in the XOR-RELAYED-ADDRESS attribute ๐ŸŽ‰ If the Allocate request gets rejected because the server doesn't have the resources for it, the agent SHOULD send a Binding request instead to get a server-reflexive candidate. A Binding response only gives the agent a server-reflexive candidate (also from the mapped address) ๐Ÿฆ‹ The base of a server-reflexive candidate is the host candidate the Allocate or Binding request was sent from. The base of a relayed candidate is that candidate itself. And if a relayed candidate is identical to a host candidate (which can happen in rare cases), the relayed candidate MUST be discarded ๐Ÿ—‘๏ธ

If an IPv6-only agent is on a network that uses NAT64 [RFC6146] and DNS64 [RFC6147], it may also gather IPv4 server-reflexive and/or relayed candidates from IPv4-only STUN or TURN servers ๐ŸŒ IPv6-only agents SHOULD also use IPv6 prefix discovery [RFC7050] to find the IPv6 prefix used by NAT64 (if there is one), and generate server-reflexive candidates for each IPv6-only interface to match ๐Ÿง  The NAT64 server-reflexive candidates are prioritized like IPv4 server-reflexive candidates โœจ

5.1.1.3. Computing Foundations

The ICE agent assigns each candidate a foundation. Two candidates have the same foundation when ALL of these are true:

  • They have the same type (host, relayed, server reflexive, or peer reflexive) ๐ŸŽ€
  • Their bases have the same IP address (the ports can be different) ๐ŸŒธ
  • For reflexive and relayed candidates, the STUN or TURN servers used to get them have the same IP address (the IP address the agent used to contact the STUN or TURN server) ๐Ÿงš
  • They were obtained using the same transport protocol (TCP, UDP) ๐Ÿš€

Similarly, two candidates have different foundations if their types are different, their bases have different IP addresses, the STUN or TURN servers used to get them have different IP addresses (the IP addresses the agent used to contact those servers), or their transport protocols are different ๐Ÿ’…

Careful with those "MUST"-level "ALL" words, sorry, I mean the rule is just that all four bullets have to match for the same foundation. Easy peasy ๐Ÿซถ

5.1.1.4. Keeping Candidates Alive

Once server-reflexive and relayed candidates are allocated, they MUST be kept alive until ICE processing has completed, as described in Section 8.3 โฐ For server-reflexive candidates learned through a Binding request, the bindings MUST be kept alive by sending additional Binding requests to the server. Refreshes for allocations are done with the Refresh transaction, as described in [RFC5766] ๐Ÿ”„ The Refresh requests will also refresh the server-reflexive candidate. Two birds, one stone ๐Ÿฆ

Host candidates don't time out, but their addresses may change or disappear for a bunch of reasons ๐ŸŒช๏ธ An ICE agent SHOULD monitor the interfaces it uses, invalidate candidates whose base has gone away, and acquire new candidates as appropriate when new IP addresses (on new or currently used interfaces) show up ๐Ÿ‘€

5.1.2. Prioritizing Candidates

The prioritization process gives each candidate a priority. Each candidate for a data stream MUST have a unique priority, and that priority MUST be a positive integer between 1 and (2**31 - 1) ๐Ÿ”ข ICE uses this priority to decide the order of connectivity checks and how much each candidate is preferred. Higher-priority values win over lower ones ๐Ÿ‘‘

An ICE agent SHOULD compute this priority using the formula in Section 5.1.2.1 and pick its parameters using the guidelines in Section 5.1.2.2. If an agent goes with a different formula, ICE may take longer to converge, since the agents won't be coordinated in their checks ๐Ÿข

The prioritization process is the same for both the initiating and the responding agent ๐Ÿค

The recommended formula mixes a preference for the candidate type (server reflexive, peer reflexive, relayed, and host), a preference for the IP address the candidate was obtained from, and a component ID, like this ๐Ÿงฎ

priority = (2^24)*(type preference) +
           (2^8)*(local preference) +
           (2^0)*(256 - component ID)

The type preference MUST be an integer from 0 (lowest preference) to 126 (highest preference) inclusive. It MUST be identical for all candidates of the same type, and MUST be different for candidates of different types. The type preference for peer-reflexive candidates MUST be higher than that of server-reflexive candidates ๐Ÿ’œ Setting the value to 0 means candidates of this type only get used as a last resort ๐Ÿฅฒ Note that candidates gathered through the procedures of Section 5.1.1 will never be peer-reflexive candidates. Candidates of this type are learned from the connectivity checks ICE performs ๐Ÿ”

The local preference MUST be an integer from 0 (lowest preference) to 65535 (highest preference) inclusive. When there's only a single IP address, this value SHOULD be set to 65535 ๐Ÿ’ฏ If there are multiple candidates for a particular component of a particular data stream that have the same type, the local preference MUST be unique for each one. If an ICE agent is dual stack, the local preference SHOULD be set according to the current best practice described in [RFC8421] ๐ŸŒ

The component ID MUST be an integer between 1 and 256 inclusive ๐ŸŽฏ

5.1.2.2. Guidelines for Choosing Type and Local Preferences

okay so the type preferences that are RECOMMENDED are 126 for host candidates, 110 for peer-reflexive candidates, 100 for server-reflexive candidates, and 0 for relayed candidates ๐ŸŽ€ relayed gets the lowest one, no cap ๐Ÿ˜ญ

if an ICE agent is multihomed with multiple IP addresses, the recommendations in [RFC8421] SHOULD be followed ๐ŸŒธ and if you're using multiple TURN servers, the local priorities for candidates from those servers get picked kinda the same way as multihomed local candidates ๐Ÿฆ‹ the local preference is how you rank the servers, but it MUST be unique for each one ๐Ÿ‘‘

when picking type preferences, agents can look at stuff like latency, packet loss, cost, network topology, security, privacy, and others ๐Ÿ’œ

5.1.3. Eliminating Redundant Candidates

next up, the ICE agents (initiating and responding) clean house and get rid of redundant candidates ๐Ÿงนโœจ two candidates can have the same transport address but different bases, and those are NOT redundant, bestie ๐Ÿ™ˆ a server-reflexive candidate and a host candidate are often redundant when the agent isn't behind a NAT ๐ŸŒˆ a candidate is redundant if and only if its transport address and base equal those of another candidate. the agent SHOULD eliminate the redundant candidate with the lower priority ๐Ÿ’€

5.2. Lite Implementation Procedures

lite implementations only use host candidates ๐Ÿงš for each IP address, no matter the IP address family, there MUST be zero or one candidate. since lite can't dynamically pick between candidates, including more than one candidate from a given IP address family is NOT RECOMMENDED, because only a connectivity check can truly tell you which address to use ๐Ÿ˜ญ instead, it is RECOMMENDED that agents with multiple public IP addresses run full ICE implementations so they use their addresses to the max ๐Ÿ‘‘

each component gets an ID called the "component ID" ๐ŸŽ€ for RTP/RTCP data streams, unless RTCP is multiplexed on the same port as RTP, RTP itself has component ID 1 and RTCP has component ID 2. if an agent is using RTCP without multiplexing, it MUST obtain candidates for it ๐Ÿ’… but no component ID 2 doesn't automatically mean RTCP/RTP multiplexing, because it could also just mean RTCP isn't being used ๐Ÿ™ˆ

each candidate gets a foundation. the foundation MUST be different for two candidates allocated from different IP addresses; otherwise, it MUST be the same ๐Ÿ”ฅ a simple integer that goes up for each IP address will do the trick โœจ also, each candidate MUST be assigned a unique priority among all candidates for the same data stream. if the formula in Section 5.1.2.1 is used to calculate the priority, the type preference SHOULD be set to 126 ๐Ÿ’– if a host is IPv4 only, the local preference SHOULD be set to 65535 ๐Ÿ“ if a host is IPv6 or dual stack, the local preference SHOULD be set to the precedence value for IP addresses described in RFC 6724 [RFC6724].

next, an agent picks a default candidate for each component of each data stream ๐Ÿฆ‹ if a host is IPv4 only, there's only one candidate per component per data stream, so that one is the default (easy ๐Ÿ˜Œ). if a host is IPv6 only, the default would typically be a globally scoped IPv6 address ๐ŸŒ. dual-stack hosts SHOULD allow configuration of whether IPv4 or IPv6 is used for the default candidate, and that config needs to be based on which one the administrator believes has a higher chance of success in the current network environment ๐Ÿ’œ

these procedures are the same for the initiating and responding agents ๐Ÿซถ

5.3. Exchanging Candidate Information

ICE agents (initiating and responding) need some candidate info to get exchanged ๐Ÿ“ฌ each ICE usage MUST define how that info is exchanged with the using protocol. here's what needs to go across:

  • Candidates: one or more candidates. For each candidate:
    • Address: the IP address and transport protocol port of the candidate.
    • Transport: the transport protocol of the candidate. This MAY be omitted if the using protocol only runs over a single transport protocol.
    • Foundation: a sequence of up to 32 characters.
    • Component ID: the component ID of the candidate. This MAY be omitted if the using protocol does not use the concept of components.
    • Priority: the 32-bit priority of the candidate.
    • Type: the type of the candidate.
    • Related Address and Port: the related IP address and port of the candidate. These MAY be omitted or set to invalid values if the agent does not want to reveal them, e.g., for privacy reasons.
    • Extensibility Parameters: the using protocol might define ways to add new per-candidate ICE parameters in the future.
  • Lite or Full: whether the agent is a lite agent or a full agent.
  • Connectivity-Check Pacing Value: the pacing value for connectivity checks that the agent wants to use. This MAY be omitted if the agent wants to use a defined default value.
  • Username Fragment and Password: values used to perform connectivity checks. The values MUST be unguessable, with at least 128 bits of random number generator output used to generate the password, and at least 24 bits of output to generate the username fragment ๐Ÿ”
  • Extensions: new media-stream or session-level attributes (ICE options).

if the using protocol is vulnerable to, and able to detect, ICE mismatch (Section 5.4), there needs to be a way for the detecting agent to tell its peer about it. it's a boolean flag ๐Ÿšฉ

the using protocol may (or may not) need to handle backwards compatibility with older implementations that don't support ICE. if a fallback to non-ICE is supported and being used, then presumably the using protocol gives a way to convey the default candidate (its IP address and port) along with the ICE parameters ๐ŸŽ€

once an agent has sent its candidate info, it MUST be prepared to receive both STUN and data packets on each candidate. as Section 12.1 covers, data packets can be sent to a candidate before it shows up as the default destination for data ๐Ÿซฃ

5.4. ICE Mismatch

certain middleboxes, like ALGs, can change signaling info in ways that break ICE (for example, by rewriting IP addresses in SDP) ๐Ÿ˜ค this is called "ICE mismatch". if the using protocol is vulnerable to ICE mismatch, the responding agent needs to be able to detect it and tell the peer ICE agent about it ๐Ÿ•ต๏ธโ€โ™€๏ธ

each using protocol needs to define whether it's vulnerable to ICE mismatch, how ICE mismatch gets detected, and whether any specific actions need to happen once it's detected ๐Ÿ“‹

6. ICE Candidate Processing โœจ

once an ICE agent has gathered its candidates and exchanged them with its peer (Section 5), it figures out its own role ๐Ÿ‘‘ full implementations also form checklists and start running connectivity checks with the peer ๐Ÿƒโ€โ™€๏ธ

6.1. Procedures for Full Implementation

6.1.1. Determining Role

for each session, each ICE agent (initiating and responding) takes on a role ๐ŸŽญ there are two roles: controlling and controlled. the controlling agent is responsible for choosing the final candidate pairs used for communication ๐Ÿ’… the sections below walk through the exact procedures for controlling and controlled agents.

here are the rules for determining the role and what it changes:

Both agents are full: the initiating agent that started ICE processing MUST take the controlling role, and the other MUST take the controlled role ๐Ÿค both agents form checklists, run the ICE state machines, and generate connectivity checks. the controlling agent runs the logic in Section 8.1 to nominate pairs that become the selected pairs (if the connectivity checks tied to the nominations succeed), and then both agents end ICE as described in Section 8.1.2 ๐Ÿ

One agent full, one lite: the full agent MUST take the controlling role, and the lite agent MUST take the controlled role ๐ŸŒŸ the full agent forms checklists, runs the ICE state machines, and generates connectivity checks. it runs the logic in Section 8.1 to nominate pairs that become the selected pairs (if the connectivity checks for the nominations succeed), and uses the logic in Section 8.1.2 to end ICE. the lite implementation just listens for connectivity checks, receives and responds to them, and then concludes ICE as described in Section 8.2 ๐Ÿฆ‹ for the lite implementation, the state of ICE processing for each data stream is considered to be Running, and the state of ICE overall is Running too ๐Ÿ’œ

Both lite: the initiating agent that started ICE processing MUST take the controlling role, and the other MUST take the controlled role ๐Ÿซถ in this case, no connectivity checks are ever sent. instead, once candidates are exchanged, each agent does the processing described in Section 8 without connectivity checks. it's possible that both agents believe they're controlled or both believe they're controlling. in the latter case, the conflict gets resolved through the glare detection capabilities of the signaling protocol that does the candidate exchange ๐Ÿ˜ญ the state of ICE processing for each data stream is considered to be Running, and the state of ICE overall is Running.

once the roles are determined for a session, they stick around for the whole session lifetime ๐Ÿ”’ the roles can be redetermined as part of an ICE restart (Section 9), but an ICE agent MUST NOT redetermine the role as part of an ICE restart unless one or more of the following criteria is fulfilled:

Full becomes lite: if the controlling agent is full and switches to lite, the roles MUST be redetermined if the peer agent is also full ๐Ÿ”„

Role conflict: if the ICE restart causes a role conflict, the roles might be redetermined because of the role conflict procedures in Section 7.3.1.1 โšก

NOTE: There are certain Third Party Call Control (3PCC) [RFC3725] scenarios where an ICE restart might cause a role conflict. ๐Ÿšจ
NOTE: The agents need to tell each other whether they're full or lite before the roles get determined. The mechanism for that is specific to the signaling protocol and outside the scope of this document ๐Ÿ“ฃ

an agent MUST accept if the peer initiates a redetermination of the roles, even if the criteria for doing so aren't fulfilled. this can happen if the peer is compliant with RFC 5245 ๐Ÿซถ

6.1.2. Forming the Checklists

there's one checklist for each data stream ๐Ÿ“ to form a checklist, the initiating and responding ICE agents form candidate pairs, compute pair priorities, order pairs by priority, prune pairs, remove lower-priority pairs, and set checklist states ๐Ÿ’… if candidates get added to a checklist (for example, because peer-reflexive candidates were detected), the agent re-does these steps for the updated checklist ๐Ÿ”

6.1.2.1. Checklist State โœจ

okay so every checklist has a state ๐Ÿ’… which just tells you how the ICE checks are going for its data stream ๐Ÿฆ‹ there are three of them:

  • Running ๐Ÿƒโ€โ™€๏ธ: the checklist is neither Completed nor Failed yet. Every checklist starts out Running ๐ŸŒธ
  • Completed ๐ŸŽ‰: the checklist has a nominated pair for every component of the data stream. ate ๐Ÿ‘‘
  • Failed ๐Ÿ’€: the checklist doesn't have a valid pair for each component, AND every candidate pair in it is either Failed or Succeeded. so basically one component has pairs that are ALL Failed, which means that component failed, which means the whole checklist failed ๐Ÿ˜ญ it's giving domino effect

6.1.2.2. Forming Candidate Pairs ๐ŸŽ€

the ICE agent pairs each local candidate with each remote candidate for the same component of the same data stream with the same IP address family ๐Ÿ’– not every local candidate is gonna find a partner though, and not every remote candidate will either ๐Ÿ™ˆ that happens when one agent doesn't include candidates for all the components of a data stream. when that's the case, the number of components for that data stream gets effectively reduced, and it's treated as the minimum, across both agents, of the maximum component ID each agent gave across all components for that data stream โœจ very math, very cute

for RTP, this happens when one agent gives candidates for RTCP and the other one doesn't ๐ŸŽง another example: the initiating agent can multiplex RTP and RTCP on the same port [RFC5761] ๐Ÿฆ‹ but since it doesn't know whether the peer can do that multiplexing, it includes candidates for RTP and RTCP on separate ports. if the peer CAN multiplex, it'll only include a single component for each candidate, for the combined RTP/RTCP mux. then ICE just acts like there's one component for that candidate. iconic behavior honestly ๐Ÿ’œ

with IPv6, it's super common for a host to have multiple host candidates for each interface ๐ŸŒˆ so to keep the candidate pairs from blowing up and to skip pairs that are highly unlikely to work, IPv6 link-local addresses MUST NOT be paired with anything other than link-local addresses ๐Ÿซถ not me pairing a link-local with a global address ๐Ÿ™…โ€โ™€๏ธ

the candidate pairs whose local and remote candidates are BOTH the default candidates for a particular component are called the "default candidate pair" for that component โœจ this is the pair that would carry the data if neither agent were ICE aware. main character pair, no cap ๐Ÿ‘‘

here's Figure 5, which shows how transport addresses, candidates, candidate pairs, and checklists all relate to each other ๐Ÿงš

          +--------------------------------------------+
          |                                            |
          | +---------------------+                    |
          | |+----+ +----+ +----+ |   +Type            |
          | || IP | |Port| |Tran| |   +Priority        |
          | ||Addr| |    | |    | |   +Foundation      |
          | |+----+ +----+ +----+ |   +Component ID    |
          | |      Transport      |   +Related Address |
          | |        Addr         |                    |
          | +---------------------+   +Base            |
          |             Candidate                      |
          +--------------------------------------------+
          *                                         *
          *    *************************************
          *    *
        +-------------------------------+
        |                               |
        | Local     Remote              |
        | +----+    +----+   +default?  |
        | |Cand|    |Cand|   +valid?    |
        | +----+    +----+   +nominated?|
        |                    +State     |
        |                               |
        |                               |
        |          Candidate Pair       |
        +-------------------------------+
        *                              *
        *                  ************
        *                  *
        +------------------+
        |  Candidate Pair  |
        +------------------+
        +------------------+
        |  Candidate Pair  |
        +------------------+
        +------------------+
        |  Candidate Pair  |
        +------------------+

             Checklist


            Figure 5: Conceptual Diagram of a Checklist

6.1.2.3. Computing Pair Priority and Ordering Pairs ๐Ÿ”ฅ

the ICE agent works out a priority for each candidate pair ๐Ÿ’… let G be the priority of the candidate from the controlling agent, and D be the priority of the candidate from the controlled agent. then the pair priority is:

pair priority = 2^32*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0)

then the agent sorts each checklist in decreasing order of pair priority ๐Ÿ“ˆ if two pairs have the exact same priority, the order between them is arbitrary, so no drama either way ๐ŸŒธ

6.1.2.4. Pruning the Pairs โœ‚๏ธ

this sorted list of pairs is what decides the sequence of connectivity checks that get run ๐Ÿงšโ€โ™€๏ธ each check sends a request from a local candidate to a remote candidate. but here's the tea: an ICE agent can't send requests directly from a reflexive candidate (server reflexive or peer reflexive), only from its base ๐Ÿ˜ญ so the agent goes through the sorted list next, and for every pair where the local candidate is reflexive, the candidate MUST be replaced by its base ๐Ÿซถ

then the agent prunes each checklist. it removes a candidate pair if it's redundant with a higher-priority pair in the same checklist ๐Ÿ’– two pairs are redundant if their local candidates have the same base AND their remote candidates are identical. what's left is an ordered sequence of pairs, called the "checklist" for that data stream โœจ

6.1.2.5. Removing Lower-Priority Pairs ๐Ÿ›ก๏ธ

okay this one's serious bestie ๐Ÿ’€ to limit the attacks described in Section 19.5.1, an ICE agent MUST limit the total number of connectivity checks it performs across ALL the checklists in the checklist set ๐Ÿ”’ it does this by limiting the total number of candidate pairs in the checklist set. the default limit is 100, but the value MUST be configurable ๐Ÿ”ง the limit gets enforced by discarding lower-priority candidate pairs within each checklist until the total number of pairs in the checklist set is smaller than the limit value. that discarding SHOULD be done evenly, so every checklist loses the same amount ๐ŸŽ€

it is RECOMMENDED to pick a lower limit than the default when possible, and to set it to the maximum number of plausible candidate pairs that might show up in an actual deployment ๐ŸŒท the whole configuration thing is basically a tool for fixing this value out in the field if it turns out to be problematic once deployed. so you can tweak it, periodt ๐Ÿ’œ

6.1.2.6. Computing Candidate Pair States โœจ

okay so every candidate pair in the checklist has a foundation (basically the combo of the local and remote candidates' foundations in that pair) and one of five vibes. ๐Ÿ’…

  • Waiting ๐Ÿ•: no check has gone out for this pair yet, but it isn't Frozen, so it's ready to go.
  • In-Progress ๐Ÿƒโ€โ™€๏ธ: a check was sent and we're still waiting on the transaction to finish.
  • Succeeded ๐ŸŽ‰: a check was sent and it came back with a successful result. iconic.
  • Failed ๐Ÿ’€: a check was sent and it failed. Either no response ever showed up, or a failure response came back.
  • Frozen ๐ŸงŠ: no check has been sent, and it can't be sent until the pair gets unfrozen and moves into Waiting. no skipping the line bestie.

Pairs move between these states the way Figure 6 shows ๐Ÿ‘‡

      +-----------+
      |           |
      |           |
      |  Frozen   |
      |           |
      |           |
      +-----------+
            |
            |unfreeze
            |
            V
      +-----------+         +-----------+
      |           |         |           |
      |           | perform |           |
      |  Waiting  |-------->|In-Progress|
      |           |         |           |
      |           |         |           |
      +-----------+         +-----------+
                                  / |
                                //  |
                              //    |
                            //      |
                           /        |
                         //         |
               failure //           |success
                     //             |
                    /               |
                  //                |
                //                  |
              //                    |
             V                      V
      +-----------+         +-----------+
      |           |         |           |
      |           |         |           |
      |   Failed  |         | Succeeded |
      |           |         |           |
      |           |         |           |
      +-----------+         +-----------+

              Figure 6: Pair State Finite State Machine (FSM)

so here's how the starting states get set up for each pair in a checklist. it's giving step-by-step energy ๐ŸŒธ

  1. The checklists go into an ordered list (the order depends on each ICE usage), and that list is called the "checklist set".
  2. The ICE agent starts by putting every single candidate pair in the Frozen state ๐ŸงŠ.
  3. The agent sets every checklist in the checklist set to the Running state.
  4. For each foundation, the agent picks exactly one candidate pair and sets it to Waiting (aka unfreezing it). To find that pair, the agent looks at the first checklist (following the usage-defined checklist set order) that has that foundation, then picks the first candidate pair with it, ordered by the lowest component ID and then the highest priority if the component IDs are equal.
NOTE: The procedures above are different from RFC 5245, where only candidate pairs in the first checklist were initially placed in the Waiting state. Now it applies to candidate pairs in the first checklist that have that foundation, even if the checklist is not the first one in the checklist set. ๐Ÿซถ

here's an example table ๐Ÿ“

Table legend:

  • Each row (m1, m2,...) represents a checklist associated with a data stream. m1 represents the first checklist in the checklist set.
  • Each column (f1, f2,...) represents a foundation. Every candidate pair within a given column share the same foundation.
  • f-cp represents a candidate pair in the Frozen state.
  • w-cp represents a candidate pair in the Waiting state.
  1. The agent sets all of the pairs in the checklist set to the Frozen state.
      f1    f2    f3    f4    f5
    -----------------------------
m1 | f-cp  f-cp  f-cp
   |
m2 | f-cp  f-cp  f-cp  f-cp
   |
m3 | f-cp                    f-cp
  1. For each foundation, the candidate pair with the lowest component ID is placed in the Waiting state, unless a candidate pair associated with the same foundation has already been put in the Waiting state in one of the other examined checklists in the checklist set.
      f1    f2    f3    f4    f5
    -----------------------------
m1 | w-cp  w-cp  w-cp
   |
m2 | f-cp  f-cp  f-cp  w-cp
   |
m3 | f-cp                    w-cp

                    Table 1: Pair State Example

In the first checklist (m1), the candidate pair for each foundation is placed in the Waiting state, as no pairs for the same foundations have yet been placed in the Waiting state.

In the second checklist (m2), the candidate pair for foundation f4 is placed in the Waiting state. The candidate pair for foundations f1, f2, and f3 are kept in the Frozen state, as candidate pairs for those foundations have already been placed in the Waiting state (within checklist m1).

In the third checklist (m3), the candidate pair for foundation f5 is placed in the Waiting state. The candidate pair for foundation f1 is kept in the Frozen state, as a candidate pair for that foundation has already been placed in the Waiting state (within checklist m1).

Once each checklist have been processed, one candidate pair for each foundation in the checklist set has been placed in the Waiting state. ๐ŸŽ€

6.1.3. ICE State ๐ŸŒˆ

The ICE agent has a state that's decided by the state of its checklists. It's Completed if all checklists are Completed, Failed if all checklists are Failed, or Running otherwise.

6.1.4. Scheduling Checks โฐ

6.1.4.1. Triggered-Check Queue ๐Ÿฆ‹

Once the ICE agent has computed the checklists and created the checklist set (as described in Section 6.1.2), the agent starts doing connectivity checks, both ordinary and triggered. For triggered checks, the agent keeps a FIFO queue for each checklist, called the "triggered-check queue". This queue holds candidate pairs that get checks sent at the next available opportunity. It starts out empty. ๐Ÿซง

6.1.4.2. Performing Connectivity Checks ๐Ÿš€

The timer Ta controls when ordinary and triggered connectivity checks get generated. As soon as the initial states for the candidate pairs in the checklist set are set, a check gets done for a candidate pair in the first checklist that's Running, following the procedures in Section 7. After that, every time Ta fires, the next Running checklist in the checklist set gets picked and a check is done for a candidate in it. Once the last Running checklist in the checklist set has been processed, we loop back to the first one. the cycle continues ๐Ÿ”

Whenever Ta fires, the ICE agent does a check for a candidate pair in the picked checklist by following these steps:

  1. If the triggered-check queue for the checklist has one or more candidate pairs in it, the agent removes the top pair from the queue, does a connectivity check on it, sets its state to In-Progress, and skips the remaining steps.
  2. If no candidate pair is in the Waiting state, and there are one or more pairs in the Frozen state, the agent looks at the foundation for each Frozen pair. For a given foundation, if no pair (in any checklist in the checklist set) is in the Waiting or In-Progress state, the agent sets that pair's state to Waiting and moves on to the next step.
  3. If one or more candidate pairs are in the Waiting state, the agent picks the highest-priority one (if several share the same priority, the pair with the lowest component ID wins), does a connectivity check on it, sets its state to In-Progress, and skips the remaining steps.
  4. If this step is reached, no check could be done for the picked checklist. So, without waiting for Ta to fire again, the agent selects the next Running checklist and goes back to step 1. If this happens for every Running checklist, meaning there are no candidate pairs left to check, the agent stops these steps.

Once the agent has picked a candidate pair to check, it starts a check and sends the Binding request from the base associated with the pair's local candidate to the pair's remote candidate, as described in Section 7.2.4. ๐Ÿ“จ

Based on local policy, an agent MAY choose to stop performing connectivity checks for one or more checklists in the checklist set at any time. However, only the controlling agent is allowed to conclude ICE (Section 8). ๐Ÿ‘‘

To compute the message integrity for the check, the agent uses the remote username fragment and password it learned from the candidate information it got from its peer. The agent already knows the local username fragment for its own candidate. ๐Ÿ”

6.2. Lite Implementation Procedures ๐Ÿชถ

Lite implementations skip most of the steps in Section 6, except for verifying the peer's ICE support and determining its role in the ICE processing. bestie, that's the whole job ๐Ÿ’–

If the lite implementation is the controlling agent (which will only happen if the peer ICE agent is also a lite implementation), it picks a candidate pair from the ones in the candidate exchange (for IPv4, there is only ever one pair). Then it updates the peer with the new candidate information reflecting that pick, if needed (for an IPv4-only host, it is never needed).

7. Performing Connectivity Checks ๐Ÿ”

This section describes how connectivity checks are performed.

An ICE agent MUST be compliant to [RFC5389]. A full implementation acts both as a STUN client and a STUN server, while a lite implementation only acts as a STUN server (as it does not generate connectivity checks). ๐ŸŽฏ

7.1. STUN Extensions ๐Ÿงฉ

ICE extends STUN with the attributes: PRIORITY, USE-CANDIDATE, ICE-CONTROLLED, and ICE-CONTROLLING. These attributes are formally defined in Section 16.1. This section describes how they're used.

The attributes are only applicable to ICE connectivity checks.

7.1.1. PRIORITY ๐Ÿ“Š

The PRIORITY attribute MUST be included in a Binding request and be set to the value computed by the algorithm in Section 5.1.2 for the local candidate, but with the candidate type preference of peer-reflexive candidates.

7.1.2. USE-CANDIDATE ๐ŸŽฏ

The controlling agent MUST include the USE-CANDIDATE attribute in order to nominate a candidate pair (Section 8.1.1). The controlled agent MUST NOT include the USE-CANDIDATE attribute in a Binding request. ๐Ÿ™…โ€โ™€๏ธ

7.1.3. ICE-CONTROLLED and ICE-CONTROLLING ๐ŸŽญ

The controlling agent MUST include the ICE-CONTROLLING attribute in a Binding request. The controlled agent MUST include the ICE-CONTROLLED attribute in a Binding request.

The content of either attribute is used as tiebreaker values when an ICE role conflict occurs (Section 7.3.1.1). ๐ŸฅŠ

7.2. STUN Client Procedures ๐Ÿ’Œ

7.2.1. Creating Permissions for Relayed Candidates โœจ

okay so bestie, if your connectivity check is going out through a relayed local candidate, you MUST create a permission first ๐ŸŽ€ unless you already made one before. You'd have made one before if you told the TURN server to create a permission for that relayed candidate toward the IP address of the remote candidate ๐Ÿฆ‹. To do this, the ICE agent follows the procedures in [RFC5766] ๐Ÿ’…. The permission MUST be created toward the IP address of the remote candidate, no exceptions ๐Ÿซถ. It is RECOMMENDED that the agent waits to create a TURN channel until ICE completes ๐ŸŒธ, because then permissions for connectivity checks usually get made with a CreatePermission request ๐Ÿ’–. Once it exists, the agent MUST keep that permission active until ICE concludes ๐Ÿ‘‘. Main character energy means never letting your permission lapse mid-call ๐Ÿ˜ญ.

7.2.2. Forming Credentials ๐Ÿ”

A connectivity-check Binding request MUST utilize the STUN short-term credential mechanism ๐Ÿ’œ.

The username is made by smooshing together the username fragment your peer gave you with your own username fragment, separated by a colon (":") ๐Ÿงš.

The password is just equal to the password your peer provided โœจ.

Here's an example so it clicks ๐Ÿ“. Say ICE agent L is the initiating agent and ICE agent R is the responding agent. Agent L included a username fragment of LFRAG for its candidates and a password of LPASS. Agent R provided a username fragment of RFRAG and a password of RPASS. A connectivity check from L to R utilizes the username RFRAG:LFRAG and a password of RPASS. A connectivity check from R to L utilizes the username LFRAG:RFRAG and a password of LPASS. The responses utilize the same usernames and passwords as the requests (note that the USERNAME attribute is not present in the response) ๐Ÿ™ˆ.

7.2.3. Diffserv Treatment ๐ŸŒˆ

If the agent is using Differentiated Services Code Point (DSCP) markings [RFC2475] in data packets that it will send, the agent SHOULD apply the same markings to Binding requests and responses that it will send ๐ŸŽ€.

If multiple DSCP markings are used on the data packets, the agent SHOULD choose one of them for use with the connectivity check ๐Ÿ’….

7.2.4. Sending the Request ๐Ÿš€

A connectivity check is generated by sending a Binding request from the base associated with a local candidate to a remote candidate ๐Ÿฆ‹. [RFC5389] describes how Binding requests are constructed and generated ๐Ÿ“–.

Support for backwards compatibility with RFC 3489 MUST NOT be assumed when performing connectivity checks ๐Ÿ™…. The FINGERPRINT mechanism MUST be used for connectivity checks ๐Ÿ’–.

7.2.5. Processing the Response ๐Ÿ“ฌ

This section defines extra procedures for processing Binding responses that are specific to ICE connectivity checks โœจ.

When a Binding response comes back, it gets matched to its Binding request using the transaction ID [RFC5389] ๐Ÿงš. That links the response to the candidate pair the request was sent for ๐Ÿ”—. After that, the response gets processed according to the role conflict, failure, or success procedures below, depending on what happened ๐Ÿ’….

7.2.5.1. Role Conflict โš”๏ธ

If the Binding request generates a 487 (Role Conflict) error response (Section 7.3.1.1), and the ICE agent included an ICE-CONTROLLED attribute in the request, the agent MUST switch to the controlling role ๐Ÿ‘‘. If the agent included an ICE-CONTROLLING attribute in the request, the agent MUST switch to the controlled role ๐ŸŒธ.

Once the agent has switched roles, the agent MUST add the candidate pair whose check generated the 487 error response to the triggered-check queue associated with the checklist that the pair belongs to, and set the candidate pair state to Waiting ๐Ÿฆ‹. When that triggered connectivity check is performed later, the ICE-CONTROLLING/ICE-CONTROLLED attribute of the Binding request will show the agent's new role ๐Ÿ’œ. The agent MUST change the tiebreaker value ๐ŸŽ€.

NOTE: A role switch requires an agent to recompute pair priorities (Section 6.1.2.3), since the priority values depend on the role ๐Ÿ™ˆ.

NOTE: A role switch will also affect whether the agent is responsible for nominating candidate pairs, and whether the agent is responsible for starting the exchange of updated candidate information with the peer once ICE is concluded ๐Ÿ“.

7.2.5.2. Failure ๐Ÿ’€

This section describes the cases when the candidate pair state is set to Failed ๐Ÿ™….

NOTE: When the ICE agent sets the candidate pair state to Failed because of a connectivity-check error, the agent does not change the states of other candidate pairs with the same foundation ๐Ÿซถ.

7.2.5.2.1. Non-Symmetric Transport Addresses ๐Ÿชž

The ICE agent MUST check that the source and destination transport addresses in the Binding request and response are symmetric ๐Ÿ”. That means the source IP address and port of the response MUST equal the destination IP address and port the Binding request was sent to, and the destination IP address and port of the response MUST equal the source IP address and port the Binding request was sent from ๐Ÿ’…. If the addresses aren't symmetric, the agent MUST set the candidate pair state to Failed ๐Ÿ˜ญ.

7.2.5.2.2. ICMP Error ๐ŸŒฉ๏ธ

An ICE agent MAY support processing of ICMP errors for connectivity checks ๐Ÿฆ‹. If the agent supports it, and a Binding request generates a hard ICMP error, the agent SHOULD set the state of the candidate pair to Failed ๐Ÿ’–. Implementers need to be aware that ICMP errors can be used as a Denial-of-Service (DoS) attack method when deciding how and whether to process ICMP errors ๐Ÿšจ.

7.2.5.2.3. Timeout โฐ

If the Binding request transaction times out, the ICE agent MUST set the candidate pair state to Failed ๐Ÿ’€.

7.2.5.2.4. Unrecoverable STUN Response ๐Ÿ›‘

If the Binding request generates a STUN error response that is unrecoverable [RFC5389], the ICE agent SHOULD set the candidate pair state to Failed ๐Ÿ™ƒ.

7.2.5.3. Success ๐ŸŽ‰

A connectivity check counts as a success if each of the following criteria is true ๐Ÿ†:

  • The Binding request generated a success response; and
  • The source and destination transport addresses in the Binding request and response are symmetric.

If a check is a success, the ICE agent performs (in order) the actions described in the following sections ๐ŸŒŸ.

7.2.5.3.1. Discovering Peer-Reflexive Candidates ๐Ÿ”ญ

The ICE agent MUST check the mapped address from the STUN response ๐Ÿ‘€. If the transport address doesn't match any of the local candidates the agent knows about, the mapped address represents a new candidate: a peer-reflexive candidate ๐Ÿ†•. Like other candidates, a peer-reflexive candidate has a type, base, priority, and foundation ๐Ÿงฉ. They're computed as follows:

  • The type is peer reflexive.
  • The base is the local candidate of the candidate pair from which the Binding request was sent.
  • The priority is the value of the PRIORITY attribute in the Binding request.
  • The foundation is described in Section 5.1.1.3.

The peer-reflexive candidate then gets added to the list of local candidates for the data stream. The username fragment and password are the same as for all other local candidates for that data stream ๐ŸŽ€.

The ICE agent doesn't need to pair the peer-reflexive candidate with remote candidates, because a valid pair will be created due to the procedures in Section 7.2.5.3.2 โœจ. If an agent wants to pair the peer-reflexive candidate with remote candidates other than the one in the valid pair that will be generated, the agent MAY provide updated candidate information to the peer that includes the peer-reflexive candidate ๐Ÿงš. This will cause the peer-reflexive candidate to be paired with all other remote candidates ๐ŸŒˆ.

7.2.5.3.2. Constructing a Valid Pair ๐Ÿ’Ž

The ICE agent constructs a candidate pair whose local candidate equals the mapped address of the response and whose remote candidate equals the destination address the request was sent to ๐ŸŽฏ. This is called a "valid pair" ๐Ÿ’œ.

The valid pair might be the same as the pair that generated the connectivity check, a different pair in the checklist, or a pair that isn't in the checklist right now ๐Ÿฆ‹.

The agent maintains a separate list, called the "valid list" ๐Ÿ“‹. There is a valid list for each checklist in the checklist set ๐Ÿ—‚๏ธ. The valid list will contain valid pairs. Initially, each valid list is empty ๐Ÿซง.

Each valid pair within the valid list has a flag, called the "nominated flag" ๐Ÿšฉ. When a valid pair is added to a valid list, the flag value is set to 'false' โŒ.

A valid pair gets added to a valid list like this ๐ŸŒธ:

  1. If the valid pair equals the pair that generated the check, the pair is added to the valid list associated with the checklist that the pair belongs to; or
  2. If the valid pair equals another pair in a checklist, that pair is added to the valid list associated with the checklist of that pair. The pair that generated the check is not added to a valid list; or
  3. If the valid pair is not in any checklist, the agent computes the priority for the pair based on the priority of each candidate, using the algorithm in Section 6.1.2. The priority of the local candidate depends on its type. Unless the type is peer reflexive, the priority equals the priority signaled for that candidate in the candidate exchange. If the type is peer reflexive, it equals the PRIORITY attribute the agent placed in the Binding request that just completed. The priority of the remote candidate is taken from the candidate information of the peer. If the candidate doesn't appear there, then the check was a triggered check to a new remote candidate. In that case, the priority is taken as the value of the PRIORITY attribute in the Binding request that triggered the check that just completed. The pair is then added to the valid list ๐Ÿ“ฅ.

NOTE: It will be very common that the valid pair is not in any checklist ๐Ÿ™ˆ. Remember that the checklist has pairs whose local candidates are never reflexive; those pairs had their local candidates converted to the base of the reflexive candidates and were then pruned if they were redundant ๐Ÿงน. When the response to the Binding request arrives, the mapped address will be reflexive if there is a NAT between the two ๐ŸŒ. In that case, the valid pair will have a local candidate that doesn't match any of the pairs in the checklist ๐Ÿ’ซ.

7.2.5.3.3. Updating Candidate Pair States ๐Ÿ”„

The ICE agent sets the states of both the candidate pair that generated the check and the constructed valid pair (which may be different) to Succeeded ๐Ÿ….

The agent MUST set the states for all other Frozen candidate pairs in all checklists with the same foundation to Waiting ๐ŸงŠโžก๏ธโณ.

NOTE: Within a given checklist, candidate pairs with the same foundations will typically have different component ID values ๐Ÿงฉ๐Ÿ’•.

7.2.5.3.4. Updating the Nominated Flag โœจ

okay so if the controlling agent sends a Binding request with the USE-CANDIDATE attribute set, and the ICE agent gets a successful response to it, the agent sets the nominated flag of the pair to true ๐ŸŽ€ but if the request fails (Section 7.2.5.2), the agent MUST remove the candidate pair from the valid list, set the candidate pair state to Failed, and set the checklist state to Failed ๐Ÿ’€

if the controlled agent gets a successful response to a Binding request it sent, and that Binding request was triggered by a received Binding request with the USE-CANDIDATE attribute set (Section 7.3.1.4), the agent sets the nominated flag of the pair to true ๐Ÿฆ‹ and if the triggered request fails, the agent MUST remove the candidate pair from the valid list, set the candidate pair state to Failed, and set the checklist state to Failed ๐Ÿ˜ญ

once the nominated flag is set for a component of a data stream, it wraps up ICE processing for that component (Section 8) ๐Ÿ‘‘

7.2.5.4. Checklist State Updates ๐Ÿงฉ

bestie, this one is so important ๐Ÿซถ whether a connectivity check worked or flopped, finishing it might mean updating the checklist states. for each checklist in the checklist set, if all of the candidate pairs are in either Failed or Succeeded state, and there is not a valid pair in the valid list for each component of the data stream associated with the checklist, the state of the checklist is set to Failed ๐Ÿ’… but if there is a valid pair for each component in the valid list, the state of the checklist is set to Succeeded โœจ

7.3. STUN Server Procedures ๐Ÿ›Ž๏ธ

okay the vibe here is that an ICE agent (lite or full) MUST be prepared to receive Binding requests on the base of each candidate it included in its most recent candidate exchange ๐ŸŒธ

the agent MUST use the short-term credential mechanism (i.e., the MESSAGE-INTEGRITY attribute) to authenticate the request and perform a message integrity check ๐Ÿ” likewise, the short-term credential mechanism MUST be used for the response ๐Ÿ’œ the agent MUST consider the username to be valid if it consists of two values separated by a colon, where the first value is equal to the username fragment generated by the agent in a candidate exchange for a session in progress ๐Ÿ“

it is possible (and in fact very likely) that the initiating agent will receive a Binding request prior to receiving the candidates from its peer ๐Ÿ™ˆ if this happens, the agent MUST immediately generate a response (including computation of the mapped address as described in Section 7.3.1.2) ๐Ÿงš the agent has sufficient information at this point to generate the response, and the password from the peer is not required ๐ŸŒˆ once the answer is received, it MUST proceed with the remaining steps required; namely, see Sections 7.3.1.3, 7.3.1.4, and 7.3.1.5 for full implementations ๐Ÿ”ฅ in cases where multiple STUN requests are received before the answer, this may cause several pairs to be queued up in the triggered-check queue ๐ŸŽ€

an agent MUST NOT utilize the ALTERNATE-SERVER mechanism and MUST NOT support the backwards-compatibility mechanisms defined in RFC 5389 (for working with the protocol in RFC 3489) ๐Ÿ™…โ€โ™€๏ธ it MUST utilize the FINGERPRINT mechanism ๐Ÿ’–

if the agent is using DSCP markings [RFC2475] in its data packets, it SHOULD apply the same markings to Binding responses ๐ŸŒท the same would apply to any Layer 2 markings the endpoint might be applying to data packets ๐Ÿซง

7.3.1. Additional Procedures for Full Implementations ๐Ÿง

this subsection defines the additional server procedures that apply to full implementations, when the full implementation accepts the Binding request ๐Ÿฐ

7.3.1.1. Detecting and Repairing Role Conflicts โš”๏ธ

in certain usages of ICE (such as 3PCC), both ICE agents might end up choosing the same role, which is a role conflict ๐Ÿ˜ฌ this section describes a mechanism for detecting and repairing role conflicts ๐Ÿ› ๏ธ the usage document MUST specify whether this mechanism is needed ๐Ÿ“„

an agent MUST examine the Binding request for either the ICE-CONTROLLING or ICE-CONTROLLED attribute ๐Ÿ” it MUST follow these procedures:

  • If the agent is in the controlling role, and the ICE-CONTROLLING attribute is present in the request:
    • If the agent's tiebreaker value is larger than or equal to the contents of the ICE-CONTROLLING attribute, the agent generates a Binding error response and includes an ERROR-CODE attribute with a value of 487 (Role Conflict) but retains its role ๐Ÿ™…โ€โ™€๏ธ
    • If the agent's tiebreaker value is less than the contents of the ICE-CONTROLLING attribute, the agent switches to the controlled role ๐Ÿ”„
  • If the agent is in the controlled role, and the ICE-CONTROLLED attribute is present in the request:
    • If the agent's tiebreaker value is larger than or equal to the contents of the ICE-CONTROLLED attribute, the agent switches to the controlling role ๐Ÿ‘‘
    • If the agent's tiebreaker value is less than the contents of the ICE-CONTROLLED attribute, the agent generates a Binding error response and includes an ERROR-CODE attribute with a value of 487 (Role Conflict) but retains its role ๐Ÿ™…โ€โ™€๏ธ
  • If the agent is in the controlled role and the ICE-CONTROLLING attribute was present in the request, or if the agent was in the controlling role and the ICE-CONTROLLED attribute was present in the request, there is no conflict โœจ

a change in roles will require an agent to recompute pair priorities (Section 6.1.2.3), since those priorities are a function of role ๐Ÿงฎ the change in role will also impact whether the agent is responsible for selecting nominated pairs and initiating exchange with updated candidate information upon conclusion of ICE ๐ŸŽฏ

the remaining subsections in Section 7.3.1 are followed if the agent generated a successful response to the Binding request, even if the agent changed roles ๐Ÿฅฐ

7.3.1.2. Computing Mapped Addresses ๐Ÿ—บ๏ธ

for requests received on a relayed candidate, the source transport address used for STUN processing (namely, generation of the XOR-MAPPED-ADDRESS attribute) is the transport address as seen by the TURN server ๐Ÿ›ฐ๏ธ that source transport address will be present in the XOR-PEER-ADDRESS attribute of a Data Indication message, if the Binding request was delivered through a Data Indication ๐Ÿ“ฌ if the Binding request was delivered through a ChannelData message, the source transport address is the one that was bound to the channel ๐ŸŽ€

7.3.1.3. Learning Peer-Reflexive Candidates ๐Ÿฆ‹

if the source transport address of the request does not match any existing remote candidates, it represents a new peer-reflexive remote candidate ๐Ÿ†• this candidate is constructed as follows:

  • The type is peer reflexive.
  • The priority is the value of the PRIORITY attribute in the Binding request.
  • The foundation is an arbitrary value, different from the foundations of all other remote candidates. If any subsequent candidate exchanges contain this peer-reflexive candidate, it will signal the actual foundation for the candidate ๐Ÿงพ
  • The component ID is the component ID of the local candidate to which the request was sent.

this candidate is added to the list of remote candidates ๐Ÿ“‹ however, the ICE agent does not pair this candidate with any local candidates ๐Ÿ™…โ€โ™€๏ธ

7.3.1.4. Triggered Checks ๐Ÿš€

next, the agent constructs a pair whose local candidate has the transport address (as seen by the agent) on which the STUN request was received, and a remote candidate equal to the source transport address where the request came from (which may be the peer-reflexive remote candidate that was just learned) ๐Ÿ’ซ the local candidate will be either a host candidate (for cases where the request was not received through a relay) or a relayed candidate (for cases where it is received through a relay) ๐Ÿ  the local candidate can never be a server-reflexive candidate ๐Ÿšซ since both candidates are known to the agent, it can obtain their priorities and compute the candidate pair priority ๐Ÿง  this pair is then looked up in the checklist ๐Ÿ”Ž there can be one of several outcomes:

  • When the pair is already on the checklist:
    • If the state of that pair is Succeeded, nothing further is done. โœ…
    • If the state of that pair is In-Progress, the agent cancels the In-Progress transaction. Cancellation means that the agent will not retransmit the Binding requests associated with the connectivity-check transaction, will not treat the lack of response to be a failure, but will wait the duration of the transaction timeout for a response. In addition, the agent MUST enqueue the pair in the triggered checklist associated with the checklist, and set the state of the pair to Waiting, in order to trigger a new connectivity check of the pair. Creating a new connectivity check enables validating In-Progress pairs as soon as possible, without having to wait for retransmissions of the Binding requests associated with the original connectivity-check transaction โฉ
    • If the state of that pair is Waiting, Frozen, or Failed, the agent MUST enqueue the pair in the triggered checklist associated with the checklist (if not already present), and set the state of the pair to Waiting, in order to trigger a new connectivity check of the pair. Note that a state change of the pair from Failed to Waiting might also trigger a state change of the associated checklist ๐Ÿ”
  • If the pair is not already on the checklist:
    • The pair is inserted into the checklist based on its priority. ๐Ÿ“ฅ
    • Its state is set to Waiting.
    • The pair is enqueued into the triggered-check queue. ๐ŸŽŸ๏ธ

these steps are done to facilitate rapid completion of ICE when both agents are behind NAT ๐Ÿƒโ€โ™€๏ธ๐Ÿ’จ

when a triggered check is to be sent, it is constructed and processed as described in Section 7.2.4 ๐Ÿ› ๏ธ these procedures require the agent to know the transport address, username fragment, and password for the peer ๐Ÿ”‘ the username fragment for the remote candidate is equal to the part after the colon of the USERNAME in the Binding request that was just received ๐Ÿ‘€ using that username fragment, the agent can check the candidates received from its peer (there may be more than one in cases of forking) and find this username fragment ๐Ÿ•ต๏ธโ€โ™€๏ธ the corresponding password is then picked ๐Ÿ”

7.3.1.5. Updating the Nominated Flag ๐Ÿ’…

okay so if the controlled agent gets a Binding request with USE-CANDIDATE set, and the ICE agent accepts that request, what happens next depends on the state of the pair we figured out back in Section 7.3.1.4 ๐Ÿซถ

  • If the state of this pair is Succeeded, it means the check this pair sent earlier got a successful response and made a valid pair (Section 7.2.5.3.2). The agent sets the nominated flag value of the valid pair to true โœจ
  • If the received Binding request triggered a new check to be enqueued in the triggered-check queue (Section 7.3.1.4), then once that check is sent, and it gets a successful response and makes a valid pair, the agent sets the nominated flag of the pair to true. If the request fails (Section 7.2.5.2), the agent MUST remove the candidate pair from the valid list, set the candidate pair state to Failed, and set the checklist state to Failed. ๐Ÿ’€

If the controlled agent does not accept the request from the controlling agent, the controlled agent MUST reject the nomination request with an appropriate error code response (e.g., 400) [RFC5389]. not the vibe ๐Ÿ™ˆ

Once the nominated flag is set for a component of a data stream, it concludes the ICE processing for that component. See Section 8 ๐ŸŽ€

7.3.2. Additional Procedures for Lite Implementations ๐Ÿงš

okay lite version, same energy but simpler ๐Ÿ“ If the controlled agent receives a Binding request with the USE-CANDIDATE attribute set, and the ICE agent accepts the request, the agent constructs a candidate pair. Its local candidate has the transport address the request was received on, and its remote candidate equals the source transport address of the request that came in. This candidate pair gets an arbitrary priority and goes into the valid list of the associated checklist. The agent sets the nominated flag for that pair to true ๐Ÿฆ‹

Once the nominated flag is set for a component of a data stream, it concludes the ICE processing for that component. See Section 8 โœจ

8. Concluding ICE Processing ๐Ÿ‘‘

this section is all about how an ICE agent wraps things up ๐ŸŒˆ

8.1. Procedures for Full Implementations ๐Ÿ’–

concluding ICE is basically two things: the controlling agent nominating pairs, and updating the state machinery ๐Ÿ”ฅ

8.1.1. Nominating Pairs ๐Ÿซง

so before nominating, the controlling agent just lets connectivity checks keep going until some stopping criterion is met. After that, based on an evaluation criterion, it picks one pair from the valid pairs in the valid list for nomination ๐Ÿ’…

Once the controlling agent has picked a valid pair, it repeats the connectivity check that produced that valid pair (by enqueueing the pair that generated the check into the triggered-check queue), this time with the USE-CANDIDATE attribute (Section 7.2.5.3.4). The procedures for the controlled agent are in Section 7.3.1.5 ๐ŸŽ€

Eventually, if the nominations succeed, both the controlling and controlled agents will have a single nominated pair in the valid list for each component of the data stream. Once an ICE agent sets the state of the checklist to Completed (when there is a nominated pair for each component of the data stream), that pair becomes the selected pair for that agent, and it's used for sending and receiving data for that component of the data stream โœจ

If an agent is not able to produce selected pairs for each component of a data stream, the agent MUST take proper actions for informing the other agent, e.g., by removing the stream. The exact actions are outside the scope of this specification ๐Ÿ™ˆ

The criteria for stopping the connectivity checks and for picking a pair for nomination are outside the scope of this specification. They're a matter of local optimization ๐Ÿง  The only requirement is that the agent MUST eventually pick one and only one candidate pair and generate a check for that pair with the USE-CANDIDATE attribute set ๐Ÿ’œ

Once the controlling agent has successfully nominated a candidate pair (Section 7.2.5.3.4), the agent MUST NOT nominate another pair for the same component of the data stream within the ICE session. Doing so requires an ICE restart ๐Ÿšซ

A controlling agent that doesn't support this specification (i.e., it's implemented according to RFC 5245) might nominate more than one candidate pair. This was referred to as "aggressive nomination" in RFC 5245 ๐Ÿ‘€ If more than one candidate pair is nominated by the controlling agent, and the controlled agent accepts multiple nomination requests, the agents MUST produce the selected pairs and use the pairs with the highest priority โญ

The usage of the 'ice2' ICE option (Section 10) by endpoints supporting this specification is supposed to prevent controlling agents that are implemented according to RFC 5245 from using aggressive nomination ๐ŸŒธ

NOTE: In RFC 5245, usage of "aggressive nomination" allowed agents to continuously nominate pairs, before a pair was eventually selected, in order to allow sending of data on those pairs. In this specification, data can always be sent on any valid pair, without nomination. Hence, there is no longer a need for aggressive nomination. ๐Ÿซถ

8.1.2. Updating Checklist and ICE States ๐Ÿ”ฅ

okay so for both a controlling and a controlled agent: when a candidate pair for a component of a data stream gets nominated, it might impact other pairs in the checklist for that data stream. It might also impact the state of the checklist ๐Ÿ‘‘

  • Once a candidate pair for a component of a data stream has been nominated, and the state of the checklist associated with the data stream is Running, the ICE agent MUST remove all candidate pairs for the same component from the checklist and from the triggered-check queue. If the state of a pair is In-Progress, the agent cancels the In-Progress transaction. Cancellation means the agent won't retransmit the Binding requests associated with the connectivity-check transaction, won't treat the lack of response as a failure, but will wait the duration of the transaction timeout for a response ๐Ÿ˜ญ
  • Once candidate pairs for each component of a data stream have been nominated, and the state of the checklist associated with the data stream is Running, the ICE agent sets the state of the checklist to Completed ๐ŸŽ€
  • Once a candidate pair for a component of a data stream has been nominated, an agent MUST continue to respond to any Binding request it might still receive for the nominated pair and for any remaining candidate pairs in the checklist associated with the data stream. As defined in Section 7.3.1.4, when the state of a pair is Succeeded, an agent will no longer generate triggered checks when receiving a Binding request for the pair ๐Ÿฆ‹

Once the state of each checklist in the checklist set is Completed, the agent sets the state of the ICE session to Completed ๐ŸŒˆ

If the state of a checklist is Failed, ICE has not been able to successfully complete the process for the data stream associated with the checklist. The correct behavior depends on the state of the checklists in the checklist set. If the controlling agent wants to continue the session without the data stream associated with the Failed checklist, and there are still one or more checklists in Running or Completed mode, the agent can let the ICE processing continue. The agent MUST take proper actions for removing the failed data stream. If the controlling agent does not want to continue the session and MUST terminate the session, the state of the ICE session is set to Failed ๐Ÿ’€

If the state of each checklist in the checklist set is Failed, the state of the ICE session is set to Failed. Unless the controlling agent wants to continue the session without the data streams, it MUST terminate the session ๐Ÿ˜ญ

8.2. Procedures for Lite Implementations ๐Ÿงš

when ICE concludes, a lite ICE agent can free host candidates that ICE didn't use, as described in Section 8.3 ๐Ÿ“

If the peer is a full agent, once the lite agent accepts a nomination request for a candidate pair, the lite agent considers that pair nominated. Once there are nominated pairs for each component of a data stream, those pairs become the selected pairs for the components of the data stream. Once the lite agent has produced selected pairs for all components of all data streams, the ICE session state is set to Completed โœจ

If the peer is a lite agent, the agent pairs local candidates with remote candidates that are of the same data stream and have the same component, transport protocol, and IP address family. For each component of each data stream, if there's only one candidate pair, that pair is added to the valid list. If there's more than one pair, it is RECOMMENDED that an agent follow the procedures of RFC 6724 [RFC6724] to select a pair and add it to the valid list ๐Ÿ’œ

If all of the components for all data streams had one pair, the state of ICE processing is Completed. Otherwise, the controlling agent MUST send an updated candidate list to reconcile different agents selecting different candidate pairs. ICE processing is complete after, and only after, the updated candidate exchange is complete ๐Ÿซถ

8.3. Freeing Candidates ๐Ÿงน

8.3.1. Full Implementation Procedures ๐ŸŒธ

these rules are about when it's safe for an agent to stop sending or receiving checks on a candidate that didn't become a selected candidate (i.e., it's not associated with a selected pair), and when to actually free the candidate ๐Ÿ’…

Once a checklist has reached the Completed state, the agent SHOULD wait an additional three seconds, and then it can cease responding to checks or generating triggered checks on all local candidates other than the ones that became selected candidates. Once all ICE sessions have ceased using a given local candidate (a candidate may be used by multiple ICE sessions, e.g., in forking scenarios), the agent can free that candidate. The three-second delay handles cases when aggressive nomination is used, and the selected pairs can quickly change after ICE has completed โณ

Freeing of server-reflexive candidates is never explicit; it happens by lack of a keepalive ๐Ÿ‚

8.3.2. Lite Implementation Procedures ๐ŸŒ™

a lite implementation can free candidates that didn't become selected candidates as soon as ICE processing has reached the Completed state for all ICE sessions using those candidates ๐Ÿฆ‹

9. ICE Restarts โœจ

okay so an ICE agent MAY restart ICE for existing data streams ๐Ÿ’… when it does, all the previous states of the data streams get flushed, except the roles of the agents ๐Ÿซถ the only real difference between a restart and a brand new data session is that during the restart, you can keep sending data over the existing data sessions, whereas a new data session always has to sort out the roles first ๐Ÿฆ‹

these things can ONLY be done with an ICE restart (the agent MUST use ICE restarts to do so, periodt) ๐Ÿ‘‘:

  • Change the destinations of data streams.
  • Change from a lite implementation to a full implementation.
  • Change from a full implementation to a lite implementation.

to restart ICE, an agent MUST change both the password and the username fragment for the data stream(s) being restarted ๐ŸŽ€

when ICE is restarted, the candidate set for the new ICE session might include some, none, or all of the candidates used in the current ICE session โœจ

as described in Section 6.1.1, agents MUST NOT redetermine the roles as part of an ICE restart, unless certain criteria that require the roles to be redetermined are fulfilled ๐Ÿ™ˆ


10. ICE Option ๐ŸŒˆ

this section defines a brand new ICE option, ice2 ๐Ÿงš when an ICE agent includes ice2 in a candidate exchange, the option is basically saying "hey, I'm compliant with this specification" ๐Ÿ’– for example, the agent will not use the aggressive nomination procedure defined in RFC 5245. and it also makes sure that a peer compliant with RFC 5245 doesn't use aggressive nomination either, as required by Section 14 of RFC 5245 for peers that receive unknown ICE options ๐Ÿ’…

an agent compliant to this specification MUST inform the peer about the compliance using the ice2 option ๐Ÿซถ

NOTE: The encoding of the ice2 option, and the message(s) used to carry it to the peer, are protocol specific. The encoding for SDP [RFC4566] is defined in [ICE-SIP-SDP].

11. Keepalives ๐Ÿ’œ

all endpoints MUST send keepalives for each data session ๐Ÿฆ‹ these keepalives are there to keep NAT bindings alive for the data session ๐ŸŒธ the keepalives SHOULD be sent using a format that is supported by its peer. ICE endpoints allow for STUN-based keepalives for UDP streams, so STUN keepalives MUST be used when an ICE agent is a full ICE implementation and is communicating with a peer that supports ICE (lite or full) ๐Ÿ”ฅ

an agent MUST send a keepalive on each candidate pair that is used for sending data if no packet has been sent on that pair in the last Tr seconds. Agents SHOULD use a Tr value of 15 seconds. Agents MAY use a bigger value but MUST NOT use a value smaller than 15 seconds โญ

once selected pairs have been produced for a data stream, keepalives are only sent on those pairs ๐Ÿ“

an agent MUST stop sending keepalives on a data stream if the data stream is removed. If the ICE session is terminated, an agent MUST stop sending keepalives on all data streams ๐Ÿ™ˆ

an agent MAY use another value for Tr, e.g., based on configuration or network/NAT characteristics โœจ for example, if an agent has a dynamic way to discover the binding lifetimes of the intervening NATs, it can use that value to determine Tr. Administrators deploying ICE in more controlled networking environments SHOULD set Tr to the longest duration possible in their environment ๐ŸŒˆ

when STUN is being used for keepalives, a STUN Binding Indication is used [RFC5389] ๐Ÿ’… the Indication MUST NOT utilize any authentication mechanism. It SHOULD contain the FINGERPRINT attribute to aid in demultiplexing, but it SHOULD NOT contain any other attributes. It is used solely to keep the NAT bindings alive ๐Ÿฆ‹ the Binding Indication is sent using the same local and remote candidates that are being used for data. Even though Binding Indications are used for keepalives, an agent MUST be prepared to receive a connectivity check as well ๐Ÿซถ if a connectivity check is received, a response is generated as discussed in [RFC5389], but there is no impact on ICE processing otherwise ๐Ÿ’€

agents MUST by default use STUN keepalives. Individual ICE usages and ICE extensions MAY specify usage-/extension-specific keepalives ๐Ÿ‘‘


12. Data Handling ๐ŸŽ€

12.1. Sending Data ๐Ÿฆ‹

an ICE agent MAY send data on any valid pair before selected pairs have been produced for the data stream ๐Ÿ’–

once selected pairs have been produced for a data stream, an agent MUST send data on those pairs only ๐Ÿ”ฅ

an agent sends data from the base of the local candidate to the remote candidate. In the case of a local relayed candidate, data is forwarded through the base (located in the TURN server), using the procedures defined in [RFC5766] โœจ

if the local candidate is a relayed candidate, it is RECOMMENDED that an agent creates a channel on the TURN server towards the remote candidate ๐ŸŒธ this is done using the procedures for channel creation as defined in Section 11 of [RFC5766].

the selected pair for a component of a data stream is:

  • empty if the state of the checklist for that data stream is Running, and there is no previous selected pair for that component due to an ICE restart
  • equal to the previous selected pair for a component of a data stream if the state of the checklist for that data stream is Running, and there was a previous selected pair for that component due to an ICE restart

unless an agent is able to produce a selected pair for each component associated with a data stream, the agent MUST NOT continue sending data for any component associated with that data stream ๐Ÿ™…โ€โ™€๏ธ

12.1.1. Procedures for Lite Implementations ๐Ÿงš

a lite implementation MUST NOT send data until it has a valid list that contains a candidate pair for each component of that data stream ๐Ÿ’… once that happens, the ICE agent MAY begin sending data packets. To do that, it sends data to the remote candidate in the pair (setting the destination address and port of the packet equal to that remote candidate), and it sends it from the base associated with the candidate pair used for sending data ๐Ÿซถ in the case of a relayed candidate, data is sent from the agent and forwarded through the base (located in the TURN server), using the procedures defined in [RFC5766].

12.2. Receiving Data ๐Ÿ’œ

even though ICE agents are only allowed to send data using valid candidate pairs (and, once selected pairs have been produced, only on the selected pairs), ICE implementations SHOULD by default be prepared to receive data on any of the candidates provided in the most recent candidate exchange with the peer ๐ŸŒˆ ICE usages MAY define rules that differ from this, e.g., by defining that data will not be sent until selected pairs have been produced for a data stream ๐Ÿฆ‹

when an agent receives an RTP packet with a new source or destination IP address for a particular RTP/RTCP data stream, it is RECOMMENDED that the agent readjust its jitter buffers ๐Ÿ“

Section 8.2 of RFC 3550 [RFC3550] describes an algorithm for detecting synchronization source (SSRC) collisions and loops. These algorithms are based, in part, on seeing different source transport addresses with the same SSRC. However, when ICE is used, such changes will sometimes occur as the data streams switch between candidates ๐Ÿ˜ญ an agent can tell that a data stream is from the same peer because of the STUN exchange that comes before the media data transmission. So, if there is a change in the source transport address, but the media data packets come from the same peer agent, this MUST NOT be treated as an SSRC collision ๐Ÿ™ˆ


13. Extensibility Considerations โœจ

this specification makes very specific choices about how both ICE agents in a session coordinate to arrive at the set of candidate pairs that get selected for data ๐Ÿ’… future specifications will probably want to change these algorithms, whether that's a simple timer tweak or a bigger revamp of the priority algorithm ๐Ÿ”ฅ when that happens, making sure the two agents in a session can still interoperate is critical ๐Ÿซถ

first up, ICE provides the ICE option concept ๐Ÿฆ‹ each extension or change to ICE is associated with an ICE option. When an agent supports such an extension or change, it provides the ICE option to the peer agent as part of the candidate exchange ๐Ÿ’–

one of the complications in achieving interoperability is that ICE relies on a distributed algorithm running on both agents to converge on an agreed set of candidate pairs ๐Ÿ˜ญ if the two agents run different algorithms, it can be really hard to guarantee convergence on the same candidate pairs. The nomination procedure described in Section 8 cuts down on some of the need for tight coordination by handing the selection algorithm completely to the controlling agent, and ICE will converge perfectly even when both agents use different pair prioritization algorithms ๐Ÿ‘‘ one of the keys to that convergence is triggered checks, which make sure the nominated pair gets validated by both agents ๐ŸŒธ

ICE is also extensible to other data streams beyond RTP, and to transport protocols beyond UDP ๐Ÿงš extensions to ICE for non-RTP data streams need to specify how many components they use, and assign component IDs to them, starting at 1 for the most important component ID ๐ŸŒˆ specifications for new transport protocols MUST define how, if at all, various steps in the ICE processing differ from UDP ๐Ÿ’…


14. Setting Ta and RTO ๐ŸŽ€

14.1. General ๐Ÿฆ‹

during the ICE gathering phase (Section 5.1.1) and while ICE is performing connectivity checks (Section 7), an ICE agent triggers STUN and TURN transactions โœจ these transactions are paced at a rate indicated by Ta, and the retransmission interval for each transaction is calculated based on the retransmission timer for the STUN transactions (RTO) [RFC5389].

this section describes how the Ta and RTO values are computed during the ICE gathering phase and while ICE is performing connectivity checks ๐Ÿ’–

NOTE: Previously, in RFC 5245, different formulas were defined for computing Ta and RTO, depending on whether or not ICE was used for a real-time data stream (e.g., RTP).

the formulas below result in a behavior where an agent will send its first packet for every single connectivity check before performing a retransmit ๐Ÿ˜ญ you can see this in the formulas for the RTO (which represents the retransmit interval). Those formulas scale with N, the number of checks to be performed. As a result, ICE keeps a nicely constant rate, but it becomes more sensitive to packet loss ๐Ÿ™ˆ losing that first packet for any connectivity check is likely to make that pair take a long time to get validated, and instead, a lower-priority check (but one with no packet loss) is much more likely to finish first. This means ICE ends up performing suboptimally, choosing lower-priority pairs over higher-priority pairs ๐Ÿ’€

14.2. Ta

okay so Ta is the pacing timer for ICE agents ๐Ÿ’… ICE agents SHOULD use a default Ta value of 50 ms ๐ŸŽ€ but they MAY use another value if it makes more sense for the data they're sending ๐Ÿฆ‹

if an agent wants a Ta value that isn't the default, it MUST tell its peer the value it wants during session setup ๐Ÿ’Œ and then both agents MUST use the higher of the proposed values ๐Ÿ‘‘ if an agent doesn't propose anything, the default is used for that agent when figuring out which one is higher โœจ

now here's the important bit ๐Ÿ˜ญ no matter what Ta each agent picked, all the transactions from all the agents together MUST NOT be sent more often than once every 5 ms. this is the case even if one implementation is running several agents at once, because it's paced like there's one global Ta value for all of them ๐Ÿซถ for the background on using 5 ms with ICE, go check Appendix B.1 ๐ŸŒธ

NOTE: Appendix C shows examples of required bandwidth, using different Ta values. ๐Ÿ’œ

14.3. RTO

so RTO is the retransmission timeout, and it's kind of the main character of the timing stuff ๐ŸŽ€ during the ICE gathering phase, ICE agents SHOULD work out the RTO value with this formula ๐Ÿงš

RTO = MAX (500ms, Ta * (Num-Of-Cands))

Num-Of-Cands: the number of server-reflexive and relay candidates

for connectivity checks, agents SHOULD use this one instead ๐Ÿ”ฅ

RTO = MAX (500ms, Ta * N * (Num-Waiting + Num-In-Progress))

N: the total number of connectivity checks to be performed.

Num-Waiting: the number of checks in the checklist set in the
Waiting state.

Num-In-Progress: the number of checks in the checklist set in the
In-Progress state.

and the RTO is different for every transaction ๐Ÿฆ‹ because the number of checks in the Waiting and In-Progress states keeps changing, so it's literally always shifting, iykyk ๐Ÿ™ˆ

agents MAY calculate the RTO with other mechanisms than the ones above ๐ŸŒˆ but the one hard rule is that agents MUST NOT use an RTO smaller than 500 ms. no exceptions, bestie ๐Ÿ“


15. Examples โœจ

this section shows two ICE examples ๐Ÿงš one uses IPv4 addresses and one uses IPv6 addresses. ๐Ÿ’–

so the transport addresses get mnemonic variable names to make them easier to follow ๐ŸŽ€ the format is entity-type-seqno. "entity" is whose IP address it is and it's one of "L", "R", "STUN", or "NAT". the type is "PUB" for public transport addresses or "PRIV" for private ones [RFC1918]. the seq-no is a sequence number that's different for each transport address of the same type on a particular entity ๐ŸŒธ each variable has an IP address and port, written as varname.IP and varname.PORT, where varname is the variable's name ๐Ÿซถ

in the call flow, STUN messages get some annotations too ๐Ÿ’… "S=" is the source transport address of the message. "D=" is the destination transport address. "MA=" shows up in STUN Binding response messages and refers to the mapped address. and "USE-CAND" just means the USE-CANDIDATE attribute is there ๐Ÿ”ฅ

the call flow examples skip the STUN authentication stuff and focus on one data stream between two full implementations ๐Ÿ’œ

15.1. Example with IPv4 Addresses

this example uses the topology in Figure 7 ๐Ÿฆ‹

                              +-------+
                              |STUN   |
                              |Server |
                              +-------+
                                  |
                       +---------------------+
                       |                     |
                       |      Internet       |
                       |                     |
                       +---------------------+
                         |                |
                         |                |
                  +---------+             |
                  |   NAT   |             |
                  +---------+             |
                       |                  |
                       |                  |
                    +-----+            +-----+
                    |  L  |            |  R  |
                    +-----+            +-----+

                    Figure 7: Example Topology

in the example, ICE agents L and R are both full ICE implementations ๐ŸŽ€ each one has a single IPv4 address, and they're both set up with the same STUN server โœจ the NAT has an endpoint-independent mapping property and an address-dependent filtering property ๐ŸŒˆ here are the IP addresses for the agents, the STUN server, and the NAT:

ENTITY                   IP Address  Mnemonic name
--------------------------------------------------
ICE Agent L:             10.0.1.1    L-PRIV-1
ICE Agent R:             192.0.2.1   R-PUB-1
STUN Server:             192.0.2.2   STUN-PUB-1
NAT (Public):            192.0.2.3   NAT-PUB-1

and here's the whole call flow ๐Ÿ“ it's a lot, but it's giving very detailed bestie energy:

         L             NAT           STUN             R
         |STUN alloc.   |              |              |
         |(1) STUN Req  |              |              |
         |S=$L-PRIV-1   |              |              |
         |D=$STUN-PUB-1 |              |              |
         |------------->|              |              |
         |              |(2) STUN Req  |              |
         |              |S=$NAT-PUB-1  |              |
         |              |D=$STUN-PUB-1 |              |
         |              |------------->|              |
         |              |(3) STUN Res  |              |
         |              |S=$STUN-PUB-1 |              |
         |              |D=$NAT-PUB-1  |              |
         |              |MA=$NAT-PUB-1 |              |
         |              |<-------------|              |
         |(4) STUN Res  |              |              |
         |S=$STUN-PUB-1 |              |              |
         |D=$L-PRIV-1   |              |              |
         |MA=$NAT-PUB-1 |              |              |
         |<-------------|              |              |
         |(5) L's Candidate Information|              |
         |------------------------------------------->|
         |              |              |              | STUN
         |              |              |              | alloc.
         |              |              |(6) STUN Req  |
         |              |              |S=$R-PUB-1    |
         |              |              |D=$STUN-PUB-1 |
         |              |              |<-------------|
         |              |              |(7) STUN Res  |
         |              |              |S=$STUN-PUB-1 |
         |              |              |D=$R-PUB-1    |
         |              |              |MA=$R-PUB-1   |
         |              |              |------------->|
         |(8) R's Candidate Information|              |
         |<-------------------------------------------|
         |              |         (9) Bind Req        |Begin
         |              |         S=$R-PUB-1          |Connectivity
         |              |         D=$L-PRIV-1         |Checks
         |              |         <-------------------|
         |              |         Dropped             |
         |(10) Bind Req |              |              |
         |S=$L-PRIV-1   |              |              |
         |D=$R-PUB-1    |              |              |
         |------------->|              |              |
         |              |(11) Bind Req |              |
         |              |S=$NAT-PUB-1  |              |
         |              |D=$R-PUB-1    |              |
         |              |---------------------------->|
         |              |(12) Bind Res |              |
         |              |S=$R-PUB-1    |              |
         |              |D=$NAT-PUB-1  |              |
         |              |MA=$NAT-PUB-1 |              |
         |              |<----------------------------|
         |(13) Bind Res |              |              |
         |S=$R-PUB-1    |              |              |
         |D=$L-PRIV-1   |              |              |
         |MA=$NAT-PUB-1 |              |              |
         |<-------------|              |              |
         |Data          |              |              |
         |===========================================>|
         |              |              |              |
         |              |(14) Bind Req |              |
         |              |S=$R-PUB-1    |              |
         |              |D=$NAT-PUB-1  |              |
         |              |<----------------------------|
         |(15) Bind Req |              |              |
         |S=$R-PUB-1    |              |              |
         |D=$L-PRIV-1   |              |              |
         |<-------------|              |              |
         |(16) Bind Res |              |              |
         |S=$L-PRIV-1   |              |              |
         |D=$R-PUB-1    |              |              |
         |MA=$R-PUB-1   |              |              |
         |------------->|              |              |
         |              |(17) Bind Res |              |
         |              |S=$NAT-PUB-1  |              |
         |              |D=$R-PUB-1    |              |
         |              |MA=$R-PUB-1   |              |
         |              |---------------------------->|
         |Data          |              |              |
         |<===========================================|
         |              |              |              |
                            .......
         |              |              |              |
         |(18) Bind Req |              |              |
         |S=$L-PRIV-1   |              |              |
         |D=$R-PUB-1    |              |              |
         |USE-CAND      |              |              |
         |------------->|              |              |
         |              |(19) Bind Req |              |
         |              |S=$NAT-PUB-1  |              |
         |              |D=$R-PUB-1    |              |
         |              |USE-CAND      |              |
         |              |---------------------------->|
         |              |(20) Bind Res |              |
         |              |S=$R-PUB-1    |              |
         |              |D=$NAT-PUB-1  |              |
         |              |MA=$NAT-PUB-1 |              |
         |              |<----------------------------|
         |(21) Bind Res |              |              |
         |S=$R-PUB-1    |              |              |
         |D=$L-PRIV-1   |              |              |
         |MA=$NAT-PUB-1 |              |              |
         |<-------------|              |              |
         |              |              |              |

                      Figure 8: Example Flow

okay the first few messages ๐ŸŒธ Messages 1-4: agent L grabs a host candidate from its local IP address, and then sends a STUN Binding request to the STUN server โœจ that request creates a NAT binding, and the NAT's public IP address for that binding becomes L's server-reflexive candidate ๐Ÿซถ

Message 5: agent L sends its local candidate information over to agent R, using whatever signaling protocol goes with the ICE usage ๐Ÿ’–

Okay so bestie, agent R isn't behind a NAT, which means its server-reflexive candidate is literally the same thing as its host candidate ๐Ÿ™ˆ So in Messages 6-7, R grabs a host candidate from its local IP address and then fires a STUN Binding request off to the STUN server โœจ

Message 8 is the handoff: R sends its local candidate info over to agent L using whatever signaling protocol goes with the ICE usage ๐Ÿ’Œ

Since both agents are full ICE implementations, the one who started the whole thing (agent L) becomes the controlling agent ๐Ÿ‘‘

Now for pairing! Both agents start with two pairs each ๐Ÿ’– But agent L prunes the pair that contains its server-reflexive candidate, so only one pair is left, L1. Agent R keeps two pairs. Its highest-priority one is R1, and the second one is R2. Here's the tea, shown in a table (pair numbers are just for reference, no cap) ๐ŸŽ€

                         Pairs
ENTITY                   Local         Remote     Pair #     Valid
------------------------------------------------------------------
ICE Agent L:             L_PRIV_1      R_PUB_1       L1

ICE Agent R:             R_PUB_1       L_PRIV_1      R1
                         R_PUB_1       NAT_PUB_1     R2

Message 9 is kind of a flop ๐Ÿ˜ญ R starts a connectivity check for pair #2, but the remote candidate there is agent L's private address. The request can't be routed from R to L, so the network just drops it. Literally dead on arrival ๐Ÿ’€

Messages 10-13 are where L slays โญ Agent L starts a connectivity check for pair L1, and it succeeds! L then creates a brand new pair, L2, with $NAT_PUB_1 as the local candidate and $R_PUB_1 as the remote one. L2 gets added to agent L's valid list, so agent L can now send and receive data on it if it wants to ๐Ÿฆ‹

                         Pairs
ENTITY                   Local         Remote     Pair #     Valid
------------------------------------------------------------------
ICE Agent L:             L_PRIV_1      R_PUB_1       L1
                         NAT_PUB_1     R_PUB_1       L2        X

ICE Agent R:             R_PUB_1       L_PRIV_1      R1
                         R_PUB_1       NAT_PUB_1     R2

Messages 14-17 are the glow-up for agent R ๐ŸŒธ When R gets the Binding request from agent L (message 11), it kicks off a triggered connectivity check. That pair matches one of R's existing pairs, R2. The check succeeds, so R2 joins agent R's valid list, and R can now send and receive data on it too ๐Ÿงš

                         Pairs
ENTITY                   Local         Remote     Pair #     Valid
------------------------------------------------------------------
ICE Agent L:             L_PRIV_1      R_PUB_1       L1
                         NAT_PUB_1     R_PUB_1       L2        X

ICE Agent R:             R_PUB_1       L_PRIV_1      R1
                         R_PUB_1       NAT_PUB_1     R2        X

Messages 18-21 are the finale ๐Ÿ”ฅ At some point, the controlling agent (agent L) decides to nominate a pair from its valid list, and it picks L2. It runs a connectivity check on L2 and includes the USE-CANDIDATE attribute in the Binding request. The check succeeds, so agent L sets the nominated flag of L2 to 'true', and agent R sets the nominated flag of its matching pair, R2, to 'true' too ๐Ÿ’œ

Since there are no more components for this stream, the nominated pairs become the selected pairs. That means processing for this stream moves into the Completed state, and the whole ICE process moves into the Completed state with it. Main character energy, periodt ๐Ÿ‘‘๐ŸŽ€

15.2. Example with IPv6 Addresses

okay so this one is the IPv6 version of the last example ๐Ÿ’– same vibe, same cast, just with IPv6 addresses ๐Ÿฆ‹ here's the topology:

                            +-------+
                            |STUN   |
                            |Server |
                            +-------+
                                |
                     +---------------------+
                     |                     |
                     |      Internet       |
                     |                     |
                     +---------------------+
                        |                |
                        |                |
                        |                |
                        |                |
                        |                |
                        |                |
                        |                |
                     +-----+          +-----+
                     |  L  |          |  R  |
                     +-----+          +-----+

Figure 9: Example Topology

In this example, ICE agents L and R are full ICE implementations ๐Ÿ’… Both agents have a single IPv6 address, and they're both configured with the same STUN server. Here are the IP addresses for the ICE agents and the STUN server:

ENTITY                   IP Address  mnemonic name
--------------------------------------------------
ICE Agent L:             2001:db8::3   L-PUB-1
ICE Agent R:             2001:db8::5   R-PUB-1
STUN Server:             2001:db8::9   STUN-PUB-1

and here's the whole message flow, bestie ๐Ÿซถ

          L                           STUN             R
          |STUN alloc.                  |              |
          |(1) STUN Req                 |              |
          |S=$L-PUB-1                   |              |
          |D=$STUN-PUB-1                |              |
          |---------------------------->|              |
          |(2) STUN Res                 |              |
          | S=$STUN-PUB-1               |              |
          | D=$L-PUB-1                  |              |
          | MA=$L-PUB-1                 |              |
          |<----------------------------|              |
          |(3) L's Candidate Information|              |
          |------------------------------------------->|
          |                             |              | STUN
          |                             |              | alloc.
          |                             |(4) STUN Req  |
          |                             |S=$R-PUB-1    |
          |                             |D=$STUN-PUB-1 |
          |                             |<-------------|
          |                             |(5) STUN Res  |
          |                             |S=$STUN-PUB-1 |
          |                             |D=$R-PUB-1    |
          |                             |MA=$R-PUB-1   |
          |                             |------------->|
          |(6) R's Candidate Information|              |
          |<-------------------------------------------|
          |(7) Bind Req                 |              |
          |S=$L-PUB-1                   |              |
          |D=$R-PUB-1                   |              |
          |------------------------------------------->|
          |(8) Bind Res                 |              |
          |S=$R-PUB-1                   |              |
          |D=$L-PUB-1                   |              |
          |MA=$L-PUB-1                  |              |
          |<-------------------------------------------|
          |Data                         |              |
          |===========================================>|
          |                             |              |
          |(9) Bind Req                 |              |
          |S=$R-PUB-1                   |              |
          |D=$L-PUB-1                   |              |
          |<-------------------------------------------|
          |(10) Bind Res                |              |
          |S=$L-PUB-1                   |              |
          |D=$R-PUB-1                   |              |
          |MA=$R-PUB-1                  |              |
          |------------------------------------------->|
          |Data                         |              |
          |<===========================================|
          |                             |              |
                             .......
          |                             |              |
          |(11) Bind Req                |              |
          |S=$L-PUB-1                   |              |
          |D=$R-PUB-1                   |              |
          |USE-CAND                     |              |
          |------------------------------------------->|
          |(12) Bind Res                |              |
          |S=$R-PUB-1                   |              |
          |D=$L-PUB-1                   |              |
          |MA=$L-PUB-1                  |              |
          |<-------------------------------------------|
          |              |              |              |

Figure 10: Example Flow

Messages 1-2: Agent L grabs a host candidate from its local IP address, then sends a STUN Binding request to the STUN server ๐Ÿงš Since agent L isn't behind a NAT, L's server-reflexive candidate ends up being identical to the host candidate.

Message 3: Agent L sends its local candidate information to agent R, using whatever signaling protocol goes with the ICE usage ๐Ÿ“จ

Messages 4-5: Agent R grabs a host candidate from its local IP address, then sends a STUN Binding request to the STUN server ๐ŸŒธ Since agent R isn't behind a NAT either, R's server-reflexive candidate is identical to the host candidate.

Message 6: Agent R sends its local candidate information back to agent L, using the signaling protocol tied to the ICE usage ๐ŸŽ€

Since both agents are full ICE implementations, the initiating agent (agent L) becomes the controlling agent ๐Ÿ‘‘

Agents L and R both pair up the candidates, and each starts out with one pair. At agent L, the pair (L1) has a local candidate of $L_PUB_1 and a remote candidate of $R_PUB_1. At agent R, the pair (R1) has a local candidate of $R_PUB_1 and a remote candidate of $L_PUB_1. Here are the pairs (the pair numbers are just for reference ๐Ÿ“):

                         Pairs
ENTITY                   Local         Remote     Pair #     Valid
------------------------------------------------------------------
ICE Agent L:             L_PUB_1       R_PUB_1       L1

ICE Agent R:             R_PUB_1       L_PUB_1       R1

Messages 7-8: Agent L kicks off a connectivity check for pair L1. The check succeeds, so pair (L1) gets added to agent L's valid list. Agent L can now send and receive data on pair (L1) if it wants to โœจ

                         Pairs
ENTITY                   Local         Remote     Pair #     Valid
------------------------------------------------------------------
ICE Agent L:             L_PUB_1       R_PUB_1       L1         X

ICE Agent R:             R_PUB_1       L_PUB_1       R1

Messages 9-10: When agent R gets the Binding request from agent L (message 7), it starts a triggered connectivity check ๐Ÿ”ฅ The pair matches agent R's existing pair (R1). The check succeeds, so pair (R1) gets added to agent R's valid list. Agent R can now send and receive data on pair (R1) if it wants to ๐Ÿ’œ

                         Pairs
ENTITY                   Local         Remote     Pair #     Valid
------------------------------------------------------------------
ICE Agent L:             L_PUB_1       R_PUB_1       L1         X

ICE Agent R:             R_PUB_1       L_PUB_1       R1         X

Messages 11-12: At some point, the controlling agent (agent L) decides to nominate pair (L1) from the valid list. It does a connectivity check on pair (L1) and includes the USE-CANDIDATE attribute in the Binding request ๐Ÿฆ‹ When the check succeeds, agent L sets the nominated flag value of pair (L1) to 'true', and agent R sets the nominated flag value of the matching pair (R1) to 'true' ๐Ÿฅฐ

Since there are no more components associated with the stream, the nominated pairs become the selected pairs. That means processing for this stream moves into the Completed state, and the ICE process moves into the Completed state too ๐ŸŽ‰


16. STUN Extensions ๐ŸŒˆ

16.1. Attributes

okay so this section is where the STUN protocol gets some new ICE-specific bling ๐Ÿ’… this spec defines four STUN attributes: PRIORITY, USE-CANDIDATE, ICE-CONTROLLED, and ICE-CONTROLLING.

The PRIORITY attribute tells you what priority should be attached to a peer-reflexive candidate, if this check ends up discovering one ๐Ÿงš It's a 32-bit unsigned integer with an attribute value of 0x0024.

The USE-CANDIDATE attribute says the candidate pair from this check is going to be used for sending data ๐Ÿ’– It has no content (the Length field of the attribute is zero), so it's basically just a flag ๐Ÿšฉ Its attribute value is 0x0025.

The ICE-CONTROLLED attribute shows up in a Binding request ๐ŸŒธ It tells the server that the client believes it's currently in the controlled role. Its content is a 64-bit unsigned integer in network byte order, holding a random number. That number is used to solve role conflicts, and when it does, it's called the "tiebreaker value" ๐ŸŽ€ An ICE agent MUST use the same number for all Binding requests, for all streams, within an ICE session, unless it has received a 487 response. In that case, it MUST change the number (Section 7.2.5.1). The agent MAY change the number when an ICE restart occurs.

The ICE-CONTROLLING attribute also shows up in a Binding request ๐Ÿ‘‘ It tells the server that the client believes it's currently in the controlling role. Like ICE-CONTROLLED, its content is a 64-bit unsigned integer in network byte order holding a random number, and that number is used for solving role conflicts. An agent MUST use the same number for all Binding requests, for all streams, within an ICE session, unless it has received a 487 response. In that case, it MUST change the number (Section 7.2.5.1). The agent MAY change the number when an ICE restart occurs ๐Ÿซถ

16.2. New Error-Response Codes

This spec defines just one new error-response code ๐Ÿ™ˆ

  • 487 (Role Conflict): The Binding request had either the ICE-CONTROLLING or ICE-CONTROLLED attribute, which means it claimed an ICE role that clashed with the server. The remote server compared the tiebreaker values from the client and the server, and figured out that the client needs to switch roles. Major role-swap energy ๐Ÿ’€

17. Operational Considerations โญ

This section covers the stuff operators should know about when they're running networks where endpoints use ICE ๐ŸŒธ

17.1. NAT and Firewall Types

okay so ICE was literally built to play nice with the NAT and firewall gear that already exists ๐Ÿ’… which means you do NOT have to replace or reconfigure any of it to deploy ICE. fr. ICE was designed for places where the Voice over IP (VoIP) operator has zero control over the IP network stuff, firewalls and NATs included ๐Ÿงš

that said, ICE slays hardest when the NAT devices are "behave" compliant ๐Ÿฆ‹, meaning they meet the recommendations in [RFC4787] and [RFC5382]. in behave-compliant networks ICE works without needing a TURN server ๐Ÿ˜ญ which means better voice quality, faster call setup, and less bandwidth load for the network operator. iconic, honestly ๐Ÿ‘‘

17.2. Bandwidth Requirements

deploying ICE can touch network capacity in a few ways, and operators need to keep that in mind ๐Ÿ“Š

17.2.1. STUN and TURN Server-Capacity Planning

first things first, ICE uses TURN and STUN servers, which are usually chilling in data centers ๐Ÿข. STUN servers need relatively little bandwidth. for each component of each data stream, there will be one or more STUN transactions from each client to the STUN server. in a basic voice-only IPv4 VoIP deployment there are four transactions per call (one for RTP and one for RTCP, for both the caller and callee). each transaction is a single request and a single response. the request is 20 bytes long and the response is 28.

so if a system has N users and each one makes four calls in a busy hour, that's N*1.7bps. for one million users that's 1.7 Mbps, which is tiny (relatively speaking) ๐ŸŒธ

TURN traffic is way more substantial ๐Ÿ‘€ the TURN server sees traffic volume equal to the STUN volume (and if you deploy TURN servers, you don't need a separate STUN server at all), PLUS the traffic for the actual data. how many calls need TURN for data relay depends heavily on network topology, and it can and will change over time. in a network with 100% behave-compliant NATs, it's exactly zero ๐ŸŽ‰

the planning considerations above get more significant in multimedia scenarios (e.g., audio and video conferences) and as the number of participants in a session grows ๐Ÿ“ˆ

17.2.2. Gathering and Connectivity Checks

gathering candidates and running connectivity checks can be bandwidth hungry ๐Ÿฝ๏ธ. ICE paces both of these processes. the gathering and connectivity-check phases are meant to generate traffic at roughly the same bandwidth the data traffic itself will eat once ICE wraps up. this was done so that if a network is designed to support a certain type of communication traffic (voice, video, or just text), it'll have enough capacity to support the ICE checks for that data too. once ICE has concluded, the subsequent ICE keepalives cause a marginal bump in total bandwidth utilization, but it's typically an extremely small increase ๐Ÿ’–

congestion from the gathering and check phases has been a real problem in deployments that didn't use pacing ๐Ÿ˜ญ typically, access links got congested because endpoints flooded the network with checks as fast as they could send them. so network operators need to make sure their ICE implementations support the pacing feature. yes, pacing makes call setup take longer, but it makes ICE network friendly and easier to deploy ๐Ÿซถ

17.2.3. Keepalives

STUN keepalives (in the form of STUN Binding Indications) get sent in the middle of a data session. but they're only sent in the absence of actual data traffic ๐Ÿคซ. in deployments with continuous media and no Voice Activity Detection (VAD), or deployments where VAD is used together with short interval (max 1 second) comfort noise, the keepalives are never used and there's no increase in bandwidth usage. when VAD is used without comfort noise, keepalives get sent during silence periods. that's a single packet every 15-20 seconds, which is WAY less than the packet every 20-30 ms sent when there's voice. so keepalives don't have any real impact on capacity planning ๐Ÿ’…

17.3. ICE and ICE-Lite

deployments mixing ICE and ICE-lite interoperate with each other ๐Ÿค. they were explicitly designed to do that, so no drama.

ICE-lite can only be deployed in limited use cases though ๐Ÿฅบ. those cases, and the caveats involved in deploying them, are documented in Appendix A.

17.4. Troubleshooting and Performance Management

ICE uses end-to-end connectivity checks and puts a lot of the processing in the endpoints. that's a challenge for the network operator: how do they troubleshoot ICE deployments? how can they know how ICE is performing? ๐Ÿค”

good news, ICE has built-in features for exactly this ๐Ÿ”. signaling servers, usually deployed in the network operator's data centers, see the contents of the candidate exchanges that carry the ICE parameters. these include the type of each candidate (host, server reflexive, or relayed) along with their related addresses. once ICE processing completes, an updated candidate exchange happens, signaling the selected address (and its type). this updated signaling is done exactly for the purpose of educating network equipment (like a diagnostic tool attached to signaling) about the results of ICE processing โœจ

so through the logs a signaling server generates, a network operator can observe what types of candidates each call is using and what addresses ICE selected. that's the primary info for evaluating how ICE is performing ๐Ÿ“ˆ

17.5. Endpoint Configuration

ICE relies on several pieces of data configured into the endpoints. that config data includes timers, credentials for TURN servers, and hostnames for STUN and TURN servers. ICE itself doesn't provide a mechanism for this configuration. instead, it's assumed this info is attached to whatever mechanism configures all the other parameters in the endpoint. for SIP phones, standard solutions such as the configuration framework [RFC6080] have been defined ๐ŸŽ€


18. IAB Considerations

the IAB studied "Unilateral Self-Address Fixing" (UNSAF), which is the general process by which an ICE agent tries to determine its address in another realm on the other side of a NAT through a collaborative protocol reflection mechanism [RFC3424]. ICE is an example of a protocol that does this. plot twist though: the process for ICE is bilateral, not unilateral, and that difference seriously changes the issues the IAB raised ๐ŸŽญ. ICE can be considered a Bilateral Self-Address Fixing (B-SAF) protocol rather than an UNSAF protocol. either way, the IAB has mandated that any protocols developed for this purpose document a specific set of considerations, and this section does exactly that ๐Ÿ“

18.1. Problem Definition

from RFC 3424, any UNSAF proposal needs to provide:

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 the prolonged dependence on and usage of the supposed short term fix -- meaning that it is no longer accurate to call it "short term".

the specific problems ICE solves are:

  • Providing a means for two peers to determine the set of transport addresses that can be used for communication.
  • Providing a means for an agent to determine an address that is reachable by another peer with which it wishes to communicate.

18.2. Exit Strategy

from RFC 3424, any UNSAF proposal needs to provide:

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.

ICE itself doesn't easily get phased out ๐Ÿ™ƒ. still, it's useful even in a globally connected Internet, for example as a way to detect whether a router failure has temporarily disrupted connectivity. ICE also helps prevent certain security attacks that have nothing to do with NAT. what ICE really does is help phase out other UNSAF mechanisms. it effectively picks amongst those mechanisms, prioritizing the better ones and deprioritizing the worse ones. as NATs begin to dissipate with IPv6 being introduced, server-reflexive and relayed candidates (both forms of UNSAF addresses) simply never get used, because higher-priority connectivity exists to the native host candidates. so the servers get used less and less and can eventually be removed once their usage goes to zero ๐ŸŒˆ

ICE can also help with the transition from IPv4 to IPv6 ๐Ÿฆ‹. it can be used to determine whether to use IPv6 or IPv4 when two dual-stack hosts communicate with SIP (IPv6 gets used). it can also let a network with both 6to4 and native v6 connectivity figure out which address to use when communicating with a peer.

18.3. Brittleness Introduced by ICE

from RFC 3424, any UNSAF proposal needs to provide:

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.

ICE actually removes brittleness from existing UNSAF mechanisms ๐Ÿ’ช. in particular, classic STUN (as described in RFC 3489 [RFC3489]) has several points of brittleness. one of them is the discovery process that requires an ICE agent to try to classify the type of NAT it's behind. that process is error prone, but with ICE it's simply not used. instead of unilaterally assessing whether the address is valid, its validity is dynamically determined by measuring connectivity to a peer. and that process of determining connectivity is very robust ๐Ÿซถ

another point of brittleness in classic STUN, and in any other unilateral mechanism, is its absolute reliance on an additional server. ICE makes use of a server for allocating unilateral addresses, but it allows agents to connect directly when possible. so in some cases, even if a STUN server fails, a call can still progress when ICE is used ๐Ÿ“ž

another brittleness point in classic STUN is that it assumes the STUN server is on the public Internet. with ICE, that isn't necessary. there can be a multitude of STUN servers in a variety of address realms, and ICE discovers the one that provides a usable address ๐ŸŒ

the most troubling brittleness point in classic STUN is that it doesn't work in all network topologies. where there's a shared NAT between each agent and the STUN server, traditional STUN may not work. with ICE, that restriction is removed ๐Ÿ™Œ

classic STUN also introduces some security considerations. luckily, ICE mitigates those too ๐Ÿ›ก๏ธ

so ICE repairs the brittleness introduced in classic STUN, and it doesn't introduce any additional brittleness into the system ๐Ÿ’œ

the penalty for these improvements is that ICE increases session establishment times โณ

18.4. Requirements for a Long-Term Solution ๐Ÿฆ‹

okay so, RFC 3424 says any UNSAF proposal needs to do two things: ๐Ÿ’…

  • Identify requirements for longer term, sound technical solutions;
  • contribute to the process of finding the right longer term solution.

Our conclusions from RFC 3489 remain unchanged. ๐ŸŒธ However, we feel ICE actually helps, bestie, because we believe it can be part of the long-term solution โœจ

18.5. Issues with Existing NAPT Boxes ๐Ÿงš

RFC 3424 says any UNSAF proposal needs to provide:

  • Discussion of the impact of the noted practical issues with existing, deployed NA[P]Ts and experience reports.

A bunch of NAT boxes are now being deployed that try to provide "generic" ALG functionality ๐Ÿ™ˆ These generic ALGs hunt for IP addresses, in either text or binary form within a packet, and rewrite them if they match a binding. This interferes with classic STUN, no cap ๐Ÿ’€ However, the update to STUN [RFC5389] uses an encoding that hides these binary addresses from generic ALGs, so it's giving protection ๐Ÿซถ

Existing NAPT boxes have non-deterministic and typically short expiration times for UDP-based bindings ๐Ÿ˜ญ This requires implementations to send periodic keepalives to maintain those bindings. ICE uses a default of 15 s, which is a very conservative estimate ๐Ÿ“ Eventually, over time, as NAT boxes become compliant to behave [RFC4787], this minimum keepalive will become deterministic and well known, and the ICE timers can be adjusted ๐ŸŽ€ Having a way to discover and control the minimum keepalive interval would be far better still ๐Ÿ‘‘

  1. Security Considerations ๐Ÿ”ฅ

19.1. IP Address Privacy ๐Ÿ”’

Okay bestie, this part is serious, so listen up ๐Ÿ’– The process of probing for candidates reveals the source addresses of the client and its peer to any on-network listening attacker, and the process of exchanging candidates reveals the addresses to any attacker that is able to see the negotiation. Some addresses, such as the server-reflexive addresses gathered through the local interface of VPN users, may be sensitive information ๐Ÿ™ˆ If these potential attacks cannot be mitigated, ICE usages can define mechanisms for controlling which addresses are revealed to the negotiation and/or probing process. Individual implementations may also have implementation-specific rules for controlling which addresses are revealed. For example, [WebRTC-IP-HANDLING] provides additional information about the privacy aspects of revealing IP addresses via ICE for WebRTC applications. ICE implementations where such issues can arise are RECOMMENDED to provide a programmatic or user interface that provides control over which network interfaces are used to generate candidates โœจ

Based on the types of candidates provided by the peer, and the results of the connectivity tests performed against those candidates, the peer might be able to determine characteristics of the local network, e.g., if different timings are apparent to the peer. Within the limit, the peer might be able to probe the local network ๐Ÿ‘€

There are several types of attacks possible in an ICE system. The subsections consider these attacks and their countermeasures ๐Ÿ’…

19.2. Attacks on Connectivity Checks ๐Ÿ’€

An attacker might attempt to disrupt the STUN connectivity checks. Ultimately, all of these attacks fool an ICE agent into thinking something incorrect about the results of the connectivity checks. Depending on the type of attack, the attacker needs to have different capabilities. In some cases, the attacker needs to be on the path of the connectivity checks. In other cases, the attacker does not need to be on the path, as long as it is able to generate STUN connectivity checks. While attacks on connectivity checks are typically performed by network entities, if an attacker is able to control an endpoint, it might be able to trigger connectivity-check attacks. The possible false conclusions an attacker can try and cause are:

  • False Invalid: An attacker can fool a pair of agents into thinking a candidate pair is invalid, when it isn't. This can be used to cause an agent to prefer a different candidate (such as one injected by the attacker) or to disrupt a call by forcing all candidates to fail.
  • False Valid: An attacker can fool a pair of agents into thinking a candidate pair is valid, when it isn't. This can cause an agent to proceed with a session but then not be able to receive any data.
  • False Peer-Reflexive Candidate: An attacker can cause an agent to discover a new peer-reflexive candidate when it is not expected to. This can be used to redirect data streams to a DoS target or to the attacker, for eavesdropping or other purposes.
  • False Valid on False Candidate: An attacker has already convinced an agent that there is a candidate with an address that does not actually route to that agent (e.g., by injecting a false peer-reflexive candidate or false server-reflexive candidate). The attacker then launches an attack that forces the agents to believe that this candidate is valid.

If an attacker can cause a false peer-reflexive candidate or false valid on a false candidate, it can launch any of the attacks described in [RFC5389] ๐Ÿšจ

To force the false invalid result, the attacker has to wait for the connectivity check from one of the agents to be sent. When it is, the attacker needs to inject a fake response with an unrecoverable error response (such as a 400), or drop the response so that it never reaches the agent. However, since the candidate is, in fact, valid, the original request may reach the peer agent and result in a success response. The attacker needs to force this packet or its response to be dropped through a DoS attack, a Layer 2 network disruption, or another technique. If it doesn't do this, the success response will also reach the originator, alerting it to a possible attack. The ability for the attacker to generate a fake response is mitigated through the STUN short-term credential mechanism. In order for this response to be processed, the attacker needs the password. If the candidate exchange signaling is secured, the attacker will not have the password, and its response will be discarded ๐Ÿ”

Spoofed ICMP Hard Errors (Type 3, codes 2-4) can also be used to create false invalid results. If an ICE agent implements a response to these ICMP errors, the attacker is capable of generating an ICMP message that is delivered to the agent sending the connectivity check. The validation of the ICMP error message by the agent is its only defense. For Type 3 code=4, the outer IP header provides no validation, unless the connectivity check was sent with DF=0. For codes 2 or 3, which are originated by the host, the address is expected to be any of the remote agent's host, reflexive, or relay candidate IP addresses. The ICMP message includes the IP header and UDP header of the message triggering the error. These fields also need to be validated. The IP destination and UDP destination port need to match either the targeted candidate address and port or the candidate's base address. The source IP address and port can be any candidate for the same base address of the agent sending the connectivity check. Thus, any attacker having access to the exchange of the candidates will have the necessary information. Hence, the validation is a weak defense, and the sending of spoofed ICMP attacks is also possible for off-path attackers from a node in a network without source address validation ๐Ÿ˜ฑ

Forcing the fake valid result works in a similar way. The attacker needs to wait for the Binding request from each agent and inject a fake success response. Again, due to the STUN short-term credential mechanism, in order for the attacker to inject a valid success response, the attacker needs the password. Alternatively, the attacker can route (e.g., using a tunneling mechanism) a valid success response, which normally would be dropped or rejected by the network, to the agent ๐ŸŒˆ

Forcing the false peer-reflexive candidate result can be done with either fake requests or responses, or with replays. We consider the fake requests and responses case first. It requires the attacker to send a Binding request to one agent with a source IP address and port for the false candidate. In addition, the attacker needs to wait for a Binding request from the other agent and generate a fake response with a XOR-MAPPED-ADDRESS attribute containing the false candidate. Like the other attacks described here, this attack is mitigated by the STUN message integrity mechanisms and secure candidate exchanges ๐Ÿ›ก๏ธ

Forcing the false peer-reflexive candidate result with packet replays is different. The attacker waits until one of the agents sends a check. It intercepts this request and replays it towards the other agent with a faked source IP address. It also needs to prevent the original request from reaching the remote agent, by either launching a DoS attack to cause the packet to be dropped or forcing it to be dropped using Layer 2 mechanisms. The replayed packet is received at the other agent, and accepted, since the integrity check passes (the integrity check cannot and does not cover the source IP address and port). It is then responded to. This response will contain a XOR-MAPPED-ADDRESS with the false candidate, and it will be sent to that false candidate. The attacker then needs to receive it and relay it towards the originator ๐ŸŽญ

The other agent will then initiate a connectivity check towards that false candidate. This validation needs to succeed. This requires the attacker to force a false valid on a false candidate. The injecting of fake requests or responses to achieve this goal is prevented using the integrity mechanisms of STUN and the candidate exchange. Thus, this attack can only be launched through replays. To do that, the attacker needs to intercept the check towards this false candidate and replay it towards the other agent. Then, it needs to intercept the response and replay that back as well ๐Ÿ”

This attack is very hard to launch unless the attacker is identified by the fake candidate. This is because it requires the attacker to intercept and replay packets sent by two different hosts. If both agents are on different networks (e.g., across the public Internet), this attack can be hard to coordinate, since it needs to occur against two different endpoints on different parts of the network at the same time ๐Ÿ™Œ

If the attacker itself is identified by the fake candidate, the attack is easier to coordinate. However, if the data path is secured (e.g., using the Secure Real-time Transport Protocol (SRTP) [RFC3711]), the attacker will not be able to process the data packets, but will only be able to discard them, effectively disabling the data stream. However, this attack requires the agent to disrupt packets in order to block the connectivity check from reaching the target. In that case, if the goal is to disrupt the data stream, it's much easier to just disrupt it with the same mechanism, rather than attack ICE ๐Ÿ’œ

19.3. Attacks on Server-Reflexive Address Gathering ๐ŸŽ€

okay so ICE agents use STUN Binding requests to gather their server-reflexive candidates from a STUN server, and these requests are not authenticated in any way ๐Ÿ˜ญ which means there are a bunch of ways an attacker can hand the client a fake server-reflexive candidate:

  • An attacker can compromise the DNS so that DNS queries return a rogue STUN server address. That server can then feed the client fake server-reflexive candidates. DNS security helps with this one, though DNSSEC is not required to address it. ๐ŸŒธ
  • An attacker that can observe STUN messages (like someone on a shared network segment, such as Wi-Fi) can inject a fake response that looks valid and will be accepted by the client. ๐Ÿ‘€
  • An attacker can compromise a STUN server and make it send responses with incorrect mapped addresses. ๐Ÿ’€

so a false mapped address learned through these attacks will get used as a server-reflexive candidate while the ICE session is being set up ๐Ÿงš but for that candidate to actually carry data, the attacker also has to attack the connectivity checks, specifically by forcing a false valid on a false candidate. this is very hard to pull off if the false address points to a fourth party (not the initiator, the responder, or the attacker), because the attacker would have to attack the checks generated by each ICE agent in the session. and if the false address points to the attacker itself, SRTP prevents it. โœจ

if the attacker decides not to touch the connectivity checks, the worst it can do is stop the server-reflexive candidate from being used. but here's the thing: if the peer agent has at least one candidate that the agent under attack can reach, the STUN connectivity checks themselves will produce a peer-reflexive candidate that can be used to exchange data ๐Ÿฆ‹ and peer-reflexive candidates are generally preferred over server-reflexive ones. so an attack that only messes with STUN address gathering will normally have no impact on the session at all. main character energy for ICE, honestly ๐Ÿ‘‘

19.4. Attacks on Relayed Candidate Gathering ๐Ÿซถ

an attacker might try to mess with relayed candidate gathering so the client thinks it has a false relayed candidate ๐Ÿ˜ค but the exchanges with the TURN server are authenticated using a long-term credential, so injecting fake responses or requests won't work. also, unlike Binding requests, Allocate requests can't be replayed with modified source IP addresses and ports, since the source IP address and port aren't used to give the client its relayed candidate. secure and iconic ๐Ÿ’…

even if an attacker does manage to convince the client it has a false relayed candidate, the connectivity checks only let that candidate get used if they succeed ๐Ÿ™…โ€โ™€๏ธ so the attacker would still need to pull off a false valid on a false candidate, which is (as we covered above) a really hard thing to coordinate. ๐Ÿ”

19.5. Insider Attacks ๐Ÿ’œ

so far we've talked about third parties trying to shove fake candidate information or STUN messages into the mix, but ICE also has attacks that are possible when the attacker is an authenticated and valid participant in the ICE exchange. the plot thickens ๐Ÿ™ˆ

19.5.1. STUN Amplification Attack ๐Ÿ“ฃ

the STUN amplification attack is kind of like a "voice hammer" attack, where the attacker gets other agents to direct voice packets at the attack target. except here, the STUN connectivity checks get directed at the target instead of voice packets. the attacker sends a large number of candidates, say 50 ๐Ÿ˜ณ and the responding agent takes in the candidate information and starts its checks, which are aimed at the target, so the target never generates a response. in WebRTC, the user might not even notice this is happening, since it could be kicked off in the background by malicious JavaScript they grabbed without knowing ๐Ÿ’€

the answerer starts a new connectivity check every Ta ms (say, Ta=50ms). but the retransmission timers are set to a large number because there are so many candidates. so packets get sent once every Ta milliseconds, and then at increasing intervals after that. STUN never sends packets faster than data would be sent, and the STUN packets only stick around briefly, until ICE fails for the session. still, it's an amplification mechanism, and that's the tea โ˜•

it's impossible to eliminate the amplification, but the volume can be reduced with a variety of heuristics. ICE agents SHOULD limit the total number of connectivity checks they perform to 100 โœ‹ and agents MAY also limit the number of candidates they'll accept ๐ŸŒˆ

usually, protocols that want to dodge these kinds of attacks make the initiator wait for a response before sending the next message. with ICE, that just isn't possible ๐Ÿ˜ฉ because there's no way to tell apart these two situations:

  • There was no response because the initiator is being used to launch a DoS attack against an unsuspecting target that won't respond.
  • There was no response because the IP address and port aren't reachable by the initiator.

in the second case another check gets sent at the next opportunity, while in the first case no further checks get sent. the lowkey tragedy of having to guess ๐Ÿฅน

20. IANA Considerations ๐ŸŒท

the original ICE specification registered four STUN attributes and one new STUN error response. those attributes and that error response are reproduced here ๐Ÿ“‹ and this specification also registers a new ICE option. ๐Ÿ“

20.1. STUN Attributes ๐Ÿฆ‹

IANA has registered four STUN attributes:

   0x0024 PRIORITY
   0x0025 USE-CANDIDATE
   0x8029 ICE-CONTROLLED
   0x802A ICE-CONTROLLING

20.2. STUN Error Responses ๐Ÿšซ

IANA has registered the following STUN error-response code:

    487   Role Conflict: The client asserted an ICE role (controlling or
          controlled) that is in conflict with the role of the server.

20.3. ICE Options ๐Ÿงš

IANA has registered the following ICE option in the "ICE Options" subregistry of the "Interactive Connectivity Establishment (ICE)" registry, following the procedures defined in [RFC6336] ๐Ÿ“

   ICE Option name:
      ice2

   Contact:
      Name:    IESG
      Email:   iesg@ietf.org

   Change Controller:
      IESG

   Description:
      The ICE option indicates that the ICE agent using the ICE option
      is implemented according to RFC 8445.

   Reference:
      RFC 8445

21. Changes from RFC 5245 ๐Ÿ”„

the whole point of this updated ICE spec is to:

  • Clarify procedures in RFC 5245.
  • Make technical changes, due to discovered flaws in RFC 5245 and feedback from the community that has implemented and deployed ICE applications based on RFC 5245.
  • Make the procedures independent of the signaling protocol, by removing the SIP and SDP procedures. Procedures specific to a signaling protocol will be defined in separate usage documents. [ICE-SIP-SDP] defines ICE usage with SIP and SDP. ๐ŸŽ€

the following technical changes have been made:

  • Aggressive nomination removed.
  • The procedures for calculating candidate pair states and scheduling connectivity checks modified.
  • Procedures for calculation of Ta and RTO modified.
  • Active checklist and Frozen checklist definitions removed.
  • 'ice2' ICE option added.
  • IPv6 considerations modified.
  • Usage with no-op for keepalives, and keepalives with non-ICE peers, removed. ๐Ÿงน

22. References ๐Ÿ“š

22.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,
              <https://www.rfc-editor.org/info/rfc2119>.

   [RFC4941]  Narten, T., Draves, R., and S. Krishnan, "Privacy
              Extensions for Stateless Address Autoconfiguration in
              IPv6", RFC 4941, DOI 10.17487/RFC4941, September 2007,
              <https://www.rfc-editor.org/info/rfc4941>.

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

   [RFC6336]  Westerlund, M. and C. Perkins, "IANA Registry for
              Interactive Connectivity Establishment (ICE) Options",
              RFC 6336, DOI 10.17487/RFC6336, July 2011,
              <https://www.rfc-editor.org/info/rfc6336>.

   [RFC6724]  Thaler, D., Ed., Draves, R., Matsumoto, A., and T. Chown,
              "Default Address Selection for Internet Protocol Version 6
              (IPv6)", RFC 6724, DOI 10.17487/RFC6724, September 2012,
              <https://www.rfc-editor.org/info/rfc6724>.

   [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>.

22.2. Informative References โœจ

Okay bestie, this is the reading list ๐Ÿ“š These are the background sources the spec points to, the ones that give context rather than rules.

[ICE-SIP-SDP]
           Petit-Huguenin, M., Nandakumar, S., and A. Keranen,
           "Session Description Protocol (SDP) Offer/Answer
           procedures for Interactive Connectivity Establishment
           (ICE)", Work in Progress,
           draft-ietf-mmusic-ice-sip-sdp-21, June 2018.

[RFC1918]  Rekhter, Y., Moskowitz, B., Karrenberg, D., de Groot, G.,
           and E. Lear, "Address Allocation for Private Internets",
           BCP 5, RFC 1918, DOI 10.17487/RFC1918, February 1996,
           <https://www.rfc-editor.org/info/rfc1918>.

[RFC2475]  Blake, S., Black, D., Carlson, M., Davies, E., Wang, Z.,
           and W. Weiss, "An Architecture for Differentiated
           Services", RFC 2475, DOI 10.17487/RFC2475, December 1998,
           <https://www.rfc-editor.org/info/rfc2475>.

[RFC3102]  Borella, M., Lo, J., Grabelsky, D., and G. Montenegro,
           "Realm Specific IP: Framework", RFC 3102,
           DOI 10.17487/RFC3102, October 2001,
           <https://www.rfc-editor.org/info/rfc3102>.

[RFC3103]  Borella, M., Grabelsky, D., Lo, J., and K. Taniguchi,
           "Realm Specific IP: Protocol Specification", RFC 3103,
           DOI 10.17487/RFC3103, October 2001,
           <https://www.rfc-editor.org/info/rfc3103>.

[RFC3235]  Senie, D., "Network Address Translator (NAT)-Friendly
           Application Design Guidelines", RFC 3235,
           DOI 10.17487/RFC3235, January 2002,
           <https://www.rfc-editor.org/info/rfc3235>.

[RFC3261]  Rosenberg, J., Schulzrinne, H., Camarillo, G., Johnston,
           A., Peterson, J., Sparks, R., Handley, M., and E.
           Schooler, "SIP: Session Initiation Protocol", RFC 3261,
           DOI 10.17487/RFC3261, June 2002,
           <https://www.rfc-editor.org/info/rfc3261>.

[RFC3264]  Rosenberg, J. and H. Schulzrinne, "An Offer/Answer Model
           with Session Description Protocol (SDP)", RFC 3264,
           DOI 10.17487/RFC3264, June 2002,
           <https://www.rfc-editor.org/info/rfc3264>.

[RFC3303]  Srisuresh, P., Kuthan, J., Rosenberg, J., Molitor, A., and
           A. Rayhan, "Middlebox communication architecture and
           framework", RFC 3303, DOI 10.17487/RFC3303, August 2002,
           <https://www.rfc-editor.org/info/rfc3303>.

[RFC3424]  Daigle, L., Ed. and IAB, "IAB Considerations for
           UNilateral Self-Address Fixing (UNSAF) Across Network
           Address Translation", RFC 3424, DOI 10.17487/RFC3424,
           November 2002, <https://www.rfc-editor.org/info/rfc3424>.

[RFC3489]  Rosenberg, J., Weinberger, J., Huitema, C., and R. Mahy,
           "STUN - Simple Traversal of User Datagram Protocol (UDP)
           Through Network Address Translators (NATs)", RFC 3489,
           DOI 10.17487/RFC3489, March 2003,
           <https://www.rfc-editor.org/info/rfc3489>.

[RFC3550]  Schulzrinne, H., Casner, S., Frederick, R., and V.
           Jacobson, "RTP: A Transport Protocol for Real-Time
           Applications", STD 64, RFC 3550, DOI 10.17487/RFC3550,
           July 2003, <https://www.rfc-editor.org/info/rfc3550>.

[RFC3605]  Huitema, C., "Real Time Control Protocol (RTCP) attribute
           in Session Description Protocol (SDP)", RFC 3605,
           DOI 10.17487/RFC3605, October 2003,
           <https://www.rfc-editor.org/info/rfc3605>.

[RFC3711]  Baugher, M., McGrew, D., Naslund, M., Carrara, E., and K.
           Norrman, "The Secure Real-time Transport Protocol (SRTP)",
           RFC 3711, DOI 10.17487/RFC3711, March 2004,
           <https://www.rfc-editor.org/info/rfc3711>.

[RFC3725]  Rosenberg, J., Peterson, J., Schulzrinne, H., and G.
           Camarillo, "Best Current Practices for Third Party Call
           Control (3pcc) in the Session Initiation Protocol (SIP)",
           BCP 85, RFC 3725, DOI 10.17487/RFC3725, April 2004,
           <https://www.rfc-editor.org/info/rfc3725>.

[RFC3879]  Huitema, C. and B. Carpenter, "Deprecating Site Local
           Addresses", RFC 3879, DOI 10.17487/RFC3879, September
           2004, <https://www.rfc-editor.org/info/rfc3879>.

[RFC4038]  Shin, M-K., Ed., Hong, Y-G., Hagino, J., Savola, P., and
           E. Castro, "Application Aspects of IPv6 Transition",
           RFC 4038, DOI 10.17487/RFC4038, March 2005,
           <https://www.rfc-editor.org/info/rfc4038>.

[RFC4091]  Camarillo, G. and J. Rosenberg, "The Alternative Network
           Address Types (ANAT) Semantics for the Session Description
           Protocol (SDP) Grouping Framework", RFC 4091,
           DOI 10.17487/RFC4091, June 2005,
           <https://www.rfc-editor.org/info/rfc4091>.

[RFC4092]  Camarillo, G. and J. Rosenberg, "Usage of the Session
           Description Protocol (SDP) Alternative Network Address
           Types (ANAT) Semantics in the Session Initiation Protocol
           (SIP)", RFC 4092, DOI 10.17487/RFC4092, June 2005,
           <https://www.rfc-editor.org/info/rfc4092>.

[RFC4103]  Hellstrom, G. and P. Jones, "RTP Payload for Text
           Conversation", RFC 4103, DOI 10.17487/RFC4103, June 2005,
           <https://www.rfc-editor.org/info/rfc4103>.

[RFC4291]  Hinden, R. and S. Deering, "IP Version 6 Addressing
           Architecture", RFC 4291, DOI 10.17487/RFC4291, February
           2006, <https://www.rfc-editor.org/info/rfc4291>.

[RFC4566]  Handley, M., Jacobson, V., and C. Perkins, "SDP: Session
           Description Protocol", RFC 4566, DOI 10.17487/RFC4566,
           July 2006, <https://www.rfc-editor.org/info/rfc4566>.

[RFC4787]  Audet, F., Ed. and C. Jennings, "Network Address
           Translation (NAT) Behavioral Requirements for Unicast
           UDP", BCP 127, RFC 4787, DOI 10.17487/RFC4787, January
           2007, <https://www.rfc-editor.org/info/rfc4787>.

[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,
           <https://www.rfc-editor.org/info/rfc5245>.

[RFC5382]  Guha, S., Ed., Biswas, K., Ford, B., Sivakumar, S., and P.
           Srisuresh, "NAT Behavioral Requirements for TCP", BCP 142,
           RFC 5382, DOI 10.17487/RFC5382, October 2008,
           <https://www.rfc-editor.org/info/rfc5382>.

[RFC5761]  Perkins, C. and M. Westerlund, "Multiplexing RTP Data and
           Control Packets on a Single Port", RFC 5761,
           DOI 10.17487/RFC5761, April 2010,
           <https://www.rfc-editor.org/info/rfc5761>.

[RFC6080]  Petrie, D. and S. Channabasappa, Ed., "A Framework for
           Session Initiation Protocol User Agent Profile Delivery",
           RFC 6080, DOI 10.17487/RFC6080, March 2011,
           <https://www.rfc-editor.org/info/rfc6080>.

[RFC6146]  Bagnulo, M., Matthews, P., and I. van Beijnum, "Stateful
           NAT64: Network Address and Protocol Translation from IPv6
           Clients to IPv4 Servers", RFC 6146, DOI 10.17487/RFC6146,
           April 2011, <https://www.rfc-editor.org/info/rfc6146>.

[RFC6147]  Bagnulo, M., Sullivan, A., Matthews, P., and I. van
           Beijnum, "DNS64: DNS Extensions for Network Address
           Translation from IPv6 Clients to IPv4 Servers", RFC 6147,
           DOI 10.17487/RFC6147, April 2011,
           <https://www.rfc-editor.org/info/rfc6147>.

[RFC6298]  Paxson, V., Allman, M., Chu, J., and M. Sargent,
           "Computing TCP's Retransmission Timer", RFC 6298,
           DOI 10.17487/RFC6298, June 2011,
           <https://www.rfc-editor.org/info/rfc6298>.

[RFC6544]  Rosenberg, J., Keranen, A., Lowekamp, B., and A. Roach,
           "TCP Candidates with Interactive Connectivity
           Establishment (ICE)", RFC 6544, DOI 10.17487/RFC6544,
           March 2012, <https://www.rfc-editor.org/info/rfc6544>.

[RFC6928]  Chu, J., Dukkipati, N., Cheng, Y., and M. Mathis,
           "Increasing TCP's Initial Window", RFC 6928,
           DOI 10.17487/RFC6928, April 2013,
           <https://www.rfc-editor.org/info/rfc6928>.

[RFC7050]  Savolainen, T., Korhonen, J., and D. Wing, "Discovery of
           the IPv6 Prefix Used for IPv6 Address Synthesis",
           RFC 7050, DOI 10.17487/RFC7050, November 2013,
           <https://www.rfc-editor.org/info/rfc7050>.

[RFC7721]  Cooper, A., Gont, F., and D. Thaler, "Security and Privacy
           Considerations for IPv6 Address Generation Mechanisms",
           RFC 7721, DOI 10.17487/RFC7721, March 2016,
           <https://www.rfc-editor.org/info/rfc7721>.

[RFC7825]  Goldberg, J., Westerlund, M., and T. Zeng, "A Network
           Address Translator (NAT) Traversal Mechanism for Media
           Controlled by the Real-Time Streaming Protocol (RTSP)",
           RFC 7825, DOI 10.17487/RFC7825, December 2016,
           <https://www.rfc-editor.org/info/rfc7825>.

[RFC8421]  Martinsen, P., Reddy, T., and P. Patil, "Interactive
           Connectivity Establishment (ICE) Multihomed and IPv4/IPv6
           Dual-Stack Guidelines", RFC 8421, DOI 10.17487/RFC8421,
           July 2018, <https://www.rfc-editor.org/info/rfc8421>.

[WebRTC-IP-HANDLING]
           Uberti, J. and G. Shieh, "WebRTC IP Address Handling
           Requirements", Work in Progress, draft-ietf-rtcweb-ip-
           handling-09, June 2018.

That's the whole reading list, babe ๐ŸŽ€ these are the sources ICE points to for extra context ๐Ÿ’…

Appendix A. Lite and Full Implementations โœจ

okay so ICE has two flavours of implementation ๐Ÿ’… A full implementation can be the controlling or the controlled role in a session, and it can also do address gathering ๐Ÿ”ฅ. A lite implementation is the minimalist bestie ๐ŸŒธ: it basically just answers STUN checks, and it only ever plays the controlled role ๐Ÿซถ.

Here's the thing. ICE only helps if both endpoints speak it, so rolling it out bit by bit across a network is kinda messy ๐Ÿ˜ญ. A lot of sessions have an endpoint that isn't behind a NAT at all and doesn't need NAT traversal to begin with. Super common example: a VoIP hard phone or soft phone (the one needing traversal) calls one of these devices ๐Ÿ“ž. Even if the phone is fully ICE-capable, ICE won't get used at all if the other device doesn't support it ๐Ÿ’€. That's where lite comes in ๐Ÿงš. It's a low-cost entry point, and once those devices support lite, full implementations can connect to them and get all the ICE goodies ๐ŸŽ€.

So, a lite implementation is only appropriate for devices that will always be connected to the public Internet, with a public IP address where they can receive packets from any correspondent ๐ŸŒˆ. ICE will NOT function if a lite implementation is sitting behind a NAT ๐Ÿ™ˆ.

Lite implementations are allowed to have a single IPv4 host candidate and several IPv6 addresses ๐Ÿฆ‹. In that case, the controlling agent picks candidate pairs with a static algorithm, such as the one in [RFC6724], which is RECOMMENDED by this specification ๐Ÿ’œ. BUT, and this is a big but ๐Ÿ˜ค, static address selection is always prone to error, since it can never reflect the actual topology or give actual guarantees on connectivity. They're always heuristics, bestie. So if an ICE agent is only using ICE to pick between its IPv4 and IPv6 addresses, and none of its addresses are behind NAT, full ICE is still RECOMMENDED so you get the most robust address selection possible ๐Ÿ‘‘.

Lowkey the most important bit: the lite implementation was added to this specification as a stepping stone toward full implementation โœจ. Even for devices that are always on the public Internet with just one IPv4 address, a full implementation is preferable if you can manage it ๐Ÿ’–. Full implementations also get the security benefits of ICE that have nothing to do with NAT traversal ๐Ÿ”. And honestly, it's super common for a device that has a public address today to get dropped into a network tomorrow where it's behind a NAT ๐Ÿ˜ญ. It's hard to know for sure over the whole lifetime of a device or product whether it'll always be on the public Internet. Full implementation gives you the assurance that communications will always work ๐Ÿซถ.


Appendix B. Design Motivations โœจ

ICE has a bunch of normative behaviours that might look simple on the surface, but they come from some complicated or non-obvious thinking and use cases that deserve a proper chat ๐Ÿง ๐Ÿ’…. Since you don't need these motivations to actually implement ICE, we're talking through them here. This appendix is non-normative ๐ŸŒธ.

B.1. Pacing of STUN Transactions ๐Ÿฆ‹

STUN transactions used to gather candidates and verify connectivity get paced out at an approximate rate of one new transaction every Ta milliseconds โฑ๏ธ. Each transaction also has a retransmission timer RTO that depends on Ta too. So why pace these, and why these formulas? ๐Ÿค”

Sending these STUN requests often creates bindings on NAT devices between the client and the STUN servers ๐Ÿšง. Experience has shown that lots of NAT devices have upper limits on how fast they'll create new bindings. Discussions in the IETF ICE WG during the work on this specification concluded that once every 5 ms is well supported ๐Ÿ’–. That's why Ta has a lower bound of 5 ms. Also, sending these packets uses bandwidth, so the ICE agent needs to rate limit it ๐Ÿ“‰. Deployments based on earlier draft versions of [RFC5245] tended to overload rate-constrained access links and performed poorly overall, on top of hurting the network ๐Ÿ˜ฉ. So the pacing makes sure the NAT device doesn't get overloaded and the traffic stays at a reasonable rate ๐ŸŽ€.

So what counts as "reasonable"? STUN MUST NOT use more bandwidth than the RTP itself will use once data starts flowing ๐Ÿšซ. The formula for Ta is built so that if a STUN packet were sent every Ta seconds, it would eat the same bandwidth as RTP packets, summed across all data streams ๐Ÿ“. STUN also has retransmits, and we want to pace those too ๐Ÿ™ˆ. That's why RTO is set so the first retransmit on the first transaction happens right as the first STUN request on the last transaction goes out โœจ. Picture it like this:

          First Packets              Retransmits



                |                        |
                |                        |
         -------+------           -------+------
        /               \        /               \
       /                 \      /                 \

       +--+    +--+    +--+    +--+    +--+    +--+
       |A1|    |B1|    |C1|    |A2|    |B2|    |C2|
       +--+    +--+    +--+    +--+    +--+    +--+

    ---+-------+-------+-------+-------+-------+------------ Time
       0       Ta      2Ta     3Ta     4Ta     5Ta

In this picture there are three transactions being sent (for example, when gathering candidates, there are three host candidate/STUN server pairs) ๐Ÿงš. They're transactions A, B, and C. The retransmit timer is set so the first retransmission on the first transaction (packet A2) goes out at time 3Ta ๐Ÿ’….

Later retransmits happen even less often than Ta milliseconds apart, because STUN uses exponential backoff on its retransmissions ๐Ÿ“‰.

Now, this global minimum pacing interval of 5 ms isn't generally applicable to transport protocols ๐Ÿ™…โ€โ™€๏ธ, but it is applicable to ICE, and here's the reasoning ๐Ÿง .

  • Start with these rules that would be generally applicable to transport protocols:
    1. Let MaxBytes be the maximum number of bytes allowed to be outstanding in the network at startup, which SHOULD be 14600, as defined in Section 2 of [RFC6928] ๐ŸŒŠ.
    2. Let HTO be the transaction timeout, which SHOULD be 2*RTT if RTT is known or 500 ms otherwise. This is based on the RTO for STUN messages from [RFC5389] and the TCP initial RTO, which is 1 sec in [RFC6298] โณ.
    3. Let MinPacing be the minimum pacing interval between transactions, which is 5 ms (see above) ๐ŸŽต.
  • Notice that agents typically don't know the RTT for ICE transactions (connectivity checks especially), which means HTO will almost always be 500 ms ๐Ÿ™ˆ.
  • Notice that a MinPacing of 5 ms and an HTO of 500 ms gives at most 100 packets per HTO. For a typical ICE check under 120 bytes, that's a max of 12000 outstanding bytes in the network, which is less than the maximum rule 1 allows ๐Ÿ’–.
  • So, for ICE, the rule set boils down to just the MinPacing rule, which is the same as having a global Ta value ๐Ÿ‘‘.

B.2. Candidates with Multiple Bases ๐ŸŒˆ

Section 5.1.3 talks about eliminating candidates that share the same transport address and base ๐Ÿ—‘๏ธ. BUT candidates with the same transport address and different bases are not redundant ๐Ÿ™…โ€โ™€๏ธ. So when can an ICE agent end up with two candidates that have the same IP address and port but different bases? ๐Ÿค” Check out the topology in Figure 11:

        +----------+
        | STUN Srvr|
        +----------+
             |
             |
           -----
         //     \\
        |         |
       |  B:net10  |
        |         |
         \\     //
           -----
             |
             |
        +----------+
        |   NAT    |
        +----------+
             |
             |
           -----
         //     \\
        |    A    |
       |192.168/16 |
        |         |
         \\     //
           -----
             |
             |
             |192.168.1.100      -----
        +----------+           //     \\             +----------+
        |          |          |         |            |          |
        | Initiator|---------|  C:net10  |-----------| Responder|
        |          |10.0.1.100|         | 10.0.1.101 |          |
        +----------+           \\     //             +----------+
                                 -----

         Figure 11: Identical Candidates with Different Bases

Here the initiating agent is multihomed ๐Ÿง‘โ€๐Ÿ’ป. It has one IP address, 10.0.1.100, on network C, which is a net 10 private network, and the responding agent is on that same network too ๐ŸŽ€. The initiating agent is also connected to network A, which is 192.168/16 and has an IP address of 192.168.1.100 ๐ŸŒธ. There's a NAT on this network that maps into network B, another net 10 private network, but B is not connected to network C ๐Ÿšง. There's a STUN server on network B ๐Ÿฆ‹.

The initiating agent gets a host candidate on its network C address (10.0.1.100:2498) and a host candidate on its network A address (192.168.1.100:3344) ๐Ÿงš. It sends a STUN query to its configured STUN server from 192.168.1.100:3344 ๐Ÿ“ก. That query goes through the NAT, which happens to assign the binding 10.0.1.100:2498 ๐Ÿ˜ณ. The STUN server reflects this back in the STUN Binding response ๐Ÿ”. Now the initiating agent has a server-reflexive candidate whose transport address is identical to a host candidate (10.0.1.100:2498) ๐Ÿ‘€. BUT the server-reflexive candidate has a base of 192.168.1.100:3344, while the host candidate has a base of 10.0.1.100:2498 ๐Ÿ’…. Different bases, same address, so both are kept โœจ.

okay bestie, we're picking up with Appendix B.3 and it's lowkey such a good one ๐ŸŽ€

The candidate attribute carries two values that ICE itself never actually uses: related address and related port. ๐Ÿ’… So why are they even there? ๐Ÿค”

There are two motivations, and they're both kinda iconic. โœจ The first one is diagnostic. It is very useful to know how the different candidate types relate to each other. ๐Ÿฆ‹ With the related values included, an ICE agent can figure out which relayed candidate goes with which reflexive candidate, and which of those goes with a specific host candidate. ๐Ÿงฉ When checks succeed for one candidate but not the others, that gives you useful clues about what's going on in the network. ๐Ÿ•ต๏ธโ€โ™€๏ธ

The second reason is giving off-path Quality-of-Service (QoS) vibes. ๐Ÿ’œ When ICE is used in environments such as PacketCable 2.0, proxies do their normal SIP stuff, but they also inspect the SDP in SIP messages and pull out the IP address and port for data traffic. ๐Ÿ“ž They then talk to policy servers, which talk to access routers, so that guaranteed QoS can be set up for the data flows. ๐ŸŒˆ That QoS works by classifying the RTP traffic based on its 5-tuple and then either giving it a guaranteed rate or marking its DSCP appropriately. ๐Ÿ’–

Here's the tricky part ๐Ÿ™ˆ: when a residential NAT is present and a relayed candidate gets selected for data, that relayed candidate is a transport address on an actual TURN server. That address says absolutely nothing about the real transport address in the access router that's used to classify packets for QoS treatment. ๐Ÿ˜ญ Instead, the server-reflexive candidate toward the TURN server is what's needed. ๐ŸŽ€ By carrying that translation in the SDP, the proxy can use that transport address to request QoS from the access router. ๐Ÿ‘‘ Main character problem solved!


B.4. Importance of the STUN Username

Okay, this one is so dramatic and I'm obsessed. ๐Ÿ™ˆ ICE requires message integrity with STUN, using its short-term credential functionality. ๐Ÿ” The actual short-term credential is formed by swapping username fragments during the candidate exchange. ๐Ÿง And this isn't just about security, either. It is actually required for ICE to work correctly in the first place. ๐Ÿซถ

Let's meet three agents: L, R, and Z. ๐Ÿงš L and R are both inside private enterprise 1, which uses 10.0.0.0/8. Z is inside private enterprise 2, which also uses 10.0.0.0/8. ๐Ÿ˜ณ Plot twist: R and Z both have the IP address 10.0.1.1. ๐Ÿ’€ L sends candidates to Z, and Z replies with its host candidates, which are 10.0.1.1:8866 and 10.0.1.1:8877. ๐Ÿ“ But at that exact same time, R is in a session too, and it's also using 10.0.1.1:8866 and 10.0.1.1:8877 as its host candidates. ๐Ÿ˜ฑ

So R is ready to accept STUN messages on those ports, just like Z is. L sends a STUN request to 10.0.1.1:8866 and another to 10.0.1.1:8877, and... they do NOT go to Z like they should. They go to R! ๐Ÿซฃ If R just replied to them, L would think it has connectivity to Z, when it's actually connected to a completely different user. ๐Ÿ™…โ€โ™€๏ธ That's a whole mess.

This is where the STUN short-term credentials save the day. โœจ The username fragments are random enough that it's highly unlikely R would be using the same values as Z. So R rejects the STUN request because the credentials are invalid. ๐Ÿ›ก๏ธ Basically, the STUN username fragments act like a form of transient host identifier, tied to one particular session set up during the candidate exchange. ๐Ÿฆ‹ Iconic. ๐Ÿ‘‘

Now, the not-so-cute consequence of IP addresses not being unique ๐Ÿ˜ฌ: in the example above, R might not even be an ICE agent. It could be any host at all, and the port the STUN packet is aimed at could be any ephemeral port on that host. ๐Ÿ’€ If some application is listening on that socket and isn't ready to handle malformed packets for whatever protocol it's using, that application could be affected. ๐Ÿ˜ฐ

Thankfully, the ports exchanged are ephemeral and usually come from the dynamic or registered range, so the odds are good that the port isn't running a server on host R. It's more likely the agent side of some protocol. ๐ŸŒธ That makes hitting an allocated port much less likely, because port usage in this range is very transient. โœจ Still, the possibility of a problem does exist, and network deployers need to be ready for it. ๐Ÿซถ And honestly, this isn't an ICE-only problem. Stray packets can show up on any port at any time for any kind of protocol, especially ones on the public Internet. ๐ŸŒ So this requirement is really just restating a general design guideline for Internet applications: be prepared for unknown packets on any port. ๐Ÿ’…๐Ÿ”ฅ


B.5. The Candidate Pair Priority Formula

The priority for a candidate pair has a kinda odd form, not gonna lie. ๐Ÿ™ƒ It goes like this:

pair priority = 2^32*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0)

So why this? ๐Ÿค” When candidate pairs get sorted by this value, the result has the MAX/MIN property, and that's the whole point. ๐Ÿญ Pairs are first sorted by decreasing value of the minimum of the two priorities. ๐Ÿ“‰ For pairs that share the same minimum priority, the maximum priority is used to sort among them. ๐Ÿ“ˆ And if the max and min priorities are the same, the controlling agent's priority is used as the tiebreaker in the last part of the expression. ๐Ÿ‘‘

The factor of 2^32 is used because the priority of a single candidate is always less than 2^32, so the pair priority is basically a "concatenation" of the two component priorities. ๐Ÿงฉ That's what creates the MAX/MIN sorting. โœจ And MAX/MIN ensures that, for a particular ICE agent, a lower-priority candidate is never used until all the higher-priority candidates have been tried. ๐Ÿฆ‹ No skipping the line, bestie! ๐Ÿšซ


B.6. Why Are Keepalives Needed?

Once data starts flowing on a candidate pair, you still have to keep the bindings alive at intermediate NATs for the whole session. ๐ŸŒˆ Normally the data packets themselves (like RTP) take care of this. ๐Ÿ’œ But there are a few cases that need a closer look. ๐Ÿ‘€

First, in some RTP usages, like SIP, the data streams can be "put on hold." ๐Ÿ“ž That's done with the SDP "sendonly" or "inactive" attributes, as defined in RFC 3264 [RFC3264]. RFC 3264 tells implementations to stop transmitting data in these cases. ๐Ÿ›‘ The problem? Doing that may cause NAT bindings to time out, and then data won't be able to come off hold. ๐Ÿ˜ญ

Second, some RTP payload formats, like the one for text conversation [RFC4103], may send packets so infrequently that the interval is longer than the NAT binding timeouts. ๐Ÿข

Third, if silence suppression is in use, long stretches of silence may stop data transmission for long enough that NAT bindings time out. ๐Ÿคซ

So for these reasons, the data packets can't be relied on by themselves. ๐Ÿ™…โ€โ™€๏ธ That's why ICE defines a simple periodic keepalive using STUN Binding Indications. ๐ŸŒธ It also makes the bandwidth requirements highly predictable, which makes them amenable to QoS reservations. ๐Ÿ’– Very organized, very slay. ๐Ÿ’…


B.7. Why Prefer Peer-Reflexive Candidates?

Section 5.1.2 describes how to compute the priority of a candidate based on its type and local preferences. ๐Ÿงฎ That section requires that the type preference for peer-reflexive candidates always be higher than for server-reflexive ones. ๐Ÿคจ Why??

It has to do with the security considerations in Section 19, and the answer is kinda genius. ๐Ÿง  It is much easier for an attacker to make an ICE agent use a false server-reflexive candidate than a false peer-reflexive candidate. ๐Ÿ•ธ๏ธ So ICE thwarts attacks against address gathering with Binding requests by preferring peer-reflexive candidates. ๐Ÿ›ก๏ธ Big brain move. ๐Ÿง โœจ


B.8. Why Are Binding Indications Used for Keepalives?

Data keepalives are described in Section 11, and they use STUN when both endpoints are ICE capable. ๐Ÿค But instead of a Binding request transaction (which generates a response), the keepalives use an Indication. ๐Ÿค” Why?

The main reason is network QoS mechanisms. ๐ŸŒ Once data is flowing, network elements assume the data stream has a fairly regular structure, with periodic packets at fixed intervals, and maybe a little jitter. โฑ๏ธ If an ICE agent is sending data packets and then receives a Binding request, it would have to generate a response packet alongside its data packets. ๐Ÿ˜ฌ That increases the actual bandwidth needs for the 5-tuple carrying the data, and it introduces jitter in how those packets get delivered. ๐Ÿ“ฆ Analysis has shown this is a real concern in certain Layer 2 access networks that use fairly tight packet schedulers for data. ๐ŸŽข

There's also a bonus: using a Binding Indication lets integrity be disabled, which may result in better performance. ๐Ÿš€ That's especially useful for large-scale endpoints, like Public Switched Telephone Network (PSTN) gateways and Session Border Controllers (SBCs). ๐Ÿข๐Ÿ’œ


B.9. Selecting Candidate Type Preference

One criterion for picking type and local preference values is whether a data intermediary is involved, like a TURN server, a tunnel service such as a VPN server, or a NAT. ๐Ÿงฑ With a data intermediary, data sent to that candidate first transits the intermediary before it's received. ๐Ÿ“ฌ One type of candidate that involves a data intermediary is the relayed candidate. Another is the host candidate, which is obtained from a VPN interface. ๐Ÿ”

When data goes through a data intermediary, it can have a positive or negative effect on latency between transmission and reception. ๐ŸŒโšก It may or may not increase packet losses, because of the additional router hops that might be taken. ๐Ÿ›ฃ๏ธ It may also increase the cost of providing service, since data gets routed in and right back out of an intermediary run by a provider. ๐Ÿ’ธ If these concerns matter to you, the type preference for relayed candidates needs to be chosen carefully. ๐Ÿง

Another criterion is the IP address family. ICE works with both IPv4 and IPv6. ๐ŸŒ It provides a transition mechanism that lets dual-stack hosts prefer connectivity over IPv6 but fall back to IPv4 if the v6 networks get disconnected. ๐Ÿ”„ Implementations SHOULD follow the guidelines from [RFC8421] to avoid excessive delays in the connectivity-check phase if broken paths exist. ๐Ÿงญ

Another criterion is topological awareness. ๐Ÿ—บ๏ธ This is beneficial for candidates that make use of intermediaries. If an ICE agent has preconfigured or dynamically discovered knowledge of how close the intermediaries are to itself, it can use that to assign higher local preferences to candidates obtained from closer intermediaries. ๐Ÿ“

And another criterion might be security or privacy. ๐Ÿ”’ Say a user is a telecommuter, connected to both a corporate network and a local home network. They might want their voice traffic routed over the VPN or a similar tunnel, to keep it on the corporate network when talking to people inside the enterprise, but use the local network when talking to people outside it. ๐Ÿ ๐Ÿ’ผ In that case, a VPN address would get a higher local preference than any other address. ๐Ÿฆ‹โœจ

Appendix C. Connectivity-Check Bandwidth โœจ

okay so bestie, this part is all about how much bandwidth connectivity checks eat ๐Ÿ“ The tables below show, for IPv4 and IPv6, how much bandwidth you need for connectivity checks at different Ta values (given in ms) and different ufrag sizes (given in bytes) ๐Ÿ’…

The numbers were provided by Jusin Uberti (Google) on 11 April 2016 ๐Ÿซถ

                 IP version: IPv4
                 Packet len (bytes): 108 + ufrag
                      |
                   ms |     4     8    12    16
                 -----|------------------------
                  500 | 1.86k 1.98k 2.11k 2.24k
                  200 | 4.64k 4.96k 5.28k  5.6k
                  100 | 9.28k 9.92k 10.6k 11.2k
                   50 | 18.6k 19.8k 21.1k 22.4k
                   20 | 46.4k 49.6k 52.8k 56.0k
                   10 | 92.8k 99.2k  105k  112k
                    5 |  185k  198k  211k  224k
                    2 |  464k  496k  528k  560k
                    1 |  928k  992k 1.06M 1.12M
                 IP version: IPv6
                 Packet len (bytes): 128 + ufrag
                      |
                   ms |     4     8    12    16
                 -----|------------------------
                  500 | 2.18k  2.3k 2.43k 2.56k
                  200 | 5.44k 5.76k 6.08k  6.4k
                  100 | 10.9k 11.5k 12.2k 12.8k
                   50 | 21.8k 23.0k 24.3k 25.6k
                   20 | 54.4k 57.6k 60.8k 64.0k
                   10 |  108k  115k  121k  128k
                    5 |  217k  230k  243k  256k
                    2 |  544k  576k  608k  640k
                    1 | 1.09M 1.15M 1.22M 1.28M

Figure 12: Connectivity-Check Bandwidth ๐Ÿ“Š

Acknowledgements ๐ŸŽ€

Most of the text in this document comes from the original ICE specification, RFC 5245 ๐ŸŒธ The authors want to thank everyone who worked on that document, which is honestly so iconic of them ๐Ÿ‘‘

For the extra contributions to this revision, a big thank-you to Emil Ivov, Paul Kyzivat, Pal-Erik Martinsen, Simon Perrault, Eric Rescorla, Thomas Stach, Peter Thatcher, Martin Thomson, Justin Uberti, Suhas Nandakumar, Taylor Brandstetter, Peter Saint-Andre, Harald Alvestrand, and Roman Shpount ๐Ÿซถโœจ

Ben Campbell did the AD review ๐Ÿ’… Stephen Farrell did the sec-dir review ๐Ÿ”ฅ Stewart Bryant did the gen-art review ๐Ÿฆ‹ Qin We did the ops-dir review ๐Ÿงš And Magnus Westerlund did the tsv-art review ๐Ÿ’œ

Authors' Addresses ๐ŸŒˆ

Ari Keranen
Ericsson
Hirsalantie 11
02420 Jorvas
Finland

Email: ari.keranen@ericsson.com
Christer Holmberg
Ericsson
Hirsalantie 11
02420 Jorvas
Finland

Email: christer.holmberg@ericsson.com
Jonathan Rosenberg
jdrosen.net
Monmouth, NJ
United States of America

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