Friday, May 29, 2020

Forward Traffic from Public IP to Wireguard client behind NAT and Preserve IP

Wiregurad allows us to create virtual network interfaces between nodes that are in separate networks. This feature can be used to expose a server behind NAT with a Public IP address.

The main advantage of the method described in this post is that it preserves clients IP address, so the home server sees the real IP address of clients and can process them (e.g. block them in a firewall).

There are several posts on the internet on this topic however they are not complete, for example the method described in this post does not preserve IP address of clients and shows the wireguard server's IP address in requests instead.

Wireguard allows the Server in NAT accessible via VPS Public IP

I had an asterisk server at home on raspberry pi, and wanted to make it accessible via internet however the internet solution that was used there did not provide a public IP address. It's possible to create a SSH tunnel and forward ports using a VPS in a datacenter however  it would not preserve clients IP address. I wanted to see the real address of clients so that fail2ban can block bruteforce attacks against the asterisk server.

Steps:

VPS Server:
1. Enable net.ipv4.ip_forward on the VPS

2. Wireguard config on the VPS server is simple and does not have anything special:

[Interface]
Address = 10.0.1.1
ListenPort = <Wireguard Listen Port>
PrivateKey = <Wireguard VPS Server Private Key>

# Home
[Peer]
PublicKey = <Wireguard on Home server Public Key>
AllowedIPs = 10.0.1.2/32

where 10.0.1.1 is the local IP address of wireguard on VPS server and 10.0.1.2 is the local IP address of wireguard on Home server behind NAT.

3. Now, to forward Traffic to the VPS server, you need to use the following rules in IP tables : 

# To allow Forwarding IPs in IPtables: 
iptables -A FORWARD -i wg0 -o eth0 -j ACCEPT
iptables -A FORWARD -i eth0 -o wg0 -j ACCEPT

# This rule can be used if it is not needed tp preserve clients IP
# iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE

This rule is needed to provide internet to Home server when preserving clients IP
iptables -t nat -A POSTROUTING -s '10.0.1.0/24' -o eth0 -j MASQUERADE

# Forward TCP / UDP ports here to the server home
# TCP Public:8080 -> Home:443
iptables -t nat -A PREROUTING -p tcp -d VPS.Public.IP.Address --dport 8080 -j DNAT --to-destination 10.0.1.2:443
# TCP Public:8822 -> Home:22
iptables -t nat -A PREROUTING -p tcp -d VPS.Public.IP.Address --dport 8822 -j DNAT --to-destination 10.0.1.2:22
# UDP Public:5060 -> Home:5060
iptables -t nat -A PREROUTING -p udp -d VPS.Public.IP.Address --dport 5060 -j DNAT --to-destination 10.0.1.2:5060
# UDP Range Public:11000-11200 -> Home:11000-11200
iptables -t nat -A PREROUTING -p udp -d VPS.Public.IP.Address --dport 11000:11200 -j DNAT --to-destination 10.0.1.2:11000-11200

Home server in NAT: 
Wireguard config on the Home server is a bit more tricky. 

[Interface]
PrivateKey = <Wireguard on Home server Private Key>
Address = 10.0.1.2

[Peer]
PublicKey = <Wireguard VPS Server Public Key>

# This rule will not preserve clients IP 
# AllowedIPs = 10.0.1.1/24
# This rule will preserve clients IP:
# This is a Sample range, you need to use the script provided below to 
# exclude you VPS IP / Local NAT IP from 0.0.0.0/0 range, then use it here
AllowedIPs = 128.0.0.0/1, 64.0.0.0/2, 32.0.0.0/3, 16.0.0.0/4, 0.0.0.0/5, 12.0.0.0/6, 10.0.0.0/7, 9.0.0.0/8, 8.128.0.0/9, 8.64.0.0/10, 8.32.0.0/11, 8.16.0.0/12, 8.0.0.0/13, 8.12.0.0/14, 8.10.0.0/15, 8.9.0.0/16, 8.8.128.0/17, 8.8.64.0/18, 8.8.32.0/19, 8.8.16.0/20, 8.8.0.0/21, 8.8.12.0/22, 8.8.10.0/23, 8.8.9.0/24, 8.8.8.128/25, 8.8.8.64/26, 8.8.8.32/27, 8.8.8.16/28, 8.8.8.0/29, 8.8.8.12/30, 8.8.8.10/31, 8.8.8.9/32
Endpoint = <VPS PUBLIC IP>:<Wireguard Listen Port>
PersistentKeepalive = 25 

AllowedIPs is the tricky part here. 

One can use AllowedIPs = 10.0.1.1/24 here with iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE  rule in iptables of the VPS, this will let the home server to be accessible through the forwarded ports, however the home server will not see the real IP address of clients, and will  see all requests coming from 10.0.1.1, the IP address of wireguard VPS instead.

To let the home server accessible through the Public IP address of VPS and make it see the real IP address of clients, it is required to route packets that arrive to server home to come back through wireguard. So basically we need to add all IP ranges to AllowedIPs Except VPS IP address and other local network addresses that we dont want to go through wireguard.

It is not possible to use AllowedIPs = 0.0.0.0/0 directly, as wireguard will not be able to connect to our VPS IP address then. We also don't want our Local NAT IP range to go through Wireguard.  So we use the following Shell script to exclude our VPS IP/Local IP range from 0.0.0.0/0 range :

#!/bin/bash
echo "enter the broader range e.g. 176.0.0.0/4"
read r1
echo "enter the exclude ip e.g. 18.20.18.8/32"
read r2
pshell=`cat <<EOF
import ipaddress
n1 = ipaddress.ip_network('$r1')
n2 = ipaddress.ip_network('$r2')
l = list(n1.address_exclude(n2))
print(l)`

python3 -c "$pshell" | sed -e "s,IPv4Network(',,g" | sed -e "s,'),,g" | sed -e "s,\[,,g" | sed -e "s,\],,g"

It requires ipaddress python3 package to work.

How to disable Debian 12 sleep on production servers

 Debian 12 has power saver enabled by default which causes your server to go to sleep if there is no mouse / keyboard interaction. To resolv...