If you don't know what Wireguard is, well, you should. It's fast, easy to setup and highly configurable. We will configure Wireguard for multiple users with various restrictions using iptables.
This should fit most setups (not mine though 😉)
- LAN network:
192.168.1.0/24
(192.168.1.1
=>192.168.1.254
) - LAN DNS server address:
192.168.1.1
- Wireguard is installed (kernel and tools) on a Linux host (it should also work on other platforms though).
- The Linux host address:
192.168.1.10
- The Linux host main interface:
enp4s0
(find it withip a
)
-
Ensure your iptables firewall has its FORWARD table policy set to
DROP
:iptables -P FORWARD DROP
-
Generate a Wireguard private key
echo "Private key: $(wg genkey)"
Private key: OM5BUrGVAswOm/r8asLtdUgJB8rrXflD6TVFL5aGAHk=
-
Create a file /etc/wireguard/wg0.conf (or any other name than
wg0
) with content:[Interface] Address = 10.0.0.1/24 ListenPort = 51820 PrivateKey = OM5BUrGVAswOm/r8asLtdUgJB8rrXflD6TVFL5aGAHk= PostUp = /etc/wireguard/postup.sh PostDown = /etc/wireguard/postdown.sh
Don't forget to replace the
PrivateKey
value with the one you generated -
Create a file /etc/wireguard/postup.sh with content:
WIREGUARD_INTERFACE=wg0 WIREGUARD_LAN=10.0.0.0/24 MASQUERADE_INTERFACE=enp4s0 iptables -t nat -I POSTROUTING -o $MASQUERADE_INTERFACE -j MASQUERADE -s $WIREGUARD_LAN # Add a WIREGUARD_wg0 chain to the FORWARD chain CHAIN_NAME="WIREGUARD_$WIREGUARD_INTERFACE" iptables -N $CHAIN_NAME iptables -A FORWARD -j $CHAIN_NAME # Accept related or established traffic iptables -A $CHAIN_NAME -o $WIREGUARD_INTERFACE -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT # Accept traffic from any Wireguard IP address connected to the Wireguard server iptables -A $CHAIN_NAME -s $WIREGUARD_LAN -i $WIREGUARD_INTERFACE -j ACCEPT # Drop everything else coming through the Wireguard interface iptables -A $CHAIN_NAME -i $WIREGUARD_INTERFACE -j DROP # Return to FORWARD chain iptables -A $CHAIN_NAME -j RETURN
-
Create a file /etc/wireguard/postdown.sh with content:
WIREGUARD_INTERFACE=wg0 WIREGUARD_LAN=10.0.0.0/24 MASQUERADE_INTERFACE=enp4s0 CHAIN_NAME="WIREGUARD_$WIREGUARD_INTERFACE" iptables -t nat -D POSTROUTING -o $MASQUERADE_INTERFACE -j MASQUERADE -s $WIREGUARD_LAN # Remove and delete the WIREGUARD_wg0 chain iptables -D FORWARD -j $CHAIN_NAME iptables -F $CHAIN_NAME iptables -X $CHAIN_NAME
-
Start the Wireguard server (without any client configured yet):
wg-quick up wg0
Let's setup a client with full access to Internet and your LAN through Wireguard.
-
Install Wireguard on your client device
-
On your client device, create a configuration file client.conf with content:
[Interface] Address = 10.0.0.2/32 DNS = 192.168.1.1 PrivateKey = YOUR_CLIENT_PRIVATE_KEY [Peer] AllowedIPs = 0.0.0.0/0, ::/0 Endpoint = 192.168.1.10:51820 PersistentKeepalive = 25 PublicKey = YOUR_SERVER_PUBLIC_KEY
-
Replace in the configuration above
YOUR_SERVER_PUBLIC_KEY
with the key shown usingwg show wg0 public-key
on your server. For example:p6aGalk69yCM8vNhbvC5mEH/HhJr1c8f55UaeJSChX0=
. -
Generate keys for your client:
priv=`wg genkey` && printf "Private key: $priv\nPublic key: `echo "$priv" | wg pubkey`\n" && unset -v priv
Private key: 2L4L8YwusK4Ot4jVoo/1wwQfLAeRM6kJ/WWxzfnWKm4= Public key: GmVyaj+K36xEk7ko/8jijMB9XX9dFgi4mJxsAEFMHmA=
-
Replace in client.conf
YOUR_CLIENT_PRIVATE_KEY
with the private key just generated above. -
Use the public key shown above to add the following block to /etc/wireguard/wg0.conf on your server:
[Peer] # Your first admin client PublicKey = GmVyaj+K36xEk7ko/8jijMB9XX9dFgi4mJxsAEFMHmA= AllowedIPs = 10.0.0.2/32
-
On your server, restart Wireguard:
wg-quick down wg0 && wg-quick up wg0
. -
You should now be able to connect to the Wireguard server from your client. You can check on the server with
wg
and it should show alatest handshake
line.
Let's add a user who should only have access to the LAN.
-
Repeat steps 1 to 5 from the First admin client section above.
-
Use the public key shown in step 4 to add the following block to /etc/wireguard/wg0.conf on your server:
[Peer] # LAN only user PublicKey = 7GneIV/Od7WEKfTpIXr+rTzPf3okaQTBwsfBs5Eqiyw= AllowedIPs = 10.0.0.3/32
-
Shutdown Wireguard:
wg-quick down wg0
-
Modify /etc/wireguard/postup.sh:
-
Limit full access to our first admin client
10.0.0.2
only by changing:iptables -A $CHAIN_NAME -s 10.0.0.0/24 -i $WIREGUARD_INTERFACE -j ACCEPT
to
iptables -A $CHAIN_NAME -s 10.0.0.2 -i $WIREGUARD_INTERFACE -j ACCEPT
-
Add a new line to allow our new user to LAN access only
iptables -A $CHAIN_NAME -s 10.0.0.3 -i $WIREGUARD_INTERFACE -d 192.168.1.0/24 -j ACCEPT
-
-
Start Wireguard:
wg-quick up wg0
-
Note that the client should set its
AllowedIPs = 0.0.0.0/0, ::/0
toAllowedIPs = 192.168.1.0/24
so it tunnels only to when trying to reach an address on the LAN.
Let's re-use the user we previously created. Let's only allow him to access port 445 (Samba) on a server 192.168.1.20
for example.
-
Shutdown Wireguard:
wg-quick down wg0
-
Modify
iptables -A $CHAIN_NAME -s 10.0.0.3 -i $WIREGUARD_INTERFACE -d 192.168.1.0/24 -j ACCEPT
to
iptables -A $CHAIN_NAME -s 10.0.0.3 -i $WIREGUARD_INTERFACE -d 192.168.10.20 -p tcp --dport 445 -j ACCEPT
-
Start Wireguard:
wg-quick up wg0
That's useful for our friends who want to stream restricted content on Netflix without allowing them on your LAN 😉
-
Shutdown Wireguard:
wg-quick down wg0
-
Modify
iptables -A $CHAIN_NAME -s 10.0.0.3 -i $WIREGUARD_INTERFACE -d 192.168.10.20 -p tcp --dport 445 -j ACCEPT
to
# DNS iptables -A $CHAIN_NAME -s 10.0.0.3 -i $WIREGUARD_INTERFACE -d 192.168.1.1 -p udp --dport 53 -j ACCEPT # Drop traffic to your any private IP address iptables -A $CHAIN_NAME -s 10.0.0.3 -i $WIREGUARD_INTERFACE -d 10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 -j DROP # Accept outgoing connections to HTTP(S) ports to any IP address (public because of rule above) iptables -A $CHAIN_NAME -s 10.0.0.3 -i $WIREGUARD_INTERFACE -d 0.0.0.0/0 -p tcp -m multiport --dports 80,443 -j ACCEPT
-
Start Wireguard:
wg-quick up wg0
-
Don't forget to set back the client to
AllowedIPs = 0.0.0.0/0, ::/0
Feel free to comment, I'll try my best to make you a rule 😉
Enjoy!
With Netflix having announced a crackdown on account sharing, I've set up a Wireguard user for my friends to log in with every now and then to let Netflix know, that their devices are in my home (have the same external ip) similar to the "Restrict the user to limited Web browsing only"-section.
I had to to it directly via iptables, as Wireguard wouldn't start with the postup.sh and postdown.sh in the wg0.conf. But that's okay I guess, since Wireguard runs 24/7 anyways.
Yet the next step was to restrict the the Wireguard users' permissions to only be able to use Netflix. I whitelisted the ip-ranges and ports from here, but I couldn't get Netflix to work.
I'm not sure whether these ip-ranges are somewhat regional (US?) and I would need different ips, since I'm in Europe. Also I know that Netflix has servers directly at ISPs acting as proxies in order to be closer to the end user. But I don't know if the end user "sees" their ips.
I don't know about the rest of the world. Here in Germany Netflix has not yet rolled out their anti-account-sharing-measures. But once they do, this use case, I'm describing, might not be all that extraordinary.
So if somebody has an idea what to forward in order to make Netflix work, I'd appreciate a hint :)
(I've tried the following workaround:
This wouldn't have been a good solution anyway, since all you'd need to bypass it, is to configure your own dns in your Wireguard client.)