Never mind this question - seems I was doing something wrong. It works with DNAT:
iptables -t nat -A OUTPUT -p tcp -d 192.168.251.3 -j DNAT --to-destination 1.2.3.4
Question:
We are unsure if with IPTABLES SNAT and/or DNAT it is possible to pass the "real" source IP to the destination.
Answer:
Yes, it is possible, and here's how to do it if you're using CSF. Don't rely on CSF's redirect feature, i.e. having a line similar to the following in /etc/csf/csf.redirect
:
XXX.XXX.XXX.184|2222|10.0.0.100|22|tcp
Instead, put the following iptables
commands in /etc/csf/csfpost.sh
:
/sbin/iptables -I FORWARD -i vmbr0 -o vmbr10 -d 10.0.0.0/24 -j ACCEPT
/sbin/iptables -I FORWARD -i vmbr0 -o vmbr10 -d 10.0.0.0/24 -j LOCALINPUT
/sbin/iptables -t nat -A PREROUTING -i vmbr0 -p tcp -m tcp --dport 2222 -j DNAT --to-destination 10.0.0.100:22
Test:
$ ssh xxx.xxx.xxx.184 -p 2222 'netstat -tn'
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 72 10.0.0.100:22 xxx.xxx.xxx.199:55812 ESTABLISHED
Explanation:
/sbin/iptables --table nat --append PREROUTING --in-interface vmbr0 --protocol tcp --match tcp --dport 2222 --jump DNAT --to-destination 10.0.0.100:22
This line redirects TCP traffic coming in on the external interface on port 2222
to the internal address 10.0.0.100
on port 22
.
/sbin/iptables
the full iptables
executable is required.
--table nat
working on the nat (Network Address Translation) table.
--append PREROUTING
append this rule after all existing rules in the PREROUTING
chain.
--in-interface vmbr0
catch all traffic comin in on the vmbr0
interface.
--protocol tcp
catch only tcp traffic.
--match tcp
use the tcp module.
--dport 2222
catch only traffic directed to port 2222
.
--jump DNAT
perform a Destination Network Address Translation.
--to-destination 10.0.0.100:22
change the destination address to 10.0.0.100
and the destination port to 22
.
/sbin/iptables --insert FORWARD --in-interface vmbr0 --out-interface vmbr10 --destination 10.0.0.0/24 --jump LOCALINPUT
This line allows to not skip all of CSF's filtering just because we are redirecting.
/sbin/iptables
the full iptables
executable is required.
--insert FORWARD
insert this rule before existing rules in the FORWARD
chain. This is where redirected packets are going, as opposed e.g. to the INPUT
chain.
--in-interface vmbr0
match traffic coming in on the vmbr0
interface.
--out-interface vmbr10
match traffic going out from the vmbr0
interface as an effect of redirection.
--destination 10.0.0.0/24
match only traffic destined to (redirected to) the internal network.
--jump LOCALINPUT
go through the LOCALINPUT
chain. This is where CSF performs all the good filtering it is known for, keeping banned and blacklisted IPs from reaching the system. With this rule, we extend CSF's filtering to all hosts on the internal network (as opposed to just traffic destined for the host where CSF is running).
/sbin/iptables --insert FORWARD --in-interface vmbr0 --out-interface vmbr10 --destination 10.0.0.0/24 --jump ACCEPT
This line passes all remaining forwarded traffic to the internal hosts.
/sbin/iptables
the full iptables
executable is required.
--insert FORWARD
insert this rule before existing rules in the FORWARD
chain. This rule will be evaluated after all the filering is performed in the LOCALINPUT
chain.
--in-interface vmbr0
match traffic coming in on the vmbr0
interface.
--out-interface vmbr10
match traffic going out from the vmbr0
interface as an effect of redirection.
--destination 10.0.0.0/24
match only traffic destined to (redirected to) the internal network.
--jump ACCEPT
after CSF has performed all its filtering (in the LOCALINPUT
chain), we want remaining packets to be ACCEPT
ed.
Best Answer
I hope I'm understanding your question, too. Your response to Luke in the comments to baumgart's answer caused me to second-guess my understanding your requirements, but I'm going to post this anyway.
What baumgart is telling you to do in his answer will work, but his last paragraph where he talks about "...will likely cause problems with client-server apps..." isn't correct. He's forgetting that Netfilter's NAT implementation is stateful. That stateful nature of the NAT engine in Netfilter is your friend here.
When the conversation between an Internet host and one of your public IPs gets DNAT'ed to a private IP address Netfilter won't "MASQUERADE" the response packets coming from the private IP back to the Internet host. That's not to say the response packets aren't NAT'ed, but they're not "MASQUERADED". Rather, Netfilter implicity "does the right thing" and SNAT's the response packets from the private IP back to the public IP address to which the Internet host initiated the conversation. It's really very slick.
Meanwhile, for conversations originating from the private IP address to the Internet (not in response to incoming requests from the Internet) the "MASQUERADE" rule will apply.
Basically, Netfilter does what you want "out of the box". I took some time and mocked this up on a test setup just to be sure, and, so long as I understand your requirements properly, it's doing exactly what you're looking for.
(Sorry about not being able to answer earlier in the day-- I was busy with some things earlier today and couldn't, ya' know, play Server Fault as much as I like to.)