WireGuard tunnel inside another tunnel

For various reasons, I'd like to run a WireGuard tunnel inside another tunnel. It's a bit complicated, I'll try to explain as best I can.

The setup is as follows:

  • WG tunnel A: between home router and VPN provider (home router initiates)
  • WG tunnel B: between remote router and home router (remote router initiates)
  • Tunnel B goes inside tunnel A
  • Both routers are running OpenWrt 21.02
  • Public IP on home router: 20.20.20.20
  • VPN providers IP: 30.30.30.30
  • VPN provider is forwarding port 12345 to my home router, inside tunnel A (Mullvad)

So ultimately, the remote router is connecting to 30.30.30.30:12345, which should establish a tunnel between my two routers. The problem is how to configure the home router, below are parts of the WireGuard config on home router:

Allowed IPs: 0.0.0.0/0 (remote router is on 4G, will be a random public IPv4 address)
Route Allowed IPs: Unchecked (home clients should be routed over WAN, no tunnel)

Tunnel B is listening on port 12345 on all interfaces on my home router, when I try to set up the tunnel from remote router, remote router is not getting any incoming packages. I believe the problem has to do with routing. If my home router sees incoming traffic from a public IPv4 inside tunnel A, will it automatically respond on the same interface, and route packages through tunnel A? I'm guessing no, so do I need to use some sort of policy based routing perhaps? (I've never used that before).

I've used WireGuard on OpenWrt in various semi-advanced setups, so I've checked the basics on tunnel A. I'll appreciate any tips on this.

There are a few ways you could do this. I think you're going to need PBR to get this to work, so take a look at that. But one way to make this really easy would be to put in another OpenWrt router (behind your main router) to serve as the 'server' for your road-warrior VPN setup. This would be the home-based endpoint for your mobile connection. Then, that router would connect to the LAN of the main home router which would have the tunnel upstream VPN provider running.

It seems like your end goal is to route traffic from your mobile device through the VPN provider. But I'm curious why you want to hop through your home first. I don't really see what it accomplishes.

1 Like

I already have another OpenWrt device acting as an AP, so that is a possible solution. But I don't understand what you mean. Do you mean that I could for example create a seperate VLAN/subnet on my main router, which have all it's traffic routed through tunnel A? Because that's something I would like to know how to do, but if I check "Route Allowed IPs", that would apply for all my LAN interfaces. (How to apply 0.0.0.0/0 tunnel A route only to specific LAN interface?)

I'm not trying to route traffic to a VPN provider via my LAN, it's the other way around. The goal of this is to have a Chromecast on the travel router stream media from a Plex server at home, through WireGuard.

The remote router is routing 0.0.0.0/0 through tunnel A, to my home router. If I connect a laptop to the travel router, I can enter the local IP of the Plex server at home, and all traffic between the two different subnets is routed through WireGuard.
The problem comes when the Chromecast is using the "Remote Access" IP it receives from Plex. The travel router is sending encrypted WireGuard pakcets to 20.20.20.20:51820, when the Chromecast reaches out to 20.20.20.20:32400, that traffic is routed outside the VPN tunnel, directly over 4G. This is because the tunnel itself can't be tunneled, so all traffic to this IP is sent directly (ideally, only UDP to port 51820 should be untunneled).

Anyway, that's why I'm trying to do a tunnel inside a tunnel, then Plex and WireGuard won't connect to the same public IP. As a bonus, anyone sniffing my WireGuard traffic wouldn't be able to see my public IP at home. This ended up being a loong explanation, but I think it's a rather interesting problem, and it would be really cool to have a working travel router like this.

Some other ideas on how to get this working:

  • Have two different IPv4 addresses on home router, one dedicated to WireGuard tunnel.
  • Somehow force Plex to use local IP, maybe disable remote access would help?
  • Use NAT rules on travel router to rewrite source/destination IP of pakcets?
  • Have tunnel B connect over IPv6, directly to home router.

So a few thoughts on this...

I would treat this as 2 independent tunnels and not consider it tunnel within a tunnel. Specifically, what I think you want to do is run a tunnel between your travel router and your home. The traffic that emerges from the travel router's tunnel at your home will no longer be tunneled. It will basically be like you are at home (albeit on a different subnet, but no different than if you're using VLANs at home). From there, you can setup your VPN service tunnel from your home router to the VPN provider, and use additional methods to ensure that only the desired traffic gets sent through the tunnel to the provider (i.e. PBR and/or adjusting allowed IPs to exclude RFC1918 addresses).

I don't think this is the case -- after all, your first tunnel from your travel router > home is going directly to your home. It is not going through the commercial VPN. And unless your commercial VPN allows you to make multiple connections and provides you a personal publicly routable inbound IP, you can't go through the commercial VPN first anyway.

This shouldn't happen if things are properly configured on your travel router (and/or phone). Your devices should connect via wifi to the travel router, and that router should transparently tunnel everything to your home endpoint. There is no reason that any traffic should be sent over 4G that is not part of that tunnel, unless something is wrong or the phone is set to prefer 4g over wifi.

If you know the LAN address of your Plex server, it should work when you use that address on the phone (which is connected to the travel router's wifi because all traffic on the travel router gets tunneled to your home).

1 Like

Wireguard instance B needs to be listening to the tunnel endpoint of instance A. That one connection is the only purpose of instance A, it doesn't need to route anywhere. Unless of course you also want to send general home Internet usage through Mullvad. But don't do that until you have the two tunnels working, that will make it easier to monitor instance A for any incoming from B so you know the forwarding is working.

The "allowed IPs" in Wireguard have a firewall like function inside the tunnel. At the receiving end, after the packet is decrypted, the source IP on the packet sent through the tunnel (not the external Internet IP of the outer encrypted packet originator) is examined. If it does not match, the packet is dropped. This functionality can be turned off by setting allowed IPs to all. In a site to site situation, the allowed IPs would all be from the LAN(s) on the other end of the tunnel. This is useful in conjunction with route allowed IPs since you've identified the subnets of the remote LAN so routes can also be installed. In a full Internet usage situation, the allowed IP would be the IP of the web site being accessed via VPN, which means you have to allow all returning packets, and also route a request for any website IP into the tunnel.

Route allowed IPs is completely optional if you'd rather install routes yourself.

1 Like

But it IS a tunnel within a tunnel. Maybe I should have explained my reasoning better in my first post, I'm not trying to send traffic to the internet via my VPN provider, see my post further up about Chromecast and local Plex server. In my first attempt at this, I just had a VPN tunnel from my travel router, directly to my home router. That didn't work as expected.

Tunnel B is going from my travel router to the public IP of my VPN provider. My quote just above this holds true. See the link to Mullvad in my original post for an explanation on how this works.

I didn't expect this either, but it seems this is how WireGuard works on OpenWrt!
This doesn't really have anything to do with how to set up one tunnel inside another, but rather how traffic going to the same IP as the tunnel endpoint is routed.

I've run some tests to compare the behavior to Windows/Android. In all three test cases the tunnel endpoint is 20.20.20.20:51820. VPN provider is not involved in any way in theses tests. This is what I found:

  • Tunnel from Android to home router: traffic to 20.20.20.20:X (for example port 80) is routed inside tunnel. This is the desired behavior.
  • Tunnel from Windows to home router: same behavior as seen on Android, traffic to 20.20.20.20:X (for example port 80) is routed inside tunnel. This is the desired behavior.
  • Tunnel from travel router to home router: traffic to 20.20.20.20:X (for example port 80) is routed outside the tunnel! I've done thorough tests with Windows connected to travel router's WiFi. I see that all traffic to 20.20.20.20:X is routed outside the tunnel, while all traffic to any other IP is routed inside tunnel. Ping from travel router WebUI to 20.20.20.20 also seems to be routed outside tunnel.

Again, this has nothing to do with how to set up routes on my home router, as I asked in the original post. This is a separate issue, on how WireGuard does routing on OpenWrt. I welcome anyone to verify this issue. If this is not the expected behavior, is this a bug/flaw that should be looked into more seriously?

As far as I know, I can't manually specify which IP the Chromecast should connect to. I think the Chromecast gets this address from Plex (as in: Plex's central servers, not my home server). I can however access my home Plex server on Windows by entering the local IP in the browser, so I know the tunnel is up and running.

I agree. Tunnel A is dedicated to this purpose, tunnel B is listening on all interfaces, including the one belonging to tunnel A.

Yes, that's why I have set "Allowed IPs" to 0.0.0.0/0, to allow incoming tunnel B from any public IPv4. I have not cheked "Route allowed IPs", because I want clients on my home network to reach the internet via the normal WAN interface.

Now we are at the core of the routing problem. The only traffic I want to send through tunnel A is the encrypted packets that make up tunnel B. These are going to an unknown, and sometimes changing address in the other end (travel router on 4G). All these packets are coming from the tunnel B interface, so I'll look into policy based routing for a solution.

Could you please post a simple example on how to do this?

WireGuard clients based on wg-quick implement own PBR with fwmark to prevent traffic leak.
WireGuard on OpenWrt is integrated with netifd and creates an explicit endpoint route.
You can enable the nohostroute option and configure PBR like this:

uci set network.lan.ip4table="1"
uci set network.lan.ip6table="1"
uci set network.vpn.ip4table="2"
uci set network.vpn.ip6table="2"
uci set network.vpn.fwmark="1"
uci set network.vpn.nohostroute="1"
uci -q delete network.all_vpn
uci set network.all_vpn="rule"
uci set network.all_vpn.mark="1"
uci set network.all_vpn.invert="1"
uci set network.all_vpn.lookup="2"
uci set network.all_vpn.priority="30000"
uci -q delete network.all_vpn6
uci set network.all_vpn6="rule6"
uci set network.all_vpn6.mark="1"
uci set network.all_vpn6.invert="1"
uci set network.all_vpn6.lookup="2"
uci set network.all_vpn6.priority="30000"
uci commit network
/etc/init.d/network restart

However note that PBR configured with netifd conflicts with the VPR package.

1 Like

It sounds like that's exactly what I'm looking for!

If I enable nohostroute option, then traffic to 20.20.20.20:X would be routed inside the tunnel, because I've set 0.0.0.0/0? And I would manually have to create a route to 20.20.20.20:51820 over WAN? Am I understanding this correctly? Would I be able to set up the required routes with the "vpn-policy-routing" package?