Skip to content

Cisco IOS NAT Virtual Interface

Up until recently, I’ve had ADSL at home for some years. For the last year or so, I’ve used a Cisco 1812 as my router (the ISP-router was put into bridge-mode). A few weeks ago, when I got a 10/10Mbps fiber-connection, it suddenly became more relevant to host some services at home (why pay for web-hosting, when you can host it home, for free?). As a result of this, I stumbled upon a “problem” that annoyed me a bit; loopback-support – the ability to reach your services using your external IP, and hence applying port-forwards (this way you could use ssh externalip -p "some odd port number" regardless if you are home or not). This is quite useful if you move between different networks a lot (e.g. using a laptop – which was the case for me). This feature is known as tromboning, or hairpinning, and is something that often works on cheap routers you get from your ISP. So, why shouldn’t this work on a Cisco-device?

Why can’t you just use the normal ip nat inside and ip nat outside clauses? Well, if I’m not entirely mistaken (feel free to correct me if I’m wrong), if a packet, destined for an IP-address on a interface with ip nat outside, is received on a interface with ip nat inside, the packet is just dropped.

After a bit of intense Googling, reading page up and page down, it seemed that this feature wasn’t natively supported – at least for a while ago. There where different “hacks”, which involved PBR (Policy-based routing) using a Loopback-interface, and some other trickery (more info). After some more reading, this “hack” would only work if you have several static, and public, IP-addresses (I read somewhere that it might be possible with only one public IP-address, using VRF’s and whatnot, but this was way above my skill-level at the time). This is often not the case for most home-users, and as such, these “hacks” where a no-go for me.

I also came across NVI (NAT Virtual Interface), but Cisco’s tutorials also pointed in the direction that it was required to have more than one static, and public, IP-address. I decided to try anyways, knowing very little about the subject, and soon found out that is was quite easy.

So, let’s get to the configuring. NVI was introduced in IOS 12.3(14)T, so you’ll need this, or newer, for it to work.

The setup is quite basic:

R1(config)#interface fastEthernet 0
R1(config-if)#ip address dhcp
R1(config-if)#no shutdown
R1(config-if)#ip nat enable
R1(config-if)#interface fastEthernet 1
R1(config-if)#ip address 192.168.0.1 255.255.255.0
R1(config-if)#no shutdown
R1(config-if)#ip nat enable
R1(config-if)#exit
R1(config)#access-list 1 permit 192.168.0.0 0.0.0.255
R1(config)#ip nat source list 1 interface FastEthernet0 overload

And that’s it. To verify;

R1#show ip nat nvi translations
Pro Source global         Source local          Destin  local         Destin  global
tcp <fa0-address>:49525    192.168.0.26:49525    17.148.16.46:993      17.148.16.46:993
tcp <fa0-address>:61251    192.168.0.33:61251    173.225.132.24:443    173.225.132.24:443
tcp <fa0-address>:61252    192.168.0.33:61252    173.225.132.36:443    173.225.132.36:443
tcp <fa0-address>:61253    192.168.0.33:61253    173.225.132.11:443    173.225.132.11:443
tcp <fa0-address>:61254    192.168.0.33:61254    173.225.132.25:443    173.225.132.25:443
tcp <fa0-address>:61255    192.168.0.33:61255    173.225.132.29:443    173.225.132.29:443
 --More--

Please note that if you cannot get it to work, you can try applying the following command to all NAT-enabled interfaces (thanks to Tim for pointing this out!);

 no ip redirects

If you, like me, already had ip nat inside/outside applied before using NVI, you’d have to remove some old settings before entering the commands above. The first thing you’ll do, is to remove the ip nat inside/outside;

R1(config)#interface fastEthernet 0
R1(config-if)#no ip nat outside
R1(config-if)#interface fastEthernet 1
R1(config-if)#no ip nat inside

Then you’ll need to clear the NAT-translation table (since static NAT-entries cannot be removed if in use), and then remove old, static NAT-entries. Finally you’ll add the static NAT-entries again, but with a different syntax.

R1#clear ip nat translation *
R1#show run | i static
ip nat inside source static tcp 192.168.0.2 80 interface FastEthernet0 80
R1#conf t
R1(config)#no ip nat inside source static tcp 192.168.0.2 80 interface FastEthernet0 80
R1(config)#ip nat source static tcp 192.168.0.2 80 interface FastEthernet0 80

So, the syntax-change is basically to remove the inside/outside restriction. If you have loads of old static NAT-entries, you could copy-paste them to a text-editor, and replace ip nat with no ip nat, and then copy them into the router. Likewise, you could use the replace-function to change the syntax; replace ip nat {inside|outside} with ip nat.

Oh, as a footnote; I’m aware that this could, in some degree, be solved by using split-horizon DNS – however, this would not work if the external ports that are forwarded, differs from the internal one (e.g. if port 4321 on your external address is forwarded to port 22 on an internal address, using PAT).

Update #1: Tim pointed out that he needed to apply no ip redirects to get all of the above working. The post has been changed to reflect this. Thanks, Tim!

39 Comments

  1. havard havard

    thanks for this guide!
    I had the same problem, but now everything is working smoodly ;)

    • jocke jocke

      I’m glad you could use it.

  2. John John

    This is not working for UDP Port Forwarding

    • havard havard

      It is working for me with UDP. Using it with Plex (media center) so I can see movies from my iPad. It uses both UDP and TCP.

    • jocke jocke

      John, this should work just fine.

      ROUTER(config)#ip nat source static udp 10.10.10.10 1337 interface FastEthernet0 1337

      Then, using ‘nc’ in Linux (assuming 11.11.11.11 is the outside IP of 10.10.10.10);

      On 10.10.10.10;

      root@omg:~# nc -lup 1337

      On any machine “outside the NAT”;

      root@kek:~# nc -u 11.11.11.11 1337

      On the last host, type a few random lines, like this;

      root@kek:~# nc -u 11.11.11.11 1337
      hello
      hi
      this
      is a 
      test
      !

      And if all is working correctly, these lines should show up at the 10.10.10.10-host;

      root@omg:~# nc -lup 1337
      hello
      hi
      this
      is a
      test
      !

      (If you’re using ACL’s on the router, you obviously need to punch a hole for the port in that one as well).

      • John John

        Indeed, it works. Thanks

      • John John

        Update:
        – config applied to one 892 Router running IOS Version 15.1(2)T2 works fine [both TCP and UDP ports are forwarded]
        – same config applied to one 1921 Router running IOS Version 15.0(1r)M9 doesn’t work [only TCP ports are forwarded; for UDP incomming packets the router responds with ICMP destination unreachable – port unreachable]

        Any ideea? Is this a bug in IPO 15.0?

      • jocke jocke

        Good to hear that you got it working.

        As for the 1921, couldn’t you just try another IOS-version? I suspect the behavior you’re seeing, is just a bug.

  3. Tim Tim

    no ip redirects

    was required for me to get this working

    • jocke jocke

      I never actually thought that not having no ip redirects would lead to problems. However, it seems to be the case, after some quick Google-searches. Thanks for the heads-up (-:

      I’ve made a habit of applying the following to interfaces that I use, to avoid some unwanted scenarios, which is why I never stumbled upon the issue you mentioned, Tim;

       no ip redirects
       no ip unreachables
       no ip proxy-arp
      
  4. Richard Richard

    Can you confirm which version of IOS this was added in?

    I have a 3745 and would like to add this.

  5. Joe Joe

    Hi there,

    I have a Cisco 891 and I have been able to get NVI working correctly using your tutorial. I too am obtaining my public IP address via DHCP, however I believe that this is causing some problems for me with my setup.

    What I am finding is that when the WAN interface is set as DHCP, after a reload, the NAT NVI rules are not setup correctly, in that they are setup as traditional static NAT rules. However if I set the router to use a static (private) address on it’s WAN interface, the NAT NVI rules are setup correctly.

    Has anyone else seen this behaviour when using NAT NVI and the WAN IP address is not static and is provided via DHCP?

    Thanks.

    • Joe Joe

      It’s also worth noting that I see the same behaviour on both an 881 and 891 router.

    • jocke jocke

      Hello, Joe!

      Good to hear that the tutorial is of use.

      Regarding your issue; my bet would be that you’re hitting the same IOS-bug that’s been bothering me for some time.

      Can you confirm that the config is the same after a reload? (sh run | i ip nat source)

      Can you also confirm that the NAT-rules work if you apply them manually again after a reload? (copy-paste the ‘ip nat source’-entries)

      If so, I believe this is the same behavior I have on my 892. I did not have the issue on some 12.x-version I used ages ago (on 892 and 1812, both using the exact same config as I use today), but it’s been present on all 15.x-versions I’ve tested so far. It must be said that I haven’t tried that many 15.x-versions, as I didn’t bother to spend much time on it (since I have my router on UPS, I rarely need to reload it — and if it reloads, I can just SSH in and fix it).

      • SeanL SeanL

        I’m having the same issue. I’ve tried it on an 881, 891, and a 1841. IOS 12.4, 15.1, and 15.2. All have the exact same problem. Everything works until the router reloads. NVI NATs turn into legacy NATs and it stops working. I remove the nat config lines and paste them back in and it all starts working again… until I reload.

        Any luck?

      • jocke jocke

        Hi Sean,

        Do you actually have to _remove_ the config? (i.e. by using ‘no’ in front of them?). If so, this would imply that ‘sh run’ is different before the reload, compared to after a reload. Or am I entirely mistaken in this assumption?

        In my case, it’s enough to just re-paste the config, and everything works as expected. This does not work for you?

        I’m not trying to imply that this is a solution; just curious if we are experiencing the exact same bug, or just similar ones.

      • SeanL SeanL

        Good question. I tested this and you’re correct–I don’t need to remove it, just reenter the lines.

        Apparently the issue is related to me using DHCP from my ISP. So when the router reboots, whatever propagates the NAT table doesn’t find an outside IP address assigned yet and–BUGGED. TAC was unable to come up with another solution. It doesn’t look like it will be fixed any time soon since NVI isn’t supported in the global VRF anyway. I’ve been working through this here as well: https://supportforums.cisco.com/message/3820590.

        I’m using the following as a workaround until I can get a static address from my ISP, see this bug fixed, or come up with something else (don’t laugh):

        event manager applet DHCP_ADDRESS_CHANGE
         event syslog pattern "FastEthernet0/1 assigned DHCP address"
         action 100 syslog msg "FIXING NVI NAT"
         action 125 cli command "enable"
         action 150 cli command "config t"
         action 200 cli command "ip nat source static tcp 192.168.168.50 8123 interface FastEthernet0/1 8123"
         action 201 cli command "ip nat source static tcp 192.168.168.50 80 interface FastEthernet0/1 80"
         action 202 cli command "ip nat source static tcp 192.168.168.55 3074 interface FastEthernet0/1 3074"
         action 203 cli command "ip nat source static udp 192.168.168.55 3074 interface FastEthernet0/1 3074"
         action 204 cli command "ip nat source static udp 192.168.168.55 88 interface FastEthernet0/1 88"
         action 205 cli command "ip nat source static tcp 192.168.168.50 25565 interface FastEthernet0/1 25565"
        

        It works 100% of the time, and disgusts me every time. ;-)

        Sean

      • jocke jocke

        Haha, what a gorgeous little hack — you shouldn’t be disgusted by it, it’s actually quite awesome! (-:

      • jocke jocke

        Just confirmed that this happens on a 7204 NPE-G1 running 15.2(4)M5 as well, so it seems to be a bug in most 15.x versions.

  6. DavidS DavidS

    Wow. Exactly what I’ve spent some time trying to find. It’s amazing how Cisco has *so* many tutorials on their site and neglect this very specific use case. Thank you so much for your effort!

    • jocke jocke

      You’re very welcome. I’m glad that it’s of use for people (-:

  7. Craig Craig

    This was fantastic and worked a treat on my 1801! Very easy to understand, thanks so much!

    • jocke jocke

      Glad that I could be of help (-:

  8. Lilli Vachon Lilli Vachon

    I need your help. Please follow the post on Cisco Forums. Let me know shall I go for Classic Nat or the new style nat which is at above. Actually I am trying to connect web server. It works fine inside the Network. But it doesn’t work outside the Network. Let me know whats the problem. Thank you.

    https://supportforums.cisco.com/thread/2231684

    • jocke jocke

      If the only goal is for the server to be available externally, you can use either of the two methods. NAT NVI is easier to set up (in my opinion), and you get the added benefit of loopback/hairpinning/tromboning support, but in your scenario either works just fine.

  9. Thomas Panicker Thomas Panicker

    Thanks for posting this. I was able to resolve one similar issue.

    Kudos for sharing the knowledge…. :)

  10. Francesc Francesc

    Great stuff!! Thank you very much for sharing this.

  11. Thomas Panicker Thomas Panicker

    One more thing, I was able to do PAT with internal one port (3389) and external another port (2000).

  12. Maxim Maxim

    Excellent post, I?ve spent a day trying to find a way to do inside-inside NAT translations.

    Thanks a lot!

    • jocke jocke

      You’re welcome. Glad that it was helpful (-:

  13. Dan Dan

    Thanks for taking the time to write this up.

    Unfortunately I can’t get it to work, can anyone provide some pointers?

    I’m having to use a dialer to handle PPPOE which complicates it a little.

    Cheers

    !
    ip cef
    ip dhcp use vrf connected
    no ip dhcp conflict logging
    ip dhcp excluded-address 192.168.20.1 192.168.20.100
    !
    ip dhcp pool DynamicPool
    network 192.168.20.0 255.255.255.0
    dns-server 8.8.8.8 4.4.4.4 208.67.222.222
    default-router 192.168.20.1
    lease 0 0 15
    !
    voice-card 0
    no dspfarm
    !
    !
    interface GigabitEthernet0/0
    no ip address
    no ip redirects
    duplex auto
    speed auto
    pppoe enable group global
    pppoe-client dial-pool-number 1
    no mop enabled
    !
    interface GigabitEthernet0/1
    ip address dhcp
    no ip redirects
    ip virtual-reassembly
    duplex auto
    speed auto
    no mop enabled
    !
    interface FastEthernet0/1/0
    !
    interface FastEthernet0/1/1
    !
    interface FastEthernet0/1/2
    !
    interface FastEthernet0/1/3
    !
    interface Serial0/0/0
    no ip address
    shutdown
    clock rate 2000000
    !
    interface GigabitEthernet1/0
    ip address 192.168.20.1 255.255.255.0
    no ip redirects
    ip nat enable
    ip virtual-reassembly
    !
    interface Vlan1
    no ip address
    !
    interface Dialer1
    mtu 1480
    ip address negotiated
    no ip redirects
    ip virtual-reassembly
    encapsulation ppp
    dialer pool 1
    ppp pap sent-username ***** password 0 ****
    !
    interface Group-Async0
    physical-layer async
    no ip address
    encapsulation slip
    no group-range
    !
    ip forward-protocol nd
    ip route 0.0.0.0 0.0.0.0 Dialer1 10.20.0.1
    !
    no ip http server
    no ip http secure-server
    ip nat source list 1 interface Dialer1 overload
    !
    access-list 1 permit 192.168.20.0 0.0.0.255
    dialer-list 1 protocol ip permit
    !

    #show ip nat nvi translations
    Pro Source global Source local Destin local Destin global
    udp 212.250.84.221:68 192.168.20.10:68 192.168.20.255:67 192.168.20.255:67
    udp 212.250.84.221:137 192.168.20.10:137 192.168.20.255:137 192.168.20.255:137
    udp 212.250.84.221:138 192.168.20.10:138 192.168.20.255:138 192.168.20.255:138

    • jocke jocke

      Seems like you’re missing ‘ip nat enable’ on the dialer interface?

    • jocke jocke

      Haha, nice write-up. Glad you got it working, and I agree; it should be more straightforward to do hairpinning on IOS-devices.

Leave a Reply

Your email address will not be published. Required fields are marked *