Linux Firewall (Part 6) : VPN
Intro
In this post, we will use Wireguard to connect to Windscribe using linux network namespaces.
Enabling WireGuard system-wide poses significant risks, as all network traffic, including sensitive data, is routed through the WireGuard interface. This approach creates a single point of failure, access issues and potential vulnerability for the entire system. Moreover, system-wide WireGuard activation can lead to performance issues, particularly on resource-constrained devices or networks with high traffic volumes.
WireGuard’s integration with network namespaces offers a robust solution for enhancing network isolation and security. By deploying WireGuard within dedicated namespaces, users create isolated environments where VPN connections operate independently from the main network. This setup ensures that VPN-related activities remain segregated, reducing the risk of unauthorized access or data leakage. With WireGuard’s lightweight design and efficient performance, users can achieve robust security measures while maintaining flexibility and scalability in their network infrastructure.
We need to setup Wireguard and add some entries in the linux firewall to allow specific traffic. I will use RHEL for this post, but this can be run on most linux distributions with similar steps, for example the Raspberry Pi.
Prerequisites
If you haven’t already, install Wireguard and enable resolved
dnf install wireguard-tools
systemctl enable --now systemd-resolved
Generate private, public and pre-shared keys for WireGuard
cd /etc/wireguard
(umask 077 && wg genkey | tee private.key | wg pubkey > public.key)
(umask 077 && wg genpsk > /etc/wireguard/psk.key)
Download the Wireguard configuration file from your VPN provider, or create one if not provided. It should look something like
wg-sea.conf
[Interface]
PrivateKey = <Private Key>
Address = <IP Address>/32
DNS = <DNS Address>
[Peer]
PublicKey = <Client Public Key>
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = <IP Address or Server Name>:<port>
PresharedKey = <Pre-Shared Key>
Download and install SOCKS v5 server. I will use microsocks for this post.
Wireguard
We are going to name most things with wg-sea
prefix for Seattle location. Let’s create a bash script for setup.
wg-sea-setup.sh
Delete existing network interfaces and namespaces if they exist
ip link delete wg-sea
ip link delete wg-sea.0
ip netns delete wg-sea
Create a network namespace
ip netns add wg-sea
Create a pair of virtual Ethernet devices (wg-sea.0
and wg-sea.1
), with one end (wg-sea.1
) being moved into the network namespace named “wg-sea”
ip link add wg-sea.0 type veth peer name wg-sea.1
ip link set wg-sea.1 netns wg-sea
Assign IP addresses to the virtual Ethernet devices: “192.168.10.1” to wg-sea.0
and “192.168.10.2” to wg-sea.1
within the “wg-sea” network namespace
ip addr add 192.168.10.1/24 dev wg-sea.0
ip -n wg-sea addr add 192.168.10.2/24 dev wg-sea.1
Bring up the network interfaces wg-sea.0
and wg-sea.1
in their respective namespaces (main and “wg-sea”)
ip link set wg-sea.0 up
ip -n wg-sea link set lo up
ip -n wg-sea link set wg-sea.1 up
Add a default route within the “wg-sea” network namespace, directing all traffic to pass through the IP address “192.168.10.1”
ip -n wg-sea route add default via 192.168.10.1
The firewall we configured in Part 2 of this series will block all incoming DNS requests not originating from LAN or DMZ. We need DNS server for name resolution of VPN peers. Our firewall is configured to allow outgoing connections to the internet, so we can use the DNS servers on the internet.
echo "nameserver 1.1.1.1" > /etc/netns/wg-sea/resolv.conf
echo "nameserver 8.8.8.8" >> /etc/netns/wg-sea/resolv.conf
Create a WireGuard interface named “wg-sea” and move it into the “wg-sea” network namespace
ip link add wg-sea type wireguard
ip link set wg-sea netns wg-sea
Read the IP address specified in the WireGuard configuration file /etc/wireguard/wg-sea.conf
and assigns it to the “wg-sea” interface within the “wg-sea” network namespace
ip -n wg-sea addr add $(awk '/^Address/ {print $3}' /etc/wireguard/wg-sea.conf) dev wg-sea
Update the WireGuard configuration for the “wg-sea” interface within the “wg-sea” network namespace by synchronizing it with the stripped-down version of the configuration
ip netns exec wg-sea wg syncconf wg-sea <(wg-quick strip wg-sea)
Bring up the “wg-sea” interface within the “wg-sea” network namespace
ip -n wg-sea link set wg-sea up
Add routes within the “wg-sea” network namespace to direct traffic for IP ranges 0.0.0.0/1 and 128.0.0.0/1 through the “wg-sea” interface.
[!NOTE]
We split the 0.0.0.0/0 block into two separate blocks 0.0.0.0/1 and 128.0.0.0/1 because they are more specific and will override the default route
ip -n wg-sea route add 0.0.0.0/1 dev wg-sea
ip -n wg-sea route add 128.0.0.0/1 dev wg-sea
Extract the DNS server address specified in the WireGuard configuration file /etc/wireguard/wg-sea.conf and uses it to populate the /etc/netns/wg-sea/resolv.conf file used by the “wg-sea” network namespace. This ensures that DNS resolution within the namespace is configured to use the specified DNS server
echo "nameserver $(awk '/^DNS/ {print $3}' /etc/wireguard/wg-sea.conf)" > /etc/netns/wg-sea/resolv.conf
Firewall
Let’s configure nftables. We will start by adding some defines
defines.nft
# interfaces
define if_wg_sea = "wg-sea.0"
# networks
define net_wg_sea = 192.168.10.0/30
# machines
define wg_wsh = 10.0.0.2 # windscribe seattle hendrix
Allow connections going out from Wireguard to WAN and allow connections from LAN to Wireguard
forward.nft
chain forward {
iifname $if_wg_sea oifname $if_wan accept # accept wireguard to wan
iifname $if_lan oifname $if_wg_sea accept # accept lan to wireguard
}
Masquerade traffic going in and out of Wireguard on LAN
nat.nft
chain postrouting {
ip saddr $net_wg_sea oifname $if_wan masquerade # from wg to wan
ip saddr $net_lan oifname $if_wg_sea masquerade # from lan to wg
}
SOCKS5 Sever
Start microsocks in “wg-sea” network namespace so clients can connect to the VPN using SOCKS5
ip netns exec wg-sea microsocks
To configure Firefox to use VPN, go to Firefox Settings > Network Settings. Select Manual proxy configuration for Configure Proxy Access to the Internet. Enter the IP address of the machine where we set up Wireguard. Add port 1080 (default for microsocks) and select SOCKS v5. Select Proxy DNS when using SOCKS v5 and click OK. Firefox will now use the VPN. Turn off anytime by switching back to No Proxy.
Thank you for reading. Check out the other parts in the series below.