1

I have following config:

two interfaces eth0 connected via ISP1 and wlan0 connected via ISP2 to the internet. Both connections have different IP addresses and allow internet connectivity.

I setup two wireguard interfaces wg0 and wg1. wg0 should always go via eth0 (which is default anyway), and wg1 should always go via wlan0 interface.

The problem that I have is that I use same remote server-peer (eg. peer wan ip 11.11.11.11) to connect to both wg0 and wg1 at the same time. So, when packet arrives on wg1 it probably tries to send it back via eth0 instead of wlan0. I tried to add static routing rules, but the thing is that I do not need to always route 11.11.11.11 via wlan0, since if connection comes from eth0 it should also send it via eth0.

Is there some way to say - connection to wg1 should always communicate via wlan0?

Other solution that I can see is possible here (and not sure if it would work), is to setup link aggregation for eth0 and wlan0, but I read that it is not possible to aggregate different physical connections? It would be the best if I could have then single wg0 interface available with whichever interface is up and running (eth0 or wlan0).

This is current config:

2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 02:81:1e:50:c6:18 brd ff:ff:ff:ff:ff:ff
    inet 192.168.100.200/24 brd 192.168.100.255 scope global eth0
       valid_lft forever preferred_lft forever
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 0e:41:58:01:16:9e brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.134/24 brd 192.168.0.255 scope global wlan0
       valid_lft forever preferred_lft forever
4: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
    link/none
    inet 10.9.0.1/24 scope global wg0
       valid_lft forever preferred_lft forever
5: wg1: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
    link/none
    inet 10.9.1.1/24 scope global wg0-client
       valid_lft forever preferred_lft forever

UPDATE

Adding the output of the command listed in the comments:

ip route

default via 192.168.100.1 dev eth0 onlink
10.9.0.0/24 dev wg0 proto kernel scope link src 10.9.0.1
10.9.1.0/24 dev wg1 proto kernel scope link src 10.9.1.1
192.168.0.0/24 dev wlan0 proto kernel scope link src 192.168.0.134
192.168.100.0/24 dev eth0 proto kernel scope link src 192.168.100.200

ip rule

0:      from all lookup local
32766:  from all lookup main
32767:  from all lookup default

ip route show table local

local 10.9.0.1 dev wg0 proto kernel scope host src 10.9.0.1
broadcast 10.9.0.255 dev wg0 proto kernel scope link src 10.9.0.1
local 10.9.1.1 dev wg1 proto kernel scope host src 10.9.1.1
broadcast 10.9.1.255 dev wg1 proto kernel scope link src 10.9.1.1
local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1
local 192.168.0.134 dev wlan0 proto kernel scope host src 192.168.0.134
broadcast 192.168.0.255 dev wlan0 proto kernel scope link src 192.168.0.134
local 192.168.100.200 dev eth0 proto kernel scope host src 192.168.100.200
broadcast 192.168.100.255 dev eth0 proto kernel scope link src 192.168.100.200

ip route show table main

default via 192.168.100.1 dev eth0 onlink
10.9.0.0/24 dev wg0 proto kernel scope link src 10.9.0.1
10.9.1.0/24 dev wg1 proto kernel scope link src 10.9.1.1
192.168.0.0/24 dev wlan0 proto kernel scope link src 192.168.0.134
192.168.100.0/24 dev eth0 proto kernel scope link src 192.168.100.200

and wireguard configs:

wg0.conf

[Interface]
Address = 10.9.0.1/24
PrivateKey = xxx
ListenPort = 51820

PostUp = sysctl net.ipv4.conf.%i.forwarding=1 net.ipv4.conf.$(ip r l 0/0 | mawk '{print $5;exit}').forwarding=1
PostUp = sysctl net.ipv6.conf.$(ip r l 0/0 | mawk '{print $5;exit}').accept_ra=2
PostUp = sysctl net.ipv6.conf.%i.forwarding=1 net.ipv6.conf.$(ip r l 0/0 | mawk '{print $5;exit}').forwarding=1
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -s 10.9.0.0/24 -o $(ip r l 0/0 | mawk '{print $5;exit}') -j MASQUERADE
PostUp = ip6tables -A FORWARD -i %i -j ACCEPT; ip6tables -t nat -A POSTROUTING -o $(ip r l 0/0 | mawk '{print $5;exit}') -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -s 10.9.0.0/24 -o $(ip r l 0/0 | mawk '{print $5;exit}') -j MASQUERADE
PostDown = ip6tables -D FORWARD -i %i -j ACCEPT; ip6tables -t nat -D POSTROUTING -o $(ip r l 0/0 | mawk '{print $5;exit}') -j MASQUERADE

# Client 1
[Peer]
PublicKey = yyy
AllowedIPs = 10.9.0.2/32

wg1.conf

[Interface]
Address = 10.9.1.1/24
PrivateKey = zzz

PostUp = sysctl net.ipv4.conf.wg1.forwarding=1 net.ipv4.conf.wlan0.forwarding=1
PostUp = sysctl net.ipv6.conf.wlan0.accept_ra=2
PostUp = sysctl net.ipv6.conf.wg1.forwarding=1 net.ipv6.conf.wlan0.forwarding=1
PostUp = iptables -A FORWARD -i wg1 -j ACCEPT; iptables -t nat -A POSTROUTING -s 10.9.1.0/24 -o wlan0 -j MASQUERADE
PostUp = ip6tables -A FORWARD -i wg1 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
#PostUp = ip route add 11.11.11.11/32 via 192.168.0.1 dev wlan0
PostDown = iptables -D FORWARD -i wg1 -j ACCEPT; iptables -t nat -D POSTROUTING -s 10.9.1.0/24 -o wlan0 -j MASQUERADE
PostDown = ip6tables -D FORWARD -i wg1 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o wlan0 -j MASQUERADE
#PostDown = ip route del 11.11.11.11/32

[Peer]
PublicKey = qqq
AllowedIPs = 10.9.1.0/24
Endpoint = 11.11.11.11:7777

# Uncomment the following, if you're behind a NAT and want the connection to be kept alive.
PersistentKeepalive = 25

wg command status:

interface: wg0
  public key: ddd
  private key: (hidden)
  listening port: 51820

peer: yyy
  endpoint: 11.11.11.11:51000
  allowed ips: 10.9.0.2/32
  latest handshake: 1 minute, 48 seconds ago
  transfer: 11.99 MiB received, 397.40 MiB sent

interface: wg1
  public key: ggg
  private key: (hidden)
  listening port: 35999

peer: qqq
  endpoint: 11.11.11.11:7777
  allowed ips: 10.9.1.0/24
  transfer: 0 B received, 525.95 KiB sent
  persistent keepalive: every 25 seconds
8
  • And you might as well provide how you configure WireGuard. If it's done using wg0.conf / wg1.conf files please also provide them (you should redact the keys). If it's done otherwise, please provide how it's done.
    – A.B
    Commented Jan 6 at 13:45
  • @A.B I just added to the question. btw. I do not have nft or nftables command. Commented Jan 6 at 15:59
  • 11.11.11.11 is openwrt router with 2 different interfaces. so both interfaces have completely different private/public keys. Commented Jan 6 at 16:09
  • I added output of wg command. you can see that wg0 is running, but wg1 is trying to send data, but I guess it uses eth0 instead of wlan0. Commented Jan 6 at 16:17
  • one is initiated from wg1, because that ISP has no public IPs. guess they use natting, so I have to initiate address from wg1 to 11.11.11.11. The other one (wg0) is initiated towards rpi. Commented Jan 6 at 16:20

1 Answer 1

0

With the current IPv4 setup as it's running, a policy routing rule relying on layer 4 (UDP port) can be used to have two different routes towards the same server.

So instead of using a route to the server through wlan0 that would also override the one intended to happen through eth0 like:

ip route add 11.11.11.11/32 via 192.168.0.1 dev wlan0

one can instead rely on the WireGuard's source port to route differently, using a rule with a port selector and an alternate routing table selected by this rule. The easiest is choosing a fixed local WireGuard port. It doesn't matter if the remote system sees an other port because of ISP2's NAT: the routing rule matters only on the local system, not on the remote system.

Before the changes, there's no fixed source port and the route to reach 11.11.11.11 port 7777 is through eth0 while the intent is to use wlan0:

# ip route get 11.11.11.11 ipproto udp dport 7777
11.11.11.11 via 192.168.100.1 dev eth0 src 192.168.100.200 uid 0 
    cache 
  • use the fixed port to 51821 on wg1

    by adding this line to the [Interface] section of wg1.conf:

    ListenPort = 51821
    

    and meanwhile for immediate effect:

    wg set wg1 listen-port 51821
    
  • prepare a new routing table (arbitrarily chosen as 1000) with a default route using the Wireless gateway to ISP2:

    ip route add default via 192.168.0.1 dev wlan0 table 1000
    
  • select this routing table when the locally initiated UDP source port is 51821 (iif lo is the special syntax for locally initiated instead of routed/forwarded so this won't disrupt other routed traffic if any that would use this same UDP source port by pure chance).

    ip rule add iif lo ipproto udp sport 51821 lookup 1000
    
  • as Loose Reverse Path Forwarding is already selected (rp_filter=2) there's no further adjustment needed for replies because a default route exists somewhere (even if it's not on the same interface).

    So in both cases replies through wlan0 are fine. Before and after:

    # ip route get iif wlan0 from 11.11.11.11 ipproto udp dport 51821 to 192.168.0.134
    local 192.168.0.134 from 11.11.11.11 dev lo 
        cache <local> iif wlan0 
    

But now after these changes:

# ip route get 11.11.11.11 ipproto udp sport 51821
11.11.11.11 via 192.168.0.1 dev wlan0 table 1000 src 192.168.0.134 uid 0 
    cache 

The traffic, only for UDP source port 51821, meaning only for the wg1 interface, uses wlan0 instead of eth0. The other WireGuard interface won't be affected:

# ip route get 11.11.11.11 ipproto udp sport 51820
11.11.11.11 via 192.168.100.1 dev eth0 src 192.168.100.200 uid 0 
    cache 

The only two commands that have to be run (in addition to the listening port already added in wg1.conf) should probably be integrated as additional PreUp/PostUp/PreDown/PostDown entries in wg1.conf.

5
  • Thanks. I added these configs instead PostUp = ip rule add iif lo ipproto udp dport 7777 lookup 7777 PostDown = ip rule del iif lo ipproto udp dport 7777 lookup 7777 PostUp = ip route add 11.11.11.11/32 via 192.168.0.1 dev wlan0 table 7777 PostDown = ip route del 11.11.11.11/32 table 7777 which is probably not that good (since now it will route all udp 7777 via that table), but I guess I will never need udp 7777 destination other than this wireguard port. Commented Jan 6 at 19:53
  • It is basically what you sad just with destination port. Thanks for your help! Commented Jan 6 at 19:55
  • As you want. Is there a reason you didn't keep the source port? Because I see only advantages on keeping the local source port over the remote destination port as selector. If using PostUp even a local dynamic port can be used (eg: $(wg show %i listen-port) , look for %i in man wg-quick).
    – A.B
    Commented Jan 6 at 19:55
  • somehow after updating dyndns settings, this setup stopped working. It seems that it can receive traffic from 10.9.1.2 in 10.9.1.1, but it seems that 10.9.1.1 cannot send the response back. Both wg0 and wg1 are connected. 10.9.0.2 to 10.9.0.1 traffic works OK. Do you maybe know how could I debug this? Commented May 28 at 12:37
  • Also, this is what I see for non-working wireguard: TX errors 0 dropped 5 overruns 0 carrier 0 collisions 0 Commented May 28 at 12:42

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .