This is a Canonical Question about Hairpin NAT (Loopback NAT).
The generic form of this question is:
We have a network with clients, a server, and a NAT Router. There is port forwarding on the router to the server so some of it's services are available externally. We have DNS pointing to the external IP. Local network clients fail to connect, but external work.
- Why does this fail?
- How can I create a unified naming scheme (DNS names which work both locally and externally)?
This question has answeres merged from multiple other questions. They originally referenced FreeBSD, D-Link, Microtik, and other equipment. They're all trying to solve the same problem however.
Since this has been elevated to be the canonical question on hairpin NAT, I thought it should probably have an answer that was more generally-valid than the currently-accepted one, which (though excellent) relates specifically to FreeBSD.
This question applies to services provided by servers on RFC1918-addressed IPv4 networks, which are made available to external users by introducing destination NAT (DNAT) at the gateway. Internal users then try to access those services via the external address. Their packet goes out from the client to the gateway device, which rewrites the destination address and immediately injects it back into the internal network. It is this sharp about-turn the packet makes at the gateway that gives rise to the name hairpin NAT, by analogy with the hairpin turn.
The problem arises when the gateway device rewrites the destination address, but not the source address. The server then receives a packet with an internal destination address (its own), and an internal source address (the client's); it knows it can reply directly to such an address, so it does so. Since that reply is direct, it doesn't go via the gateway, which therefore never gets a chance to balance the effect of inbound destination NAT on the initial packet by rewriting the source address of the return packet.
The client thus sends a packet to an external IP address, but gets a reply from an internal IP address. It has no idea that the two packets are part of the same conversation, so no conversation happens.
The solution is that for packets which require such destination NAT, and which reach the gateway from the internal network, to also perform source NAT (SNAT) on the inbound packet, usually by rewriting the source address to be that of the gateway. The server then thinks the client is the gateway itself, and replies directly to it. That in turn gives the gateway a chance to balance the effects of both DNAT and SNAT on the inbound packet by rewriting both source and destination addresses on the return packet.
The client thinks it's talking to an external server. The server thinks it's talking to the gateway device. All parties are happy. A diagram may be helpful at this point:
Some consumer gateway devices are bright enough to recognise those packets for which the second NAT step is needed, and those will probably work out-of-the-box in a hairpin NAT scenario. Others aren't, and so won't, and it is unlikely that they can be made to work. A discussion of which consumer-grade devices are which is off-topic for Server Fault.
Proper networking devices can generally be told to work, but - because they are not in the business of second-guessing their admins - they do have to be told do so. Linux uses
iptables
to do the DNAT thus:which will enable simple DNAT for the HTTP port, to an internal server on
192.168.3.11
. But to enable hairpin NAT, one would also need a rule such as:Note that such rules need to be in the right place in the relevant chains in order to work properly, and depending on settings in the
filter
chain, additional rules may be needed to permit the NATted traffic to flow. All such discussions are outside the scope of this answer.But as others have said, properly-enabling hairpin NAT isn't the best way to handle the problem. The best is split-horizon DNS, where your organisation serves different answers for the original lookup depending on where the requesting client is, either by having different physical servers for internal vs. external users, or by configuring the DNS server to respond differently according to the address of the requesting client.
What you're looking for is called "hairpin NAT". Requests from the internal interface for an IP address assigned to the external interface should be NAT'ted as though they came in from the external-side interface.
I don't have any FreeBSD familiarity at all, but reading the "pf" manual for OpenBSD (http://www.openbsd.org/faq/pf/rdr.html) the proposed solutions of split-horizon DNS, using a DMZ network, or TCP proxying lead me to believe that "pf" doesn't support hairpin NAT.
I'd look at going the route of split-horizon DNS and not using IP addresses in URLs internally but, instead, using names.
The problem here is, that your router does not NAT your internal client's address. Thus, the TCP handshake fails.
Let's assume following IPs
Here is what is happening:
Why not use split horizon dns instead of hardcoding IP addresses everywhere? You would have ext.yourdomain pointing to 217.x.x.x on the outside, and then 192.x.x.x on the inside.
Ill answer to my questions just to broaden horizons for those with similar problems.
I am contacted my ISP and asked them to try solving my problems. What they had offered me is another public IP address just for server, Now I have local traffic on the WAN side of FreeBSD and We made specific pipes for faster throughput fol local traffic to public IP of Server
If it's an original D-Link router (i.e., not Rev. D / Firmware Version 1.00VG from Virgin Media), you should be able to adjust the settings to work around this. (However, I agree with the previous poster's suggestion of DD-WRT for many other reasons!)
This screenshot is from the Rev. C model; yours may be slightly different.
Recently answered a similar question: Cisco static NAT not working on LAN side and just realized that this is a Canonical Question. So permit me to summarize the solution here.
First of all: forget about NAT (if you can) - the question is not at all about configuring NAT. It's about accessing a server placed behind NAT from both the Internet and the LAN. Employing two DNS zones is a viable alternative, but not always the solution. But the solution does exist and is incredibly simple (although not perfect, probably):
(1) on the server: add the public IP address as a secondary IP address on the server's network interface with the 255.255.255.255 mask (web service or whatever you want on the server should listen on this IP address too); all modern operating systems will permit you to do this (or a loopback interface with the public IP address assigned to it can be used instead of adding a secondary IP to the primary interface).
(2) on the LAN hosts: add a host route for the public IP address, for example, for Windows hosts use the following command: route -p add 203.0.113.130 mask 255.255.255.255 192.168.1.11 (you can also use DHCP "static route" option to distribute the route). Or, if there is (a) L3 switch(es)/router(s) in between the clients and the Internet-facing router, configure that host route on this(these) intermediate switch(es)/router(s), not on the clients.
For those concerning with the TCP three-way handshake: it will work OK in the proposed configuration.
Please provide feedback (at least, vote).
From a technical point of view the best solution to this problem is to enable IPv6 on your network. When IPv6 is enabled you need to create an AAAA record for your domain. Keep the existing A record pointing to the external IPv4 of the router. Create an AAAA record pointing to the IPv6 address of the server.
IPv6 has enough addresses to avoid NAT, so you won't need hairpin NAT for IPv6. And once you have enabled IPv6 and created AAAA records any client supporting RFC 8305 will try IPv6 before IPv4. This means you don't need hairpin NAT for IPv4 either, because the clients won't be using it.
You will still need your existing IPv4 NAT for outgoing connections and port forwarding for incoming connections until most of the world has enabled IPv6 as well.
It's faster as well.
Using IPv6 will give you a better performance than hairpin NAT.
With hairpin NAT your client will send a packet through a switch to the router, the router will then perform two rounds of translation and finally send the packet through the switch to the server. Packets from the server to the client will go through that entire path in reverse.
With IPv6 you avoid NAT, instead packets are sent directly through the switch between client and server. This means on a roundtrip you reduce the number of passes through the switch from 4 to 2, and you avoid 2 trips through the router and the 4 translations the router would have performed. This translates to better performance.
This is true even if you use a switch built into the same box as the router.
What if the ISP doesn't have IPv6?
If you are using an ISP which doesn't support IPv6 I will question whether you should be hosting servers on that network. These are my suggestions on what to do if the ISP does not currently support IPv6.
First tell the ISP that you need IPv6. And maybe remind them that the IPv6 protocol has been around for 20 years so they are long overdue in supporting it. If that's not enough for the ISP to take you seriously start looking for other ISPs.
If you find an ISP with IPv6 support you can run with both ISPs for a transition period. On the router connected to the new ISP you can disable IPv4 on the LAN side and then connect the LAN sides of both routers to the same switch. IPv4 and IPv6 are two independent protocols and as such it is no problem at all if those connections go through different routers. As a side benefit it gives you some amount of redundancy if one of the connections has an outage.
If you cannot find an ISP with IPv6 support you should consider moving your server to a hosting facility. With a server in a hosting facility you are less dependent on geographical location and for that reason there is more competition between providers which will help ensuring there is one that satisfies your needs.
Moving the server to a hosting facility is not going to give your clients IPv6, but moving the server means you no longer need hairpin NAT to reach it.
What you should not do
Don't turn on IPv6 and create AAAA records if you don't have a way to route the IPv6 traffic. If your ISP doesn't support IPv6 but you choose to enable IPv6 on your LAN anyway (maybe using RFC 4193 addresses) and create AAAA records it will work for clients on your LAN reaching the server on your LAN. But communication between your LAN and the outside world would first try IPv6 (which wouldn't work), and you would be relying on falling back to IPv4 which at best is a little slower or at worst doesn't happen.
Since I also asked this question (see How do I access a network service NATed behind a firewall from inside using its outside IP?) and was redirected here but the answers here didn't provide a solution (in contrast to generic explanations) let my provide my Linux (
iptables
specific) solution here to save everybody a few hours of experimentation. This file is iniptables-restore
format and can be read into iptables directly (after editing the IP addresses of course). This is for a web server (port 80) and only for IPv4 - the rules for IPv6 and for SSL (port 443) are analogous.Replace
lan.local
,web.local
andweb.public.com
with your local network (eg. 10.0.x.0/24), your webserver's local IP (e.g. 10.0.1.2), and your router's public IP (eg. 4.5.6.7). The-4
is just to allow IPv6 and IPv4 rules in the same file (such lines ignored byip6tables
). Also, remember to put IPv6 addresses in [brackets] when they include port declarations, e.g.[fe0a:bd52::2]:80
.Those were all the things that caused me to pull my hair out when trying to actually implement the explanations in this question. I hope I left nothing out.
I'll add an answer here as the comments here didn't address my particular problem. I suspect that's because I hit a nasty linux kernel bug. The setup is:
Despite the complex looking picture the only relevant change to situations covered in other comments is the addition of the software bridge, br0. It's there because the gateway box is also a wireless access point for the LAN.
Our gateway box is still performing NAT duties for the machines on the LAN. Because it has only 1 ethernet port it is forced to do hairpin NAT. I suspect it should just work with the iptables rules given in other comments here, but on the Linux kernel 4.9 at least it doesn't. Under 4.9 our while our gateway box can access the internet the machines on the LAN trying to access it via NAT can't.
tcpdump
shows responses to incoming packets hitting eth0, but they don't make it out of br0. Running this command fixes that:Before that command is run incoming packets are processed according to the kernels default behaviour, which is to give them to the bridge then pass them kernel's routing modules. The command forces packets that aren't from the LAN to bypass the bridge and go directly to routing, which means the bridge doesn't get a chance to drop them. Broadcast and multicast addresses must be bridged, otherwise things like DHCP and mDNS won't work. if you are using IPv6, you must add rules for it as well.
You might be tempted to fix the problem using this:
I certainly was so tempted - it was my first attempt. As soon as I did it machines on the LAN gained access the internet, so it works for a while. Then the following occurred (and I didn't care to repeat the experiment):
The only way out was to reboot every machine in the building. The one exception was the hardware switches, which could not be rebooted. They had to be power cycled.