RFC 6296

IPv6-to-IPv6 Network Prefix Translation

๐Ÿ“… published June 2011, from ietf

RFC 6296: IPv6-to-IPv6 Network Prefix Translation โœจ

Okay bestie, let's get into it! ๐ŸŽ€ This is RFC 6296, titled "IPv6-to-IPv6 Network Prefix Translation." It's a 2011 document, and it's on the Experimental track, so it's a "let's try it and see" kind of spec, not a "this is the law" kind of spec. ๐Ÿงช

The authors are M. Wasserman from Painless Security and F. Baker from Cisco Systems. It was published as part of the IETF stream, with ISSN 2070-1721 and a date of June 2011. The title block doesn't list anything it obsoletes or updates. ๐Ÿ’…


Abstract ๐Ÿฆ‹

So basically, this doc describes a stateless, transport-agnostic IPv6-to-IPv6 Network Prefix Translation (NPTv6) function. It gives you the address-independence perk that IPv4-to-IPv4 NAT (NAPT44) is known for. It also creates a 1:1 relationship between addresses in the "inside" and "outside" prefixes, so end-to-end reachability at the network layer stays intact. ๐ŸŒธ


Status of This Memo ๐Ÿ“œ

This document is not an Internet Standards Track specification. It's being published so people can examine it, implement it experimentally, and evaluate it. ๐Ÿ”

This document defines an Experimental Protocol for the Internet community. It's a product of the IETF, and it represents the IETF community's consensus. It got public review and was approved for publication by the Internet Engineering Steering Group (IESG). Not every IESG-approved document is eligible for any level of Internet Standard, so check Section 2 of RFC 5741 if you want the details. ๐Ÿง

Info on the current status of this document, any errata, and how to send feedback is at http://www.rfc-editor.org/info/rfc6296. โœจ


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

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) as they're in effect on the date of publication. Please read these carefully, because they spell out your rights and restrictions for this document. ๐Ÿ“š

Important!! Code Components pulled out of this document must include Simplified BSD License text, as described in Section 4.e of the Trust Legal Provisions. They come without warranty, as described in the Simplified BSD License. โš ๏ธ


Table of Contents ๐Ÿ—‚๏ธ

1.  Introduction . . . . . . . . . . . . . . . . . . . . . . . . .  3
  1.1.  What is Address Independence?  . . . . . . . . . . . . . .  4
  1.2.  NPTv6 Applicability  . . . . . . . . . . . . . . . . . . .  5
  1.3.  Requirements Terminology . . . . . . . . . . . . . . . . .  7
2.  NPTv6 Overview . . . . . . . . . . . . . . . . . . . . . . . .  7
  2.1.  NPTv6: The Simplest Case . . . . . . . . . . . . . . . . .  7
  2.2.  NPTv6 between Peer Networks  . . . . . . . . . . . . . . .  8
  2.3.  NPTv6 Redundancy and Load Sharing  . . . . . . . . . . . .  9
  2.4.  NPTv6 Multihoming  . . . . . . . . . . . . . . . . . . . .  9
  2.5.  Mapping with No Per-Flow State . . . . . . . . . . . . . . 10
  2.6.  Checksum-Neutral Mapping . . . . . . . . . . . . . . . . . 10
3.  NPTv6 Algorithmic Specification  . . . . . . . . . . . . . . . 11
  3.1.  NPTv6 Configuration Calculations . . . . . . . . . . . . . 11
  3.2.  NPTv6 Translation, Internal Network to External Network  . 12
  3.3.  NPTv6 Translation, External Network to Internal Network  . 12
  3.4.  NPTv6 with a /48 or Shorter Prefix . . . . . . . . . . . . 12
  3.5.  NPTv6 with a /49 or Longer Prefix  . . . . . . . . . . . . 13
  3.6.  /48 Prefix Mapping Example . . . . . . . . . . . . . . . . 13
  3.7.  Address Mapping for Longer Prefixes  . . . . . . . . . . . 14
4.  Implications of Network Address Translator Behavioral
    Requirements . . . . . . . . . . . . . . . . . . . . . . . . . 15
  4.1.  Prefix Configuration and Generation  . . . . . . . . . . . 15
  4.2.  Subnet Numbering . . . . . . . . . . . . . . . . . . . . . 15
  4.3.  NAT Behavioral Requirements  . . . . . . . . . . . . . . . 15
5.  Implications for Applications  . . . . . . . . . . . . . . . . 16
  5.1.  Recommendation for Network Planners Considering Use of
        NPTv6 Translation  . . . . . . . . . . . . . . . . . . . . 17
  5.2.  Recommendations for Application Writers  . . . . . . . . . 18
  5.3.  Recommendation for Future Work . . . . . . . . . . . . . . 18
6.  A Note on Port Mapping . . . . . . . . . . . . . . . . . . . . 18
7.  Security Considerations  . . . . . . . . . . . . . . . . . . . 19
8.  Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 19
9.  References . . . . . . . . . . . . . . . . . . . . . . . . . . 20
  9.1.  Normative References . . . . . . . . . . . . . . . . . . . 20
  9.2.  Informative References . . . . . . . . . . . . . . . . . . 20
Appendix A.  Why GSE?  . . . . . . . . . . . . . . . . . . . . . . 23
Appendix B.  Verification Code . . . . . . . . . . . . . . . . . . 25

1. Introduction ๐ŸŒˆ

This doc describes a stateless IPv6-to-IPv6 Network Prefix Translation (NPTv6) function. Its whole purpose is to give the edge network address independence. ๐Ÿฆ‹ It's transport-agnostic for two kinds of transports: the ones that don't checksum the IP header (SCTP is the example), and the ones that use the TCP/UDP/DCCP (Datagram Congestion Control Protocol) pseudo-header and checksum [RFC1071]. ๐Ÿ’…

Now, the IETF does not recommend Network Address Translation for IPv6, and [RFC2993] and Section 5 explain why. ๐Ÿ™ˆ Still, if somebody is going to translate, this spec gives them a mechanism with fewer architectural problems than a traditional stateful NAT running in an IPv6 environment. It's also a solid alternative to the complexity and cost of multihoming with provider-independent addressing, plus the routing and network management headaches of overlaid ISP address space. Some problems do stick around though, so check out the alternatives in [RFC4864] and the considerations in [RFC5902]. ๐Ÿง 

The stateless approach here has a few ramifications, and they're kind of iconic:

  • Any security benefit that NAPT44 might offer is not present in NPTv6. If you want those benefits, you'll need a firewall. An example of one is described in [RFC6092]. ๐Ÿ”ฅ
  • End-to-end reachability is preserved, even though the address used "inside" the edge network is different from the address used "outside" it. That has implications for application referrals and other uses of Internet layer addresses. ๐Ÿซถ
  • If there are multiple identically configured prefix translators between two networks, they don't need to swap dynamic state, because there is no dynamic state. The algorithmic translation will be identical across each of them. So the network can route asymmetrically, load share, and fail over among them with no issues. โœจ
  • Since translation is 1:1 at the network layer, there's no need to modify port numbers or other transport parameters. ๐Ÿ’–
  • TCP sessions that authenticate peers using the TCP Authentication Option [RFC5925] can't have their addresses translated, because the addresses are used in calculating the Message Authentication Code. This applies in general to any UNilateral Self-Address Fixing (UNSAF) [RFC3424] Protocol, which the IAB recommends against deploying in an environment that changes Internet addresses. ๐Ÿšซ
  • Applications using the Internet Key Exchange Protocol Version 2 (IKEv2) [RFC5996] should, at least in theory, detect the presence of the translator. No NAT traversal solution is required, but [RFC5996] would require such sessions to use UDP. ๐Ÿงฉ

1.1. What is Address Independence? ๐ŸŒธ

For the purposes of this document, IPv6 address independence is made up of the following properties:

From the perspective of the edge network:

  • The IPv6 addresses used inside the local network (for interfaces, access lists, and logs) don't need to be renumbered if the global prefix(es) assigned for use by the edge network change. ๐Ÿ”
  • The IPv6 addresses used inside the edge network (for interfaces, access lists, and logs), or within other upstream networks (such as when multihoming), don't need to be renumbered when a site adds, drops, or changes upstream networks. ๐Ÿ”„
  • An administration doesn't have to convince an upstream network to route its internal IPv6 prefixes, or to advertise prefixes derived from other upstream networks into it. ๐Ÿ™Œ
  • Unless it wants to optimize routing between multiple upstream networks while multihoming, there's no need for a BGP exchange with the upstream network. ๐Ÿ›ฃ๏ธ

From the perspective of the upstream network:

  • IPv6 addresses used by the edge network are guaranteed to have a provider-allocated prefix. That gets rid of the need and concern for BCP 38 [RFC2827] ingress filtering, and for advertising customer-specific prefixes. ๐Ÿ‘‘

So address independence has ramifications for the edge network, for the networks it directly connects with (especially its upstream networks), and for the Internet as a whole. ๐ŸŒ

The desire for address independence has been a major reason for IPv4 NAT deployment in medium- to large-sized enterprise networks. That includes enterprises that have plenty of IPv4 provider-independent address space (from IPv4 "swamp space"). It has also pushed edge networks to join Regional Internet Registry (RIR) communities, so they can get BGP Autonomous System Numbers and provider-independent prefixes. As a result, it's been one of the drivers of the explosion of the IPv4 route table. ๐Ÿ“ˆ Service providers have said that the lack of address independence from their customers has been a negative incentive to deploy, because of the impact of customer routing on their networks. ๐Ÿ˜ฌ

The Local Network Protection [RFC4864] document talks about a related concept called "Address Autonomy," which it counts as a benefit of NAPT44. [RFC4864] says address autonomy can be achieved by using global addresses on all nodes within a site that need external connectivity, together with Unique Local Addresses (ULAs) [RFC4193] for all internal communication. However, this solution fails to meet the requirement for address independence. If an ISP renumbering event happens, all of the hosts, routers, DHCP servers, Access Control Lists (ACLs), firewalls, and other internal systems configured with global addresses from the ISP will need to be renumbered before global connectivity is fully restored. ๐Ÿ’€

The use of IPv6 provider-independent (PI) addresses has also been suggested as a way to meet the address-independence requirement. ๐Ÿค” But this approach requires that an enterprise qualify to receive a PI assignment, and then persuade its ISP to install specific routes for the enterprise's PI addresses. There are a bunch of practical issues with that, especially if you want to route to a number of geographically and topologically diverse sites. That can involve coordinating with several ISPs to route portions of a single PI prefix. These problems are why so many enterprises with plenty of IPv4 swamp space chose IPv4 NAT for part, or substantially all, of their internal network, instead of using their provider-independent address space. ๐Ÿฅฒ

That's the end of part 1! ๐ŸŒˆ๐Ÿ’œ

1.2. NPTv6 Applicability โœจ

Okay so, NPTv6 is literally the simple, iconic answer to address independence in IPv6 ๐Ÿฆ‹ The address-independence perk comes straight from the translation function of the network prefix translator. To dodge as many of the NAPT44 headaches as possible, NPTv6 is defined to include a two-way, checksum-neutral, algorithmic translation function, and nothing else ๐Ÿ’…

Because NPTv6 doesn't map ports and is checksum-neutral, an NPTv6 Translator doesn't have to rewrite transport layer headers ๐Ÿ™Œ That makes it feasible to deploy new or improved transport layer protocols without upgrading NPTv6 Translators. And since NPTv6 leaves those headers alone, it won't interfere with encryption of the full IP payload in many cases ๐Ÿ” bestie, that's a whole vibe.

The default NPTv6 address-mapping mechanism is purely algorithmic, so NPTv6 translators don't need to keep per-node or per-connection state. That lets you build more robust and adaptive networks than you can with NAPT44 ๐ŸŒธ Since the default NPTv6 mapping works in either direction, it doesn't get in the way of inbound connection establishment. Internal nodes can join direct Peer-to-Peer applications without the application layer overhead you find in lots of IPv4 Peer-to-Peer apps. Main character energy for real โญ

Now the tea โ˜• Even though NPTv6 compares favorably to NAPT44 in several ways, it doesn't fix every architectural problem of IPv4 NAT, as described in [RFC2993]. NPTv6 modifies IP headers in transit, so it isn't compatible with security mechanisms, like the IPsec Authentication Header, that provide integrity protection for the IP header ๐Ÿ˜ญ It may also interfere with application protocols that carry IP addresses inside the application-specific portion of the IP datagram. Those apps already need Application Layer Gateways (ALGs) to work through NAPT44 devices, and similar ALGs may be needed for them to work through NPTv6 Translators ๐Ÿ™ˆ

Separate internal and external prefixes also make DNS deployment messy ๐Ÿ’€ Internal nodes want to talk to other internal nodes using internal addresses, while external nodes need external addresses to reach those same nodes. This often leads to "split DNS," which can add complexity to network configuration.

The choice of address inside the edge network matters too ๐Ÿงš You could use a ULA, which maximizes address independence. That could also be seen as a misuse of the ULA. If you expect a ULA to block access to a system from outside the ULA's range, NPTv6 overrides that. On the other hand, the administration knows it made that choice, and it could deploy a second ULA for privacy if it wanted to. The only prefix that will be translated is one that has an NPTv6 Translator configured to translate to or from it. Also, using any other global-scope address format means you either obtain a PI prefix or are at the mercy of the agency it was allocated from ๐Ÿ“

Any prefix translation mechanism, NPTv6 included, has big technical impacts when deployed. We strongly encourage anyone thinking about implementing or deploying NPTv6 to read [RFC4864] and [RFC5902], and to carefully consider the alternatives described in that document. Some of those may cause fewer problems than NPTv6 does ๐Ÿซถ

1.3. Requirements 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 RFC 2119 [RFC2119].


2. NPTv6 Overview ๐ŸŽ€

NPTv6 may be implemented in an IPv6 router to map one IPv6 address prefix to another IPv6 prefix as each IPv6 datagram transits the router. A router that implements an NPTv6 prefix translation function is referred to as an NPTv6 Translator ๐Ÿ’œ

2.1. NPTv6: The Simplest Case ๐ŸŒˆ

In its simplest form, an NPTv6 Translator connects two network links. One is an "internal" network link attached to a leaf network inside a single administrative domain. The other is an "external" network with connectivity to the global Internet. All of the hosts on the internal network use addresses from a single, locally routed prefix, and those addresses get translated to and from addresses in a globally routable prefix as IP datagrams transit the NPTv6 Translator. The lengths of these two prefixes are functionally the same. If they differ, the longer one limits your ability to use subnets in the shorter one ๐Ÿ™ƒ

               External Network:  Prefix = 2001:0DB8:0001:/48
                   --------------------------------------
                                     |
                                     |
                              +-------------+
                              |     NPTv6   |
                              |  Translator |
                              +-------------+
                                     |
                                     |
                   --------------------------------------
               Internal Network:  Prefix = FD01:0203:0405:/48

                       Figure 1: A Simple Translator

Figure 1 shows an NPTv6 Translator attached to two networks. In this example, the internal network uses IPv6 Unique Local Addresses (ULAs) [RFC4193] to represent the internal IPv6 nodes, and the external network uses globally routable IPv6 addresses to represent those same nodes โœจ

When an NPTv6 Translator forwards datagrams in the "outbound" direction (internal network to external network), NPTv6 overwrites the IPv6 source prefix in the IPv6 header with a corresponding external prefix. When datagrams go the "inbound" direction (external network to internal network), the IPv6 destination prefix gets overwritten with a corresponding internal prefix ๐Ÿฆ‹ Using the prefixes in the diagram above, an IP datagram passing through the NPTv6 Translator in the outbound direction has its source prefix (FD01:0203:0405:/48) overwritten with the external prefix (2001:0DB8:0001:/48). In an inbound datagram, the destination prefix (2001:0DB8:0001:/48) gets overwritten with the internal prefix (FD01:0203:0405:/48). In both cases, it's the local IPv6 prefix that gets overwritten, and the remote IPv6 prefix stays unchanged. Nodes on the internal network are said to be "behind" the NPTv6 Translator ๐Ÿงš

2.2. NPTv6 between Peer Networks ๐Ÿค

NPTv6 can also be used between two private networks. In these cases, both networks may use ULA prefixes, with each subnet in one network mapped into a corresponding subnet in the other network, and vice versa. Or, each network may use ULA prefixes for internal addressing and global unicast addresses on the other network ๐Ÿ’…

                  Internal Prefix = FD01:4444:5555:/48
                  --------------------------------------
                       V            |      External Prefix
                       V            |      2001:0DB8:6666:/48
                       V        +---------+      ^
                       V        |  NPTv6  |      ^
                       V        |  Device |      ^
                       V        +---------+      ^
              External Prefix       |            ^
              2001:0DB8:0001:/48    |            ^
                  --------------------------------------
                  Internal Prefix = FD01:0203:0405:/48

               Figure 2: Flow of Information in Translation

2.3. NPTv6 Redundancy and Load Sharing ๐Ÿ”

Sometimes more than one NPTv6 Translator is attached to a network, as shown in Figure 3. In those cases, the NPTv6 Translators are configured with the same internal and external prefixes. Since there's only one translation, even with multiple translators, they map only one external address (prefix and Interface Identifier (IID)) to the internal address ๐Ÿซถ

               External Network:  Prefix = 2001:0DB8:0001:/48
                   --------------------------------------
                          |                      |
                          |                      |
                   +-------------+        +-------------+
                   |  NPTv6      |        |  NPTv6      |
                   |  Translator |        |  Translator |
                   |   #1        |        |   #2        |
                   +-------------+        +-------------+
                          |                      |
                          |                      |
                   --------------------------------------
               Internal Network:  Prefix = FD01:0203:0405:/48

                      Figure 3: Parallel Translators

2.4. NPTv6 Multihoming ๐ŸŒ

            External Network #1:          External Network #2:
         Prefix = 2001:0DB8:0001:/48    Prefix = 2001:0DB8:5555:/48
         ---------------------------    --------------------------
                         |                      |
                         |                      |
                  +-------------+        +-------------+
                  |  NPTv6      |        |  NPTv6      |
                  |  Translator |        |  Translator |
                  |   #1        |        |   #2        |
                  +-------------+        +-------------+
                         |                      |
                         |                      |
                  --------------------------------------
              Internal Network:  Prefix = FD01:0203:0405:/48

      Figure 4: Parallel Translators with Different Upstream Networks

When multihoming, NPTv6 Translators are attached to an internal network, as shown in Figure 4, but they connect to different external networks. In those cases, the NPTv6 Translators are configured with the same internal prefix but different external prefixes. Since there are multiple translations, they map multiple external addresses (prefix and IID) to the common internal address ๐Ÿ˜ฎ A system inside the edge network can't tell which external address it's using, apart from services like Session Traversal Utilities for NAT (STUN) [RFC5389].

Multihoming like this has one downside compared with multihoming using a provider-independent address. When routes change between NPTv6 Translators, the translated prefix can change because the upstream network changes. That makes sessions and referrals that depend on it fail too ๐Ÿ˜ญ This isn't expected to be a major issue, though, in networks where routing is generally stable ๐ŸŒธ

2.5. Mapping with No Per-Flow State ๐Ÿง 

When NPTv6 is used as described in this document, no per-node or per-flow state is kept in the NPTv6 Translator. Both inbound and outbound datagrams are translated algorithmically, using only information found in the IPv6 header. Because of this, NPTv6's two-way, algorithmic address mapping can support both outbound and inbound connection establishment without maintaining mapping state or using state-priming or rendezvous mechanisms. That's a big upgrade over NAPT44 devices, but it also has significant security implications, which are described in Section 7 ๐Ÿ”๐Ÿ‘‘

2.6. Checksum-Neutral Mapping ๐ŸŽ€

okay so bestie, when you change one of the IP header fields that's part of the IPv6 pseudo-header checksum (like an IP address), the checksum field in the transport layer header can go invalid ๐Ÿ˜ญ. Thankfully, an incremental change in the area covered by the Internet standard checksum [RFC1071] leads to a well-defined change in the checksum value [RFC1624]. So if you change part of the covered area, you can fix the damage by making a matching change to a different 16-bit field covered by that same checksum โœจ

The NPTv6 mapping mechanisms in this document are checksum-neutral, which means they result in IP headers that generate the same IPv6 pseudo-header checksum when it's calculated with the standard Internet checksum algorithm [RFC1071]. Any changes made while translating the IPv6 prefix get offset by changes to other parts of the IPv6 address ๐Ÿ’…. That means transport layers that use the Internet checksum (like TCP and UDP) calculate the same IPv6 pseudo-header checksum for both the internal and external forms of the same datagram. So the NPTv6 Translator doesn't have to touch those transport layer headers to fix the checksum value. Iconic, honestly ๐Ÿฆ‹

The outgoing checksum correction happens by changing a 16-bit section of the source address that isn't used for routing in the external network. Thanks to how checksum arithmetic works, applying the matching correction to the same bits of the destination address of the inbound packet puts the Destination Address (DA) back to its correct internal value ๐Ÿงš

As noted in Section 4.2, this mapping means an edge network using a /48 external prefix can't use subnet 0xFFFF ๐Ÿ™ˆ

3. NPTv6 Algorithmic Specification ๐Ÿงฎ

The [RFC4291] IPv6 Address is reproduced for clarity in Figure 5 ๐Ÿ“ธ.

      0    15 16   31 32   47 48   63 64   79 80   95 96  111 112  127
     +-------+-------+-------+-------+-------+-------+-------+-------+
     |     Routing Prefix    | Subnet|   Interface Identifier (IID)  |
     +-------+-------+-------+-------+-------+-------+-------+-------+

Figure 5: Enumeration of the IPv6 Address [RFC4291]

3.1. NPTv6 Configuration Calculations ๐ŸŒธ

When an NPTv6 Translation function gets configured, it's set up with:

  • one or more "internal" interfaces with their "internal" routing domain prefixes, and
  • one or more "external" interfaces with their "external" routing domain prefixes.

In the simple case there's one of each. If a single router provides NPTv6 translation between a bunch of domains (which can happen when multihoming), each internal/external pair has to be treated as a separate NPTv6 Translator from this specification's point of view ๐Ÿ‘‘.

When an NPTv6 Translator is configured, the translation function first makes sure the internal and external prefixes are the same length, zero-extending the shorter one if it needs to. These two prefixes are then used in the prefix translation function described in Sections 3.2 and 3.3 ๐Ÿ’–.

Next, they're zero-extended to /64 for the calculation. The translation function works out the one's complement sum of the 16-bit words of the /64 external prefix and the /64 internal prefix. Then it finds the difference between those values: internal minus external. This value, called the "adjustment", stays effectively constant for the whole lifetime of the NPTv6 Translator configuration and gets used in per-datagram processing ๐Ÿ”ฅ.

3.2. NPTv6 Translation, Internal Network to External Network โœˆ๏ธ

When a datagram goes through the NPTv6 Translator from an internal network to an external one, its IPv6 Source Address either gets changed in two ways or the datagram gets thrown out:

  • If the internal subnet number has no mapping (like being 0xFFFF, or just not mapped), discard the datagram. This SHOULD result in an ICMP Destination Unreachable ๐Ÿšซ.
  • The internal prefix gets overwritten with the external prefix, which in effect subtracts the difference between the two checksums (the adjustment) from the pseudo-header's checksum, and
  • A 16-bit word of the address has the adjustment added to it using one's complement arithmetic. If the result is 0xFFFF, it gets overwritten as zero. The choice of word follows Sections 3.4 or 3.5, whichever applies ๐Ÿง.

3.3. NPTv6 Translation, External Network to Internal Network ๐Ÿ”„

When a datagram goes through the NPTv6 Translator from an external network to an internal one, its IPv6 Destination Address gets changed in two ways:

  • The external prefix gets overwritten with the internal prefix, which in effect adds the difference between the two checksums (the adjustment) to the pseudo-header's checksum, and
  • A 16-bit word of the address has the adjustment subtracted from it (bitwise inverted and added to it) using one's complement arithmetic. If the result is 0xFFFF, it gets overwritten as zero. The choice of word follows Section 3.4 or Section 3.5, whichever applies ๐ŸŒˆ.

3.4. NPTv6 with a /48 or Shorter Prefix ๐ŸŽฏ

When an NPTv6 Translator is configured with internal and external prefixes that are 48 bits long (a /48) or shorter, the adjustment MUST be added to or subtracted from bits 48..63 of the address.

This mapping doesn't modify the Interface Identifier (IID), which lives in the lower half of the IPv6 address. So it won't get in the way of future protocols that might use unique IIDs for node identification ๐Ÿซถ.

NPTv6 Translator implementations MUST implement the /48 mapping.

3.5. NPTv6 with a /49 or Longer Prefix ๐Ÿ“

When an NPTv6 Translator is configured with internal and external prefixes longer than 48 bits (like a /52, /56, or /60), the adjustment must be added to or subtracted from one of the words in bits 64..79, 80..95, 96..111, or 112..127 of the address. The choice of word doesn't matter as long as it's consistent, but these words MUST be inspected in that sequence, and the first one that isn't initially 0xFFFF gets chosen, just for consistency's sake ๐Ÿ“.

NPTv6 Translator implementations SHOULD implement the mapping for longer prefixes.

3.6. /48 Prefix Mapping Example ๐Ÿงช

For the network shown in Figure 1, the Internal Prefix is FD01:0203:0405:/48, and the External Prefix is 2001:0DB8:0001:/48.

If a node with internal address FD01:0203:0405:0001::1234 sends an outbound datagram through the NPTv6 Translator, the resulting external address will be 2001:0DB8:0001:D550::1234. To get there, you calculate the checksum of both the internal and external 48-bit prefixes, subtract the internal prefix from the external prefix using one's complement arithmetic to work out the "adjustment", and add that adjustment to the 16-bit subnet field (in this case, 0x0001) โœจ.

Let me show the work, bestie ๐Ÿค“:

The one's complement checksum of FD01:0203:0405 is 0xFCF5. The one's complement checksum of 2001:0DB8:0001 is 0xD245. Using one's complement arithmetic, 0xD245 - 0xFCF5 = 0xD54F. The subnet in the original datagram is 0x0001. Using one's complement arithmetic, 0x0001 + 0xD54F = 0xD550. Since 0xD550 != 0xFFFF, it is not changed to 0x0000.

So the value 0xD550 gets written into the 16-bit subnet area, resulting in a mapped external address of 2001:0DB8:0001:D550::1234 ๐Ÿ’….

When a response datagram comes back, it contains the destination address 2001:0DB8:0001:D550::0001, which gets mapped back to FD01:0203:0405:0001::1234 using the inverse mapping algorithm ๐Ÿ”.

In this case, the difference between the two prefixes gets calculated like this:

Using one's complement arithmetic, 0xFCF5 - 0xD245 = 0x2AB0. The subnet in the original datagram = 0xD550. Using one's complement arithmetic, 0xD550 + 0x2AB0 = 0x0001. Since 0x0001 != 0xFFFF, it is not changed to 0x0000.

So the value 0x0001 gets written into the subnet field, and the internal value of the subnet field is properly restored ๐ŸŽ‰.

3.7. Address Mapping for Longer Prefixes ๐Ÿงฉ

If the prefix being mapped is longer than 48 bits, the algorithm gets a little more complex. A common case is that the internal and external prefixes have different lengths. In that situation, the shorter prefix is zero-extended to the length of the longer one (as described in Section 3.1) so it can overwrite the prefix. Then both get zero-extended to 64 bits so one's complement arithmetic works. The "adjustment" is calculated using those 64-bit prefixes ๐Ÿง .

For example, if the internal prefix is a /48 ULA and the external prefix is a /56 provider-allocated prefix, the ULA becomes a /56 with zeros in bits 48..55. For one's complement arithmetic purposes, they're both then zero-extended to 64 bits. A side effect of this is that a subset of the subnets possible in the shorter prefix is untranslatable. The security value of this is debatable, but the administration may choose to use those subnets for ones that it knows don't need any external accessibility ๐Ÿ”.

Next, we find the first word in the IID that doesn't have the value 0xFFFF, checking bits 64..79, then 80..95, 96..111, and finally 112..127. We do the same calculation (with the same proof of correctness) as in Section 3.6, but apply it to that word ๐Ÿ’ซ.

Although any 16-bit portion of an IPv6 IID could contain 0xFFFF, an IID of all-ones is a reserved anycast identifier that should not be used on the network [RFC2526]. If an NPTv6 Translator finds a datagram with an IID of all-zeros while doing address mapping, that datagram MUST be dropped, and an ICMPv6 Parameter Problem error SHOULD be generated [RFC4443] ๐Ÿšจ.

Note: This mechanism does involve modification of the IID. It may not be compatible with future mechanisms that use unique IIDs for node identification ๐Ÿ‘€.

4. Implications of Network Address Translator Behavioral Requirements ๐Ÿ“œ

4.1. Prefix Configuration and Generation ๐Ÿ› ๏ธ

NPTv6 Translators MUST support manual configuration of internal and external prefixes, and MUST NOT place any restrictions on those prefixes except that they be valid IPv6 unicast prefixes as described in [RFC4291]. They MAY also support random generation of ULA addresses on command ๐ŸŽฒ. Since the most common place an NPTv6 Translator is expected to be implemented is a Customer Premises Equipment (CPE) router, the reader is urged to consider the requirements of [RFC6204] ๐Ÿ .

4.2. Subnet Numbering ๐Ÿ”ข

For reasons detailed in Appendix B, a network using NPTv6 Translation and a /48 external prefix MUST NOT use the value 0xFFFF to designate a subnet that it expects to be translated ๐Ÿ’€.

4.3. NAT Behavioral Requirements ๐Ÿ’…

okay bestie, the big rule here is that NPTv6 Translators MUST support hairpinning behavior, as defined in the NAT Behavioral Requirements for UDP document [RFC4787] ๐Ÿ”ฅ. So when an NPTv6 Translator gets a datagram on the internal interface whose destination address matches the site's external prefix, it translates the datagram and forwards it internally. This is how internal nodes can reach other internal nodes using their external, global addresses when they need to ๐Ÿฆ‹

Conceptually, the datagram leaves the domain (translated as described in Section 3.2) and then comes back in (translated again as described in Section 3.3). So the datagram exchange goes through the NPTv6 Translator in both directions for the whole lifetime of the session ๐Ÿ’œ The alternative would be making the translator drop the datagram, which forces the sender to use the correct internal prefix for its peer ๐Ÿ™ˆ If you only did the external-to-internal translation, the datagram would be sent from the untranslated internal address of the source to the translated, and therefore internal, address of its peer. That lets the session skip the NPTv6 Translator for future datagrams, and the original sender would be unlikely to recognize the response when it arrived. Not ideal, babe ๐Ÿ’€

Because NPTv6 does not perform port mapping and uses a one-to-one, reversible-mapping algorithm, none of the other NAT behavioral requirements apply to NPTv6 โœจ


5. Implications for Applications ๐ŸŒธ

NPTv6 Translation does not create several of the problems known to exist with other kinds of NATs, as discussed in [RFC2993] ๐Ÿซถ Like, it is stateless, so a "reset" or brief outage of an NPTv6 Translator does not break connections that traverse the translation function. And if multiple NPTv6 Translators exist between the same two networks, the load can shift or be dynamically load shared among them. Also, an NPTv6 Translator does not aggregate traffic for several hosts or interfaces behind a smaller number of external addresses. So there is no inherent expectation for an NPTv6 Translator to block new inbound flows from external hosts, and no issue with a filter or blacklist associated with one prefix within the domain affecting another ๐Ÿงš A firewall can, of course, be used in conjunction with an NPTv6 Translator. This gives the network administrator more flexibility to specify security policy than would be possible with a traditional NAT ๐Ÿ‘‘

However, NPTv6 Translation does create difficulties for some kinds of applications. Some examples include:

  • An application instance "behind" an NPTv6 Translator will see a different address for its connections than its peers "outside" the NPTv6 Translator. ๐Ÿ˜ญ
  • An application instance "outside" an NPTv6 Translator will see a different address for its connections than any peer "inside" an NPTv6 Translator. ๐Ÿฅบ
  • An application instance wishing to establish communication with a peer "behind" an NPTv6 Translator may need to use a different address to reach that peer, depending on whether the instance is behind the same NPTv6 Translator or external to it. Since an NPTv6 Translator implements hairpinning (Section 4.3), it suffices for applications to always use their external addresses. However, this creates inefficiencies in the local network and may also complicate implementation of the NPTv6 Translator. [RFC3484] also would prefer the private address in such a case in order to reduce those inefficiencies. ๐Ÿ™ƒ
  • An application instance that moves from a realm "behind" an NPTv6 Translator to a realm that is "outside" the network, or vice versa, may find that it is no longer able to reach its peers at the same addresses it was previously able to use. ๐ŸŒ€
  • An application instance that is intermittently communicating with a peer that moves from behind an NPTv6 Translator to "outside" of it, or vice versa, may find that it is no longer able to reach that peer at the same address it had previously used. ๐Ÿซ 

Many, but not all, of the applications that are adversely affected by NPTv6 Translation are those that do "referrals". That's where an application instance passes its own addresses, and/or addresses of its peers, to other peers. (Some believe referrals are inherently undesirable; others believe that they are necessary in some circumstances. A discussion of the merits of referrals, or lack thereof, is beyond the scope of this document.) ๐Ÿคทโ€โ™€๏ธ

To some extent, the incidence of these difficulties can be reduced by DNS hacks that attempt to expose addresses "behind" an NPTv6 Translator only to hosts that are also behind the same NPTv6 Translator. They may also expose only the "internal" addresses of hosts behind the NPTv6 Translator to other hosts behind the same NPTv6 Translator. However, this cannot be a complete solution. A full discussion of these issues is out of scope for this document, but briefly: (a) reliance on DNS to solve this problem depends on hosts always making queries from DNS servers in the same realm as they are (or on DNS interception proxies, which create their own problems) and on mobile hosts/applications not caching those results; (b) reliance on DNS to solve this problem depends on network administrators on all networks using such applications to reliably and accurately maintain current DNS entries for every host using those applications; and (c) reliance on DNS to solve this problem depends on applications always using DNS names, even though they often must run in environments where DNS names are not reliably maintained for every host. Other issues are that there is often no single distinguished name for a host, and no reliable way for a host to determine what DNS names are associated with it and which names are appropriate to use in which contexts. ๐Ÿ˜ตโ€๐Ÿ’ซ

5.1. Recommendation for Network Planners Considering Use of NPTv6 Translation ๐Ÿ“‹

So, in light of the above, network planners considering the use of NPTv6 translation should carefully consider the kinds of applications they will need to run in the future. They should also determine whether the address-stability and provider-independence benefits are consistent with their application requirements ๐Ÿง 

5.2. Recommendations for Application Writers โœ๏ธ

Several mechanisms (e.g., STUN [RFC5389], Traversal Using Relays around NAT (TURN) [RFC5766], and Interactive Connectivity Establishment (ICE) [RFC5245]) have been used with traditional IPv4 NAT to circumvent some of the limitations of such devices. Similar mechanisms could also be applied to circumvent some of the issues with an NPTv6 Translator. However, all of these require the assistance of an external server, or a function co-located with the translator, that can tell an "internal" host what its "external" addresses are ๐Ÿ”‘

5.3. Recommendation for Future Work ๐Ÿ”ฎ

It might be desirable to define a general mechanism that would allow hosts within a translation domain to determine their external addresses and/or request that inbound traffic be permitted. If such a mechanism were to be defined, it would ideally be general enough to also accommodate other types of NAT likely to be encountered by IPV6 applications, in particular IPv4/IPv6 Translation [RFC6144] [RFC6147] [RFC6145] [RFC6146] [RFC6052]. For this and other reasons, such a mechanism is beyond the scope of this document ๐Ÿฆ‹


6. A Note on Port Mapping ๐ŸŽ€

In addition to overwriting IP addresses when datagrams are forwarded, NAPT44 devices overwrite the source port number in outbound traffic and the destination port number in inbound traffic. This mechanism is called "port mapping" ๐Ÿ“

The major benefit of port mapping is that it allows multiple computers to share a single IPv4 address. A large number of internal IPv4 addresses (typically from one of the [RFC1918] private address spaces) can be mapped into a single external, globally routable IPv4 address. The local port number is used to identify which internal node should receive each inbound datagram. This address-amplification feature is not generally foreseen as a necessity at this time ๐Ÿ’…

Since port mapping requires rewriting a portion of the transport layer header, it requires NAPT44 devices to be aware of all of the transport protocols that they forward. That stifles the development of new and improved transport protocols and prevents the use of IPsec encryption ๐Ÿ˜ค Modifying the transport layer header is incompatible with security mechanisms that encrypt the full IP payload, and it restricts the NAPT44 to forwarding transport layers that use weak checksum algorithms that are easily recalculated in routers.

Since there is significant detriment caused by modifying transport layer headers, and very little, if any, benefit to the use of port mapping in IPv6, NPTv6 Translators that comply with this specification MUST NOT perform port mapping ๐Ÿšซโœจ


7. Security Considerations ๐Ÿ”

โš ๏ธ Read this one carefully, it's serious business.

When NPTv6 is deployed using either of the two-way, algorithmic mappings defined in this document, it allows direct inbound connections to internal nodes. While this can be viewed as a benefit of NPTv6 versus NAPT44, it does open internal nodes to attacks that would be more difficult in a NAPT44 network. From a security standpoint, although this situation is not substantially worse than running IPv6 with no NAT, some enterprises may assume that an NPTv6 Translator will offer similar protection to a NAPT44 device ๐Ÿ˜ฑ

The port mapping mechanism in NAPT44 implementations requires that state be created in both directions. This has lead to an industry-wide perception that NAT functionality is the same as a stateful firewall. It is not! The translation function of the NAT only creates dynamic state in one direction and has no policy. For this reason, it is RECOMMENDED that NPTv6 Translators also implement firewall functionality, such as described in [RFC6092], with appropriate configuration options, including turning it on or off ๐Ÿ›ก๏ธ

When [RFC4864] talks about randomizing the subnet identifier, the idea is to make it harder for worms to guess a valid subnet identifier at an advertised network prefix. This should not be interpreted as endorsing concealment of the subnet identifier behind the obfuscating function of a translator such as NPTv6. [RFC4864] specifically talks about how to obtain the desired properties of concealment without using a translator. Topology hiding when using NAT is often ineffective in environments where the topology is visible in application layer messaging protocols such as DNS, SIP, SMTP, etc. If the information were not available through the application layer, [RFC2993] would not be valid ๐Ÿ™ˆ

Due to the potential interactions with IKEv2/IPsec NAT traversal, it would be valuable to test interactions of NPTv6 with various aspects of current-day IKEv2/IPsec NAT traversal ๐Ÿงช


8. Acknowledgements ๐Ÿซถ

The checksum-neutral algorithmic address mapping described in this document is based on email written by Iljtsch van Beijnum ๐Ÿ’Œ

The following people provided advice or review comments that substantially improved this document: Allison Mankin, Christian Huitema, Dave Thaler, Ed Jankiewicz, Eric Kline, Iljtsch van Beijnum, Jari Arkko, Keith Moore, Mark Townsley, Merike Kaeo, Ralph Droms, Remi Despres, Steve Blake, and Tony Hain ๐ŸŒˆ


9. References ๐Ÿ“š

9.1. Normative References โœจ

Okay bestie, the must-read citations first ๐Ÿ“š These are the ones the spec leans on, so you need them to be fully on the same page:

  • [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.
  • [RFC2526] Johnson, D. and S. Deering, "Reserved IPv6 Subnet Anycast Addresses", RFC 2526, March 1999.
  • [RFC4193] Hinden, R. and B. Haberman, "Unique Local IPv6 Unicast Addresses", RFC 4193, October 2005.
  • [RFC4291] Hinden, R. and S. Deering, "IP Version 6 Addressing Architecture", RFC 4291, February 2006.
  • [RFC4443] Conta, A., Deering, S., and M. Gupta, "Internet Control Message Protocol (ICMPv6) for the Internet Protocol Version 6 (IPv6) Specification", RFC 4443, March 2006.
  • [RFC4787] Audet, F. and C. Jennings, "Network Address Translation (NAT) Behavioral Requirements for Unicast UDP", BCP 127, RFC 4787, January 2007.

9.2. Informative References ๐ŸŒธ

These ones are the extra reading ๐Ÿซถ Not required to build the thing, but they give you the full story and the receipts:

  • [GSE] O'Dell, M., "GSE - An Alternate Addressing Architecture for IPv6", Work in Progress, February 1997.
  • [NIST] NIST, "Draft NIST Framework and Roadmap for Smart Grid Interoperability Standards, Release 1.0", September 2009.
  • [RFC1071] Braden, R., Borman, D., Partridge, C., and W. Plummer, "Computing the Internet checksum", RFC 1071, September 1988.
  • [RFC1624] Rijsinghani, A., "Computation of the Internet Checksum via Incremental Update", RFC 1624, May 1994.
  • [RFC1918] Rekhter, Y., Moskowitz, R., Karrenberg, D., Groot, G., and E. Lear, "Address Allocation for Private Internets", BCP 5, RFC 1918, February 1996.
  • [RFC2827] Ferguson, P. and D. Senie, "Network Ingress Filtering: Defeating Denial of Service Attacks which employ IP Source Address Spoofing", BCP 38, RFC 2827, May 2000.
  • [RFC2993] Hain, T., "Architectural Implications of NAT", RFC 2993, November 2000.
  • [RFC3424] Daigle, L. and IAB, "IAB Considerations for UNilateral Self-Address Fixing (UNSAF) Across Network Address Translation", RFC 3424, November 2002.
  • [RFC3484] Draves, R., "Default Address Selection for Internet Protocol version 6 (IPv6)", RFC 3484, February 2003.
  • [RFC4864] Van de Velde, G., Hain, T., Droms, R., Carpenter, B., and E. Klein, "Local Network Protection for IPv6", RFC 4864, May 2007.
  • [RFC5245] Rosenberg, J., "Interactive Connectivity Establishment (ICE): A Protocol for Network Address Translator (NAT) Traversal for Offer/Answer Protocols", RFC 5245, April 2010.
  • [RFC5389] Rosenberg, J., Mahy, R., Matthews, P., and D. Wing, "Session Traversal Utilities for NAT (STUN)", RFC 5389, October 2008.
  • [RFC5766] Mahy, R., Matthews, P., and J. Rosenberg, "Traversal Using Relays around NAT (TURN): Relay Extensions to Session Traversal Utilities for NAT (STUN)", RFC 5766, April 2010.
  • [RFC5902] Thaler, D., Zhang, L., and G. Lebovitz, "IAB Thoughts on IPv6 Network Address Translation", RFC 5902, July 2010.
  • [RFC5925] Touch, J., Mankin, A., and R. Bonica, "The TCP Authentication Option", RFC 5925, June 2010.
  • [RFC5996] Kaufman, C., Hoffman, P., Nir, Y., and P. Eronen, "Internet Key Exchange Protocol Version 2 (IKEv2)", RFC 5996, September 2010.
  • [RFC6052] Bao, C., Huitema, C., Bagnulo, M., Boucadair, M., and X. Li, "IPv6 Addressing of IPv4/IPv6 Translators", RFC 6052, October 2010.
  • [RFC6092] Woodyatt, J., "Recommended Simple Security Capabilities in Customer Premises Equipment (CPE) for Providing Residential IPv6 Internet Service", RFC 6092, January 2011.
  • [RFC6144] Baker, F., Li, X., Bao, C., and K. Yin, "Framework for IPv4/IPv6 Translation", RFC 6144, April 2011.
  • [RFC6145] Li, X., Bao, C., and F. Baker, "IP/ICMP Translation Algorithm", RFC 6145, April 2011.
  • [RFC6146] Bagnulo, M., Matthews, P., and I. van Beijnum, "Stateful NAT64: Network Address and Protocol Translation from IPv6 Clients to IPv4 Servers", RFC 6146, April 2011.
  • [RFC6147] Bagnulo, M., Sullivan, A., Matthews, P., and I. van Beijnum, "DNS64: DNS Extensions for Network Address Translation from IPv6 Clients to IPv4 Servers", RFC 6147, April 2011.
  • [RFC6204] Singh, H., Beebee, W., Donley, C., Stark, B., and O. Troan, "Basic Requirements for IPv6 Customer Edge Routers", RFC 6204, April 2011.

Appendix A. Why GSE? ๐Ÿงš

Okay so, for this chat we're going to oversimplify how the Internet is shaped and split networks into two big buckets: transit and edge ๐Ÿ’… A "transit network" is basically a network that provides connectivity to other networks. Its AS number might pop up in the middle of BGP AS paths, or, if it's a mobile or residential broadband network, it might offer network services to smaller networks that can't justify RIR membership. An "edge network" is literally any network that isn't transit. It's the ultimate customer. It does provide internal connectivity for its own use, but in every other way it's a consumer of transit services ๐Ÿซถ When it comes to routing, a transit network usually needs some way to choose how it routes to other networks, while an edge network is usually super happy with a simple default route. ๐ŸŒˆ

The [GSE] proposal, and this proposal as a result (which is similar to GSE in most respects and inspired by it), responds directly to what the RIR communities are worried about right now ๐Ÿ‘‘ In IPv4, edge networks are used to having their addressing be separate from their upstream transit networks. Either it's provider independent, or a network prefix translator makes their external address different from their internal one, and they honestly like that distinction. In IPv6, there's this mantra that edge network addresses should be derived from their upstream, and if they have multiple upstreams, edge networks are expected to design their networks to use all of those prefixes equivalently. The edge sees this as unnecessary and unwanted operational complexity, so they're pushing very hard in the RIR communities for provider-independent addressing. Honestly, it's giving main character energy ๐Ÿ’€

Here's the thing though. Widespread provider-independent addressing has a natural, and maybe unavoidable, side effect that's likely to be super expensive in the long term ๐Ÿ˜ญ With widespread PI addressing, the routing table would list the networks at the edge of the transit domain, rather than list the transit domain itself. Per the BGP Update Report of 17 December 2010, there are currently over 36,000 Autonomous Systems being advertised in BGP, and over 15,000 of them advertise only one prefix. There are roughly 5000 ASs that show up in a non-final position in AS paths, and maybe another 5000 networks whose AS numbers are terminal in more than one AS path. So in other words, we already have prefixes for some 36,000 transit and edge networks in the route table, and a lot of them arguably only need an Autonomous System number for multihoming. The vast majority of networks (2/3) that have the tools to multihome aren't visibly doing it, and they'd be well served by any solution that gives them address independence without the overhead of RIR membership and BGP routing ๐Ÿฆ‹

Current growth estimates suggest we could easily see that be on the order of 10,000,000 within fifteen years ๐Ÿ™ˆ Tens of thousands of route table entries are very survivable. Our protocols and computers will probably do pretty well with tens of millions of routes too, but the heat produced and power consumed by those routers, plus the inevitable impact on the cost of those routers, is not a good outcome at all. To avoid a massive and unscalable route table, we need a way that's politically acceptable and that returns us to enumerating the transit domain, not the edge. โœจ

There have been a bunch of proposals. As described, Shim6 moves the complexity to the edge, and the edge is rebelling ๐Ÿ’… Geographic addressing basically forces ISPs to "own" geographic territory from a routing perspective, because otherwise there's no clue in the address about which network a datagram should be delivered to in order to reach it. Metropolitan Addressing can imply regulatory authority, and even if it's implemented using internet exchange consortia, it puts a ton of complexity on the transit networks that directly serve the edge. The one that's likely to be the most acceptable is any proposal that lets an edge network be operationally independent of its upstreams, with no obligation to renumber when it adds, drops, or changes ISPs, and with no additional burden on the ISP or the edge network as a result. ๐Ÿซถ From an application perspective, the Roadmap for the Smart Grid [NIST] adds another operational requirement, and it says that:

"...the network should provide the capability to enable an application in a particular domain to communicate with an application in any other domain over the information network, with proper management control as to who and where applications can be inter-connected."

In other words, the structure of the network should allow for and enable appropriate access control, but the structure of the network should not inherently limit access. ๐Ÿ”ฅ

So the GSE model statelessly translates the prefix between an edge network and its upstream transit network, and it does that with a minimum of fuss and bother ๐ŸŽ€ Stated in the simplest terms, it lets the edge network behave as if it has a provider-independent prefix from a multihoming and renumbering perspective, without the overhead of RIR membership or maintaining BGP connectivity. It also lets the transit networks aggressively aggregate what are, from their perspective, provider-allocated customer prefixes, so the routing table stays a rational size. Iconic, honestly. ๐Ÿ‘‘๐ŸŒธ

Appendix B. Verification Code โœจ

okay so this appendix is totally non-normative ๐Ÿซถ It's a proof of concept, and it is in no way optimized ๐Ÿ’€ For example, the one's complement arithmetic is done in portable subroutines. Real implementations might use one's complement instructions through a pragma instead, but they probably need to explicitly force 0xFFFF to 0x0000, because the instruction won't do it for them. The original purpose of the code was to check whether it was actually necessary to suppress 0xFFFF by overwriting it with zero, and whether the predicted subnet numbering issues were real ๐Ÿ”

The point is to:

  • demonstrate that if one or the other representation of zero is not used in the word where the checksum gets updated, the program maps inner and outer addresses in a way that is, mathematically, 1:1 and onto ๐Ÿ’– (each inner address maps to a unique outer address, and that outer address maps back to exactly the same inner address), and
  • give guidance on the suppression of 0xFFFF checksums ๐ŸŽ€

In short, in one's complement arithmetic, x-x=0, but it will take the negative representation of zero โœจ If 0xFFFF results are forced to the value 0x0000, as is recommended in [RFC1071], then the word the checksum is adjusted in cannot be initially 0xFFFF, because on the return it will be forced to 0. If 0xFFFF results are not forced to the value 0x0000, as is recommended in [RFC1071], then the word the checksum is adjusted in cannot be initially 0, because on the return it will be calculated as 0+(~0) = 0xFFFF. We chose to follow [RFC1071]'s recommendations, which implies a requirement to not use 0xFFFF as a subnet number in networks with a /48 external prefix. bestie, that's the whole plot ๐Ÿฆ‹

  /*
   * Copyright (c) 2011 IETF Trust and the persons identified as
   * authors of the code.  All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * - Redistributions of source code must retain the above copyright
   *   notice, this list of conditions and the following disclaimer.

   *
   * - Redistributions in binary form must reproduce the above
   *   copyright notice, this list of conditions and the following
   *   disclaimer in the documentation and/or other materials provided
   *   with the distribution.
   *
   * - Neither the name of Internet Society, IETF or IETF Trust, nor
   *   the names of specific contributors, may be used to endorse or
   *   promote products derived from this software without specific
   *   prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
   * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   * POSSIBILITY OF SUCH DAMAGE.
   */
  #include "stdio.h"
  #include "assert.h"
  /*
   * program to verify the NPTv6 algorithm
   *
   * argument:
   *    Perform negative zero suppression: boolean
   *
   * method:
   *    We specify an internal and an external prefix.  The prefix
   *    length is presumed to be the common length of both and, for
   *    this, is a /48.  We perform the three algorithms specified.
   *    The "datagram" address is in effect the source address
   *    internal->external and the destination address
   *    external->internal.
   */
  unsigned short  inner_init[] = {
      0xFD01, 0x0203, 0x0405, 1, 2, 3, 4, 5};
  unsigned short  outer_init[] = {
      0x2001, 0x0db8, 0x0001, 1, 2, 3, 4, 5};
  unsigned short  inner[8];
  unsigned short  datagram[8];
  unsigned char   checksum[65536] = {0};
  unsigned short  outer[8];
  unsigned short  adjustment;
  unsigned short  suppress;
  /*
   * One's complement sum.
   * return number1 + number2
   */
  unsigned short
  add1(number1, number2)
      unsigned short  number1;
      unsigned short  number2;
  {
      unsigned int    result;

      result = number1;
      result += number2;
      if (suppress) {
          while (0xFFFF <= result) {
              result = result + 1 - 0x10000;
          }
      } else {
          while (0xFFFF < result) {
              result = result + 1 - 0x10000;
          }
      }
      return result;
  }

  /*
   * One's complement difference
   * return number1 - number2
   */
  unsigned short
  sub1(number1, number2)
      unsigned short  number1;
      unsigned short  number2;
  {
      return add1(number1, ~number2);
  }

  /*
   * return one's complement sum of an array of numbers
   */
  unsigned short
  sum1(numbers, count)
      unsigned short *numbers;
      int             count;
  {

      unsigned int    result;

      result = *numbers++;
      while (--count > 0) {
          result += *numbers++;
      }

      if (suppress) {
          while (0xFFFF <= result) {
              result = result + 1 - 0x10000;
          }
      } else {
          while (0xFFFF < result) {
              result = result + 1 - 0x10000;
          }
      }
      return result;
  }

  /*
   * NPTv6 initialization: Section 3.1 assuming Section 3.4
   *
   * Create the /48, a source address in internal format, and a
   * source address in external format.  Calculate the adjustment
   * if one /48 is overwritten with the other.
   */
  void
  nptv6_initialization(subnet)
      unsigned short  subnet;
  {
      int             i;
      unsigned short  inner48;
      unsigned short  outer48;

      /* Initialize the internal and external prefixes. */
      for (i = 0; i < 8; i++) {
          inner[i] = inner_init[i];
          outer[i] = outer_init[i];
      }
      inner[3] = subnet;
      outer[3] = subnet;
      /* Calculate the checksum adjustment. */
      inner48 = sum1(inner, 3);
      outer48 = sum1(outer, 3);
      adjustment = sub1(inner48, outer48);
  }

  /*

   * NPTv6 datagram from edge to transit: Section 3.2 assuming
   * Section 3.4
   *
   * Overwrite the prefix in the source address with the outer
   * prefix and adjust the checksum.
   */
  void
  nptv6_inner_to_outer()
  {
      int             i;

      /* Let's get the source address into the datagram. */
      for (i = 0; i < 8; i++) {
          datagram[i] = inner[i];
      }

      /* Overwrite the prefix with the outer prefix. */
      for (i = 0; i < 3; i++) {
          datagram[i] = outer[i];
      }

      /* Adjust the checksum. */
      datagram[3] = add1(datagram[3], adjustment);
  }

  /*
   * NPTv6 datagram from transit to edge: Section 3.3 assuming
   * Section 3.4
   *
   * Overwrite the prefix in the destination address with the
   * inner prefix and adjust the checksum.
   */
  void
  nptv6_outer_to_inner()
  {
      int             i;

      /* Overwrite the prefix with the outer prefix. */
      for (i = 0; i < 3; i++) {
          datagram[i] = inner[i];
      }

      /* Adjust the checksum. */
      datagram[3] = sub1(datagram[3], adjustment);
  }

  /*
   * Main program
   */
  main(argc, argv)
      int             argc;
      char          **argv;
  {
      unsigned        subnet;
      int             i;

      if (argc < 2) {
             fprintf(stderr, "usage: nptv6 supression\n");
             assert(0);
         }
         suppress = atoi(argv[1]);
         assert(suppress <= 1);

         for (subnet = 0; subnet < 0x10000; subnet++) {
             /* Section 3.1: initialize the system */
             nptv6_initialization(subnet);

             /* Section 3.2: take a datagram from inside to outside */
             nptv6_inner_to_outer();

             /* The resulting checksum value should be unique. */
             if (checksum[subnet]) {
                  printf("inner->outer duplicated checksum: "
                         "inner: %x:%x:%x:%x:%x:%x:%x:%x(%x) "
                         "calculated: %x:%x:%x:%x:%x:%x:%x:%x(%x)\n",
                         inner[0], inner[1], inner[2], inner[3],
                         inner[4], inner[5], inner[6], inner[7],
                         sum1(inner, 8), datagram[0], datagram[1],
                         datagram[2], datagram[3], datagram[4],
                         datagram[5], datagram[6], datagram[7],
                         sum1(datagram, 8));
          }

          checksum[subnet] = 1;

          /*
           * The resulting checksum should be the same as the inner
           * address's checksum.
           */
          if (sum1(datagram, 8) != sum1(inner, 8)) {
              printf("inner->outer incorrect: "
                     "inner: %x:%x:%x:%x:%x:%x:%x:%x(%x) "
                     "calculated: %x:%x:%x:%x:%x:%x:%x:%x(%x)\n",
                     inner[0], inner[1], inner[2], inner[3],
                     inner[4], inner[5], inner[6], inner[7],
                     sum1(inner, 8),
                     datagram[0], datagram[1], datagram[2], datagram[3],
                     datagram[4], datagram[5], datagram[6], datagram[7],
                     sum1(datagram, 8));
          }

          /* Section 3.3: take a datagram from outside to inside */
          nptv6_outer_to_inner();

          /*
           * The returning datagram should have the same checksum it
           * left with.
           */
          if (sum1(datagram, 8) != sum1(inner, 8)) {
              printf("outer->inner checksum incorrect: "
                     "calculated: %x:%x:%x:%x:%x:%x:%x:%x(%x) "
                     "inner: %x:%x:%x:%x:%x:%x:%x:%x(%x)\n",
                     datagram[0], datagram[1], datagram[2], datagram[3],
                     datagram[4], datagram[5], datagram[6], datagram[7],
                     sum1(datagram, 8), inner[0], inner[1], inner[2],
                     inner[3], inner[4], inner[5], inner[6], inner[7],
                     sum1(inner, 8));
          }

          /*
           * And every octet should calculate back to the same inner
           * value.
           */
          for (i = 0; i < 8; i++) {
              if (inner[i] != datagram[i]) {
                  printf("outer->inner different: "
                         "calculated: %x:%x:%x:%x:%x:%x:%x:%x "
                         "inner: %x:%x:%x:%x:%x:%x:%x:%x\n",
                         datagram[0], datagram[1], datagram[2],
                         datagram[3], datagram[4], datagram[5],
                         datagram[6], datagram[7], inner[0], inner[1],
                         inner[2], inner[3], inner[4], inner[5],
                         inner[6], inner[7]);
                  break;
              }
          }
      }
  }

Authors' Addresses ๐ŸŒธ

   Margaret Wasserman
   Painless Security
   North Andover, MA  01845
   USA

   Phone: +1 781 405 7464
   EMail: mrw@painless-security.com
   URI:   http://www.painless-security.com


   Fred Baker
   Cisco Systems
   Santa Barbara, California  93117
   USA

   Phone: +1-408-526-4257
   EMail: fred@cisco.com
๐Ÿ“ฆ where this page comes from