What I'm trying to achieve is to have http(s) requests originating from
machine A appear to the target server to be coming from machine B.
To illustrate with an example:
Let's say I have two VMs A and B running Ubuntu and living in the same VPN, machine A has public ip 1.1.1.1
and private ip 10.1.0.1
while machine B has public ip 2.2.2.2
and private ip 10.1.0.2
, the VPN's ip range is 10.1.0.0/20
.
Given the above I would like to be able to do this:
ssh root@1.1.1.1
root@1.1.1.1:~# curl ifconfig.me
2.2.2.2
root@1.1.1.1:~#
Note that I'm looking for a solution to route only outgoing traffic, I would like the routing of any incoming traffic to not be altered.
I was able to get halfway there by doing the following:
- on machine B enabling ip forwarding with
sysctl -w net.ipv4.ip_forward=1
- on machine B updating iptables with
iptables -t nat -A POSTROUTING -s 10.1.0.0/20 -o eth0 -j MASQUERADE
- on machine A updating routing with
ip route change default via 10.1.0.2
However this approach breaks all traffic coming in directly to 1.1.1.1
including ssh
, e.g.
to connect to 1.1.1.1
I would now have to do this ssh -o ProxyCommand="ssh -W %h:%p root@2.2.2.2" root@10.1.0.1
, which is not acceptable for my use case.
It is my understanding that by using iptables
on machine A (rather than ip route change default ...
) I should be able to route outging traffic through machine B, however, so far, I've failed.
One of the things that I've tried is updating the OUTPUT
chain with DNAT
on machine A (with machine B setup as above) but that causes any and all requests to time out.
ssh root@1.1.1.1
root@1.1.1.1:~# curl -m 5 ifconfig.me
1.1.1.1
root@1.1.1.1:~# iptables -t nat -A OUTPUT -p tcp -m multiport --dports 80,443 -j DNAT --to-destination 10.1.0.2
root@1.1.1.1:~# curl -m 5 ifconfig.me
curl: (28) Failed to connect to ifconfig.me port 80: Connection timed out
While I'm not wedded to the iptables
solution I would like to avoid, if possible, solutions that require the download of non-standard tools.
In case it matters, the specific platform I'm using is Digital Ocean, so the VMs are Droplets
and the VPN is what they call Virtual Private Cloud.
Best Answer
Easiest solution for the SSH access with MASQUERADE setup is to add a port forwarding rule on
2.2.2.2
:Then you can use
ssh -p 222 user@2.2.2.2
to connect to1.1.1.1
.If this solution is not enough, then you need a more complex setup.
The MASQUERADE solution above breaks inbound SSH connectivity because of the default route change at
1.1.1.1
.In this setup incoming packets for the SSH connection come from Internet facing interface. However,
1.1.1.1
sends response packets via2.2.2.2
, which drops them since they are not associated with a connection.To work around this, you need to mark the packets belonging to the SSH connection:
First rule applies packet mark 1 to all packets that are destined to SSH port.
Second rule restores existing connection marks to packet marks to handle routing for both directions.
Third rule saves existing packet mark to connection mark for later connection packets.
Next step is to create a custom routing table for packets related to SSH connections:
Edit
/etc/iproute2/rt_tables
and add the following line:Next, add a custom routing table:
Then, add a route to the custom routing table: