0

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/tap0.


I have confirmed the following, with no extra routing set up and empty iptables (as confirmed by an empty iptables-save output):

  • curl ifconfig.me correctly routes through the WAN adapter, ens33, and shows my real IP.
  • curl --interface tun0 ifconfig.me correctly routes through the VPN connection and shows the proxied IP address.
  • Traffic is indeed reaching machine B from machine A at on the device ens34, as confirmed by tcpdump. ARP is correctly responding with physical addresses.
  • sysctl -p returns net.ipv4.ip_forward = 1 (I have enabled ip_forward system-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 WANIF to 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.

When using WANIF=tun0 or WANIF=tap0, 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

Where 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 8.8.4.4? 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.

7
  • Related: unix.stackexchange.com/questions/442760/… but it was never answered, and the suggestions there are what are parroted all over the internet and simply do not work :/ Mar 19, 2021 at 21:06
  • Bridging VPN is always bad idea. Use routing.
    – Jiri B
    Mar 19, 2021 at 21:38
  • @JiriB can you explain how? I have tried to use routes, as I explained above. They didn't work. Mar 20, 2021 at 0:37
  • Sorry but it's not clear from huge pile info what you want to achieve. You have machine B as route/gw for your lan and this has a VPN tunnel to some machine on internet? And you want your LAN traffic goes over this VPN tunnel? It would be easier to state immediatelly in the beginning what you want to achieve instead of description of what you have done... If I was guessing correctly, then you need a to change default gw on machine A to go via IP on tun0 on machine B.
    – Jiri B
    Mar 20, 2021 at 0:48
  • @JiriB I explained exactly what I want in the very beginning of the post. I have done exactly what you said - machine A has specified machine B as its gateway for the only NIC. The NIC on machine B that shares the LAN with machine A must have its packets forwarded over to the VPN adapter (and back, of course). Mar 20, 2021 at 1:57

1 Answer 1

1

The general rule about all of the similar setups is "you don't bridge l2 LAN segments with VPN". It causes more trouble than benefits.

Use the routing/forwarding.

This is the good advice that you will appreciate later; however, I fully understand that it has the enormous potential to attract the negative karma right now.

1
  • Okay, and how? I've attempted routing, as per a few of my attempts. Nothing works. Mar 20, 2021 at 21:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.