Ubuntu – Disable internet access only if its accessed via a VPN on Ubuntu 17

networkingSecurityvpn

Is there a way to prevent my system from using the regular internet and only restrict it to using a VPN only on Ubuntu 17? FYI, I already setup protonvpn via the .ovpn files and currently just connect to it by turning it on with the dropdown in the menu.

I want to force all connections to only use VPN, and if the vpn isn't accessible, it should prevent all types of connections to the internet.

I know it has something to do with setting the routes on the IPv4 section, but I'm not sure what.

enter image description here

Best Answer

  • The solution is to use iptables to deny all outgoing traffic except when the traffic passes through the tunnel.

    If the tunnel is broken, access to the Internet is no longer possible until the tunnel is established again.

    I assume that you’re using TUN-based routing to connect to the OpenVPN server and that you’re using the redirect-gateway OpenVPN client option.

    Create a file anywhere (eg /root/iptables.vpn), you have to change [VPN_IP] and [VPN_PORT] with the ip:port of the vpn server

    *mangle
    :PREROUTING ACCEPT [0:0]
    :INPUT ACCEPT [0:0]
    :FORWARD ACCEPT [0:0]
    :OUTPUT ACCEPT [0:0]
    :POSTROUTING ACCEPT [0:0]
    COMMIT
    
    *nat
    :PREROUTING ACCEPT [0:0]
    :INPUT ACCEPT [0:0]
    :OUTPUT ACCEPT [0:0]
    :POSTROUTING ACCEPT [0:0]
    COMMIT
    
    # Set a default DROP policy.
    *filter
    :INPUT DROP [0:0]
    :FORWARD DROP [0:0]
    :OUTPUT DROP [0:0]
    
    # Allow basic INPUT traffic.
    -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    -A INPUT -i lo -j ACCEPT
    -A INPUT -p icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT
    
    # Allow basic OUTPUT traffic.
    -A OUTPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    -A OUTPUT -o lo -j ACCEPT
    -A OUTPUT -p icmp -j ACCEPT
    
    # Allow traffic to the OpenVPN server and via the tunnel.
    -A OUTPUT -o tun+ -j ACCEPT
    -A OUTPUT -p udp -m udp -d [VPN_IP] --dport [VPN_PORT] -j ACCEPT
    
    # Reject everything else.
    -A INPUT -m conntrack --ctstate INVALID -j DROP
    -A INPUT -j REJECT --reject-with icmp-port-unreachable
    -A FORWARD -j REJECT --reject-with icmp-port-unreachable
    -A OUTPUT -j REJECT --reject-with icmp-port-unreachable
    COMMIT
    

    After the connection with vpn server is established you have to enable the rules:

    iptables-restore < /root/iptables.vpn
    

    All traffic now will be routed trough the tunnel.

    EDIT As the author write he runs the connection using a network manager like approach, so the problem is that he does not know the remote ip of the server, as it is grabbed from a pool. I think (but for now I have not the time to test this solution) that one approach may be:

    1. Modify the previously created file (in our example /root/iptables.vpn), replacing [VPN_IP] with $route_vpn_gateway and [VPN_PORT] with $remote_port
    2. Create a script (eg /etc/openvpn/route.sh):
    while read line
      do eval "echo ${line}"
    done < /root/iptables.vpn | /sbin/iptables-restore -v
    

    (https://stackoverflow.com/questions/5289665/use-external-file-with-variables)

    1. Modify (and then reload) your .openvpn file appending:

    script-security 2

    /etc/openvpn/route.sh

    (How do I run a script after OpenVPN has connected successfully?)

    The script will run every time the connection to the vpn is established.

    As mentioned I've not tested this...

    Remember to flush your iptables after closing the vpn connection

  • Related Question