Iptables: how to redirect locally-generated packets to a remote server?
I'm trying to workaround a limitation in a server application. The limitation is that I can only connect to a LOCAL mysql database. I am trying to fool the server in to using a remote mysql database. I was hoping to do this by simply forwarding 3306 to another server on the same subnet.
To that end I've set up iptables rules to forward all connections to port 3306 to a non-standard mysql port on a remote server. This works, except that I need to deal with the loopback interface in a special way and I'm stuck. Code:
iptables -t nat -A PREROUTING -p tcp --dport 3306 -j DNAT --to 128.XXX.XXX.XXX:3197 Code:
iptables -t nat -A OUTPUT -p tcp -o lo --dport 3306 -j DNAT --to 128.XXX.XXX.XXX:3197 Here are what my chains look like: Code:
# iptables -L |
Quote:
Or to just be sure where things are growing dim use something like this. Code:
iptables -I OUTPUT -j LOG --log-prefix "Out: " --log-tcp-options |
Quote:
Do an "iptables -nvL -t nat" on your box to see the packet counters with your own eyes. :) |
Yes in fact in table 3-2 at http://www.faqs.org/docs/iptables/tr...goftables.html it says:
source of packet = local process table=nat chain=output: Quote:
Quote:
Code:
# iptables -nvL -t nat Code:
iptables -t nat -A OUTPUT -p tcp -o lo --dport 3306 -j DNAT --to 128.xxx.xxx.xxx:3197 Code:
# telnet localhost 3306 Code:
[root@adm-10-cms ~]# telnet localhost 3306 hmm... |
Looking at http://tinyurl.com/yhqr5no I believe that the problem is that once I do the DNAT in -t nat, the packet will not traverse the FORWARD chain. So I think what needs to be done is to resend the packet back to this host so that it originates from eth0 and gets processed by those rules. I tried:
Code:
iptables -t nat -A OUTPUT -p tcp -o lo --dport 3306 -j DNAT --to 169.xxx.xxx.xxx:3306 ...but that's not quite it. |
Quote:
You can easily telnet to different port and then in iptables use REDIRECT to turn packets to localhost ANY port. |
Quote:
Code:
[root@adm-10-cms ~]# telnet localhost 3306 Code:
[bwood@dev-10-cms ~]$ telnet 169.xxx.xxx.xxx 3306 (Mysql is not running on adm-10-cms. I am definitley getting a response from the 128.xxx box mentioned above.) |
If fails when you telnet to localhost port 3306, right?
I'd _guess_ it's because you do a DNAT but probably the source IP address that's set on those packets is still set to 127.0.0.1, isn't that right? Try snatting or masquerading all traffic to the real mysql server so that it sees your IP address on that network interface, otherwise the mysql server will get 127.0.0.1 as the source address of those packets and won't be able to reply back. |
Use REDIRECT rule in iptables to turn local port <ANY> to local port <ANY>.
|
Quote:
Code:
iptables -t nat -A OUTPUT -p tcp -o lo --dport 3306 -j DNAT --to 169.xxx.xxx.xxx:3306 |
Quote:
|
wait, wait, you confuse me.
nat -A OUTPUT - is located BEFORE router. So, you need to do things different way. You need to connect to port 3306 on local and remote host - no problems. But you need separate connections. In that case you can choose port 3306 for local and 4444 for remote server. Now your iptables rules should be next: iptables -t nat -A OUTPUT -p tcp -o lo --dport 4444 -j DNAT --to 169.xxx.xxx.xxx:3306 Now packets to port 3306 will not match any rules and go to local host as it suppose to be. But packets to 4444 will match our rule and NAT will change destination. |
Sure... just add filters to the rule in -t nat POSTROUTING that will match only traffic you care to masquerade/snat.
And just to make sure: it fails when you try to connect to telnet localhost 3306 (which is supposed to end up connecting to a remote mysql server), is that right? |
But I'm seeing in your rules that you are masquerading all traffic that's going out... so the problem is not what I'm describing. Let me read it again to see what's going on.
|
can you do a tcpdump on your network interface that connects to the nerwork where the remote mysql server is?
something like: tcpdump -i blah -p tcp and port 3197 -n -v and then try to do the telnet and see what addresses/ports are showing up? |
Thanks eantoraz,
First I setup my rules again: Code:
[root@adm-10-cms ~]# iptables -F Code:
[root@adm-10-cms ~]# tcpdump -i eth0 -p tcp and port 3197 -n -v Code:
[root@adm-10-cms ~]# tcpdump -i lo -p tcp and port 3197 -n -v Code:
[root@adm-10-cms ~]# telnet localhost 3306 Code:
0 packets captured Code:
[root@adm-10-cms ~]# tcpdump -i lo -p tcp and port 3306 -n -v Code:
[root@adm-10-cms ~]# tcpdump -i lo -p tcp and port 3307 -n -v Code:
[root@adm-10-cms ~]# iptables -t nat -D OUTPUT -p tcp -o lo --dport 3306 -j DNAT --to 128.xxx.xxx.xxx:3197 |
With the rules you set in place, do the tcpdump on -i lo and try the telnet localhost 3306 and tell us what comes out.
|
And is the counter of the -t nat OUTPUT rule you set increasing when you do the telnet?
|
Oh, I saw you tried the tcpdump listening on -i lo so skip that test for now. Tell me about the counter, because that traffic must be going somewhere, right?
|
I would think that the problem here is that there's code on the network stack doing checkups after OUTPUT that when looking at the packet (source address: 127.0.0.1, dest addres: something not in loopback) drops it for not being "consistent".... perhaps someone knows about this? And perhaps could sysconf be used to disable such checkup?
|
Quote:
Code:
[root@adm-10-cms ~]# tcpdump -i lo -v The counter is incrementing. I see: Code:
[root@adm-10-cms ~]# iptables -L -nvx -t nat Code:
Chain OUTPUT (policy ACCEPT 108 packets, 7372 bytes) |
Quote:
http://www.linuxquestions.org/questi...21#post3909121 Since this is a locally-generated packet it is never going to hit this rule Code:
iptables -A FORWARD -p tcp -d 128.xxx.xxx.xxx --dport 3197 -j ACCEPT Code:
iptables -t nat -A OUTPUT -p tcp -o lo --dport 3306 -j DNAT --to 128.xxx.xxx.xxx:3197 |
Well, FORWARD is not touched by packets that are going out from OUTPUT so don't worry cause it doesn't affect you.
I think it's because of the source address inconsistency, I think. Check out this article I just found (a little dated, by the way): http://lists.netfilter.org/pipermail...er/040104.html So, how about other tricks? Why do you need locally generated connections on local port 3306 to get connected to a remote host in the first place? In case it's a _must_, wouldn't a SSH tunnel (or a simpler approach) work for you? In case you want to try the ssh runnel trick, remove the OUTPUT rule doing the DNAT to remote:3197 and run this command on that same host: ssh -nNT -L 3306:remote-server:3197 user@localhost After the connection is established (you will know because after a few seconds the command won't return), try telnet localhost 3306 Maybe there are simpler approaches but _at least_ I bet that one will work. |
It _has_ to be the IP address inconsistency.
With all your rules in place, try to do a telnet to your local IP address on the intranet (instead of localhost). That way, it did work with your DNAT trick. |
At least, it did work for me.
|
Quote:
Quote:
Will try telnet to ipaddr tomorrow and report back. If that works, I may look into snat. Thanks.; |
The ssh tunnel as I told you to use it yesterday requires no ssh on the mysql server but on the host you are working instead (the one where you want local connections to port 3306 to be sent to a remote server port 3197).
|
Thanks again for all the help!
You are right. Telnetting to anything other than localhost works: Code:
[root@adm-10-cms ~]# telnet 169.xxx.xxx.xxx 3306 Thanks for enlightening me on the ssh tunnel. I assumed that you needed sshd running on the target server. Since you don't I'm pursuing this option since it is way simpler. Always good to know more about iptables though! |
I think your problem is really solved here (I mean, solved the iptables way) :
http://unix.stackexchange.com/questi...s-to-127-0-0-1 you need to activate local routing on your outbound interface. if eth0 : sysctl -w net.ipv4.conf.eth0.route_localnet=1 it seems to be like security feature hope it helps some people coming to this question ! |
All times are GMT -5. The time now is 02:54 AM. |