I'm trying to implement a set of iptables rules for OpenVPN:

  1. Everything (without exception) goes through OpenVPN
  2. If OpenVPN is down or inaccessible everything (without exception) cannot access the internet
  3. Local access is always possible, irrespective of the status of OpenVPN

The best (out of six examples) I've seen so far is this, however it still allows access to the internet when the VPN is down through ipv6:

# Clean down existing rules iptables -P INPUT ACCEPT iptables -P FORWARD ACCEPT iptables -P OUTPUT ACCEPT iptables -t nat -F iptables -t mangle -F iptables -F iptables -X ip6tables -P INPUT ACCEPT ip6tables -P FORWARD ACCEPT ip6tables -P OUTPUT ACCEPT ip6tables -t nat -F ip6tables -t mangle -F ip6tables -F ip6tables -X # Allow loopback device (internal communication) iptables -A INPUT -i lo -j ACCEPT iptables -A OUTPUT -o lo -j ACCEPT # Allow all local traffic. iptables -A INPUT -s 192.168.0.0/16 -j ACCEPT iptables -A OUTPUT -d 192.168.0.0/16 -j ACCEPT # Allow VPN establishment iptables -A OUTPUT -p udp --dport 1194 -j ACCEPT iptables -A INPUT -p udp --sport 1194 -j ACCEPT # Accept all TUN connections (tun = VPN tunnel) iptables -A OUTPUT -o tun+ -j ACCEPT iptables -A INPUT -i tun+ -j ACCEPT # Set default policies to drop all communication unless specifically allowed iptables -P INPUT DROP iptables -P OUTPUT DROP iptables -P FORWARD DROP 

If I try to blanket block all ipv6 traffic (which is what a number of examples suggest) then I cannot connect to anything:

# Set default policies to drop all communication unless specifically allowed ip6tables -P INPUT DROP ip6tables -P OUTPUT DROP ip6tables -P FORWARD DROP 

If I try to mirror what is in the ipv4 section then I have this:

# Allow loopback device (internal communication) ip6tables -A INPUT -i lo -j ACCEPT ip6tables -A OUTPUT -o lo -j ACCEPT # Allow all local traffic. # (Skipped as I don't know how to do this) # Allow VPN establishment ip6tables -A OUTPUT -p udp --dport 1194 -j ACCEPT ip6tables -A INPUT -p udp --sport 1194 -j ACCEPT # Accept all TUN connections (tun = VPN tunnel) ip6tables -A OUTPUT -o tun+ -j ACCEPT ip6tables -A INPUT -i tun+ -j ACCEPT 

Now I'm unable to connect to anywhere and curl just hangs.

How can I fix this?

4 Answers

Future readers, be aware that the rules presented here "will allow deanonymization because it allows any connection over port 1194, not just traffic originating from OpenVPN". This answer presents a much simpler set of rules which do not require hardcoding any IPs or ports.

It turns out that I'd not whitelisted the DNS servers of the VPN service. Once I did that, I was able to blacklist ipv6 without an issue.

Please note: As per Rock Storm's comment, this is probably not the best way of doing this as it allows any connection over port 1194. See this answer for a better approach which doesn't require hardcoding any IPs or ports - however it needs a further modification to allow local traffic (which, in my case, is allowing input and output for 192.168.0.0/16)

For the sake of completeness, this is what I finally got to work. Three things to bear in mind:

  1. You should replace [Primary DNS IP here] and [Secondary DNS IP here] with the IP addresses of the DNS servers you're planning to use
  2. Don't forget to edit /etc/resolvconf.conf to add the IP addresses in #1 as nameservers and blacklist your own to avoid DNS leakages.
  3. This assumes your local traffic has an IP range starting 192.168. If not, you'll need to change this.

Code as follows:

# Remove any existing rules sudo iptables -P INPUT ACCEPT sudo iptables -P FORWARD ACCEPT sudo iptables -P OUTPUT ACCEPT sudo iptables -t nat -F sudo iptables -t mangle -F sudo iptables -F sudo iptables -X sudo ip6tables -P INPUT ACCEPT sudo ip6tables -P FORWARD ACCEPT sudo ip6tables -P OUTPUT ACCEPT sudo ip6tables -t nat -F sudo ip6tables -t mangle -F sudo ip6tables -F sudo ip6tables -X # Allow loopback device (internal communication) sudo iptables -A INPUT -i lo -j ACCEPT sudo iptables -A OUTPUT -o lo -j ACCEPT # Allow all local traffic sudo iptables -A INPUT -s 192.168.0.0/16 -j ACCEPT sudo iptables -A OUTPUT -d 192.168.0.0/16 -j ACCEPT # Allow DNS (could be VPN provider or someone like Cloudflare's 1.1.1.1) sudo iptables -A OUTPUT -d [Primary DNS IP here] -j ACCEPT sudo iptables -A OUTPUT -d [Secondary DNS IP here] -j ACCEPT # Allow related and established connections sudo iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT # Allow VPN establishment sudo iptables -A OUTPUT -p udp --dport 53 -j ACCEPT sudo iptables -A INPUT -p udp --sport 53 -j ACCEPT sudo iptables -A OUTPUT -p udp --dport 1198 -j ACCEPT sudo iptables -A INPUT -p udp --sport 1198 -j ACCEPT # Accept all tun0 (VPN tunnel) connections sudo iptables -A OUTPUT -o tun0 -j ACCEPT sudo iptables -A INPUT -i tun0 -j ACCEPT # Allow for nslookup to not throw an error sudo ip6tables -I OUTPUT 1 -p udp -s 0000:0000:0000:0000:0000:0000:0000:0001 -d 0000:0000:0000:0000:0000:0000:0000:0001 -j ACCEPT # Drop everything else (ipv4) sudo iptables -P INPUT DROP sudo iptables -P OUTPUT DROP sudo iptables -P FORWARD DROP # Drop everything (ipv6) sudo ip6tables -P INPUT DROP sudo ip6tables -P OUTPUT DROP sudo ip6tables -P FORWARD DROP 

Your example script cleans all rules for IPv4 and IPv6 rulesets... but doesn't add any rules for IPv6.

Notice how the "Clean down existing rules" section calls both iptables and ip6tables, resetting both firewalls to their default "wide open" state. The remaining sections, however, do nothing with ip6tables at all.

3

I just fell over this topic, and have a comment and some additional information.

My objective was to have a VPN connection and killswitch (running on tun0) with a network gateway to share the VPN service on the local lan..on the server ip (used as gateway on various PCs and TVs. etc)

But I would also like to access the server over SSH on the WAN IP!

I also what to run a second private VPN on tun1, so I can access my local LAN from anywhere.

So. I run a VPN client with killswitch and gateway and a VPN server. And I have full VPN and SSH access on the global WAN IP

This complicate things a bit.

Also the line

#Allow related and established connections sudo iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 

Will disable the killswitch sever side!!!. The gateway is ok, but programs link a torrent-client etc, will still have access to the net if the main vpn is down.

Here is my solution

IT works pretty well.

Can any iptables gurus find any loopholes etc in the setup then please comment.

I have made it as a script to active the setup. It makes it a bit more easy when debugging and setting to no firewall. Its not really persistent, so either commit it properly or run on startup with systemd.

#!/bin/sh #A link to this script runs as a systemd runscript #Here: #nano /usr/local/bin/fwmark.sh echo running NEW set_iptabels # Clean down existing rules iptables -P INPUT ACCEPT iptables -P FORWARD ACCEPT iptables -P OUTPUT ACCEPT iptables -t nat -F iptables -t nat -X iptables -t mangle -F iptables -F iptables -X ip6tables -P INPUT ACCEPT ip6tables -P FORWARD ACCEPT ip6tables -P OUTPUT ACCEPT ip6tables -t nat -F ip6tables -t nat -X ip6tables -t mangle -F ip6tables -F ip6tables -X #Start Killswitch configuration # Allow loopback device (internal communication) iptables -A INPUT -i lo -j ACCEPT iptables -A OUTPUT -o lo -j ACCEPT # Allow all local traffic iptables -A INPUT -s 192.168.0.0/16 -j ACCEPT iptables -A OUTPUT -d 192.168.0.0/16 -j ACCEPT # Allow DNS iptables -A OUTPUT -d 4.2.2.2 -j ACCEPT iptables -A OUTPUT -d 4.2.2.3 -j ACCEPT # Allow related and established connections # DO NOT RUN THIS---LOTS OF GUIDES SAY TO..IT DISABLES THE KILLSWITCH SERVER SIDE. GATEWAY IS OK SEVER NOT!!!!!!!! #### DONT RUN >>iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT # Allow VPN establishment iptables -A OUTPUT -p udp --dport 53 -j ACCEPT iptables -A INPUT -p udp --sport 53 -j ACCEPT iptables -A OUTPUT -p udp --dport 1912 -j ACCEPT iptables -A INPUT -p udp --sport 1912 -j ACCEPT # Accept all tun0 (VPN tunnel) connections iptables -A OUTPUT -o tun0 -j ACCEPT iptables -A INPUT -i tun0 -j ACCEPT # Allow for nslookup to not throw an error ip6tables -I OUTPUT 1 -p udp -s 0000:0000:0000:0000:0000:0000:0000:0001 -d 0000:0000:0000:0000:0000:0000:0000:0001 -j ACCEPT # Drop everything else (ipv4) iptables -P INPUT DROP iptables -P OUTPUT DROP iptables -P FORWARD DROP # Drop everything (ipv6) ip6tables -P INPUT DROP ip6tables -P OUTPUT DROP ip6tables -P FORWARD DROP #End Killswitch #Gatewate forward #ssh port 80 etc are set to route to enp6s0 via mark 65 rule created here: ip rule add fwmark 65 table novpn > /dev/null 2>&1; ip route add default via 192.168.1.1 dev enp6s0 table novpn > /dev/null 2>&1; ip route flush cache > /dev/null 2>&1; #VPN Gateway iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE iptables -A FORWARD -i tun0 -o enp6s0 -m state --state RELATED,ESTABLISHED -j ACCEPT iptables -A FORWARD -i enp6s0 -o tun0 -j ACCEPT #Set connection port for Access from WAN #ssh force private global IP IN AND OUT iptables -A INPUT -p tcp --sport 22 -j ACCEPT iptables -A INPUT -p tcp --dport 22 -j ACCEPT iptables -A OUTPUT -o enp6s0 -p tcp -m tcp --sport 22 -m comment --comment "ssh-22" -j ACCEPT iptables -A OUTPUT -o enp6s0 -p tcp -m tcp --dport 22 -m comment --comment "ssh-22" -j ACCEPT iptables -t mangle -A OUTPUT -p tcp --sport 22 -j MARK --set-mark 65 iptables -t mangle -A OUTPUT -p tcp --sport 22 -j MARK --set-mark 65 iptables -A INPUT -i tun0 -p tcp -m tcp --sport 22 -j DROP iptables -A INPUT -i tun0 -p tcp -m tcp --dport 22 -j DROP iptables -A OUTPUT -o tun0 -p tcp -m tcp --sport 22 -j DROP iptables -A OUTPUT -o tun0 -p tcp -m tcp --dport 22 -j DROP #Private VPN ON tun1 IN AND OUT - use TCP! UDP will give endless TLS errors, that are currently unresolved. iptables -A INPUT -p tcp --sport 1194 -j ACCEPT iptables -A INPUT -p tcp --dport 1194 -j ACCEPT iptables -A OUTPUT -o enp6s0 -p tcp -m tcp --sport 1194 -m comment --comment "vpn-1194" -j ACCEPT iptables -A OUTPUT -o enp6s0 -p tcp -m tcp --dport 1194 -m comment --comment "vpn-1194" -j ACCEPT iptables -t mangle -A OUTPUT -p tcp --sport 1194 -j MARK --set-mark 65 iptables -t mangle -A OUTPUT -p tcp --dport 1194 -j MARK --set-mark 65 iptables -A INPUT -i tun0 -p tcp -m tcp --sport 1194 -j DROP iptables -A INPUT -i tun0 -p tcp -m tcp --dport 1194 -j DROP iptables -A OUTPUT -o tun0 -p tcp -m tcp --sport 1194 -j DROP iptables -A OUTPUT -o tun0 -p tcp -m tcp --dport 1194 -j DROP #http force private global IP OUT ONLY iptables -A INPUT -p tcp --sport 80 -j ACCEPT iptables -A INPUT -p tcp --dport 80 -j ACCEPT iptables -t mangle -A OUTPUT -p tcp --sport 80 -j MARK --set-mark 65 iptables -t mangle -A OUTPUT -p tcp --sport 80 -j MARK --set-mark 65 iptables -A INPUT -i tun0 -p tcp -m tcp --sport 80 -j DROP iptables -A INPUT -i tun0 -p tcp -m tcp --dport 80 -j DROP #End WAN access #Specific private VPN server setup on tun1 service Activate with>> openvpn@server start/stop/status #Private VPN Server iptables -t nat -A POSTROUTING -o tun1 -j MASQUERADE iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o enp6s0 -j MASQUERADE iptables -A FORWARD -i tun1 -o enp6s0 -m state --state RELATED,ESTABLISHED -j ACCEPT iptables -A FORWARD -i enp6s0 -o tun1 -j ACCEPT #VPN server forward iptables -A FORWARD -i tun1 -o enp6s0 -s 10.8.0.0/24 -j ACCEPT iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT #Local LAN access iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o enp6s0 -j SNAT --to-source 192.168.1.100 # VPN Server enable tun1 iptables -A INPUT -i tun1 -j ACCEPT iptables -A FORWARD -i tun1 -j ACCEPT iptables -A OUTPUT -o tun1 -j ACCEPT #End Private VPN Server #save and make persistant - remove all putput from logfile iptables-save >/etc/iptables/rules.v4 > /dev/null 2>&1; ip6tables-save >/etc/iptables/rules.v6 > /dev/null 2>&1; netfilter-persistent save > /dev/null 2>&1; 

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy