Take the 2-minute tour ×
Server Fault is a question and answer site for system and network administrators. It's 100% free, no registration required.

I have a small network with a router, which maintains a connection to Internet, a server and some workstations in a local network.

Network map

Server is meant to be accessed from the Internet, and there are several DNAT entries set in the router iptables, like this:

-A PREROUTING -i ppp0 -p tcp -m multiport --dports 22,25,80,443 -j DNAT --to-destination 192.168.2.10

External packets come to router via ppp0 interface, and internal ones go from br-lan, which actually includes the switch and WLAN adapter. The problem is, while external access works fine, trying to access the server from inside the LAN by a DNS-resolved external IP (assigned to ppp0) fails.

The only solution I was able to invent is to add static entries to router's /etc/hosts pointing to the internal IP, but as there are no wildcards (and I have at least three top-level domains assigned to that system, not counting tens of subdomains), that's rather crunchy and failure-prone. Can you suggest something better?

I've only found this question, which was not very helpful.

If that's relevant, the router runs OpenWRT 10.03 Kamikaze with dnsmasq.

share|improve this question
    
What version of OpenWRT? –  Corey S. Nov 23 '10 at 12:44
    
@Corey 10.03 Stable, but that has nothing to do with openwrt itself, isn't it? –  whitequark Nov 23 '10 at 16:44

5 Answers 5

up vote 4 down vote accepted

I deleted my original answer, because I wasn't fully confident that it was correct. I have since had some time to set up a little virtual network of VMs to simulate the network in question. Here is the set of firewall rules that worked for me (in iptables-save format, for the nat table only):

-A PREROUTING -d 89.179.245.232/32 -p tcp -m multiport --dports 22,25,80,443 -j DNAT --to-destination 192.168.2.10
-A POSTROUTING -s 192.168.2.0/24 -o ppp0 -j MASQUERADE
-A POSTROUTING -s 192.168.2.0/24 -d 192.168.2.10/32 -p tcp -m multiport --dports 22,25,80,443 -j MASQUERADE

The first POSTROUTING rule is a straightforward way of sharing the internet connection with the LAN. I left it there for completeness.

The PREROUTING rule and the second POSTROUTING rule together establish the appropriate NATs, so that connections to the server via the external IP address can happen, regardless of whether the connections originate from outside or from inside the LAN. When clients on the LAN connect to the server via the external IP address, the server sees the connections as coming from the router's internal IP address (192.168.2.1).

Interestingly, it turns out that there are a couple of variations of the second POSTROUTING rule that also work. If the target is changed to -j SNAT --to-source 192.168.2.1, the effect is (not surprisingly) the same as the MASQUERADE: the server sees connections from local LAN clients as originating from the router's internal IP address. On the other hand, if the target is changed to -j SNAT --to-source 89.179.245.232, then the NATs still work, but this time the server sees connections from local LAN clients as originating from the router's external IP address (89.179.245.232).

Finally, note that your original PREROUTING/DNAT rule with -i ppp0 does not work, because the rule never matches packets coming from the LAN clients (since those don't enter the router via the ppp0 interface). It would be possible to make it work by adding a second PREROUTING rule just for the internal LAN clients, but it would be inelegant (IMO) and would still need to refer explicitly to the external IP address.

Now, even after having laid out a "hairpin NAT" (or "NAT loopback", or "NAT reflection", or whatever one prefers to call it) solution in full detail, I still believe that a split-horizon DNS solution---with external clients resolving to the external IP and internal clients resolving to the internal IP---would be the more advisable route to take. Why? Because more people understand how DNS works than understand how NAT works, and a big part of building good systems is choosing to use parts that are maintainable. A DNS setup is more likely to be understood, and thus correctly maintained, than an arcane NAT setup (IMO, of course).

share|improve this answer
    
This works perfectly, thank you a lot! I agree that DNS setup is better, but you cannot forward different ports on same external IP to different machines on LAN with it. Anyway, I'm the only one who will ever maintain this setup, so it's fine. –  whitequark Nov 24 '10 at 6:25
    
I'm glad to hear this worked for you! –  Steven Monday Nov 24 '10 at 6:35

A common solution is to point your internal hosts at a local DNS server that returns the correct "internal" address for these hostnames.

Another solution -- and we're using this where I work on our Cisco firewalls -- is to rewrite DNS responses on the firewall that correspond to these addresses. I don't think there are tools for Linux that do this right now.

You should be able to configure the routing on your gateway to do the right thing. You may need to configure the servers to be aware of their externally mappped ip address (e.g., by assigning it to a dummy interface). With this configuration, communication from one internal system to another internal system -- using it's "external" address -- would go through the router.

share|improve this answer
    
Hmm. So are you suggesting adding the external IP to servers' interfaces and then configuring router so it will forward all packets to the external IP coming from inside the LAN to that server? Interesting, I'll test it soon. –  whitequark Nov 23 '10 at 17:30
    
Can you suggest the configuration? I tried this: ip rule add to 89.179.245.232 dev br-lan table 10; ip route add 89.179.245.232 via 192.168.2.10 dev br-lan table 10, and it isn't working. –  whitequark Nov 24 '10 at 5:40
    
What's in routing table 10? On the internal servers, you probably want them to have both a local 192.168.x.x address (for communicating locally) and the public address (as an alias) on their primary interface. –  larsks Nov 24 '10 at 14:06

larsks comment about hosting an internal version of the namespace\domain is generally the way I've handled this issue in the past. Of course, you need a DNS server internally in order to do this.

share|improve this answer
    
Yeah, I've wrote that I am using dnsmasq. Any ideas on setting up automatic substitution? –  whitequark Nov 23 '10 at 17:47
    
I know nothing about OpenWRT and Kamikaze, but based on what I'm reading - what if you added the following to your /etc/dnsmasq.conf "cname=ext-hostname.domain.com,int-hostname.domain.com" –  CurtM Nov 23 '10 at 17:58
    
Well, as far as I was able to determine, dnsmasq's cname does not support masks, and thus is not applicable for me due to subdomain count. –  whitequark Nov 24 '10 at 5:08

What you are asking to do is called NAT Loopback and it requires that you add a SNAT rule so that packets originating from your LAN to your Server will go back through the router:

-A POSTROUTING -p tcp -s 192.168.2.0/24 -d 192.168.2.10 -m multiport --dports 22,25,80,443 -j SNAT --to-source 89.179.245.232
share|improve this answer
    
Sadly, that does not work. I've originally missed the -i ppp0 option in my rule in question, as that was handled by other chain; this rule would prevent routing of packets coming from LAN (and if I'd enable it, packets will go from wrong source and will be rejected). –  whitequark Nov 23 '10 at 18:11
    
Have you tried it? It will only affect packets from your LAN going to your server IP on those very specific ports. –  SiegeX Nov 23 '10 at 18:43
    
Yes, I did. (And I tried changing the first rule, too). E.g. dig sends a packet to 192.168.2.1#53, and then gets an unexpected reply from 192.168.2.10#53, with or without your rule. –  whitequark Nov 24 '10 at 4:34

You want to use dnsmasq to override the real DNS entry for your server to use the INTERNAL IP address.

If your server is www.example.com and it's IP address is 1.2.3.4, from the OUTSIDE, it should look like:

Name:    www.example.com
Address:  1.2.3.4

But on the INSIDE of your network, you need www.example.com to point to 192.168.2.10 so that you can access using the same name as you would on the outside, so nslookup should return this on your LAN:

Name:    www.example.com
Address:  192.168.2.10

Why have those packets "leave" your LAN to just come right back in? I've never had much success in doing that. But at the same time, I never had a reason to do it either. I have seen this same operation done in many other configurations such as with Endian firewalls, or larger more complex network hidden behind Cisco ASA devices as well as a variety of different DNS servers.

So long as the Internet knows how to get to your server and your internal hosts know how to get to your server (by means of overriding the DNS entries at your local DNS servers), that is the important thing.

share|improve this answer
    
Well, dnsmasq has alias directive which can rewrite external IP to internal 'on the fly', but what if I want e.g. have router:22 be the server's SSH, and router:2222 be the router's SSH? Externally, this would work fine, but on internal access the rewrite will break port 2222 access. –  whitequark Nov 24 '10 at 5:19

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.