8

I want to use the RPi in my house as a WireGuard VPN. Unfortunately, my ISP mandates a CGNAT. My plan was to have the RPi connect as a WireGuard peer to my server (with a static IP). I would then connect my client (my phone) to the server and have all of its traffic routed through the server via the RPi to the internet.

A chart demonstrating what I wanted to achieve:

A chart demonstrating what I wanted to achieve

I got the RPi and the client connected to the server. However, I couldn't figure out how to set up the routing. I attempted to configure routing on the server, so that when traffic comes from 10.6.0.0/24 (the VPN's subnet) on wg1, reroute it back through via 10.6.0.1 (the RPi) on wg1. That didn't seem to work. Looking with tcpdump, I see that packets from the client reach the server, but don't reach the RPi.

Here's the important bits of my configuration (all on the server in wg1.conf as PostUp rules):

ufw route allow in on wg1 out on wg1
ip rule add from 10.6.0.0/24 lookup 200
ip route add default via 10.6.0.1 dev wg1 table 200
iptables -t nat -I POSTROUTING -o wg1 -j MASQUERADE

The RPi too is configured to apply NAT (iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE).
The client is configured to route everything via WireGuard (AllowedIPs = 0.0.0.0/0).
Both the server and the RPi have ip_forward enabled.

Jackdaw
  • 1,834
Tbsc
  • 83

2 Answers2

4

The via <gw> part of your route cannot do anything here, as WireGuard is a L3 tunnel which doesn't carry any L2 (MAC) addressing inside. Instead the WireGuard interface itself selects which peer to forward packets to, by matching the destination IP address against the "AllowedIPs=" parameters of all peers.

So you can only route via dev wg1, and whichever peer has AllowedIPs = 0.0.0.0/0, ::/0 will be the one that everything is forwarded to. (The 'via' parameter is ignored if specified.) There's no other way to do it.

(This design wart effectively limits WireGuard tunnels to only one "gateway" per interface. In some cases, you might need to create several dedicated WireGuard interfaces, each with a single peer that has AllowedIPs set to /0, in order to be able to control routing externally.)

I know that putting 0.0.0.0/0 on the RPi AllowedIPs should get client traffic routed via the RPi, but also the server's entire traffic, which is unwanted.

That's done not by AllowedIPs= itself, but by the helper program you use to bring up the WireGuard tunnel. Specifically it is wg-quick that by default creates system-level routes through the tunnel based on AllowedIPs= of all peers.

To avoid this, specify Table= in your wg-quick configuration so that it would put the routes in an alternate table (or nowhere at all).

Alternatively, configure the tunnel via systemd-networkd (which also has a similar option, but does not create any routes by default).

grawity
  • 501,077
4

Internet Gateway as a Spoke

We have an endpoint with WireGuard running on it, Endpoint A, from which we want to access the Internet. To get from Endpoint A to the Internet in this scenario, however, WireGuard traffic needs to go through two hops: one through the VPN hub, Host C; and the second through a spoke of the hub, Host β. However, while we want to use Host β as the Internet gateway for Endpoint A, we don’t want that for Host C — Host C itself can use the default routes at Site C to access the Internet as needed. Hub with an Internet Gateway Spoke

Details of the network used in this explanation

Within our WireGuard network, Endpoint A has an IPv4 address of 10.0.0.1 and an IPv6 address of fd10:0:0:1::1; Host C has an IPv4 address of 10.0.0.3, and an IPv6 address of fd10:0:0:3::1; and Host β has an IPv4 address of 10.0.0.2 and an IPv6 address of fd10:0:0:2::1. Host C has a public IP address of 192.0.2.3, allowing Endpoint A and Host β to each establish a WireGuard tunnel to it.

Endpoint A

On Endpoint A, when the WireGuard network is up, we want to send all Internet traffic through Host C, so we configure AllowedIPs = 0.0.0.0/0, ::/0 for Host C in Endpoint A’s WireGuard config:

# /etc/wireguard/wg0.conf

local settings for Endpoint A

[Interface] PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEE= Address = 10.0.0.1/32, fd10:0:0:1::1/64 ListenPort = 51821

remote settings for Host C

[Peer] PublicKey = jUd41n3XYa3yXBzyBvWqlLhYgRef5RiBD7jwo70U+Rw= Endpoint = 192.0.2.3:51823 AllowedIPs = 0.0.0.0/0, ::/0

0.0.0.0/0 is the entire IPv4 space, and ::/0 is the entire IPv6 space. (If you don’t care about IPv6 traffic, you can omit the IPv6 addresses and address blocks from this and the other WireGuard configurations.)

Host C

On Host C, we want to send all the traffic destined for 10.0.0.1 or fd10:0:0:1::/64 to Endpoint A, and all other traffic that comes through our WireGuard network on to Host β. So we configure WireGuard on Host C with AllowedIPs = 10.0.0.1/32, fd10:0:0:1::/64 for its Endpoint A [Peer] section, and AllowedIPs = 0.0.0.0/0, ::/0 for its Host β [Peer] section.

But since we don’t want all of Host C’s traffic to go to Host β — just traffic forwarded through the WireGuard network — we configure the routes for this WireGuard interface to use a custom routing table, via the interface’s Table = 123 setting. And we use a PreUp command to add a policy routing rule that directs the host to use this table only for traffic coming in from this WireGuard interface (ip rule add iif wg0 table 123 priority 456):

# /etc/wireguard/wg0.conf

local settings for Host C

[Interface] PrivateKey = CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCGA= Address = 10.0.0.3/32, fd10:0:0:3::1/64 ListenPort = 51823 Table = 123

IPv4 forwarding & routing

PreUp = sysctl -w net.ipv4.ip_forward=1 PreUp = ip rule add iif wg0 table 123 priority 456 PostDown = ip rule del iif wg0 table 123 priority 456

IPv6 forwarding & routing

PreUp = sysctl -w net.ipv6.conf.all.forwarding=1 PreUp = ip -6 rule add iif wg0 table 123 priority 456 PostDown = ip -6 rule del iif wg0 table 123 priority 456

remote settings for Endpoint A

[Peer] PublicKey = /TOE4TKtAqVsePRVR+5AA43HkAK5DSntkOCO7nYq5xU= AllowedIPs = 10.0.0.1/32, fd10:0:0:1::/64

remote settings for Host β

[Peer] PublicKey = fE/wdxzl0klVp/IR8UcaoGUMjqaWi3jAd7KzHKFS6Ds= AllowedIPs = 0.0.0.0/0, ::/0

Host B

Similar to the previous Site Gateway as a Spoke scenario, on Host β, we want to send all the traffic destined for the 10.0.0.0/24 and fd10::/56 networks back through Host C — so that’s what we use as the AllowedIPs setting for Host C in Host β’s WireGuard config:

# /etc/wireguard/wg0.conf

local settings for Host β

[Interface] PrivateKey = ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBFA= Address = 10.0.0.2/32, fd10:0:0:2::1/64 ListenPort = 51822

IPv4 forwarding

PreUp = sysctl -w net.ipv4.ip_forward=1

IPv4 masquerading

PreUp = iptables -t mangle -A PREROUTING -i wg0 -j MARK --set-mark 0x30 PreUp = iptables -t nat -A POSTROUTING ! -o wg0 -m mark --mark 0x30 -j MASQUERADE PostDown = iptables -t mangle -D PREROUTING -i wg0 -j MARK --set-mark 0x30 PostDown = iptables -t nat -D POSTROUTING ! -o wg0 -m mark --mark 0x30 -j MASQUERADE

IPv6 forwarding

PreUp = sysctl -w net.ipv6.conf.all.forwarding=1

IPv6 masquerading

PreUp = ip6tables -t mangle -A PREROUTING -i wg0 -j MARK --set-mark 0x30 PreUp = ip6tables -t nat -A POSTROUTING ! -o wg0 -m mark --mark 0x30 -j MASQUERADE PostDown = ip6tables -t mangle -D PREROUTING -i wg0 -j MARK --set-mark 0x30 PostDown = ip6tables -t nat -D POSTROUTING ! -o wg0 -m mark --mark 0x30 -j MASQUERADE

remote settings for Host C

[Peer] PublicKey = jUd41n3XYa3yXBzyBvWqlLhYgRef5RiBD7jwo70U+Rw= Endpoint = 192.0.2.3:51823 AllowedIPs = 10.0.0.0/24, fd10::/56 PersistentKeepalive = 25

Note that in Host β’s configuration for Host C, we’ve also included a PersistentKeepalive = 25 setting. This ensures that Host β pokes a hole through any NAT (or egress-only) firewalls between Host C and Host β, allowing Endpoint A to initiate connections through the WireGuard network to Host β. You can omit this setting if there are no NAT or egress-only firewalls between Host C and Host β (but if you do that, make sure you instead set up Host C’s WireGuard config to include the public IP address of Host β in its Endpoint setting for Host β).

Also note that we’ve included some iptables rules in Host β’s WireGuard configuration. These iptables rules masquerade packets from the WireGuard network when Host β forwards them out to Site B. You can omit these rules if the LAN router (or each individual endpoint) at Site B is already configured to route traffic destined for the WireGuard network (10.0.0.0/24) back through Host β.

Test It Out

After starting up our configured WireGuard interfaces on each host (Endpoint A, Host C, and Host β), we can run cURL (or a regular webrowser) from Endpoint A to access Google (or any other Internet site) through our WireGuard network: `` $ curl google.com

301 Moved ...

<h1>Reference :</h1>
<p>copy-pasted from <a href="https://www.procustodibus.com/blog/2022/06/multi-hop-wireguard/#internet-gateway-as-a-spoke" rel="nofollow noreferrer">https://www.procustodibus.com/blog/2022/06/multi-hop-wireguard/#internet-gateway-as-a-spoke</a> (saved me from 2 weeks of unsuccessful search...)</p>
Dev0110
  • 111