10

I have a fairly simple iptables firewall on a server that provides MySQL services, but iptables seems to be giving me very inconsistent results.

The default policy on the script is as follows:

iptables -P INPUT DROP

I can then make MySQL public with the following rule:

iptables -A INPUT -p tcp --dport 3306 -j ACCEPT

With this rule in place, I can connect to MySQL from any source IP to any destination IP on the server without a problem. However, when I try to restrict access to just three IPs by replacing the above line with the following, I run into trouble (xxx=masked octect):

iptables -A INPUT -p tcp --dport 3306 -m state --state NEW -s 208.XXX.XXX.184 -j ACCEPT 
iptables -A INPUT -p tcp --dport 3306 -m state --state NEW -s 208.XXX.XXX.196 -j ACCEPT 
iptables -A INPUT -p tcp --dport 3306 -m state --state NEW -s 208.XXX.XXX.251 -j ACCEPT 

Once the above rules are in place, the following happens:

  • I can connect to the MySQL server from the .184, .196 and .251 hosts just fine as long as am connecting to the MySQL server using it's default IP address or an IP alias in the same subnet as the default IP address.

  • I am unable to connect to MySQL using IP aliases that are assigned to the server from a different subnet than the server's default IP when I'm coming from the .184 or .196 hosts, but .251 works just fine. From the .184 or .196 hosts, a telnet attempt just hangs...

    # telnet 209.xxx.xxx.22 3306
    Trying 209.xxx.xxx.22...
    
  • If I remove the .251 line (making .196 the last rule added), the .196 host still can not connect to MySQL using IP aliases (so it's not the order of the rules that is causing the inconsistent behavior). I know, this particular test was silly as it shouldn't matter what order these three rules are added in, but I figured someone might ask.

  • If I switch back to the "public" rule, all hosts can connect to the MySQL server using either the default or aliased IPs (in either subnet):

    iptables -A INPUT -p tcp --dport 3306 -j ACCEPT
    

The server is running in a CentOS 5.4 OpenVZ/Proxmox container (2.6.32-4-pve).

And, just in case you prefer to see the problem rules in the context of the iptables script, here it is (xxx=masked octect):

# Flush old rules, old custom tables
/sbin/iptables --flush
/sbin/iptables --delete-chain

# Set default policies for all three default chains
/sbin/iptables -P INPUT DROP
/sbin/iptables -P FORWARD DROP
/sbin/iptables -P OUTPUT ACCEPT

# Enable free use of loopback interfaces
/sbin/iptables -A INPUT -i lo -j ACCEPT
/sbin/iptables -A OUTPUT -o lo -j ACCEPT

# All TCP sessions should begin with SYN
/sbin/iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP

# Accept inbound TCP packets (Do this *before* adding the 'blocked' chain)
/sbin/iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allow the server's own IP to connect to itself
/sbin/iptables -A INPUT -i eth0 -s 208.xxx.xxx.178 -j ACCEPT

# Add the 'blocked' chain *after* we've accepted established/related connections
#   so we remain efficient and only evaluate new/inbound connections
/sbin/iptables -N BLOCKED
/sbin/iptables -A INPUT -j BLOCKED

# Accept inbound ICMP messages
/sbin/iptables -A INPUT -p ICMP --icmp-type 8 -j ACCEPT
/sbin/iptables -A INPUT -p ICMP --icmp-type 11 -j ACCEPT

# ssh (private)
/sbin/iptables -A INPUT -p tcp --dport 22 -m state --state NEW -s xxx.xxx.xxx.xxx -j ACCEPT          

# ftp (private)
/sbin/iptables -A INPUT -p tcp --dport 21 -m state --state NEW -s xxx.xxx.xxx.xxx -j ACCEPT          

# www (public)
/sbin/iptables -A INPUT -p tcp --dport 80 -j ACCEPT                                
/sbin/iptables -A INPUT -p tcp --dport 443 -j ACCEPT                               

# smtp (public)
/sbin/iptables -A INPUT -p tcp --dport 25 -j ACCEPT                                
/sbin/iptables -A INPUT -p tcp --dport 2525 -j ACCEPT                              

# pop (public)
/sbin/iptables -A INPUT -p tcp --dport 110 -j ACCEPT                               

# mysql (private)
/sbin/iptables -A INPUT -p tcp --dport 3306 -m state --state NEW -s 208.xxx.xxx.184 -j ACCEPT 
/sbin/iptables -A INPUT -p tcp --dport 3306 -m state --state NEW -s 208.xxx.xxx.196 -j ACCEPT 
/sbin/iptables -A INPUT -p tcp --dport 3306 -m state --state NEW -s 208.xxx.xxx.251 -j ACCEPT 

Any ideas? Thanks in advance. :-)

Curtis
  • 503
  • 2
  • 9
  • 1
    Do the `.184 or .196 hosts` client hosts also have additional IP addresses in your the other subnet? If you do a `tcpdump -qn port 3306` and attempt and connect from one of those systems what do you see? Do you see the source address you expect? – Zoredache Jun 25 '12 at 23:37
  • 1
    Thanks, Zordache! That solved it. The .251 host did not have any IPs assigned from the other subnet. The other two hosts do (.184 and .196), and so when they connect to an IP on the other subnet, the source IP on those hosts switches to an IP in the same subnet. I had thought that the outgoing/source IP would always be the default one assigned. But, tcpdump clearly shows that the source IP changes to the 209.xxx.xxx.xxx subnet whenever it connects to an IP in that same subnet. (Had to run tcpdump from the physical Proxmox host, however.) You're a genious. Thanks! – Curtis Jun 26 '12 at 00:12

1 Answers1

8

Do the .184 or .196 hosts client hosts also have additional IP addresses in your the other subnet?

If you do a tcpdump -qn port 3306 and attempt and connect from one of those systems what do you see? Do you see the source address you expect? This is probably a simple routing issue.

When a system is making the route decision, it consults the route table. Route tables are a list that is always consulted in a specific order. The link routes for local networks are almost always the most preferred routes, and will be used before a route that uses a gateway(router). The default gateway is always the route that is used when no other route will applies. If a route a given route has a src defined, then that address will be preferred and most likely used when that route is being used.

10.2.13.0/24 dev eth1  proto kernel  scope link  src 10.2.13.1 
10.2.4.0/23 dev eth0  proto kernel  scope link  src 10.2.4.245 
default via 10.2.4.1 dev eth0 

So given this example route table for a multi-homed system, anything destined for 10.2.13.0/24 will come from 10.2.13.1, and anything destined for 10.2.4.0/23 will come from 10.2.4.245.

Zoredache
  • 128,755
  • 40
  • 271
  • 413