NAT and the Failure of Source Routing

Paul Francis, in the conclusion of his 1994 Ph.D. thesis, traces the evolution of the IPv4 address scheme. After quoting a June 1978 Clark/Cohen paper (IEN 46), Francis notes:

    Well, something happened here. An argument was put forth that 32 bits is enough because the address does not have to do routing – the source route can handle the rest. Clearly it was recognized that a variable length something was needed, but the source route was deemed sufficient for that, and the 32-bit address won out in the end. So, perhaps what killed IP is not that the address is too short (though probably it is), but that the ability for DNS to hand a host a source route (which it could then put in the header so that the right thing could happen in the network) was not created.

    (p. 177)

Not only did the failure to fully implement source routing (in DNS) make it impossible to address into a private network, it also created the situation where NAT had to be implemented as it was.

Consider the following network:

          /----------X-Y------------
         /          /   \\           \\
        /          /     \\   public  \\
       / 10.0.0.0 /       \\    net    \\
      /          /         \\           \\
     H1---------/           \\-----------H2

H1 is on a private network. H2 is a server of some kind on the public network. The two networks are interconnected by a router with address X on the private network and address Y on the public net.

Can H1 initiate a working TCP session to H2 without NAT tables on the router? The answer is yes! H1 addresses its packet as follows. Address X is the IP Destination Address. A Loose Source and Record Route (LSRR) option is also used with a single address – H2’s. What happens?

Well, the packet routes first to X on the private network, then the LSRR is processed. RFC 791:

    If the address in destination address field has been reached and the pointer is not greater than the length, the next address in the source route replaces the address in the destination address field, and the recorded route address replaces the source address just used, and pointer is increased by four.

    The recorded route address is the internet module’s own internet address as known in the environment into which this datagram is being forwarded.

So H2’s address is moved into the destination address field. Yet note carefully what else happens. The “recorded route address replaces the source address”, and the “recorded route address is the… internet address as known in the environment into which this datagram is being forwarded“. So address Y is placed into the LSRR option!

So H2 receives a packet addressed to it (of course), with H1’s private IP address as the source address and an LSRR option listing the address Y. This is enough information to construct a return packet addressed to Y with H1 listed in an LSRR option. Now, can H1 count on H2 to do this? According to RFC 1122 (section 4.2.3.8) it can:

    When a TCP connection is OPENed passively and a packet arrives with a completed IP Source Route option (containing a return route), TCP MUST save the return route and use it for all segments sent on this connection.

So far, it certainly seems like we don’t need NAT! What’s the problem, then? Well, consider what H1’s routing table has to look like:

        Destination                  Action
        -----------                  ------
        H1's local subnet            direct delivery
        10.0.0.0/8                   local subnet's router
        default                      LSRR via X

It’s the default route that’s the problem. As far I know, there is not a single operating system today that can specify a loose source route as a target in a routing table entry. And even if the operating system supported it, how would such an entry be configured? Neither DHCP nor PPP can deliver such a route, and of course no routing protocol can communicate such a thing. Not to mention the simple fact that source routing is so heavily filtered that it is essentially unusable in the Internet.

So, not only was IP “killed” by the failure of DNS to hand out a source route (which would have let H2 connect to H1), but also by the failure to specify a source route in a routing table entry (to let H1 connect to H2).

One Response to “NAT and the Failure of Source Routing”

  1. cosine says:

    It seems that setting a source route on a system-wide basis has been requested before… and shot down before:

      Source routing is supported but what it sounds like is that you want to set up a source routing table in the kernel to source route packets even if the app has not set the source route option on the socket. This would be a bad thing. Even if you could get it to work, what would you do if the application DID set the source route option. This has always been left up to the application to enable and specify on a socket by socket basis.

    My answer?

    You prepend any source route listed in the kernel routing table. Assuming the app has set a source route option, you still have to route to the first destination on the list. If that destination has a source route listed in the routing table, then you prepend it. You send the packet with a source route that starts with the one from the routing table and ends with the one from the application. This takes care of the case where the app lists an initial destination that requires additional source routing.

    Incidentally, this also takes care of the case where you’re connecting to a remote host on a remote private network, and DNS has (somehow) given a loose source route via the remote host’s gateway. The application, of course, requests the source route provided by DNS. Since the initial destination (the remote gateway’s public address) matches the default route, the local gateway’s private address is prepended to the source route. Thus we use a source route that lists first the local gateway’s private address, then the remote gateway’s public address, and finally the remote host’s private address. By the time the packet is delivered, the recorded route shows the local gateway’s public address and the remote gateway’s private address – exactly what the remote host needs to answer the packet! And since the initial destination on the reply will be the remote gateway’s private address, which matches not the remote host’s default entry, but something like a 10.0.0.0/8 entry, no additional source route will be prepended to the reply, again, exactly the correct behavior!

    What happens if one of the intermediate addresses requires source routing? I don’t know. But I think, six years after that post I referenced, I can finally answer the author’s basic question.

Leave a Reply for cosine