[Apologies for the long prelude; question halfway down.]
I have a working OpenVPN setup whereby a VPN server pushes a route back to one client (hereafter called the “router”) which can then expose its own subnet to the machine running the server as well as to other machines running the VPN client. This is accomplished just by making the router use the SNAT
target from iptables
. So for example, say the VPN server and other undistinguished clients are on the 10.0.77.0/24 network, the VPN creates a tun0
interface covering 192.168.252.0/24, and the private subnet is 192.168.33.0/24. The OpenVPN server configuration says (among other things)
client-to-client
route 192.168.33.0 255.255.255.0
push "route 192.168.33.0 255.255.255.0"
When the Linux “router” machine, 192.168.33.10 let us say, connects to the VPN it gets pushed a route, so its table looks like
192.168.33.0 * 255.255.255.0 U 0 0 0 eth1
192.168.252.0 192.168.252.5 255.255.255.0 UG 0 0 0 tun0
192.168.252.5 * 255.255.255.255 UH 0 0 0 tun0
and then it is configured to run
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -s 192.168.252.0/24 -j SNAT --to-source 192.168.33.10
It can also add some iptables
rules to create a firewall, but the above suffices to let the machine running the OpenVPN server (or another client) connect to, say, 192.168.33.11: the packets are sent via tun0
to the router, which uses SNAT to set the source IP to its own 192.168.33.10 and then forward the packets to its sibling machine 192.168.33.11. Reply packets are sent to the router, which then forwards them back through the tunnel and all is well. So for example on 192.168.33.11 I can
nc -l localhost 9999
and from the 10.0.77.13 (some other VPN client) I can
nc 192.168.33.11 9999
and make a connection. So far so good.
Note that no changes are being made to the physical router machine on either network; the “router” in quotes (a random machine running a VPN client) needs to use SNAT so that other machines on its network are able to send reply packets back through the VPN. For purposes of this question I am not “in control” of either network: I can only add some machines with their own routing rules and VPN clients or servers.
Now for the problem: let us say the two networks (neither on the public Internet) in fact overlap in their actual ranges. So in this example, the private subnet is not 192.168.33.11 but also 10.0.77.0/24. And let us assume that renumbering either network is simply not an option. So besides using SNAT to allow the router to forward packets, I need to remap the router’s private network to a different IP range from the perspective of the OpenVPN server. Let us say I pick 10.0.78.0/24 as the virtual network range:
route 10.0.78.0 255.255.255.0
push "route 10.0.78.0 255.255.255.0"
and from the OpenVPN server machine I want connections made to 10.0.78.11 to go through the tunnel and be processed with SNAT as before, but I also want the destination address in the router’s subnet to be 10.0.77.11. How can I configure iptables
to do this?
The NETMAP
target looked like it was what I wanted, but I could not get it to work:
iptables -t nat -A PREROUTING -i tun0 -j NETMAP --to 10.0.77.0/24
iptables -t nat -A POSTROUTING -s 192.168.252.0/24 -j SNAT --to-source 10.0.77.10
From the OpenVPN server machine I can ping 10.0.78.10 (i.e. the remapped address of the router) when the NETMAP
target is added, so it is doing something.
tcpdump -i tun0
run on the router during this ping shows ICMP echo request
and ICMP echo reply
as expected. But if I try to ping 10.0.78.11 (i.e. the remapped address of a sibling machine on the router’s subnet), I do not get replies, and tcpdump
on the router shows requests but not replies; tcpdump
on 10.0.77.11 (the sibling machine) shows no packets at all. Also running on the router:
iptables -t nat -L -v
shows packets being processed by NETMAP
but none by SNAT
. So it seems like the NETMAP
target is somehow superseding the SNAT
target?
Essentially what I want is that when the router receives a packet on tun0
from e.g. 192.168.252.5 (the OpenVPN server’s address on the tunnel) destined for 10.0.78.11, it is rewritten in two ways: the destination address is changed to 10.0.77.11, and the source address is changed to 10.0.77.10 (with a new source port being picked so that SNAT can keep track of which connection this is). Then when 10.0.77.11 sends a reply to the fake port on 10.0.77.10, the router should reverse the process, sending a packet back to 192.168.252.5 on tun0
with the faked source address of 10.0.78.11. Can NETMAP
do this, or can any other target in iptables
do this?
Other things I tried without success: configuring the router machine for proxy ARP; adding the virtual network range to the routing table. But it feels like such things should not be necessary.
Update: I do not care about DNS in this context at all—only a handful of machines in the “private subnet” need to be contacted, so using IP addresses is acceptable.