I'm using a two-VM setup wherein the first VM,
machine A, has a closed, private LAN shared with the second VM,
machine B, which has a second network interface that is configured to hit the internet.
Both adapters for the internal LAN are configured using static IPs; DHCP is disabled. The public LAN adapter (the second adapter in
machine B) is confirmed to hit the internet successfully.
machine A's adapter is configured to use the LAN address of
machine B as its gateway address.
I'm trying to bridge the gap between the two interfaces on
machine B with an OpenVPN connection, so that
machine A transparently connects to the internet over this OpenVPN connection without needing VPN installed on the machine itself.
(private LAN) machine A ─────────────────► ens34 │ ▼ OpenVPN ────────►tun0 OR tap0 │ (public LAN) ▼ WAN ◄─────────────────── ens33
It makes no difference to me if the OpenVPN device is TUN or TAP. Whatever works is acceptable. It also doesn't matter to me if the WAN card is usable by
machine B or if it's completely taken-over by the configuration - the OpenVPN connection is over a VPN service, not a private/enterprise network or the like; it's meant for all of the traffic to be routed through it, as a proxy.
It's worth mentioning that I also have a third interface on the machine,
ens38, that is configured as host-only for SSH reasons, that will otherwise be down in all cases aside from debugging.
I intend for all traffic to be routed over the VPN connection - not just specific ports - and would rather have the network interface on
machine A behave as closely as possible to how it would if the interface was configured to use a VPN connection directly.
I am creating the TUN/TAP devices via
openvpn --mktun --dev tun0/
tap0 and then re-using them with
openvpn --config ... --dev tun0/
I have confirmed the following, with no extra routing set up and empty iptables (as confirmed by an empty
curl ifconfig.mecorrectly routes through the WAN adapter,
ens33, and shows my real IP.
curl --interface tun0 ifconfig.mecorrectly routes through the VPN connection and shows the proxied IP address.
- Traffic is indeed reaching
machine Aat on the device
ens34, as confirmed by
tcpdump. ARP is correctly responding with physical addresses.
net.ipv4.ip_forward = 1(I have enabled
ip_forwardsystem-wide for all of the attempts below).
The first attempt was to use packet marking and iproute2 routes as described in this thread, but there was nothing going through as per
tcpdump -i tun0. My tables are
ACCEPT by default so
-j LOG was showing me less than ideal results for debugging.
The second attempt was to use pre-routing and masquerading using the following script:
#! /bin/bash set -euo pipefail IPTABLES=/sbin/iptables WANIF='tun0' LANIF='ens34' # enable ip forwarding in the kernel echo 'Enabling Kernel IP forwarding...' /bin/echo 1 > /proc/sys/net/ipv4/ip_forward # flush rules and delete chains echo 'Flushing rules and deleting existing chains...' $IPTABLES -F $IPTABLES -X $IPTABLES -F -t nat $IPTABLES -X -t nat # enable masquerading to allow LAN internet access echo 'Enabling IP Masquerading and other rules...' $IPTABLES -t nat -A POSTROUTING -o $LANIF -j MASQUERADE $IPTABLES -A FORWARD -i $LANIF -o $WANIF -m state --state RELATED,ESTABLISHED -j ACCEPT $IPTABLES -A FORWARD -i $WANIF -o $LANIF -j ACCEPT $IPTABLES -t nat -A POSTROUTING -o $WANIF -j MASQUERADE $IPTABLES -A FORWARD -i $WANIF -o $LANIF -m state --state RELATED,ESTABLISHED -j ACCEPT $IPTABLES -A FORWARD -i $LANIF -o $WANIF -j ACCEPT
This did work when setting the
ens33 (the public WAN adapter) -
machine A was successfully able to talk to the outside world through
machine B, just not over VPN of course.
tcpdump showed no activity on those interfaces.
The third attempt was to use DNAT:
iptables -t nat -A PREROUTING --in-interface $LANIF -j DNAT --to-destination 10.8.1.13
10.8.1.13 was the IP of the TUN device at the time.
This did nothing.
The last attempt was to use a bridge adapter. I first tried with a TUN device but learned that bridge adapters didn't support them, so I switched to a TAP device and ran the following commands:
ip link add br0 type bridge ip link set tap0 master br0 ip link set dev ens34 down ip addr flush dev ens34 ip link set dev ens34 up ip link set ens34 master br0 ip addr add 192.168.4.42 dev br0 # static IP otherwise configured for ens34 ip link set dev br0 up
This successfully resulted in traffic from
machine A to reach the TAP device, but it was treating the VPN network as though it was a local peer and asking the VPN network ARP requests for public IPs (e.g.
Who has 188.8.131.52? Tell 192.168.4.80).
I'm completely stumped. Is what I'm trying to do even possible? Why isn't iptables able to forward to TUN/TAP devices?
The second attempt (masquerading) seemed to be the best bet since it's what I perceive to be the 'proper' solution, but it seems that iptables simply refuses to route to the TUN or TAP devices.