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. :-)
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.So given this example route table for a multi-homed system, anything destined for
10.2.13.0/24
will come from10.2.13.1
, and anything destined for10.2.4.0/23
will come from10.2.4.245
.