Score:1

Routing only the private network in wireguard VPN

in flag

I have a few hosts behind a NAT router that I want to access via a wireguard VPN. I could successfully configure the private network, but there's still something that baffles me.

I want each peer to:

  • access each other (172.9.9.*) via the VPN (via wg0)
  • access every other host outside the VPN (via eth0).

Here's a schema of the network and current configuration:

┌─────┐    ┌──────────┐    ┌─────┐
│  S  ├────┤ Internet ├────┤  A  │
└─────┘    └───┬──────┘    └─────┘
               │
               │
          ┌────┴─────┐
          │ NAT DHCP │
       ┌──┤  Router  ├──┐
       │  └──────────┘  │
       │                │
    ┌──┴──┐          ┌──┴──┐
    │  X  │          │  B  │
    └─────┘          └─────┘
  • S is the VPN server and it's accessible on the internet via static IP;
  • X is a "compute server", it can access the internet, but is behind a NAT and it's IP is dynamic and not known in advance;
  • A is a "remote client" that wants to connect to X;
  • B is a "local client" that wants to connect to X and it's in the same local network.

I want that A and B can connect to X through S, but all of these hosts should use the VPN only when contacting each other and not when accessing the internet.

So, for instance, A can ping google.com directly, but will ping X via S.

After searching and reading documentations, it's still unclear to me if it's possible to do this without using iptables and if it's possible to do so using only the wireguard configuration.

The current configuration is the following:

## S wg0.conf

[Interface]
PrivateKey = S-private-key
Address = 172.9.9.1/24
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
ListenPort = 51820

[Peer]
# A
PublicKey = A-public-key
AllowedIPs = 172.9.9.100/32

[Peer]
# B
PublicKey = B-public-key
AllowedIPs = 172.9.9.101/32

[Peer]
# X
PublicKey = X-public-key
AllowedIPs = 172.9.9.10/32
# A wg0.conf

[Interface]
Address = 172.9.9.100/24
PrivateKey = A-private-key
DNS = 1.1.1.1

[Peer]
PublicKey = S-public-key
Endpoint = S-ip-address:51820
AllowedIPs = 0.0.0.0/0, ::/0

B's configuration is similar to A, but with IP 172.9.9.101 and different private key.

# X wg0.conf

[Interface]
Address = 172.9.9.10/24
PrivateKey = X-private-key
DNS = 1.1.1.1

[Peer]
PublicKey = S-public-key
Endpoint = S-ip-address:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25  # To keep the server reachable

This configuration works and all the hosts can access each other via the VPN, but I want that ONLY traffic directed to hosts 172.9.9.* goes through this VPN. The other traffic shall be routed by the default gateway.

What puzzles me is that, if I change the configuration of A so that

AllowedIPs = 172.9.9.0/24

then, for A, the packages are routed as intended (e.g. I can curl ifconfig.me and get A's public IP), but if I do the same on X, it will not work and packages not going to 172.9.9.0/24 will fail to be delivered.

EDIT#1

Forgot to mention that I would also love if, when connecting to X, the local clients such as B would not send packages outside the local network, so B -> Router -> X and not B -> Router -> S -> Router -> X.

mx flag
`AllowedIPs` is the way to go, as Justin explained clearly in their answer. It is possible that you cannot `curl ifconfig.me` when using `AllowedIPs = 172.9.9.0/24` because of DNS issues. Check if you can `ping 8.8.8.8`: if you can, then fix your DNS resolution.
Score:2
cn flag

Set AllowedIPs to the IP addresses you want to route to/through the peer.

In a normal hub-and-spoke configuration, on your hub (S), you'd configure AllowedIPs for each peer like you have, routing packets to each peer only if they use the peer's WireGuard IP address as their destination address; and on your spokes (A, B, and X), you'd configure AllowedIPs to the CIDR of your WireGuard network (172.9.9.0/24), routing packets to the hub only if they use another peer's WireGuard IP addresses as their destination address.

So with a normal configuration, you'd access A from B or X with A's WireGuard IP address of 172.9.9.100, B from A or X with 172.9.9.101, and X from A or B with 172.9.9.10.

But if you also want to be able to access each spoke via the IP address bound to the spoke's physical NIC (eg eth0), you'd need to adjust the AllowedIPs on both the hub and the spokes to include those IP addresses.

For example, if A's eth0 address is 198.51.100.65, B's is 192.168.0.66, and X's is 192.168.0.88, you'd adjust the peers in the hub's WireGuard config to this:

## S wg0.conf
...

[Peer]
# A
PublicKey = A-public-key
AllowedIPs = 172.9.9.100/32
AllowedIPs = 198.51.100.65/32

[Peer]
# B
PublicKey = B-public-key
AllowedIPs = 172.9.9.101/32
AllowedIPs = 192.168.0.66/32

[Peer]
# X
PublicKey = X-public-key
AllowedIPs = 172.9.9.10/32
AllowedIPs = 192.168.0.88/32

And set AllowedIPs in each of the spoke's config to this:

AllowedIPs = 172.9.9.0/24
AllowedIPs = 198.51.100.65/32
AllowedIPs = 192.168.0.66/32
AllowedIPs = 192.168.0.88/32

(Note you can also specify all the blocks on one line like AllowedIPs = 172.9.9.0/24, 198.51.100.65/32, 192.168.0.66/32, 192.168.0.88/32 if you prefer.)


With your current configuration, where you have AllowedIPs = 0.0.0.0/0 on X, when you run curl 198.51.100.65 from X, what's happening is that X is routing the packets destined for A (and everything else) through its WireGuard tunnel to S, and then S is routing those packets unencrypted over the Internet to A (masqueraded with S's own public IP address); in response, A sends unencrypted packets over the Internet to S, which S routes through its WireGuard tunnel to X.

If you want to make sure S doesn't ever route packets tunneled through your WireGuard network out to the Internet, you can adjust your iptables rules to prevent this; something like the following would probably do the trick:

PostUp = iptables -A FORWARD -i wg0 -o wg0 -j ACCEPT; iptables -A FORWARD -i wg0 -o eth0 -j DROP; iptables -A FORWARD -i eth0 -o wg0 -j DROP
ARDVL avatar
in flag
Thank you for this detailed explanation! It is very clear, although regarding the access using the `NIC` IP address, it's still unclear to me: since `X` and `B` are behind DHCP and their IP might change (especially for `B`), I cannot know that in advance and set the appropriate allowed IP.
ARDVL avatar
in flag
Also, I already tried to set the `AllowedIPs` to `172.9.9.0/24`, but didn't work. As it was mentioned in a comment, it was a DNS issue.
cn flag
To use DHCP-assigned NIC addresses, you'd either have to configure your DHCP server to assign X and B fixed IP addresses, or update the other peers' `AllowedIPs` settings every time a different address was assigned to X or B. (But also note that you can do a hybrid of this, where you access A via its NIC address, but X and B via their WireGuard addresses -- in that case, you can simply omit X and B's NIC addresses from your `AllowedIPs` settings.)
Score:0
in flag

I had an issue with DNS: using AllowedIPs = 172.9.9.0/24 allowed me to ping 8.8.8.8, but not google.com.

I solved including the interface DNS in the allowed IPs, so I get DNS resolution via VPN, but traffic is not in the VPN:

[Interface]
...
DNS = 1.1.1.1

[Peer]
...
AllowedIPs = 172.9.9.0/24, 1.1.1.1/32

This doesn't answer the second question I had: if it's possible to make X and B communicate directly without going through S. The other answer helps in understanding that.

EDIT

It seems that it works also by dropping the DNS field, so it should use the same DNS server for both interfaces.

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.