1

I am trying to achieve something very similar to iptables - Target to route packet to specific interface? and https://unix.stackexchange.com/questions/21093/output-traffic-on-different-interfaces-based-on-destination-port but I do not get it working.

Here is my setup:

RPi4 (local IP, eth0: 10.0.0.196/24; wireguard IP: 10.10.10.2/24; wireguard interface is named "client") <---> Server (wireguard IP: 10.10.10.1/24, global IPv4) <---> Internet

Here is my testing snippet so far:

systemctl start wg-quick@client.service

sysctl -w net.ipv4.conf.all.rp_filter=0
sysctl -w net.ipv4.conf.client.rp_filter=0

for i in /proc/sys/net/ipv4/conf/*/rp_filter ; do
  echo 0 > $i
done

ip rule add fwmark 2 table 3
ip route add default via 10.10.10.1 table 3
ip route flush cache

iptables -t mangle -A OUTPUT -p tcp --dport 25 -j MARK --set-mark 2
iptables -t nat -A POSTROUTING -o client -j SNAT --to-source 10.10.10.2

If I then try to reach for example

telnet -4 gmail-smtp-in.l.google.com 25
Trying 108.177.119.26...
telnet: Unable to connect to remote host: No route to host

Any other traffic (anything not marked my mark "2") is routed properly via eth0 (not "client") and works fine (like ping 1.1.1.1 and curl ifconfig.me)


Here is what the routing and iptables look like before and after running the snippet above.

BEFORE:

# ip route show table all
default via 10.0.0.1 dev eth0 proto dhcp src 10.0.0.196 metric 100
10.0.0.0/24 dev eth0 proto kernel scope link src 10.0.0.196
10.0.0.1 dev eth0 proto dhcp scope link src 10.0.0.196 metric 100
broadcast 10.0.0.0 dev eth0 table local proto kernel scope link src 10.0.0.196
local 10.0.0.196 dev eth0 table local proto kernel scope host src 10.0.0.196
broadcast 10.0.0.255 dev eth0 table local proto kernel scope link src 10.0.0.196
broadcast 127.0.0.0 dev lo table local proto kernel scope link src 127.0.0.1
local 127.0.0.0/8 dev lo table local proto kernel scope host src 127.0.0.1
local 127.0.0.1 dev lo table local proto kernel scope host src 127.0.0.1
broadcast 127.255.255.255 dev lo table local proto kernel scope link src 127.0.0.1
# iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
# iptables -S -t nat
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P POSTROUTING ACCEPT
-P OUTPUT ACCEPT
# iptables -S -t mangle
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT

AFTER:

# ip route show table all
default via 10.10.10.1 dev client table 3
default via 10.0.0.1 dev eth0 proto dhcp src 10.0.0.196 metric 100
10.0.0.0/24 dev eth0 proto kernel scope link src 10.0.0.196
10.0.0.1 dev eth0 proto dhcp scope link src 10.0.0.196 metric 100
10.10.10.0/24 dev client proto kernel scope link src 10.10.10.2
broadcast 10.0.0.0 dev eth0 table local proto kernel scope link src 10.0.0.196
local 10.0.0.196 dev eth0 table local proto kernel scope host src 10.0.0.196
broadcast 10.0.0.255 dev eth0 table local proto kernel scope link src 10.0.0.196
broadcast 10.10.10.0 dev client table local proto kernel scope link src 10.10.10.2
local 10.10.10.2 dev client table local proto kernel scope host src 10.10.10.2
broadcast 10.10.10.255 dev client table local proto kernel scope link src 10.10.10.2
broadcast 127.0.0.0 dev lo table local proto kernel scope link src 127.0.0.1
local 127.0.0.0/8 dev lo table local proto kernel scope host src 127.0.0.1
local 127.0.0.1 dev lo table local proto kernel scope host src 127.0.0.1
broadcast 127.255.255.255 dev lo table local proto kernel scope link src 127.0.0.1
# ip rule show
0:      from all lookup local
32765:  from all fwmark 0x2 lookup 3
32766:  from all lookup main
32767:  from all lookup default
# iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
# iptables -S -t nat
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P POSTROUTING ACCEPT
-P OUTPUT ACCEPT
-A POSTROUTING -o client -j SNAT --to-source 10.10.10.2
# iptables -S -t mangle
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-A OUTPUT -p tcp -m tcp --dport 25 -j MARK --set-xmark 0x2/0xffffffff
3
  • in my mind its a doubled question which got already answered in the past see: How to port redirect to a other ip
    – djdomi
    Jan 2, 2021 at 12:24
  • If you are using the client in raspberry pi, it will be work. I test your code and I cannot have any problem. Jan 2, 2021 at 23:47
  • Can you try ip route add default via 10.10.10.0/24 dev client table 3 Jan 5, 2021 at 14:22

2 Answers 2

0

Here's a picture of the network packet flow through netfilter's tables. It seems to me that it's not working because the routing decisions is made before the packet passes through your fwmark rule and you can't make it exit through another interface.

You can use policy-based routing directly for that, no need for fwmark. Reading your example correctly, this should redirect all your outgoing SMTP traffic through Wireguard:

iptables -t nat -A POSTROUTING -o client -j SNAT --to-source 10.10.10.2
ip rule add priority 1000 dport 25 table 3
ip route add default via 10.10.10.1 table 3

See man ip-rule for details

-1

I'm understanding your need is just establishing a VPN connection sending all external traffic through the VPN. If I got it right, configure your wireguard this way:

SERVER SIDE (/etc/wireguard/wg0.conf)

[Interface]
PrivateKey = <YOUR PRIVATE KEY HERE>
Address = 10.10.10.1/24
ListenPort = 51820
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; ip6tables -D FORWARD -i wg0 -j ACCEPT

[Peer]
PublicKey = [CLIETS PUBLIC KEY]
AllowedIPs = 10.10.10.2/32   # The client's IP address

CLIENT SIDE (/etc/wireguard/wg0.conf)

[Interface]
PrivateKey = <Output of privatekey file that contains your private key>
Address = 10.10.10.2/24
PostUp = ip route add [SERVER_PUBLIC_IP] via [LOCAL_GATEWAY_IP] dev eth0

[Peer]
PublicKey = <Server Public key>
Endpoint = <Server Public IP>:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepAlive = 25

Note that you need to add a route to sending all traffic targetted to your public wireguard IP through the ethernet, otherwise it will break your client's connection.

The howto below was very helpful to me: How To Set Up WireGuard Firewall Rules in Linux

NOTE 1: In this case, you need to setup NAT MASQUERADE only on the server-side.

NOTE 2: You need to set IP forward on your Linux machines:

sudo echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
sudo sysctl -p
2
  • Thanks but this will forward all traffic through the VPN (I only want to route particular ports through it)
    – bonanza
    Jan 3, 2021 at 16:50
  • @bonanza, You can adjust IPTABLES rules to forward only particular ports, but I don't think that will going to work with wireguard because wireguard will only route for targets listed at AllowedIPs, which will automatically create a route at the system level. Jan 5, 2021 at 22:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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