NAT on a stick

NAT on a stick.

I ran into this a while back, and then again the other day. Its really a puzzling way of doing NAT.

The topology:


Imagine this scenario (even though its very unlikely as far as i can see):

Our organisation has purchased an internet connection with a local provider. They are only able to provide us with 2 available IP addresses + our transit IP address.

We have several servers, and alot of clients that needs to connect to the internet.

NAT is the obvious choice. However, theres a problem. Our gateway only have 1 interface, and we are not allowed to buy anything else! Also, we cant use sub-interfaces.

(i told you it was quite unlikely ūüôā )

So, our IP addresses are:

Our public IP transit address:

Our gateway at the ISP:

Our extra assigned IP addresses:

Our internal IP addresses:

We have configured a router to act as the server, and this router has the IP address:

Beyond that, we have a loopback interface with this IP address:

For demonstration purposes, the entire internet is represented as, which is a loopback on the ISP router.

Also, i know that the choice of IP addresses would not really work in real life, but bear with me, its not important for the scenario.

Our first hat-trick is to get basic connectivity between our gateway-router (R1) and our LAN, as well as to the ISP.

Lets configure the interface in this manner:

interface FastEthernet0/0
 ip address secondary
 ip address
 ip virtual-reassembly
 duplex auto
 speed auto

Lets verify that we have connectivity:

To our server:

Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to, timeout is 2 seconds:
Success rate is 100 percent (5/5), round-trip min/avg/max = 1/18/60 ms

And to our ISP:

Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to, timeout is 2 seconds:
Success rate is 100 percent (5/5), round-trip min/avg/max = 4/73/104 ms

Everything is OK! so far.

Lets just check the routing table on R1, so you can all follow along a bit better:

R1#sh ip route | beg Gate
Gateway of last resort is to network is subnetted, 1 subnets
C is directly connected, FastEthernet0/0 is subnetted, 1 subnets
C is directly connected, Loopback0
C is directly connected, FastEthernet0/0
S* [1/0] via

Okay, everything seems fine RIB wise.

Next up is a mind-bender. Remember that in order for NAT to work, we need to designate one interface as inside, and another as outside.

This is really to create a logical flow of things. However, our main limitation is that we only have 1 interface to operate on. If we had a router with two interfaces, we could use one as inside and the other as the outside interface.

What we want to utilize in order to get this working, is how IOS process packets.

I can highly recommend that you take a look at this:

First, inbound packets to the router are first subject to policy-based routing, before any NAT’ing takes place. It is also taking place right before ordinary routing.

What we want to do, is send packets to the R1 router, these will be received by the “inside” interface, completing the first requirement. The routing decision has already been made, we need to send it to loopback0. This is done in order to “hit” an outside interface.

When the loopback interface sees the packets, it makes the routing decision, not per policy-based routing, but by ordinary routing. However, IOS routes it OUT of the loopback0

interface, back to our f0/0 interface. This completes the second requirement, going out of the interface thats configured as “outside”.

Since it doesnt match what we want to policy-base route on f0/0, it gets routed OUT of the f0/0 interface, NAT’ed as

Return answers goes through the same process. It is received by the f0/0 interface, gets policy-routed (since the outside NAT is not on the f0/0 interface) to the loopback interface, which IS the outside interface and gets translated back to our original source (LAN IP addresses).

So lets get the components configured.

One of the most important components is our policy-routing. As mentioned, we will put our policy onto the f0/0 interface, which means that packets comming into this interface will be subject to policy routing if it matches the route-map.

We want two things to match our policy-routing. Namely inside traffic, that needs to get NAT’ed in order to goto the internet, and return traffic, destined for the NAT addresses (remember they must hit the outside interface again).

This access-list should do the job:

R1(config)#access-list 110 permit ip any
R1(config)#access-list 110 permit ip any

We then need to create our route-map used for policy-based route:

R1(config)#route-map PBR
R1(config-route-map)#match ip add 110
R1(config-route-map)#set int loo0

So, everything that matches our access-list gets policy-routed to the loopback0 interface.

Lets go ahead and apply it to the interface, so we are done with it:

R1(config-route-map)#int f0/0
R1(config-if)#ip policy route-map PBR

At this point, we are done with the policy routing section. Next up is our NAT setup.

Remember that we want our f0/0 interface to be the inside interface and the loopback0 interface to be the outside interface, so lets get that out of the way:

R1(config-if)#int f0/0
R1(config-if)#ip nat inside
R1(config-if)#int loo0
R1(config-if)#ip nat outside

Alright, next up is to create a pool of IP addresses we can use for the NAT process. (I want to point out at this point that i have not gotten NAT with the 1 transit IP address working in this scenario).

ip nat pool TSTPOOL netmask

The above creates a NAT pool, which states that we want to use 2 IP addresses, namely .1 and .2.

We also need to create an access-list that specifies which internal (as Cisco calls Inside Local) IP addresses we want to perform NAT on:

R1(config)#access-list 120 permit ip any

Basically it states that all internal IP addresses will be NAT’ed when going out the outside interface.

Finally, lets put our NAT statement into place:

ip nat inside source list 120 pool TSTPOOL overload

So we want to take all IP addresses listed in access-list 120 and replace the source-address with the addresses in the TSTPOOL. We also want to perform PAT (port based NAT) to further increase our chances of getting an internet connection. (Otherwise, only 2 simultanous connections could exist).

Now, lets test this out! Lets try with a ping from our Server-1 to the internet (which is

Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to, timeout is 2 seconds:
Success rate is 100 percent (5/5), round-trip min/avg/max = 176/252/312 ms

Awesome, we have connectivity. Lets check out what the “internet” is really receiving by looking at the ISP router:

*Mar  1 10:37:41.017: IP: s= (FastEthernet0/0), d=, len 100, rcvd 4
*Mar  1 10:37:41.017: IP: tableid=0, s= (local), d= (FastEthernet0/0), routed via FIB
*Mar  1 10:37:41.021: IP: s= (local), d= (FastEthernet0/0), len 100, sending
*Mar  1 10:37:41.309: IP: tableid=0, s= (FastEthernet0/0), d= (Loopback0), routed via RIB

Again, what we would expect. The source address has been translated into our assigned IP addresses. As a final confirmation, lets check the NAT status on R1:

R1(config)#do sh ip nat trans
Pro Inside global      Inside local       Outside local      Outside global

As can be seen, we have translated the source-address of to

I want to show you the output of “debug ip policy” on R1, so you can see the logic taking place:

*Mar  1 10:42:02.557: IP: s= (FastEthernet0/0), d= (Loopback0), len 100, policy routed
*Mar  1 10:42:02.557:     ICMP type=8, code=0
*Mar  1 10:42:02.557: IP: FastEthernet0/0 to Loopback0

And later on:

*Mar  1 10:42:02.617: IP: s= (FastEthernet0/0), d= (Loopback0), len 100, policy routed
*Mar  1 10:42:02.617:     ICMP type=0, code=0
*Mar  1 10:42:02.621: IP: FastEthernet0/0 to Loopback0

The first one shows that a request from an internal host is POLICY routed to the loopback0 interface. The second one shows the reply, in which the destination is POLICY routed to the loopback0 interface.

This matches our access-list for policy based routing.

In summary, this is VERY ugly and it has some caveats. For example you cannot specify your own next-hop ip address on the loopback interface. If you had a /24 loopback interface, you could specify an ip-next hop of something else in there and IOS would try to route it through the loopback, resulting in it getting hit with the ip nat outside. Also, i have not found a way to use the transit net as the source address as you would normally use.

I wanted to show you this so you dont go “What!?” if you see it anywhere, which is most likely to be in a lab scenario, not real-life.

So please! dont ever use this ūüôā