Iptables masquerading / NAT firewall works with IPs, FAILS on SOME connections, esp when Domain Names are involved

domain-name-systemfedoraiptablesnat;

Problem Description:

One of two gateway ("firewall") systems failed, so I generated an "identical" one on replacement hardware, and found that when I switched one of the internal machines to go through the new gateway, ping failed. Switched back, it works. So, I tried pinging with an IP, avoiding DNS, and it worked. During troubleshooting I found that if I route through the old gateway, I can run 'dig' just fine, but through the new one, it fails with:

[root@MyHost sysconfig]# dig  @67.100.88.26 google.com mx

; <<>> DiG 8.2 <<>> @67.100.88.26 google.com mx 
; (1 server found)
;; res options: init recurs defnam dnsrch
;; res_nsend to server 67.100.88.26: Connection refused
[root@MyHost sysconfig]# 

If I switch it back to the other gateway, everything works perfectly. This suggests there's nothing wrong with the client box but that the firewalling is not, in fact identical, even though it appears to be.

I added logging for dropped packets, but there's nothing from the internal system at all!

Please note that this is implicitly a DNS / iptables interaction problem. Observing "fix DNS and you'll fix your problem" is only a restatement of the problem from a different perspective.

The question is: What, specifically, about this firewall config is blocking proper functioning when an identical machine, same OS, etc, works fine with this same iptables configuration, and with the same exact test system (and whatever might be right/ wrong with its resolve.conf).

(Also note: I think it's rather cowardly to vote down this question without commentary why.)

Examples:

[root@MyHost sysconfig]# ping google.com 
ping: unknown host google.com
[root@MyHost sysconfig]# ping 74.125.224.82
PING 74.125.224.82 (74.125.224.82) from 192.168.127.16 : 56(84) bytes of data.
64 bytes from 74.125.224.82: icmp_seq=0 ttl=53 time=46.425 msec
64 bytes from 74.125.224.82: icmp_seq=1 ttl=53 time=45.486 msec

--- 74.125.224.82 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/mdev = 45.486/45.955/46.425/0.516 ms
[root@MyHost sysconfig]#

Background information:

  • New firewall, old hardware on a fresh Fedora Core 14 installation – the two gateway systems are as close to identical as I can make them.

  • NetworkManager (appropriately) turned off.

  • DNS configuration seems fine on both the firewall and internal nodes – NO DNS services (BIND, etc) are used here, just public DNS servers. Access to DNS services from both gateways are fine.

  • The iptables directive "-A FORWARD -m state –state
    ESTABLISHED,RELATED -j ACCEPT " should enable the DNS messages to
    pass through without difficulty, as with the ping example, but with dig, I just don't know.

  • I added "-A INPUT -m limit –limit 3/min -j LOG –log-prefix
    "FW-IN-DROP-DEFAULT " –log-tcp-options –log-ip-options" as
    suggested in an attempted answer, and NO LOGGING is performed by this
    as a result of the failed DNS calls that are related to the ping
    cited in the example.

I wonder if I should perhaps use actual MASQUERADING instead of SNAT / DNAT.

Contents of /etc/sysconfig/iptables:

*nat
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 192.168.127.0/24 -o eth0 -j SNAT --to-source 76.110.113.22
-A PREROUTING -i eth0 -p tcp --dport 25 -j DNAT --to-destination 192.168.127.50
-A PREROUTING -i eth0 -p tcp --dport 1234 -j DNAT --to-destination 192.168.127.61:99
-A PREROUTING -i eth0 -p tcp --dport 993 -j DNAT --to-destination 192.168.127.50
-A PREROUTING -i eth0 -p tcp --dport 995 -j DNAT --to-destination 192.168.127.50
COMMIT
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 993 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 25 -j ACCEPT
-A INPUT -m state --state NEW -m udp -p udp --dport 1194 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 995 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
-A FORWARD -p icmp -j ACCEPT
-A FORWARD -i lo -j ACCEPT
-A FORWARD -i eth2 -j ACCEPT
-A FORWARD -o eth2 -j ACCEPT
-A FORWARD -i eth0 -m state --state NEW -m tcp -p tcp -d 192.168.127.50 --dport 25 -j ACCEPT
-A FORWARD -i eth0 -m state --state NEW -m tcp -p tcp -d 192.168.127.61 --dport 99 -j ACCEPT
-A FORWARD -i eth0 -m state --state NEW -m tcp -p tcp -d 192.168.127.50 --dport 993 -j ACCEPT
-A FORWARD -i eth0 -m state --state NEW -m tcp -p tcp -d 192.168.127.50 --dport 995 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

Best Answer

Your problem is that DNS isn't working.

From the perspective of the firewall, it can't tell if you typed:

$ ping google.com

or:

$ ping 2001:4860:800f::63

Fix DNS and you'll fix your problem.


To help diagnose, try adding some rules such as:

-A INPUT -m limit --limit 3/min -j LOG --log-prefix "FW-IN-DROP-DEFAULT " --log-tcp-options --log-ip-options 

before your REJECT rules. Then you'll know if it's being dropped.