RFC 1631

The IP Network Address Translator (NAT)

๐Ÿ“… published May 1994, from ietf

RFC 1631: The IP Network Address Translator (NAT) ๐ŸŽ€

okay bestie, come sit next to me ๐Ÿงš this is the RFC that gave us NAT, and it's giving early-90s internet problem-solving ๐Ÿ’… here's the title block tea:

  • Working group: Network Working Group
  • RFC number: 1631
  • Authors: K. Egevang (Cray Communications) and P. Francis (NTT)
  • Category: Informational
  • Date: May 1994
  • Obsoletes / Updates: nothing listed in the title block ๐Ÿ™ˆ

Status of this Memo โœจ

okay so first, the legal-ish stuff ๐Ÿ“œ this memo is just providing information for the Internet community ๐ŸŒˆ. It does not specify an Internet standard of any kind, so it's not the official rulebook ๐Ÿ™…โ€โ™€๏ธ. And distribution is unlimited, so share away ๐Ÿ’–!

Abstract ๐Ÿ’œ

so the two biggest problems the IP Internet is dealing with are IP address depletion ๐Ÿ˜ญ and scaling in routing ๐Ÿ’€. both have fixes being cooked up ๐Ÿณ. the short-term fix is CIDR (Classless InterDomain Routing), and the long-term fixes are a bunch of proposals for new internet protocols with bigger addresses ๐ŸŒŸ.

but here's the thing: CIDR might not be enough to keep the IP Internet going until the long-term stuff is ready ๐Ÿ˜ฌ. so this memo proposes another short-term fix, address reuse โ™ป๏ธ, which can either complement CIDR or make it unnecessary (main character energy ๐Ÿ‘‘). the way it works is you put Network Address Translators (NAT) at the borders of stub domains. each NAT box has a table of pairs: local IP addresses and globally unique addresses ๐Ÿ—‚๏ธ. the IP addresses inside the stub domain are not globally unique. they get reused in other domains, which solves address depletion ๐ŸŽ‰. the globally unique addresses get handed out using the current CIDR allocation schemes, and CIDR takes care of the scaling problem ๐Ÿง . the biggest perk of NAT is that you can install it without changing routers or hosts ๐Ÿซถ. this memo has a preliminary design for NAT and talks through its pros and cons ๐Ÿ“.

Acknowledgments ๐Ÿซถ

this memo is based on a paper by Paul Francis (formerly Tsuchiya) and Tony Eng, published in Computer Communication Review in January 1993 ๐Ÿ“š. Paul got the concept of address reuse from Van Jacobson ๐Ÿ™Œ.

Kjeld Borch Egevang edited the paper to make this memo, and he introduced adjustment of sequence-numbers for FTP ๐Ÿง. big thanks to Jacob Michael Christensen for his comments on the idea and text ๐Ÿ’Œ (we thought for a long time that we were the only ones who had had the idea ๐Ÿ˜ญ relatable).

1. Introduction ๐ŸŒธ

the two big problems from the abstract are the headline here too ๐Ÿ“ฐ: IP address depletion and routing scaling. the short-term fix is CIDR (Classless InterDomain Routing) [2] ๐Ÿ’…, and the long-term fixes are new internet protocols with larger addresses ๐Ÿš€.

until the long-term stuff is ready, address reuse is an easy way to keep the demand for IP addresses down ๐Ÿ™Œ. the trick is that only a tiny percentage of hosts in a stub domain are talking outside the domain at any given time ๐Ÿค. (a stub domain is a domain, like a corporate network, that only handles traffic originated by or destined to hosts in that domain ๐Ÿข.) honestly, lots of hosts (if not most) never talk outside their stub domain ๐Ÿ™ˆ. so only a subset of the IP addresses inside a stub domain need be translated into globally unique IP addresses when outside communication is required โœจ.

the downside is that this takes away the end-to-end meaning of an IP address ๐Ÿ˜ฌ, and it makes up for that with more state in the network ๐Ÿงพ. there are various work-arounds that cut down on the potential pitfalls ๐Ÿ› ๏ธ. and ngl, connection-oriented protocols are basically doing address reuse at every hop ๐Ÿคฏ.

the huge perk is that it can be installed incrementally, without changes to either hosts or routers ๐ŸŽ‰. (a few unusual applications may require changes, fr.) because of that, this solution can be implemented and experimented with quickly โšก. if nothing else, it can provide temporary relief while other, more complex and far-reaching solutions get worked out ๐Ÿซ .

2. Overview of NAT ๐Ÿฆ‹

the design in this memo is called NAT, for Network Address Translator ๐Ÿ’–. NAT is a router function that can be configured the way figure 1 shows. only the stub border router requires modifications ๐Ÿ› ๏ธ.

NAT's basic operation goes like this. the addresses inside a stub domain can be reused by any other stub domain ๐Ÿ”. for example, a single Class A address could be used by many stub domains ๐Ÿ˜๏ธ. NAT gets installed at each exit point between a stub domain and the backbone ๐Ÿšช. if there's more than one exit point, it's super important that every NAT has the same translation table ๐Ÿ—๏ธ.

        \ | /                 .                                /
   +---------------+  WAN     .           +-----------------+/
   |Regional Router|----------------------|Stub Router w/NAT|---
   +---------------+          .           +-----------------+\
                              .                      |         \
                              .                      |  LAN
                              .               ---------------
                        Stub border

                      Figure 1: NAT Configuration

for instance, in the example of figure 2, both stubs A and B internally use class A address 10.0.0.0. Stub A's NAT is assigned the class C address 198.76.29.0, and Stub B's NAT is assigned the class C address 198.76.28.0. the class C addresses are globally unique, so no other NAT boxes can use them ๐Ÿ”’.

                                       \ | /
                                     +---------------+
                                     |Regional Router|
                                     +---------------+
                                   WAN |           | WAN
                                       |           |
                   Stub A .............|....   ....|............ Stub B
                                       |           |
                     {s=198.76.29.7,^  |           |  v{s=198.76.29.7,
                      d=198.76.28.4}^  |           |  v d=198.76.28.4}
                       +-----------------+       +-----------------+
                       |Stub Router w/NAT|       |Stub Router w/NAT|
                       +-----------------+       +-----------------+
                             |                         |
                             |  LAN               LAN  |
                       -------------             -------------
                                 |                 |
               {s=10.33.96.5, ^  |                 |  v{s=198.76.29.7,
                d=198.76.28.4}^ +--+             +--+ v d=10.81.13.22}
                                |--|             |--|
                               /____\           /____\
                             10.33.96.5       10.81.13.22

                     Figure 2: Basic NAT Operation

so when stub A host 10.33.96.5 wants to send a packet to stub B host 10.81.13.22 ๐Ÿ“ฆ, it uses the globally unique address 198.76.28.4 as the destination and sends the packet to its primary router ๐Ÿ“ฎ. the stub router has a static route for net 198.76.0.0, so the packet gets forwarded onto the WAN-link ๐Ÿ›ฃ๏ธ. but wait, NAT swaps the source address 10.33.96.5 in the IP header for the globally unique 198.76.29.7 before the packet gets forwarded ๐Ÿ”„. return-path IP packets go through similar address translations too ๐Ÿ’ซ.

notice that this needs no changes to hosts or routers ๐Ÿ™Œ. for instance, as far as the stub A host is concerned, 198.76.28.4 is just the address of the host in stub B ๐Ÿ‘€. the address translations are totally transparent ๐Ÿซฅ.

of course, this is just a simple example, and there are loads of issues to explore ๐Ÿ”. next up, we look at various aspects of NAT ๐Ÿ‘€.

3. Various Aspects of NAT โœจ

3.1 Address Spaces ๐Ÿฆ‹

Partitioning of Reusable and Non-reusable Addresses ๐Ÿงฉ

for NAT to work properly, the IP address space has to be split into two parts: the reusable addresses used inside stub domains, and the globally unique addresses ๐Ÿช“. we call the reusable ones local addresses and the globally unique ones global addresses. any given address must either be a local address or a global address, and there is no overlap ๐Ÿšซ.

the problem with overlap goes like this: say a host in stub A wants to send packets to a host in stub B, but stub B's local addresses overlap with stub A's local addresses ๐Ÿ˜ต. then the routers in stub A wouldn't be able to distinguish stub B's global address from their own local addresses ๐Ÿคฏ.

Initial Assignment of Local and Global Addresses ๐ŸŽ€

a single Class A address should be allocated for local networks (see RFC 1597 [3]) ๐Ÿ“ฎ. that address could then be used for internets with no connection to the Internet ๐Ÿ๏ธ. NAT then gives you an easy way to turn an experimental network into a "real" network by translating the experimental addresses into globally unique Internet addresses ๐Ÿช„.

existing stubs that have unique addresses assigned internally, but are running out of them, can switch addresses subnet by subnet over to local addresses ๐Ÿ”. the freed-up addresses can then be used by NAT for external communications ๐ŸŒ.

3.2 Routing Across NAT ๐Ÿ›ฃ๏ธ

the router running NAT should never advertise the local networks to the backbone ๐Ÿšซ๐Ÿ“ก. only the networks with global addresses may be known outside the stub ๐ŸŒ. however, global information that NAT receives from the stub border router can be advertised inside the stub the usual way ๐Ÿ“ข.

Private Networks that Span Backbones ๐ŸŒ

in lots of cases, a private network (like a corporate network) is spread across different locations and uses a public backbone to talk between those locations ๐Ÿข๐ŸŒ. in that situation, address translation isn't desirable ๐Ÿ™…โ€โ™€๏ธ. a lot of hosts might want to talk across the backbone, which would need big address tables ๐Ÿ“š, and there would be more applications that depend on configured addresses instead of going to a name server ๐Ÿงพ. we call this kind of private network a backbone-partitioned stub ๐Ÿงฉ.

backbone-partitioned stubs should behave as though they were a non-partitioned stub ๐Ÿงธ. that means the routers in all partitions should maintain routes to the local address spaces of every partition ๐Ÿ—บ๏ธ. of course, the (public) backbones don't maintain routes to any local addresses ๐Ÿ™ƒ. so the border routers must tunnel through the backbones using encapsulation ๐Ÿš‡. to do that, each NAT box sets aside one global address for tunneling ๐Ÿ“ฆ. when NAT box x in stub partition X wants to deliver a packet to stub partition Y, it encapsulates the packet in an IP header whose destination address is the global address of NAT box y that's been reserved for encapsulation ๐ŸŽ. when NAT box y receives a packet with that destination address, it decapsulates the IP header and routes the packet internally ๐Ÿ’–.

3.3 Header Manipulations

okay so NAT doesn't just swap out the IP address and call it a day ๐Ÿ’…. It also has to fix the IP checksum AND the TCP checksum ๐Ÿ˜ญ. And bestie, TCP's checksum also covers a pseudo header that includes the source and destination addresses, so everything is connected ๐Ÿ•ธ๏ธ. NAT must also look out for ICMP and FTP and fix every spot where an IP address shows up. There are undoubtedly other places that need changes too ๐Ÿ™ˆ. Hopefully most of them get discovered during experimentation with NAT.

The checksum fixes for IP and TCP are actually simple and efficient โœจ. Both use a one's complement sum, so you only need the arithmetic difference between the before-translation and after-translation addresses, and then you add that to the checksum. The only tricky part is figuring out whether the addition wrapped around (in either the positive or negative direction) ๐ŸŒ€. If it did, you have to add or subtract 1 to keep the one's complement math correct. Here's the sample C code for it ๐ŸŽ€:

void checksumadjust(unsigned char *chksum, unsigned char *optr,
int olen, unsigned char *nptr, int nlen)
/* assuming: unsigned char is 8 bits, long is 32 bits.
  - chksum points to the chksum in the packet
  - optr points to the old data in the packet
  - nptr points to the new data in the packet
*/
{
  long x, old, new;
  x=chksum[0]*256+chksum[1];
  x=~x;
  while (olen) {
    if (olen==1) {
      old=optr[0]*256+optr[1];
      x-=old & 0xff00;
      if (x<=0) { x--; x&=0xffff; }
      break;
    }
    else {
      old=optr[0]*256+optr[1]; optr+=2;
      x-=old & 0xffff;
      if (x<=0) { x--; x&=0xffff; }
      olen-=2;
    }
  }
  while (nlen) {
    if (nlen==1) {
      new=nptr[0]*256+nptr[1];
      x+=new & 0xff00;
      if (x & 0x10000) { x++; x&=0xffff; }
      break;
    }
    else {
      new=nptr[0]*256+nptr[1]; nptr+=2;
      x+=new & 0xffff;
      if (x & 0x10000) { x++; x&=0xffff; }
      nlen-=2;
    }
  }
  x=~x;
  chksum[0]=x/256; chksum[1]=x & 0xff;
}

Now FTP, which is a whole mood ๐Ÿ˜ญ. The arguments to the File Transfer Protocol (FTP) PORT command include an IP address, and it's written in ASCII (yes, really!) ๐Ÿ™ƒ. If that IP address is local to the stub domain, NAT has to substitute it. Because it's ASCII, the packet size can change. For example, 10.18.177.42 is 12 ASCII characters, but 193.45.228.137 is 14 ASCII characters ๐Ÿ”ข. If the new size matches the old one, only the TCP checksum needs adjusting again. If the new size is smaller, ASCII zeroes may be inserted, but that's not guaranteed to work ๐Ÿ’€. If the new size is larger, TCP sequence numbers have to change too.

NAT also keeps a special table to fix the TCP sequence and acknowledge numbers for packets with source port FTP or destination port FTP ๐Ÿงš. Each table entry should have the source, destination, source port, destination port, initial sequence number, delta for sequence numbers, and a timestamp. New entries only get created when FTP PORT commands are seen. The initial sequence numbers are how NAT figures out whether a packet's sequence number is before or after the last FTP PORT command (and delta may be increased for every FTP PORT command) ๐Ÿ“ˆ. Sequence numbers get incremented and acknowledge numbers get decremented. If the FIN bit is set in one of the packets, the entry may be deleted soon after (1 minute should be safe) ๐Ÿงน. Entries that haven't been used for, e.g., 24 hours should be safe to delete too.

The sequence number adjustment has to be coded carefully so it doesn't hurt TCP performance in general ๐ŸŽ๏ธ. And of course, if the FTP session is encrypted, the PORT command will fail ๐Ÿ”’.

Now ICMP ๐Ÿ™ƒ. If an ICMP message passes through NAT, it may need two address modifications and three checksum modifications. Why? Because most ICMP messages contain part of the original IP packet in the body ๐Ÿ“ฆ. So for NAT to be completely transparent to the host, the IP address of the IP header embedded in the ICMP data must be modified, the checksum field of that same embedded IP header must be modified to match, and the ICMP header checksum must be modified to reflect those changes in the ICMP body. On top of that, the normal IP header also needs to be modified, as already described.

It's not totally clear whether the IP header inside the ICMP body really needs to be modified ๐Ÿค”. That depends on whether any host code actually looks at that embedded IP header. In fact, it might be useful to provide the exact header seen by the router or host that issued the ICMP message, to help with debugging ๐Ÿ”. Either way, no modifications are needed for Echo and Timestamp messages, and NAT should never need to handle a Redirect message.

SNMP messages could be modified, but it's even more dubious than ICMP that it will be necessary ๐Ÿคท.


Applications with IP-address Content

Any application that carries (and uses) an IP address inside the application itself won't work through NAT unless NAT knows about that application and does the right translation ๐Ÿ™…. It's not possible, or even necessarily desirable, for NAT to know about all of these applications. And if encryption is used, it's impossible for NAT to make the translation ๐Ÿ”.

These systems might be able to avoid NAT if the hosts they run on are assigned global addresses ๐ŸŒ. Whether that works depends on the intra-domain routing algorithm and the internal topology, because the global address has to be advertised in the intra-domain routing algorithm. With a low-feature routing algorithm like RIP, the host might need its own class C address space, which has to be advertised internally AND externally (thus hurting global scaling) ๐Ÿ“‰. With a high-feature routing algorithm like OSPF, the host address can be passed around individually and can come from the NAT table ๐Ÿฆ‹.


Privacy, Security, and Debugging Considerations

Unfortunately, NAT reduces the number of options for providing security ๐Ÿ˜ค. With NAT, nothing that carries an IP address, or information derived from an IP address (like the TCP-header checksum), can be encrypted. Most application-level encryption should be ok, but this still prevents encryption of the TCP header ๐Ÿ”“.

On the other hand, NAT can be seen as providing a kind of privacy mechanism ๐Ÿ•ถ๏ธ. That's because machines on the backbone can't monitor which hosts are sending and receiving traffic (assuming, of course, that the application data is encrypted).

The same thing that boosts privacy can also make debugging problems (including security violations) harder ๐Ÿšจ. If a host is abusing the Internet in some way (like trying to attack another machine, or sending huge amounts of junk mail or something), it's much harder to pinpoint the source of the trouble, because the host's IP address is hidden.

4. Conclusions โœจ

NAT may be a good short-term solution to the address depletion and scaling problems ๐ŸŒธ. That's because it requires very few changes and can be installed incrementally. But NAT has several negative characteristics that make it inappropriate as a long-term solution, and may even make it inappropriate as a short-term solution ๐Ÿ˜ฌ. Only implementation and experimentation will determine whether it's appropriate.

The negative characteristics are:

  1. It requires a sparse end-to-end traffic matrix. Otherwise, the NAT tables will be large, which gives lower performance. The expectation is that end-to-end traffic matrices really are sparse, but experience with NAT will show whether they are. Either way, future applications may need a rich traffic matrix (for instance, distributed resource discovery), which makes long-term use of NAT unattractive ๐Ÿ“‰.
  2. It increases the probability of mis-addressing.
  3. It breaks certain applications (or at least makes them more difficult to run).
  4. It hides the identity of hosts. This has the benefit of privacy, but it's generally a negative effect ๐Ÿซ .
  5. Problems with SNMP, DNS, ... you name it ๐Ÿ’€.

Current Implementations

Paul and Tony implemented an experimental prototype of NAT on public domain KA9Q TCP/IP software [1] ๐Ÿ› ๏ธ. This implementation manipulates addresses and IP checksums.

Kjeld implemented NAT in a Cray Communications IP-router ๐Ÿ–ฅ๏ธ. It was tested with Telnet and FTP. This implementation manipulates addresses, IP checksums, TCP sequence/acknowledge numbers, and FTP PORT commands.

The prototypes have demonstrated that IP addresses can be translated transparently to hosts, within the limitations described in this paper ๐Ÿ‘‘.


REFERENCES โœจ

[1] Karn, P., "KA9Q", anonymous FTP from ucsd.edu (hamradio/packet/ka9q/docs).

[2] Fuller, V., Li, T., and J. Yu, "Classless Inter-Domain Routing (CIDR) an Address Assignment and Aggregation Strategy", RFC 1519, BARRNet, cisco, Merit, OARnet, September 1993.

[3] Rekhter, Y., Moskowitz, B., Karrenberg, D., and G. de Groot, "Address Allocation for Private Internets", RFC 1597, T.J. Watson Research Center, IBM Corp., Chrysler Corp., RIPE NCC, March 1994.


Security Considerations ๐Ÿ”

Security issues are not discussed in this memo. ๐Ÿšจ Read that again, bestie: the memo itself doesn't cover them, so don't assume anything is secured just because this document says nothing about it ๐Ÿ’œ.

Authors' Addresses ๐Ÿฆ‹

Kjeld Borch Egevang
Cray Communications
Smedeholm 12-14
DK-2730 Herlev
Denmark

Phone: +45 44 53 01 00
EMail: kbe@craycom.dk
Paul Francis
NTT Software Lab
3-9-11 Midori-cho Musashino-shi
Tokyo 180 Japan

Phone: +81-422-59-3843
Fax +81-422-59-3765
EMail: francis@cactus.ntt.jp
๐Ÿ“ฆ where this page comes from