RFC 5596
Datagram Congestion Control Protocol (DCCP) Simultaneous-Open Technique to Facilitate NAT/Middlebox Traversal
RFC 5596: Datagram Congestion Control Protocol (DCCP) Simultaneous-Open Technique to Facilitate NAT/Middlebox Traversal ๐ฆ
Okay bestie, so this RFC is by G. Fairhurst from the University of Aberdeen ๐. It was published in September 2009 as a Standards Track document, which means it's an actual Internet standard and not just a suggestion ๐ . It updates RFC 4340 (the main DCCP spec), and it doesn't obsolete anything. Let's get into it ๐ธ
Abstract โจ
This doc is an upgrade to DCCP, which is a transport protocol that's connection-oriented and datagram-based (both at once, iykyk ๐ง). The upgrade adds support for the DCCP-Listen packet. Why does that matter? It helps DCCP apps get through middleboxes, like a NAPT or a DCCP server sitting behind a firewall ๐ฅ. In those setups, both endpoints need to start talking at almost the same moment so the middlebox sets up the state it needs. It's giving teamwork ๐ซถ.
Status of This Memo ๐
This is an Internet standards track protocol for the Internet community, and the authors are literally asking for discussion and suggestions to make it better ๐. If you want to know where it stands officially, check the current edition of "Internet Official Protocol Standards" (STD 1) ๐. Distribution of this memo is unlimited, so share away ๐.
Copyright and License Notice ๐
The 2009 IETF Trust and the document authors own the copyright, and all rights are reserved ๐. This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents, which you can find at http://trustee.ietf.org/license-info (as they stood when this was published). Please read those carefully, because they spell out your rights and restrictions ๐งพ. If you pull Code Components out of this document, they have to include the Simplified BSD License text described in Section 4.e of the Trust Legal Provisions, and they come with no warranty under the BSD License ๐.
This document might include material from IETF Documents or Contributions that was published before November 10, 2008. Some of that material's copyright holders may not have let the IETF Trust allow changes outside the IETF Standards Process ๐ฌ. So, unless you get a proper license from those copyright holders, you can't modify this document outside the IETF Standards Process, and you can't make derivative works outside it either. The exceptions are formatting it for publication as an RFC or translating it into languages other than English ๐.
Table of Contents ๐๏ธ
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1. Scope of This Document . . . . . . . . . . . . . . . . . . 3
1.2. DCCP NAT Traversal . . . . . . . . . . . . . . . . . . . . 4
1.3. Structure of This Document . . . . . . . . . . . . . . . . 4
2. Procedure for Near-Simultaneous-Open . . . . . . . . . . . . . 5
2.1. Conventions and Terminology . . . . . . . . . . . . . . . 5
2.2. Protocol Method . . . . . . . . . . . . . . . . . . . . . 5
2.2.1. DCCP-Listen Packet Format . . . . . . . . . . . . . . 6
2.2.2. Protocol Method for DCCP Server Endpoints . . . . . . 7
2.2.3. Protocol Method for DCCP Client Endpoints . . . . . . 11
2.2.4. Processing by Routers and Middleboxes . . . . . . . . 11
2.3. Examples of Use . . . . . . . . . . . . . . . . . . . . . 12
2.3.1. Repetition of DCCP-Listen . . . . . . . . . . . . . . 13
2.3.2. Optional Triggered Retransmission of DCCP-Request . . 14
2.4. Backwards Compatibility with RFC 4340 . . . . . . . . . . 16
3. Discussion of Design Decisions . . . . . . . . . . . . . . . . 16
3.1. Rationale for a New Packet Type . . . . . . . . . . . . . 17
3.1.1. Use of Sequence Numbers . . . . . . . . . . . . . . . 18
3.2. Generation of Listen Packets . . . . . . . . . . . . . . . 18
3.3. Repetition of DCCP-Listen Packets . . . . . . . . . . . . 18
4. Security Considerations . . . . . . . . . . . . . . . . . . . 19
5. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 20
6. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 20
7. References . . . . . . . . . . . . . . . . . . . . . . . . . . 21
7.1. Normative References . . . . . . . . . . . . . . . . . . . 21
7.2. Informative References . . . . . . . . . . . . . . . . . . 21
Appendix A. Discussion of Existing NAT Traversal Techniques . . . 23
A.1. NAT Traversal Based on a Simultaneous-Request . . . . . . 24
A.2. Role Reversal . . . . . . . . . . . . . . . . . . . . . . 25
1. Introduction โจ
DCCP [RFC4340] is both datagram-based and connection-oriented ๐ธ. According to RFC 4340, DCCP servers set up connections by passively listening for incoming connection requests, and DCCP clients are the ones who actively send them ๐. Those lopsided roles can cause drama when the server is 'inside' a middlebox, like a Network Address Port Translation (NAPT) device, which only lets connection requests start from the inside (for example, because of port overloading) [RFC5597] ๐ฉ. Host-based and network firewalls can also have policies that cause the same kind of trouble. Honestly, this is the default behaviour for a lot of firewalls right now ๐.
UDP can get through middleboxes with various techniques [RFC4787] that use the fact that UDP is connectionless, so those techniques aren't a good fit for DCCP ๐ซ. TCP handles middlebox traversal with its simultaneous-open procedure [RFC5382] โจ. The ideas behind the TCP solution work for DCCP too, but DCCP can't just copy the same methods (see Appendix A) ๐ .
So after we talk about the problem space for DCCP, this document defines an update to the DCCP state machine that offers native support ๐ฆ. That lets a DCCP client connect to a DCCP server sitting inside one or more middleboxes. Nice bonus: it cuts down on the need for external helpers like data relay servers [STUN], because it directly supports a well-known idea called 'hole punching' ๐จ.
The method only needs a minor change to the normal DCCP operational procedure ๐. A dedicated DCCP packet type ties its use to one specific condition. That means the method stays inter-operable with hosts that don't implement this update, or that choose to turn it off (see Section 4) ๐ซถ.
1.1. Scope of This Document ๐บ๏ธ
This method is useful when a DCCP server is located inside the perimeter controlled by a middlebox ๐ฐ. It applies to both client/server and peer-to-peer apps, like Voice over IP (VoIP), file sharing, or online gaming ๐ฎ. It also helps with connections that use out-of-band signaling beforehand. For example, a well-known rendezvous server can tell both endpoints the connection parameters ([RFC3261], [H.323]) ([RFC3235], [NAT-APP]) ๐.
1.2. DCCP NAT Traversal ๐
The behavioural requirements for NAT devices that support DCCP are in [RFC5597] ๐. A "traditional NAT" [RFC3022] maps one IP address directly to a different IP address. It doesn't need the simultaneous-open technique from this document, so it's not the main character here ๐ โโ๏ธ.
The method is required when the DCCP server sits behind one or more NAPT devices in the path. Nested NAPT devices are possible too, so yes, it can get layered ๐ง . This document calls DCCP hosts inside the perimeter of one or more NAPT devices as having "private" addresses. DCCP hosts in the global address realm get "public" addresses ๐.
DCCP NAT traversal is considered for these scenarios:
- Private client connects to public server.
- Public client connects to private server.
- Private client connects to private server.
Here's the tea โ. A defining feature of traditional NAT devices [RFC3022] is that private hosts can connect out to external hosts, but outside hosts can't connect in to them. So case (1) already works with the protocol in [RFC4340]. A pre-configured, static NAT address map would let outside hosts start connections in cases (2) and (3) ๐๏ธ.
A DCCP implementation that conforms to [RFC4340], along with a NAT device that conforms to [RFC5597], would need a DCCP relay server to do NAT traversal for cases (2) and (3) ๐ค.
This document describes a method that supports cases (2) and (3) without any DCCP relay server ๐. This method updates RFC 4340. It requires the DCCP server to discover the IP address and the DCCP port that match the DCCP client. That signaling might happen out-of-band, for example using the Session Description Protocol (SDP) [RFC4566] ๐จ.
1.3. Structure of This Document ๐งญ
If you want background on existing NAT traversal techniques, go check out Appendix A ๐.
The normative specification of the update is in Section 2 ๐. After that, Section 3 explains the design decisions, which is informative, so it's the fun behind-the-scenes part ๐ฌ. Security considerations are in Section 4, and IANA considerations are in the closing Section 5 ๐ก๏ธ.
2. Procedure for Near-Simultaneous-Open ๐ค
This section is normative and specifies the simultaneous-open technique for DCCP ๐. It updates the connection-establishment procedures of [RFC4340] ๐ซ.
2.1. Conventions and Terminology ๐
This document uses the terms and definitions from [RFC4340], so you should already be familiar with that spec ๐ค. In particular, it uses the following convention from Section 3.2 of [RFC4340]:
Each DCCP connection runs between two hosts, which we often name
DCCP A and DCCP B. Each connection is actively initiated by one
of the hosts, which we call the client; the other, initially
passive host is called the server.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119] ๐.
2.2. Protocol Method ๐
The word "session" means what it's defined as in ([RFC2663], Section 2.3). DCCP sessions are uniquely identified by the 4-tuple of <source IP-address, source port, target IP-address, target port> ๐ชช.
DCCP also introduces Service Codes, which can identify different services available through the same port [RFC5595] ๐.
2.2.1. DCCP-Listen Packet Format โจ
okay so this section adds a brand new DCCP packet type called DCCP-Listen ๐ฆ here's how it's laid out:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Dest Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data Offset | CCVal | CsCov | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Res | Type |X| Reserved | Sequence Number High Bits |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number Low Bits |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Service Code |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 1: Format of a DCCP-Listen Packet
- Source Port ๐ธ is the port the DCCP server is watching, waiting for a connection from whatever IP address shows up as the destination IP address in the packet.
- Destination Port ๐ is the port a DCCP client picked to identify the connection. In this technique, that value needs to be sent to the server out-of-band.
- X ๐ has to be set to 1. A DCCP-Listen packet goes out before a connection exists, so there's no way to negotiate short sequence numbers ([RFC4340], Section 5.1). The value of X MUST be set to 1. A DCCP-Listen packet is sent before a connection is established; therefore, there is no way to negotiate use of short sequence numbers ([RFC4340], Section 5.1).
- Sequence Number ๐ is not related to the DCCP sequence number used in normal DCCP messages (see Section 3 for a description of the use of the DCCP sequence number). So for DCCP-Listen packets:
- A DCCP server SHOULD set the high and low bits of the Sequence Number field to 0.
- A DCCP client MUST ignore the value of the Sequence Number field.
- Middleboxes MUST NOT interpret sequence numbers in DCCP-Listen packets.
- Service Code ๐ง is the Service Code value the server is listening for a connection on (Section 8.1.2 of [RFC4340] and [RFC5595]). This value MUST correspond to a Service Code that the server is actually offering for a connection identified by the same source IP address and the same source port as that of the DCCP-Listen packet. Since the server may use multiple Service Codes, the specific value of the Service Code field needs to be communicated out-of-band, from client to server, prior to sending the DCCP-Listen packet, e.g., described using the Session Description Protocol (SDP) [RFC4566].
- Header options ๐ at the time of writing, there are no known uses of header options ([RFC4340], Section 5.8) with a DCCP-Listen packet. Clients MUST ignore all options in received DCCP-Listen packets. Therefore, feature values cannot be negotiated using a DCCP-Listen packet.
- Payload data ๐ซถ at the time of writing, there are no known uses of payload data with a DCCP-Listen packet. Since DCCP-Listen packets are issued before an actual connection is established, endpoints MUST ignore any payload data encountered in DCCP-Listen packets.
- Required values ๐ the following protocol fields are required to have specific values:
- Data Offset MUST have a value of five or more (i.e., at least 20 bytes).
- CCVal MUST be zero (a connection has not been established).
- CsCov MUST be zero (use of the CsCov feature cannot be negotiated).
- Type has the value 10, assigned by IANA to denote a DCCP-Listen packet.
- X MUST be 1 (the generic header must be used).
The remaining fields, including the "Res" and "Reserved" fields, are specified by [RFC4340] and its successors. This document doesn't change how these fields are interpreted. ๐
2.2.2. Protocol Method for DCCP Server Endpoints ๐
this document updates Section 8.1 of [RFC4340] for the case of a fully specified DCCP server endpoint. The update changes the way the server does a passive-open. ๐ฅ
before connection setup, it's common for a DCCP server endpoint to not be fully specified ๐ before the connection is established, a server usually only specifies the destination port and Service Code. (Sometimes the destination address is also specified.) That leaves the source address and source port unspecified. The endpoint only becomes fully specified after doing the handshake for an incoming connection. For those cases, this document does not update Section 8.4 of [RFC4340], so the server sticks with the existing state transitions in the left half of Figure 2 (CLOSED => LISTEN => RESPOND).
a fully specified DCCP server endpoint permits exactly one client, identified by source IP-address:port, destination IP-address:port, plus a single Service Code, to set up the connection. Such a server SHOULD perform the actions and state transitions shown in the right half of Figure 2 and specified below.
unspecified remote +--------+ fully specified remote
+---------------------| CLOSED |---------------------+
| +--------+ send DCCP-Listen |
| |
v v
+--------+ timeout +---------+
| LISTEN | +---+-----------| INVITED |
+--------+ | | +---------+
| | | 1st / 2nd ^ |
| more than 2 | | retransm. | | receive
| retransmissions | +-------------+ | Request
| | resend Listen v
| | +---------+
| +-------------->| LISTEN1 |
| +---------+
| |
| receive Request +---------+ receive Request* |
+------------------->| RESPOND |<--------------------+
send Response +---------+ send Response
* Note: The case of a server that responds to a DCCP-Request in
the INVITED state, transitions to the LISTEN1 state, and then
immediately transitions to the RESPOND state does not require
reception of an additional DCCP-Request packet.
Figure 2: Updated State Transition Diagram for DCCP-Listen
this diagram adds two new DCCP server states on top of the ones listed in Section 4.3 of [RFC4340]:
- INVITED ๐ฆ is tied to one specific DCCP connection and represents a fully specified server socket in the listening state that's generating DCCP-Listen packets toward the client.
- LISTEN1 ๐ธ is tied to one specific DCCP connection and represents a fully specified server socket in the passive listening state that won't generate any more DCCP-Listen packets toward the client.
a fully specified server endpoint does a passive-open from the CLOSED state by inviting the remote client to connect. It does this by sending a single DCCP-Listen packet to the specified remote IP-address:port, using the format from Section 2.2.1. The figure below provides pseudocode describing the packet processing in the INVITED state. This processing step follows Step 2 in Section 8.5 of [RFC4340]).
the INVITED state is like LISTEN, a passive state, characterised by waiting while there's no established connection. If the server endpoint in the INVITED state receives a DCCP-Request that matches the set of bound ports and addresses, it moves to the LISTEN1 state and then immediately moves to the RESPOND state, where further processing picks up as specified in [RFC4340].
the server SHOULD keep sending a DCCP-Listen packet while in the INVITED state, at a 200-millisecond interval with up to at most 2 repetitions (Section 3 discusses this choice of time interval). If the server is still in the INVITED state after a further 200ms following transmission of the third DCCP-Listen packet, it SHOULD progress to the LISTEN1 state.
fully specified server endpoints SHOULD treat ICMP error messages received in response to a DCCP-Listen packet as "soft errors" that don't cause a state transition. Getting an ICMP error message because of a DCCP-Listen packet doesn't necessarily mean the following connection request failed, so it should not result in a server state change. This reaction to soft errors takes advantage of the great thing about the Internet: for many network failures, the network can be dynamically rebuilt without disrupting the endpoints. ๐
server endpoints SHOULD ignore any incoming DCCP-Listen packets. A DCCP server in the LISTEN, INVITED, or LISTEN1 states MAY generate a DCCP-Reset packet (Code 7, "Connection Refused") in response to a received DCCP-Listen packet. That DCCP-Reset packet is a signal that two servers are waiting for connections on the same port at the same time. ๐ญ
further details on the design rationale are in Section 3. โจ
The figure below provides pseudocode describing the packet processing in the INVITED state. This processing step follows Step 2 in Section 8.5 of RFC 4340 [RFC4340].
Step 2a: Process INVITED state
If S.state == INVITED,
/* State only entered for fully specified server endpoints */
/* on entry S will have been set to a socket */
If P.type == Request
/* Exit INVITED state and continue to process the packet */
S.state = LISTEN1
Continue with S.state := LISTEN1
Otherwise,
If P.type == Listen
/* The following line is optional */
Generate Reset(Connection Refused)
/* Otherwise, drop packet and return */
Otherwise,
Generate Reset(No Connection) unless P.type == Reset
Step 2b: Process LISTEN1 state
If S.state == LISTEN1,
/* State only entered for fully specified server endpoints */
/* Follows receipt of a Response packet */
/* or sending third Listen packet (after timer expiry) */
If P.type == Request,
S.state = RESPOND
Choose S.ISS (initial seqno) or set from Init Cookies
Initialize S.GAR := S.ISS
Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
Continue with S.state == RESPOND
/* A Response packet will be generated in Step 11 */
Otherwise,
If P.type == Listen
/* The following line is optional */
Generate Reset(Connection Refused)
/* Otherwise, drop packet and return */
Otherwise,
Generate Reset(No Connection) unless P.type == Reset
Figure 3: Updated DCCP Pseudocode for INVITED and LISTEN1 States
2.2.3. Protocol Method for DCCP Client Endpoints ๐
okay so this one is a rule for clients ๐ซถ This document updates Section 8.1.1 of [RFC4340] by adding the following rule for the reception of DCCP-Listen packets by clients:
Endpoints are required to ignore any header options or payload data they find in DCCP-Listen packets (Section 2.2.1), so DCCP-Listen packets literally don't give a client any meaningful communication ๐. A client in any state MUST silently discard any received DCCP-Listen packet, unless it implements the optional procedure defined in the following section. ๐
2.2.3.1. Optional Generation of Triggered Requests
this section is about an optional optimisation for the client ๐ฆ It lets the client skip waiting for a timeout after a dropped DCCP-Request. The operation requires clients to respond to reception of DCCP-Listen packets when received in the REQUEST state. DCCP-Listen packets MUST be silently discarded in all other states.
A client implementing this optimisation MAY immediately perform a retransmission of a DCCP-Request following the reception of the first DCCP-Listen packet. The retransmission is performed in the same manner as a timeout in the REQUEST state [RFC4340]. A triggered retransmission SHOULD result in the client increasing the exponential-backoff timer interval. โจ
Note that a path delay greater than 200ms will result in multiple DCCP-Listen packets arriving at the client before a DCCP-Response is received. Clients MUST therefore perform only one such retransmission for each DCCP connection. This requires maintaining local state (e.g., one flag per connection). ๐ฅ
Implementors and users of this optional method need to be aware that host timing or path reordering can result in a server receiving two DCCP-Requests (i.e., the server sending one unnecessary packet). This would, in turn, trigger a client to send a second corresponding DCCP-Response (also unnecessary). These additional packets are not expected to modify or delay the DCCP open procedure [RFC4340]. ๐
Section 2.3.2 provides examples of the use of triggered retransmission. ๐ธ
2.2.4. Processing by Routers and Middleboxes ๐ง
DCCP-Listen packets do not require special treatment and should thus be forwarded end-to-end across Internet paths, by routers and middleboxes alike. ๐
Middleboxes may utilise the connection information (address, port, Service Code) to establish local forwarding state. The DCCP-Listen packet carries the necessary information to uniquely identify a DCCP session in combination with the source and destination addresses (found in the enclosing IP header), including the DCCP Service Code value [RFC5595]. The processing of the DCCP-Listen packet by NAT devices is specified in [RFC5597]. ๐
2.3. Examples of Use ๐
In the examples below, DCCP A is the client and DCCP B is the server. A middlebox device (NAT/Firewall), NA, is placed before DCCP A, and another middlebox, NB, is placed before DCCP B. Both NA and NB use a policy that permits DCCP packets to traverse the device for outgoing links, but only permits incoming DCCP packets when a previous packet has been sent out for the same connection. ๐ฆ
In the figure below, DCCP A and DCCP B decide to communicate using an out-of-band mechanism (in this case, labelled SDP), whereupon the client and server are started. DCCP B actively indicates its listening state by sending a DCCP-Listen message. This fulfills the requirement of punching a hole in NB (also creating the binding to the external address and port). This message is dropped by NA since no hole exists there yet. DCCP A initiates a connection by entering the REQUEST state and sending a DCCP-Request. (It is assumed that if NA were a NAT device, then this would also result in a binding that maps the pinhole to the external address and port.) The DCCP-Request is received by DCCP B, via the binding at NB. DCCP B transmits the DCCP-Response and connects through the bindings now in place at NA and NB. โจ
DCCP A DCCP B
------ NA NB ------
+-----------------+ +-+ +-+ +-----------------+
| | | | | | | | State = CLOSED
| SDP --> |--+-+----+-+->| | State = INVITED
| | | |X---+-+--|<-- DCCP-Listen |
|(State=REQUEST) | | | | | | |
|DCCP-Request --> |--+-+----+-+->| |
|(State=PARTOPEN) | <+-+----+-+--|<-- DCCP-Response| State = RESPOND
|DCCP-Ack --> |--+-+----+-+> | |
| | | | | | | |
| | | | | | | |
|DCCP-Data --> |--+-+----+-+->| | State = OPEN
+-----------------+ +-+ +-+ +-----------------+
Figure 4: Event Sequence When the Server Is Started Before the Client ๐ธ
2.3.1. Repetition of DCCP-Listen ๐
this part looks at what happens when the DCCP-Request never shows up ๐ญ
The figure below shows the sequence of packets where the DCCP server enters the INVITED state after reception of out-of-band signaling (e.g., SDP). The key timer operations at the client and server are respectively shown on the left and right of the diagram. It considers the case when the server does not receive a DCCP-Request within the first 600ms (often the request would be received within this interval).
The repetition of DCCP-Listen packets may be implemented using a timer. The timer is restarted with an interval of 200ms when sending each DCCP-Listen packet. It is cancelled when the server leaves the INVITED state. If the timer expires after the first and second transmission, it triggers a transmission of another DCCP-Listen packet. If it expires after sending the third DCCP-Listen packet, the server leaves the INVITED state to enter the LISTEN1 state (where it passively waits for a DCCP-Request). ๐
DCCP A DCCP B
------ NA NB ------
+----+ +-+ +-+ +-----------------+
| | | | | | | | State = CLOSED
| -->|--+-+----+-+--|--> SDP |
| | | | | | | | State = INVITED
| | | | | | | |
| | | |X---+-+--|<-- DCCP-Listen | Timer Starts
| | | | | | | | |
DCCP-Request | -->|--->+--X | | | (dropped) | |
Timer Starts | | | | | | | | |
| | | | | | | | | 1st Timer Expiry
| | |<-+-+----+++--|<-- DCCP-Listen |
| | | | | | | | | Timer Starts
| | | | | | | | | |
| | | | | | | | | 2nd Timer Expiry
| | | | | | | | |
| | |<-+-+----+-+--|<-- DCCP-Listen | Timer Starts
| | | | | | | | | |
| | | | | | | | | 3rd Timer Expiry
| | | | | | | | |
| | | | | | | | | State = LISTEN1
| ~ ~ ~ ~ ~ ~ ~ ~
| | | | | | | | |
Timer Expiry | -->|--+-+----+-+--|--> DCCP-Request |
| | | | | | | | State = RESPOND
| <--|--+-+----+-+--|<-- DCCP-Response|
+----+ +-+ +-+ +-----------------+
Figure 5: Repetition of the DCCP-Listen Packet
2.3.2. Optional Triggered Retransmission of DCCP-Request ๐ฆ
The following figure illustrates a triggered retransmission. In this figure, the first DCCP-Listen is assumed to be lost in the network (e.g., does not open a pinhole at NB). A later DCCP-Request is also not received (perhaps as a side effect of the first loss). After 200ms, the DCCP-Listen packet is retransmitted and correctly received. This triggers the retransmission of the DCCP-Request, which, when received, results in a corresponding DCCP-Response.
DCCP A DCCP B
------ NA NB ------
+-----------------+ +-+ +-+ +-----------------+
| | | | | | | | State = CLOSED
|SDP |--+-+----+-+->| | State = INVITED
|(State= REQUEST) | | | | | | |
| | | | | |X-|<-- DCCP-Listen |
|DCCP-Request --> |--+-+---X| | | |
| | <+-+----+-+--|<-- DCCP-Listen |(retransmit)
| | | | | | | |
|DCCP-Request --> |--+-+----+-+->| | State = RESPOND
| (Triggered) | | | | | | |
| |<-+-+----+-+--|<-- DCCP-Response|
|(State= PARTOPEN)| | | | | | |
|DCCP-Ack --> |--+-+----+-+->| | State = OPEN
+-----------------+ +-+ +-+ +-----------------+
Figure 6: Example Showing a Triggered DCCP-Request
The figure below illustrates the sequence of packets exchanged when a DCCP-Listen and DCCP-Request are processed out of order. Reception of the DCCP-Listen packet by the client triggers retransmission of the DCCP-Request. The server responds to the first DCCP-Request and enters the RESPOND state. The server subsequently responds to the second DCCP-Request with another DCCP-Response, which is ignored by the client (already in the PARTOPEN state). ๐
DCCP A DCCP B
------ NA NB ------
+-----------------+ +-+ +-+ +-----------------+
| | | | | | | | State = CLOSED
|SDP |--+-+----+-+->| | State = INVITED
|(State = REQUEST)| | | | | | |
|DCCP-Request --> |--+-+- -+-+--|<-- DCCP-Listen |
| | | | \/ | | | |
| | | | /\ | | | |
| |<-+-+- -+-+->| |
|DCCP-Request --> |--+-+- -+-+--|<-- DCCP-Response| State = RESPOND
| (Triggered) | | | \/ | | | |
| | | | /\ | | | |
| |<-+-+- -+-+->| |
|(State= PARTOPEN)| | | | | | |
|DCCP-Ack --> |--+-+- -+-+--|<-- DCCP-Response|
| (Triggered) | | | \/ | | | |
| | | | /\ | | | |
| (Ignored) |<-+-+- -+-+->| | State = OPEN
| | | | | | | |
+-----------------+ +-+ +-+ +-----------------+
Figure 7: Example Showing an Unnecessary Triggered DCCP-Request
The RFC text in your message is partway through the document, so this part picks up at Section 2.4, with the sections that follow it.
2.4. Backwards Compatibility with RFC 4340 ๐
No changes are required if a DCCP client conforming to this document communicates with a DCCP server conforming to [RFC4340]. Bestie, that's the dream: old and new can still talk to each other โจ
If a client implements only [RFC4340], an incoming DCCP-Listen packet would be ignored due to step 1 in Section 8.1 of [RFC4340], which at the same time also conforms to the behaviour specified by this document. So the old client just ignores the new packet and everyone is still on the same page ๐ซถ
This document further does not modify communication for any DCCP server that implements a passive-open without fully binding the addresses, ports, and Service Codes to be used. The authors therefore do not expect practical deployment problems with existing, conformant DCCP implementations. No drama, no deployment chaos ๐ธ
3. Discussion of Design Decisions ๐
This is an informative section that reviews the rationale for the design of this method. Think of it as the "why did they do it this way" tea โ
3.1. Rationale for a New Packet Type ๐ฆ
The DCCP-Listen packet specified in Section 2.2.1 has the same format as the DCCP-Request packet ([RFC4340], Section 5.1), the only difference is in the value of the Type field. The usage, however, differs. The DCCP-Listen packet serves as an advisory message, not as part of the actual connection setup: sequence numbers have no meaning, and no payload can be communicated. So it looks like a DCCP-Request, but it's really just a little heads-up ๐
A DCCP-Request packet could, in theory, also have been used for the same purpose. The following arguments were against this:
The first problem was that of semantic overloading: the DCCP-Request defined in [RFC4340] serves a well-defined purpose, being the initial packet of the 3-way handshake. Additional use in the manner of a DCCP-Listen packet would have required DCCP processors to have two different processing paths: one where a DCCP-Request was interpreted as part of the initial handshake, and another where the same packet was interpreted as an indication of an intention to accept a new connection. This would complicate packet processing in hosts and, in particular, stateful middleboxes (which may have restricted computational resources). Two jobs for one packet is just messy ๐ญ
The second problem is that a client receiving a DCCP-Request from a server could generate a DCCP-Reset packet if it had not yet entered the REQUEST state (step 7 in Section 8.5 of [RFC4340]). The method specified in this document lets client endpoints ignore DCCP-Listen packets. Adding a similar rule for the DCCP-Request packet would have been cumbersome: clients would not have been able to distinguish between a DCCP-Request packet meant to indicate an intention to accept a new connection and a genuinely erratic connection initiation. Nobody wants to guess which one they got ๐
The third problem is similar and refers to a client receiving the indication after having itself sent a (connection-initiation) DCCP-Request. Step 7 in Section 8.5 of [RFC4340] requires the client to reply to a DCCP-Request from the server with a DCCP-Sync packet. Since sequence numbers are ignored for this type of message, additional and complex processing would become necessary: either to ask the client not to respond to a DCCP-Request when the request is used as an indication, or to ask middleboxes and servers to ignore DCCP-Sync packets generated in response to DCCP-Request packets that are used as indications. Furthermore, since no initial sequence numbers have been negotiated at this stage, sending a DCCP-SyncAck would not be meaningful. Way too many extra rules, no thank you ๐ โโ๏ธ
The use of a separate packet type therefore allows simpler and clearer processing. Separate packet, separate job, zero confusion โจ
3.1.1. Use of Sequence Numbers ๐ง
Although the DCCP-Listen Sequence Number fields are ignored, they have been retained in the DCCP-Listen packet header to reuse the generic header format from Section 5.1 of [RFC4340]. Reusing the header format is the smart move, no need to reinvent the wheel ๐
DCCP assigns a random initial value to the sequence number when a DCCP connection is established [RFC4340]. However, a sender is required to set this value to zero for a DCCP-Listen packet. Both clients and middleboxes are also required to ignore this value. So zero it out and everyone ignores it, simple as that ๐
The rationale for ignoring the Sequence Number fields of DCCP-Listen packets is that, at the time the DCCP-Listen is exchanged, the endpoints have not yet entered connection setup: the DCCP-Listen packet is sent while the server is still in the passive-open (INVITED) state, i.e., it has not yet allocated state, other than binding to the client's IP-address:port and Service Code. The server hasn't really started the connection yet, so there's no real sequence number to talk about ๐
3.2. Generation of Listen Packets ๐ธ
A DCCP server should by default permit generation of DCCP-Listen packets. Since DCCP-Listen packets solve a particular problem with NAT and/or firewall traversal, the generation of DCCP-Listen packets on passive sockets is tied to a condition (binding to a remote address and Service Code that are both known a priori) to ensure this does not interfere with the general case of "normal" DCCP connections (where client addresses are generally not known in advance). Basically, it only kicks in when the address and Service Code are already known, so regular connections aren't disrupted ๐
In the TCP world, the analogue is a transition from LISTEN to SYN_SENT by virtue of sending data: "A fully specified passive call can be made active by the subsequent execution of a SEND" ([RFC0793], Section 3.8). Unlike TCP, this update does not perform a role change from passive to active. Like TCP, DCCP-Listen packets are only sent by a DCCP-server when the endpoint is fully specified (Section 2.2). TCP has a similar vibe here, but DCCP doesn't flip roles ๐ฆ
3.3. Repetition of DCCP-Listen Packets ๐
Repetition is a necessary requirement to increase robustness and the chance of successful connection establishment when a DCCP-Listen packet is lost due to congestion, link loss, or some other reason. Packets get lost, so sending it more than once is the whole point ๐ญ
The decision to recommend a maximum number of 3 timeouts (2 repeated copies of the original DCCP-Listen packet) results from the following consideration: the repeated copies need to be spaced sufficiently far apart in time to avoid suffering from correlated loss. The interval of 200ms was chosen to accommodate a wide range of wireless and wired network paths. Spacing matters so that one bad moment doesn't wipe out all the copies at once ๐ง
Another constraint is given by the retransmission interval for the DCCP-Request ([RFC4340], Section 8.1.1). To establish state, intermediate systems need to receive a (retransmitted) DCCP-Listen packet before the DCCP-Request times out (1 second). With three timeouts, each spaced 200 milliseconds apart, the overall time is still below one second. The sum of 600 milliseconds is sufficiently large to provide for longer one-way delays, as is the case, e.g., on some wireless links. The timing has to fit inside the DCCP-Request timeout, and 600ms does exactly that โฐ
The rationale behind transitioning to the LISTEN1 state after two repetitions is that other problems, independent of establishing middlebox state, may occur (such as delay or loss of the initial DCCP-Request). Any late or retransmitted DCCP-Request packets will then still reach the server, allowing connection establishment to successfully complete. So even if the first request gets lost, the server still catches the connection later ๐ซถ
4. Security Considerations ๐
General security considerations for DCCP are described in [RFC4340]. Security considerations for Service Codes are further described in [RFC5595].
The method specified in this document generates a DCCP-Listen packet addressed to a specific DCCP client. This exposes the state of a DCCP server that is in a passive listening state (i.e., waiting to accept a connection from a known client). Heads up, this one's a little spicy ๐
The exposed information is not encrypted and therefore could be seen on the network path to the DCCP client. An attacker on this return path could observe a DCCP-Listen packet and then exploit this by spoofing a packet (e.g., DCCP-Request or DCCP-Reset) with the IP addresses, DCCP ports, and Service Code that correspond to the values to be used for the connection. As in other on-path attacks, this could be used to inject data into a connection or to deny a connection request. A similar on-path attack is also possible for any DCCP connection, once the session is initiated by the client ([RFC4340], Section 18). Okay, this is the serious bit, so pay attention ๐จ
The DCCP-Listen packet is only sent in response to explicit, prior out-of-band signaling from a DCCP client to the DCCP server (e.g., SDP [RFC4566] information communicated via the Session Initiation Protocol [RFC3261]) and will normally directly precede a DCCP-Request sent by the client (which carries the same information). So it only shows up after the client has already told the server what's up over a separate channel ๐
This update does not significantly increase the complexity or vulnerability of a DCCP implementation that conforms to [RFC4340]. A DCCP server SHOULD therefore, by default, permit generation of DCCP-Listen packets. A server that wishes to prevent disclosing this information MAY refrain from generating DCCP-Listen packets without impacting subsequent DCCP state transitions, but possibly inhibiting middlebox traversal. So servers can opt out if they really want to keep it private, but it might make getting through middleboxes harder ๐ค
The DCCP base specification in RFC 4340 defines an Init Cookie option, which lets a DCCP server avoid having to hold any state until the three-way, connection-setup handshake has completed. This specification enables an out-of-band mechanism that forces the server to hold state for a connection that has not yet been established. This is a change in the security profile of DCCP, although the impact is expected to be minimal and depends on the security features of the out-of-band mechanism (SIP SDP is one such mechanism that provides sufficient security features). It's a real shift in how DCCP handles state, so the out-of-band channel's security really matters here ๐ฅบ
The method creates a new way for a client to set up a DCCP connection to a server using out-of-band data, transported over a signaling connection. If the signaling connection is not encrypted, an eavesdropper could see the client IP address and the port for the to-be-established DCCP connection, and generate a DCCP-Listen packet towards the client using its own server IP address and port. However, a client will only respond to a received DCCP-Listen packet if the server IP address and port match an existing DCCP connection that is in the REQUEST state (Section 2.3.2). The method therefore cannot be used to redirect the connection to a different server IP address. So an eavesdropper can't hijack the connection to a different server, which is a relief ๐ฆ
5. IANA Considerations ๐
The IANA registered a new packet type, "DCCP-Listen", in the IANA DCCP Packet Types Registry. The decimal value 10 has been assigned to this type. This registry entry references this document. The new packet type officially has its own spot in the registry now ๐
6. Acknowledgements ๐
This update was originally co-authored by Dr. Gerrit Renker, University of Aberdeen, and the present author acknowledges his insight in design of the protocol mechanism and in careful review of the early revisions of the document text. Dan Wing assisted on issues relating to the use of NAT and NAPT. Huge shoutout to them for the help ๐
7. References ๐
7.1. Normative References
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.
[RFC4340] Kohler, E., Handley, M., and S. Floyd, "Datagram
Congestion Control Protocol (DCCP)", RFC 4340, March 2006.
[RFC5595] Fairhurst, G., "The DCCP Service Code", RFC 5595,
September 2009.
7.2. Informative References
bestie, the informative refs are giving "more reading for the curious" ๐๐ค Every single one is listed below, all details intact ๐ซถ
[Epp05] Eppinger, J-L., "TCP Connections for P2P Apps: A Software
Approach to Solving the NAT Problem", Carnegie Mellon
University/ISRI Technical Report CMU-ISRI-05-104,
January 2005.
[FSK05] Ford, B., Srisuresh, P., and D. Kegel, "Peer-to-Peer
Communication Across Network Address Translators",
Proceedings of USENIX-05, pages 179-192, 2005.
[GF05] Guha, S. and P. Francis, "Characterization and Measurement
of TCP Traversal through NATs and Firewalls", Proceedings
of Internet Measurement Conference (IMC-05), pages 199-
211, 2005.
[GTF04] Guha, S., Takeda, Y., and P. Francis, "NUTSS: A SIP based
approach to UDP and TCP connectivity", Proceedings of
SIGCOMM-04 Workshops, Portland, OR, pages 43-48, 2004.
[H.323] ITU-T, "Packet-based Multimedia Communications Systems",
Recommendation H.323, July 2003.
[ICE] Rosenberg, J., "TCP Candidates with Interactive
Connectivity Establishment (ICE)", Work in Progress,
July 2008.
[NAT-APP] Ford, B., "Application Design Guidelines for Traversal
through Network Address Translators", Work in Progress,
March 2007.
[RFC0793] Postel, J., "Transmission Control Protocol", STD 7,
RFC 793, September 1981.
[RFC2663] Srisuresh, P. and M. Holdrege, "IP Network Address
Translator (NAT) Terminology and Considerations",
RFC 2663, August 1999.
[RFC3022] Srisuresh, P. and K. Egevang, "Traditional IP Network
Address Translator (Traditional NAT)", RFC 3022,
January 2001.
[RFC3235] Senie, D., "Network Address Translator (NAT)-Friendly
Application Design Guidelines", RFC 3235, January 2002.
[RFC3261] Rosenberg, J., Schulzrinne, H., Camarillo, G., Johnston,
A., Peterson, J., Sparks, R., Handley, M., and E.
Schooler, "SIP: Session Initiation Protocol", RFC 3261,
June 2002.
[RFC4566] Handley, M., Jacobson, V., and C. Perkins, "SDP: Session
Description Protocol", RFC 4566, July 2006.
[RFC4787] Audet, F. and C. Jennings, "Network Address Translation
(NAT) Behavioral Requirements for Unicast UDP", BCP 127,
RFC 4787, January 2007.
[RFC5382] Guha, S., Biswas, K., Ford, B., Sivakumar, S., and P.
Srisuresh, "NAT Behavioral Requirements for TCP", BCP 142,
RFC 5382, October 2008.
[RFC5597] Denis-Courmont, R., "Network Address Translation (NAT)
Behavioral Requirements for the Datagram Congestion
Control Protocol", BCP 150, RFC 5597, September 2009.
[STUN] Rosenberg, J., Mahy, R., and P. Matthews, "Traversal Using
Relays around NAT (TURN): Relay Extensions to Session
Traversal Utilities for NAT (STUN)", Work in Progress,
June 2009.
Appendix A. Discussion of Existing NAT Traversal Techniques โจ
okay so this appendix is a quick tour of how existing techniques get connections through NAT boxes ๐ฆ It starts with TCP NAT traversal using simultaneous-open, then moves on to role reversal ๐ For more deep dives, check [GTF04] and [GF05] ๐
The big shared idea is making peer-to-peer sessions look like "outbound" sessions on each NAT device ๐ Usually a rendezvous server sitting in the public address realm helps clients figure out their NAT topology and where their peers live ๐ง
The term 'hole punching' was coined in [FSK05] ๐ณ๏ธ It means creating soft state in a traditional NAT device by starting an outbound connection ๐ฅ A well-behaved NAT can then use that to let a reverse connection come back to the host in the private address realm ๐
UDP and TCP hole punching are basically the same technique [RFC4787] ๐ซถ Adapting the basic UDP hole punching idea to TCP NAT traversal [RFC5382] was introduced in Section 4 of [FSK05] and depends on TCP's simultaneous-open feature [RFC0793] โจ One difference is how clients run connectivity checks once they have suitable address pairs. UDP is fine with a single socket, but TCP clients need several sockets for the same address and port tuple:
- a passive socket to listen for connectivity tests from peers, and
- multiple active connections from the same address to test reachability of other peers.
When client A sends a SYN to its peer B, that creates soft state in A's NAT. At the same time, B tries to connect to A ๐
- if the SYN from B left B's NAT before A's SYN arrived, both endpoints do a simultaneous-open (4-way handshake of SYN/SYNACK) ๐
- otherwise, A's SYN may not get into B's NAT, so B does a normal open (SYN_SENT => ESTABLISHED) and A does a simultaneous-open (SYN_SENT => SYN_RCVD => ESTABLISHED) ๐
In that second case, the NAT must not interfere with a RST segment (REQ-4 in [RFC5382]) ๐ญ Simultaneous-open is simple, which is why it's the preferred mode in the TCP extension for Interactive Connectivity Establishment (ICE) ([ICE], Section 2) ๐
A.1. NAT Traversal Based on a Simultaneous-Request โจ
Out of all the TCP NAT traversal approaches, TCP simultaneous-open looks like the obvious candidate for DCCP because it's so simple ([GF05], [NAT-APP]) ๐ฆ
The catch: TCP simultaneous-open erases the line between client and server, since both sides go through active (SYN_SENT) and passive (SYN_RCVD) states ๐ That clashes with DCCP's design choice to keep client and server functions clearly separate ([RFC4340], Section 4.6) ๐
Several DCCP mechanisms quietly rely on clear client/server roles ๐
- Feature Negotiation: with a few exceptions, nearly all of DCCP's negotiable features use the "server-priority" reconciliation rule ([RFC4340], Section 6.3.1). Each peer shares its preference lists of feature values, and the server makes the final call ๐
- Closing States: only a server may generate DCCP-CloseReq packets (asking the peer to hold timewait state). A client may only send DCCP-Close or DCCP-Reset packets to end a connection ([RFC4340], Section 8.3) ๐ญ
- Service Codes [RFC5595]: a server can be tied to multiple Service Codes, but a client must be tied to exactly one ([RFC4340], Section 8.1.2) ๐
- Init Cookies: these may only be used by a server, and only on DCCP-Response packets ([RFC4340], Section 8.1.4) ๐ง
The last two points aren't dealbreakers on their own, but they would have made it hard to switch a socket from passive to active ๐ฅบ In DCCP, only a client generates a DCCP-Request. The idea that "all DCCP hosts may be clients" got tossed, since it would mean messy state machine changes and would limit application programming ๐ซ So retrofitting a TCP-style simultaneous-open into DCCP, so that DCCP-Connect packets get exchanged at the same time, was not recommended ๐ โโ๏ธ
A.2. Role Reversal ๐
Another simple TCP NAT traversal scheme is role reversal ([Epp05], [GTF04]). A peer first opens an active connection just to punch a hole in the firewall, then flips back to a listening socket and accepts connections that come in through that new path ๐ฆ
This would have had a few downsides with DCCP ๐ First, a DCCP server would have to change its role to temporarily act as a 'client'. That would need state machine changes, especially around how Service Codes and maybe Init Cookies get handled ๐ฌ Second, the method would need to run after feature negotiation, since an endpoint's choice of initial options can depend on its role. An endpoint that knows it's the server can make assumptions about the preference lists of features it negotiates with the client, which lets it enforce a particular policy ๐ Finally, the server would need extra processing to make sure the connection arriving at the listening socket matches the active connection it opened earlier ๐ง
So this approach was not recommended for DCCP ๐ โจ
Author's Address ๐๏ธ
Godred Fairhurst
University of Aberdeen
School of Engineering
Fraser Noble Building
Aberdeen AB24 3UE
Scotland
EMail: gorry@erg.abdn.ac.uk
URI: http://www.erg.abdn.ac.uk
๐ฆ where this page comes from
- ietf: rfc5596 2009-09
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms