diff --git a/.duvet/.gitignore b/.duvet/.gitignore new file mode 100644 index 0000000000..a9a1bd38ab --- /dev/null +++ b/.duvet/.gitignore @@ -0,0 +1 @@ +reports/ diff --git a/.duvet/config.toml b/.duvet/config.toml new file mode 100644 index 0000000000..448aaf486f --- /dev/null +++ b/.duvet/config.toml @@ -0,0 +1,34 @@ +'$schema' = "https://awslabs.github.io/duvet/config/v0.4.0.json" + +# Citations live next to the code they annotate, so every crate's `src` tree is a source. +# Both patterns are needed: `**` does not match zero path components here, so the first +# finds `/src//.rs` and the second finds `/src/lib.rs`. Getting +# this wrong is silent in the dangerous direction -- an unmatched file simply contributes +# no citations, the snapshot does not change, and `duvet-check` passes. +[[source]] +pattern = "*/src/**/*.rs" + +[[source]] +pattern = "*/src/*.rs" + +# Every RFC tracked here restates its numbered requirements in a summary section (RFC 4787 +# section 12, RFC 5382 section 8, RFC 5508 section 9). duvet keys citations by section +# anchor and cannot be told that two sections carry the same requirement, so each of those +# copies reads as uncovered no matter what is annotated. The convention, settled in the +# RFC 5508 chapter, is to cite the *normative* section -- where the requirement is argued +# rather than tabulated -- and to read the summary sections as permanently uncited. + +[[specification]] +source = "https://www.rfc-editor.org/rfc/rfc4884" + +[[specification]] +source = "https://www.rfc-editor.org/rfc/rfc5382" + +[report.html] +enabled = true + +[report.snapshot] +enabled = true + +[[specification]] +source = "https://www.rfc-editor.org/rfc/rfc4787" diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-10.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-10.toml new file mode 100644 index 0000000000..d1175894d7 --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-10.toml @@ -0,0 +1,44 @@ +target = "https://www.rfc-editor.org/rfc/rfc4787#section-10" + +# Fragmentation of Outgoing Packets +# +# When the MTU of the adjacent link is too small, fragmentation of +# packets going from the internal side to the external side of the NAT +# may occur. This can occur if the NAT is doing Point-to-Point over +# Ethernet (PPPoE), or if the NAT has been configured with a small MTU +# to reduce serialization delay when sending large packets and small +# higher-priority packets, or for other reasons. +# +# It is worth noting that many IP stacks do not use Path MTU Discovery +# with UDP packets. +# +# The packet could have its Don't Fragment bit set to 1 (DF=1) or 0 +# (DF=0). +# +# REQ-13: If the packet received on an internal IP address has DF=1, +# the NAT MUST send back an ICMP message "Fragmentation needed and +# DF set" to the host, as described in [RFC0792]. +# +# a) If the packet has DF=0, the NAT MUST fragment the packet and +# SHOULD send the fragments in order. +# +# Justification: This is as per RFC 792. +# +# a) This is the same function a router performs in a similar +# situation [RFC1812]. + +[[spec]] +level = "MUST" +quote = ''' +REQ-13: If the packet received on an internal IP address has DF=1, +the NAT MUST send back an ICMP message "Fragmentation needed and +DF set" to the host, as described in [RFC0792]. +''' + +[[spec]] +level = "MUST" +quote = ''' +a) If the packet has DF=0, the NAT MUST fragment the packet and +SHOULD send the fragments in order. +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-11.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-11.toml new file mode 100644 index 0000000000..e8364092d3 --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-11.toml @@ -0,0 +1,51 @@ +target = "https://www.rfc-editor.org/rfc/rfc4787#section-11" + +# Receiving Fragmented Packets +# +# For a variety of reasons, a NAT may receive a fragmented packet. The +# IP packet containing the header could arrive in any fragment, +# depending on network conditions, packet ordering, and the +# implementation of the IP stack that generated the fragments. +# +# A NAT that is capable only of receiving fragments in order (that is, +# with the header in the first packet) and forwarding each of the +# fragments to the internal host is described as "Received Fragments +# Ordered". +# +# A NAT that is capable of receiving fragments in or out of order and +# forwarding the individual fragments (or a reassembled packet) to the +# internal host is referred to as "Receive Fragments Out of Order". +# See the Security Considerations section of this document for a +# discussion of this behavior. +# +# A NAT that is neither of these is referred to as "Receive Fragments +# None". +# +# REQ-14: A NAT MUST support receiving in-order and out-of-order +# fragments, so it MUST have "Received Fragment Out of Order" +# behavior. +# +# a) A NAT's out-of-order fragment processing mechanism MUST be +# designed so that fragmentation-based DoS attacks do not +# compromise the NAT's ability to process in-order and +# unfragmented IP packets. +# +# Justification: See Security Considerations. + +[[spec]] +level = "MUST" +quote = ''' +REQ-14: A NAT MUST support receiving in-order and out-of-order +fragments, so it MUST have "Received Fragment Out of Order" +behavior. +''' + +[[spec]] +level = "MUST" +quote = ''' +a) A NAT's out-of-order fragment processing mechanism MUST be +designed so that fragmentation-based DoS attacks do not +compromise the NAT's ability to process in-order and +unfragmented IP packets. +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-12.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-12.toml new file mode 100644 index 0000000000..98be36cf25 --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-12.toml @@ -0,0 +1,326 @@ +target = "https://www.rfc-editor.org/rfc/rfc4787#section-12" + +# Requirements +# +# The requirements in this section are aimed at minimizing the +# complications caused by NATs to applications, such as realtime +# communications and online gaming. The requirements listed earlier in +# the document are consolidated here into a single section. +# +# It should be understood, however, that applications normally do not +# know in advance if the NAT conforms to the recommendations defined in +# this section. Peer-to-peer media applications still need to use +# normal procedures, such as ICE [ICE]. +# +# A NAT that supports all the mandatory requirements of this +# specification (i.e., the "MUST"), is "compliant with this +# specification". A NAT that supports all the requirements of this +# specification (i.e., including the "RECOMMENDED") is "fully compliant +# with all the mandatory and recommended requirements of this +# specification". +# +# REQ-1: A NAT MUST have an "Endpoint-Independent Mapping" behavior. +# +# REQ-2: It is RECOMMENDED that a NAT have an "IP address pooling" +# behavior of "Paired". Note that this requirement is not +# applicable to NATs that do not support IP address pooling. +# +# REQ-3: A NAT MUST NOT have a "Port assignment" behavior of "Port +# overloading". +# +# a) If the host's source port was in the range 0-1023, it is +# RECOMMENDED the NAT's source port be in the same range. If the +# host's source port was in the range 1024-65535, it is +# RECOMMENDED that the NAT's source port be in that range. +# +# REQ-4: It is RECOMMENDED that a NAT have a "Port parity +# preservation" behavior of "Yes". +# +# REQ-5: A NAT UDP mapping timer MUST NOT expire in less than two +# minutes, unless REQ-5a applies. +# +# a) For specific destination ports in the well-known port range +# (ports 0-1023), a NAT MAY have shorter UDP mapping timers that +# are specific to the IANA-registered application running over +# that specific destination port. +# +# b) The value of the NAT UDP mapping timer MAY be configurable. +# +# c) A default value of five minutes or more for the NAT UDP mapping +# timer is RECOMMENDED. +# +# REQ-6: The NAT mapping Refresh Direction MUST have a "NAT Outbound +# refresh behavior" of "True". +# +# a) The NAT mapping Refresh Direction MAY have a "NAT Inbound +# refresh behavior" of "True". +# +# REQ-7 A NAT device whose external IP interface can be configured +# dynamically MUST either (1) Automatically ensure that its internal +# network uses IP addresses that do not conflict with its external +# network, or (2) Be able to translate and forward traffic between +# all internal nodes and all external nodes whose IP addresses +# numerically conflict with the internal network. +# +# REQ-8: If application transparency is most important, it is +# RECOMMENDED that a NAT have "Endpoint-Independent Filtering" +# behavior. If a more stringent filtering behavior is most +# important, it is RECOMMENDED that a NAT have "Address-Dependent +# Filtering" behavior. +# +# a) The filtering behavior MAY be an option configurable by the +# administrator of the NAT. +# +# REQ-9: A NAT MUST support "Hairpinning". +# +# a) A NAT Hairpinning behavior MUST be "External source IP address +# and port". +# +# REQ-10: To eliminate interference with UNSAF NAT traversal +# mechanisms and allow integrity protection of UDP communications, +# NAT ALGs for UDP-based protocols SHOULD be turned off. Future +# standards track specifications that define an ALG can update this +# to recommend the ALGs on which they define default. +# +# a) If a NAT includes ALGs, it is RECOMMENDED that the NAT allow +# the NAT administrator to enable or disable each ALG separately. +# +# REQ-11: A NAT MUST have deterministic behavior, i.e., it MUST NOT +# change the NAT translation (Section 4) or the Filtering +# (Section 5) Behavior at any point in time, or under any particular +# conditions. +# +# REQ-12: Receipt of any sort of ICMP message MUST NOT terminate the +# NAT mapping. +# +# a) The NAT's default configuration SHOULD NOT filter ICMP messages +# based on their source IP address. +# +# b) It is RECOMMENDED that a NAT support ICMP Destination +# Unreachable messages. +# +# REQ-13 If the packet received on an internal IP address has DF=1, +# the NAT MUST send back an ICMP message "Fragmentation needed and +# DF set" to the host, as described in [RFC0792]. +# +# a) If the packet has DF=0, the NAT MUST fragment the packet and +# SHOULD send the fragments in order. +# +# REQ-14: A NAT MUST support receiving in-order and out-of-order +# fragments, so it MUST have "Received Fragment Out of Order" +# behavior. +# +# a) A NAT's out-of-order fragment processing mechanism MUST be +# designed so that fragmentation-based DoS attacks do not +# compromise the NAT's ability to process in-order and +# unfragmented IP packets. + +[[spec]] +level = "MUST" +quote = ''' +REQ-1: A NAT MUST have an "Endpoint-Independent Mapping" behavior. +''' + +[[spec]] +level = "SHOULD" +quote = ''' +REQ-2: It is RECOMMENDED that a NAT have an "IP address pooling" +behavior of "Paired". +''' + +[[spec]] +level = "MUST" +quote = ''' +REQ-3: A NAT MUST NOT have a "Port assignment" behavior of "Port +overloading". +''' + +[[spec]] +level = "SHOULD" +quote = ''' +a) If the host's source port was in the range 0-1023, it is +RECOMMENDED the NAT's source port be in the same range. +''' + +[[spec]] +level = "SHOULD" +quote = ''' +If the +host's source port was in the range 1024-65535, it is +RECOMMENDED that the NAT's source port be in that range. +''' + +[[spec]] +level = "SHOULD" +quote = ''' +REQ-4: It is RECOMMENDED that a NAT have a "Port parity +preservation" behavior of "Yes". +''' + +[[spec]] +level = "MUST" +quote = ''' +REQ-5: A NAT UDP mapping timer MUST NOT expire in less than two +minutes, unless REQ-5a applies. +''' + +[[spec]] +level = "MAY" +quote = ''' +a) For specific destination ports in the well-known port range +(ports 0-1023), a NAT MAY have shorter UDP mapping timers that +are specific to the IANA-registered application running over +that specific destination port. +''' + +[[spec]] +level = "MAY" +quote = ''' +b) The value of the NAT UDP mapping timer MAY be configurable. +''' + +[[spec]] +level = "SHOULD" +quote = ''' +c) A default value of five minutes or more for the NAT UDP mapping +timer is RECOMMENDED. +''' + +[[spec]] +level = "MUST" +quote = ''' +REQ-6: The NAT mapping Refresh Direction MUST have a "NAT Outbound +refresh behavior" of "True". +''' + +[[spec]] +level = "MAY" +quote = ''' +a) The NAT mapping Refresh Direction MAY have a "NAT Inbound +refresh behavior" of "True". +''' + +[[spec]] +level = "MUST" +quote = ''' +REQ-7 A NAT device whose external IP interface can be configured +dynamically MUST either (1) Automatically ensure that its internal +network uses IP addresses that do not conflict with its external +network, or (2) Be able to translate and forward traffic between +all internal nodes and all external nodes whose IP addresses +numerically conflict with the internal network. +''' + +[[spec]] +level = "SHOULD" +quote = ''' +REQ-8: If application transparency is most important, it is +RECOMMENDED that a NAT have "Endpoint-Independent Filtering" +behavior. +''' + +[[spec]] +level = "SHOULD" +quote = ''' +If a more stringent filtering behavior is most +important, it is RECOMMENDED that a NAT have "Address-Dependent +Filtering" behavior. +''' + +[[spec]] +level = "MAY" +quote = ''' +a) The filtering behavior MAY be an option configurable by the +administrator of the NAT. +''' + +[[spec]] +level = "MUST" +quote = ''' +REQ-9: A NAT MUST support "Hairpinning". +''' + +[[spec]] +level = "MUST" +quote = ''' +a) A NAT Hairpinning behavior MUST be "External source IP address +and port". +''' + +[[spec]] +level = "SHOULD" +quote = ''' +REQ-10: To eliminate interference with UNSAF NAT traversal +mechanisms and allow integrity protection of UDP communications, +NAT ALGs for UDP-based protocols SHOULD be turned off. +''' + +[[spec]] +level = "SHOULD" +quote = ''' +a) If a NAT includes ALGs, it is RECOMMENDED that the NAT allow +the NAT administrator to enable or disable each ALG separately. +''' + +[[spec]] +level = "MUST" +quote = ''' +REQ-11: A NAT MUST have deterministic behavior, i.e., it MUST NOT +change the NAT translation (Section 4) or the Filtering +(Section 5) Behavior at any point in time, or under any particular +conditions. +''' + +[[spec]] +level = "MUST" +quote = ''' +REQ-12: Receipt of any sort of ICMP message MUST NOT terminate the +NAT mapping. +''' + +[[spec]] +level = "SHOULD" +quote = ''' +a) The NAT's default configuration SHOULD NOT filter ICMP messages +based on their source IP address. +''' + +[[spec]] +level = "SHOULD" +quote = ''' +b) It is RECOMMENDED that a NAT support ICMP Destination +Unreachable messages. +''' + +[[spec]] +level = "MUST" +quote = ''' +REQ-13 If the packet received on an internal IP address has DF=1, +the NAT MUST send back an ICMP message "Fragmentation needed and +DF set" to the host, as described in [RFC0792]. +''' + +[[spec]] +level = "MUST" +quote = ''' +a) If the packet has DF=0, the NAT MUST fragment the packet and +SHOULD send the fragments in order. +''' + +[[spec]] +level = "MUST" +quote = ''' +REQ-14: A NAT MUST support receiving in-order and out-of-order +fragments, so it MUST have "Received Fragment Out of Order" +behavior. +''' + +[[spec]] +level = "MUST" +quote = ''' +a) A NAT's out-of-order fragment processing mechanism MUST be +designed so that fragmentation-based DoS attacks do not +compromise the NAT's ability to process in-order and +unfragmented IP packets. +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-4.1.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-4.1.toml new file mode 100644 index 0000000000..9497e22ce8 --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-4.1.toml @@ -0,0 +1,140 @@ +target = "https://www.rfc-editor.org/rfc/rfc4787#section-4.1" + +# Address and Port Mapping +# +# When an internal endpoint opens an outgoing session through a NAT, +# the NAT assigns the session an external IP address and port number so +# that subsequent response packets from the external endpoint can be +# received by the NAT, translated, and forwarded to the internal +# endpoint. This is a mapping between an internal IP address and port +# IP:port and external IP:port tuple. It establishes the translation +# +# that will be performed by the NAT for the duration of the session. +# For many applications, it is important to distinguish the behavior of +# the NAT when there are multiple simultaneous sessions established to +# different external endpoints. +# +# The key behavior to describe is the criteria for reuse of a mapping +# for new sessions to external endpoints, after establishing a first +# mapping between an internal X:x address and port and an external +# Y1:y1 address tuple. Let's assume that the internal IP address and +# port X:x are mapped to X1':x1' for this first session. The endpoint +# then sends from X:x to an external address Y2:y2 and gets a mapping +# of X2':x2' on the NAT. The relationship between X1':x1' and X2':x2' +# for various combinations of the relationship between Y1:y1 and Y2:y2 +# is critical for describing the NAT behavior. This arrangement is +# illustrated in the following diagram: +# +# E +# +------+ +------+ x +# | Y1 | | Y2 | t +# +--+---+ +---+--+ e +# | Y1:y1 Y2:y2 | r +# +----------+ +----------+ n +# | | a +# X1':x1' | | X2':x2' l +# +--+---+-+ +# ...........| NAT |............... +# +--+---+-+ I +# | | n +# X:x | | X:x t +# ++---++ e +# | X | r +# +-----+ n +# a +# l +# +# Address and Port Mapping +# +# The following address and port mapping behavior are defined: +# +# Endpoint-Independent Mapping: +# +# The NAT reuses the port mapping for subsequent packets sent +# from the same internal IP address and port (X:x) to any +# external IP address and port. Specifically, X1':x1' equals +# X2':x2' for all values of Y2:y2. +# +# Address-Dependent Mapping: +# +# The NAT reuses the port mapping for subsequent packets sent +# from the same internal IP address and port (X:x) to the same +# external IP address, regardless of the external port. +# Specifically, X1':x1' equals X2':x2' if and only if, Y2 equals +# Y1. +# +# Address and Port-Dependent Mapping: +# +# The NAT reuses the port mapping for subsequent packets sent +# from the same internal IP address and port (X:x) to the same +# external IP address and port while the mapping is still active. +# Specifically, X1':x1' equals X2':x2' if and only if, Y2:y2 +# equals Y1:y1. +# +# It is important to note that these three possible choices make no +# difference to the security properties of the NAT. The security +# properties are fully determined by which packets the NAT allows in +# and which it does not. This is determined by the filtering behavior +# in the filtering portions of the NAT. +# +# REQ-1: A NAT MUST have an "Endpoint-Independent Mapping" behavior. +# +# Justification: In order for UNSAF methods to work, REQ-1 needs to be +# met. Failure to meet REQ-1 will force the use of a UDP relay, +# which is very often impractical. +# +# Some NATs are capable of assigning IP addresses from a pool of IP +# addresses on the external side of the NAT, as opposed to just a +# single IP address. This is especially common with larger NATs. Some +# NATs use the external IP address mapping in an arbitrary fashion +# (i.e., randomly): one internal IP address could have multiple +# external IP address mappings active at the same time for different +# sessions. These NATs have an "IP address pooling" behavior of +# "Arbitrary". Some large Enterprise NATs use an IP address pooling +# behavior of "Arbitrary" as a means of hiding the IP address assigned +# to specific endpoints by making their assignment less predictable. +# Other NATs use the same external IP address mapping for all sessions +# associated with the same internal IP address. These NATs have an "IP +# address pooling" behavior of "Paired". NATs that use an "IP address +# pooling" behavior of "Arbitrary" can cause issues for applications +# that use multiple ports from the same endpoint, but that do not +# negotiate IP addresses individually (e.g., some applications using +# RTP and RTCP). +# +# REQ-2: It is RECOMMENDED that a NAT have an "IP address pooling" +# behavior of "Paired". Note that this requirement is not +# applicable to NATs that do not support IP address pooling. +# +# Justification: This will allow applications that use multiple ports +# originating from the same internal IP address to also have the +# same external IP address. This is to avoid breaking peer-to-peer +# applications that are not capable of negotiating the IP address +# for RTP and the IP address for RTCP separately. As such it is +# envisioned that this requirement will become less important as +# applications become NAT-friendlier with time. The main reason why +# this requirement is here is that in a peer-to-peer application, +# you are subject to the other peer's mistake. In particular, in +# the context of SIP, if my application supports the extensions +# defined in [RFC3605] for indicating RTP and RTCP addresses and +# ports separately, but the other peer does not, there may still be +# breakage in the form of the stream losing RTCP packets. This +# requirement will avoid the loss of RTP in this context, although +# the loss of RTCP may be inevitable in this particular example. It +# is also worth noting that RFC 3605 is unfortunately not a +# mandatory part of SIP [RFC3261]. Therefore, this requirement will +# address a particularly nasty problem that will prevail for a +# significant period of time. + +[[spec]] +level = "MUST" +quote = ''' +REQ-1: A NAT MUST have an "Endpoint-Independent Mapping" behavior. +''' + +[[spec]] +level = "SHOULD" +quote = ''' +REQ-2: It is RECOMMENDED that a NAT have an "IP address pooling" +behavior of "Paired". +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-4.2.1.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-4.2.1.toml new file mode 100644 index 0000000000..b773183c5a --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-4.2.1.toml @@ -0,0 +1,115 @@ +target = "https://www.rfc-editor.org/rfc/rfc4787#section-4.2.1" + +# Port Assignment Behavior +# +# This section uses the following diagram for reference. +# +# E +# +-------+ +-------+ x +# | Y1 | | Y2 | t +# +---+---+ +---+---+ e +# | Y1:y1 Y2:y2 | r +# +---------+ +---------+ n +# | | a +# X1':x1' | | X2':x2' l +# +--+---+--+ +# ...........| NAT |............... +# +--+---+--+ I +# | | n +# +---------+ +---------+ t +# | X1:x1 X2:x2 | e +# +---+---+ +---+---+ r +# | X1 | | X2 | n +# +-------+ +-------+ a +# l +# +# Port Assignment +# +# Some NATs attempt to preserve the port number used internally when +# assigning a mapping to an external IP address and port (e.g., x1=x1', +# x2=x2'). This port assignment behavior is referred to as "port +# preservation". In case of port collision, these NATs attempt a +# variety of techniques for coping. For example, some NATs will +# overridden the previous mapping to preserve the same port. Other +# NATs will assign a different IP address from a pool of external IP +# addresses; this is only possible as long as the NAT has enough +# external IP addresses; if the port is already in use on all available +# external IP addresses, then these NATs will pick a different port +# (i.e., they don't do port preservation anymore). +# +# Some NATs use "Port overloading", i.e., they always use port +# preservation even in the case of collision (i.e., X1'=X2' and +# x1=x2=x1'=x2'). Most applications will fail if the NAT uses "Port +# overloading". +# +# A NAT that does not attempt to make the external port numbers match +# the internal port numbers in any case is referred to as "no port +# preservation". +# +# When NATs do allocate a new source port, there is the issue of which +# IANA-defined range of port to choose. The ranges are "well-known" +# from 0 to 1023, "registered" from 1024 to 49151, and "dynamic/ +# private" from 49152 through 65535. For most protocols, these are +# destination ports and not source ports, so mapping a source port to a +# source port that is already registered is unlikely to have any bad +# effects. Some NATs may choose to use only the ports in the dynamic +# range; the only downside of this practice is that it limits the +# number of ports available. Other NAT devices may use everything but +# the well-known range and may prefer to use the dynamic range first, +# or possibly avoid the actual registered ports in the registered +# range. Other NATs preserve the port range if it is in the well-known +# range. [RFC0768] specifies that the source port is set to zero if no +# reply packets are expected. In this case, it does not matter what +# the NAT maps it to, as the source port will not be used. However, +# many common OS APIs do not allow a user to send from port zero, +# applications do not use port zero, and the behavior of various +# existing NATs with regards to a packet with a source of port zero is +# unknown. This document does not specify any normative behavior for a +# NAT when handling a packet with a source port of zero which means +# that applications cannot count on any sort of deterministic behavior +# for these packets. +# +# REQ-3: A NAT MUST NOT have a "Port assignment" behavior of "Port +# overloading". +# +# a) If the host's source port was in the range 0-1023, it is +# RECOMMENDED the NAT's source port be in the same range. If the +# host's source port was in the range 1024-65535, it is +# RECOMMENDED that the NAT's source port be in that range. +# +# Justification: This requirement must be met in order to enable two +# applications on the internal side of the NAT both to use the same +# port to try to communicate with the same destination. NATs that +# implement port preservation have to deal with conflicts on ports, +# and the multiple code paths this introduces often result in +# nondeterministic behavior. However, it should be understood that +# when a port is randomly assigned, it may just randomly happen to +# be assigned the same port. Applications must, therefore, be able +# to deal with both port preservation and no port preservation. +# +# a) Certain applications expect the source UDP port to be in the +# well-known range. See the discussion of Network File System +# port expectations in [RFC2623] for an example. + +[[spec]] +level = "MUST" +quote = ''' +REQ-3: A NAT MUST NOT have a "Port assignment" behavior of "Port +overloading". +''' + +[[spec]] +level = "SHOULD" +quote = ''' +a) If the host's source port was in the range 0-1023, it is +RECOMMENDED the NAT's source port be in the same range. +''' + +[[spec]] +level = "SHOULD" +quote = ''' +If the +host's source port was in the range 1024-65535, it is +RECOMMENDED that the NAT's source port be in that range. +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-4.2.2.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-4.2.2.toml new file mode 100644 index 0000000000..c3b614d3f1 --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-4.2.2.toml @@ -0,0 +1,38 @@ +target = "https://www.rfc-editor.org/rfc/rfc4787#section-4.2.2" + +# Port Parity +# +# Some NATs preserve the parity of the UDP port, i.e., an even port +# will be mapped to an even port, and an odd port will be mapped to an +# odd port. This behavior respects the [RFC3550] rule that RTP use +# even ports, and RTCP use odd ports. RFC 3550 allows any port numbers +# to be used for RTP and RTCP if the two numbers are specified +# separately; for example, using [RFC3605]. However, some +# implementations do not include RFC 3605, and do not recognize when +# the peer has specified the RTCP port separately using RFC 3605. If +# such an implementation receives an odd RTP port number from the peer +# (perhaps after having been translated by a NAT), and then follows the +# RFC 3550 rule to change the RTP port to the next lower even number, +# this would obviously result in the loss of RTP. NAT-friendly +# application aspects are outside the scope of this document. It is +# expected that this issue will fade away with time, as implementations +# improve. Preserving the port parity allows for supporting +# communication with peers that do not support explicit specification +# of both RTP and RTCP port numbers. +# +# REQ-4: It is RECOMMENDED that a NAT have a "Port parity +# preservation" behavior of "Yes". +# +# Justification: This is to avoid breaking peer-to-peer applications +# that do not explicitly and separately specify RTP and RTCP port +# numbers and that follow the RFC 3550 rule to decrement an odd RTP +# port to make it even. The same considerations apply, as per the +# IP address pooling requirement. + +[[spec]] +level = "SHOULD" +quote = ''' +REQ-4: It is RECOMMENDED that a NAT have a "Port parity +preservation" behavior of "Yes". +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-4.3.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-4.3.toml new file mode 100644 index 0000000000..88b2fb29ec --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-4.3.toml @@ -0,0 +1,114 @@ +target = "https://www.rfc-editor.org/rfc/rfc4787#section-4.3" + +# Mapping Refresh +# +# NAT mapping timeout implementations vary, but include the timer's +# value and the way the mapping timer is refreshed to keep the mapping +# alive. +# +# The mapping timer is defined as the time a mapping will stay active +# without packets traversing the NAT. There is great variation in the +# values used by different NATs. +# +# REQ-5: A NAT UDP mapping timer MUST NOT expire in less than two +# minutes, unless REQ-5a applies. +# +# a) For specific destination ports in the well-known port range +# (ports 0-1023), a NAT MAY have shorter UDP mapping timers that +# are specific to the IANA-registered application running over +# that specific destination port. +# +# b) The value of the NAT UDP mapping timer MAY be configurable. +# +# c) A default value of five minutes or more for the NAT UDP mapping +# timer is RECOMMENDED. +# +# Justification: This requirement is to ensure that the timeout is +# long enough to avoid too-frequent timer refresh packets. +# +# a) Some UDP protocols using UDP use very short-lived connections. +# There can be very many such connections; keeping them all in a +# connections table could cause considerable load on the NAT. +# Having shorter timers for these specific applications is, +# therefore, an optimization technique. It is important that the +# shorter timers applied to specific protocols be used sparingly, +# and only for protocols using well-known destination ports that +# are known to have a shorter timer, and that are known not to be +# used by any applications for other purposes. +# +# b) Configuration is desirable for adapting to specific networks +# and troubleshooting. +# +# c) This default is to avoid too-frequent timer refresh packets. +# +# Some NATs keep the mapping active (i.e., refresh the timer value) +# when a packet goes from the internal side of the NAT to the external +# side of the NAT. This is referred to as having a NAT Outbound +# refresh behavior of "True". +# +# Some NATs keep the mapping active when a packet goes from the +# external side of the NAT to the internal side of the NAT. This is +# referred to as having a NAT Inbound Refresh Behavior of "True". +# +# Some NATs keep the mapping active on both, in which case, both +# properties are "True". +# +# REQ-6: The NAT mapping Refresh Direction MUST have a "NAT Outbound +# refresh behavior" of "True". +# +# a) The NAT mapping Refresh Direction MAY have a "NAT Inbound +# refresh behavior" of "True". +# +# Justification: Outbound refresh is necessary for allowing the client +# to keep the mapping alive. +# +# a) Inbound refresh may be useful for applications with no outgoing +# UDP traffic. However, allowing inbound refresh may allow an +# external attacker or misbehaving application to keep a mapping +# alive indefinitely. This may be a security risk. Also, if the +# process is repeated with different ports, over time, it could +# use up all the ports on the NAT. + +[[spec]] +level = "MUST" +quote = ''' +REQ-5: A NAT UDP mapping timer MUST NOT expire in less than two +minutes, unless REQ-5a applies. +''' + +[[spec]] +level = "MAY" +quote = ''' +a) For specific destination ports in the well-known port range +(ports 0-1023), a NAT MAY have shorter UDP mapping timers that +are specific to the IANA-registered application running over +that specific destination port. +''' + +[[spec]] +level = "MAY" +quote = ''' +b) The value of the NAT UDP mapping timer MAY be configurable. +''' + +[[spec]] +level = "SHOULD" +quote = ''' +c) A default value of five minutes or more for the NAT UDP mapping +timer is RECOMMENDED. +''' + +[[spec]] +level = "MUST" +quote = ''' +REQ-6: The NAT mapping Refresh Direction MUST have a "NAT Outbound +refresh behavior" of "True". +''' + +[[spec]] +level = "MAY" +quote = ''' +a) The NAT mapping Refresh Direction MAY have a "NAT Inbound +refresh behavior" of "True". +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-4.4.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-4.4.toml new file mode 100644 index 0000000000..e35199e317 --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-4.4.toml @@ -0,0 +1,93 @@ +target = "https://www.rfc-editor.org/rfc/rfc4787#section-4.4" + +# Conflicting Internal and External IP Address Spaces +# +# Many NATs, particularly consumer-level devices designed to be +# deployed by nontechnical users, routinely obtain their external IP +# address, default router, and other IP configuration information for +# their external interface dynamically from an external network, such +# as an upstream ISP. The NAT, in turn, automatically sets up its own +# internal subnet in one of the private IP address spaces assigned to +# this purpose in [RFC1918], typically providing dynamic IP +# configuration services for hosts on this internal network. +# +# Auto-configuration of NATs and private networks can be problematic, +# however, if the NAT's external network is also in RFC 1918 private +# address space. In a common scenario, an ISP places its customers +# behind a NAT and hands out private RFC 1918 addresses to them. Some +# of these customers, in turn, deploy consumer-level NATs, which, in +# effect, act as "second-level" NATs, multiplexing their own private +# RFC 1918 IP subnets onto the single RFC 1918 IP address provided by +# the ISP. There is no inherent guarantee, in this case, that the +# ISP's "intermediate" privately-addressed network and the customer's +# internal privately-addressed network will not use numerically +# identical or overlapping RFC 1918 IP subnets. Furthermore, customers +# of consumer-level NATs cannot be expected to have the technical +# +# knowledge to prevent this scenario from occurring by manually +# configuring their internal network with non-conflicting RFC 1918 +# subnets. +# +# NAT vendors need to design their NATs to ensure that they function +# correctly and robustly even in such problematic scenarios. One +# possible solution is for the NAT to ensure that whenever its external +# link is configured with an RFC 1918 private IP address, the NAT +# automatically selects a different, non-conflicting RFC 1918 IP subnet +# for its internal network. A disadvantage of this solution is that, +# if the NAT's external interface is dynamically configured or re- +# configured after its internal network is already in use, then the NAT +# may have to renumber its entire internal network dynamically if it +# detects a conflict. +# +# An alternative solution is for the NAT to be designed so that it can +# translate and forward traffic correctly, even when its external and +# internal interfaces are configured with numerically overlapping IP +# subnets. In this scenario, for example, if the NAT's external +# interface has been assigned an IP address P in RFC 1918 space, then +# there might also be an internal node I having the same RFC 1918 +# private IP address P. An IP packet with destination address P on the +# external network is directed at the NAT, whereas an IP packet with +# the same destination address P on the internal network is directed at +# node I. The NAT therefore needs to maintain a clear operational +# distinction between "external IP addresses" and "internal IP +# addresses" to avoid confusing internal node I with its own external +# interface. In general, the NAT needs to allow all internal nodes +# (including I) to communicate with all external nodes having public +# (non-RFC 1918) IP addresses, or having private IP addresses that do +# not conflict with the addresses used by its internal network. +# +# REQ-7: A NAT device whose external IP interface can be configured +# dynamically MUST either (1) automatically ensure that its internal +# network uses IP addresses that do not conflict with its external +# network, or (2) be able to translate and forward traffic between +# all internal nodes and all external nodes whose IP addresses +# numerically conflict with the internal network. +# +# Justification: If a NAT's external and internal interfaces are +# configured with overlapping IP subnets, then there is, of course, +# no way for an internal host with RFC 1918 IP address Q to initiate +# a direct communication session to an external node having the same +# RFC 1918 address Q, or to other external nodes with IP addresses +# that numerically conflict with the internal subnet. Such nodes +# can still open communication sessions indirectly via NAT traversal +# techniques, however, with the help of a third-party server, such +# as a STUN server having a public, non-RFC 1918 IP address. In +# +# this case, nodes with conflicting private RFC 1918 addresses on +# opposite sides of the second-level NAT can communicate with each +# other via their respective temporary public endpoints on the main +# Internet, as long as their common, first-level NAT (e.g., the +# upstream ISP's NAT) supports hairpinning behavior, as described in +# Section 6. + +[[spec]] +level = "MUST" +quote = ''' +REQ-7: A NAT device whose external IP interface can be configured +dynamically MUST either (1) automatically ensure that its internal +network uses IP addresses that do not conflict with its external +network, or (2) be able to translate and forward traffic between +all internal nodes and all external nodes whose IP addresses +numerically conflict with the internal network. +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-5.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-5.toml new file mode 100644 index 0000000000..1f67749d2e --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-5.toml @@ -0,0 +1,104 @@ +target = "https://www.rfc-editor.org/rfc/rfc4787#section-5" + +# Filtering Behavior +# +# This section describes various filtering behaviors observed in NATs. +# +# When an internal endpoint opens an outgoing session through a NAT, +# the NAT assigns a filtering rule for the mapping between an internal +# IP:port (X:x) and external IP:port (Y:y) tuple. +# +# The key behavior to describe is what criteria are used by the NAT to +# filter packets originating from specific external endpoints. +# +# Endpoint-Independent Filtering: +# +# The NAT filters out only packets not destined to the internal +# address and port X:x, regardless of the external IP address and +# port source (Z:z). The NAT forwards any packets destined to +# X:x. In other words, sending packets from the internal side of +# the NAT to any external IP address is sufficient to allow any +# packets back to the internal endpoint. +# +# Address-Dependent Filtering: +# +# The NAT filters out packets not destined to the internal +# address X:x. Additionally, the NAT will filter out packets +# from Y:y destined for the internal endpoint X:x if X:x has not +# sent packets to Y:any previously (independently of the port +# used by Y). In other words, for receiving packets from a +# specific external endpoint, it is necessary for the internal +# endpoint to send packets first to that specific external +# endpoint's IP address. +# +# Address and Port-Dependent Filtering: +# +# This is similar to the previous behavior, except that the +# external port is also relevant. The NAT filters out packets +# not destined for the internal address X:x. Additionally, the +# NAT will filter out packets from Y:y destined for the internal +# endpoint X:x if X:x has not sent packets to Y:y previously. In +# other words, for receiving packets from a specific external +# endpoint, it is necessary for the internal endpoint to send +# packets first to that external endpoint's IP address and port. +# +# REQ-8: If application transparency is most important, it is +# RECOMMENDED that a NAT have an "Endpoint-Independent Filtering" +# behavior. If a more stringent filtering behavior is most +# important, it is RECOMMENDED that a NAT have an "Address-Dependent +# Filtering" behavior. +# +# a) The filtering behavior MAY be an option configurable by the +# administrator of the NAT. +# +# Justification: The recommendation to use Endpoint-Independent +# Filtering is aimed at maximizing application transparency; in +# particular, for applications that receive media simultaneously +# from multiple locations (e.g., gaming), or applications that use +# rendezvous techniques. However, it is also possible that, in some +# circumstances, it may be preferable to have a more stringent +# filtering behavior. Filtering independently of the external +# endpoint is not as secure: An unauthorized packet could get +# through a specific port while the port was kept open if it was +# lucky enough to find the port open. In theory, filtering based on +# both IP address and port is more secure than filtering based only +# on the IP address (because the external endpoint could, in +# reality, be two endpoints behind another NAT, where one of the two +# endpoints is an attacker). However, such a policy could interfere +# with applications that expect to receive UDP packets on more than +# one UDP port. Using Endpoint-Independent Filtering or Address- +# Dependent Filtering instead of Address and Port-Dependent +# Filtering on a NAT (say, NAT-A) also has benefits when the other +# endpoint is behind a non-BEHAVE compliant NAT (say, NAT-B) that +# does not support REQ-1. When the endpoints use ICE, if NAT-A uses +# Address and Port-Dependent Filtering, connectivity will require a +# UDP relay. However, if NAT-A uses Endpoint-Independent Filtering +# or Address-Dependent Filtering, ICE will ultimately find +# connectivity without requiring a UDP relay. Having the filtering +# behavior being an option configurable by the administrator of the +# NAT ensures that a NAT can be used in the widest variety of +# deployment scenarios. + +[[spec]] +level = "SHOULD" +quote = ''' +REQ-8: If application transparency is most important, it is +RECOMMENDED that a NAT have an "Endpoint-Independent Filtering" +behavior. +''' + +[[spec]] +level = "SHOULD" +quote = ''' +If a more stringent filtering behavior is most +important, it is RECOMMENDED that a NAT have an "Address-Dependent +Filtering" behavior. +''' + +[[spec]] +level = "MAY" +quote = ''' +a) The filtering behavior MAY be an option configurable by the +administrator of the NAT. +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-6.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-6.toml new file mode 100644 index 0000000000..4a59770de9 --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-6.toml @@ -0,0 +1,66 @@ +target = "https://www.rfc-editor.org/rfc/rfc4787#section-6" + +# Hairpinning Behavior +# +# If two hosts (called X1 and X2) are behind the same NAT and +# exchanging traffic, the NAT may allocate an address on the outside of +# the NAT for X2, called X2':x2'. If X1 sends traffic to X2':x2', it +# goes to the NAT, which must relay the traffic from X1 to X2. This is +# referred to as hairpinning and is illustrated below. +# +# NAT +# +----+ from X1:x1 to X2':x2' +-----+ X1':x1' +# | X1 |>>>>>>>>>>>>>>>>>>>>>>>>>>>>>--+--- +# +----+ | v | +# | v | +# | v | +# | v | +# +----+ from X1':x1' to X2:x2 | v | X2':x2' +# | X2 |<<<<<<<<<<<<<<<<<<<<<<<<<<<<<--+--- +# +----+ +-----+ +# +# Hairpinning Behavior +# +# Hairpinning allows two endpoints on the internal side of the NAT to +# communicate even if they only use each other's external IP addresses +# and ports. +# +# More formally, a NAT that supports hairpinning forwards packets +# originating from an internal address, X1:x1, destined for an external +# address X2':x2' that has an active mapping to an internal address +# X2:x2, back to that internal address, X2:x2. Note that typically X1' +# is the same as X2'. +# +# Furthermore, the NAT may present the hairpinned packet with either an +# internal (X1:x1) or an external (X1':x1') source IP address and port. +# Therefore, the hairpinning NAT behavior can be either "External +# source IP address and port" or "Internal source IP address and port". +# "Internal source IP address and port" may cause problems by confusing +# implementations that expect an external IP address and port. +# +# REQ-9: A NAT MUST support "Hairpinning". +# +# a) A NAT Hairpinning behavior MUST be "External source IP address +# and port". +# +# Justification: This requirement is to allow communications between +# two endpoints behind the same NAT when they are trying each +# other's external IP addresses. +# +# a) Using the external source IP address is necessary for +# applications with a restrictive policy of not accepting packets +# from IP addresses that differ from what is expected. + +[[spec]] +level = "MUST" +quote = ''' +REQ-9: A NAT MUST support "Hairpinning". +''' + +[[spec]] +level = "MUST" +quote = ''' +a) A NAT Hairpinning behavior MUST be "External source IP address +and port". +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-7.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-7.toml new file mode 100644 index 0000000000..4d53ac5ade --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-7.toml @@ -0,0 +1,46 @@ +target = "https://www.rfc-editor.org/rfc/rfc4787#section-7" + +# Application Level Gateways +# +# Certain NATs have implemented Application Level Gateways (ALGs) for +# various protocols, including protocols for negotiating peer-to-peer +# sessions, such as SIP. +# +# Certain NATs have these ALGs turned on permanently, others have them +# turned on by default but allow them to be turned off, and others have +# them turned off by default but allow them be turned on. +# +# NAT ALGs may interfere with UNSAF methods or protocols that try to be +# NAT-aware and therefore must be used with extreme caution. +# +# REQ-10: To eliminate interference with UNSAF NAT traversal +# mechanisms and allow integrity protection of UDP communications, +# NAT ALGs for UDP-based protocols SHOULD be turned off. Future +# standards track specifications that define ALGs can update this to +# recommend the defaults for the ALGs that they define. +# +# a) If a NAT includes ALGs, it is RECOMMENDED that the NAT allow +# the NAT administrator to enable or disable each ALG separately. +# +# Justification: NAT ALGs may interfere with UNSAF methods. +# +# a) This requirement allows the user to enable those ALGs that are +# necessary to aid in the operation of some applications without +# enabling ALGs, which interfere with the operation of other +# applications. + +[[spec]] +level = "SHOULD" +quote = ''' +REQ-10: To eliminate interference with UNSAF NAT traversal +mechanisms and allow integrity protection of UDP communications, +NAT ALGs for UDP-based protocols SHOULD be turned off. +''' + +[[spec]] +level = "SHOULD" +quote = ''' +a) If a NAT includes ALGs, it is RECOMMENDED that the NAT allow +the NAT administrator to enable or disable each ALG separately. +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-8.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-8.toml new file mode 100644 index 0000000000..ead654edd6 --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-8.toml @@ -0,0 +1,65 @@ +target = "https://www.rfc-editor.org/rfc/rfc4787#section-8" + +# Deterministic Properties +# +# The classification of NATs is further complicated by the fact that, +# under some conditions, the same NAT will exhibit different behaviors. +# This has been seen on NATs that preserve ports or have specific +# algorithms for selecting a port other than a free one. If the +# external port that the NAT wishes to use is already in use by another +# session, the NAT must select a different port. This results in +# different code paths for this conflict case, which results in +# different behavior. +# +# For example, if three hosts X1, X2, and X3 all send from the same +# port x, through a port preserving NAT with only one external IP +# address, called X1', the first one to send (i.e., X1) will get an +# external port of x, but the next two will get x2' and x3' (where +# these are not equal to x). There are NATs where the External NAT +# mapping characteristics and the External Filter characteristics +# change between the X1:x and the X2:x mapping. To make matters worse, +# there are NATs where the behavior may be the same on the X1:x and +# X2:x mappings, but different on the third X3:x mapping. +# +# Another example is that some NATs have an "Endpoint-Independent +# Mapping", combined with "Port Overloading", as long as two endpoints +# are not establishing sessions to the same external direction, but +# then switch their behavior to "Address and Port-Dependent Mapping" +# +# without "Port Preservation" upon detection of these conflicting +# sessions establishments. +# +# Any NAT that changes the NAT Mapping or the Filtering behavior +# without configuration changes, at any point in time, under any +# particular conditions, is referred to as a "non-deterministic" NAT. +# NATs that don't are called "deterministic". +# +# Non-deterministic NATs generally change behavior when a conflict of +# some sort happens, i.e., when the port that would normally be used is +# already in use by another mapping. The NAT mapping and External +# Filtering in the absence of conflict is referred to as the Primary +# behavior. The behavior after the first conflict is referred to as +# Secondary and after the second conflict is referred to as Tertiary. +# No NATs have been observed that change on further conflicts, but it +# is certainly possible that they exist. +# +# REQ-11: A NAT MUST have deterministic behavior, i.e., it MUST NOT +# change the NAT translation (Section 4) or the Filtering +# (Section 5) Behavior at any point in time, or under any particular +# conditions. +# +# Justification: Non-deterministic NATs are very difficult to +# troubleshoot because they require more intensive testing. This +# non-deterministic behavior is the root cause of much of the +# uncertainty that NATs introduce about whether or not applications +# will work. + +[[spec]] +level = "MUST" +quote = ''' +REQ-11: A NAT MUST have deterministic behavior, i.e., it MUST NOT +change the NAT translation (Section 4) or the Filtering +(Section 5) Behavior at any point in time, or under any particular +conditions. +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-9.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-9.toml new file mode 100644 index 0000000000..81b9e9e248 --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-9.toml @@ -0,0 +1,80 @@ +target = "https://www.rfc-editor.org/rfc/rfc4787#section-9" + +# ICMP Destination Unreachable Behavior +# +# When a NAT sends a packet toward a host on the other side of the NAT, +# an ICMP message may be sent in response to that packet. That ICMP +# message may be sent by the destination host or by any router along +# the network path. The NAT's default configuration SHOULD NOT filter +# ICMP messages based on their source IP address. Such ICMP messages +# SHOULD be rewritten by the NAT (specifically, the IP headers and the +# ICMP payload) and forwarded to the appropriate internal or external +# host. The NAT needs to perform this function for as long as the UDP +# mapping is active. Receipt of any sort of ICMP message MUST NOT +# destroy the NAT mapping. A NAT that performs the functions described +# in the paragraph above is referred to as "support ICMP Processing". +# +# There is no significant security advantage to blocking ICMP +# Destination Unreachable packets. Additionally, blocking ICMP +# Destination Unreachable packets can interfere with application +# failover, UDP Path MTU Discovery (see [RFC1191] and [RFC1435]), and +# traceroute. Blocking any ICMP message is discouraged, and blocking +# ICMP Destination Unreachable is strongly discouraged. +# +# REQ-12: Receipt of any sort of ICMP message MUST NOT terminate the +# NAT mapping. +# +# a) The NAT's default configuration SHOULD NOT filter ICMP messages +# based on their source IP address. +# +# b) It is RECOMMENDED that a NAT support ICMP Destination +# Unreachable messages. +# +# Justification: This is easy to do and is used for many things +# including MTU discovery and rapid detection of error conditions, +# and has no negative consequences. + +[[spec]] +level = "SHOULD" +quote = ''' +The NAT's default configuration SHOULD NOT filter +ICMP messages based on their source IP address. +''' + +[[spec]] +level = "SHOULD" +quote = ''' +Such ICMP messages +SHOULD be rewritten by the NAT (specifically, the IP headers and the +ICMP payload) and forwarded to the appropriate internal or external +host. +''' + +[[spec]] +level = "MUST" +quote = ''' +Receipt of any sort of ICMP message MUST NOT +destroy the NAT mapping. +''' + +[[spec]] +level = "MUST" +quote = ''' +REQ-12: Receipt of any sort of ICMP message MUST NOT terminate the +NAT mapping. +''' + +[[spec]] +level = "SHOULD" +quote = ''' +a) The NAT's default configuration SHOULD NOT filter ICMP messages +based on their source IP address. +''' + +[[spec]] +level = "SHOULD" +quote = ''' +b) It is RECOMMENDED that a NAT support ICMP Destination +Unreachable messages. +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc4884/section-3.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4884/section-3.toml new file mode 100644 index 0000000000..4acd6e9bc9 --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4884/section-3.toml @@ -0,0 +1,84 @@ +target = "https://www.rfc-editor.org/rfc/rfc4884#section-3" + +# Summary of Changes to ICMP +# +# The following is a summary of changes to ICMP that are introduced by +# this memo: +# +# An ICMP Extension Structure MAY be appended to ICMPv4 Destination +# Unreachable, Time Exceeded, and Parameter Problem messages. +# +# An ICMP Extension Structure MAY be appended to ICMPv6 Destination +# Unreachable, and Time Exceeded messages. +# +# The above mentioned messages include an "original datagram" field, +# and the message formats are updated to specify a length attribute +# for the "original datagram" field. +# +# When the ICMP Extension Structure is appended to an ICMP message +# and that ICMP message contains an "original datagram" field, the +# "original datagram" field MUST contain at least 128 octets. +# +# When the ICMP Extension Structure is appended to an ICMPv4 message +# and that ICMPv4 message contains an "original datagram" field, the +# "original datagram" field MUST be zero padded to the nearest +# 32-bit boundary. +# +# When the ICMP Extension Structure is appended to an ICMPv6 message +# and that ICMPv6 message contains an "original datagram" field, the +# "original datagram" field MUST be zero padded to the nearest +# 64-bit boundary. +# +# ICMP messages defined in the future SHOULD indicate whether or not +# they support the extension mechanism defined in this +# specification. It is recommended that all new messages support +# extensions. + +[[spec]] +level = "MAY" +quote = ''' +An ICMP Extension Structure MAY be appended to ICMPv4 Destination +Unreachable, Time Exceeded, and Parameter Problem messages. +''' + +[[spec]] +level = "MAY" +quote = ''' +An ICMP Extension Structure MAY be appended to ICMPv6 Destination +Unreachable, and Time Exceeded messages. +''' + +[[spec]] +level = "MUST" +quote = ''' +When the ICMP Extension Structure is appended to an ICMP message +and that ICMP message contains an "original datagram" field, the +"original datagram" field MUST contain at least 128 octets. +''' + +[[spec]] +level = "MUST" +quote = ''' +When the ICMP Extension Structure is appended to an ICMPv4 message +and that ICMPv4 message contains an "original datagram" field, the +"original datagram" field MUST be zero padded to the nearest +32-bit boundary. +''' + +[[spec]] +level = "MUST" +quote = ''' +When the ICMP Extension Structure is appended to an ICMPv6 message +and that ICMPv6 message contains an "original datagram" field, the +"original datagram" field MUST be zero padded to the nearest +64-bit boundary. +''' + +[[spec]] +level = "SHOULD" +quote = ''' +ICMP messages defined in the future SHOULD indicate whether or not +they support the extension mechanism defined in this +specification. +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc4884/section-4.6.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4884/section-4.6.toml new file mode 100644 index 0000000000..3c0b29be98 --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4884/section-4.6.toml @@ -0,0 +1,36 @@ +target = "https://www.rfc-editor.org/rfc/rfc4884#section-4.6" + +# ICMP Messages That Can Be Extended +# +# The ICMP Extension Structure MAY be appended to messages of the +# following types: +# +# - ICMPv4 Destination Unreachable +# +# - ICMPv4 Time Exceeded +# +# - ICMPv4 Parameter Problem +# +# - ICMPv6 Destination Unreachable +# +# - ICMPv6 Time Exceeded +# +# The ICMP Extension Structure MUST NOT be appended to any of the other +# ICMP messages mentioned in Section 4. Extensions were not defined +# for the ICMPv6 "Packet Too Big" and "Parameter Problem" messages +# because these messages lack space for a length attribute. + +[[spec]] +level = "MAY" +quote = ''' +The ICMP Extension Structure MAY be appended to messages of the +following types: +''' + +[[spec]] +level = "MUST" +quote = ''' +The ICMP Extension Structure MUST NOT be appended to any of the other +ICMP messages mentioned in Section 4. +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc4884/section-4.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4884/section-4.toml new file mode 100644 index 0000000000..75f346e047 --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4884/section-4.toml @@ -0,0 +1,166 @@ +target = "https://www.rfc-editor.org/rfc/rfc4884#section-4" + +# ICMP Extensibility +# +# RFC 792 defines the following ICMPv4 message types: +# +# - Destination Unreachable +# +# - Time Exceeded +# +# - Parameter Problem +# +# - Source Quench +# +# - Redirect +# +# - Echo Request/Reply +# +# - Timestamp/Timestamp Reply +# +# - Information Request/Information Reply +# +# [RFC1191] reserves bits for the "Next-Hop MTU" field in the +# Destination Unreachable message. +# +# RFC 4443 defines the following ICMPv6 message types: +# +# - Destination Unreachable +# +# - Packet Too Big +# +# - Time Exceeded +# +# - Parameter Problem +# +# - Echo Request/Reply +# +# Many ICMP messages are extensible as currently defined. Protocol +# designers can extend ICMP messages by simply appending fields or data +# structures to them. +# +# However, the following ICMP messages are not extensible as currently +# defined: +# +# - ICMPv4 Destination Unreachable (type = 3) +# +# - ICMPv4 Time Exceeded (type = 11) +# +# - ICMPv4 Parameter Problem (type = 12) +# +# - ICMPv6 Destination Unreachable (type = 1) +# +# - ICMPv6 Packet Too Big (type = 2) +# +# - ICMPv6 Time Exceeded (type = 3) +# +# - ICMPv6 Parameter Problem (type = 4) +# +# These messages contain an "original datagram" field which represents +# the leading octets of the datagram to which the ICMP message is a +# response. RFC 792 defines the "original datagram" field for ICMPv4 +# messages. In RFC 792, the "original datagram" field includes the IP +# header plus the next eight octets of the original datagram. +# [RFC1812] extends the "original datagram" field to contain as many +# octets as possible without causing the ICMP message to exceed the +# minimum IPv4 reassembly buffer size (i.e., 576 octets). RFC 4443 +# defines the "original datagram" field for ICMPv6 messages. In RFC +# 4443, the "original datagram" field always contained as many octets +# as possible without causing the ICMP message to exceed the minimum +# IPv6 MTU (i.e., 1280 octets). +# +# Unfortunately, the "original datagram" field lacks a length +# attribute. Application software infers the length of this field from +# the total length of the ICMP message. If an extension structure were +# appended to the message without adding a length attribute for the +# "original datagram" field, the message would become unparsable. +# Specifically, application software would not be able to determine +# where the "original datagram" field ends and where the extension +# structure begins. +# +# In order to solve this problem, this memo introduces an 8-bit length +# attribute to the following ICMPv4 messages. +# +# - Destination Unreachable (type = 3) +# +# - Time Exceeded (type = 11) +# +# - Parameter Problem (type = 12) +# +# It also introduces an 8-bit length attribute to the following ICMPv6 +# messages. +# +# - Destination Unreachable (type = 1) +# +# - Time Exceeded (type = 3) +# +# The length attribute MUST be specified when the ICMP Extension +# Structure is appended to the above mentioned ICMP messages. +# +# The length attribute represents the length of the "original datagram" +# field. Space for the length attribute is claimed from reserved +# octets, whose value was previously required to be zero. +# +# For ICMPv4 messages, the length attribute represents 32-bit words. +# When the length attribute is specified, the "original datagram" field +# MUST be zero padded to the nearest 32-bit boundary. Because the +# +# sixth octet of each of the impacted ICMPv4 messages was reserved for +# future use, this octet was selected as the location of the length +# attribute in ICMPv4. +# +# For ICMPv6 messages, the length attribute represents 64-bit words. +# When the length attribute is specified, the "original datagram" field +# MUST be zero padded to the nearest 64-bit boundary. Because the +# fifth octet of each of the impacted ICMPv6 messages was reserved for +# future use, this octet was selected as the location of the length +# attribute in ICMPv6. +# +# In order to achieve backwards compatibility, when the ICMP Extension +# Structure is appended to an ICMP message and that ICMP message +# contains an "original datagram" field, the "original datagram" field +# MUST contain at least 128 octets. If the original datagram did not +# contain 128 octets, the "original datagram" field MUST be zero padded +# to 128 octets. (See Section 5.1 for rationale.) +# +# The following sub-sections depict length attribute as it has been +# introduced to selected ICMP messages. + +[[spec]] +level = "MUST" +quote = ''' +The length attribute MUST be specified when the ICMP Extension +Structure is appended to the above mentioned ICMP messages. +''' + +[[spec]] +level = "MUST" +quote = ''' +When the length attribute is specified, the "original datagram" field +MUST be zero padded to the nearest 32-bit boundary. +''' + +[[spec]] +level = "MUST" +quote = ''' +When the length attribute is specified, the "original datagram" field +MUST be zero padded to the nearest 64-bit boundary. +''' + +[[spec]] +level = "MUST" +quote = ''' +In order to achieve backwards compatibility, when the ICMP Extension +Structure is appended to an ICMP message and that ICMP message +contains an "original datagram" field, the "original datagram" field +MUST contain at least 128 octets. +''' + +[[spec]] +level = "MUST" +quote = ''' +If the original datagram did not +contain 128 octets, the "original datagram" field MUST be zero padded +to 128 octets. +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc4884/section-5.4.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4884/section-5.4.toml new file mode 100644 index 0000000000..37a0ca7e8f --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4884/section-5.4.toml @@ -0,0 +1,16 @@ +target = "https://www.rfc-editor.org/rfc/rfc4884#section-5.4" + +# Compliant Application Receives ICMP Message with No Extensions +# +# When a compliant application receives an ICMP message, it examines +# the length attribute that is associated with the "original datagram" +# field. If the length attribute is zero, the compliant application +# MUST determine that the message contains no extensions. + +[[spec]] +level = "MUST" +quote = ''' +If the length attribute is zero, the compliant application +MUST determine that the message contains no extensions. +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc4884/section-5.5.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4884/section-5.5.toml new file mode 100644 index 0000000000..3faf9f4440 --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4884/section-5.5.toml @@ -0,0 +1,39 @@ +target = "https://www.rfc-editor.org/rfc/rfc4884#section-5.5" + +# Compliant Application Receives ICMP Message with Non-Compliant +# +# Extensions +# +# When a compliant application receives an ICMP message, it examines +# the length attribute that is associated with the "original datagram" +# field. If the length attribute is zero, the compliant application +# MUST determine that the message contains no extensions. In this +# case, that determination is technically correct, but not backwards +# compatible with the non-compliant implementation that originated the +# ICMP message. +# +# So, to ease transition yet encourage compliant implementation, +# compliant TRACEROUTE implementations MUST include a non-default +# operation mode to also interpret non-compliant responses. +# Specifically, when a TRACEROUTE application operating in non- +# compliant mode receives a sufficiently long ICMP message that does +# not specify a length attribute, it will parse for a valid extension +# header at a fixed location, assuming a 128-octet "original datagram" +# field. If the application detects a valid version and checksum, it +# will treat the octets that follow as an extension structure. + +[[spec]] +level = "MUST" +quote = ''' +If the length attribute is zero, the compliant application +MUST determine that the message contains no extensions. +''' + +[[spec]] +level = "MUST" +quote = ''' +So, to ease transition yet encourage compliant implementation, +compliant TRACEROUTE implementations MUST include a non-default +operation mode to also interpret non-compliant responses. +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc4884/section-7.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4884/section-7.toml new file mode 100644 index 0000000000..6a3733dc60 --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc4884/section-7.toml @@ -0,0 +1,59 @@ +target = "https://www.rfc-editor.org/rfc/rfc4884#section-7" + +# The ICMP Extension Structure +# +# This memo proposes an optional ICMP Extension Structure that can be +# appended to the ICMP messages referenced in Section 4.6 of this +# document. +# +# The Extension Structure contains exactly one Extension Header +# followed by one or more objects. Having received an ICMP message +# with extensions, application software MAY process selected objects +# while ignoring others. The presence of an unrecognized object does +# not imply that an ICMP message is malformed. +# +# As stated above, the total length of the ICMP message, including +# extensions, MUST NOT exceed the minimum reassembly buffer size. +# Figure 6 depicts the ICMP Extension Header. +# +# 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 +# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +# |Version| (Reserved) | Checksum | +# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +# +# Figure 6: ICMP Extension Header +# +# The fields of the ICMP Extension Header are as follows: +# +# Version: 4 bits +# +# ICMP extension version number. This is version 2. +# +# Reserved: 12 bits +# +# Must be set to 0. +# +# Checksum: 16 bits +# +# The one's complement of the one's complement sum of the data +# structure, with the checksum field replaced by zero for the +# purpose of computing the checksum. An all-zero value means that +# no checksum was transmitted. See Section 5.2 for a description of +# how this field is used. + +[[spec]] +level = "MAY" +quote = ''' +Having received an ICMP message +with extensions, application software MAY process selected objects +while ignoring others. +''' + +[[spec]] +level = "MUST" +quote = ''' +As stated above, the total length of the ICMP message, including +extensions, MUST NOT exceed the minimum reassembly buffer size. +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-4.1.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-4.1.toml new file mode 100644 index 0000000000..03d4e344c8 --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-4.1.toml @@ -0,0 +1,50 @@ +target = "https://www.rfc-editor.org/rfc/rfc5382#section-4.1" + +# Address and Port Mapping Behavior +# +# A NAT uses a mapping to translate packets for each TCP connection. A +# mapping is dynamically allocated for connections initiated from the +# internal side, and potentially reused for certain subsequent +# connections. NAT behavior regarding when a mapping can be reused +# differs for different NATs as described in [BEHAVE-UDP]. +# +# Consider an internal IP address and TCP port (X:x) that initiates a +# TCP connection to an external (Y1:y1) tuple. Let the mapping +# allocated by the NAT for this connection be (X1':x1'). Shortly +# thereafter, the endpoint initiates a connection from the same (X:x) +# to an external address (Y2:y2) and gets the mapping (X2':x2') on the +# NAT. As per [BEHAVE-UDP], if (X1':x1') equals (X2':x2') for all +# values of (Y2:y2), then the NAT is defined to have "Endpoint- +# Independent Mapping" behavior. If (X1':x1') equals (X2':x2') only +# when Y2 equals Y1, then the NAT is defined to have "Address-Dependent +# Mapping" behavior. If (X1':x1') equals (X2':x2') only when (Y2:y2) +# equals (Y1:y1), possible only for consecutive connections to the same +# external address shortly after the first is terminated and if the NAT +# retains state for connections in TIME_WAIT state, then the NAT is +# defined to have "Address and Port-Dependent Mapping" behavior. This +# document introduces one additional behavior where (X1':x1') never +# equals (X2':x2'), that is, for each connection a new mapping is +# allocated; in such a case, the NAT is defined to have "Connection- +# Dependent Mapping" behavior. +# +# REQ-1: A NAT MUST have an "Endpoint-Independent Mapping" behavior +# for TCP. +# +# Justification: REQ-1 is necessary for UNSAF methods to work. +# Endpoint-Independent Mapping behavior allows peer-to-peer +# applications to learn and advertise the external IP address and +# port allocated to an internal endpoint such that external peers +# can contact it (subject to the NAT's security policy). The +# security policy of a NAT is independent of its mapping behavior +# and is discussed later in Section 4.3. Having Endpoint- +# Independent Mapping behavior allows peer-to-peer applications to +# work consistently without compromising the security benefits of +# the NAT. + +[[spec]] +level = "MUST" +quote = ''' +REQ-1: A NAT MUST have an "Endpoint-Independent Mapping" behavior +for TCP. +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-4.2.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-4.2.toml new file mode 100644 index 0000000000..98e84ac415 --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-4.2.toml @@ -0,0 +1,75 @@ +target = "https://www.rfc-editor.org/rfc/rfc5382#section-4.2" + +# Internally Initiated Connections +# +# An internal endpoint initiates a TCP connection through a NAT by +# sending a SYN packet. The NAT allocates (or reuses) a mapping for +# the connection, as described in the previous section. The mapping +# defines the external IP address and port used for translation of all +# packets for that connection. In particular, for client-server +# +# applications where an internal client initiates the connection to an +# external server, the mapping is used to translate the outbound SYN, +# the resulting inbound SYN-ACK response, the subsequent outbound ACK, +# and other packets for the connection. This method of connection +# initiation corresponds to the 3-way handshake (defined in [RFC0793]) +# and is supported by all NATs. +# +# Peer-to-peer applications use an alternate method of connection +# initiation termed simultaneous-open (Fig. 8, [RFC0793]) to traverse +# NATs. In the simultaneous-open mode of operation, both peers send +# SYN packets for the same TCP connection. The SYN packets cross in +# the network. Upon receiving the other end's SYN packet, each end +# responds with a SYN-ACK packet, which also cross in the network. The +# connection is considered established once the SYN-ACKs are received. +# From the perspective of the NAT, the internal host's SYN packet is +# met by an inbound SYN packet for the same connection (as opposed to a +# SYN-ACK packet during a 3-way handshake). Subsequent to this +# exchange, both an outbound and an inbound SYN-ACK are seen for the +# connection. Some NATs erroneously block the inbound SYN for the +# connection in progress. Some NATs block or incorrectly translate the +# outbound SYN-ACK. Such behavior breaks TCP simultaneous-open and +# prevents peer-to-peer applications from functioning correctly behind +# a NAT. +# +# In order to provide network address translation service for TCP, it +# is necessary for a NAT to correctly receive, translate, and forward +# all packets for a connection that conform to valid transitions of the +# TCP State-Machine (Fig. 6, [RFC0793]). +# +# REQ-2: A NAT MUST support all valid sequences of TCP packets +# (defined in [RFC0793]) for connections initiated both internally +# as well as externally when the connection is permitted by the NAT. +# In particular: +# a) In addition to handling the TCP 3-way handshake mode of +# connection initiation, A NAT MUST handle the TCP simultaneous- +# open mode of connection initiation. +# +# Justification: The intent of this requirement is to allow standards +# compliant TCP stacks to traverse NATs no matter what path the +# stacks take through the TCP state-machine and no matter which end +# initiates the connection as long as the connection is permitted by +# the filtering policy of the NAT (filtering policy is described in +# the following section). +# a) In addition to TCP packets for a 3-way handshake, A NAT must be +# prepared to accept an inbound SYN and an outbound SYN-ACK for +# an internally initiated connection in order to support +# simultaneous-open. + +[[spec]] +level = "MUST" +quote = ''' +REQ-2: A NAT MUST support all valid sequences of TCP packets +(defined in [RFC0793]) for connections initiated both internally +as well as externally when the connection is permitted by the NAT. +''' + +[[spec]] +level = "MUST" +quote = ''' +In particular: +a) In addition to handling the TCP 3-way handshake mode of +connection initiation, A NAT MUST handle the TCP simultaneous- +open mode of connection initiation. +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-4.3.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-4.3.toml new file mode 100644 index 0000000000..016ad29199 --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-4.3.toml @@ -0,0 +1,200 @@ +target = "https://www.rfc-editor.org/rfc/rfc5382#section-4.3" + +# Externally Initiated Connections +# +# The NAT allocates a mapping for the first connection initiated by an +# internal endpoint to an external endpoint. In some scenarios, the +# NAT's policy may allow this mapping to be reused for connections +# initiated from the external side to the internal endpoint. Consider +# as before an internal IP address and port (X:x) that is assigned (or +# reuses) a mapping (X1':x1') when it initiates a connection to an +# external (Y1:y1). An external endpoint (Y2:y2) attempts to initiate +# a connection with the internal endpoint by sending a SYN to +# (X1':x1'). A NAT can choose to either allow the connection to be +# established, or to disallow the connection. If the NAT chooses to +# allow the connection, it translates the inbound SYN and routes it to +# (X:x) as per the existing mapping. It also translates the SYN-ACK +# generated by (X:x) in response and routes it to (Y2:y2), and so on. +# Alternately, the NAT can disallow the connection by filtering the +# inbound SYN. +# +# A NAT may allow an existing mapping to be reused by an externally +# initiated connection if its security policy permits. Several +# different policies are possible as described in [BEHAVE-UDP]. If a +# NAT allows the connection initiation from all (Y2:y2), then it is +# defined to have "Endpoint-Independent Filtering" behavior. If the +# NAT allows connection initiations only when Y2 equals Y1, then the +# NAT is defined to have "Address-Dependent Filtering" behavior. If +# the NAT allows connection initiations only when (Y2:y2) equals +# (Y1:y1), then the NAT is defined to have "Address and Port-Dependent +# Filtering" behavior (possible only shortly after the first connection +# has been terminated but the mapping is still active). One additional +# filtering behavior defined in this document is when the NAT does not +# allow any connection initiations from the external side; in such +# cases, the NAT is defined to have "Connection-Dependent Filtering" +# behavior. The difference between "Address and Port-Dependent +# Filtering" and "Connection-Dependent Filtering" behavior is that the +# former permits an inbound SYN during the TIME_WAIT state of the first +# connection to initiate a new connection while the latter does not. +# +# REQ-3: If application transparency is most important, it is +# RECOMMENDED that a NAT have an "Endpoint-Independent Filtering" +# behavior for TCP. If a more stringent filtering behavior is most +# important, it is RECOMMENDED that a NAT have an "Address-Dependent +# Filtering" behavior. +# a) The filtering behavior MAY be an option configurable by the +# administrator of the NAT. +# b) The filtering behavior for TCP MAY be independent of the +# filtering behavior for UDP. +# +# Justification: The intent of this requirement is to allow peer-to- +# peer applications that do not always initiate connections from the +# internal side of the NAT to continue to work in the presence of +# NATs. This behavior also allows applications behind a BEHAVE +# compliant NAT to inter-operate with remote endpoints that are +# behind non-BEHAVE compliant (legacy) NATs. If the remote +# endpoint's NAT does not have Endpoint-Independent Mapping behavior +# but has only one external IP address, then an application can +# still traverse the combination of the two NATs if the local NAT +# has Address-Dependent Filtering. Section 9 contains a detailed +# discussion on the security implications of this requirement. +# +# If the inbound SYN packet is filtered, either because a corresponding +# mapping does not exist or because of the NAT's filtering behavior, a +# NAT has two basic choices: to ignore the packet silently, or to +# signal an error to the sender. Signaling an error through ICMP +# messages allows the sender to quickly detect that the SYN did not +# reach the intended destination. Silently dropping the packet, on the +# other hand, allows applications to perform simultaneous-open more +# reliably. +# +# Silently dropping the SYN aids simultaneous-open as follows. +# Consider that the application is attempting a simultaneous-open and +# the outbound SYN from the internal endpoint has not yet crossed the +# NAT (due to network congestion or clock skew between the two +# endpoints); this outbound SYN would otherwise have created the +# necessary mapping at the NAT to allow translation of the inbound SYN. +# Since the outbound SYN did not reach the NAT in time, the inbound SYN +# cannot be processed. If a NAT responds to the premature inbound SYN +# with an error message that forces the external endpoint to abandon +# the connection attempt, it hinders applications performing a TCP +# simultaneous-open. If instead the NAT silently ignores the inbound +# SYN, the external endpoint retransmits the SYN after a TCP timeout. +# In the meantime, the NAT creates the mapping in response to the +# (delayed) outbound SYN such that the retransmitted inbound SYN can be +# routed and simultaneous-open can succeed. The downside to this +# behavior is that in the event the inbound SYN is erroneous, the +# remote side does not learn of the error until after several TCP +# timeouts. +# +# NAT support for simultaneous-open as well as quickly signaling errors +# are both important for applications. Unfortunately, there is no way +# for a NAT to signal an error without forcing the endpoint to abort a +# potential simultaneous-open: TCP RST and ICMP Port Unreachable +# packets require the endpoint to abort the attempt while the ICMP Host +# and Network Unreachable errors may adversely affect other connections +# to the same host or network [RFC1122]. +# +# In addition, when an unsolicited SYN is received by the NAT, the NAT +# may not know whether the application is attempting a simultaneous- +# open (and that it should therefore silently drop the SYN) or whether +# the SYN is in error (and that it should notify the sender). +# +# REQ-4: A NAT MUST NOT respond to an unsolicited inbound SYN packet +# for at least 6 seconds after the packet is received. If during +# this interval the NAT receives and translates an outbound SYN for +# the connection the NAT MUST silently drop the original unsolicited +# inbound SYN packet. Otherwise, the NAT SHOULD send an ICMP Port +# Unreachable error (Type 3, Code 3) for the original SYN, unless +# REQ-4a applies. +# a) The NAT MUST silently drop the original SYN packet if sending a +# response violates the security policy of the NAT. +# +# Justification: The intent of this requirement is to allow +# simultaneous-open to work reliably in the presence of NATs as well +# as to quickly signal an error in case the unsolicited SYN is in +# error. As of writing this memo, it is not possible to achieve +# both; the requirement therefore represents a compromise. The NAT +# should tolerate some delay in the outbound SYN for a TCP +# simultaneous-open, which may be due to network congestion or loose +# synchronization between the endpoints. If the unsolicited SYN is +# not part of a simultaneous-open attempt and is in error, the NAT +# should endeavor to signal the error in accordance with [RFC1122]. +# a) There may, however, be reasons for the NAT to rate-limit or +# omit such error notifications, for example, in the case of an +# attack. Silently dropping the SYN packet when under attack +# allows simultaneous-open to work without consuming any extra +# network bandwidth or revealing the presence of the NAT to +# attackers. Section 9 mentions the security considerations for +# this requirement. +# +# For NATs that combine NAT functionality with end-host functionality +# (e.g., an end-host that also serves as a NAT for other hosts behind +# it), REQ-4 above applies only to SYNs intended for the NAT'ed hosts +# and not to SYNs intended for the NAT itself. One way to determine +# whether the inbound SYN is intended for a NAT'ed host is to allocate +# NAT mappings from one port range, and allocate ports for local +# endpoints from a different non-overlapping port range. More dynamic +# implementations can be imagined. + +[[spec]] +level = "SHOULD" +quote = ''' +REQ-3: If application transparency is most important, it is +RECOMMENDED that a NAT have an "Endpoint-Independent Filtering" +behavior for TCP. +''' + +[[spec]] +level = "SHOULD" +quote = ''' +If a more stringent filtering behavior is most +important, it is RECOMMENDED that a NAT have an "Address-Dependent +Filtering" behavior. +''' + +[[spec]] +level = "MAY" +quote = ''' +a) The filtering behavior MAY be an option configurable by the +administrator of the NAT. +''' + +[[spec]] +level = "MAY" +quote = ''' +b) The filtering behavior for TCP MAY be independent of the +filtering behavior for UDP. +''' + +[[spec]] +level = "MUST" +quote = ''' +REQ-4: A NAT MUST NOT respond to an unsolicited inbound SYN packet +for at least 6 seconds after the packet is received. +''' + +[[spec]] +level = "MUST" +quote = ''' +If during +this interval the NAT receives and translates an outbound SYN for +the connection the NAT MUST silently drop the original unsolicited +inbound SYN packet. +''' + +[[spec]] +level = "SHOULD" +quote = ''' +Otherwise, the NAT SHOULD send an ICMP Port +Unreachable error (Type 3, Code 3) for the original SYN, unless +REQ-4a applies. +''' + +[[spec]] +level = "MUST" +quote = ''' +a) The NAT MUST silently drop the original SYN packet if sending a +response violates the security policy of the NAT. +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-5.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-5.toml new file mode 100644 index 0000000000..981ea9c711 --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-5.toml @@ -0,0 +1,147 @@ +target = "https://www.rfc-editor.org/rfc/rfc5382#section-5" + +# NAT Session Refresh +# +# A NAT maintains state associated with in-progress and established +# connections. Because of this, a NAT is susceptible to a resource- +# exhaustion attack whereby an attacker (or virus) on the internal side +# attempts to cause the NAT to create more state than for which it has +# resources. To prevent such an attack, a NAT needs to abandon +# sessions in order to free the state resources. +# +# A common method that is applicable only to TCP is to preferentially +# abandon sessions for crashed endpoints, followed by closed TCP +# connections and partially open connections. A NAT can check if an +# endpoint for a session has crashed by sending a TCP keep-alive packet +# and receiving a TCP RST packet in response. If the NAT cannot +# determine whether the endpoint is active, it should not abandon the +# session until the TCP connection has been idle for some time. Note +# that an established TCP connection can stay idle (but live) +# indefinitely; hence, there is no fixed value for an idle-timeout that +# accommodates all applications. However, a large idle-timeout +# motivated by recommendations in [RFC1122] can reduce the chances of +# abandoning a live session. +# +# A TCP connection passes through three phases: partially open, +# established, and closing. During the partially open phase, endpoints +# synchronize initial sequence numbers. The phase is initiated by the +# first SYN for the connection and extends until both endpoints have +# sent a packet with the ACK flag set (TCP states: SYN_SENT and +# SYN_RCVD). ACKs in both directions mark the beginning of the +# established phase where application data can be exchanged +# indefinitely (TCP states: ESTABLISHED, FIN_WAIT_1, FIN_WAIT_2, and +# CLOSE_WAIT). The closing phase begins when both endpoints have +# terminated their half of the connection by sending a FIN packet. +# Once FIN packets are seen in both directions, application data can no +# longer be exchanged, but the stacks still need to ensure that the FIN +# packets are received (TCP states: CLOSING and LAST_ACK). +# +# TCP connections can stay in established phase indefinitely without +# exchanging any packets. Some end-hosts can be configured to send +# keep-alive packets on such idle connections; by default, such keep- +# alive packets are sent every 2 hours if enabled [RFC1122]. +# Consequently, a NAT that waits for slightly over 2 hours can detect +# idle connections with keep-alive packets being sent at the default +# rate. TCP connections in the partially open or closing phases, on +# the other hand, can stay idle for at most 4 minutes while waiting for +# in-flight packets to be delivered [RFC1122]. +# +# The "established connection idle-timeout" for a NAT is defined as the +# minimum time a TCP connection in the established phase must remain +# idle before the NAT considers the associated session a candidate for +# removal. The "transitory connection idle-timeout" for a NAT is +# defined as the minimum time a TCP connection in the partially open or +# closing phases must remain idle before the NAT considers the +# associated session a candidate for removal. TCP connections in the +# TIME_WAIT state are not affected by the "transitory connection idle- +# timeout". +# +# REQ-5: If a NAT cannot determine whether the endpoints of a TCP +# connection are active, it MAY abandon the session if it has been +# idle for some time. In such cases, the value of the "established +# connection idle-timeout" MUST NOT be less than 2 hours 4 minutes. +# The value of the "transitory connection idle-timeout" MUST NOT be +# less than 4 minutes. +# a) The value of the NAT idle-timeouts MAY be configurable. +# +# Justification: The intent of this requirement is to minimize the +# cases where a NAT abandons session state for a live connection. +# While some NATs may choose to abandon sessions reactively in +# response to new connection initiations (allowing idle connections +# to stay up indefinitely in the absence of new initiations), other +# NATs may choose to proactively reap idle sessions. In cases where +# the NAT cannot actively determine if the connection is alive, this +# requirement ensures that applications can send keep-alive packets +# at the default rate (every 2 hours) such that the NAT can +# passively determine that the connection is alive. The additional +# 4 minutes allows time for in-flight packets to cross the NAT. +# +# NAT behavior for handling RST packets, or connections in TIME_WAIT +# state is left unspecified. A NAT MAY hold state for a connection in +# TIME_WAIT state to accommodate retransmissions of the last ACK. +# However, since the TIME_WAIT state is commonly encountered by +# internal endpoints properly closing the TCP connection, holding state +# for a closed connection may limit the throughput of connections +# through a NAT with limited resources. [RFC1337] describes hazards +# associated with TIME_WAIT assassination. +# +# The handling of non-SYN packets for connections for which there is no +# active mapping is left unspecified. Such packets may be received if +# the NAT silently abandons a live connection, or abandons a connection +# in TIME_WAIT state before the 4 minute TIME_WAIT period expires. The +# decision to either silently drop such packets or to respond with a +# TCP RST packet is left up to the implementation. +# +# NAT behavior for notifying endpoints when abandoning live connections +# is left unspecified. When a NAT abandons a live connection, for +# example due to a timeout expiring, the NAT MAY either send TCP RST +# packets to the endpoints or MAY silently abandon the connection. +# +# Sending a RST notification allows endpoint applications to recover +# more quickly; however, notifying the endpoints may not always be +# possible if, for example, session state is lost due to a power +# failure. + +[[spec]] +level = "MAY" +quote = ''' +REQ-5: If a NAT cannot determine whether the endpoints of a TCP +connection are active, it MAY abandon the session if it has been +idle for some time. +''' + +[[spec]] +level = "MUST" +quote = ''' +In such cases, the value of the "established +connection idle-timeout" MUST NOT be less than 2 hours 4 minutes. +''' + +[[spec]] +level = "MUST" +quote = ''' +The value of the "transitory connection idle-timeout" MUST NOT be +less than 4 minutes. +''' + +[[spec]] +level = "MAY" +quote = ''' +a) The value of the NAT idle-timeouts MAY be configurable. +''' + +[[spec]] +level = "MAY" +quote = ''' +A NAT MAY hold state for a connection in +TIME_WAIT state to accommodate retransmissions of the last ACK. +''' + +[[spec]] +level = "MAY" +quote = ''' +When a NAT abandons a live connection, for +example due to a timeout expiring, the NAT MAY either send TCP RST +packets to the endpoints or MAY silently abandon the connection. +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-6.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-6.toml new file mode 100644 index 0000000000..6eb7cf10aa --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-6.toml @@ -0,0 +1,28 @@ +target = "https://www.rfc-editor.org/rfc/rfc5382#section-6" + +# Application Level Gateways +# +# Application Level Gateways (ALGs) in certain NATs modify IP addresses +# and TCP ports embedded inside application protocols. Such ALGs may +# interfere with UNSAF methods or protocols that try to be NAT-aware +# and must therefore be used with extreme caution. +# +# REQ-6: If a NAT includes ALGs that affect TCP, it is RECOMMENDED +# that all of those ALGs (except for FTP [RFC0959]) be disabled by +# default. +# +# Justification: The intent of this requirement is to prevent ALGs +# from interfering with UNSAF methods. The default state of an FTP +# ALG is left unspecified because of legacy concerns: as of writing +# this memo, a large fraction of legacy FTP clients do not enable +# passive (PASV) mode by default and require an ALG to traverse +# NATs. + +[[spec]] +level = "SHOULD" +quote = ''' +REQ-6: If a NAT includes ALGs that affect TCP, it is RECOMMENDED +that all of those ALGs (except for FTP [RFC0959]) be disabled by +default. +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-7.1.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-7.1.toml new file mode 100644 index 0000000000..e1e74408a8 --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-7.1.toml @@ -0,0 +1,37 @@ +target = "https://www.rfc-editor.org/rfc/rfc5382#section-7.1" + +# Port Assignment +# +# NATs that allow different internal endpoints to simultaneously use +# the same mapping are defined in [BEHAVE-UDP] to have a "Port +# assignment" behavior of "Port overloading". Such behavior is +# undesirable, as it prevents two internal endpoints sharing the same +# mapping from establishing simultaneous connections to a common +# external endpoint. +# +# REQ-7: A NAT MUST NOT have a "Port assignment" behavior of "Port +# overloading" for TCP. +# +# Justification: This requirement allows two applications on the +# internal side of the NAT to consistently communicate with the same +# destination. +# +# NAT behavior for preserving the source TCP port range for connections +# is left unspecified. Some applications expect the source TCP port to +# be in the well-known range (TCP ports from 0 to 1023). The "r" +# series of commands (rsh, rcp, rlogin, etc.) are an example. NATs +# that preserve the range from which the source port is picked allow +# such applications to function properly through the NAT; however, by +# doing so the NAT may compromise the security of the application in +# certain situations; applications that depend only on the IP address +# and source TCP port range for security (the "r" commands, for +# example) cannot distinguish between an attacker and a legitimate user +# behind the same NAT. + +[[spec]] +level = "MUST" +quote = ''' +REQ-7: A NAT MUST NOT have a "Port assignment" behavior of "Port +overloading" for TCP. +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-7.2.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-7.2.toml new file mode 100644 index 0000000000..8b618f773c --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-7.2.toml @@ -0,0 +1,42 @@ +target = "https://www.rfc-editor.org/rfc/rfc5382#section-7.2" + +# Hairpinning Behavior +# +# NATs that forward packets originating from an internal address, +# destined for an external address that matches the active mapping for +# an internal address, back to that internal address are defined in +# [BEHAVE-UDP] as supporting "hairpinning". If the NAT presents the +# hairpinned packet with an external source IP address and port (i.e., +# the mapped source address and port of the originating internal +# endpoint), then it is defined to have "External source IP address and +# port" for hairpinning. Hairpinning is necessary to allow two +# internal endpoints (known to each other only by their external mapped +# addresses) to communicate with each other. "External source IP +# address and port" behavior for hairpinning avoids confusing +# implementations that expect the external source IP address and port. +# +# REQ-8: A NAT MUST support "hairpinning" for TCP. +# a) A NAT's hairpinning behavior MUST be of type "External source +# IP address and port". +# +# Justification: This requirement allows two applications behind the +# same NAT that are trying to communicate with each other using +# their external addresses. +# a) Using the external source address and port for the hairpinned +# packet is necessary for applications that do not expect to +# receive a packet from a different address than the external +# address they are trying to communicate with. + +[[spec]] +level = "MUST" +quote = ''' +REQ-8: A NAT MUST support "hairpinning" for TCP. +''' + +[[spec]] +level = "MUST" +quote = ''' +a) A NAT's hairpinning behavior MUST be of type "External source +IP address and port". +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-7.3.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-7.3.toml new file mode 100644 index 0000000000..187edd01a7 --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-7.3.toml @@ -0,0 +1,44 @@ +target = "https://www.rfc-editor.org/rfc/rfc5382#section-7.3" + +# ICMP Responses to TCP Packets +# +# Several TCP mechanisms depend on the reception of ICMP error messages +# triggered by the transmission of TCP segments. One such mechanism is +# path MTU discovery [RFC1191], which is required for the correct +# +# operation of TCP. The current path MTU discovery mechanism requires +# the sender of TCP segments to be notified of ICMP "Datagram Too Big" +# responses. +# +# REQ-9: If a NAT translates TCP, it SHOULD translate ICMP Destination +# Unreachable (Type 3) messages. +# +# Justification: Translating ICMP Destination Unreachable messages, +# particularly the "Fragmentation Needed and Don't Fragment was Set" +# (Type 3, Code 4) message avoids communication failures ("black +# holes" [RFC2923]). Furthermore, TCP's connection establishment +# and maintenance mechanisms also behave much more efficiently when +# ICMP Destination Unreachable messages arrive in response to +# outgoing TCP segments. +# +# REQ-10: Receipt of any sort of ICMP message MUST NOT terminate the +# NAT mapping or TCP connection for which the ICMP was generated. +# +# Justification: This is necessary for reliably performing TCP +# simultaneous-open where a remote NAT may temporarily signal an +# ICMP error. + +[[spec]] +level = "SHOULD" +quote = ''' +REQ-9: If a NAT translates TCP, it SHOULD translate ICMP Destination +Unreachable (Type 3) messages. +''' + +[[spec]] +level = "MUST" +quote = ''' +REQ-10: Receipt of any sort of ICMP message MUST NOT terminate the +NAT mapping or TCP connection for which the ICMP was generated. +''' + diff --git a/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-8.toml b/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-8.toml new file mode 100644 index 0000000000..9c4437acf9 --- /dev/null +++ b/.duvet/requirements/www.rfc-editor.org/rfc/rfc5382/section-8.toml @@ -0,0 +1,228 @@ +target = "https://www.rfc-editor.org/rfc/rfc5382#section-8" + +# Requirements +# +# A NAT that supports all of the mandatory requirements of this +# specification (i.e., the "MUST") and is compliant with [BEHAVE-UDP], +# is "compliant with this specification". A NAT that supports all of +# the requirements of this specification (i.e., included the +# "RECOMMENDED") and is fully compliant with [BEHAVE-UDP] is "fully +# compliant with all the mandatory and recommended requirements of this +# specification". +# +# REQ-1: A NAT MUST have an "Endpoint-Independent Mapping" behavior +# for TCP. +# +# REQ-2: A NAT MUST support all valid sequences of TCP packets +# (defined in [RFC0793]) for connections initiated both internally +# as well as externally when the connection is permitted by the NAT. +# In particular: +# a) In addition to handling the TCP 3-way handshake mode of +# connection initiation, A NAT MUST handle the TCP simultaneous- +# open mode of connection initiation. +# +# REQ-3: If application transparency is most important, it is +# RECOMMENDED that a NAT have an "Endpoint-Independent Filtering" +# behavior for TCP. If a more stringent filtering behavior is most +# important, it is RECOMMENDED that a NAT have an "Address-Dependent +# Filtering" behavior. +# +# a) The filtering behavior MAY be an option configurable by the +# administrator of the NAT. +# b) The filtering behavior for TCP MAY be independent of the +# filtering behavior for UDP. +# +# REQ-4: A NAT MUST NOT respond to an unsolicited inbound SYN packet +# for at least 6 seconds after the packet is received. If during +# this interval the NAT receives and translates an outbound SYN for +# the connection the NAT MUST silently drop the original unsolicited +# inbound SYN packet. Otherwise, the NAT SHOULD send an ICMP Port +# Unreachable error (Type 3, Code 3) for the original SYN, unless +# REQ-4a applies. +# a) The NAT MUST silently drop the original SYN packet if sending a +# response violates the security policy of the NAT. +# +# REQ-5: If a NAT cannot determine whether the endpoints of a TCP +# connection are active, it MAY abandon the session if it has been +# idle for some time. In such cases, the value of the "established +# connection idle-timeout" MUST NOT be less than 2 hours 4 minutes. +# The value of the "transitory connection idle-timeout" MUST NOT be +# less than 4 minutes. +# a) The value of the NAT idle-timeouts MAY be configurable. +# +# REQ-6: If a NAT includes ALGs that affect TCP, it is RECOMMENDED +# that all of those ALGs (except for FTP [RFC0959]) be disabled by +# default. +# +# The following requirements reiterate requirements from [BEHAVE-UDP] +# or [BEHAVE-ICMP] that directly affect TCP. This document does not +# relax any requirements in [BEHAVE-UDP] or [BEHAVE-ICMP]. +# +# REQ-7: A NAT MUST NOT have a "Port assignment" behavior of "Port +# overloading" for TCP. +# +# REQ-8: A NAT MUST support "hairpinning" for TCP. +# a) A NAT's hairpinning behavior MUST be of type "External source +# IP address and port". +# +# REQ-9: If a NAT translates TCP, it SHOULD translate ICMP Destination +# Unreachable (Type 3) messages. +# +# REQ-10: Receipt of any sort of ICMP message MUST NOT terminate the +# NAT mapping or TCP connection for which the ICMP was generated. + +[[spec]] +level = "MUST" +quote = ''' +REQ-1: A NAT MUST have an "Endpoint-Independent Mapping" behavior +for TCP. +''' + +[[spec]] +level = "MUST" +quote = ''' +REQ-2: A NAT MUST support all valid sequences of TCP packets +(defined in [RFC0793]) for connections initiated both internally +as well as externally when the connection is permitted by the NAT. +''' + +[[spec]] +level = "MUST" +quote = ''' +In particular: +a) In addition to handling the TCP 3-way handshake mode of +connection initiation, A NAT MUST handle the TCP simultaneous- +open mode of connection initiation. +''' + +[[spec]] +level = "SHOULD" +quote = ''' +REQ-3: If application transparency is most important, it is +RECOMMENDED that a NAT have an "Endpoint-Independent Filtering" +behavior for TCP. +''' + +[[spec]] +level = "SHOULD" +quote = ''' +If a more stringent filtering behavior is most +important, it is RECOMMENDED that a NAT have an "Address-Dependent +Filtering" behavior. +''' + +[[spec]] +level = "MAY" +quote = ''' +a) The filtering behavior MAY be an option configurable by the +administrator of the NAT. +''' + +[[spec]] +level = "MAY" +quote = ''' +b) The filtering behavior for TCP MAY be independent of the +filtering behavior for UDP. +''' + +[[spec]] +level = "MUST" +quote = ''' +REQ-4: A NAT MUST NOT respond to an unsolicited inbound SYN packet +for at least 6 seconds after the packet is received. +''' + +[[spec]] +level = "MUST" +quote = ''' +If during +this interval the NAT receives and translates an outbound SYN for +the connection the NAT MUST silently drop the original unsolicited +inbound SYN packet. +''' + +[[spec]] +level = "SHOULD" +quote = ''' +Otherwise, the NAT SHOULD send an ICMP Port +Unreachable error (Type 3, Code 3) for the original SYN, unless +REQ-4a applies. +''' + +[[spec]] +level = "MUST" +quote = ''' +a) The NAT MUST silently drop the original SYN packet if sending a +response violates the security policy of the NAT. +''' + +[[spec]] +level = "MAY" +quote = ''' +REQ-5: If a NAT cannot determine whether the endpoints of a TCP +connection are active, it MAY abandon the session if it has been +idle for some time. +''' + +[[spec]] +level = "MUST" +quote = ''' +In such cases, the value of the "established +connection idle-timeout" MUST NOT be less than 2 hours 4 minutes. +''' + +[[spec]] +level = "MUST" +quote = ''' +The value of the "transitory connection idle-timeout" MUST NOT be +less than 4 minutes. +''' + +[[spec]] +level = "MAY" +quote = ''' +a) The value of the NAT idle-timeouts MAY be configurable. +''' + +[[spec]] +level = "SHOULD" +quote = ''' +REQ-6: If a NAT includes ALGs that affect TCP, it is RECOMMENDED +that all of those ALGs (except for FTP [RFC0959]) be disabled by +default. +''' + +[[spec]] +level = "MUST" +quote = ''' +REQ-7: A NAT MUST NOT have a "Port assignment" behavior of "Port +overloading" for TCP. +''' + +[[spec]] +level = "MUST" +quote = ''' +REQ-8: A NAT MUST support "hairpinning" for TCP. +''' + +[[spec]] +level = "MUST" +quote = ''' +a) A NAT's hairpinning behavior MUST be of type "External source +IP address and port". +''' + +[[spec]] +level = "SHOULD" +quote = ''' +REQ-9: If a NAT translates TCP, it SHOULD translate ICMP Destination +Unreachable (Type 3) messages. +''' + +[[spec]] +level = "MUST" +quote = ''' +REQ-10: Receipt of any sort of ICMP message MUST NOT terminate the +NAT mapping or TCP connection for which the ICMP was generated. +''' + diff --git a/.duvet/snapshot.txt b/.duvet/snapshot.txt new file mode 100644 index 0000000000..d6892e8bbe --- /dev/null +++ b/.duvet/snapshot.txt @@ -0,0 +1,356 @@ +SPECIFICATION: https://www.rfc-editor.org/rfc/rfc4787 + SECTION: [Address and Port Mapping](#section-4.1) + TEXT[!MUST,todo]: REQ-1: A NAT MUST have an "Endpoint-Independent Mapping" behavior. + TEXT[!SHOULD,test,exception]: REQ-2: It is RECOMMENDED that a NAT have an "IP address pooling" + TEXT[!SHOULD,test,exception]: behavior of "Paired". + + SECTION: [Port Assignment Behavior](#section-4.2.1) + TEXT[!MUST,implementation,test]: REQ-3: A NAT MUST NOT have a "Port assignment" behavior of "Port + TEXT[!MUST,implementation,test]: overloading". + TEXT[!SHOULD,exception]: a) If the host's source port was in the range 0-1023, it is + TEXT[!SHOULD,exception]: RECOMMENDED the NAT's source port be in the same range. + TEXT[!SHOULD]: If the + TEXT[!SHOULD]: host's source port was in the range 1024-65535, it is + TEXT[!SHOULD]: RECOMMENDED that the NAT's source port be in that range. + + SECTION: [Port Parity](#section-4.2.2) + TEXT[!SHOULD]: REQ-4: It is RECOMMENDED that a NAT have a "Port parity + TEXT[!SHOULD]: preservation" behavior of "Yes". + + SECTION: [Mapping Refresh](#section-4.3) + TEXT[!MUST,todo]: REQ-5: A NAT UDP mapping timer MUST NOT expire in less than two + TEXT[!MUST,todo]: minutes, unless REQ-5a applies. + TEXT[!MAY,implementation]: a) For specific destination ports in the well-known port range + TEXT[!MAY,implementation]: (ports 0-1023), a NAT MAY have shorter UDP mapping timers that + TEXT[!MAY,implementation]: are specific to the IANA-registered application running over + TEXT[!MAY,implementation]: that specific destination port. + TEXT[!MAY]: b) The value of the NAT UDP mapping timer MAY be configurable. + TEXT[!SHOULD,todo]: c) A default value of five minutes or more for the NAT UDP mapping + TEXT[!SHOULD,todo]: timer is RECOMMENDED. + TEXT[!MUST,implementation,test]: REQ-6: The NAT mapping Refresh Direction MUST have a "NAT Outbound + TEXT[!MUST,implementation,test]: refresh behavior" of "True". + TEXT[!MAY]: a) The NAT mapping Refresh Direction MAY have a "NAT Inbound + TEXT[!MAY]: refresh behavior" of "True". + + SECTION: [Conflicting Internal and External IP Address Spaces](#section-4.4) + TEXT[!MUST]: REQ-7: A NAT device whose external IP interface can be configured + TEXT[!MUST]: dynamically MUST either (1) automatically ensure that its internal + TEXT[!MUST]: network uses IP addresses that do not conflict with its external + TEXT[!MUST]: network, or (2) be able to translate and forward traffic between + TEXT[!MUST]: all internal nodes and all external nodes whose IP addresses + TEXT[!MUST]: numerically conflict with the internal network. + + SECTION: [Filtering Behavior](#section-5) + TEXT[!SHOULD,todo]: REQ-8: If application transparency is most important, it is + TEXT[!SHOULD,todo]: RECOMMENDED that a NAT have an "Endpoint-Independent Filtering" + TEXT[!SHOULD,todo]: behavior. + TEXT[!SHOULD,todo]: If a more stringent filtering behavior is most + TEXT[!SHOULD,todo]: important, it is RECOMMENDED that a NAT have an "Address-Dependent + TEXT[!SHOULD,todo]: Filtering" behavior. + TEXT[!MAY]: a) The filtering behavior MAY be an option configurable by the + TEXT[!MAY]: administrator of the NAT. + + SECTION: [Hairpinning Behavior](#section-6) + TEXT[!MUST,todo]: REQ-9: A NAT MUST support "Hairpinning". + TEXT[!MUST]: a) A NAT Hairpinning behavior MUST be "External source IP address + TEXT[!MUST]: and port". + + SECTION: [Application Level Gateways](#section-7) + TEXT[!SHOULD]: REQ-10: To eliminate interference with UNSAF NAT traversal + TEXT[!SHOULD]: mechanisms and allow integrity protection of UDP communications, + TEXT[!SHOULD]: NAT ALGs for UDP-based protocols SHOULD be turned off. + TEXT[!SHOULD]: a) If a NAT includes ALGs, it is RECOMMENDED that the NAT allow + TEXT[!SHOULD]: the NAT administrator to enable or disable each ALG separately. + + SECTION: [Deterministic Properties](#section-8) + TEXT[!MUST,exception]: REQ-11: A NAT MUST have deterministic behavior, i.e., it MUST NOT + TEXT[!MUST,exception]: change the NAT translation (Section 4) or the Filtering + TEXT[!MUST,exception]: (Section 5) Behavior at any point in time, or under any particular + TEXT[!MUST,exception]: conditions. + + SECTION: [ICMP Destination Unreachable Behavior](#section-9) + TEXT[!SHOULD]: The NAT's default configuration SHOULD NOT filter + TEXT[!SHOULD]: ICMP messages based on their source IP address. + TEXT[!SHOULD]: Such ICMP messages + TEXT[!SHOULD]: SHOULD be rewritten by the NAT (specifically, the IP headers and the + TEXT[!SHOULD]: ICMP payload) and forwarded to the appropriate internal or external + TEXT[!SHOULD]: host. + TEXT[!MUST]: Receipt of any sort of ICMP message MUST NOT + TEXT[!MUST]: destroy the NAT mapping. + TEXT[!MUST]: REQ-12: Receipt of any sort of ICMP message MUST NOT terminate the + TEXT[!MUST]: NAT mapping. + TEXT[!SHOULD]: a) The NAT's default configuration SHOULD NOT filter ICMP messages + TEXT[!SHOULD]: based on their source IP address. + TEXT[!SHOULD]: b) It is RECOMMENDED that a NAT support ICMP Destination + TEXT[!SHOULD]: Unreachable messages. + + SECTION: [Fragmentation of Outgoing Packets](#section-10) + TEXT[!MUST,todo]: REQ-13: If the packet received on an internal IP address has DF=1, + TEXT[!MUST,todo]: the NAT MUST send back an ICMP message "Fragmentation needed and + TEXT[!MUST,todo]: DF set" to the host, as described in [RFC0792]. + TEXT[!MUST,todo]: a) If the packet has DF=0, the NAT MUST fragment the packet and + TEXT[!MUST,todo]: SHOULD send the fragments in order. + + SECTION: [Receiving Fragmented Packets](#section-11) + TEXT[!MUST,todo]: REQ-14: A NAT MUST support receiving in-order and out-of-order + TEXT[!MUST,todo]: fragments, so it MUST have "Received Fragment Out of Order" + TEXT[!MUST,todo]: behavior. + TEXT[!MUST]: a) A NAT's out-of-order fragment processing mechanism MUST be + TEXT[!MUST]: designed so that fragmentation-based DoS attacks do not + TEXT[!MUST]: compromise the NAT's ability to process in-order and + TEXT[!MUST]: unfragmented IP packets. + + SECTION: [Requirements](#section-12) + TEXT[!MUST]: REQ-1: A NAT MUST have an "Endpoint-Independent Mapping" behavior. + TEXT[!SHOULD]: REQ-2: It is RECOMMENDED that a NAT have an "IP address pooling" + TEXT[!SHOULD]: behavior of "Paired". + TEXT[!MUST]: REQ-3: A NAT MUST NOT have a "Port assignment" behavior of "Port + TEXT[!MUST]: overloading". + TEXT[!SHOULD]: a) If the host's source port was in the range 0-1023, it is + TEXT[!SHOULD]: RECOMMENDED the NAT's source port be in the same range. + TEXT[!SHOULD]: If the + TEXT[!SHOULD]: host's source port was in the range 1024-65535, it is + TEXT[!SHOULD]: RECOMMENDED that the NAT's source port be in that range. + TEXT[!SHOULD]: REQ-4: It is RECOMMENDED that a NAT have a "Port parity + TEXT[!SHOULD]: preservation" behavior of "Yes". + TEXT[!MUST]: REQ-5: A NAT UDP mapping timer MUST NOT expire in less than two + TEXT[!MUST]: minutes, unless REQ-5a applies. + TEXT[!MAY]: a) For specific destination ports in the well-known port range + TEXT[!MAY]: (ports 0-1023), a NAT MAY have shorter UDP mapping timers that + TEXT[!MAY]: are specific to the IANA-registered application running over + TEXT[!MAY]: that specific destination port. + TEXT[!MAY]: b) The value of the NAT UDP mapping timer MAY be configurable. + TEXT[!SHOULD]: c) A default value of five minutes or more for the NAT UDP mapping + TEXT[!SHOULD]: timer is RECOMMENDED. + TEXT[!MUST]: REQ-6: The NAT mapping Refresh Direction MUST have a "NAT Outbound + TEXT[!MUST]: refresh behavior" of "True". + TEXT[!MAY]: a) The NAT mapping Refresh Direction MAY have a "NAT Inbound + TEXT[!MAY]: refresh behavior" of "True". + TEXT[!MUST]: REQ-7 A NAT device whose external IP interface can be configured + TEXT[!MUST]: dynamically MUST either (1) Automatically ensure that its internal + TEXT[!MUST]: network uses IP addresses that do not conflict with its external + TEXT[!MUST]: network, or (2) Be able to translate and forward traffic between + TEXT[!MUST]: all internal nodes and all external nodes whose IP addresses + TEXT[!MUST]: numerically conflict with the internal network. + TEXT[!SHOULD]: REQ-8: If application transparency is most important, it is + TEXT[!SHOULD]: RECOMMENDED that a NAT have "Endpoint-Independent Filtering" + TEXT[!SHOULD]: behavior. + TEXT[!SHOULD]: If a more stringent filtering behavior is most + TEXT[!SHOULD]: important, it is RECOMMENDED that a NAT have "Address-Dependent + TEXT[!SHOULD]: Filtering" behavior. + TEXT[!MAY]: a) The filtering behavior MAY be an option configurable by the + TEXT[!MAY]: administrator of the NAT. + TEXT[!MUST]: REQ-9: A NAT MUST support "Hairpinning". + TEXT[!MUST]: a) A NAT Hairpinning behavior MUST be "External source IP address + TEXT[!MUST]: and port". + TEXT[!SHOULD]: REQ-10: To eliminate interference with UNSAF NAT traversal + TEXT[!SHOULD]: mechanisms and allow integrity protection of UDP communications, + TEXT[!SHOULD]: NAT ALGs for UDP-based protocols SHOULD be turned off. + TEXT[!SHOULD]: a) If a NAT includes ALGs, it is RECOMMENDED that the NAT allow + TEXT[!SHOULD]: the NAT administrator to enable or disable each ALG separately. + TEXT[!MUST]: REQ-11: A NAT MUST have deterministic behavior, i.e., it MUST NOT + TEXT[!MUST]: change the NAT translation (Section 4) or the Filtering + TEXT[!MUST]: (Section 5) Behavior at any point in time, or under any particular + TEXT[!MUST]: conditions. + TEXT[!MUST]: REQ-12: Receipt of any sort of ICMP message MUST NOT terminate the + TEXT[!MUST]: NAT mapping. + TEXT[!SHOULD]: a) The NAT's default configuration SHOULD NOT filter ICMP messages + TEXT[!SHOULD]: based on their source IP address. + TEXT[!SHOULD]: b) It is RECOMMENDED that a NAT support ICMP Destination + TEXT[!SHOULD]: Unreachable messages. + TEXT[!MUST]: REQ-13 If the packet received on an internal IP address has DF=1, + TEXT[!MUST]: the NAT MUST send back an ICMP message "Fragmentation needed and + TEXT[!MUST]: DF set" to the host, as described in [RFC0792]. + TEXT[!MUST]: a) If the packet has DF=0, the NAT MUST fragment the packet and + TEXT[!MUST]: SHOULD send the fragments in order. + TEXT[!MUST]: REQ-14: A NAT MUST support receiving in-order and out-of-order + TEXT[!MUST]: fragments, so it MUST have "Received Fragment Out of Order" + TEXT[!MUST]: behavior. + TEXT[!MUST]: a) A NAT's out-of-order fragment processing mechanism MUST be + TEXT[!MUST]: designed so that fragmentation-based DoS attacks do not + TEXT[!MUST]: compromise the NAT's ability to process in-order and + TEXT[!MUST]: unfragmented IP packets. + +SPECIFICATION: https://www.rfc-editor.org/rfc/rfc4884 + SECTION: [Summary of Changes to ICMP](#section-3) + TEXT[!MAY]: An ICMP Extension Structure MAY be appended to ICMPv4 Destination + TEXT[!MAY]: Unreachable, Time Exceeded, and Parameter Problem messages. + TEXT[!MAY,implementation]: An ICMP Extension Structure MAY be appended to ICMPv6 Destination + TEXT[!MAY,implementation]: Unreachable, and Time Exceeded messages. + TEXT[!MUST,implementation,test]: When the ICMP Extension Structure is appended to an ICMP message + TEXT[!MUST,implementation,test]: and that ICMP message contains an "original datagram" field, the + TEXT[!MUST,implementation,test]: "original datagram" field MUST contain at least 128 octets. + TEXT[!MUST,implementation]: When the ICMP Extension Structure is appended to an ICMPv4 message + TEXT[!MUST,implementation]: and that ICMPv4 message contains an "original datagram" field, the + TEXT[!MUST,implementation]: "original datagram" field MUST be zero padded to the nearest + TEXT[!MUST,implementation]: 32-bit boundary. + TEXT[!MUST,implementation]: When the ICMP Extension Structure is appended to an ICMPv6 message + TEXT[!MUST,implementation]: and that ICMPv6 message contains an "original datagram" field, the + TEXT[!MUST,implementation]: "original datagram" field MUST be zero padded to the nearest + TEXT[!MUST,implementation]: 64-bit boundary. + TEXT[!SHOULD]: ICMP messages defined in the future SHOULD indicate whether or not + TEXT[!SHOULD]: they support the extension mechanism defined in this + TEXT[!SHOULD]: specification. + + SECTION: [ICMP Extensibility](#section-4) + TEXT[!MUST]: The length attribute MUST be specified when the ICMP Extension + TEXT[!MUST]: Structure is appended to the above mentioned ICMP messages. + TEXT[!MUST]: When the length attribute is specified, the "original datagram" field + TEXT[!MUST]: MUST be zero padded to the nearest 32-bit boundary. + TEXT[!MUST]: When the length attribute is specified, the "original datagram" field + TEXT[!MUST]: MUST be zero padded to the nearest 64-bit boundary. + TEXT[!MUST]: In order to achieve backwards compatibility, when the ICMP Extension + TEXT[!MUST]: Structure is appended to an ICMP message and that ICMP message + TEXT[!MUST]: contains an "original datagram" field, the "original datagram" field + TEXT[!MUST]: MUST contain at least 128 octets. + TEXT[!MUST]: If the original datagram did not + TEXT[!MUST]: contain 128 octets, the "original datagram" field MUST be zero padded + TEXT[!MUST]: to 128 octets. + + SECTION: [ICMP Messages That Can Be Extended](#section-4.6) + TEXT[!MAY]: The ICMP Extension Structure MAY be appended to messages of the + TEXT[!MAY]: following types: + TEXT[!MUST]: The ICMP Extension Structure MUST NOT be appended to any of the other + TEXT[!MUST]: ICMP messages mentioned in Section 4. + + SECTION: [Compliant Application Receives ICMP Message with No Extensions](#section-5.4) + TEXT[!MUST]: If the length attribute is zero, the compliant application + TEXT[!MUST]: MUST determine that the message contains no extensions. + + SECTION: [Compliant Application Receives ICMP Message with Non-Compliant](#section-5.5) + TEXT[!MUST]: If the length attribute is zero, the compliant application + TEXT[!MUST]: MUST determine that the message contains no extensions. + TEXT[!MUST]: So, to ease transition yet encourage compliant implementation, + TEXT[!MUST]: compliant TRACEROUTE implementations MUST include a non-default + TEXT[!MUST]: operation mode to also interpret non-compliant responses. + + SECTION: [The ICMP Extension Structure](#section-7) + TEXT[!MAY]: Having received an ICMP message + TEXT[!MAY]: with extensions, application software MAY process selected objects + TEXT[!MAY]: while ignoring others. + TEXT[!MUST]: As stated above, the total length of the ICMP message, including + TEXT[!MUST]: extensions, MUST NOT exceed the minimum reassembly buffer size. + +SPECIFICATION: https://www.rfc-editor.org/rfc/rfc5382 + SECTION: [Address and Port Mapping Behavior](#section-4.1) + TEXT[!MUST,todo]: REQ-1: A NAT MUST have an "Endpoint-Independent Mapping" behavior + TEXT[!MUST,todo]: for TCP. + + SECTION: [Internally Initiated Connections](#section-4.2) + TEXT[!MUST]: REQ-2: A NAT MUST support all valid sequences of TCP packets + TEXT[!MUST]: (defined in [RFC0793]) for connections initiated both internally + TEXT[!MUST]: as well as externally when the connection is permitted by the NAT. + TEXT[!MUST]: In particular: + TEXT[!MUST]: a) In addition to handling the TCP 3-way handshake mode of + TEXT[!MUST]: connection initiation, A NAT MUST handle the TCP simultaneous- + TEXT[!MUST]: open mode of connection initiation. + + SECTION: [Externally Initiated Connections](#section-4.3) + TEXT[!SHOULD]: REQ-3: If application transparency is most important, it is + TEXT[!SHOULD]: RECOMMENDED that a NAT have an "Endpoint-Independent Filtering" + TEXT[!SHOULD]: behavior for TCP. + TEXT[!SHOULD]: If a more stringent filtering behavior is most + TEXT[!SHOULD]: important, it is RECOMMENDED that a NAT have an "Address-Dependent + TEXT[!SHOULD]: Filtering" behavior. + TEXT[!MAY]: a) The filtering behavior MAY be an option configurable by the + TEXT[!MAY]: administrator of the NAT. + TEXT[!MAY]: b) The filtering behavior for TCP MAY be independent of the + TEXT[!MAY]: filtering behavior for UDP. + TEXT[!MUST]: REQ-4: A NAT MUST NOT respond to an unsolicited inbound SYN packet + TEXT[!MUST]: for at least 6 seconds after the packet is received. + TEXT[!MUST]: If during + TEXT[!MUST]: this interval the NAT receives and translates an outbound SYN for + TEXT[!MUST]: the connection the NAT MUST silently drop the original unsolicited + TEXT[!MUST]: inbound SYN packet. + TEXT[!SHOULD]: Otherwise, the NAT SHOULD send an ICMP Port + TEXT[!SHOULD]: Unreachable error (Type 3, Code 3) for the original SYN, unless + TEXT[!SHOULD]: REQ-4a applies. + TEXT[!MUST]: a) The NAT MUST silently drop the original SYN packet if sending a + TEXT[!MUST]: response violates the security policy of the NAT. + + SECTION: [NAT Session Refresh](#section-5) + TEXT[!MAY,todo]: REQ-5: If a NAT cannot determine whether the endpoints of a TCP + TEXT[!MAY,todo]: connection are active, it MAY abandon the session if it has been + TEXT[!MAY,todo]: idle for some time. + TEXT[!MUST,todo]: In such cases, the value of the "established + TEXT[!MUST,todo]: connection idle-timeout" MUST NOT be less than 2 hours 4 minutes. + TEXT[!MUST,todo]: The value of the "transitory connection idle-timeout" MUST NOT be + TEXT[!MUST,todo]: less than 4 minutes. + TEXT[!MAY]: a) The value of the NAT idle-timeouts MAY be configurable. + TEXT[!MAY]: A NAT MAY hold state for a connection in + TEXT[!MAY]: TIME_WAIT state to accommodate retransmissions of the last ACK. + TEXT[!MAY]: When a NAT abandons a live connection, for + TEXT[!MAY]: example due to a timeout expiring, the NAT MAY either send TCP RST + TEXT[!MAY]: packets to the endpoints or MAY silently abandon the connection. + + SECTION: [Application Level Gateways](#section-6) + TEXT[!SHOULD]: REQ-6: If a NAT includes ALGs that affect TCP, it is RECOMMENDED + TEXT[!SHOULD]: that all of those ALGs (except for FTP [RFC0959]) be disabled by + TEXT[!SHOULD]: default. + + SECTION: [Port Assignment](#section-7.1) + TEXT[!MUST,implementation,test]: REQ-7: A NAT MUST NOT have a "Port assignment" behavior of "Port + TEXT[!MUST,implementation,test]: overloading" for TCP. + + SECTION: [Hairpinning Behavior](#section-7.2) + TEXT[!MUST]: REQ-8: A NAT MUST support "hairpinning" for TCP. + TEXT[!MUST]: a) A NAT's hairpinning behavior MUST be of type "External source + TEXT[!MUST]: IP address and port". + + SECTION: [ICMP Responses to TCP Packets](#section-7.3) + TEXT[!SHOULD]: REQ-9: If a NAT translates TCP, it SHOULD translate ICMP Destination + TEXT[!SHOULD]: Unreachable (Type 3) messages. + TEXT[!MUST]: REQ-10: Receipt of any sort of ICMP message MUST NOT terminate the + TEXT[!MUST]: NAT mapping or TCP connection for which the ICMP was generated. + + SECTION: [Requirements](#section-8) + TEXT[!MUST]: REQ-1: A NAT MUST have an "Endpoint-Independent Mapping" behavior + TEXT[!MUST]: for TCP. + TEXT[!MUST]: REQ-2: A NAT MUST support all valid sequences of TCP packets + TEXT[!MUST]: (defined in [RFC0793]) for connections initiated both internally + TEXT[!MUST]: as well as externally when the connection is permitted by the NAT. + TEXT[!MUST]: In particular: + TEXT[!MUST]: a) In addition to handling the TCP 3-way handshake mode of + TEXT[!MUST]: connection initiation, A NAT MUST handle the TCP simultaneous- + TEXT[!MUST]: open mode of connection initiation. + TEXT[!SHOULD]: REQ-3: If application transparency is most important, it is + TEXT[!SHOULD]: RECOMMENDED that a NAT have an "Endpoint-Independent Filtering" + TEXT[!SHOULD]: behavior for TCP. + TEXT[!SHOULD]: If a more stringent filtering behavior is most + TEXT[!SHOULD]: important, it is RECOMMENDED that a NAT have an "Address-Dependent + TEXT[!SHOULD]: Filtering" behavior. + TEXT[!MAY]: a) The filtering behavior MAY be an option configurable by the + TEXT[!MAY]: administrator of the NAT. + TEXT[!MAY]: b) The filtering behavior for TCP MAY be independent of the + TEXT[!MAY]: filtering behavior for UDP. + TEXT[!MUST]: REQ-4: A NAT MUST NOT respond to an unsolicited inbound SYN packet + TEXT[!MUST]: for at least 6 seconds after the packet is received. + TEXT[!MUST]: If during + TEXT[!MUST]: this interval the NAT receives and translates an outbound SYN for + TEXT[!MUST]: the connection the NAT MUST silently drop the original unsolicited + TEXT[!MUST]: inbound SYN packet. + TEXT[!SHOULD]: Otherwise, the NAT SHOULD send an ICMP Port + TEXT[!SHOULD]: Unreachable error (Type 3, Code 3) for the original SYN, unless + TEXT[!SHOULD]: REQ-4a applies. + TEXT[!MUST]: a) The NAT MUST silently drop the original SYN packet if sending a + TEXT[!MUST]: response violates the security policy of the NAT. + TEXT[!MAY]: REQ-5: If a NAT cannot determine whether the endpoints of a TCP + TEXT[!MAY]: connection are active, it MAY abandon the session if it has been + TEXT[!MAY]: idle for some time. + TEXT[!MUST]: In such cases, the value of the "established + TEXT[!MUST]: connection idle-timeout" MUST NOT be less than 2 hours 4 minutes. + TEXT[!MUST]: The value of the "transitory connection idle-timeout" MUST NOT be + TEXT[!MUST]: less than 4 minutes. + TEXT[!MAY]: a) The value of the NAT idle-timeouts MAY be configurable. + TEXT[!SHOULD]: REQ-6: If a NAT includes ALGs that affect TCP, it is RECOMMENDED + TEXT[!SHOULD]: that all of those ALGs (except for FTP [RFC0959]) be disabled by + TEXT[!SHOULD]: default. + TEXT[!MUST]: REQ-7: A NAT MUST NOT have a "Port assignment" behavior of "Port + TEXT[!MUST]: overloading" for TCP. + TEXT[!MUST]: REQ-8: A NAT MUST support "hairpinning" for TCP. + TEXT[!MUST]: a) A NAT's hairpinning behavior MUST be of type "External source + TEXT[!MUST]: IP address and port". + TEXT[!SHOULD]: REQ-9: If a NAT translates TCP, it SHOULD translate ICMP Destination + TEXT[!SHOULD]: Unreachable (Type 3) messages. + TEXT[!MUST]: REQ-10: Receipt of any sort of ICMP message MUST NOT terminate the + TEXT[!MUST]: NAT mapping or TCP connection for which the ICMP was generated. diff --git a/.duvet/specifications/www.rfc-editor.org/rfc/rfc4787.txt b/.duvet/specifications/www.rfc-editor.org/rfc/rfc4787.txt new file mode 100644 index 0000000000..00219c79bf --- /dev/null +++ b/.duvet/specifications/www.rfc-editor.org/rfc/rfc4787.txt @@ -0,0 +1,1627 @@ + + + + + + +Network Working Group F. Audet, Ed. +Request for Comments: 4787 Nortel Networks +BCP: 127 C. Jennings +Category: Best Current Practice Cisco Systems + January 2007 + + + Network Address Translation (NAT) Behavioral Requirements + for Unicast UDP + +Status of This Memo + + This document specifies an Internet Best Current Practices for the + Internet Community, and requests discussion and suggestions for + improvements. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The IETF Trust (2007). + +Abstract + + This document defines basic terminology for describing different + types of Network Address Translation (NAT) behavior when handling + Unicast UDP and also defines a set of requirements that would allow + many applications, such as multimedia communications or online + gaming, to work consistently. Developing NATs that meet this set of + requirements will greatly increase the likelihood that these + applications will function properly. + + + + + + + + + + + + + + + + + + + + + + +Audet & Jennings Best Current Practice [Page 1] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + +Table of Contents + + 1. Applicability Statement . . . . . . . . . . . . . . . . . . . 3 + 2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3 + 3. Terminology . . . . . . . . . . . . . . . . . . . . . . . . . 4 + 4. Network Address and Port Translation Behavior . . . . . . . . 5 + 4.1. Address and Port Mapping . . . . . . . . . . . . . . . . . 5 + 4.2. Port Assignment . . . . . . . . . . . . . . . . . . . . . 9 + 4.2.1. Port Assignment Behavior . . . . . . . . . . . . . . . 9 + 4.2.2. Port Parity . . . . . . . . . . . . . . . . . . . . . 11 + 4.2.3. Port Contiguity . . . . . . . . . . . . . . . . . . . 11 + 4.3. Mapping Refresh . . . . . . . . . . . . . . . . . . . . . 12 + 4.4. Conflicting Internal and External IP Address Spaces . . . 13 + 5. Filtering Behavior . . . . . . . . . . . . . . . . . . . . . . 15 + 6. Hairpinning Behavior . . . . . . . . . . . . . . . . . . . . . 16 + 7. Application Level Gateways . . . . . . . . . . . . . . . . . . 17 + 8. Deterministic Properties . . . . . . . . . . . . . . . . . . . 18 + 9. ICMP Destination Unreachable Behavior . . . . . . . . . . . . 19 + 10. Fragmentation of Outgoing Packets . . . . . . . . . . . . . . 20 + 11. Receiving Fragmented Packets . . . . . . . . . . . . . . . . . 20 + 12. Requirements . . . . . . . . . . . . . . . . . . . . . . . . . 21 + 13. Security Considerations . . . . . . . . . . . . . . . . . . . 24 + 14. IAB Considerations . . . . . . . . . . . . . . . . . . . . . . 25 + 15. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 26 + 16. References . . . . . . . . . . . . . . . . . . . . . . . . . . 26 + 16.1. Normative References . . . . . . . . . . . . . . . . . . . 26 + 16.2. Informative References . . . . . . . . . . . . . . . . . . 26 + + + + + + + + + + + + + + + + + + + + + + + + +Audet & Jennings Best Current Practice [Page 2] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + +1. Applicability Statement + + The purpose of this specification is to define a set of requirements + for NATs that would allow many applications, such as multimedia + communications or online gaming, to work consistently. Developing + NATs that meet this set of requirements will greatly increase the + likelihood that these applications will function properly. + + The requirements of this specification apply to Traditional NATs as + described in [RFC2663]. + + This document is meant to cover NATs of any size, from small + residential NATs to large Enterprise NATs. However, it should be + understood that Enterprise NATs normally provide much more than just + NAT capabilities; for example, they typically provide firewall + functionalities. A comprehensive description of firewall behaviors + and associated requirements is specifically out-of-scope for this + specification. However, this specification does cover basic firewall + aspects present in NATs (see Section 5). + + Approaches using directly signaled control of middle boxes are out of + scope. + + UDP Relays (e.g., Traversal Using Relay NAT [TURN]) are out of scope. + + Application aspects are out of scope, as the focus here is strictly + on the NAT itself. + + This document only covers aspects of NAT traversal related to Unicast + UDP [RFC0768] over IP [RFC0791] and their dependencies on other + protocols. + +2. Introduction + + Network Address Translators (NATs) are well known to cause very + significant problems with applications that carry IP addresses in the + payload (see [RFC3027]). Applications that suffer from this problem + include Voice Over IP and Multimedia Over IP (e.g., SIP [RFC3261] and + H.323 [ITU.H323]), as well as online gaming. + + Many techniques are used to attempt to make realtime multimedia + applications, online games, and other applications work across NATs. + Application Level Gateways [RFC2663] are one such mechanism. STUN + [RFC3489bis] describes a UNilateral Self-Address Fixing (UNSAF) + mechanism [RFC3424]. Teredo [RFC4380] describes an UNSAF mechanism + consisting of tunnelling IPv6 [RFC2460] over UDP/IPv4. UDP Relays + have also been used to enable applications across NATs, but these are + generally seen as a solution of last resort. Interactive + + + +Audet & Jennings Best Current Practice [Page 3] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + + Connectivity Establishment [ICE] describes a methodology for using + many of these techniques and avoiding a UDP relay, unless the type of + NAT is such that it forces the use of such a UDP relay. This + specification defines requirements for improving NATs. Meeting these + requirements ensures that applications will not be forced to use UDP + relay. + + As pointed out in UNSAF [RFC3424], "From observations of deployed + networks, it is clear that different NAT box implementations vary + widely in terms of how they handle different traffic and addressing + cases". This wide degree of variability is one factor in the overall + brittleness introduced by NATs and makes it extremely difficult to + predict how any given protocol will behave on a network traversing + NAT. Discussions with many of the major NAT vendors have made it + clear that they would prefer to deploy NATs that were deterministic + and caused the least harm to applications while still meeting the + requirements that caused their customers to deploy NATs in the first + place. The problem NAT vendors face is that they are not sure how + best to do that or how to document their NATs' behavior. + + The goals of this document are to define a set of common terminology + for describing the behavior of NATs and to produce a set of + requirements on a specific set of behaviors for NATs. + + This document forms a common set of requirements that are simple and + useful for voice, video, and games, which can be implemented by NAT + vendors. This document will simplify the analysis of protocols for + deciding whether or not they work in this environment and will allow + providers of services that have NAT traversal issues to make + statements about where their applications will work and where they + will not, as well as to specify their own NAT requirements. + +3. Terminology + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [RFC2119]. + + Readers are urged to refer to [RFC2663] for information on NAT + taxonomy and terminology. Traditional NAT is the most common type of + NAT device deployed. Readers may refer to [RFC3022] for detailed + information on traditional NAT. Traditional NAT has two main + varieties -- Basic NAT and Network Address/Port Translator (NAPT). + + NAPT is by far the most commonly deployed NAT device. NAPT allows + multiple internal hosts to share a single public IP address + simultaneously. When an internal host opens an outgoing TCP or UDP + session through a NAPT, the NAPT assigns the session a public IP + + + +Audet & Jennings Best Current Practice [Page 4] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + + address and port number, so that subsequent response packets from the + external endpoint can be received by the NAPT, translated, and + forwarded to the internal host. The effect is that the NAPT + establishes a NAT session to translate the (private IP address, + private port number) tuple to a (public IP address, public port + number) tuple, and vice versa, for the duration of the session. An + issue of relevance to peer-to-peer applications is how the NAT + behaves when an internal host initiates multiple simultaneous + sessions from a single (private IP, private port) endpoint to + multiple distinct endpoints on the external network. In this + specification, the term "NAT" refers to both "Basic NAT" and "Network + Address/Port Translator (NAPT)". + + This document uses the term "session" as defined in RFC 2663: "TCP/ + UDP sessions are uniquely identified by the tuple of (source IP + address, source TCP/UDP ports, target IP address, target TCP/UDP + Port)". + + This document uses the term "address and port mapping" as the + translation between an external address and port and an internal + address and port. Note that this is not the same as an "address + binding" as defined in RFC 2663. + + This document uses IANA terminology for port ranges, i.e., "Well + Known Ports" is 0-1023, "Registered" is 1024-49151, and "Dynamic + and/or Private" is 49152-65535, as defined in + http://www.iana.org/assignments/port-numbers. + + STUN [RFC3489] used the terms "Full Cone", "Restricted Cone", "Port + Restricted Cone", and "Symmetric" to refer to different variations of + NATs applicable to UDP only. Unfortunately, this terminology has + been the source of much confusion, as it has proven inadequate at + describing real-life NAT behavior. This specification therefore + refers to specific individual NAT behaviors instead of using the + Cone/Symmetric terminology. + +4. Network Address and Port Translation Behavior + + This section describes the various NAT behaviors applicable to NATs. + +4.1. Address and Port Mapping + + When an internal endpoint opens an outgoing session through a NAT, + the NAT assigns the session an external IP address and port number so + that subsequent response packets from the external endpoint can be + received by the NAT, translated, and forwarded to the internal + endpoint. This is a mapping between an internal IP address and port + IP:port and external IP:port tuple. It establishes the translation + + + +Audet & Jennings Best Current Practice [Page 5] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + + that will be performed by the NAT for the duration of the session. + For many applications, it is important to distinguish the behavior of + the NAT when there are multiple simultaneous sessions established to + different external endpoints. + + The key behavior to describe is the criteria for reuse of a mapping + for new sessions to external endpoints, after establishing a first + mapping between an internal X:x address and port and an external + Y1:y1 address tuple. Let's assume that the internal IP address and + port X:x are mapped to X1':x1' for this first session. The endpoint + then sends from X:x to an external address Y2:y2 and gets a mapping + of X2':x2' on the NAT. The relationship between X1':x1' and X2':x2' + for various combinations of the relationship between Y1:y1 and Y2:y2 + is critical for describing the NAT behavior. This arrangement is + illustrated in the following diagram: + + E + +------+ +------+ x + | Y1 | | Y2 | t + +--+---+ +---+--+ e + | Y1:y1 Y2:y2 | r + +----------+ +----------+ n + | | a + X1':x1' | | X2':x2' l + +--+---+-+ + ...........| NAT |............... + +--+---+-+ I + | | n + X:x | | X:x t + ++---++ e + | X | r + +-----+ n + a + l + + Address and Port Mapping + + The following address and port mapping behavior are defined: + + Endpoint-Independent Mapping: + + The NAT reuses the port mapping for subsequent packets sent + from the same internal IP address and port (X:x) to any + external IP address and port. Specifically, X1':x1' equals + X2':x2' for all values of Y2:y2. + + + + + + +Audet & Jennings Best Current Practice [Page 6] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + + Address-Dependent Mapping: + + The NAT reuses the port mapping for subsequent packets sent + from the same internal IP address and port (X:x) to the same + external IP address, regardless of the external port. + Specifically, X1':x1' equals X2':x2' if and only if, Y2 equals + Y1. + + Address and Port-Dependent Mapping: + + The NAT reuses the port mapping for subsequent packets sent + from the same internal IP address and port (X:x) to the same + external IP address and port while the mapping is still active. + Specifically, X1':x1' equals X2':x2' if and only if, Y2:y2 + equals Y1:y1. + + It is important to note that these three possible choices make no + difference to the security properties of the NAT. The security + properties are fully determined by which packets the NAT allows in + and which it does not. This is determined by the filtering behavior + in the filtering portions of the NAT. + + REQ-1: A NAT MUST have an "Endpoint-Independent Mapping" behavior. + + Justification: In order for UNSAF methods to work, REQ-1 needs to be + met. Failure to meet REQ-1 will force the use of a UDP relay, + which is very often impractical. + + Some NATs are capable of assigning IP addresses from a pool of IP + addresses on the external side of the NAT, as opposed to just a + single IP address. This is especially common with larger NATs. Some + NATs use the external IP address mapping in an arbitrary fashion + (i.e., randomly): one internal IP address could have multiple + external IP address mappings active at the same time for different + sessions. These NATs have an "IP address pooling" behavior of + "Arbitrary". Some large Enterprise NATs use an IP address pooling + behavior of "Arbitrary" as a means of hiding the IP address assigned + to specific endpoints by making their assignment less predictable. + Other NATs use the same external IP address mapping for all sessions + associated with the same internal IP address. These NATs have an "IP + address pooling" behavior of "Paired". NATs that use an "IP address + pooling" behavior of "Arbitrary" can cause issues for applications + that use multiple ports from the same endpoint, but that do not + negotiate IP addresses individually (e.g., some applications using + RTP and RTCP). + + + + + + +Audet & Jennings Best Current Practice [Page 7] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + + REQ-2: It is RECOMMENDED that a NAT have an "IP address pooling" + behavior of "Paired". Note that this requirement is not + applicable to NATs that do not support IP address pooling. + + Justification: This will allow applications that use multiple ports + originating from the same internal IP address to also have the + same external IP address. This is to avoid breaking peer-to-peer + applications that are not capable of negotiating the IP address + for RTP and the IP address for RTCP separately. As such it is + envisioned that this requirement will become less important as + applications become NAT-friendlier with time. The main reason why + this requirement is here is that in a peer-to-peer application, + you are subject to the other peer's mistake. In particular, in + the context of SIP, if my application supports the extensions + defined in [RFC3605] for indicating RTP and RTCP addresses and + ports separately, but the other peer does not, there may still be + breakage in the form of the stream losing RTCP packets. This + requirement will avoid the loss of RTP in this context, although + the loss of RTCP may be inevitable in this particular example. It + is also worth noting that RFC 3605 is unfortunately not a + mandatory part of SIP [RFC3261]. Therefore, this requirement will + address a particularly nasty problem that will prevail for a + significant period of time. + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Audet & Jennings Best Current Practice [Page 8] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + +4.2. Port Assignment + +4.2.1. Port Assignment Behavior + + This section uses the following diagram for reference. + + E + +-------+ +-------+ x + | Y1 | | Y2 | t + +---+---+ +---+---+ e + | Y1:y1 Y2:y2 | r + +---------+ +---------+ n + | | a + X1':x1' | | X2':x2' l + +--+---+--+ + ...........| NAT |............... + +--+---+--+ I + | | n + +---------+ +---------+ t + | X1:x1 X2:x2 | e + +---+---+ +---+---+ r + | X1 | | X2 | n + +-------+ +-------+ a + l + + Port Assignment + + Some NATs attempt to preserve the port number used internally when + assigning a mapping to an external IP address and port (e.g., x1=x1', + x2=x2'). This port assignment behavior is referred to as "port + preservation". In case of port collision, these NATs attempt a + variety of techniques for coping. For example, some NATs will + overridden the previous mapping to preserve the same port. Other + NATs will assign a different IP address from a pool of external IP + addresses; this is only possible as long as the NAT has enough + external IP addresses; if the port is already in use on all available + external IP addresses, then these NATs will pick a different port + (i.e., they don't do port preservation anymore). + + Some NATs use "Port overloading", i.e., they always use port + preservation even in the case of collision (i.e., X1'=X2' and + x1=x2=x1'=x2'). Most applications will fail if the NAT uses "Port + overloading". + + A NAT that does not attempt to make the external port numbers match + the internal port numbers in any case is referred to as "no port + preservation". + + + + +Audet & Jennings Best Current Practice [Page 9] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + + When NATs do allocate a new source port, there is the issue of which + IANA-defined range of port to choose. The ranges are "well-known" + from 0 to 1023, "registered" from 1024 to 49151, and "dynamic/ + private" from 49152 through 65535. For most protocols, these are + destination ports and not source ports, so mapping a source port to a + source port that is already registered is unlikely to have any bad + effects. Some NATs may choose to use only the ports in the dynamic + range; the only downside of this practice is that it limits the + number of ports available. Other NAT devices may use everything but + the well-known range and may prefer to use the dynamic range first, + or possibly avoid the actual registered ports in the registered + range. Other NATs preserve the port range if it is in the well-known + range. [RFC0768] specifies that the source port is set to zero if no + reply packets are expected. In this case, it does not matter what + the NAT maps it to, as the source port will not be used. However, + many common OS APIs do not allow a user to send from port zero, + applications do not use port zero, and the behavior of various + existing NATs with regards to a packet with a source of port zero is + unknown. This document does not specify any normative behavior for a + NAT when handling a packet with a source port of zero which means + that applications cannot count on any sort of deterministic behavior + for these packets. + + REQ-3: A NAT MUST NOT have a "Port assignment" behavior of "Port + overloading". + + a) If the host's source port was in the range 0-1023, it is + RECOMMENDED the NAT's source port be in the same range. If the + host's source port was in the range 1024-65535, it is + RECOMMENDED that the NAT's source port be in that range. + + Justification: This requirement must be met in order to enable two + applications on the internal side of the NAT both to use the same + port to try to communicate with the same destination. NATs that + implement port preservation have to deal with conflicts on ports, + and the multiple code paths this introduces often result in + nondeterministic behavior. However, it should be understood that + when a port is randomly assigned, it may just randomly happen to + be assigned the same port. Applications must, therefore, be able + to deal with both port preservation and no port preservation. + + a) Certain applications expect the source UDP port to be in the + well-known range. See the discussion of Network File System + port expectations in [RFC2623] for an example. + + + + + + + +Audet & Jennings Best Current Practice [Page 10] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + +4.2.2. Port Parity + + Some NATs preserve the parity of the UDP port, i.e., an even port + will be mapped to an even port, and an odd port will be mapped to an + odd port. This behavior respects the [RFC3550] rule that RTP use + even ports, and RTCP use odd ports. RFC 3550 allows any port numbers + to be used for RTP and RTCP if the two numbers are specified + separately; for example, using [RFC3605]. However, some + implementations do not include RFC 3605, and do not recognize when + the peer has specified the RTCP port separately using RFC 3605. If + such an implementation receives an odd RTP port number from the peer + (perhaps after having been translated by a NAT), and then follows the + RFC 3550 rule to change the RTP port to the next lower even number, + this would obviously result in the loss of RTP. NAT-friendly + application aspects are outside the scope of this document. It is + expected that this issue will fade away with time, as implementations + improve. Preserving the port parity allows for supporting + communication with peers that do not support explicit specification + of both RTP and RTCP port numbers. + + REQ-4: It is RECOMMENDED that a NAT have a "Port parity + preservation" behavior of "Yes". + + Justification: This is to avoid breaking peer-to-peer applications + that do not explicitly and separately specify RTP and RTCP port + numbers and that follow the RFC 3550 rule to decrement an odd RTP + port to make it even. The same considerations apply, as per the + IP address pooling requirement. + +4.2.3. Port Contiguity + + Some NATs attempt to preserve the port contiguity rule of RTCP=RTP+1. + These NATs do things like sequential assignment or port reservation. + Sequential port assignment assumes that the application will open a + mapping for RTP first and then open a mapping for RTCP. It is not + practical to enforce this requirement on all applications. + Furthermore, there is a problem with glare if many applications (or + endpoints) are trying to open mappings simultaneously. Port + preservation is also problematic since it is wasteful, especially + considering that a NAT cannot reliably distinguish between RTP over + UDP and other UDP packets where there is no contiguity rule. For + those reasons, it would be too complex to attempt to preserve the + contiguity rule by suggesting specific NAT behavior, and it would + certainly break the deterministic behavior rule. + + In order to support both RTP and RTCP, it will therefore be necessary + that applications follow rules to negotiate RTP and RTCP separately, + and account for the very real possibility that the RTCP=RTP+1 rule + + + +Audet & Jennings Best Current Practice [Page 11] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + + will be broken. As this is an application requirement, it is outside + the scope of this document. + +4.3. Mapping Refresh + + NAT mapping timeout implementations vary, but include the timer's + value and the way the mapping timer is refreshed to keep the mapping + alive. + + The mapping timer is defined as the time a mapping will stay active + without packets traversing the NAT. There is great variation in the + values used by different NATs. + + REQ-5: A NAT UDP mapping timer MUST NOT expire in less than two + minutes, unless REQ-5a applies. + + a) For specific destination ports in the well-known port range + (ports 0-1023), a NAT MAY have shorter UDP mapping timers that + are specific to the IANA-registered application running over + that specific destination port. + + b) The value of the NAT UDP mapping timer MAY be configurable. + + c) A default value of five minutes or more for the NAT UDP mapping + timer is RECOMMENDED. + + Justification: This requirement is to ensure that the timeout is + long enough to avoid too-frequent timer refresh packets. + + a) Some UDP protocols using UDP use very short-lived connections. + There can be very many such connections; keeping them all in a + connections table could cause considerable load on the NAT. + Having shorter timers for these specific applications is, + therefore, an optimization technique. It is important that the + shorter timers applied to specific protocols be used sparingly, + and only for protocols using well-known destination ports that + are known to have a shorter timer, and that are known not to be + used by any applications for other purposes. + + b) Configuration is desirable for adapting to specific networks + and troubleshooting. + + c) This default is to avoid too-frequent timer refresh packets. + + Some NATs keep the mapping active (i.e., refresh the timer value) + when a packet goes from the internal side of the NAT to the external + side of the NAT. This is referred to as having a NAT Outbound + refresh behavior of "True". + + + +Audet & Jennings Best Current Practice [Page 12] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + + Some NATs keep the mapping active when a packet goes from the + external side of the NAT to the internal side of the NAT. This is + referred to as having a NAT Inbound Refresh Behavior of "True". + + Some NATs keep the mapping active on both, in which case, both + properties are "True". + + REQ-6: The NAT mapping Refresh Direction MUST have a "NAT Outbound + refresh behavior" of "True". + + a) The NAT mapping Refresh Direction MAY have a "NAT Inbound + refresh behavior" of "True". + + Justification: Outbound refresh is necessary for allowing the client + to keep the mapping alive. + + a) Inbound refresh may be useful for applications with no outgoing + UDP traffic. However, allowing inbound refresh may allow an + external attacker or misbehaving application to keep a mapping + alive indefinitely. This may be a security risk. Also, if the + process is repeated with different ports, over time, it could + use up all the ports on the NAT. + +4.4. Conflicting Internal and External IP Address Spaces + + Many NATs, particularly consumer-level devices designed to be + deployed by nontechnical users, routinely obtain their external IP + address, default router, and other IP configuration information for + their external interface dynamically from an external network, such + as an upstream ISP. The NAT, in turn, automatically sets up its own + internal subnet in one of the private IP address spaces assigned to + this purpose in [RFC1918], typically providing dynamic IP + configuration services for hosts on this internal network. + + Auto-configuration of NATs and private networks can be problematic, + however, if the NAT's external network is also in RFC 1918 private + address space. In a common scenario, an ISP places its customers + behind a NAT and hands out private RFC 1918 addresses to them. Some + of these customers, in turn, deploy consumer-level NATs, which, in + effect, act as "second-level" NATs, multiplexing their own private + RFC 1918 IP subnets onto the single RFC 1918 IP address provided by + the ISP. There is no inherent guarantee, in this case, that the + ISP's "intermediate" privately-addressed network and the customer's + internal privately-addressed network will not use numerically + identical or overlapping RFC 1918 IP subnets. Furthermore, customers + of consumer-level NATs cannot be expected to have the technical + + + + + +Audet & Jennings Best Current Practice [Page 13] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + + knowledge to prevent this scenario from occurring by manually + configuring their internal network with non-conflicting RFC 1918 + subnets. + + NAT vendors need to design their NATs to ensure that they function + correctly and robustly even in such problematic scenarios. One + possible solution is for the NAT to ensure that whenever its external + link is configured with an RFC 1918 private IP address, the NAT + automatically selects a different, non-conflicting RFC 1918 IP subnet + for its internal network. A disadvantage of this solution is that, + if the NAT's external interface is dynamically configured or re- + configured after its internal network is already in use, then the NAT + may have to renumber its entire internal network dynamically if it + detects a conflict. + + An alternative solution is for the NAT to be designed so that it can + translate and forward traffic correctly, even when its external and + internal interfaces are configured with numerically overlapping IP + subnets. In this scenario, for example, if the NAT's external + interface has been assigned an IP address P in RFC 1918 space, then + there might also be an internal node I having the same RFC 1918 + private IP address P. An IP packet with destination address P on the + external network is directed at the NAT, whereas an IP packet with + the same destination address P on the internal network is directed at + node I. The NAT therefore needs to maintain a clear operational + distinction between "external IP addresses" and "internal IP + addresses" to avoid confusing internal node I with its own external + interface. In general, the NAT needs to allow all internal nodes + (including I) to communicate with all external nodes having public + (non-RFC 1918) IP addresses, or having private IP addresses that do + not conflict with the addresses used by its internal network. + + REQ-7: A NAT device whose external IP interface can be configured + dynamically MUST either (1) automatically ensure that its internal + network uses IP addresses that do not conflict with its external + network, or (2) be able to translate and forward traffic between + all internal nodes and all external nodes whose IP addresses + numerically conflict with the internal network. + + Justification: If a NAT's external and internal interfaces are + configured with overlapping IP subnets, then there is, of course, + no way for an internal host with RFC 1918 IP address Q to initiate + a direct communication session to an external node having the same + RFC 1918 address Q, or to other external nodes with IP addresses + that numerically conflict with the internal subnet. Such nodes + can still open communication sessions indirectly via NAT traversal + techniques, however, with the help of a third-party server, such + as a STUN server having a public, non-RFC 1918 IP address. In + + + +Audet & Jennings Best Current Practice [Page 14] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + + this case, nodes with conflicting private RFC 1918 addresses on + opposite sides of the second-level NAT can communicate with each + other via their respective temporary public endpoints on the main + Internet, as long as their common, first-level NAT (e.g., the + upstream ISP's NAT) supports hairpinning behavior, as described in + Section 6. + +5. Filtering Behavior + + This section describes various filtering behaviors observed in NATs. + + When an internal endpoint opens an outgoing session through a NAT, + the NAT assigns a filtering rule for the mapping between an internal + IP:port (X:x) and external IP:port (Y:y) tuple. + + The key behavior to describe is what criteria are used by the NAT to + filter packets originating from specific external endpoints. + + Endpoint-Independent Filtering: + + The NAT filters out only packets not destined to the internal + address and port X:x, regardless of the external IP address and + port source (Z:z). The NAT forwards any packets destined to + X:x. In other words, sending packets from the internal side of + the NAT to any external IP address is sufficient to allow any + packets back to the internal endpoint. + + Address-Dependent Filtering: + + The NAT filters out packets not destined to the internal + address X:x. Additionally, the NAT will filter out packets + from Y:y destined for the internal endpoint X:x if X:x has not + sent packets to Y:any previously (independently of the port + used by Y). In other words, for receiving packets from a + specific external endpoint, it is necessary for the internal + endpoint to send packets first to that specific external + endpoint's IP address. + + Address and Port-Dependent Filtering: + + This is similar to the previous behavior, except that the + external port is also relevant. The NAT filters out packets + not destined for the internal address X:x. Additionally, the + NAT will filter out packets from Y:y destined for the internal + endpoint X:x if X:x has not sent packets to Y:y previously. In + other words, for receiving packets from a specific external + endpoint, it is necessary for the internal endpoint to send + packets first to that external endpoint's IP address and port. + + + +Audet & Jennings Best Current Practice [Page 15] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + + REQ-8: If application transparency is most important, it is + RECOMMENDED that a NAT have an "Endpoint-Independent Filtering" + behavior. If a more stringent filtering behavior is most + important, it is RECOMMENDED that a NAT have an "Address-Dependent + Filtering" behavior. + + a) The filtering behavior MAY be an option configurable by the + administrator of the NAT. + + Justification: The recommendation to use Endpoint-Independent + Filtering is aimed at maximizing application transparency; in + particular, for applications that receive media simultaneously + from multiple locations (e.g., gaming), or applications that use + rendezvous techniques. However, it is also possible that, in some + circumstances, it may be preferable to have a more stringent + filtering behavior. Filtering independently of the external + endpoint is not as secure: An unauthorized packet could get + through a specific port while the port was kept open if it was + lucky enough to find the port open. In theory, filtering based on + both IP address and port is more secure than filtering based only + on the IP address (because the external endpoint could, in + reality, be two endpoints behind another NAT, where one of the two + endpoints is an attacker). However, such a policy could interfere + with applications that expect to receive UDP packets on more than + one UDP port. Using Endpoint-Independent Filtering or Address- + Dependent Filtering instead of Address and Port-Dependent + Filtering on a NAT (say, NAT-A) also has benefits when the other + endpoint is behind a non-BEHAVE compliant NAT (say, NAT-B) that + does not support REQ-1. When the endpoints use ICE, if NAT-A uses + Address and Port-Dependent Filtering, connectivity will require a + UDP relay. However, if NAT-A uses Endpoint-Independent Filtering + or Address-Dependent Filtering, ICE will ultimately find + connectivity without requiring a UDP relay. Having the filtering + behavior being an option configurable by the administrator of the + NAT ensures that a NAT can be used in the widest variety of + deployment scenarios. + +6. Hairpinning Behavior + + If two hosts (called X1 and X2) are behind the same NAT and + exchanging traffic, the NAT may allocate an address on the outside of + the NAT for X2, called X2':x2'. If X1 sends traffic to X2':x2', it + goes to the NAT, which must relay the traffic from X1 to X2. This is + referred to as hairpinning and is illustrated below. + + + + + + + +Audet & Jennings Best Current Practice [Page 16] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + + NAT + +----+ from X1:x1 to X2':x2' +-----+ X1':x1' + | X1 |>>>>>>>>>>>>>>>>>>>>>>>>>>>>>--+--- + +----+ | v | + | v | + | v | + | v | + +----+ from X1':x1' to X2:x2 | v | X2':x2' + | X2 |<<<<<<<<<<<<<<<<<<<<<<<<<<<<<--+--- + +----+ +-----+ + + Hairpinning Behavior + + Hairpinning allows two endpoints on the internal side of the NAT to + communicate even if they only use each other's external IP addresses + and ports. + + More formally, a NAT that supports hairpinning forwards packets + originating from an internal address, X1:x1, destined for an external + address X2':x2' that has an active mapping to an internal address + X2:x2, back to that internal address, X2:x2. Note that typically X1' + is the same as X2'. + + Furthermore, the NAT may present the hairpinned packet with either an + internal (X1:x1) or an external (X1':x1') source IP address and port. + Therefore, the hairpinning NAT behavior can be either "External + source IP address and port" or "Internal source IP address and port". + "Internal source IP address and port" may cause problems by confusing + implementations that expect an external IP address and port. + + REQ-9: A NAT MUST support "Hairpinning". + + a) A NAT Hairpinning behavior MUST be "External source IP address + and port". + + Justification: This requirement is to allow communications between + two endpoints behind the same NAT when they are trying each + other's external IP addresses. + + a) Using the external source IP address is necessary for + applications with a restrictive policy of not accepting packets + from IP addresses that differ from what is expected. + +7. Application Level Gateways + + Certain NATs have implemented Application Level Gateways (ALGs) for + various protocols, including protocols for negotiating peer-to-peer + sessions, such as SIP. + + + +Audet & Jennings Best Current Practice [Page 17] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + + Certain NATs have these ALGs turned on permanently, others have them + turned on by default but allow them to be turned off, and others have + them turned off by default but allow them be turned on. + + NAT ALGs may interfere with UNSAF methods or protocols that try to be + NAT-aware and therefore must be used with extreme caution. + + REQ-10: To eliminate interference with UNSAF NAT traversal + mechanisms and allow integrity protection of UDP communications, + NAT ALGs for UDP-based protocols SHOULD be turned off. Future + standards track specifications that define ALGs can update this to + recommend the defaults for the ALGs that they define. + + a) If a NAT includes ALGs, it is RECOMMENDED that the NAT allow + the NAT administrator to enable or disable each ALG separately. + + Justification: NAT ALGs may interfere with UNSAF methods. + + a) This requirement allows the user to enable those ALGs that are + necessary to aid in the operation of some applications without + enabling ALGs, which interfere with the operation of other + applications. + +8. Deterministic Properties + + The classification of NATs is further complicated by the fact that, + under some conditions, the same NAT will exhibit different behaviors. + This has been seen on NATs that preserve ports or have specific + algorithms for selecting a port other than a free one. If the + external port that the NAT wishes to use is already in use by another + session, the NAT must select a different port. This results in + different code paths for this conflict case, which results in + different behavior. + + For example, if three hosts X1, X2, and X3 all send from the same + port x, through a port preserving NAT with only one external IP + address, called X1', the first one to send (i.e., X1) will get an + external port of x, but the next two will get x2' and x3' (where + these are not equal to x). There are NATs where the External NAT + mapping characteristics and the External Filter characteristics + change between the X1:x and the X2:x mapping. To make matters worse, + there are NATs where the behavior may be the same on the X1:x and + X2:x mappings, but different on the third X3:x mapping. + + Another example is that some NATs have an "Endpoint-Independent + Mapping", combined with "Port Overloading", as long as two endpoints + are not establishing sessions to the same external direction, but + then switch their behavior to "Address and Port-Dependent Mapping" + + + +Audet & Jennings Best Current Practice [Page 18] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + + without "Port Preservation" upon detection of these conflicting + sessions establishments. + + Any NAT that changes the NAT Mapping or the Filtering behavior + without configuration changes, at any point in time, under any + particular conditions, is referred to as a "non-deterministic" NAT. + NATs that don't are called "deterministic". + + Non-deterministic NATs generally change behavior when a conflict of + some sort happens, i.e., when the port that would normally be used is + already in use by another mapping. The NAT mapping and External + Filtering in the absence of conflict is referred to as the Primary + behavior. The behavior after the first conflict is referred to as + Secondary and after the second conflict is referred to as Tertiary. + No NATs have been observed that change on further conflicts, but it + is certainly possible that they exist. + + REQ-11: A NAT MUST have deterministic behavior, i.e., it MUST NOT + change the NAT translation (Section 4) or the Filtering + (Section 5) Behavior at any point in time, or under any particular + conditions. + + Justification: Non-deterministic NATs are very difficult to + troubleshoot because they require more intensive testing. This + non-deterministic behavior is the root cause of much of the + uncertainty that NATs introduce about whether or not applications + will work. + +9. ICMP Destination Unreachable Behavior + + When a NAT sends a packet toward a host on the other side of the NAT, + an ICMP message may be sent in response to that packet. That ICMP + message may be sent by the destination host or by any router along + the network path. The NAT's default configuration SHOULD NOT filter + ICMP messages based on their source IP address. Such ICMP messages + SHOULD be rewritten by the NAT (specifically, the IP headers and the + ICMP payload) and forwarded to the appropriate internal or external + host. The NAT needs to perform this function for as long as the UDP + mapping is active. Receipt of any sort of ICMP message MUST NOT + destroy the NAT mapping. A NAT that performs the functions described + in the paragraph above is referred to as "support ICMP Processing". + + There is no significant security advantage to blocking ICMP + Destination Unreachable packets. Additionally, blocking ICMP + Destination Unreachable packets can interfere with application + failover, UDP Path MTU Discovery (see [RFC1191] and [RFC1435]), and + traceroute. Blocking any ICMP message is discouraged, and blocking + ICMP Destination Unreachable is strongly discouraged. + + + +Audet & Jennings Best Current Practice [Page 19] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + + REQ-12: Receipt of any sort of ICMP message MUST NOT terminate the + NAT mapping. + + a) The NAT's default configuration SHOULD NOT filter ICMP messages + based on their source IP address. + + b) It is RECOMMENDED that a NAT support ICMP Destination + Unreachable messages. + + Justification: This is easy to do and is used for many things + including MTU discovery and rapid detection of error conditions, + and has no negative consequences. + +10. Fragmentation of Outgoing Packets + + When the MTU of the adjacent link is too small, fragmentation of + packets going from the internal side to the external side of the NAT + may occur. This can occur if the NAT is doing Point-to-Point over + Ethernet (PPPoE), or if the NAT has been configured with a small MTU + to reduce serialization delay when sending large packets and small + higher-priority packets, or for other reasons. + + It is worth noting that many IP stacks do not use Path MTU Discovery + with UDP packets. + + The packet could have its Don't Fragment bit set to 1 (DF=1) or 0 + (DF=0). + + REQ-13: If the packet received on an internal IP address has DF=1, + the NAT MUST send back an ICMP message "Fragmentation needed and + DF set" to the host, as described in [RFC0792]. + + a) If the packet has DF=0, the NAT MUST fragment the packet and + SHOULD send the fragments in order. + + Justification: This is as per RFC 792. + + a) This is the same function a router performs in a similar + situation [RFC1812]. + +11. Receiving Fragmented Packets + + For a variety of reasons, a NAT may receive a fragmented packet. The + IP packet containing the header could arrive in any fragment, + depending on network conditions, packet ordering, and the + implementation of the IP stack that generated the fragments. + + + + + +Audet & Jennings Best Current Practice [Page 20] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + + A NAT that is capable only of receiving fragments in order (that is, + with the header in the first packet) and forwarding each of the + fragments to the internal host is described as "Received Fragments + Ordered". + + A NAT that is capable of receiving fragments in or out of order and + forwarding the individual fragments (or a reassembled packet) to the + internal host is referred to as "Receive Fragments Out of Order". + See the Security Considerations section of this document for a + discussion of this behavior. + + A NAT that is neither of these is referred to as "Receive Fragments + None". + + REQ-14: A NAT MUST support receiving in-order and out-of-order + fragments, so it MUST have "Received Fragment Out of Order" + behavior. + + a) A NAT's out-of-order fragment processing mechanism MUST be + designed so that fragmentation-based DoS attacks do not + compromise the NAT's ability to process in-order and + unfragmented IP packets. + + Justification: See Security Considerations. + +12. Requirements + + The requirements in this section are aimed at minimizing the + complications caused by NATs to applications, such as realtime + communications and online gaming. The requirements listed earlier in + the document are consolidated here into a single section. + + It should be understood, however, that applications normally do not + know in advance if the NAT conforms to the recommendations defined in + this section. Peer-to-peer media applications still need to use + normal procedures, such as ICE [ICE]. + + A NAT that supports all the mandatory requirements of this + specification (i.e., the "MUST"), is "compliant with this + specification". A NAT that supports all the requirements of this + specification (i.e., including the "RECOMMENDED") is "fully compliant + with all the mandatory and recommended requirements of this + specification". + + + + + + + + +Audet & Jennings Best Current Practice [Page 21] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + + REQ-1: A NAT MUST have an "Endpoint-Independent Mapping" behavior. + + REQ-2: It is RECOMMENDED that a NAT have an "IP address pooling" + behavior of "Paired". Note that this requirement is not + applicable to NATs that do not support IP address pooling. + + REQ-3: A NAT MUST NOT have a "Port assignment" behavior of "Port + overloading". + + a) If the host's source port was in the range 0-1023, it is + RECOMMENDED the NAT's source port be in the same range. If the + host's source port was in the range 1024-65535, it is + RECOMMENDED that the NAT's source port be in that range. + + REQ-4: It is RECOMMENDED that a NAT have a "Port parity + preservation" behavior of "Yes". + + REQ-5: A NAT UDP mapping timer MUST NOT expire in less than two + minutes, unless REQ-5a applies. + + a) For specific destination ports in the well-known port range + (ports 0-1023), a NAT MAY have shorter UDP mapping timers that + are specific to the IANA-registered application running over + that specific destination port. + + b) The value of the NAT UDP mapping timer MAY be configurable. + + c) A default value of five minutes or more for the NAT UDP mapping + timer is RECOMMENDED. + + REQ-6: The NAT mapping Refresh Direction MUST have a "NAT Outbound + refresh behavior" of "True". + + a) The NAT mapping Refresh Direction MAY have a "NAT Inbound + refresh behavior" of "True". + + REQ-7 A NAT device whose external IP interface can be configured + dynamically MUST either (1) Automatically ensure that its internal + network uses IP addresses that do not conflict with its external + network, or (2) Be able to translate and forward traffic between + all internal nodes and all external nodes whose IP addresses + numerically conflict with the internal network. + + REQ-8: If application transparency is most important, it is + RECOMMENDED that a NAT have "Endpoint-Independent Filtering" + behavior. If a more stringent filtering behavior is most + important, it is RECOMMENDED that a NAT have "Address-Dependent + Filtering" behavior. + + + +Audet & Jennings Best Current Practice [Page 22] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + + a) The filtering behavior MAY be an option configurable by the + administrator of the NAT. + + REQ-9: A NAT MUST support "Hairpinning". + + a) A NAT Hairpinning behavior MUST be "External source IP address + and port". + + REQ-10: To eliminate interference with UNSAF NAT traversal + mechanisms and allow integrity protection of UDP communications, + NAT ALGs for UDP-based protocols SHOULD be turned off. Future + standards track specifications that define an ALG can update this + to recommend the ALGs on which they define default. + + a) If a NAT includes ALGs, it is RECOMMENDED that the NAT allow + the NAT administrator to enable or disable each ALG separately. + + REQ-11: A NAT MUST have deterministic behavior, i.e., it MUST NOT + change the NAT translation (Section 4) or the Filtering + (Section 5) Behavior at any point in time, or under any particular + conditions. + + REQ-12: Receipt of any sort of ICMP message MUST NOT terminate the + NAT mapping. + + a) The NAT's default configuration SHOULD NOT filter ICMP messages + based on their source IP address. + + b) It is RECOMMENDED that a NAT support ICMP Destination + Unreachable messages. + + REQ-13 If the packet received on an internal IP address has DF=1, + the NAT MUST send back an ICMP message "Fragmentation needed and + DF set" to the host, as described in [RFC0792]. + + a) If the packet has DF=0, the NAT MUST fragment the packet and + SHOULD send the fragments in order. + + REQ-14: A NAT MUST support receiving in-order and out-of-order + fragments, so it MUST have "Received Fragment Out of Order" + behavior. + + a) A NAT's out-of-order fragment processing mechanism MUST be + designed so that fragmentation-based DoS attacks do not + compromise the NAT's ability to process in-order and + unfragmented IP packets. + + + + + +Audet & Jennings Best Current Practice [Page 23] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + +13. Security Considerations + + NATs are often deployed to achieve security goals. Most of the + recommendations and requirements in this document do not affect the + security properties of these devices, but a few of them do have + security implications and are discussed in this section. + + This document recommends that the timers for mapping be refreshed on + outgoing packets (see REQ-6) and does not make recommendations about + whether or not inbound packets should update the timers. If inbound + packets update the timers, an external attacker can keep the mapping + alive forever and attack future devices that may end up with the same + internal address. A device that was also the DHCP server for the + private address space could mitigate this by cleaning any mappings + when a DHCP lease expired. For unicast UDP traffic (the scope of + this document), it may not seem relevant to support inbound timer + refresh; however, for multicast UDP, the question is harder. It is + expected that future documents discussing NAT behavior with multicast + traffic will refine the requirements around handling of the inbound + refresh timer. Some devices today do update the timers on inbound + packets. + + This document recommends that the NAT filters be specific to the + external IP address only (see REQ-8) and not to the external IP + address and UDP port. It can be argued that this is less secure than + using the IP and port. Devices that wish to filter on IP and port do + still comply with these requirements. + + Non-deterministic NATs are risky from a security point of view. They + are very difficult to test because they are, well, non-deterministic. + Testing by a person configuring one may result in the person thinking + it is behaving as desired, yet under different conditions, which an + attacker can create, the NAT may behave differently. These + requirements recommend that devices be deterministic. + + This document requires that NATs have an "external NAT mapping is + endpoint independent" behavior. This does not reduce the security of + devices. Which packets are allowed to flow across the device is + determined by the external filtering behavior, which is independent + of the mapping behavior. + + When a fragmented packet is received from the external side, and the + packets are out of order so that the initial fragment does not arrive + first, many systems simply discard the out-of-order packets. + Moreover, since some networks deliver small packets ahead of large + ones, there can be many out-of-order fragments. NATs that are + capable of delivering these out-of-order packets are possible, but + they need to store the out-of-order fragments, which can open up a + + + +Audet & Jennings Best Current Practice [Page 24] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + + Denial-of-Service (DoS) opportunity, if done incorrectly. + Fragmentation has been a tool used in many attacks, some involving + passing fragmented packets through NATs, and others involving DoS + attacks based on the state needed to reassemble the fragments. NAT + implementers should be aware of [RFC3128] and [RFC1858]. + +14. IAB Considerations + + The IAB has studied the problem of "Unilateral Self Address Fixing", + which is the general process by which a client attempts to determine + its address in another realm on the other side of a NAT through a + collaborative protocol reflection mechanism [RFC3424]. + + This specification does not, in itself, constitute an UNSAF + application. It consists of a series of requirements for NATs aimed + at minimizing the negative impact that those devices have on peer-to- + peer media applications, especially when those applications are using + UNSAF methods. + + Section 3 of UNSAF lists several practical issues with solutions to + NAT problems. This document makes recommendations to reduce the + uncertainty and problems introduced by these practical issues with + NATs. In addition, UNSAF lists five architectural considerations. + Although this is not an UNSAF proposal, it is interesting to consider + the impact of this work on these architectural considerations. + + Arch-1: The scope of this is limited to UDP packets in NATs like the + ones widely deployed today. The "fix" helps constrain the + variability of NATs for true UNSAF solutions such as STUN. + + Arch-2: This will exit at the same rate that NATs exit. It does not + imply any protocol machinery that would continue to live + after NATs were gone, or make it more difficult to remove + them. + + Arch-3: This does not reduce the overall brittleness of NATs, but + will hopefully reduce some of the more outrageous NAT + behaviors and make it easer to discuss and predict NAT + behavior in given situations. + + Arch-4: This work and the results [RESULTS] of various NATs + represent the most comprehensive work at IETF on what the + real issues are with NATs for applications like VoIP. This + work and STUN have pointed out, more than anything else, the + brittleness NATs introduce and the difficulty of addressing + these issues. + + + + + +Audet & Jennings Best Current Practice [Page 25] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + + Arch-5: This work and the test results [RESULTS] provide a reference + model for what any UNSAF proposal might encounter in + deployed NATs. + +15. Acknowledgments + + The editor would like to acknowledge Bryan Ford, Pyda Srisuresh, and + Dan Kegel for their multiple contributions on peer-to-peer + communications across a NAT. Dan Wing contributed substantial text + on IP fragmentation and ICMP behavior. Thanks to Rohan Mahy, + Jonathan Rosenberg, Mary Barnes, Melinda Shore, Lyndsay Campbell, + Geoff Huston, Jiri Kuthan, Harald Welte, Steve Casner, Robert + Sanders, Spencer Dawkins, Saikat Guha, Christian Huitema, Yutaka + Takeda, Paul Hoffman, Lisa Dusseault, Pekka Savola, Peter Koch, Jari + Arkko, and Alfred Hoenes for their contributions. + +16. References + +16.1. Normative References + + [RFC0768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC0791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + +16.2. Informative References + + [RFC0792] Postel, J., "Internet Control Message Protocol", STD 5, + RFC 792, September 1981. + + [RFC1191] Mogul, J. and S. Deering, "Path MTU discovery", + RFC 1191, November 1990. + + [RFC1435] Knowles, S., "IESG Advice from Experience with Path MTU + Discovery", RFC 1435, March 1993. + + [RFC1812] Baker, F., "Requirements for IP Version 4 Routers", + RFC 1812, June 1995. + + [RFC1858] Ziemba, G., Reed, D., and P. Traina, "Security + Considerations for IP Fragment Filtering", RFC 1858, + October 1995. + + + + + +Audet & Jennings Best Current Practice [Page 26] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + + [RFC1918] Rekhter, Y., Moskowitz, R., Karrenberg, D., Groot, G., + and E. Lear, "Address Allocation for Private + Internets", BCP 5, RFC 1918, February 1996. + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version + 6 (IPv6) Specification", RFC 2460, December 1998. + + [RFC2623] Eisler, M., "NFS Version 2 and Version 3 Security + Issues and the NFS Protocol's Use of RPCSEC_GSS and + Kerberos V5", RFC 2623, June 1999. + + [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. + + [RFC3027] Holdrege, M. and P. Srisuresh, "Protocol Complications + with the IP Network Address Translator", RFC 3027, + January 2001. + + [RFC3128] Miller, I., "Protection Against a Variant of the Tiny + Fragment Attack (RFC 1858)", RFC 3128, June 2001. + + [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. + + [RFC3424] Daigle, L. and IAB, "IAB Considerations for UNilateral + Self-Address Fixing (UNSAF) Across Network Address + Translation", RFC 3424, November 2002. + + [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, March 2003. + + [RFC3550] Schulzrinne, H., Casner, S., Frederick, R., and V. + Jacobson, "RTP: A Transport Protocol for Real-Time + Applications", STD 64, RFC 3550, July 2003. + + [RFC3605] Huitema, C., "Real Time Control Protocol (RTCP) + attribute in Session Description Protocol (SDP)", + RFC 3605, October 2003. + + + + +Audet & Jennings Best Current Practice [Page 27] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + + [RFC4380] Huitema, C., "Teredo: Tunneling IPv6 over UDP through + Network Address Translations (NATs)", RFC 4380, + February 2006. + + [RFC3489bis] Rosenberg, J., "Simple Traversal Underneath Network + Address Translators (NAT) (STUN)", Work in Progress, + October 2006. + + [ICE] Rosenberg, J., "Interactive Connectivity Establishment + (ICE): A Methodology for Network Address Translator + (NAT) Traversal for Offer/Answer Protocols", Work + in Progress, October 2006. + + [RESULTS] Jennings, C., "NAT Classification Test Results", Work + in Progress, October 2006. + + [TURN] Rosenberg, J., "Obtaining Relay Addresses from Simple + Traversal Underneath NAT (STUN)", Work in Progress, + October 2006. + + [ITU.H323] "Packet-based Multimedia Communications Systems", ITU- + T Recommendation H.323, July 2003. + +Authors' Addresses + + Francois Audet (editor) + Nortel Networks + 4655 Great America Parkway + Santa Clara, CA 95054 + US + + Phone: +1 408 495 2456 + EMail: audet@nortel.com + + + Cullen Jennings + Cisco Systems + 170 West Tasman Drive + MS: SJC-21/2 + San Jose, CA 95134 + US + + Phone: +1 408 902 3341 + EMail: fluffy@cisco.com + + + + + + + +Audet & Jennings Best Current Practice [Page 28] + +RFC 4787 NAT UDP Unicast Requirements January 2007 + + +Full Copyright Statement + + Copyright (C) The IETF Trust (2007). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND + THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF + THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at + ietf-ipr@ietf.org. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + +Audet & Jennings Best Current Practice [Page 29] + diff --git a/.duvet/specifications/www.rfc-editor.org/rfc/rfc4884.txt b/.duvet/specifications/www.rfc-editor.org/rfc/rfc4884.txt new file mode 100644 index 0000000000..85def5fce9 --- /dev/null +++ b/.duvet/specifications/www.rfc-editor.org/rfc/rfc4884.txt @@ -0,0 +1,1067 @@ + + + + + + +Network Working Group R. Bonica +Request for Comments: 4884 Juniper Networks +Updates: 792, 4443 D. Gan +Category: Standards Track Consultant + D. Tappan + Consultant + C. Pignataro + Cisco Systems, Inc. + April 2007 + + + Extended ICMP to Support Multi-Part Messages + +Status of This Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The IETF Trust (2007). + +Abstract + + This document redefines selected ICMP messages to support multi-part + operation. A multi-part ICMP message carries all of the information + that ICMP messages carried previously, as well as additional + information that applications may require. + + Multi-part messages are supported by an ICMP extension structure. + The extension structure is situated at the end of the ICMP message. + It includes an extension header followed by one or more extension + objects. Each extension object contains an object header and object + payload. All object headers share a common format. + + This document further redefines the above mentioned ICMP messages by + specifying a length attribute. All of the currently defined ICMP + messages to which an extension structure can be appended include an + "original datagram" field. The "original datagram" field contains + the initial octets of the datagram that elicited the ICMP error + message. Although the original datagram field is of variable length, + the ICMP message does not include a field that specifies its length. + Therefore, in order to facilitate message parsing, this document + allocates eight previously reserved bits to reflect the length of the + "original datagram" field. + + + +Bonica, et al. Standards Track [Page 1] + +RFC 4884 Multi-Part ICMP Messages April 2007 + + + The proposed modifications change the requirements for ICMP + compliance. The impact of these changes on compliant implementations + is discussed, and new requirements for future implementations are + presented. + + This memo updates RFC 792 and RFC 4443. + +Table of Contents + + 1. Introduction ....................................................3 + 2. Conventions Used in This Document ...............................4 + 3. Summary of Changes to ICMP ......................................4 + 4. ICMP Extensibility ..............................................4 + 4.1. ICMPv4 Destination Unreachable .............................7 + 4.2. ICMPv4 Time Exceeded .......................................8 + 4.3. ICMPv4 Parameter Problem ...................................8 + 4.4. ICMPv6 Destination Unreachable .............................9 + 4.5. ICMPv6 Time Exceeded .......................................9 + 4.6. ICMP Messages That Can Be Extended ........................10 + 5. Backwards Compatibility ........................................10 + 5.1. Classic Application Receives ICMP Message with + Extensions ................................................12 + 5.2. Non-Compliant Application Receives ICMP Message + with No Extensions ........................................12 + 5.3. Non-Compliant Application Receives ICMP Message + with Compliant Extensions .................................13 + 5.4. Compliant Application Receives ICMP Message with + No Extensions .............................................14 + 5.5. Compliant Application Receives ICMP Message with + Non-Compliant Extensions ..................................14 + 6. Interaction with Network Address Translation ...................14 + 7. The ICMP Extension Structure ...................................15 + 8. ICMP Extension Objects .........................................16 + 9. Security Considerations ........................................16 + 10. IANA Considerations ...........................................17 + 11. Acknowledgments ...............................................17 + 12. References ....................................................17 + 12.1. Normative References .....................................17 + 12.2. Informative References ...................................17 + + + + + + + + + + + + +Bonica, et al. Standards Track [Page 2] + +RFC 4884 Multi-Part ICMP Messages April 2007 + + +1. Introduction + + This document redefines selected ICMPv4 [RFC0792] and ICMPv6 + [RFC4443] messages to include an extension structure and a length + attribute. The extension structure supports multi-part ICMP + operation. Protocol designers can make an ICMP message carry + additional information by encoding that information in the extension + structure. + + This document also addresses a fundamental problem in ICMP + extensibility. All of the ICMP messages addressed by this memo + include an "original datagram" field. The "original datagram" field + contains the initial octets of the datagram that elicited the ICMP + error message. Although the "original datagram" field is of variable + length, the ICMP message does not include a field that specifies its + length. + + Application software infers the length of the "original datagram" + field from the total length of the ICMP message. If an extension + structure were appended to the message without adding a length + attribute for the "original datagram" field, the message would become + unparsable. Specifically, application software would not be able to + determine where the "original datagram" field ends and where the + extension structure begins. Therefore, this document proposes a + length attribute as well as an extension structure that is appended + to the ICMP message. + + The current memo also addresses backwards compatibility with existing + ICMP implementations that either do not implement the extensions + defined herein or implement them without adding the required length + attributes. In particular, this document addresses backwards + compatibility with certain, widely deployed, MPLS-aware ICMPv4 + implementations that send the extensions defined herein without + adding the required length attribute. + + The current memo does not define any ICMP extension objects. It + defines only the extension header and a common header that all + extension objects share. [UNNUMBERED], [ROUTING-INST], and + [MPLS-ICMP] provide sample applications of the ICMP Extension Object. + + The above mentioned memos share a common characteristic. They all + append information to the ICMP Time Expired message for consumption + by TRACEROUTE. In this case, as in many others, appending + information to the existing ICMP Time Expired Message is preferable + to defining a new message and emitting two messages whenever a packet + is dropped due to TTL expiration. + + + + + +Bonica, et al. Standards Track [Page 3] + +RFC 4884 Multi-Part ICMP Messages April 2007 + + +2. Conventions Used in This Document + + 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]. + +3. Summary of Changes to ICMP + + The following is a summary of changes to ICMP that are introduced by + this memo: + + An ICMP Extension Structure MAY be appended to ICMPv4 Destination + Unreachable, Time Exceeded, and Parameter Problem messages. + + An ICMP Extension Structure MAY be appended to ICMPv6 Destination + Unreachable, and Time Exceeded messages. + + The above mentioned messages include an "original datagram" field, + and the message formats are updated to specify a length attribute + for the "original datagram" field. + + When the ICMP Extension Structure is appended to an ICMP message + and that ICMP message contains an "original datagram" field, the + "original datagram" field MUST contain at least 128 octets. + + When the ICMP Extension Structure is appended to an ICMPv4 message + and that ICMPv4 message contains an "original datagram" field, the + "original datagram" field MUST be zero padded to the nearest + 32-bit boundary. + + When the ICMP Extension Structure is appended to an ICMPv6 message + and that ICMPv6 message contains an "original datagram" field, the + "original datagram" field MUST be zero padded to the nearest + 64-bit boundary. + + ICMP messages defined in the future SHOULD indicate whether or not + they support the extension mechanism defined in this + specification. It is recommended that all new messages support + extensions. + +4. ICMP Extensibility + + RFC 792 defines the following ICMPv4 message types: + + - Destination Unreachable + + - Time Exceeded + + + + +Bonica, et al. Standards Track [Page 4] + +RFC 4884 Multi-Part ICMP Messages April 2007 + + + - Parameter Problem + + - Source Quench + + - Redirect + + - Echo Request/Reply + + - Timestamp/Timestamp Reply + + - Information Request/Information Reply + + [RFC1191] reserves bits for the "Next-Hop MTU" field in the + Destination Unreachable message. + + RFC 4443 defines the following ICMPv6 message types: + + - Destination Unreachable + + - Packet Too Big + + - Time Exceeded + + - Parameter Problem + + - Echo Request/Reply + + Many ICMP messages are extensible as currently defined. Protocol + designers can extend ICMP messages by simply appending fields or data + structures to them. + + However, the following ICMP messages are not extensible as currently + defined: + + - ICMPv4 Destination Unreachable (type = 3) + + - ICMPv4 Time Exceeded (type = 11) + + - ICMPv4 Parameter Problem (type = 12) + + - ICMPv6 Destination Unreachable (type = 1) + + - ICMPv6 Packet Too Big (type = 2) + + - ICMPv6 Time Exceeded (type = 3) + + - ICMPv6 Parameter Problem (type = 4) + + + + +Bonica, et al. Standards Track [Page 5] + +RFC 4884 Multi-Part ICMP Messages April 2007 + + + These messages contain an "original datagram" field which represents + the leading octets of the datagram to which the ICMP message is a + response. RFC 792 defines the "original datagram" field for ICMPv4 + messages. In RFC 792, the "original datagram" field includes the IP + header plus the next eight octets of the original datagram. + [RFC1812] extends the "original datagram" field to contain as many + octets as possible without causing the ICMP message to exceed the + minimum IPv4 reassembly buffer size (i.e., 576 octets). RFC 4443 + defines the "original datagram" field for ICMPv6 messages. In RFC + 4443, the "original datagram" field always contained as many octets + as possible without causing the ICMP message to exceed the minimum + IPv6 MTU (i.e., 1280 octets). + + Unfortunately, the "original datagram" field lacks a length + attribute. Application software infers the length of this field from + the total length of the ICMP message. If an extension structure were + appended to the message without adding a length attribute for the + "original datagram" field, the message would become unparsable. + Specifically, application software would not be able to determine + where the "original datagram" field ends and where the extension + structure begins. + + In order to solve this problem, this memo introduces an 8-bit length + attribute to the following ICMPv4 messages. + + - Destination Unreachable (type = 3) + + - Time Exceeded (type = 11) + + - Parameter Problem (type = 12) + + It also introduces an 8-bit length attribute to the following ICMPv6 + messages. + + - Destination Unreachable (type = 1) + + - Time Exceeded (type = 3) + + The length attribute MUST be specified when the ICMP Extension + Structure is appended to the above mentioned ICMP messages. + + The length attribute represents the length of the "original datagram" + field. Space for the length attribute is claimed from reserved + octets, whose value was previously required to be zero. + + For ICMPv4 messages, the length attribute represents 32-bit words. + When the length attribute is specified, the "original datagram" field + MUST be zero padded to the nearest 32-bit boundary. Because the + + + +Bonica, et al. Standards Track [Page 6] + +RFC 4884 Multi-Part ICMP Messages April 2007 + + + sixth octet of each of the impacted ICMPv4 messages was reserved for + future use, this octet was selected as the location of the length + attribute in ICMPv4. + + For ICMPv6 messages, the length attribute represents 64-bit words. + When the length attribute is specified, the "original datagram" field + MUST be zero padded to the nearest 64-bit boundary. Because the + fifth octet of each of the impacted ICMPv6 messages was reserved for + future use, this octet was selected as the location of the length + attribute in ICMPv6. + + In order to achieve backwards compatibility, when the ICMP Extension + Structure is appended to an ICMP message and that ICMP message + contains an "original datagram" field, the "original datagram" field + MUST contain at least 128 octets. If the original datagram did not + contain 128 octets, the "original datagram" field MUST be zero padded + to 128 octets. (See Section 5.1 for rationale.) + + The following sub-sections depict length attribute as it has been + introduced to selected ICMP messages. + +4.1. ICMPv4 Destination Unreachable + + Figure 1 depicts the ICMPv4 Destination Unreachable Message. + + 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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type | Code | Checksum | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | unused | Length | Next-Hop MTU* | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Internet Header + leading octets of original datagram | + | | + | // | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 1: ICMPv4 Destination Unreachable + + The syntax and semantics of all fields are unchanged from RFC 792. + However, a length attribute is added to the second word. The length + attribute represents length of the padded "original datagram" field, + measured in 32-bit words. + + * The Next-Hop MTU field is not required in all cases. It is + depicted only to demonstrate that those bits are not available for + assignment in this memo. + + + +Bonica, et al. Standards Track [Page 7] + +RFC 4884 Multi-Part ICMP Messages April 2007 + + +4.2. ICMPv4 Time Exceeded + + Figure 2 depicts the ICMPv4 Time Exceeded Message. + + 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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type | Code | Checksum | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | unused | Length | unused | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Internet Header + leading octets of original datagram | + | | + | // | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 2: ICMPv4 Time Exceeded + + The syntax and semantics of all fields are unchanged from RFC 792, + except for a length attribute which is added to the second word. The + length attribute represents length of the padded "original datagram" + field, measured in 32-bit words. + +4.3. ICMPv4 Parameter Problem + + Figure 3 depicts the ICMPv4 Parameter Problem Message. + + 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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type | Code | Checksum | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Pointer | Length | unused | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Internet Header + leading octets of original datagram | + | | + | // | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 3: ICMPv4 Parameter Problem + + The syntax and semantics of all fields are unchanged from RFC 792, + except for a length attribute which is added to the second word. The + length attribute represents length of the padded "original datagram" + field, measured in 32-bit words. + + + + +Bonica, et al. Standards Track [Page 8] + +RFC 4884 Multi-Part ICMP Messages April 2007 + + +4.4. ICMPv6 Destination Unreachable + + Figure 4 depicts the ICMPv6 Destination Unreachable Message. + + 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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type | Code | Checksum | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Length | Unused | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | As much of invoking packet | + + as possible without the ICMPv6 packet + + | exceeding the minimum IPv6 MTU [RFC4443] | + + Figure 4: ICMPv6 Destination Unreachable + + The syntax and semantics of all fields are unchanged from RFC 4443. + However, a length attribute is added to the second word. The length + attribute represents length of the padded "original datagram" field, + measured in 64-bit words. + +4.5. ICMPv6 Time Exceeded + + Figure 5 depicts the ICMPv6 Time Exceeded Message. + + 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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type | Code | Checksum | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Length | Unused | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | As much of invoking packet | + + as possible without the ICMPv6 packet + + | exceeding the minimum IPv6 MTU [RFC4443] | + + Figure 5: ICMPv6 Time Exceeded + + The syntax and semantics of all fields are unchanged from RFC 4443, + except for a length attribute which is added to the second word. The + length attribute represents length of the padded "original datagram" + field, measured in 64-bit words. + + + + + + + + +Bonica, et al. Standards Track [Page 9] + +RFC 4884 Multi-Part ICMP Messages April 2007 + + +4.6. ICMP Messages That Can Be Extended + + The ICMP Extension Structure MAY be appended to messages of the + following types: + + - ICMPv4 Destination Unreachable + + - ICMPv4 Time Exceeded + + - ICMPv4 Parameter Problem + + - ICMPv6 Destination Unreachable + + - ICMPv6 Time Exceeded + + The ICMP Extension Structure MUST NOT be appended to any of the other + ICMP messages mentioned in Section 4. Extensions were not defined + for the ICMPv6 "Packet Too Big" and "Parameter Problem" messages + because these messages lack space for a length attribute. + +5. Backwards Compatibility + + ICMP messages can be categorized as follows: + + - Messages that do not include any ICMP extensions + + - Messages that include non-compliant ICMP extensions + + - Messages that includes compliant ICMP extensions + + Any ICMP implementation can send a message that does not include + extensions. ICMP implementations produced prior to 1999 are not + known to send ICMP extensions. + + Some ICMP implementations, produced between 1999 and the time of this + publication, may send a non-compliant version of ICMP extensions + described in this memo. Specifically, these implementations may + append the ICMP Extension Structure to the Time Exceeded and + Destination Unreachable messages. When they do this, they send + exactly 128 octets representing the original datagram, zero padding + if required. They also calculate checksums as described in this + document. However, they do not specify a length attribute to be + associated with the "original datagram" field. + + It is assumed that ICMP implementations produced in the future will + send ICMP extensions that are compliant with this specification. + + + + + +Bonica, et al. Standards Track [Page 10] + +RFC 4884 Multi-Part ICMP Messages April 2007 + + + Likewise, applications that consume ICMP messages can be categorized + as follows: + + - Classic applications + + - Non-compliant applications + + - Compliant applications + + Classic applications do not parse extensions defined in this memo. + They are insensitive to the length attribute that is associated with + the "original datagram" field. + + Non-compliant implementations parse the extensions defined in this + memo, but only in conjunction with the Time Expired and Destination + Unreachable messages. They require the "original datagram" field to + contain exactly 128 octets and are insensitive to the length + attribute that is associated with the "original datagram" field. + Non-compliant applications were produced between 1999 and the time of + publication of this memo. + + Compliant applications comply fully with the specifications of this + document. + + In order to demonstrate backwards compatibility, Table 1 describes + how members of each application category would parse each category of + ICMP message. + + +----------------+----------------+----------------+----------------+ + | | No Extensions | Non-compliant | Compliant | + | | | Extensions | Extensions | + +----------------+----------------+----------------+----------------+ + | Classic | - | Section 5.1 | Section 5.1 | + | Application | | | | + | | | | | + | Non-compliant | Section 5.2 | - | Section 5.3 | + | Application | | | | + | | | | | + | Compliant | Section 5.4 | Section 5.5 | - | + | Application | | | | + +----------------+----------------+----------------+----------------+ + + Table 1 + + In the table above, cells that contain a dash represent the nominal + case and require no explanation. In the following sections, we + assume that the ICMP message type is "Time Exceeded". + + + + +Bonica, et al. Standards Track [Page 11] + +RFC 4884 Multi-Part ICMP Messages April 2007 + + +5.1. Classic Application Receives ICMP Message with Extensions + + When a classic application receives an ICMP message that includes + extensions, it will incorrectly interpret those extensions as being + part of the "original datagram" field. Fortunately, the extensions + are guaranteed to begin at least 128 octets beyond the beginning of + the "original datagram" field. So, only those ICMP applications that + process the 129th octet of the "original datagram" field will be + adversely effected. To date, only two applications falling into this + category have been identified, and the degree to which they are + effected is minimal. + + Some TCP stacks, when they receive an ICMP message, verify the + checksum in the original datagram field [ATTACKS]. If the checksum + is incorrect, the TCP stack discards the ICMP message for security + reasons. If the trailing octets of the original datagram field are + overwritten by ICMP extensions, the TCP stack will discard an ICMP + message that it would not otherwise have discarded. The impact of + this issue is considered to be minimal because many ICMP messages are + discarded for other reasons (e.g., ICMP filtering, network + congestion, checksum was incorrect because original datagram field + was truncated.) + + Another theoretically possible, but highly improbably scenario occurs + when ICMP extensions overwrite the portion of the original datagram + field that represents the TCP header, causing the TCP stack to + operate upon the wrong TCP connection. This scenario is highly + unlikely because it occurs only when the TCP header appears at or + beyond the 128th octet of the original datagram field and then only + when the extensions approximate a valid TCP header. + +5.2. Non-Compliant Application Receives ICMP Message with No Extensions + + When a non-compliant ICMPv4 application receives a message that + contains no extensions, the application examines the total length of + the ICMPv4 message. If the total ICMPv4 message length is less than + the length of its IP header plus 144 octets, the application + correctly determines that the message does not contain any + extensions. + + The 144-octet sum is derived from 8 octets for the first two words of + the ICMPv4 Time Exceeded message, 128 octets for the "original + datagram" field, 4 octets for the ICMP Extension Header, and 4 octets + for a single ICMP Object header. All of these octets would be + required if extensions were present. + + + + + + +Bonica, et al. Standards Track [Page 12] + +RFC 4884 Multi-Part ICMP Messages April 2007 + + + If the ICMPv4 payload contains 144 octets or more, the application + must examine the 137th octet to determine whether it represents a + valid ICMPv4 Extension Header. In order to represent a valid + Extension Header, it must contain a valid version number and + checksum. If it does not contain a valid version number and + checksum, the application correctly determines that the message does + not contain any extensions. + + Non-compliant applications assume that the ICMPv4 Extension Structure + begins on the 137th octet of the Time Exceeded message, after a + 128-octet field representing the padded "original datagram" message. + + It is possible that a non-compliant application will parse an ICMPv4 + message incorrectly under the following conditions: + + - the message does not contain extensions + + - the original datagram field contains 144 octets or more + + - selected octets of the original datagram field represent the + correct values for an extension header version number and + checksum + + Although this is possible, it is very unlikely. + + A similar analysis can be performed for ICMPv6. However, the numeric + constants would change as appropriate. + +5.3. Non-Compliant Application Receives ICMP Message with Compliant + Extensions + + When a non-compliant application receives a message that contains + compliant ICMP extensions, it will parse those extensions correctly + only if the "original datagram" field contains exactly 128 octets. + This is because non-compliant applications are insensitive to the + length attribute that is associated with the "original datagram" + field. (They assume its value to be 128.) + + Provided that the entire ICMP message does not exceed the minimum + reassembly buffer size (576 octets for ICMPv4 or 1280 octets for + ICMPv6), there is no upper limit upon the length of the "original + datagram" field. However, each implementation will decide how many + octets to include. Those wishing to be backward compatible with non- + compliant TRACEROUTE implementations will include exactly 128 octets. + Those not requiring compatibility with non-compliant TRACEROUTE + applications may include more octets. + + + + + +Bonica, et al. Standards Track [Page 13] + +RFC 4884 Multi-Part ICMP Messages April 2007 + + +5.4. Compliant Application Receives ICMP Message with No Extensions + + When a compliant application receives an ICMP message, it examines + the length attribute that is associated with the "original datagram" + field. If the length attribute is zero, the compliant application + MUST determine that the message contains no extensions. + +5.5. Compliant Application Receives ICMP Message with Non-Compliant + Extensions + + When a compliant application receives an ICMP message, it examines + the length attribute that is associated with the "original datagram" + field. If the length attribute is zero, the compliant application + MUST determine that the message contains no extensions. In this + case, that determination is technically correct, but not backwards + compatible with the non-compliant implementation that originated the + ICMP message. + + So, to ease transition yet encourage compliant implementation, + compliant TRACEROUTE implementations MUST include a non-default + operation mode to also interpret non-compliant responses. + Specifically, when a TRACEROUTE application operating in non- + compliant mode receives a sufficiently long ICMP message that does + not specify a length attribute, it will parse for a valid extension + header at a fixed location, assuming a 128-octet "original datagram" + field. If the application detects a valid version and checksum, it + will treat the octets that follow as an extension structure. + +6. Interaction with Network Address Translation + + The ICMP extensions defined in this memo do not interfere with + Network Address Translation. [RFC3022] permits traditional NAT + devices to modify selected fields within ICMP messages. These fields + include the "original datagram" field mentioned above. However, if a + NAT device modifies the "original datagram" field, it should modify + only the leading octets of that field, which represent the outermost + IP header. Because the outermost IP header is guaranteed to be + contained by the first 128 octets of the "original datagram" field, + ICMP extensions and NAT will not interfere with one another. + + It is conceivable that a NAT implementation might overstep the + restrictions of RFC 3022 and overwrite the length attribute specified + by this memo. If a NAT implementation were to overwrite the length + attribute with zeros, the resulting packet will be indistinguishable + from a packet that was generated by a non-compliant ICMP + implementation. See Section 5.5 for packet details and a discussion + of backwards compatibility. + + + + +Bonica, et al. Standards Track [Page 14] + +RFC 4884 Multi-Part ICMP Messages April 2007 + + +7. The ICMP Extension Structure + + This memo proposes an optional ICMP Extension Structure that can be + appended to the ICMP messages referenced in Section 4.6 of this + document. + + The Extension Structure contains exactly one Extension Header + followed by one or more objects. Having received an ICMP message + with extensions, application software MAY process selected objects + while ignoring others. The presence of an unrecognized object does + not imply that an ICMP message is malformed. + + As stated above, the total length of the ICMP message, including + extensions, MUST NOT exceed the minimum reassembly buffer size. + Figure 6 depicts the ICMP Extension Header. + + 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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |Version| (Reserved) | Checksum | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 6: ICMP Extension Header + + The fields of the ICMP Extension Header are as follows: + + Version: 4 bits + + ICMP extension version number. This is version 2. + + Reserved: 12 bits + + Must be set to 0. + + Checksum: 16 bits + + The one's complement of the one's complement sum of the data + structure, with the checksum field replaced by zero for the + purpose of computing the checksum. An all-zero value means that + no checksum was transmitted. See Section 5.2 for a description of + how this field is used. + + + + + + + + + + +Bonica, et al. Standards Track [Page 15] + +RFC 4884 Multi-Part ICMP Messages April 2007 + + +8. ICMP Extension Objects + + Each extension object contains one or more 32-bit words, representing + an object header and payload. All object headers share a common + format. Figure 7 depicts the object header and payload. + + 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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Length | Class-Num | C-Type | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + | // (Object payload) // | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 7: Object Header and Payload + + An object header has the following fields: + + Length: 16 bits + + Length of the object, measured in octets, including the object + header and object payload. + + Class-Num: 8 bits + + Identifies object class. + + C-Type: 8 bits + + Identifies object sub-type. + +9. Security Considerations + + Upon receipt of an ICMP message, application software must check it + for syntactic correctness. The extension checksum must be verified. + Improperly specified length attributes and other syntax problems may + result in buffer overruns. + + This memo does not define the conditions under which a router sends + an ICMP message. Therefore, it does not expose routers to any new + denial-of-service attacks. Routers may need to limit the rate at + which ICMP messages are sent. + + + + + + + +Bonica, et al. Standards Track [Page 16] + +RFC 4884 Multi-Part ICMP Messages April 2007 + + +10. IANA Considerations + + The ICMP Extension Object header contains two 8-bit fields: The + Class-Num identifies the object class, and the C-Type identifies the + class sub-type. Sub-type values are defined relative to a specific + object class value, and are defined per class. + + IANA has established a registry of ICMP extension objects classes and + class sub-types. There are no values assigned within this document + to maintain. Object classes 0xF7 - 0xFF are reserved for private + use. Object class values are assignable on a first-come-first-serve + basis. The policy for assigning sub-type values should be defined in + the document defining new class values. + +11. Acknowledgments + + Thanks to Pekka Nikander, Mark Doll, Fernando Gont, Joe Touch, + Christian Voiqt, and Sharon Chrisholm for their comments regarding + this document. + +12. References + +12.1. Normative References + + [RFC0792] Postel, J., "Internet Control Message Protocol", STD + 5, RFC 792, September 1981. + + [RFC1191] Mogul, J. and S. Deering, "Path MTU discovery", RFC + 1191, November 1990. + + [RFC1812] Baker, F., "Requirements for IP Version 4 Routers", + RFC 1812, June 1995. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC4443] Conta, A., Deering, S., and M. Gupta, Ed., "Internet + Control Message Protocol (ICMPv6) for the Internet + Protocol Version 6 (IPv6) Specification", RFC 4443, + March 2006. + +12.2. Informative References + + [UNNUMBERED] Atlas, A., Bonica, R., Rivers, JR., Shen, N., and E. + Chen, "ICMP Extensions for Unnumbered Interfaces", + Work in Progress, March 2007. + + + + + +Bonica, et al. Standards Track [Page 17] + +RFC 4884 Multi-Part ICMP Messages April 2007 + + + [MPLS-ICMP] Bonica, R., Gan, D., Tappan, D., and C. Pignataro, + "ICMP Extensions for MultiProtocol Label Switching", + Work in Progress, January 2007. + + [ATTACKS] Gont, F., "ICMP attacks against TCP", Work in + Progress, October 2006. + + [ROUTING-INST] Shen, N. and E. Chen, "ICMP Extensions for Routing + Instances", Work in Progress, November 2006. + + [RFC3022] Srisuresh, P. and K. Egevang, "Traditional IP Network + Address Translator (Traditional NAT)", RFC 3022, + January 2001. + +Authors' Addresses + + Ronald P. Bonica + Juniper Networks + 2251 Corporate Park Drive + Herndon, VA 20171 + US + + EMail: rbonica@juniper.net + + + Der-Hwa Gan + Consultant + + EMail: derhwagan@yahoo.com + + + Daniel C. Tappan + Consultant + + EMail: Dan.Tappan@gmail.com + + + Carlos Pignataro + Cisco Systems, Inc. + 7025 Kit Creek Road + Research Triangle Park, NC 27709 + US + + EMail: cpignata@cisco.com + + + + + + + +Bonica, et al. Standards Track [Page 18] + +RFC 4884 Multi-Part ICMP Messages April 2007 + + +Full Copyright Statement + + Copyright (C) The IETF Trust (2007). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND + THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF + THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at + ietf-ipr@ietf.org. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + +Bonica, et al. Standards Track [Page 19] + diff --git a/.duvet/specifications/www.rfc-editor.org/rfc/rfc5382.txt b/.duvet/specifications/www.rfc-editor.org/rfc/rfc5382.txt new file mode 100644 index 0000000000..995986c3ce --- /dev/null +++ b/.duvet/specifications/www.rfc-editor.org/rfc/rfc5382.txt @@ -0,0 +1,1179 @@ + + + + + + +Network Working Group S. Guha, Ed. +Request for Comments: 5382 Cornell U. +BCP: 142 K. Biswas +Category: Best Current Practice Cisco Systems + B. Ford + MPI-SWS + S. Sivakumar + Cisco Systems + P. Srisuresh + Kazeon Systems + October 2008 + + + NAT Behavioral Requirements for TCP + +Status of This Memo + + This document specifies an Internet Best Current Practices for the + Internet Community, and requests discussion and suggestions for + improvements. Distribution of this memo is unlimited. + +Abstract + + This document defines a set of requirements for NATs that handle TCP + that would allow many applications, such as peer-to-peer applications + and online games to work consistently. Developing NATs that meet + this set of requirements will greatly increase the likelihood that + these applications will function properly. + + + + + + + + + + + + + + + + + + + + + + + +Guha, et al. Best Current Practice [Page 1] + +RFC 5382 NAT TCP Requirements October 2008 + + +Table of Contents + + 1. Applicability Statement . . . . . . . . . . . . . . . . . . . 3 + 2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3 + 3. Terminology . . . . . . . . . . . . . . . . . . . . . . . . . 4 + 4. TCP Connection Initiation . . . . . . . . . . . . . . . . . . 4 + 4.1. Address and Port Mapping Behavior . . . . . . . . . . . . 5 + 4.2. Internally Initiated Connections . . . . . . . . . . . . . 5 + 4.3. Externally Initiated Connections . . . . . . . . . . . . . 7 + 5. NAT Session Refresh . . . . . . . . . . . . . . . . . . . . . 10 + 6. Application Level Gateways . . . . . . . . . . . . . . . . . . 12 + 7. Other Requirements Applicable to TCP . . . . . . . . . . . . . 12 + 7.1. Port Assignment . . . . . . . . . . . . . . . . . . . . . 12 + 7.2. Hairpinning Behavior . . . . . . . . . . . . . . . . . . . 13 + 7.3. ICMP Responses to TCP Packets . . . . . . . . . . . . . . 13 + 8. Requirements . . . . . . . . . . . . . . . . . . . . . . . . . 14 + 9. Security Considerations . . . . . . . . . . . . . . . . . . . 16 + 10. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 17 + 11. References . . . . . . . . . . . . . . . . . . . . . . . . . . 18 + 11.1. Normative References . . . . . . . . . . . . . . . . . . . 18 + 11.2. Informational References . . . . . . . . . . . . . . . . . 18 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Guha, et al. Best Current Practice [Page 2] + +RFC 5382 NAT TCP Requirements October 2008 + + +1. Applicability Statement + + This document is adjunct to [BEHAVE-UDP], which defines many terms + relating to NATs, lays out general requirements for all NATs, and + sets requirements for NATs that handle IP and unicast UDP traffic. + The purpose of this document is to set requirements for NATs that + handle TCP traffic. + + The requirements of this specification apply to traditional NATs as + described in [RFC2663]. + + This document only covers the TCP aspects of NAT traversal. + Middlebox behavior that is not necessary for network address + translation of TCP is out of scope. Packet inspection above the TCP + layer and firewalls are out of scope except for Application Level + Gateway (ALG) behavior that may interfere with NAT traversal. + Application and OS aspects of TCP NAT traversal are out of scope. + Signaling-based approaches to NAT traversal, such as Middlebox + Communication (MIDCOM) and Universal Plug and Play (UPnP), that + directly control the NAT are out of scope. Finally, TCP connections + intended for the NAT (e.g., an HTTP or Secure Shell Protocol (SSH) + management interface) and TCP connections initiated by the NAT (e.g., + reliable syslog client) are out of scope. + +2. Introduction + + Network Address Translators (NATs) hinder connectivity in + applications where sessions may be initiated to internal hosts. + Readers may refer to [RFC3022] for detailed information on + traditional NATs. [BEHAVE-UDP] lays out the terminology and + requirements for NATs in the context of IP and UDP. This document + supplements these by setting requirements for NATs that handle TCP + traffic. All definitions and requirements in [BEHAVE-UDP] are + inherited here. + + [RFC4614] chronicles the evolution of TCP from the original + definition [RFC0793] to present-day implementations. While much has + changed in TCP with regards to congestion control and flow control, + security, and support for high-bandwidth networks, the process of + initiating a connection (i.e., the 3-way handshake or simultaneous- + open) has changed little. It is the process of connection initiation + that NATs affect the most. Experimental approaches such as T/TCP + [RFC1644] have proposed alternate connection initiation approaches, + but have been found to be complex and susceptible to denial-of- + service attacks. Modern operating systems and NATs consequently + primarily support the 3-way handshake and simultaneous-open modes of + connection initiation as described in [RFC0793]. + + + + +Guha, et al. Best Current Practice [Page 3] + +RFC 5382 NAT TCP Requirements October 2008 + + + Recently, many techniques have been devised to make peer-to-peer TCP + applications work across NATs. [STUNT], [NATBLASTER], and [P2PNAT] + describe Unilateral Self-Address Fixing (UNSAF) mechanisms that allow + peer-to-peer applications to establish TCP through NATs. These + approaches require only endpoint applications to be modified and work + with standards compliant OS stacks. The approaches, however, depend + on specific NAT behavior that is usually, but not always, supported + by NATs (see [TCPTRAV] and [P2PNAT] for details). Consequently, a + complete TCP NAT traversal solution is sometimes forced to rely on + public TCP relays to traverse NATs that do not cooperate. This + document defines requirements that ensure that TCP NAT traversal + approaches are not forced to use data relays. + +3. Terminology + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [RFC2119]. + + "NAT" in this specification includes both "Basic NAT" and "Network + Address/Port Translator (NAPT)" [RFC2663]. The term "NAT Session" is + adapted from [NAT-MIB] and is defined as follows. + + NAT Session - A NAT session is an association between a TCP session + as seen in the internal realm and a TCP session as seen in the + external realm, by virtue of NAT translation. The NAT session will + provide the translation glue between the two session representations. + + This document uses the term "TCP connection" (or just "connection") + to refer to individual TCP flows identified by the 4-tuple (source + and destination IP address and TCP port) and the initial sequence + numbers (ISN). + + This document uses the term "address and port mapping" (or just + "mapping") as defined in [BEHAVE-UDP] to refer to state at the NAT + necessary for network address and port translation of TCP + connections. This document also uses the terms "Endpoint-Independent + Mapping", "Address-Dependent Mapping", "Address and Port-Dependent + Mapping", "filtering behavior", "Endpoint-Independent Filtering", + "Address-Dependent Filtering", "Address and Port-Dependent + Filtering", "Port assignment", "Port overloading", "hairpinning", and + "External source IP address and port" as defined in [BEHAVE-UDP]. + +4. TCP Connection Initiation + + This section describes various NAT behaviors applicable to TCP + connection initiation. + + + + +Guha, et al. Best Current Practice [Page 4] + +RFC 5382 NAT TCP Requirements October 2008 + + +4.1. Address and Port Mapping Behavior + + A NAT uses a mapping to translate packets for each TCP connection. A + mapping is dynamically allocated for connections initiated from the + internal side, and potentially reused for certain subsequent + connections. NAT behavior regarding when a mapping can be reused + differs for different NATs as described in [BEHAVE-UDP]. + + Consider an internal IP address and TCP port (X:x) that initiates a + TCP connection to an external (Y1:y1) tuple. Let the mapping + allocated by the NAT for this connection be (X1':x1'). Shortly + thereafter, the endpoint initiates a connection from the same (X:x) + to an external address (Y2:y2) and gets the mapping (X2':x2') on the + NAT. As per [BEHAVE-UDP], if (X1':x1') equals (X2':x2') for all + values of (Y2:y2), then the NAT is defined to have "Endpoint- + Independent Mapping" behavior. If (X1':x1') equals (X2':x2') only + when Y2 equals Y1, then the NAT is defined to have "Address-Dependent + Mapping" behavior. If (X1':x1') equals (X2':x2') only when (Y2:y2) + equals (Y1:y1), possible only for consecutive connections to the same + external address shortly after the first is terminated and if the NAT + retains state for connections in TIME_WAIT state, then the NAT is + defined to have "Address and Port-Dependent Mapping" behavior. This + document introduces one additional behavior where (X1':x1') never + equals (X2':x2'), that is, for each connection a new mapping is + allocated; in such a case, the NAT is defined to have "Connection- + Dependent Mapping" behavior. + + REQ-1: A NAT MUST have an "Endpoint-Independent Mapping" behavior + for TCP. + + Justification: REQ-1 is necessary for UNSAF methods to work. + Endpoint-Independent Mapping behavior allows peer-to-peer + applications to learn and advertise the external IP address and + port allocated to an internal endpoint such that external peers + can contact it (subject to the NAT's security policy). The + security policy of a NAT is independent of its mapping behavior + and is discussed later in Section 4.3. Having Endpoint- + Independent Mapping behavior allows peer-to-peer applications to + work consistently without compromising the security benefits of + the NAT. + +4.2. Internally Initiated Connections + + An internal endpoint initiates a TCP connection through a NAT by + sending a SYN packet. The NAT allocates (or reuses) a mapping for + the connection, as described in the previous section. The mapping + defines the external IP address and port used for translation of all + packets for that connection. In particular, for client-server + + + +Guha, et al. Best Current Practice [Page 5] + +RFC 5382 NAT TCP Requirements October 2008 + + + applications where an internal client initiates the connection to an + external server, the mapping is used to translate the outbound SYN, + the resulting inbound SYN-ACK response, the subsequent outbound ACK, + and other packets for the connection. This method of connection + initiation corresponds to the 3-way handshake (defined in [RFC0793]) + and is supported by all NATs. + + Peer-to-peer applications use an alternate method of connection + initiation termed simultaneous-open (Fig. 8, [RFC0793]) to traverse + NATs. In the simultaneous-open mode of operation, both peers send + SYN packets for the same TCP connection. The SYN packets cross in + the network. Upon receiving the other end's SYN packet, each end + responds with a SYN-ACK packet, which also cross in the network. The + connection is considered established once the SYN-ACKs are received. + From the perspective of the NAT, the internal host's SYN packet is + met by an inbound SYN packet for the same connection (as opposed to a + SYN-ACK packet during a 3-way handshake). Subsequent to this + exchange, both an outbound and an inbound SYN-ACK are seen for the + connection. Some NATs erroneously block the inbound SYN for the + connection in progress. Some NATs block or incorrectly translate the + outbound SYN-ACK. Such behavior breaks TCP simultaneous-open and + prevents peer-to-peer applications from functioning correctly behind + a NAT. + + In order to provide network address translation service for TCP, it + is necessary for a NAT to correctly receive, translate, and forward + all packets for a connection that conform to valid transitions of the + TCP State-Machine (Fig. 6, [RFC0793]). + + REQ-2: A NAT MUST support all valid sequences of TCP packets + (defined in [RFC0793]) for connections initiated both internally + as well as externally when the connection is permitted by the NAT. + In particular: + a) In addition to handling the TCP 3-way handshake mode of + connection initiation, A NAT MUST handle the TCP simultaneous- + open mode of connection initiation. + + Justification: The intent of this requirement is to allow standards + compliant TCP stacks to traverse NATs no matter what path the + stacks take through the TCP state-machine and no matter which end + initiates the connection as long as the connection is permitted by + the filtering policy of the NAT (filtering policy is described in + the following section). + a) In addition to TCP packets for a 3-way handshake, A NAT must be + prepared to accept an inbound SYN and an outbound SYN-ACK for + an internally initiated connection in order to support + simultaneous-open. + + + + +Guha, et al. Best Current Practice [Page 6] + +RFC 5382 NAT TCP Requirements October 2008 + + +4.3. Externally Initiated Connections + + The NAT allocates a mapping for the first connection initiated by an + internal endpoint to an external endpoint. In some scenarios, the + NAT's policy may allow this mapping to be reused for connections + initiated from the external side to the internal endpoint. Consider + as before an internal IP address and port (X:x) that is assigned (or + reuses) a mapping (X1':x1') when it initiates a connection to an + external (Y1:y1). An external endpoint (Y2:y2) attempts to initiate + a connection with the internal endpoint by sending a SYN to + (X1':x1'). A NAT can choose to either allow the connection to be + established, or to disallow the connection. If the NAT chooses to + allow the connection, it translates the inbound SYN and routes it to + (X:x) as per the existing mapping. It also translates the SYN-ACK + generated by (X:x) in response and routes it to (Y2:y2), and so on. + Alternately, the NAT can disallow the connection by filtering the + inbound SYN. + + A NAT may allow an existing mapping to be reused by an externally + initiated connection if its security policy permits. Several + different policies are possible as described in [BEHAVE-UDP]. If a + NAT allows the connection initiation from all (Y2:y2), then it is + defined to have "Endpoint-Independent Filtering" behavior. If the + NAT allows connection initiations only when Y2 equals Y1, then the + NAT is defined to have "Address-Dependent Filtering" behavior. If + the NAT allows connection initiations only when (Y2:y2) equals + (Y1:y1), then the NAT is defined to have "Address and Port-Dependent + Filtering" behavior (possible only shortly after the first connection + has been terminated but the mapping is still active). One additional + filtering behavior defined in this document is when the NAT does not + allow any connection initiations from the external side; in such + cases, the NAT is defined to have "Connection-Dependent Filtering" + behavior. The difference between "Address and Port-Dependent + Filtering" and "Connection-Dependent Filtering" behavior is that the + former permits an inbound SYN during the TIME_WAIT state of the first + connection to initiate a new connection while the latter does not. + + REQ-3: If application transparency is most important, it is + RECOMMENDED that a NAT have an "Endpoint-Independent Filtering" + behavior for TCP. If a more stringent filtering behavior is most + important, it is RECOMMENDED that a NAT have an "Address-Dependent + Filtering" behavior. + a) The filtering behavior MAY be an option configurable by the + administrator of the NAT. + b) The filtering behavior for TCP MAY be independent of the + filtering behavior for UDP. + + + + + +Guha, et al. Best Current Practice [Page 7] + +RFC 5382 NAT TCP Requirements October 2008 + + + Justification: The intent of this requirement is to allow peer-to- + peer applications that do not always initiate connections from the + internal side of the NAT to continue to work in the presence of + NATs. This behavior also allows applications behind a BEHAVE + compliant NAT to inter-operate with remote endpoints that are + behind non-BEHAVE compliant (legacy) NATs. If the remote + endpoint's NAT does not have Endpoint-Independent Mapping behavior + but has only one external IP address, then an application can + still traverse the combination of the two NATs if the local NAT + has Address-Dependent Filtering. Section 9 contains a detailed + discussion on the security implications of this requirement. + + If the inbound SYN packet is filtered, either because a corresponding + mapping does not exist or because of the NAT's filtering behavior, a + NAT has two basic choices: to ignore the packet silently, or to + signal an error to the sender. Signaling an error through ICMP + messages allows the sender to quickly detect that the SYN did not + reach the intended destination. Silently dropping the packet, on the + other hand, allows applications to perform simultaneous-open more + reliably. + + Silently dropping the SYN aids simultaneous-open as follows. + Consider that the application is attempting a simultaneous-open and + the outbound SYN from the internal endpoint has not yet crossed the + NAT (due to network congestion or clock skew between the two + endpoints); this outbound SYN would otherwise have created the + necessary mapping at the NAT to allow translation of the inbound SYN. + Since the outbound SYN did not reach the NAT in time, the inbound SYN + cannot be processed. If a NAT responds to the premature inbound SYN + with an error message that forces the external endpoint to abandon + the connection attempt, it hinders applications performing a TCP + simultaneous-open. If instead the NAT silently ignores the inbound + SYN, the external endpoint retransmits the SYN after a TCP timeout. + In the meantime, the NAT creates the mapping in response to the + (delayed) outbound SYN such that the retransmitted inbound SYN can be + routed and simultaneous-open can succeed. The downside to this + behavior is that in the event the inbound SYN is erroneous, the + remote side does not learn of the error until after several TCP + timeouts. + + NAT support for simultaneous-open as well as quickly signaling errors + are both important for applications. Unfortunately, there is no way + for a NAT to signal an error without forcing the endpoint to abort a + potential simultaneous-open: TCP RST and ICMP Port Unreachable + packets require the endpoint to abort the attempt while the ICMP Host + and Network Unreachable errors may adversely affect other connections + to the same host or network [RFC1122]. + + + + +Guha, et al. Best Current Practice [Page 8] + +RFC 5382 NAT TCP Requirements October 2008 + + + In addition, when an unsolicited SYN is received by the NAT, the NAT + may not know whether the application is attempting a simultaneous- + open (and that it should therefore silently drop the SYN) or whether + the SYN is in error (and that it should notify the sender). + + REQ-4: A NAT MUST NOT respond to an unsolicited inbound SYN packet + for at least 6 seconds after the packet is received. If during + this interval the NAT receives and translates an outbound SYN for + the connection the NAT MUST silently drop the original unsolicited + inbound SYN packet. Otherwise, the NAT SHOULD send an ICMP Port + Unreachable error (Type 3, Code 3) for the original SYN, unless + REQ-4a applies. + a) The NAT MUST silently drop the original SYN packet if sending a + response violates the security policy of the NAT. + + Justification: The intent of this requirement is to allow + simultaneous-open to work reliably in the presence of NATs as well + as to quickly signal an error in case the unsolicited SYN is in + error. As of writing this memo, it is not possible to achieve + both; the requirement therefore represents a compromise. The NAT + should tolerate some delay in the outbound SYN for a TCP + simultaneous-open, which may be due to network congestion or loose + synchronization between the endpoints. If the unsolicited SYN is + not part of a simultaneous-open attempt and is in error, the NAT + should endeavor to signal the error in accordance with [RFC1122]. + a) There may, however, be reasons for the NAT to rate-limit or + omit such error notifications, for example, in the case of an + attack. Silently dropping the SYN packet when under attack + allows simultaneous-open to work without consuming any extra + network bandwidth or revealing the presence of the NAT to + attackers. Section 9 mentions the security considerations for + this requirement. + + For NATs that combine NAT functionality with end-host functionality + (e.g., an end-host that also serves as a NAT for other hosts behind + it), REQ-4 above applies only to SYNs intended for the NAT'ed hosts + and not to SYNs intended for the NAT itself. One way to determine + whether the inbound SYN is intended for a NAT'ed host is to allocate + NAT mappings from one port range, and allocate ports for local + endpoints from a different non-overlapping port range. More dynamic + implementations can be imagined. + + + + + + + + + + +Guha, et al. Best Current Practice [Page 9] + +RFC 5382 NAT TCP Requirements October 2008 + + +5. NAT Session Refresh + + A NAT maintains state associated with in-progress and established + connections. Because of this, a NAT is susceptible to a resource- + exhaustion attack whereby an attacker (or virus) on the internal side + attempts to cause the NAT to create more state than for which it has + resources. To prevent such an attack, a NAT needs to abandon + sessions in order to free the state resources. + + A common method that is applicable only to TCP is to preferentially + abandon sessions for crashed endpoints, followed by closed TCP + connections and partially open connections. A NAT can check if an + endpoint for a session has crashed by sending a TCP keep-alive packet + and receiving a TCP RST packet in response. If the NAT cannot + determine whether the endpoint is active, it should not abandon the + session until the TCP connection has been idle for some time. Note + that an established TCP connection can stay idle (but live) + indefinitely; hence, there is no fixed value for an idle-timeout that + accommodates all applications. However, a large idle-timeout + motivated by recommendations in [RFC1122] can reduce the chances of + abandoning a live session. + + A TCP connection passes through three phases: partially open, + established, and closing. During the partially open phase, endpoints + synchronize initial sequence numbers. The phase is initiated by the + first SYN for the connection and extends until both endpoints have + sent a packet with the ACK flag set (TCP states: SYN_SENT and + SYN_RCVD). ACKs in both directions mark the beginning of the + established phase where application data can be exchanged + indefinitely (TCP states: ESTABLISHED, FIN_WAIT_1, FIN_WAIT_2, and + CLOSE_WAIT). The closing phase begins when both endpoints have + terminated their half of the connection by sending a FIN packet. + Once FIN packets are seen in both directions, application data can no + longer be exchanged, but the stacks still need to ensure that the FIN + packets are received (TCP states: CLOSING and LAST_ACK). + + TCP connections can stay in established phase indefinitely without + exchanging any packets. Some end-hosts can be configured to send + keep-alive packets on such idle connections; by default, such keep- + alive packets are sent every 2 hours if enabled [RFC1122]. + Consequently, a NAT that waits for slightly over 2 hours can detect + idle connections with keep-alive packets being sent at the default + rate. TCP connections in the partially open or closing phases, on + the other hand, can stay idle for at most 4 minutes while waiting for + in-flight packets to be delivered [RFC1122]. + + + + + + +Guha, et al. Best Current Practice [Page 10] + +RFC 5382 NAT TCP Requirements October 2008 + + + The "established connection idle-timeout" for a NAT is defined as the + minimum time a TCP connection in the established phase must remain + idle before the NAT considers the associated session a candidate for + removal. The "transitory connection idle-timeout" for a NAT is + defined as the minimum time a TCP connection in the partially open or + closing phases must remain idle before the NAT considers the + associated session a candidate for removal. TCP connections in the + TIME_WAIT state are not affected by the "transitory connection idle- + timeout". + + REQ-5: If a NAT cannot determine whether the endpoints of a TCP + connection are active, it MAY abandon the session if it has been + idle for some time. In such cases, the value of the "established + connection idle-timeout" MUST NOT be less than 2 hours 4 minutes. + The value of the "transitory connection idle-timeout" MUST NOT be + less than 4 minutes. + a) The value of the NAT idle-timeouts MAY be configurable. + + Justification: The intent of this requirement is to minimize the + cases where a NAT abandons session state for a live connection. + While some NATs may choose to abandon sessions reactively in + response to new connection initiations (allowing idle connections + to stay up indefinitely in the absence of new initiations), other + NATs may choose to proactively reap idle sessions. In cases where + the NAT cannot actively determine if the connection is alive, this + requirement ensures that applications can send keep-alive packets + at the default rate (every 2 hours) such that the NAT can + passively determine that the connection is alive. The additional + 4 minutes allows time for in-flight packets to cross the NAT. + + NAT behavior for handling RST packets, or connections in TIME_WAIT + state is left unspecified. A NAT MAY hold state for a connection in + TIME_WAIT state to accommodate retransmissions of the last ACK. + However, since the TIME_WAIT state is commonly encountered by + internal endpoints properly closing the TCP connection, holding state + for a closed connection may limit the throughput of connections + through a NAT with limited resources. [RFC1337] describes hazards + associated with TIME_WAIT assassination. + + The handling of non-SYN packets for connections for which there is no + active mapping is left unspecified. Such packets may be received if + the NAT silently abandons a live connection, or abandons a connection + in TIME_WAIT state before the 4 minute TIME_WAIT period expires. The + decision to either silently drop such packets or to respond with a + TCP RST packet is left up to the implementation. + + + + + + +Guha, et al. Best Current Practice [Page 11] + +RFC 5382 NAT TCP Requirements October 2008 + + + NAT behavior for notifying endpoints when abandoning live connections + is left unspecified. When a NAT abandons a live connection, for + example due to a timeout expiring, the NAT MAY either send TCP RST + packets to the endpoints or MAY silently abandon the connection. + + Sending a RST notification allows endpoint applications to recover + more quickly; however, notifying the endpoints may not always be + possible if, for example, session state is lost due to a power + failure. + +6. Application Level Gateways + + Application Level Gateways (ALGs) in certain NATs modify IP addresses + and TCP ports embedded inside application protocols. Such ALGs may + interfere with UNSAF methods or protocols that try to be NAT-aware + and must therefore be used with extreme caution. + + REQ-6: If a NAT includes ALGs that affect TCP, it is RECOMMENDED + that all of those ALGs (except for FTP [RFC0959]) be disabled by + default. + + Justification: The intent of this requirement is to prevent ALGs + from interfering with UNSAF methods. The default state of an FTP + ALG is left unspecified because of legacy concerns: as of writing + this memo, a large fraction of legacy FTP clients do not enable + passive (PASV) mode by default and require an ALG to traverse + NATs. + +7. Other Requirements Applicable to TCP + + A list of general and UDP-specific NAT behavioral requirements are + described in [BEHAVE-UDP]. A list of ICMP-specific NAT behavioral + requirements are described in [BEHAVE-ICMP]. The requirements listed + below reiterate the requirements from these two documents that + directly affect TCP. The following requirements do not relax any + requirements in [BEHAVE-UDP] or [BEHAVE-ICMP]. + +7.1. Port Assignment + + NATs that allow different internal endpoints to simultaneously use + the same mapping are defined in [BEHAVE-UDP] to have a "Port + assignment" behavior of "Port overloading". Such behavior is + undesirable, as it prevents two internal endpoints sharing the same + mapping from establishing simultaneous connections to a common + external endpoint. + + REQ-7: A NAT MUST NOT have a "Port assignment" behavior of "Port + overloading" for TCP. + + + +Guha, et al. Best Current Practice [Page 12] + +RFC 5382 NAT TCP Requirements October 2008 + + + Justification: This requirement allows two applications on the + internal side of the NAT to consistently communicate with the same + destination. + + NAT behavior for preserving the source TCP port range for connections + is left unspecified. Some applications expect the source TCP port to + be in the well-known range (TCP ports from 0 to 1023). The "r" + series of commands (rsh, rcp, rlogin, etc.) are an example. NATs + that preserve the range from which the source port is picked allow + such applications to function properly through the NAT; however, by + doing so the NAT may compromise the security of the application in + certain situations; applications that depend only on the IP address + and source TCP port range for security (the "r" commands, for + example) cannot distinguish between an attacker and a legitimate user + behind the same NAT. + +7.2. Hairpinning Behavior + + NATs that forward packets originating from an internal address, + destined for an external address that matches the active mapping for + an internal address, back to that internal address are defined in + [BEHAVE-UDP] as supporting "hairpinning". If the NAT presents the + hairpinned packet with an external source IP address and port (i.e., + the mapped source address and port of the originating internal + endpoint), then it is defined to have "External source IP address and + port" for hairpinning. Hairpinning is necessary to allow two + internal endpoints (known to each other only by their external mapped + addresses) to communicate with each other. "External source IP + address and port" behavior for hairpinning avoids confusing + implementations that expect the external source IP address and port. + + REQ-8: A NAT MUST support "hairpinning" for TCP. + a) A NAT's hairpinning behavior MUST be of type "External source + IP address and port". + + Justification: This requirement allows two applications behind the + same NAT that are trying to communicate with each other using + their external addresses. + a) Using the external source address and port for the hairpinned + packet is necessary for applications that do not expect to + receive a packet from a different address than the external + address they are trying to communicate with. + +7.3. ICMP Responses to TCP Packets + + Several TCP mechanisms depend on the reception of ICMP error messages + triggered by the transmission of TCP segments. One such mechanism is + path MTU discovery [RFC1191], which is required for the correct + + + +Guha, et al. Best Current Practice [Page 13] + +RFC 5382 NAT TCP Requirements October 2008 + + + operation of TCP. The current path MTU discovery mechanism requires + the sender of TCP segments to be notified of ICMP "Datagram Too Big" + responses. + + REQ-9: If a NAT translates TCP, it SHOULD translate ICMP Destination + Unreachable (Type 3) messages. + + Justification: Translating ICMP Destination Unreachable messages, + particularly the "Fragmentation Needed and Don't Fragment was Set" + (Type 3, Code 4) message avoids communication failures ("black + holes" [RFC2923]). Furthermore, TCP's connection establishment + and maintenance mechanisms also behave much more efficiently when + ICMP Destination Unreachable messages arrive in response to + outgoing TCP segments. + + REQ-10: Receipt of any sort of ICMP message MUST NOT terminate the + NAT mapping or TCP connection for which the ICMP was generated. + + Justification: This is necessary for reliably performing TCP + simultaneous-open where a remote NAT may temporarily signal an + ICMP error. + +8. Requirements + + A NAT that supports all of the mandatory requirements of this + specification (i.e., the "MUST") and is compliant with [BEHAVE-UDP], + is "compliant with this specification". A NAT that supports all of + the requirements of this specification (i.e., included the + "RECOMMENDED") and is fully compliant with [BEHAVE-UDP] is "fully + compliant with all the mandatory and recommended requirements of this + specification". + + REQ-1: A NAT MUST have an "Endpoint-Independent Mapping" behavior + for TCP. + + REQ-2: A NAT MUST support all valid sequences of TCP packets + (defined in [RFC0793]) for connections initiated both internally + as well as externally when the connection is permitted by the NAT. + In particular: + a) In addition to handling the TCP 3-way handshake mode of + connection initiation, A NAT MUST handle the TCP simultaneous- + open mode of connection initiation. + + REQ-3: If application transparency is most important, it is + RECOMMENDED that a NAT have an "Endpoint-Independent Filtering" + behavior for TCP. If a more stringent filtering behavior is most + important, it is RECOMMENDED that a NAT have an "Address-Dependent + Filtering" behavior. + + + +Guha, et al. Best Current Practice [Page 14] + +RFC 5382 NAT TCP Requirements October 2008 + + + a) The filtering behavior MAY be an option configurable by the + administrator of the NAT. + b) The filtering behavior for TCP MAY be independent of the + filtering behavior for UDP. + + REQ-4: A NAT MUST NOT respond to an unsolicited inbound SYN packet + for at least 6 seconds after the packet is received. If during + this interval the NAT receives and translates an outbound SYN for + the connection the NAT MUST silently drop the original unsolicited + inbound SYN packet. Otherwise, the NAT SHOULD send an ICMP Port + Unreachable error (Type 3, Code 3) for the original SYN, unless + REQ-4a applies. + a) The NAT MUST silently drop the original SYN packet if sending a + response violates the security policy of the NAT. + + REQ-5: If a NAT cannot determine whether the endpoints of a TCP + connection are active, it MAY abandon the session if it has been + idle for some time. In such cases, the value of the "established + connection idle-timeout" MUST NOT be less than 2 hours 4 minutes. + The value of the "transitory connection idle-timeout" MUST NOT be + less than 4 minutes. + a) The value of the NAT idle-timeouts MAY be configurable. + + REQ-6: If a NAT includes ALGs that affect TCP, it is RECOMMENDED + that all of those ALGs (except for FTP [RFC0959]) be disabled by + default. + + The following requirements reiterate requirements from [BEHAVE-UDP] + or [BEHAVE-ICMP] that directly affect TCP. This document does not + relax any requirements in [BEHAVE-UDP] or [BEHAVE-ICMP]. + + REQ-7: A NAT MUST NOT have a "Port assignment" behavior of "Port + overloading" for TCP. + + REQ-8: A NAT MUST support "hairpinning" for TCP. + a) A NAT's hairpinning behavior MUST be of type "External source + IP address and port". + + REQ-9: If a NAT translates TCP, it SHOULD translate ICMP Destination + Unreachable (Type 3) messages. + + REQ-10: Receipt of any sort of ICMP message MUST NOT terminate the + NAT mapping or TCP connection for which the ICMP was generated. + + + + + + + + +Guha, et al. Best Current Practice [Page 15] + +RFC 5382 NAT TCP Requirements October 2008 + + +9. Security Considerations + + [BEHAVE-UDP] discusses security considerations for NATs that handle + IP and unicast UDP traffic. Security concerns specific to handling + TCP packets are discussed in this section. + + Security considerations for REQ-1: This requirement does not + introduce any TCP-specific security concerns. + + Security considerations for REQ-2: This requirement does not + introduce any TCP-specific security concerns. Simultaneous-open + and other transitions in the TCP state machine are by-design and + necessary for TCP to work correctly in all scenarios. Further, + this requirement only affects connections already in progress as + authorized by the NAT in accordance with its policy. + + Security considerations for REQ-3: The security provided by the NAT + is governed by its filtering behavior as addressed in + [BEHAVE-UDP]. Connection-Dependent Filtering behavior is most + secure from a firewall perspective, but severely restricts + connection initiations through a NAT. Endpoint-Independent + Filtering behavior, which is most transparent to applications, + requires an attacker to guess the IP address and port of an active + mapping in order to get his packet to an internal host. Address- + Dependent Filtering, on the other hand, is less transparent than + Endpoint-Independent Filtering but more transparent than + Connection-Dependent Filtering; it is more secure than Endpoint- + Independent Filtering as it requires an attacker to additionally + guess the address of the external endpoint for a NAT session + associated with the mapping and be able to receive packets + addressed to the same. While this protects against most attackers + on the Internet, it does not necessarily protect against attacks + that originate from behind a remote NAT with a single IP address + that is also translating a legitimate connection to the victim. + + Security considerations for REQ-4: This document recommends that a + NAT respond to unsolicited inbound SYN packets with an ICMP error + delayed by a few seconds. Doing so may reveal the presence of a + NAT to an external attacker. Silently dropping the SYN makes it + harder to diagnose network problems and forces applications to + wait for the TCP stack to finish several retransmissions before + reporting an error. An implementer must therefore understand and + carefully weigh the effects of not sending an ICMP error or rate- + limiting such ICMP errors to a very small number. + + + + + + + +Guha, et al. Best Current Practice [Page 16] + +RFC 5382 NAT TCP Requirements October 2008 + + + Security considerations for REQ-5: This document recommends that a + NAT that passively monitors TCP state keep idle sessions alive for + at least 2 hours 4 minutes or 4 minutes depending on the state of + the connection. If a NAT is under attack, it may attempt to + actively determine the liveliness of a TCP connection or let the + NAT administrator configure more conservative timeouts. + + Security considerations for REQ-6: This requirement does not + introduce any TCP-specific security concerns. + + Security considerations for REQ-7: This requirement does not + introduce any TCP-specific security concerns. + + Security considerations for REQ-8: This requirement does not + introduce any TCP-specific security concerns. + + Security considerations for REQ-9: This requirement does not + introduce any TCP-specific security concerns. + + Security considerations for REQ-10: This requirement does not + introduce any TCP-specific security concerns. + + NAT implementations that modify TCP sequence numbers (e.g., for + privacy reasons or for ALG support) must ensure that TCP packets with + Selective Acknowledgement (SACK) notifications [RFC2018] are properly + handled. + + NAT implementations that modify local state based on TCP flags in + packets must ensure that out-of-window TCP packets are properly + handled. [RFC4953] summarizes and discusses a variety of solutions + designed to prevent attackers from affecting TCP connections. + +10. Acknowledgments + + Joe Touch contributed the mechanism for handling unsolicited inbound + SYNs. Thanks to Mark Allman, Francois Audet, Lars Eggert, Paul + Francis, Fernando Gont, Sam Hartman, Paul Hoffman, Dave Hudson, + Cullen Jennings, Philip Matthews, Tom Petch, Magnus Westerlund, and + Dan Wing for their many contributions, comments, and suggestions. + + + + + + + + + + + + +Guha, et al. Best Current Practice [Page 17] + +RFC 5382 NAT TCP Requirements October 2008 + + +11. References + +11.1. Normative References + + [BEHAVE-UDP] Audet, F. and C. Jennings, "Network Address + Translation (NAT) Behavioral Requirements for Unicast + UDP", BCP 127, RFC 4787, January 2007. + + [RFC0793] Postel, J., "Transmission Control Protocol", STD 7, + RFC 793, September 1981. + + [RFC0959] Postel, J. and J. Reynolds, "File Transfer Protocol", + STD 9, RFC 959, October 1985. + + [RFC1122] Braden, R., "Requirements for Internet Hosts - + Communication Layers", STD 3, RFC 1122, October 1989. + + [RFC1191] Mogul, J. and S. Deering, "Path MTU discovery", + RFC 1191, November 1990. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + +11.2. Informational References + + [BEHAVE-ICMP] Srisuresh, P., Ford, B., Sivakumar, S., and S. Guha, + "NAT Behavioral Requirements for ICMP protocol", Work + in Progress, June 2008. + + [NAT-MIB] Rohit, R., Srisuresh, P., Raghunarayan, R., Pai, N., + and C. Wang, "Definitions of Managed Objects for + Network Address Translators (NAT)", RFC 4008, + March 2005. + + [NATBLASTER] Biggadike, A., Ferullo, D., Wilson, G., and A. Perrig, + "NATBLASTER: Establishing TCP connections between + hosts behind NATs", Proceedings of the ACM SIGCOMM + Asia Workshop (Beijing, China), April 2005. + + [P2PNAT] Ford, B., Srisuresh, P., and D. Kegel, "Peer-to-peer + communication across network address translators", + Proceedings of the USENIX Annual Technical + Conference (Anaheim, CA), April 2005. + + [RFC1337] Braden, B., "TIME-WAIT Assassination Hazards in TCP", + RFC 1337, May 1992. + + + + + +Guha, et al. Best Current Practice [Page 18] + +RFC 5382 NAT TCP Requirements October 2008 + + + [RFC1644] Braden, B., "T/TCP -- TCP Extensions for Transactions + Functional Specification", RFC 1644, July 1994. + + [RFC2018] Mathis, M., Mahdavi, J., Floyd, S., and A. Romanow, + "TCP Selective Acknowledgment Options", RFC 2018, + October 1996. + + [RFC2663] Srisuresh, P. and M. Holdrege, "IP Network Address + Translator (NAT) Terminology and Considerations", + RFC 2663, August 1999. + + [RFC2923] Lahey, K., "TCP Problems with Path MTU Discovery", + RFC 2923, September 2000. + + [RFC3022] Srisuresh, P. and K. Egevang, "Traditional IP Network + Address Translator (Traditional NAT)", RFC 3022, + January 2001. + + [RFC4614] Duke, M., Braden, R., Eddy, W., and E. Blanton, "A + Roadmap for Transmission Control Protocol (TCP) + Specification Documents", RFC 4614, September 2006. + + [RFC4953] Touch, J., "Defending TCP Against Spoofing Attacks", + RFC 4953, July 2007. + + [STUNT] Guha, S. and P. Francis, "NUTSS: A SIP based approach + to UDP and TCP connectivity", Proceedings of the ACM + SIGCOMM Workshop on Future Directions in Network + Architecture (Portland, OR), August 2004. + + [TCPTRAV] Guha, S. and P. Francis, "Characterization and + Measurement of TCP Traversal through NATs and + Firewalls", Proceedings of the Internet Measurement + Conference (Berkeley, CA), October 2005. + + + + + + + + + + + + + + + + + +Guha, et al. Best Current Practice [Page 19] + +RFC 5382 NAT TCP Requirements October 2008 + + +Authors' Addresses + + Saikat Guha (editor) + Cornell University + 331 Upson Hall + Ithaca, NY 14853 + US + Phone: +1 607 255 1008 + EMail: saikat@cs.cornell.edu + + Kaushik Biswas + Cisco Systems, Inc. + 170 West Tasman Dr. + San Jose, CA 95134 + US + Phone: +1 408 525 5134 + EMail: kbiswas@cisco.com + + Bryan Ford + Max Planck Institute for Software Systems + Campus Building E1 4 + D-66123 Saarbruecken + Germany + Phone: +49-681-9325657 + EMail: baford@mpi-sws.org + + Senthil Sivakumar + Cisco Systems, Inc. + 7100-8 Kit Creek Road + PO Box 14987 + Research Triangle Park, NC 27709-4987 + US + Phone: +1 919 392 5158 + EMail: ssenthil@cisco.com + + Pyda Srisuresh + Kazeon Systems, Inc. + 1161 San Antonio Rd. + Mountain View, CA 94043 + US + Phone: +1 408 836 4773 + EMail: srisuresh@yahoo.com + + + + + + + + + +Guha, et al. Best Current Practice [Page 20] + +RFC 5382 NAT TCP Requirements October 2008 + + +Full Copyright Statement + + Copyright (C) The IETF Trust (2008). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND + THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF + THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at + ietf-ipr@ietf.org. + + + + + + + + + + + + +Guha, et al. Best Current Practice [Page 21] + diff --git a/.gitattributes b/.gitattributes index 3db8992b08..298fddef71 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,7 @@ k8s-intf/src/generated/** linguist-generated k8s-intf/src/generated/mod.rs -linguist-generated npins/* linguist-generated +# `duvet report` writes these: the extracted requirements carry the RFC text verbatim as +# comments, which is thousands of lines of prose that no one edits by hand. +.duvet/requirements/** linguist-generated +.duvet/snapshot.txt linguist-generated diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index da6e25d377..966f05ee8c 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -390,6 +390,24 @@ jobs: with: recipe: "license-headers" + - name: "duvet-check" + id: "duvet-check" + continue-on-error: true + uses: *just + with: + recipe: "duvet-check" + + # Deliberately no `id`. `check-lint-wiring` requires every lint step that has one to + # have its outcome read below, and reading it is what would make this a required + # check -- the aggregator fails on any outcome that is not success or skipped. This + # step formats tables into the job summary; `duvet-check` above is the gate. + - name: "duvet-summary" + if: always() + continue-on-error: true + uses: *just + with: + recipe: "duvet-summary" + - name: "Flag any lint failures" if: always() env: @@ -406,6 +424,7 @@ jobs: check-push-filter=${{ steps.check-push-filter.outcome }} check-deps-reuse=${{ steps.check-deps-reuse.outcome }} license-headers=${{ steps.license-headers.outcome }} + duvet-check=${{ steps.duvet-check.outcome }} run: | set -euo pipefail status=0 diff --git a/cli/src/cliproto.rs b/cli/src/cliproto.rs index e620a31bf0..ad7920ccb7 100644 --- a/cli/src/cliproto.rs +++ b/cli/src/cliproto.rs @@ -31,8 +31,10 @@ use std::{net::IpAddr, os::unix::net::UnixDatagram}; use strum::{AsRefStr, EnumIter, EnumString}; use thiserror::Error; -// Size of a chunk. Messages may be split into chunks of this size if they exceed it -const CLI_MSG_CHUNK_SIZE: usize = 2048; +// Size of a chunk. Messages may be split into chunks of this size if they exceed it. +// Public so that a test asserting an answer spans several chunks measures the real size +// rather than a copy of the number that silently stops tracking it. +pub const CLI_MSG_CHUNK_SIZE: usize = 2048; // Socket snd/rx size. This is a recommendation as it can't be enforced 100% pub const CLI_RX_BUFF_SIZE: usize = CLI_MSG_CHUNK_SIZE * 8192; diff --git a/dataplane/src/packet_processor/ipforward.rs b/dataplane/src/packet_processor/ipforward.rs index 719d471f22..f41d2dcf2b 100644 --- a/dataplane/src/packet_processor/ipforward.rs +++ b/dataplane/src/packet_processor/ipforward.rs @@ -219,6 +219,15 @@ impl IpForwarder { } /// Encapsulate a packet in Vxlan with the provided [`VxlanEncapsulation`] params + //= https://www.rfc-editor.org/rfc/rfc4787#section-10 + //= type=todo + //# REQ-13: If the packet received on an internal IP address has DF=1, + //# the NAT MUST send back an ICMP message "Fragmentation needed and + //# DF set" to the host, as described in [RFC0792]. + //= https://www.rfc-editor.org/rfc/rfc4787#section-10 + //= type=todo + //# a) If the packet has DF=0, the NAT MUST fragment the packet and + //# SHOULD send the fragments in order. fn vxlan_encap( &self, packet: &mut Packet, diff --git a/development/code/README.md b/development/code/README.md index 7e512e6f92..3e1ad73413 100644 --- a/development/code/README.md +++ b/development/code/README.md @@ -12,6 +12,8 @@ wrong thing. If you need to write a test, prefer [property-based tests] over simple unit tests. +To find out whether they are saying what the specification asked for, see the +[specification compliance note][duvet]. If you need to handle errors, prefer `Result` types over panics in general, but see the [error handling guide][error] for details. @@ -21,6 +23,7 @@ If you need to [handle an error][error], follow the guidelines. [avoid-global-reasoning]: ./avoid-global-reasoning.md [property-based tests]: ./property-testing.md +[duvet]: ./spec-compliance.md [error]: ./error-handling.md ## Testing instructions diff --git a/development/code/spec-compliance.md b/development/code/spec-compliance.md new file mode 100644 index 0000000000..656ef075e1 --- /dev/null +++ b/development/code/spec-compliance.md @@ -0,0 +1,200 @@ +# Specification compliance with duvet + +Status: **two specifications tracked, the RFC corpus audited, the procedure itself not yet proven.** +The open-questions list below is expected to grow; it is written down so that it grows in one place +rather than in four people's heads. + +## What it is for + +[duvet] matches citations in the source -- `//= ` followed by the requirement text, quoted +verbatim -- against requirements it extracts from a specification. A requirement nothing implements, +or an implementation nothing tests, becomes visible. + +It is the third leg of a stool. [bolero](./property-testing.md) asks whether a property holds. +cargo-mutants asks whether there are enough properties. Neither can ask +whether they are the properties the specification called for. + +That third question is not decoration. Mutation testing can actively **entrench a deviation**: +the cheapest way to kill a surviving mutant is to assert the behaviour that was observed, which +cements whatever the code already did. A suite can converge on a perfect score against the wrong +specification, and nothing inside the suite can notice. + +## What it found, first time out + +Two specifications, roughly one afternoon. + +| | outcome | +| --- | --- | +| RFC 4884 length validation | **real defect**, fixed in `net/src/headers/embedded.rs` | +| RFC 5382 REQ-7, REQ-10 | already held, already tested, never named | +| RFC 5382 REQ-5, REQ-1 | conformance gaps, recorded as `todo` | + +The defect is the strongest argument for the tool: `is_full_payload()` checked the RFC 4884 length +attribute in **bits** where the RFC counts 32-bit **words**, so it rejected seven of eight +conforming lengths and admitted sub-128-octet fields the RFC forbids. It had property tests. They +passed. + +The two already-held requirements are the second-strongest argument, for the opposite reason. The +masquerade exclusivity property -- "two live flows never share a translation" -- was written before +anyone read RFC 5382, and turns out to _be_ REQ-7 verbatim. Citing it converts an accident into a +claim a reviewer can check and a refactor cannot quietly undo. + +### `todo` versus `exception` + +Both are ways of saying "not implemented". They are not interchangeable. An `exception` asserts that +somebody weighed the requirement and declined it; a `todo` asserts only that nobody has yet. Using +`exception` for an undecided requirement is self-granted absolution, and it is invisible afterwards. +REQ-1 and REQ-5 are `todo` for exactly this reason. + +## What the tool will and will not parse + +Measured by running the extractor over the entire RFC series -- 9,827 documents, 23 seconds. + +**It is deterministic.** Two full sweeps produced 68,257 emitted files that are byte-identical, and +single-threaded output matches parallel. Snapshot regression gating is safe. + +**It fails loudly on 35 documents**, all `invalid utf-8`, nearly all pre-1990 documents carrying +Latin-1 bytes. The only ones a networking project might want are RFC 1305 (NTPv3) and RFC 2557. + +**It is blind to lowercase normative language.** This is the important one: + +| | RFC 2119 keywords | lowercase must/should | cites RFC 2119 | +| --- | --- | --- | --- | +| RFC 8200 (IPv6, STD 86) | 0 | 79 | no | +| RFC 3022 (traditional NAT) | 0 | 24 | no | + +RFC 8200 says "It must obey the protocol requirements for routers when receiving (forwarding) +interfaces." That is a real obligation with no uppercase token to key on. duvet is not +malfunctioning -- there is nothing to grip -- but the effect is that **the two specifications +closest to what this dataplane is cannot be tracked directly.** This is the boundary of the method: +it covers BCP-style documents with numbered `REQ-` clauses very well and foundational standards-track +documents not at all. + +Of the 3,767 documents that extract nothing, almost all are legitimately requirement-free. The large +cluster showing exactly ten keywords is the boilerplate "The key words MUST, MUST NOT, ..." +paragraph, which duvet correctly declines to treat as normative. + +**Modern format is fine.** There is no cliff at RFC 8650; xml2rfc v3 output parses (RFC 9000: 522 +requirements, RFC 9110: 412, RFC 8446: 431). + +## Do not cite a composite BCP + +The worst failure found, because it exits 0 and reports a plausible number. + +209 of 239 BCP entries in the mirror are symlinks to a single RFC and are harmless. The other 27 are +concatenations, and **BCP 127 is one of them**: RFC 4787 + RFC 6888 + RFC 7857 in one file. + +| | requirements | +| --- | --- | +| `bcp127.txt` | **42** | +| RFC 4787 + 6888 + 7857, extracted separately | **129** | + +duvet keys requirements by section anchor, and each member document has its own `section-5`, so the +last document in the concatenation wins. RFC 6888 loses all three of its sections; RFC 4787 loses +eight of thirteen, including section 5, _NAT Session Refresh_, where the UDP timeout requirements +live. No warning is emitted. + +Always cite the individual RFC. The composites remain useful as a **membership oracle** -- "BCP 127 +now contains an RFC we do not track" is the cheapest available drift alarm, and it is a `grep` over +27 files rather than something duvet has to parse. + +## Synthesizing requirements for a non-conforming specification + +duvet accepts a Markdown specification (`-f markdown`), and this is the intended route for RFC 8200 +and RFC 3022: restate their lowercase obligations in RFC 2119 form, in-repo, as a separate +`[[specification]]`. + +The mechanism cooperates. Section anchors are heading slugs rather than numbers, so the composite +collision cannot occur, and the prose around a requirement is carried into the emitted TOML as a +comment, so a derivation note travels with it. + +**The hazard is that this is the one place the method can certify itself.** duvet's value is that +the quoted unit is a sentence somebody else wrote. Once we author the specification we control both +sides of the match, and the path of least resistance is to write the requirement the code already +satisfies -- the same entrenchment failure as mutation testing, moved up a level and much harder to +see, because the result looks like compliance with RFC 8200. + +Rules, therefore: + +- Every synthesized requirement quotes its **source sentence verbatim**, adjacent to it. +- A synthesized requirement may **never be more specific** than the sentence it derives from. +- Where the original is genuinely ambiguous, that ambiguity **is the finding**. Record both readings + for a human; do not resolve it into one confident restatement. +- Review is by somebody who reads the original. A reviewer looking only at our Markdown cannot catch + the failure this is guarding against. + +## Open questions + +Expected to expand. Nothing here is scheduled. + +1. **Which RFCs apply to us at all.** Prior to everything else, and never yet enumerated. RFC 4787 + (59 requirements), RFC 5508 (92), RFC 6888 (41) and RFC 7857 (29) are duvet-friendly, directly + on-topic and untracked -- 221 requirements one config edit away, no synthesis needed. +2. **Which of those are not RFC 2119 conforming**, and so need synthesis per the section above. +3. **Is a citation true?** duvet checks that a `type=test` citation _exists_, not that the test + exercises the requirement. This is the vacuity problem that the llvm-cov execution counters + caught twice. The cross-check uses artifacts we already produce: mutate the region cited + `type=implementation` and see whether the test cited `type=test` fails. If it does not, the + citation is decorative. This is the only item on this list that makes the three tools check each + other rather than merely coexist. +4. **Errata.** The rsync corpus carries no errata bodies -- `inline-errata/` holds stylesheets only. + It reports that 2,613 RFCs have errata and never what they say. A second fetch leg is needed + regardless of how the corpus is pinned. The concrete instance is closed: RFC 4884 has exactly one + erratum, ID 3 (Verified, Technical, section 7), and it replaces "the data structure" with "the + ICMP Extension Structure" in the extension-checksum description. It does not touch section 3, + section 4, `MIN_ORIGINAL_DATAGRAM_OCTETS` or the padding rules. Recorded next to the constant in + `net/src/headers/embedded.rs`, because that is where the next reader is. The general problem + stands: this was read by hand, off-corpus, and nothing re-checks it. +5. **How the corpus is pinned** -- a git mirror, or `oras` into ghcr.io behind `npins`. Sizing: the + metadata that drives every drift alarm (indexes, `bcp/`, `std/`) is 5MB; the 232MB is RFC bodies, + of which we cite perhaps ten. Text gzips about 4:1. +6. **Two alarms, not one.** RFC bodies are immutable, so a diff in `rfc5382.txt` means a rerender or + a corrupt mirror: rare and loud. A new erratum, a new `updated_by`, a new BCP member is expected + churn: a routine pull request. Collapsing both into "the pin moved" trains people to rubber-stamp + it. The corpus has a `rerendered/` directory precisely because the first case is real. +7. **A scoping policy, before the first large specification lands.** Adding STUN drops 200 uncited + requirements into the snapshot in one commit; QUIC would add 522. Without a rule for scoping + _within_ a specification the report becomes wallpaper on the day it gets interesting -- the same + lesson as "do not test printers" and "classify, do not eliminate". + + Partly answered, for one shape of it. Every RFC tracked so far restates its numbered requirements + in a summary section, and duvet keys by section anchor, so each copy counts in the denominator and + only one can ever be annotated: 73 of 213 requirements, 34%, before any scoping question about + _which specifications_. The rule, first settled in the RFC 5508 chapter and now applied to all + four, is **cite the normative section** -- where the requirement is argued rather than tabulated. + `.duvet/config.toml` names the three summary sections and `just duvet-summary` prints the floor + under the table, so the headline percentage is not read as half of what it is. What is still open + is scoping across _sections that do not apply to us at all_, which is the STUN and QUIC case. +8. **Should the snapshot be a blocking gate?** Answered yes, by `ci(dev): Gate on the compliance + snapshot and print its tables`. Unlike cargo-mutants it can be: `duvet report` takes 4ms and is + bit-for-bit deterministic, so it is the cheapest correctness gate we have. Two things the answer + forced, both worth knowing before adding another gate of this shape. `duvet report` writes its + output in place, so `just duvet-check` has to set the committed copies aside and put them back or + it leaves the working tree dirty on every run. And gating a report raises the cost of a wrong + annotation: a `type=test` on an `#[ignore]`d test used to be a document that overstated itself + and is now a gate that reports coverage CI never runs. duvet is a text scanner; it cannot see + `#[ignore]`, `#[cfg(...)]` or an early `return`. Open question 3 is the general form of that, and + the reason it matters more now than it did. +9. **A coverage report analogous to the existing ones**, so that specification coverage is read the + same way as line and mutant coverage. + +## Operational notes + +- **`//=` is duvet's citation marker.** Banner comments of the form `//======== Fib ========//` are + parsed as citations and produce errors. `routing/src/cli/display.rs` carried thirteen of them; they + were deleted rather than spaced, since the section headings they drew were already the names of the + functions beneath them. Either fix works -- the point is that a banner in a source file duvet scans + is a parse error waiting for whoever adds the crate to `[[source]]`. +- **Everything under `.duvet/` is committed except `reports/`.** `duvet report` reads the + specification from `.duvet/specifications/` and only reaches the network when it is missing, so + vendoring the text is what lets the report run in a nix build sandbox. Verified offline under + `unshare -rn`. +- **The mirror is a drop-in for the network fetch.** Text pulled by rsync is byte-identical to what + duvet fetches from rfc-editor.org, and re-extraction produces identical requirements apart from + the `target` line. +- **`see_also` is empty** in the per-RFC JSON, so the RFC-to-BCP mapping has to come from the `bcp/` + symlinks or the index files, not the metadata. +- **`-n.json`** in the corpus is an all-null artifact of the mirror. It parses, so it will not crash + a loader, but anything iterating the JSON should skip a null `doc_id`. + +[duvet]: https://awslabs.github.io/duvet/ diff --git a/justfile b/justfile index b96bf7b534..c0cbb2f3dd 100644 --- a/justfile +++ b/justfile @@ -729,7 +729,8 @@ lint: \ (nixfmt) \ (check-lint-wiring) \ (check-push-filter) \ - (license-headers) + (license-headers) \ + (duvet-check) {{ _just_debuggable_ }} # Cargo cannot archive doctests, so run them inside the Nix sandbox. @@ -768,10 +769,23 @@ duvet-check: exit 1 fi done + # `duvet report` rewrites the snapshot *and* every requirement TOML in place, so the + # committed copies are set aside and put back either way. A check that leaves the + # working tree dirty is a trap anywhere; in a repo with worktrees and a shared stash + # stack it is a trap that costs someone else's work. + committed="$(mktemp -d)" + trap 'rm -rf .duvet/requirements .duvet/snapshot.txt; \ + mv "${committed}/requirements" .duvet/requirements; \ + mv "${committed}/snapshot.txt" .duvet/snapshot.txt; \ + rmdir "${committed}"' EXIT + cp -r .duvet/requirements "${committed}/requirements" + cp .duvet/snapshot.txt "${committed}/snapshot.txt" duvet report - if ! git diff --quiet -- .duvet/snapshot.txt; then - echo "error: .duvet/snapshot.txt is stale; run \`just duvet\` and commit the result" >&2 - git --no-pager diff -- .duvet/snapshot.txt >&2 + stale=0 + diff -u "${committed}/snapshot.txt" .duvet/snapshot.txt || stale=1 + diff -ru "${committed}/requirements" .duvet/requirements || stale=1 + if [ "${stale}" != 0 ]; then + echo "error: the duvet report is stale; run \`just duvet\` and commit the result" >&2 exit 1 fi diff --git a/nat/src/masquerade/apalloc/alloc.rs b/nat/src/masquerade/apalloc/alloc.rs index 50c2eb6412..8c9de60a65 100644 --- a/nat/src/masquerade/apalloc/alloc.rs +++ b/nat/src/masquerade/apalloc/alloc.rs @@ -117,8 +117,22 @@ impl IpAllocator { // FIXME: Should we clean up every time?? self.cleanup_used_ips(); + //= https://www.rfc-editor.org/rfc/rfc4787#section-4.1 + //= type=exception + //= reason=the address reused is whichever one the pool is currently drawing from, not the one this internal host already holds, so a host whose sessions straddle a port-capacity boundary is split across two public addresses + //# REQ-2: It is RECOMMENDED that a NAT have an "IP address pooling" + //# behavior of "Paired". // Draw a fresh address only when the addresses already in use are exhausted. Other errors // describe allocator failure and must be preserved. + // + // Reuse-before-draw gives a host one public address for as long as the pool does not + // move on, which is why this reads as Paired in the common case -- but the identity + // that would make it Paired is not carried: `allocate` never sees the internal IP, so + // it cannot return to an address this host already holds. Interleave two hosts across + // an exhaustion boundary and both spill; + // `expiry::pool_exhaustion_splits_a_host_across_public_addresses` measures 254 of 254 + // hosts split. Implementing REQ-2 means keying the choice on the internal IP for the + // lifetime of its mappings. match self.reuse_allocated_ip(allow_null) { Ok(port) => Ok(port), Err(e) if e.is_exhaustion() => self.allocate_from_new_ip(allow_null), diff --git a/nat/src/masquerade/apalloc/mod.rs b/nat/src/masquerade/apalloc/mod.rs index 05b9204473..053f23e9a1 100644 --- a/nat/src/masquerade/apalloc/mod.rs +++ b/nat/src/masquerade/apalloc/mod.rs @@ -99,6 +99,9 @@ mod setup; mod test_alloc; pub use port_alloc::AllocatedPort; +// `expiry` is `#![cfg(test)]`, so this is dead in a shipping build. +#[cfg(test)] +pub(crate) use setup::DEFAULT_MASQUERADE_IDLE_TIMEOUT; /////////////////////////////////////////////////////////////////////////////// // PoolTableKey @@ -281,6 +284,13 @@ impl NatAllocator { self.genid.store(genid, Ordering::Relaxed); } + //= https://www.rfc-editor.org/rfc/rfc5382#section-4.1 + //= type=todo + //# REQ-1: A NAT MUST have an "Endpoint-Independent Mapping" behavior + //# for TCP. + //= https://www.rfc-editor.org/rfc/rfc4787#section-4.1 + //= type=todo + //# REQ-1: A NAT MUST have an "Endpoint-Independent Mapping" behavior. fn allocate_v4( &self, src_vpcd: VpcDiscriminant, diff --git a/nat/src/masquerade/apalloc/pool_fuzz.rs b/nat/src/masquerade/apalloc/pool_fuzz.rs index 9f7ee7cc08..3e482d8763 100644 --- a/nat/src/masquerade/apalloc/pool_fuzz.rs +++ b/nat/src/masquerade/apalloc/pool_fuzz.rs @@ -259,6 +259,14 @@ fn re_reservation_after_a_config_change_is_honoured() { }); } +//= https://www.rfc-editor.org/rfc/rfc5382#section-7.1 +//= type=test +//# REQ-7: A NAT MUST NOT have a "Port assignment" behavior of "Port +//# overloading" for TCP. +//= https://www.rfc-editor.org/rfc/rfc4787#section-4.2.1 +//= type=test +//# REQ-3: A NAT MUST NOT have a "Port assignment" behavior of "Port +//# overloading". #[test] #[cfg_attr(miri, ignore = "exhaustive allocator walk is too slow under miri")] fn a_region_can_be_allocated_dry() { diff --git a/nat/src/masquerade/apalloc/port_alloc.rs b/nat/src/masquerade/apalloc/port_alloc.rs index c951899dc1..93a615d68b 100644 --- a/nat/src/masquerade/apalloc/port_alloc.rs +++ b/nat/src/masquerade/apalloc/port_alloc.rs @@ -92,6 +92,11 @@ pub(crate) struct PortAllocator { exclude_wellknown_ports: bool, } +//= https://www.rfc-editor.org/rfc/rfc4787#section-4.2.1 +//= type=exception +//= reason=preserving a well-known source port means allocating out of the IANA system range on the public side, where the port is not this NAT's to spend; the recommendation is declined rather than unimplemented +//# a) If the host's source port was in the range 0-1023, it is +//# RECOMMENDED the NAT's source port be in the same range. /// Ports 0..=1023 cover the IANA system/well-known range and should not be /// allocated by masquerade NAT for TCP or UDP. pub(super) const IANA_WELLKNOWN_PORT_LIMIT: u16 = 1024; @@ -830,6 +835,12 @@ impl Bitmap256 { // // In the last example above, we have three trailing ones in the first half, telling us that // port at 1 << 3 (port number 3) is free. + //= https://www.rfc-editor.org/rfc/rfc5382#section-7.1 + //# REQ-7: A NAT MUST NOT have a "Port assignment" behavior of "Port + //# overloading" for TCP. + //= https://www.rfc-editor.org/rfc/rfc4787#section-4.2.1 + //# REQ-3: A NAT MUST NOT have a "Port assignment" behavior of "Port + //# overloading". fn allocate_port_from_bitmap(&mut self) -> Result { #[allow(clippy::cast_possible_truncation)] // max value is 128 let ones = self.first_half.trailing_ones() as u16; diff --git a/nat/src/masquerade/apalloc/setup.rs b/nat/src/masquerade/apalloc/setup.rs index c6f018ee23..eef5eabf16 100644 --- a/nat/src/masquerade/apalloc/setup.rs +++ b/nat/src/masquerade/apalloc/setup.rs @@ -22,7 +22,7 @@ use std::net::{Ipv4Addr, Ipv6Addr}; use std::time::Duration; use tracing::{debug, error}; -const DEFAULT_MASQUERADE_IDLE_TIMEOUT: Duration = Duration::from_mins(2); +pub(crate) const DEFAULT_MASQUERADE_IDLE_TIMEOUT: Duration = Duration::from_mins(2); impl NatAllocator { pub(crate) fn build_pool44(config: &MasqueradeConfig) -> PoolTable { diff --git a/nat/src/masquerade/contract.rs b/nat/src/masquerade/contract.rs new file mode 100644 index 0000000000..49c348c85f --- /dev/null +++ b/nat/src/masquerade/contract.rs @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Open Network Fabric Authors + +use crate::common::NatFlowStatus; + +pub(crate) trait Requirement { + type Error: core::error::Error; + + const SPEC: &'static str; + + const ID: &'static str; + + fn check(&self) -> Result<(), Self::Error>; +} + +const fn contains(haystack: &str, needle: &str) -> bool { + let (h, n) = (haystack.as_bytes(), needle.as_bytes()); + if n.is_empty() { + return true; + } + if h.len() < n.len() { + return false; + } + let mut i = 0; + while i <= h.len() - n.len() { + let mut j = 0; + while j < n.len() && h[i + j] == n[j] { + j += 1; + } + if j == n.len() { + return true; + } + i += 1; + } + false +} + +pub(crate) mod rfc4787 { + use super::{NatFlowStatus, Requirement, contains}; + + const SECTION_9: &str = + include_str!("../../../.duvet/requirements/www.rfc-editor.org/rfc/rfc4787/section-9.toml"); + + #[derive(Debug, Clone, Copy)] + pub(crate) struct Req12 { + before: NatFlowStatus, + after: NatFlowStatus, + } + + #[derive(Debug, Clone, Copy, PartialEq, thiserror::Error)] + #[error("an ICMP packet moved a live flow from {before:?} to {after:?}")] + pub(crate) struct Req12Violated { + before: NatFlowStatus, + after: NatFlowStatus, + } + + impl Req12 { + pub(crate) const fn new(before: NatFlowStatus, after: NatFlowStatus) -> Self { + Self { before, after } + } + + const fn terminal(status: NatFlowStatus) -> bool { + matches!(status, NatFlowStatus::Closed | NatFlowStatus::Reset) + } + } + + impl Requirement for Req12 { + type Error = Req12Violated; + const SPEC: &'static str = "https://www.rfc-editor.org/rfc/rfc4787#section-9"; + const ID: &'static str = "REQ-12"; + + fn check(&self) -> Result<(), Self::Error> { + if Self::terminal(self.after) && !Self::terminal(self.before) { + return Err(Req12Violated { + before: self.before, + after: self.after, + }); + } + Ok(()) + } + } + + // A distinctive fragment of the quote as well as the bare identifier. Section 9 holds + // six requirements, so `contains(SECTION_9, "REQ-12")` alone keeps passing if the text + // beside REQ-12 drifts -- which is the drift a build failure is worth having. + const _: () = assert!( + contains(SECTION_9, ::ID), + "rfc4787#section-9 does not state REQ-12" + ); + const _: () = assert!( + contains(SECTION_9, "MUST NOT terminate the"), + "rfc4787#section-9 no longer states REQ-12 as this contract quotes it" + ); +} + +#[cfg(test)] +mod test { + use super::rfc4787::Req12; + use super::{Requirement, contains}; + use crate::common::NatFlowStatus; + + const STATUSES: [NatFlowStatus; 10] = [ + NatFlowStatus::OneWay, + NatFlowStatus::TwoWay, + NatFlowStatus::Established, + NatFlowStatus::CClosing, + NatFlowStatus::SClosing, + NatFlowStatus::CHalfClose, + NatFlowStatus::SHalfClose, + NatFlowStatus::LastAck, + NatFlowStatus::Reset, + NatFlowStatus::Closed, + ]; + + #[test] + fn the_specification_search_can_fail() { + assert!(contains("REQ-12: Receipt of any", "REQ-12")); + assert!(!contains("REQ-12: Receipt of any", "REQ-42")); + assert!(!contains("REQ-1", "REQ-12"), "a prefix is not a match"); + assert!( + contains("anything", ""), + "the empty needle is always present" + ); + } + + #[test] + fn the_contract_rejects_exactly_the_forbidden_transitions() { + let terminal = |s| matches!(s, NatFlowStatus::Closed | NatFlowStatus::Reset); + let mut rejected = 0; + for before in STATUSES { + for after in STATUSES { + let forbidden = terminal(after) && !terminal(before); + assert_eq!( + Req12::new(before, after).check().is_err(), + forbidden, + "{before:?} -> {after:?}" + ); + rejected += usize::from(forbidden); + } + } + assert_eq!( + rejected, 16, + "8 live statuses times 2 terminal ones must be the whole forbidden set" + ); + } + + #[test] + fn a_violation_reports_the_transition_that_caused_it() { + let err = Req12::new(NatFlowStatus::Established, NatFlowStatus::Closed) + .check() + .expect_err("an established flow moved to closed must violate REQ-12"); + assert_eq!( + err.to_string(), + "an ICMP packet moved a live flow from Established to Closed" + ); + } +} diff --git a/nat/src/masquerade/expiry.rs b/nat/src/masquerade/expiry.rs index 4ea4c6dbc2..0ce5ca3aee 100644 --- a/nat/src/masquerade/expiry.rs +++ b/nat/src/masquerade/expiry.rs @@ -29,6 +29,27 @@ const PAST_EXPIRY: Duration = Duration::from_secs(ONEWAY * 6); const WITHIN_LIFETIME: Duration = Duration::from_secs(crate::Masquerade::MASQUERADE_CLOSING_TIMEOUT.as_secs() / 2); +const NEARLY_ESTABLISHED: Duration = Duration::from_secs(100); + +/// Used only by the established-mapping test, which reads its stretches the other +/// way round from everything above: a period the mapping must *survive* because +/// outbound traffic keeps refreshing it, and then a silence that must finish it. +/// Deliberately literal rather than derived -- that test exercises the refresh +/// path, not a deadline, and scaling these turns "must survive" into "must expire". +const REFRESHED_FOR: Duration = Duration::from_secs(30); + +/// Long enough to outlast the Established deadline, whatever that deadline becomes. +/// +/// `DEFAULT_MASQUERADE_IDLE_TIMEOUT` is two minutes and is deliberately *not* scaled by +/// `TIMEOUT_SCALE`, so a literal here works today. It would stop working the moment REQ-5c +/// is taken: the snapshot this branch ships records "a default value of five minutes or +/// more ... is RECOMMENDED" as a todo, and at five minutes a literal five-minute silence +/// lands on the deadline rather than past it and the last assertion of +/// `outbound_traffic_keeps_an_established_mapping_alive` fails. Doubling the timeout says +/// what the test means and survives the change. +const LONG_SILENCE: Duration = + crate::masquerade::apalloc::DEFAULT_MASQUERADE_IDLE_TIMEOUT.saturating_mul(2); + fn vni(raw: u32) -> Vni { Vni::new_checked(raw).unwrap_or_else(|_| unreachable!()) } @@ -100,6 +121,122 @@ fn reply_to( .flatten() } +/// What the allocator does to a host whose sessions straddle a pool boundary. +/// +/// This walk was an `#[ignore]`d characterization probe, cited as evidence that REQ-11 held +/// for the mapping dimension. Two things were wrong with that. The citation was backed by a +/// test CI never runs -- duvet is a text scanner and cannot see `#[ignore]`, so a MUST read +/// as covered by nothing at all. And the walk was host-major: every one of a host's 256 +/// sessions was drawn before the next host started, so the spill onto the second public +/// address always fell *between* hosts and the probe passed without ever posing the +/// question. Interleaving the hosts, which is what concurrent traffic looks like, splits +/// all 254 of them. +/// +/// So it asserts the departure rather than the compliance, and fails when the departure is +/// repaired -- at which point this test and the two `type=exception` records it is named by +/// come down together. See `apalloc::alloc::allocate` for REQ-2, the requirement that would +/// have to be implemented for a host to keep one public address. +//= https://www.rfc-editor.org/rfc/rfc4787#section-8 +//= type=exception +//= reason=the pool spills a host onto a second public address at a port-capacity boundary, so the mapping behaviour under exhaustion is not the behaviour before it; measured here +//# REQ-11: A NAT MUST have deterministic behavior, i.e., it MUST NOT +//# change the NAT translation (Section 4) or the Filtering +//# (Section 5) Behavior at any point in time, or under any particular +//# conditions. +#[test] +#[cfg_attr(miri, ignore = "the 65k-session pool walk is too slow under miri")] +fn pool_exhaustion_splits_a_host_across_public_addresses() { + use std::collections::{BTreeMap, BTreeSet}; + with_paused_clock(|| async { + let (fabric, _) = fabric(); + let (mut lookup, mut masq) = fabric.stages(); + let peer = fabric.peer[0]; + let mut given: BTreeMap> = BTreeMap::new(); + + // Port-major, so every host is still drawing when the first address runs out. The + // host-major order this replaced never put a boundary inside one host's sessions. + for sport in 1024..1024 + 256u16 { + for host in 1..=254u16 { + let source: IpAddr = format!("10.0.0.{host}") + .parse() + .unwrap_or_else(|_| unreachable!()); + if let Some((public, _)) = open_flow(&mut lookup, &mut masq, source, peer, sport) { + given.entry(source).or_default().insert(public); + } + } + } + + let publics: BTreeSet<_> = given.values().flatten().copied().collect(); + let split = given.values().filter(|a| a.len() > 1).count(); + println!( + "{} hosts, {} public addresses in use, {split} hosts split", + given.len(), + publics.len() + ); + assert!( + publics.len() > 1, + "the pool never spilled to a second address, so this measured nothing about pairing" + ); + assert_eq!( + split, + given.len(), + "some host kept a single public address across the spill. If pooling has been made \ + Paired, delete this test and the REQ-2 and REQ-11 exceptions it is named by" + ); + }); +} + +fn inbound_from( + lookup: &mut FlowLookup, + masq: &mut Masquerade, + from: IpAddr, + sport: u16, + translated: (IpAddr, u16), +) -> bool { + let mut packet = build(from, translated.0, false, sport, translated.1); + Arrival::inbound().stamp(&mut packet); + let out: Vec> = run(lookup, masq, vec![packet], Some(vni(LOCAL_VNI))); + !out[0].is_done() +} + +//= https://www.rfc-editor.org/rfc/rfc4787#section-5 +//= type=todo +//# REQ-8: If application transparency is most important, it is +//# RECOMMENDED that a NAT have an "Endpoint-Independent Filtering" +//# behavior. If a more stringent filtering behavior is most +//# important, it is RECOMMENDED that a NAT have an "Address-Dependent +//# Filtering" behavior. +#[test] +fn only_the_endpoint_a_flow_addressed_can_reply() { + with_paused_clock(|| async { + let (fabric, _) = fabric(); + let (mut lookup, mut masq) = fabric.stages(); + let peer = fabric.peer[0]; + let elsewhere = *fabric + .peer + .iter() + .find(|a| **a != peer) + .unwrap_or_else(|| unreachable!("the fixture offers two peer addresses")); + let source: IpAddr = "10.0.0.7".parse().unwrap_or_else(|_| unreachable!()); + + let translated = open_flow(&mut lookup, &mut masq, source, peer, 1234) + .unwrap_or_else(|| unreachable!("a fixed private source is masqueraded")); + + assert!( + inbound_from(&mut lookup, &mut masq, peer, 80, translated), + "the endpoint the flow addressed could not answer it" + ); + assert!( + !inbound_from(&mut lookup, &mut masq, peer, 81, translated), + "a packet from the right address on the wrong port reached the tenant" + ); + assert!( + !inbound_from(&mut lookup, &mut masq, elsewhere, 80, translated), + "a packet from an address the flow never addressed reached the tenant" + ); + }); +} + #[test] fn a_flow_inside_its_lifetime_survives() { with_paused_clock(|| async { @@ -169,6 +306,59 @@ fn traffic_extends_a_flow_past_its_first_deadline() { }); } +//= https://www.rfc-editor.org/rfc/rfc4787#section-4.3 +//= type=test +//= reason=held: for established flows; see the OneWay gap recorded in nf.rs +//# REQ-6: The NAT mapping Refresh Direction MUST have a "NAT Outbound +//# refresh behavior" of "True". +#[test] +fn outbound_traffic_keeps_an_established_mapping_alive() { + with_paused_clock(|| async { + let (fabric, _) = fabric(); + let (mut lookup, mut masq) = fabric.stages(); + let peer = fabric.peer[0]; + let source: IpAddr = "10.0.0.7".parse().unwrap_or_else(|_| unreachable!()); + + let translated = open_flow(&mut lookup, &mut masq, source, peer, 1234) + .unwrap_or_else(|| unreachable!("a fixed private source is masqueraded")); + assert_eq!( + reply_to(&mut lookup, &mut masq, peer, translated), + Some(source), + "the reply that establishes the connection was not delivered" + ); + assert_eq!( + open_flow(&mut lookup, &mut masq, source, peer, 1234), + Some(translated), + "the packet that establishes the connection changed its translation" + ); + + for step in 1..=3 { + advance(NEARLY_ESTABLISHED).await; + assert_eq!( + open_flow(&mut lookup, &mut masq, source, peer, 1234), + Some(translated), + "at {}s an outbound packet no longer found the mapping", + step * NEARLY_ESTABLISHED.as_secs() + ); + } + + advance(REFRESHED_FOR).await; + assert_eq!( + reply_to(&mut lookup, &mut masq, peer, translated), + Some(source), + "the mapping did not survive five minutes of outbound traffic, so outbound packets \ + are not refreshing it" + ); + + advance(LONG_SILENCE).await; + assert_eq!( + reply_to(&mut lookup, &mut masq, peer, translated), + None, + "a mapping held open by outbound traffic never expired once that traffic stopped" + ); + }); +} + #[test] fn an_expired_flow_is_never_resurrected() { with_paused_clock(|| async { @@ -203,6 +393,74 @@ fn an_expired_flow_is_never_resurrected() { }); } +//= https://www.rfc-editor.org/rfc/rfc4787#section-4.3 +//= type=test +//# REQ-6: The NAT mapping Refresh Direction MUST have a "NAT Outbound +//# refresh behavior" of "True". +#[test] +fn outbound_traffic_keeps_an_unanswered_mapping_alive() { + // Half a lifetime, so `REFRESHES + 1` of them lands past the deadline the first + // packet set while each single step stays inside it. The assertion below is what + // caught this being written as a literal: at `emulated`'s 100x scale six seconds + // was nowhere near the 500s deadline and neither half of the test proved anything. + const STEP: Duration = Duration::from_secs(ONEWAY / 2); + const REFRESHES: u32 = 2; + + let source: IpAddr = "10.0.0.21".parse().unwrap_or_else(|_| unreachable!()); + let elapsed = Duration::from_secs(u64::from(REFRESHES + 1) * STEP.as_secs()); + assert!( + elapsed > crate::Masquerade::MASQUERADE_ONEWAY_TIMEOUT, + "the probe must land past the deadline the first packet set, or neither half proves \ + anything" + ); + + with_paused_clock(|| async { + let (fabric, _) = fabric(); + let (mut lookup, mut masq) = fabric.stages(); + let peer = fabric.peer[0]; + + let translated = open_flow(&mut lookup, &mut masq, source, peer, 5300) + .unwrap_or_else(|| unreachable!("a fixed private source is masqueraded")); + for _ in 0..=REFRESHES { + advance(STEP).await; + } + assert_eq!( + reply_to(&mut lookup, &mut masq, peer, translated), + None, + "a mapping nobody refreshed survived {}s of silence against a {}s timeout, so the \ + treatment below proves nothing", + elapsed.as_secs(), + crate::Masquerade::MASQUERADE_ONEWAY_TIMEOUT.as_secs() + ); + }); + + with_paused_clock(|| async { + let (fabric, _) = fabric(); + let (mut lookup, mut masq) = fabric.stages(); + let peer = fabric.peer[0]; + + let translated = open_flow(&mut lookup, &mut masq, source, peer, 5300) + .unwrap_or_else(|| unreachable!("a fixed private source is masqueraded")); + for _ in 0..REFRESHES { + advance(STEP).await; + assert_eq!( + open_flow(&mut lookup, &mut masq, source, peer, 5300), + Some(translated), + "the sender was given a different public tuple mid-stream" + ); + } + advance(STEP).await; + assert_eq!( + reply_to(&mut lookup, &mut masq, peer, translated), + Some(source), + "outbound traffic did not keep an unanswered mapping alive: at t={}s the flow was \ + gone, so a one-way sender loses its public tuple every {}s however much it sends", + elapsed.as_secs(), + crate::Masquerade::MASQUERADE_ONEWAY_TIMEOUT.as_secs() + ); + }); +} + #[test] fn both_halves_of_a_pair_outlive_one_sided_traffic() { with_paused_clock(|| async { diff --git a/nat/src/masquerade/fuzz.rs b/nat/src/masquerade/fuzz.rs index 0e55bf933d..a9fc4896f9 100644 --- a/nat/src/masquerade/fuzz.rs +++ b/nat/src/masquerade/fuzz.rs @@ -242,6 +242,79 @@ fn out_unchanged(out: &[Packet], before: (IpAddr, u16)) -> bool { out[0].is_done() || source_of(&out[0]) == before } +//= https://www.rfc-editor.org/rfc/rfc4787#section-4.1 +//= type=test +//# REQ-2: It is RECOMMENDED that a NAT have an "IP address pooling" +//# behavior of "Paired". +#[test] +fn an_internal_endpoint_keeps_one_public_address() { + let tally = Tally::default(); + + with_runtime(|| { + bolero::check!() + .with_generator(Scenario { strays: false }) + .cloned() + .for_each(|(exposes, probes): (Vec, Vec)| { + tally.seen.fetch_add(1, Ordering::Relaxed); + let Some(fabric) = fabric(&exposes) else { + return; + }; + tally.built.fetch_add(1, Ordering::Relaxed); + let (mut lookup, mut masq) = fabric.stages(); + + for spec in &probes { + let probe = (*spec).resolve(&fabric); + let before = (probe.source, probe.sport); + let first = run(&mut lookup, &mut masq, vec![probe.packet()], probe.arrival.dst_vpcd); + if out_unchanged(&first, before) { + continue; + } + + let mut elsewhere = (*spec).resolve(&fabric); + elsewhere.dport = elsewhere.dport.wrapping_add(1).max(1); + if let Some(other) = fabric.peer.iter().find(|a| **a != probe.destination) { + elsewhere.destination = *other; + } + if (elsewhere.destination, elsewhere.dport) == (probe.destination, probe.dport) { + continue; + } + + let second = run( + &mut lookup, + &mut masq, + vec![elsewhere.packet()], + elsewhere.arrival.dst_vpcd, + ); + if out_unchanged(&second, before) { + continue; + } + + assert_eq!( + source_of(&second[0]).0, + source_of(&first[0]).0, + "{before:?} was given {:?} talking to {:?} and {:?} talking to {:?}, so the \ + public address it is given depends on who it is addressing", + source_of(&first[0]), + (probe.destination, probe.dport), + source_of(&second[0]), + (elsewhere.destination, elsewhere.dport) + ); + tally.reached.fetch_add(1, Ordering::Relaxed); + } + }); + }); + + tally.report("address pairing"); +} + +//= https://www.rfc-editor.org/rfc/rfc5382#section-7.1 +//= type=test +//# REQ-7: A NAT MUST NOT have a "Port assignment" behavior of "Port +//# overloading" for TCP. +//= https://www.rfc-editor.org/rfc/rfc4787#section-4.2.1 +//= type=test +//# REQ-3: A NAT MUST NOT have a "Port assignment" behavior of "Port +//# overloading". #[test] fn distinct_flows_do_not_share_a_translation() { let tally = Tally::default(); diff --git a/nat/src/masquerade/mod.rs b/nat/src/masquerade/mod.rs index 1e708dd93d..ff4ddb6a97 100644 --- a/nat/src/masquerade/mod.rs +++ b/nat/src/masquerade/mod.rs @@ -4,6 +4,7 @@ pub(crate) mod allocation; mod allocator_writer; pub mod apalloc; +mod contract; mod expiry; pub(crate) mod flows; mod fuzz; @@ -17,6 +18,16 @@ mod state; mod state_machine; mod test; +// A todo has to be anchored somewhere and hairpinning has no code yet, so it sits at the +// crate root. Where it will go when it is written: `nf::Masquerade`, in the source-NAT +// direction, has to recognise that the destination it is about to translate is one of its +// own public addresses and turn the packet back inward with both halves translated. The +// pieces it needs are the pool (`apalloc`, to answer "is this mine") and the reverse +// lookup the inbound path already does. +//= https://www.rfc-editor.org/rfc/rfc4787#section-6 +//= type=todo +//# REQ-9: A NAT MUST support "Hairpinning". + // re exports pub use allocator_writer::MasqueradeConfig; pub use allocator_writer::NatAllocatorWriter; diff --git a/nat/src/masquerade/nf.rs b/nat/src/masquerade/nf.rs index 84974c52d0..9d88d4b694 100644 --- a/nat/src/masquerade/nf.rs +++ b/nat/src/masquerade/nf.rs @@ -97,6 +97,22 @@ impl Masquerade { }; // Internal flow timeouts for masquerading + //= https://www.rfc-editor.org/rfc/rfc5382#section-5 + //= type=todo + //# REQ-5: If a NAT cannot determine whether the endpoints of a TCP + //# connection are active, it MAY abandon the session if it has been + //# idle for some time. In such cases, the value of the "established + //# connection idle-timeout" MUST NOT be less than 2 hours 4 minutes. + //# The value of the "transitory connection idle-timeout" MUST NOT be + //# less than 4 minutes. + //= https://www.rfc-editor.org/rfc/rfc4787#section-4.3 + //= type=todo + //# REQ-5: A NAT UDP mapping timer MUST NOT expire in less than two + //# minutes, unless REQ-5a applies. + //= https://www.rfc-editor.org/rfc/rfc4787#section-4.3 + //= type=todo + //# c) A default value of five minutes or more for the NAT UDP mapping + //# timer is RECOMMENDED. pub const MASQUERADE_ONEWAY_TIMEOUT: Duration = Duration::from_secs(5 * Self::TIMEOUT_SCALE); pub const MASQUERADE_TWOWAY_TIMEOUT: Duration = Duration::from_secs(3 * Self::TIMEOUT_SCALE); pub const MASQUERADE_CLOSING_TIMEOUT: Duration = Duration::from_secs(2 * Self::TIMEOUT_SCALE); @@ -160,6 +176,15 @@ impl Masquerade { packet.meta().dst_vpcd } + fn refreshes_while_unanswered(packet: &Packet) -> bool { + packet.try_ip().is_some_and(|ip| { + matches!( + ip.next_header(), + NextHeader::UDP | NextHeader::ICMP | NextHeader::ICMP6 + ) + }) + } + /// Update the `FlowStatus` of a masqueraded flow with a packet, depending on the direction of the /// communication and the protocol and extend the lifetime of the flow (or invalidate it) accordingly. fn refresh_masquerade_state( @@ -186,11 +211,12 @@ impl Masquerade { | NatFlowStatus::CHalfClose | NatFlowStatus::SHalfClose | NatFlowStatus::LastAck => Some(Self::MASQUERADE_CLOSING_TIMEOUT), + //= https://www.rfc-editor.org/rfc/rfc4787#section-4.3 + //= type=implementation + //# REQ-6: The NAT mapping Refresh Direction MUST have a "NAT Outbound + //# refresh behavior" of "True". NatFlowStatus::OneWay => { - // this could happen if a burst of packets are sent before any state is there (snat), - // or if we got a TCP segment back without expected flags. This should never happen for - // a UDP packet in the reverse direction, though. - None + Self::refreshes_while_unanswered(packet).then_some(Self::MASQUERADE_ONEWAY_TIMEOUT) } }; @@ -578,6 +604,11 @@ impl Masquerade { return; } + //= https://www.rfc-editor.org/rfc/rfc4787#section-11 + //= type=todo + //# REQ-14: A NAT MUST support receiving in-order and out-of-order + //# fragments, so it MUST have "Received Fragment Out of Order" + //# behavior. // TODO: Check whether the packet is fragmented if let Err(error) = self.masquerade_packet(packet) { packet.done((&error).into()); diff --git a/nat/src/masquerade/protocol.rs b/nat/src/masquerade/protocol.rs index 1e101a3ee9..e8986e5979 100644 --- a/nat/src/masquerade/protocol.rs +++ b/nat/src/masquerade/protocol.rs @@ -6,6 +6,8 @@ //! for port conservation. use crate::common::{NatAction, NatFlowStatus}; +use crate::masquerade::contract::Requirement; +use crate::masquerade::contract::rfc4787::Req12; use net::buffer::PacketBufferMut; use net::headers::{TryHeaders, TryIp, TryTcp}; @@ -14,6 +16,11 @@ use net::packet::Packet; use net::tcp::Tcp; impl NatFlowStatus { + //= https://www.rfc-editor.org/rfc/rfc4787#section-4.3 + //# a) For specific destination ports in the well-known port range + //# (ports 0-1023), a NAT MAY have shorter UDP mapping timers that + //# are specific to the IANA-registered application running over + //# that specific destination port. fn udp_status_patch_dnat(self, packet: &Packet) -> NatFlowStatus { match packet.headers().pat().eth().net().udp().done() { Some((_, _, udp)) => match udp.source().as_u16() { @@ -50,9 +57,14 @@ fn next_flow_status_udp(action: NatAction, status: NatFlowStatus) -> NatFlowStat } } +// No arm of this machine reaches a terminal state, so an ICMP *query* -- an Echo or its +// reply -- never ends the flow it belongs to. That is half of RFC 5382 REQ-10 and RFC 4787 +// REQ-12, and it is not the half a reader assumes: an ICMP *error* does not come through +// here at all. It goes to `IcmpErrorHandler`, which does tear a one-way mapping down on a +// hard error, so neither requirement is met and neither is recorded here. #[allow(clippy::match_single_binding)] fn next_flow_status_icmp(action: NatAction, status: NatFlowStatus) -> NatFlowStatus { - match action { + let next = match action { NatAction::SrcNat => match status { _ => status, }, @@ -60,7 +72,17 @@ fn next_flow_status_icmp(action: NatAction, status: NatFlowStatus) -> NatFlowSta NatFlowStatus::OneWay => NatFlowStatus::TwoWay, _ => status, }, + }; + if cfg!(debug_assertions) + && let Err(violation) = Req12::new(status, next).check() + { + unreachable!( + "{spec} {id}: {violation} ({action})", + spec = Req12::SPEC, + id = Req12::ID + ); } + next } fn next_flow_status_tcp(action: NatAction, status: NatFlowStatus, tcp: &Tcp) -> NatFlowStatus { diff --git a/nat/src/masquerade/state_machine.rs b/nat/src/masquerade/state_machine.rs index d7616493b9..882a86101e 100644 --- a/nat/src/masquerade/state_machine.rs +++ b/nat/src/masquerade/state_machine.rs @@ -4,6 +4,8 @@ #![cfg(test)] use crate::common::{NatAction, NatFlowStatus}; +use crate::masquerade::contract::Requirement; +use crate::masquerade::contract::rfc4787::Req12; use crate::masquerade::protocol::next_flow_status; use net::buffer::TestBuffer; use net::headers::TryTcpMut; @@ -195,6 +197,11 @@ fn ordinary_udp_opens_and_settles() { } } +// This is an Echo Reply, so what it exercises is the ICMP *query* machine. RFC 5382 REQ-10 +// and RFC 4787 REQ-12 are about any ICMP message including errors, and errors do not come +// through here -- they go to `icmp_handler::nf`, which is where either requirement stands +// or falls. Citing them from a query test is how a compliance report comes to say a +// requirement is tested by something that cannot reach the code that breaks it. #[test] fn an_icmp_reply_makes_a_flow_two_way_and_nothing_more() { let packet = build_test_icmp4_echo( @@ -212,16 +219,19 @@ fn an_icmp_reply_makes_a_flow_two_way_and_nothing_more() { ); for status in STATUSES { - assert_eq!( - next_flow_status(&packet, NatAction::SrcNat, status), - status, - "an outbound icmp packet moved a flow in {status:?}" - ); - if status != NatFlowStatus::OneWay { + for action in [NatAction::SrcNat, NatAction::DstNat] { + let next = next_flow_status(&packet, action, status); assert_eq!( - next_flow_status(&packet, NatAction::DstNat, status), - status, - "an inbound icmp packet moved a flow in {status:?}" + Req12::new(status, next).check(), + Ok(()), + "{action} icmp packet terminated a flow in {status:?}" + ); + if action == NatAction::DstNat && status == NatFlowStatus::OneWay { + continue; + } + assert_eq!( + next, status, + "an {action} icmp packet moved a flow in {status:?}" ); } } diff --git a/nat/src/portfw/portfwtable/access.rs b/nat/src/portfw/portfwtable/access.rs index 400e28a701..71fc616534 100644 --- a/nat/src/portfw/portfwtable/access.rs +++ b/nat/src/portfw/portfwtable/access.rs @@ -29,11 +29,8 @@ impl Absorb for PortFwTable { pub struct PortFwTableWriter(WriteHandle); pub struct PortFwTableReader(ReadHandle); -#[allow(clippy::unnecessary_wraps)] -fn validate_ruleset(_ruleset: &[PortFwEntry]) -> Result<(), PortFwTableError> { - // deferring the implementation of this since it will change - // when we introduce port ranges - Ok(()) +fn validate_ruleset(ruleset: &[PortFwEntry]) -> Result<(), PortFwTableError> { + PortFwTable::dry_run(ruleset) } impl PortFwTableWriter { @@ -122,6 +119,39 @@ mod test { .unwrap() } + #[test] + fn a_ruleset_the_table_cannot_hold_is_refused() { + let rule = |ext: (u16, u16), int: (u16, u16)| { + PortFwEntry::new( + PortFwKey::new( + VpcDiscriminant::VNI(2000.try_into().unwrap()), + NextHeader::TCP, + ), + VpcDiscriminant::VNI(3000.try_into().unwrap()), + Prefix::from_str("70.71.72.73/32").unwrap(), + Prefix::from_str("192.168.1.1/32").unwrap(), + ext, + int, + None, + None, + ) + .unwrap() + }; + + let mut writer = PortFwTableWriter::new(); + writer + .update_table(&[rule((3000, 3009), (30, 39)), rule((3010, 3019), (40, 49))]) + .expect("rules that do not overlap are installable together"); + + let refused = + writer.update_table(&[rule((3000, 3009), (30, 39)), rule((3005, 3014), (50, 59))]); + assert!( + refused.is_err(), + "a ruleset whose rules claim overlapping external ports was accepted by the writer, \ + so the table now holds fewer rules than the caller believes it asked for" + ); + } + #[test] #[cfg_attr(not(emulated), traced_test)] fn test_port_forwarding_access_remove_rules_drops_refs() { diff --git a/nat/src/portfw/portfwtable/objects.rs b/nat/src/portfw/portfwtable/objects.rs index bbf13cd43c..b6e177d462 100644 --- a/nat/src/portfw/portfwtable/objects.rs +++ b/nat/src/portfw/portfwtable/objects.rs @@ -252,6 +252,14 @@ impl PortFwTable { Self::default() } + pub(crate) fn dry_run(ruleset: &[PortFwEntry]) -> Result<(), PortFwTableError> { + let mut scratch = Self::default(); + for rule in ruleset { + scratch.add_entry(Arc::new(rule.clone()))?; + } + Ok(()) + } + /// Add a `Arc` to this `PortFwTable`. fn add_entry(&mut self, entry: Arc) -> Result<(), PortFwTableError> { let key = &entry.key; @@ -294,7 +302,7 @@ impl PortFwTable { let mut ruleset = ruleset.to_vec(); while let Some(rule) = ruleset.pop().map(Arc::from) { if let Err(e) = self.add_entry(rule.clone()) { - error!("Failure adding port-forwarding rule (config validation failed)"); + error!("Dropping port-forwarding rule {rule}: {e}"); } } } @@ -494,6 +502,37 @@ mod test { assert_eq!(fwtable.0.len(), 1); } + #[test] + fn a_self_overlapping_ruleset_is_refused_up_front() { + let key = PortFwKey { + src_vpcd: VpcDiscriminant::VNI(2000.try_into().unwrap()), + proto: NextHeader::TCP, + }; + let rule = |ext_ports: (u16, u16), int_ports: (u16, u16)| { + PortFwEntry::new( + key, + VpcDiscriminant::VNI(3000.try_into().unwrap()), + Prefix::from_str("70.71.72.73/32").unwrap(), + Prefix::from_str("192.168.1.1/32").unwrap(), + ext_ports, + int_ports, + None, + None, + ) + .unwrap() + }; + + PortFwTable::dry_run(&[rule((3000, 3009), (30, 39)), rule((3010, 3019), (40, 49))]) + .expect("two rules that do not overlap are installable together"); + + let refused = + PortFwTable::dry_run(&[rule((3000, 3009), (30, 39)), rule((3005, 3014), (50, 59))]); + assert!( + matches!(refused, Err(PortFwTableError::OverlappingRange(_))), + "a ruleset whose rules claim overlapping external ports was accepted: {refused:?}" + ); + } + #[test] fn test_port_forwarding_entry_reject_distinct_ip_ver() { let key = PortFwKey { diff --git a/net/src/headers/embedded.rs b/net/src/headers/embedded.rs index e8397c56fc..57c019bd6d 100644 --- a/net/src/headers/embedded.rs +++ b/net/src/headers/embedded.rs @@ -48,6 +48,17 @@ pub struct EmbeddedHeaders { full_payload_length: Option, } +/// RFC 4884 section 4's backwards-compatibility floor for the "original datagram" field. +/// +/// The errata were read before this shipped, because the vendored corpus carries only the +/// base RFC and the project had recorded the constant as written without them. RFC 4884 has +/// exactly one erratum -- ID 3, Verified, Technical, against section 7 -- and it replaces +/// "the data structure" with "the ICMP Extension Structure" in the description of the +/// extension checksum. Nothing touches section 3, section 4, this floor, or the padding and +/// length-attribute rules cited in `check_full_payload`. Checked 2026-09-06 against +/// ; re-check if a second erratum appears. +const MIN_ORIGINAL_DATAGRAM_OCTETS: usize = 128; + impl EmbeddedHeaders { #[cfg(any(test, feature = "bolero"))] #[must_use] @@ -235,49 +246,52 @@ impl EmbeddedHeaders { // // From RFC 4884: The length attribute represents the length of the padded "original // datagram" field. - match self.net { - Some(Net::Ipv4(_)) => { - if icmp_length < full_packet_length { - // The embedded message is shorter than the original packet - return; - } - if icmp_length > buf.len() || !icmp_length.is_multiple_of(32) { - // Embedded payload is larger than our buffer? Or the size is not a multiple - // of 32? Something's wrong - return; - } - let padding_length = icmp_length - full_packet_length; - // ICMPv4: Padding is on 32-bit boundaries - if padding_length < 32 - && buf[full_packet_length..icmp_length].iter().all(|b| *b == 0) - { - self.full_payload_length = Some(transport_payload_length as u16); - } - return; - } - Some(Net::Ipv6(_)) => { - if icmp_length < full_packet_length { - // The embedded message is shorter than the original packet - return; - } - if icmp_length > buf.len() || !icmp_length.is_multiple_of(64) { - // Embedded payload is larger than our buffer? Or the size is not a multiple - // of 64? Something's wrong - return; - } - let padding_length = icmp_length - full_packet_length; - // ICMPv6: Padding is on 64-bit boundaries - if padding_length < 64 - && buf[full_packet_length..icmp_length].iter().all(|b| *b == 0) - { - self.full_payload_length = Some(transport_payload_length as u16); - } - return; - } - None => { - unreachable!() // Checked earlier in the function - } + debug_assert!(self.net.is_some(), "checked earlier in the function"); + + if icmp_length < full_packet_length { + // The embedded message is shorter than the original packet + return; + } + if icmp_length > buf.len() { + return; + } + //= https://www.rfc-editor.org/rfc/rfc4884#section-3 + //# When the ICMP Extension Structure is appended to an ICMP message + //# and that ICMP message contains an "original datagram" field, the + //# "original datagram" field MUST contain at least 128 octets. + if icmp_length < MIN_ORIGINAL_DATAGRAM_OCTETS { + return; + } + // The two alignment requirements below are satisfied by construction rather + // than by a check here, and that is the whole argument for citing them: the + // length attribute is not measured in octets. `icmp_length` is the field + // value multiplied by four for ICMPv4 and by eight for ICMPv6, so every value + // this parser can produce is already on the boundary the RFC names. An + // explicit `is_multiple_of` test would be a tautology -- the earlier + // `!icmp_length.is_multiple_of(32)` was worse than that, comparing an octet + // count against a bit count. + // + // What is checked is that the surplus over the original datagram is zero. + // A conformant sender pads to exactly `max(128, round_up(len, alignment))`, + // and a longer field is out of spec -- but a receiver has no reason to + // discard a determination it can make: the original datagram really is all + // present, and the surplus really is padding, because the extension structure + // starts after the declared field. Being generous about the length and strict + // about the content is the direction that loses nothing. + //= https://www.rfc-editor.org/rfc/rfc4884#section-3 + //# When the ICMP Extension Structure is appended to an ICMPv4 message + //# and that ICMPv4 message contains an "original datagram" field, the + //# "original datagram" field MUST be zero padded to the nearest + //# 32-bit boundary. + //= https://www.rfc-editor.org/rfc/rfc4884#section-3 + //# When the ICMP Extension Structure is appended to an ICMPv6 message + //# and that ICMPv6 message contains an "original datagram" field, the + //# "original datagram" field MUST be zero padded to the nearest + //# 64-bit boundary. + if buf[full_packet_length..icmp_length].iter().all(|b| *b == 0) { + self.full_payload_length = Some(transport_payload_length as u16); } + return; } // Check that the full headers + payload are present @@ -954,6 +968,28 @@ mod tests { buf } + fn create_full_ipv6_tcp_packet_with_payload() -> Vec { + let ipv6_header = Ipv6Header { + traffic_class: 0, + flow_label: 0.try_into().unwrap(), + payload_length: 80, + next_header: IpNumber::TCP, + hop_limit: 64, + source: [0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + destination: [0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], + }; + + let mut buf = Vec::new(); + ipv6_header.write(&mut buf).unwrap(); + + let tcp_header = etherparse::TcpHeader::new(80, 443, 1000, 0); + tcp_header.write(&mut buf).unwrap(); + + buf.extend_from_slice(&[1u8; 60]); + + buf + } + // Basic parsing, deparsing checks #[test] @@ -1298,12 +1334,130 @@ mod tests { assert!(!headers.is_full_payload()); } + fn v4_with_field_of(field_len: usize, padding_byte: u8) -> (EmbeddedHeaders, usize, Vec) { + let mut buf = create_full_ipv4_tcp_packet_with_payload(); + assert_eq!(buf.len(), 120, "the embedded packet is 120 octets"); + buf.extend(std::iter::repeat_n(padding_byte, field_len - buf.len())); + assert_eq!(buf.len(), field_len); + buf.extend_from_slice(&[0x55u8; 32]); + let (headers, consumed) = + EmbeddedHeaders::parse_with(EmbeddedIpVersion::Ipv4, &buf).unwrap(); + (headers, consumed.get() as usize, buf) + } + + fn v6_with_field_of(field_len: usize, padding_byte: u8) -> (EmbeddedHeaders, usize, Vec) { + let mut buf = create_full_ipv6_tcp_packet_with_payload(); + assert_eq!(buf.len(), 120, "the embedded packet is 120 octets"); + buf.extend(std::iter::repeat_n(padding_byte, field_len - buf.len())); + assert_eq!(buf.len(), field_len); + buf.extend_from_slice(&[0x55u8; 32]); + let (headers, consumed) = + EmbeddedHeaders::parse_with(EmbeddedIpVersion::Ipv6, &buf).unwrap(); + (headers, consumed.get() as usize, buf) + } + + #[test] + fn an_icmp_error_from_the_wire_reports_a_full_payload() { + use crate::headers::TryEmbeddedHeaders; + use crate::ip::NextHeader; + use crate::packet::test_utils::build_test_icmp4_destination_unreachable_packet; + + let packet = build_test_icmp4_destination_unreachable_packet( + "10.0.0.1".parse().unwrap_or_else(|_| unreachable!()), + "10.0.0.2".parse().unwrap_or_else(|_| unreachable!()), + "192.168.0.1".parse().unwrap_or_else(|_| unreachable!()), + "192.168.0.2".parse().unwrap_or_else(|_| unreachable!()), + NextHeader::UDP, + 1234, + 80, + ) + .unwrap_or_else(|e| unreachable!("{e:?}")); + + let embedded = packet + .embedded_headers() + .unwrap_or_else(|| unreachable!("an icmp error carries embedded headers")); + assert!( + embedded.is_full_payload(), + "the quoted datagram is complete and nothing follows it, so the whole payload is \ + present -- reading this as truncated means the window handed to check_full_payload \ + does not start where the lengths it compares are measured from" + ); + assert_eq!( + embedded.payload_length(), + Some(0), + "the quoted UDP datagram carries no payload beyond its header" + ); + } + + /// Over-padding past the minimum is accepted, not treated as a short quote. + /// + /// A conformant `ICMPv4` sender pads a 120-octet datagram to exactly 128 -- the nearest + /// 32-bit boundary, then the 128-octet floor. Nothing here checks that, deliberately: + /// this exercise is the receiver's side of the leniency argued at `check_full_payload`, + /// where a longer field still carries the whole original datagram and the surplus is + /// still padding. It is named for what it asserts rather than for the requirement, + /// because the alignment requirement holds by construction and no test can see it: the + /// length attribute is in 32-bit words, so `check_full_payload` cannot be handed an + /// unaligned length by the parser, and handing it one directly proves nothing about the + /// parser. + #[test] + fn a_field_padded_past_the_minimum_is_still_a_full_quote() { + for field_len in [128usize, 132, 136, 140, 144, 148, 152, 156] { + let (mut headers, consumed, buf) = v4_with_field_of(field_len, 0); + headers.check_full_payload(&buf, buf.len(), consumed, field_len); + assert!( + headers.is_full_payload(), + "a {field_len}-octet field holds the whole 120-octet datagram followed by \ + zeroes, so it must be accepted" + ); + assert_eq!(headers.payload_length(), Some(80)); + } + } + + //= https://www.rfc-editor.org/rfc/rfc4884#section-3 + //= type=test + //# When the ICMP Extension Structure is appended to an ICMP message + //# and that ICMP message contains an "original datagram" field, the + //# "original datagram" field MUST contain at least 128 octets. + #[test] + fn the_128_octet_minimum_is_exact() { + type Fixture = fn(usize, u8) -> (EmbeddedHeaders, usize, Vec); + for (family, build) in [ + ("ICMPv4", v4_with_field_of as Fixture), + ("ICMPv6", v6_with_field_of as Fixture), + ] { + for field_len in [120usize, 124] { + let (mut headers, consumed, buf) = build(field_len, 0); + headers.check_full_payload(&buf, buf.len(), consumed, field_len); + assert!( + !headers.is_full_payload(), + "{family}: a {field_len}-octet field is below the 128-octet minimum" + ); + } + + let (mut headers, consumed, buf) = build(128, 0); + headers.check_full_payload(&buf, buf.len(), consumed, 128); + assert!( + headers.is_full_payload(), + "{family}: 128 octets is the minimum, so a 128-octet field must be accepted" + ); + } + } + + #[test] + fn a_field_padded_with_anything_but_zeroes_is_refused() { + let (mut headers, consumed, buf) = v4_with_field_of(136, 0xab); + headers.check_full_payload(&buf, buf.len(), consumed, 136); + assert!( + !headers.is_full_payload(), + "non-zero padding must not be accepted as padding" + ); + } + #[test] fn test_check_full_payload_with_icmp_extensions() { let mut buf = create_full_ipv4_tcp_packet_with_payload(); - // We need to pad on a 32-bit word boundary. We have 120 bytes (20 for the IP header, 20 for - // the TCP header, 80 for the payload), add 8 to reach 128 bytes. buf.extend_from_slice(&[0u8; 8]); let icmp_payload_length = buf.len(); diff --git a/net/src/icmp4/mod.rs b/net/src/icmp4/mod.rs index 5595f80f45..8c94855edb 100644 --- a/net/src/icmp4/mod.rs +++ b/net/src/icmp4/mod.rs @@ -619,7 +619,9 @@ impl Icmp4 { if !self.supports_extensions() { return 0; } - let payload_length = buf[5]; + let Some(&payload_length) = buf.get(5) else { + return 0; + }; payload_length as usize * 4 } @@ -627,19 +629,27 @@ impl Icmp4 { if !self.is_error_message() { return None; } - let (mut headers, consumed) = EmbeddedHeaders::parse_with( - EmbeddedIpVersion::Ipv4, - &cursor.inner[cursor.inner.len() - cursor.remaining as usize..], - ) - .ok()?; + + let icmp_payload_length = { + let end = cursor.inner.len() - cursor.remaining as usize; + let start = end.checked_sub(self.size().get() as usize)?; + self.payload_length(&cursor.inner[start..end]) + }; + + let embedded_start = cursor.inner.len() - cursor.remaining as usize; + let embedded_remaining = cursor.remaining as usize; + + let (mut headers, consumed) = + EmbeddedHeaders::parse_with(EmbeddedIpVersion::Ipv4, &cursor.inner[embedded_start..]) + .ok()?; cursor.consume(consumed).ok()?; // Mark whether the payload of the embedded IP packet is full headers.check_full_payload( - &cursor.inner[cursor.inner.len() - cursor.remaining as usize..], - cursor.remaining as usize, + &cursor.inner[embedded_start..], + embedded_remaining, consumed.get() as usize, - self.payload_length(cursor.inner), + icmp_payload_length, ); Some(headers) diff --git a/net/src/icmp6/mod.rs b/net/src/icmp6/mod.rs index fc437db4a5..eb7bf8ac2b 100644 --- a/net/src/icmp6/mod.rs +++ b/net/src/icmp6/mod.rs @@ -621,12 +621,15 @@ impl Icmp6 { }) } + //= https://www.rfc-editor.org/rfc/rfc4884#section-3 + //= type=implementation + //# An ICMP Extension Structure MAY be appended to ICMPv6 Destination + //# Unreachable, and Time Exceeded messages. #[must_use] pub(crate) fn supports_extensions(&self) -> bool { - // See RFC 4884. matches!( self.icmp_type(), - Icmp6Type::DestUnreachable(_) | Icmp6Type::TimeExceeded(_) | Icmp6Type::ParamProblem(_) + Icmp6Type::DestUnreachable(_) | Icmp6Type::TimeExceeded(_) ) } @@ -635,7 +638,9 @@ impl Icmp6 { if !self.supports_extensions() { return 0; } - let payload_length = buf[4]; + let Some(&payload_length) = buf.get(4) else { + return 0; + }; payload_length as usize * 8 } @@ -643,19 +648,26 @@ impl Icmp6 { if !self.is_error_message() { return None; } - let (mut headers, consumed) = EmbeddedHeaders::parse_with( - EmbeddedIpVersion::Ipv6, - &cursor.inner[cursor.inner.len() - cursor.remaining as usize..], - ) - .ok()?; + let icmp_payload_length = { + let end = cursor.inner.len() - cursor.remaining as usize; + let start = end.checked_sub(self.size().get() as usize)?; + self.payload_length(&cursor.inner[start..end]) + }; + + let embedded_start = cursor.inner.len() - cursor.remaining as usize; + let embedded_remaining = cursor.remaining as usize; + + let (mut headers, consumed) = + EmbeddedHeaders::parse_with(EmbeddedIpVersion::Ipv6, &cursor.inner[embedded_start..]) + .ok()?; cursor.consume(consumed).ok()?; // Mark whether the payload of the embedded IP packet is full headers.check_full_payload( - &cursor.inner[cursor.inner.len() - cursor.remaining as usize..], - cursor.remaining as usize, + &cursor.inner[embedded_start..], + embedded_remaining, consumed.get() as usize, - self.payload_length(cursor.inner), + icmp_payload_length, ); Some(headers) diff --git a/routing/src/cli/display.rs b/routing/src/cli/display.rs index f8a8a66e7f..e83e922899 100644 --- a/routing/src/cli/display.rs +++ b/routing/src/cli/display.rs @@ -46,7 +46,6 @@ use std::time::Duration; use tracing::{error, warn}; -//================================= Common ==========================// fn fmt_opt_value( f: &mut std::fmt::Formatter<'_>, name: &str, @@ -60,7 +59,6 @@ fn fmt_opt_value( if nl { writeln!(f) } else { Ok(()) } } -//========================= Encapsulations ==========================// impl Display for VxlanEncapsulation { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( @@ -83,7 +81,6 @@ impl Display for Encapsulation { } } -//=================== VRFs, routes and next-hops ====================// impl Display for RouteOrigin { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -173,7 +170,7 @@ fn fmt_nhop_instruction(f: &mut std::fmt::Formatter<'_>, rc: &Nhop) -> std::fmt: Ok(()) } -// formats nhop using the display of the key, recoursing over resolvers +// formats nhop using the display of the key, recurring over resolvers // Does not use Nhop::fmt(). fn fmt_nhop_rec( f: &mut std::fmt::Formatter<'_>, @@ -491,8 +488,6 @@ impl Display for VrfTable { } } -//========================= Interfaces ================================// - impl Display for Attachment { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -594,7 +589,6 @@ impl Display for IfTable { Ok(()) } } -//========================= Interface addresses ================================// #[repr(transparent)] pub struct IfTableAddress<'a>(pub &'a IfTable); @@ -632,7 +626,6 @@ impl Display for IfTableAddress<'_> { } } -//========================= Rmac Store ================================// macro_rules! RMAC_TBL_FMT { () => { " {:<5} {:<20} {:<18} {:<8}" @@ -679,7 +672,6 @@ impl Display for RmacStore { } } -//========================= Rmac Store ================================// impl Display for Vtep { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { Heading("Local VTEP configuration").fmt(f)?; @@ -688,7 +680,6 @@ impl Display for Vtep { } } -//========================= Adjacencies ================================// macro_rules! ADJ_TBL_FMT { () => { " {:<10} {:<20} {:<18}" @@ -727,7 +718,6 @@ impl Display for AdjacencyTable { } } -//========================= Fib ================================// impl Display for FibKey { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { match self { @@ -922,7 +912,6 @@ impl Display for FibGroups<'_> { } } -//========================= Time utils =========================// use chrono::Local; pub(crate) fn fmt_time(time: &DateTime) -> String { //let fmt_iso8 = "%Y-%m-%dT%H:%M:%S%.3f%:z"; @@ -954,7 +943,6 @@ pub(crate) fn fmt_time(time: &DateTime) -> String { out } -//========================= CPI ================================// macro_rules! STATS_ROW_FMT { () => { " {:<16} {:<12} {:<12} {:<12} {:<12} {:<12}" @@ -1038,7 +1026,6 @@ impl Display for CpiStats { } } -//========================= Frrmi ================================// impl Display for FrrmiStats { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let last_conn_time = &self diff --git a/routing/src/router/rio.rs b/routing/src/router/rio.rs index b5a4543dcc..5eb8c82015 100644 --- a/routing/src/router/rio.rs +++ b/routing/src/router/rio.rs @@ -1490,7 +1490,9 @@ mod tests { #[test] #[cfg_attr(emulated, ignore = "binds Unix domain sockets")] fn a_large_answer_arrives_whole() { - const ROUTES: usize = 8192; + use cli::cliproto::CLI_MSG_CHUNK_SIZE as CHUNK; + const ROUTES: usize = 256; + const LEAST_CHUNKS: usize = 6; let rio = RunningRio::start(); let peer = CpiPeer::attach(&rio.dir); @@ -1514,9 +1516,10 @@ mod tests { .expect("the whole answer should arrive, across as many chunks as it takes"); let body = answer.result.expect("the listing should succeed"); + let chunks = body.len().div_ceil(CHUNK); assert!( - body.len() > 100 * 2048, - "the answer must span many chunks for this to test reassembly, got {} octets", + chunks >= LEAST_CHUNKS, + "the answer spans {chunks} chunks, too few to exercise reassembly ({} octets)", body.len() ); assert!(body.contains("10.0.0.0/24"), "the first route is missing"); diff --git a/scripts/duvet-summary.ts b/scripts/duvet-summary.ts index 48788cb964..99df7c9414 100755 --- a/scripts/duvet-summary.ts +++ b/scripts/duvet-summary.ts @@ -64,6 +64,34 @@ function record(stats: Stats, status: Record) { if (status.todo) stats.todos += 1; } +// Sections that restate requirements stated normatively elsewhere in the same document. +// duvet keys by section anchor and has no notion of "the same requirement twice", so each +// of these copies counts in the denominator and can never be cited: the convention, which +// `.duvet/config.toml` records, is to annotate the normative section. Without saying so the +// headline percentage reads as roughly half of what it is. +const SUMMARY_SECTIONS: Record = { + "https://www.rfc-editor.org/rfc/rfc4787": "section-12", + "https://www.rfc-editor.org/rfc/rfc5382": "section-8", + "https://www.rfc-editor.org/rfc/rfc5508": "section-9", +}; + +// Counted from the extracted requirements rather than the report, which does not say which +// section a requirement came from. Returns 0 for a spec with no summary section, and for +// one whose file has moved -- an over-count in the honest direction. +async function summaryRequirements(id: string): Promise { + const section = SUMMARY_SECTIONS[id]; + if (!section) return 0; + const path = `${REPO}/.duvet/requirements/${ + id.replace(/^https?:\/\//, "") + }/${section}.toml`; + try { + const text = await Deno.readTextFile(path); + return text.split("\n").filter((line) => line === "[[spec]]").length; + } catch { + return 0; + } +} + const BANDS = [ { from: 0.75, cell: "🟩" }, { from: 0.5, cell: "🟨" }, @@ -109,7 +137,13 @@ async function run(cmd: string, args: string[]): Promise { } function parseArgs(argv: string[]) { - const args = { json: "/tmp/duvet-summary.json", results: "", help: false }; + // Under the repo rather than /tmp: `lint` runs on a self-hosted runner where /tmp is + // shared between concurrent jobs and the nix sandbox's private /tmp does not apply. + const args = { + json: `${REPO}/target/duvet-summary.json`, + results: "", + help: false, + }; for (let i = 0; i < argv.length; i += 1) { const flag = argv[i]; const value = () => { @@ -157,7 +191,9 @@ async function main(): Promise { const total = EMPTY(); const rows: string[] = []; + let restated = 0; for (const [id, spec] of Object.entries(report.specifications)) { + restated += await summaryRequirements(id); const stats = EMPTY(); for (const requirement of spec.requirements) { const status = report.statuses[String(requirement)]; @@ -196,6 +232,16 @@ async function main(): Promise { } |`, ); out(); + if (restated) { + const share = (100 * restated / total.total).toFixed(0); + out( + `> ${restated} of the ${total.total} requirements above (${share}%) are the summary-section ` + + `restatements listed in \`.duvet/config.toml\`. They are uncitable by convention -- the ` + + `normative copy carries the annotation -- so they are a permanent floor under every ` + + `"incomplete" count here, not work outstanding.`, + ); + out(); + } out("## Citation interlock"); out(); diff --git a/scripts/spec-interlock.ts b/scripts/spec-interlock.ts index 3aeb65762e..463e59cbea 100755 --- a/scripts/spec-interlock.ts +++ b/scripts/spec-interlock.ts @@ -35,7 +35,7 @@ const ACCEPTED: Accepted[] = [ }, ...[ "https://www.rfc-editor.org/rfc/rfc4787#section-4.2.1", - "https://www.rfc-editor.org/rfc/rfc5382#section-8", + "https://www.rfc-editor.org/rfc/rfc5382#section-7.1", ].map((requirement) => ({ requirement, mutant: @@ -620,7 +620,9 @@ function parseArgs(argv: string[]) { only: [] as string[], jobs: 4, output: join(REPO, "target", "spec-interlock"), - json: "/tmp/duvet-interlock.json", + // Under the repo rather than /tmp, for the same reason as `output` above: the lab + // runner shares /tmp between concurrent jobs. + json: join(REPO, "target", "duvet-interlock.json"), results: "", }; for (let i = 0; i < argv.length; i += 1) {