Discussion:
iptables for eth -> lo forwarding
Jim Cheetham
2011-08-05 01:56:38 UTC
Permalink
Hi all,

My google-fu has failed me, and my iptables-fu is not current enough
for this question, much though it pains me to admit.

I have a remote server, running MySQL on localhost:3306 only.
I wish to allow a specific set of other remote servers to connect to
the MySQL service.

(Yes, those db connections come via usernames that are source limited by MySQL).

What I would like to do is to accept incoming connections to eth0:3306
from specific source IP addresses, and pass those connections down to
lo:3306. This sounds like basic DNAT, but it "does not work", and I'm
assuming that's because I need to do some form of SNAT at the same
time, because the lo interface won't accept IP addresses that aren't
in 127/8 (i.e. I see the SYN packet arrive on eth0, but do not see any
traffic on lo).

Does anyone have a solution to this specific scenario? Most solutions
that I've seen are assuming the iptables is the firewall, and the
MySQL server is somewhere in a DMZ, and this works with the simple
DNAT rule on nat/prerouting, but not when talking to 127.0.0.1.

As a workaround, I'm currently runing MySQL on *:3306, and blocking
connections to eth0:3306 from anything except the desired servers.
This is not good, because a failure to load the iptables rules will
leave MySQL exposed to the world. The *NAT solution is much more
'fail-safe' in that respect, which is why I'm interested in it.

-jim

_______________________________________________
NZLUG mailing list ***@linux.net.nz
http://www.linux.net.nz/cgi-bin/mailman/listinfo/nzlug
Martin D Kealey
2011-08-05 02:47:07 UTC
Permalink
This is not good, because a failure to load the iptables rules will leave
MySQL exposed to the world.
The trick is to make "ifup" dependent on iptables having already loaded.

If you're using a debianesque system, that means in /etc/network/interfaces
you'll want something like this:

iface eth0 inet static
pre-up iptables-restore < /etc/iptables-saved
address 10.98.99.100
netmask 255.240.0.0

Assuming of course that /etc/iptables-saved has the rules that you want.

(In an ideal world, iptables' root chains would default to policy "DROP"
until you say otherwise.)

iptables-restore is failsafe because it won't do anything unless it gets the
"COMMIT" at the end of the input file.

-Martin

_______________________________________________
NZLUG mailing list ***@linux.net.nz
http://www.linux.net.nz/cgi-bin/mailman/listinfo/nzlug
Jim Cheetham
2011-08-05 03:19:16 UTC
Permalink
Post by Martin D Kealey
This is not good, because a failure to load the iptables rules will leave
MySQL exposed to the world.
The trick is to make "ifup" dependent on iptables having already loaded.
Yes, and that's a great start.

I still worry about an accidental manual action, like someone managing
to invoke a script that flushes rules somewhere else. Yes, that
assumes "an incompetent root user" but that's the sort of environment
these machines operate in ...

-jim

_______________________________________________
NZLUG mailing list ***@linux.net.nz
http://www.linux.net.nz/cgi-bin/mailman/listinfo/nzlug
Steve Holdoway
2011-08-05 04:33:01 UTC
Permalink
Post by Jim Cheetham
Post by Martin D Kealey
This is not good, because a failure to load the iptables rules will leave
MySQL exposed to the world.
The trick is to make "ifup" dependent on iptables having already loaded.
Yes, and that's a great start.
I still worry about an accidental manual action, like someone managing
to invoke a script that flushes rules somewhere else. Yes, that
assumes "an incompetent root user" but that's the sort of environment
these machines operate in ...
-jim
Given that you're using iptables to provide protection for a system that
has pretty sophisticated protection built in, I think it's an acceptable
risk.

But then I readily admit that risk is a very subjective matter (:

Steve.

[1] It can pin allowable logins to a specific ip address/account over
encrypted links, and then limit that account to a single operation on a
single table.
--
Steve Holdoway BSc(Hons) MNZCS <***@greengecko.co.nz>
http://www.greengecko.co.nz
MSN: ***@greengecko.co.nz
Skype: sholdowa
Jim Cheetham
2011-08-05 05:00:46 UTC
Permalink
Post by Steve Holdoway
On Fri, Aug 5, 2011 at 2:47 PM, Martin D Kealey >> I still worry about an accidental manual action, like someone managing
to invoke a script that flushes rules somewhere else. Yes, that
Given that you're using iptables to provide protection for a system that
has pretty sophisticated protection built in, I think it's an acceptable
risk.
Defence in Depth as a security principle suggests that the more
systems we have that enforce the same rule independently, the less
likely that rule is to 'fail'.
Post by Steve Holdoway
[1] It can pin allowable logins to a specific ip address/account over
encrypted links, and then limit that account to a single operation on a
single table.
Oh, thanks -- I hadn't noticed that MySQL has SSL support, so now I
have to go hook up client-side certs :-) Oh what fun.

-jim

_______________________________________________
NZLUG mailing list ***@linux.net.nz
http://www.linux.net.nz/cgi-bin/mailman/listinfo/nzlug
Volker Kuhlmann
2011-08-05 10:51:40 UTC
Permalink
Post by Jim Cheetham
I still worry about an accidental manual action, like someone managing
to invoke a script that flushes rules somewhere else. Yes, that
assumes "an incompetent root user" but that's the sort of environment
these machines operate in ...
Uhhhm well I hate to point out that by definition, an incompetent rooter
means you're rooted...

But really, how many scripts are there flushing iptables rules? My
system has about one, and that gets run on every ifup.

Volker
--
Volker Kuhlmann is list0570 with the domain in header.
http://volker.dnsalias.net/ Please do not CC list postings to me.

_______________________________________________
NZLUG mailing list ***@linux.net.nz
http://www.linux.net.nz/cgi-bin/mailman/listinfo/nzlug
Martin D Kealey
2011-08-05 11:10:15 UTC
Permalink
Post by Volker Kuhlmann
Post by Jim Cheetham
I still worry about an accidental manual action, like someone managing
to invoke a script that flushes rules somewhere else. Yes, that
assumes "an incompetent root user" but that's the sort of environment
these machines operate in ...
Uhhhm well I hate to point out that by definition, an incompetent rooter
means you're rooted...
And the incompetent ones also won't look to see that you've set the policy
to "DROP", and then wonder why they don't get a prompt after "iptables -F".
:-)

-Martin

_______________________________________________
NZLUG mailing list ***@linux.net.nz
http://www.linux.net.nz/cgi-bin/mailman/listinfo/nzlug
Martin D Kealey
2011-08-05 03:03:22 UTC
Permalink
Post by Jim Cheetham
What I would like to do is to accept incoming connections to eth0:3306
from specific source IP addresses, and pass those connections down to
lo:3306. This sounds like basic DNAT, but it "does not work",
Could you include some diagnostics? Redact the IP addresses, of course.

run
iptables -tfilter -Z
iptables -tnat -Z

attempt to make a connection

capture output from:
iptables -tfilter -xvnL
iptables -tnat -xvnL

and post it here. We should be able to figure out why it's not working from
the packet counters.

-Martin

_______________________________________________
NZLUG mailing list ***@linux.net.nz
http://www.linux.net.nz/cgi-bin/mailman/listinfo/nzlug
Jim Cheetham
2011-08-05 03:54:57 UTC
Permalink
Post by Martin D Kealey
Post by Jim Cheetham
What I would like to do is to accept incoming connections to eth0:3306
from specific source IP addresses, and pass those connections down to
lo:3306. This sounds like basic DNAT, but it "does not work",
Could you include some diagnostics? Redact the IP addresses, of course.
OK, I've spun up a VBox VM with a host-only interface on 10.51.4.1 to
talk to. Using "nc -l 127.0.0.1 3306" to replace MySQL server, and "nc
10.51.4.101 3306" to replace MySQL client.

Initial state, all chains ACCEPT, no other rules, the connection
attempt is rejected, the client nc command exits immediately.

17:48:54.393884 IP 10.51.4.1.38024 > 10.51.4.101.mysql: Flags [S], seq
2424931192, win 14600, options [mss 1460,sackOK,TS val 2330947 ecr
0,nop,wscale 7], length 0
17:48:54.393930 IP 10.51.4.101.mysql > 10.51.4.1.38024: Flags [R.],
seq 0, ack 2424931193, win 0, length 0
1

Simple DNAT :-
# iptables -tnat -A PREROUTING -p tcp --dport 3306 -j DNAT --to 127.0.0.1

Now something happens, the client keeps on retrying the connection,
multiple SYN packets on eth0, but nothing at all on the lo interface.

17:54:28.741900 IP 10.51.4.1.37399 > 10.51.4.101.mysql: Flags [S], seq
3371825447, win 14600, options [mss 1460,sackOK,TS val 2364483 ecr
0,nop,wscale 7], length 0
17:54:31.740528 IP 10.51.4.1.37399 > 10.51.4.101.mysql: Flags [S], seq
3371825447, win 14600, options [mss 1460,sackOK,TS val 2364784 ecr
0,nop,wscale 7], length 0
17:54:37.742907 IP 10.51.4.1.37399 > 10.51.4.101.mysql: Flags [S], seq
3371825447, win 14600, options [mss 1460,sackOK,TS val 2365386 ecr
0,nop,wscale 7], length 0
17:54:49.726551 IP 10.51.4.1.37399 > 10.51.4.101.mysql: Flags [S], seq
3371825447, win 14600, options [mss 1460,sackOK,TS val 2366588 ecr
0,nop,wscale 7], length 0

The 4 packets are seen to have been accepted by the DNAT rule. I can
see some stuff showing up on filter/INPUT and filter/OUTPUT, which are
probably my ssh connection.


# iptables -tnat -xvnL ; iptables -tfilter -xvnL
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source
destination
4 240 DNAT tcp -- * * 0.0.0.0/0
0.0.0.0/0 tcp dpt:3306 to:127.0.0.1

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source
destination

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source
destination

Chain INPUT (policy ACCEPT 10 packets, 664 bytes)
pkts bytes target prot opt in out source
destination

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source
destination

Chain OUTPUT (policy ACCEPT 7 packets, 1532 bytes)
pkts bytes target prot opt in out source
destination

I am not a router ...
# cat /proc/sys/net/ipv4/ip_forward
0

Making me into one does not change anything.

# echo 1 > /proc/sys/net/ipv4/ip_forward

18:02:13.624727 IP 10.51.4.1.36474 > 10.51.4.101.mysql: Flags [S], seq
2115326988, win 14600, options [mss 1460,sackOK,TS val 2411112 ecr
0,nop,wscale 7], length 0
18:02:16.624138 IP 10.51.4.1.36474 > 10.51.4.101.mysql: Flags [S], seq
2115326988, win 14600, options [mss 1460,sackOK,TS val 2411413 ecr
0,nop,wscale 7], length 0


Where in iptables will my packet go next? I'd like to use SNAT, but
that's only active in POSTROUTING, and as far as I understand things
the next place this packet goes is the INPUT chain ...

-jim

_______________________________________________
NZLUG mailing list ***@linux.net.nz
http://www.linux.net.nz/cgi-bin/mailman/listinfo/nzlug
Martin D Kealey
2011-08-05 11:26:46 UTC
Permalink
Post by Jim Cheetham
Chain OUTPUT (policy ACCEPT 7 packets, 1532 bytes)
Can we find out where the 7 OUTPUT packets went?

-Martin

_______________________________________________
NZLUG mailing list ***@linux.net.nz
http://www.linux.net.nz/cgi-bin/mailman/listinfo/nzlug
Jim Cheetham
2011-08-08 10:07:41 UTC
Permalink
On Fri, Aug 5, 2011 at 11:26 PM, Martin D Kealey
Post by Martin D Kealey
Post by Jim Cheetham
Chain OUTPUT (policy ACCEPT 7 packets, 1532 bytes)
Can we find out where the 7 OUTPUT packets went?
Probably ssh, which was active to the host at that time.

More reading has shown that the issue is probably intractable using
just iptables. Packets from the external network are not valid on the
localhost network, being martians (which by default seem to not be
logged, as per /proc/sys/net/ipv4/conf/all/log_martians). And I can
only DNAT in the prerouting chain ...

-jim

_______________________________________________
NZLUG mailing list ***@linux.net.nz
http://www.linux.net.nz/cgi-bin/mailman/listinfo/nzlug
Martin D Kealey
2011-08-09 22:25:28 UTC
Permalink
Post by Jim Cheetham
More reading has shown that the issue is probably intractable using
just iptables. Packets from the external network are not valid on the
localhost network, being martians (which by default seem to not be
logged, as per /proc/sys/net/ipv4/conf/all/log_martians). And I can
only DNAT in the prerouting chain ...
You could try double-NAT; fix the source address so it's not a martian.

Good luck though, your sanity will need it!

-Martin

_______________________________________________
NZLUG mailing list ***@linux.net.nz
http://www.linux.net.nz/cgi-bin/mailman/listinfo/nzlug

Loading...