Need a generic iptables tcp proxy?
Posted by JacobAppelbaum on Tue 13 May 2008 at 10:02
It's as easy as the following three iptables calls:
YourIP=1.2.3.4 YourPort=80 TargetIP=2.3.4.5 TargetPort=22 iptables -t nat -A PREROUTING --dst $YourIP -p tcp --dport $YourPort -j DNAT \ --to-destination $TargetIP:$TargetPort iptables -t nat -A POSTROUTING -p tcp --dst $TargetIP --dport $TargetPort -j SNAT \ --to-source $YourIP iptables -t nat -A OUTPUT --dst $YourIP -p tcp --dport $YourPort -j DNAT \ --to-destination $TargetIP:$TargetPort
In the example above, a user may now ssh to $YourIP (1.2.3.4) on $YourPort (port 80) and they'll be transparently redirected to the $TargetIP (2.3.4.5) on the $TargetPort (22). The remote host ($TargetIP) will see the connection as coming from the server doing the forwarding ($YourIP).
Why bother with this at all? Why not just change the port that sshd listens on?
This is useful when a network filters outgoing connections based on destination ports and you don't control the host you want to connect to. If such a network only allowed outgoing connections to port 80, you'd be able to circumvent their filtering. However, if the firewall is doing stateful layer seven inspection, all bets are off. It's trivial to make this work for any other protocol, there is nothing special about ssh - it's just used as an example.
As a general note, this may invite abuse. It is basically a single hop protocol agnostic TCP proxy in kernel space. It's fast and useful though. You may want to restrict forwarding by source IP addresses if you're worried about letting anyone using you as a single hop bounce. I'll leave that as an exercise for the comments.
[ Parent | Reply to this comment ]
When new clients expects that they need loadbalancing within a year, we don't assign a public IP to the actual webserver, but to the firewall. The firewall will than forward all http trafic to the internal machine (as describes by this article, except that the port doesn't changes). After a year we can assign the public IP to the loadbalancer an add the second webserver to the pool.
About adding the public IP to the local loopback. We have several web applications that connect to their own webservices (SOA design). Say that www.example.org points to 1.2.3.4, than webserver with interface 10.0.0.1 routes to 1.2.3.4 (gateway does masquerading (POSTROUTING) part 1), but than it sees that that 1.2.3.4 points back to 10.0.0.1, that it double masquerades (adding the PREROUTING masquerade). But gateways don't like double forwarding packets. When rf_filter is enabled it will even drop the packet because the request originated from the wrong interface.
To prevent the extensive routing, you can add the 1.2.3.4 IP to your local loopback device and any attempts from the webserver to connect to itself are handled by the loopback device.
firewall gateway:
eth0: 1.2.3.4
eth1: 10.0.0.254
lo: 127.0.0.1
Server A:
eth0: IP 10.0.0.1
lo: 127.0.0.1, 1.2.3.4
--- IF LOADBALANCED
Server B:
eth0: 10.0.0.2
lo: 127.0.0.1, 1.2.3.4
Server C:
eth0: 10.0.0.3
lo: 127.0.0.1, 1.2.3.4
Server D:
eth0: 10.0.0.4
lo: 127.0.0.1, 1.2.3.4
--- END IF
Hope that this make my previous comment a bit clearer.
[ Parent | Reply to this comment ]
Setup for Clarity:
Machine A
IP address: i.i.i.1
Machine B has 2 IP
Internal IP: i.i.i.2 (on another NIC)
External IP: x.x.x.1 (on one NIC)
Machine C
IP address: x.x.x.2
Machine B and Machine C are in the same network (intranet) where Machine B can connect to Machine C only via its external IP (x.x.x.x)
Machine B and Machine A are in internal privatenetwork where Machine B can connect to Machine A only via its internal IP (i.i.i.i)
Machine A <i.i.i.1> <--> Machine B (i.i.i.2>:60 <---> Machine B <x.x.x.1> <---> Machine C <x.x.x.2>:60
Basically forward auditd log from Machine A in internal network to auditd (port 60) on Machine C on external network via Machine A.
We tried the rinetd equivalent rules given below,but in vain.
YourIP= i.i.i.1
YourPort=60
TargetIP=x.x.x.2
TargetPort=60
iptables -t nat -A PREROUTING --dst $YourIP -p tcp --dport $YourPort -j DNAT \
--to-destination $TargetIP:$TargetPort
iptables -t nat -A POSTROUTING -p tcp --dst $TargetIP --dport $TargetPort -j SNAT \
--to-source $YourIP
iptables -t nat -A OUTPUT --dst $YourIP -p tcp --dport $YourPort -j DNAT \
--to-destination $TargetIP:$TargetPort
Any Advice ?
[ Parent | Reply to this comment ]
I have 2 linux machine in internet.
First - 82.*.*.*
Second - 76.*.*.*
I need :
All inquiries should be forwarded to another address
For example if i from my home computer (33.x.x.x) ping First, in fact I must ping Second.
I run in First:
# iptables -t nat -A PREROUTING -d $First -j DNAT --to-destination $Second
# iptables -t nat -A POSTROUTING -d $Second -j SNAT --to-source $First
Everythink is works.
(Via $First IP I get access to $Second).
Problem 1:
But when i run (from my home computer) 'tracert -d $First' - I get loop:
1. ...
2. ...
....
7. 82.*.*.*
8. 82.*.*.*
9. 82.*.*.*
...
30. 82.*.*.*
Problem 2:
And on $Second I run 'tcpdump -i eth0 -n icmp' and see requests (pings from my home computer) from $First, but I want to see request from my home ip (33.x.x.x)
Thanks for help.
[ Parent | Reply to this comment ]
"TCP/IP packet repeater in the application layer. It repeats TCP and UDP packets from inside to outside of a firewall, or from outside to inside."
You can basically proxy or forward any tcp or udp connection with one single command. However, learning iptables is always a good idea ;-) !
kind regards, mistersixt.
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
===============================================
#!/bin/sh
# TCP Proxy using IPTables
IPTABLES=/sbin/iptables
echo 1 > /proc/sys/net/ipv4/ip_forward
# Flush nat table
$IPTABLES -t nat -F
# tcpproxy LOCAL_IP LOCAL_PORT REMOTE_IP REMOTE_PORT
function tcpproxy {
$IPTABLES -t nat -A PREROUTING --dst $1 -p tcp --dport $2 -j DNAT --to-destination $3:$4
$IPTABLES -t nat -A POSTROUTING --dst $3 -p tcp --dport $4 -j SNAT --to-source $1
$IPTABLES -t nat -A OUTPUT --dst $1 -p tcp --dport $2 -j DNAT --to-destination $3:$4
}
# Example 1
tcpproxy 192.168.40.244 3200 10.10.10.2 3200
# Example 2
tcpproxy 192.168.40.245 3200 192.168.1.30 3200
===============================================
sorry for any spelling errors (english isnt my native language) :)
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
-j
belong in that last rule? (sorry if this is a stupid
question. i'm an iptables ignoramus)
[ Parent | Reply to this comment ]
--dummy
[ Parent | Reply to this comment ]
Machine A
IP address: i.i.i.1
Machine B has 2 IP
Internal IP: i.i.i.2 (on another NIC)
External IP: x.x.x.1 (on one NIC)
Machine C
IP address: x.x.x.2
Machine B and Machine C are in the same network (intranet) where Machine B can connect to Machine C only via its external IP (x.x.x.x)
Machine B and Machine A are in internal privatenetwork where Machine B can connect to Machine A only via its internal IP (i.i.i.i)
Machine A <i.i.i.1> <--> Machine B (i.i.i.2>:60 <---> Machine B <x.x.x.1> <---> Machine C <x.x.x.2>:60
Basically forward auditd log from Machine A in internal network to auditd (port 60) on Machine C on external network via Machine A.
We tried the rinetd equivalent rules given below,but in vain.
YourIP= i.i.i.1
YourPort=60
TargetIP=x.x.x.2
TargetPort=60
iptables -t nat -A PREROUTING --dst $YourIP -p tcp --dport $YourPort -j DNAT \
--to-destination $TargetIP:$TargetPort
iptables -t nat -A POSTROUTING -p tcp --dst $TargetIP --dport $TargetPort -j SNAT \
--to-source $YourIP
iptables -t nat -A OUTPUT --dst $YourIP -p tcp --dport $YourPort -j DNAT \
--to-destination $TargetIP:$TargetPort
Any Advice ?
[ Parent | Reply to this comment ]
then it should look like
[bart@simps ~]# cat /proc/sys/net/ipv4/ip_forward
1
[ Parent | Reply to this comment ]
[ Send Message ]
We use NAT forwarding for websites we expect that they will be loadbalanced in the future.
[ Parent | Reply to this comment ]