0

What needs to be allowed in firewalld so that WireGuard clients can connect to each other via SSH?


The Setup

I have two clients and a server on a WireGuard VPN network. All of them are running Debian 11.

CLIENT A -------- SERVER -------- CLIENT B
10.0.1.2         10.0.1.1         10.0.1.3

What Can Be Done

  • I can SSH from either client to the server.
  • I can SSH from the server to either client.

Problem: But when I try to SSH client to client, I get, "ssh: connect to host 10.0.1.2 port 22: No route to host"


Troubleshooting

  1. The path between the machines is up because I can ping...
    • client to server,
    • server to client,
    • and client to client.
  2. The ports are accessible because I can telnet...
    • from the server to either client on port 22.
    • from either client to the server on port 22.

Problem: But when I try to telnet client to client, I get "telnet: Unable to connect to remote host: No route to host"


What Has Been Confirmed

  • SSH is a listed service on firewalld: firewall-cmd --list-services returns ssh
  • ip-foward is set on the kernel: sysctl -a returns net.ipv4.ip_forward = 1
  • Forwarding is set on the iptables: iptables-save returns -A FORWARD -i wg0 -o wg0 -j ACCEPT
  • Disabling firewalld on the server DOES allow an SSH connection between the two WireGuard clients.

Thanks for your help and pointers.

user371793
  • 27
  • 4

1 Answers1

1

While firewalld is generally an excellent tool for configuring the firewall on a Linux box, for this particular use case -- forwarding traffic for other hosts -- it's kind of a pain in the neck to use. I would suggest turning it off on your server, and just using iptables (or nftables) directly.

If you really want to use firewalld, however, try this (as root):

1. Create a custom zone for your WireGuard interface that accepts all traffic:
firewall-cmd --permanent --new-zone=mywg
firewall-cmd --permanent --zone=mywg --set-target=ACCEPT
firewall-cmd --reload
2. Add "rich" rules to the zone to reject inbound connections from WireGuard to the server itself:
firewall-cmd --zone=mywg --add-rich-rule='rule family="ipv4" priority="30001" protocol value="tcp" reject'
firewall-cmd --zone=mywg --add-rich-rule='rule family="ipv4" priority="30002" protocol value="udp" reject'
firewall-cmd --zone=mywg --add-rich-rule='rule family="ipv6" priority="30003" protocol value="tcp" reject'
firewall-cmd --zone=mywg --add-rich-rule='rule family="ipv6" priority="30004" protocol value="udp" reject'
3. Add "direct" rules to allow forwarding of IPv4 SSH connections between other WireGuard hosts, and reject everything else:
firewall-cmd --direct --add-rule ipv4 filter FORWARD 0 -i wg0 -m state --state ESTABLISHED,RELATED -j ACCEPT
firewall-cmd --direct --add-rule ipv4 filter FORWARD 1 -i wg0 -o wg0 -m state --state NEW -p tcp --dport 22 -j ACCEPT
firewall-cmd --direct --add-rule ipv4 filter FORWARD 2 -i wg0 -j REJECT
firewall-cmd --direct --add-rule ipv6 filter FORWARD 0 -i wg0 -j REJECT
4. Bind the zone to your WireGuard interface and save your changes:
firewall-cmd --zone=mywg --add-interface=wg0
firewall-cmd --runtime-to-permanent

You can add more IPv4 direct rules between 0 and 2 (renumbering the REJECT rule to be last) if you want to allow other types of traffic between your WireGuard hosts (or just replace rules 0 and 1 with a single rule like -i wg0 -o wg0 -J ACCEPT if you want to allow the server to forward any and all traffic between your WireGuard hosts).

See Hub and Spoke section of this How to Use WireGuard With Firewalld article for a full explanation (Host C is your server in this article).

user371793
  • 27
  • 4
Justin Ludwig
  • 1,006
  • 7
  • 8