Full lockdown mode on linux

Since currently the NymVPN only offers a killswitch option (that, in my opinion, as currently implemented is not secure at all) I would like to implement a full lockdown mode (all traffic MUST go through the VPN or drop, no exception) on linux. Similar to how mullvad implemented it if anyone is familiar with it.

Did anyone already tried to implement this using nftables and can share its setup?

2 Likes

Hello,

unfortunately u need some api/resolver traffic to connect with the nym nodes first.

so this is like nym nodes are designed atm, may it will be possible to reduce this in the future dont know.

i tried this to reduce it on my open wrt device but the most additional restrictions preventing the nym client get an established connection through the nym nodes.

But all in all the most vpn concepts are requiring outside traffic form the tunnel, there are only a few vpns ( i only know perfect privacy but there already dead ) which are able to handle it even during an reboot.

If u re just searching an lockdown killswitch u could playing around with the nym nft tables form the openwrt nym version, which offers during my testing a good reliable leak protection:

nym nft tables

root@OpenWrt:~# nft list table inet nym
table inet nym {
chain input {
type filter hook input priority filter - 10; policy accept;
iifname “lo” accept
ct state established,related accept
udp sport 67 udp dport 68 accept
udp dport 67 accept
udp sport 547 udp dport 546 accept
udp dport 547 accept
icmpv6 type nd-router-advert accept
icmpv6 type nd-neighbor-solicit accept
icmpv6 type nd-neighbor-advert accept
icmpv6 type nd-redirect accept
ip saddr 185.243.217.200 tcp sport 9000 accept
ip saddr 185.243.217.200 tcp sport 9001 accept
ip saddr 194.182.191.207 tcp sport 9000 accept
ip saddr 194.182.191.207 tcp sport 9001 accept
ip saddr 185.243.217.200 udp sport 4443 accept
iifname “nym0” ip saddr 9.9.9.9 udp sport 53 accept
iifname “nym0” ip saddr 9.9.9.9 tcp sport 53 accept
iifname “nym0” ip saddr 9.9.9.9 tcp sport 853 accept
iifname “nym0” ip saddr 9.9.9.9 tcp sport 443 accept
iifname “nym1” ip saddr 9.9.9.9 udp sport 53 accept
iifname “nym1” ip saddr 9.9.9.9 tcp sport 53 accept
iifname “nym1” ip saddr 9.9.9.9 tcp sport 853 accept
iifname “nym1” ip saddr 9.9.9.9 tcp sport 443 accept
iifname “nym0” ip saddr 149.112.112.112 udp sport 53 accept
iifname “nym0” ip saddr 149.112.112.112 tcp sport 53 accept
iifname “nym0” ip saddr 149.112.112.112 tcp sport 853 accept
iifname “nym0” ip saddr 149.112.112.112 tcp sport 443 accept
iifname “nym1” ip saddr 149.112.112.112 udp sport 53 accept
iifname “nym1” ip saddr 149.112.112.112 tcp sport 53 accept
iifname “nym1” ip saddr 149.112.112.112 tcp sport 853 accept
iifname “nym1” ip saddr 149.112.112.112 tcp sport 443 accept
iifname “nym0” ip saddr 1.1.1.1 udp sport 53 accept
iifname “nym0” ip saddr 1.1.1.1 tcp sport 53 accept
iifname “nym0” ip saddr 1.1.1.1 tcp sport 853 accept
iifname “nym0” ip saddr 1.1.1.1 tcp sport 443 accept
iifname “nym1” ip saddr 1.1.1.1 udp sport 53 accept
iifname “nym1” ip saddr 1.1.1.1 tcp sport 53 accept
iifname “nym1” ip saddr 1.1.1.1 tcp sport 853 accept
iifname “nym1” ip saddr 1.1.1.1 tcp sport 443 accept
iifname “nym0” ip saddr 1.0.0.1 udp sport 53 accept
iifname “nym0” ip saddr 1.0.0.1 tcp sport 53 accept
iifname “nym0” ip saddr 1.0.0.1 tcp sport 853 accept
iifname “nym0” ip saddr 1.0.0.1 tcp sport 443 accept
iifname “nym1” ip saddr 1.0.0.1 udp sport 53 accept
iifname “nym1” ip saddr 1.0.0.1 tcp sport 53 accept
iifname “nym1” ip saddr 1.0.0.1 tcp sport 853 accept
iifname “nym1” ip saddr 1.0.0.1 tcp sport 443 accept
iifname “nym0” accept
iifname != “nym0” ip daddr 10.1.98.57 drop
iifname “nym1” accept
iifname != “nym1” ip daddr 10.1.75.243 drop
ip saddr 10.0.0.0/8 accept
ip saddr 172.16.0.0/12 accept
ip saddr 192.168.0.0/16 accept
ip6 saddr fe80::/10 accept
ip6 saddr fc00::/7 accept
}

    chain output {
            type filter hook output priority filter - 10; policy accept;
            oifname "lo" accept
            udp sport 68 udp dport 67 accept
            udp sport 67 udp dport 68 accept
            udp sport 546 udp dport 547 accept
            udp sport 547 udp dport 546 accept
            icmpv6 type nd-router-solicit accept
            icmpv6 type nd-neighbor-solicit accept
            icmpv6 type nd-neighbor-advert accept
            ip daddr 185.243.217.200 tcp dport 9000 accept
            ip daddr 185.243.217.200 tcp dport 9001 accept
            ip daddr 194.182.191.207 tcp dport 9000 accept
            ip daddr 194.182.191.207 tcp dport 9001 accept
            ip daddr 185.243.217.200 udp dport 4443 accept
            oifname "nym0" ip daddr 9.9.9.9 udp dport 53 accept
            oifname "nym0" ip daddr 9.9.9.9 tcp dport 53 accept
            oifname "nym0" ip daddr 9.9.9.9 tcp dport 853 accept
            oifname "nym0" ip daddr 9.9.9.9 tcp dport 443 accept
            oifname "nym1" ip daddr 9.9.9.9 udp dport 53 accept
            oifname "nym1" ip daddr 9.9.9.9 tcp dport 53 accept
            oifname "nym1" ip daddr 9.9.9.9 tcp dport 853 accept
            oifname "nym1" ip daddr 9.9.9.9 tcp dport 443 accept
            oifname "nym0" ip daddr 149.112.112.112 udp dport 53 accept
            oifname "nym0" ip daddr 149.112.112.112 tcp dport 53 accept
            oifname "nym0" ip daddr 149.112.112.112 tcp dport 853 accept
            oifname "nym0" ip daddr 149.112.112.112 tcp dport 443 accept
            oifname "nym1" ip daddr 149.112.112.112 udp dport 53 accept
            oifname "nym1" ip daddr 149.112.112.112 tcp dport 53 accept
            oifname "nym1" ip daddr 149.112.112.112 tcp dport 853 accept
            oifname "nym1" ip daddr 149.112.112.112 tcp dport 443 accept
            oifname "nym0" ip daddr 1.1.1.1 udp dport 53 accept
            oifname "nym0" ip daddr 1.1.1.1 tcp dport 53 accept
            oifname "nym0" ip daddr 1.1.1.1 tcp dport 853 accept
            oifname "nym0" ip daddr 1.1.1.1 tcp dport 443 accept
            oifname "nym1" ip daddr 1.1.1.1 udp dport 53 accept
            oifname "nym1" ip daddr 1.1.1.1 tcp dport 53 accept
            oifname "nym1" ip daddr 1.1.1.1 tcp dport 853 accept
            oifname "nym1" ip daddr 1.1.1.1 tcp dport 443 accept
            oifname "nym0" ip daddr 1.0.0.1 udp dport 53 accept
            oifname "nym0" ip daddr 1.0.0.1 tcp dport 53 accept
            oifname "nym0" ip daddr 1.0.0.1 tcp dport 853 accept
            oifname "nym0" ip daddr 1.0.0.1 tcp dport 443 accept
            oifname "nym1" ip daddr 1.0.0.1 udp dport 53 accept
            oifname "nym1" ip daddr 1.0.0.1 tcp dport 53 accept
            oifname "nym1" ip daddr 1.0.0.1 tcp dport 853 accept
            oifname "nym1" ip daddr 1.0.0.1 tcp dport 443 accept
            oifname "nym0" accept
            oifname "nym1" accept
            udp dport 53 reject
            tcp dport 53 reject
            ip daddr 10.0.0.0/8 accept
            ip daddr 172.16.0.0/12 accept
            ip daddr 192.168.0.0/16 accept
            ip6 daddr fe80::/10 accept
            ip6 daddr fc00::/7 accept
            ip daddr 224.0.0.0/4 accept
            ip6 daddr ff00::/8 accept
            reject
    }

    chain forward {
            type filter hook forward priority filter - 10; policy accept;
            oifname "nym0" accept
            iifname "nym0" ct state established,related accept
            oifname "nym1" accept
            iifname "nym1" ct state established,related accept
            meta mark 0x0000014e accept
            udp dport 53 reject
            tcp dport 53 reject
            ip daddr 10.0.0.0/8 accept
            ip daddr 172.16.0.0/12 accept
            ip daddr 192.168.0.0/16 accept
            ip6 daddr fe80::/10 accept
            ip6 daddr fc00::/7 accept
            reject
    }

}

but u may have to also adapt some principles from openwrt to u linux and nftables .
it could be sth. like this.

complete nft table scheme

#!/usr/sbin/nft -f

1. DEFINE YOUR INTERFACES AND SUBNETS

define PHYS_IF = “wlan0” # Your physical hardware interface (e.g., eth0, wlan0)
define LOCAL_LAN = { 192.168.0.0/16, 10.0.0.0/8 } # Your home/local network subnets
define NYM_IF = “nym-tun*” # The virtual mixnet tunnel interface structure

Flush only this custom table if it already exists, avoiding touching main system rules

table inet nym_protection {

# ==========================================
# VECTOR A: ROUTED TRAFFIC LEAK PREVENTION
# ==========================================
chain forward {
    type filter hook forward priority -10; policy drop;
    # Protects containers, VMs, or hot-spotted devices routed through this machine
    iifname "lo" accept
    oifname $NYM_IF accept
}

# ==========================================
# VECTOR B: HOST OUTBOUND LEAK PREVENTION (THE KILL-SWITCH)
# ==========================================
chain output {
    type filter hook output priority -10; policy drop;

    # Always permit internal process loops
    oifname "lo" accept

    # Always permit traffic encrypted inside the Nym mixnet tunnel
    oifname $NYM_IF accept

    # Always allow access to local devices (NAS, local router dashboard, printers)
    ip daddr $LOCAL_LAN oifname $PHYS_IF accept

    # HANDSHAKE ALLOWANCE (Pick ONE option below):
    # Option 1: If running the nym-vpnd daemon under its own isolated user account (Best security)
    skuid "nym" accept
    
    # Option 2: Alternative fallback (Uncomment below if Nym runs as standard root)
    # oifname $PHYS_IF ct state new accept
}

# ==========================================
# VECTOR C: DNS HIJACK RESTRICTION (NAT)
# ==========================================
chain prerouting {
    type nat hook prerouting priority -10; policy accept;
    
    # Intercept local applications or containers attempting to leak DNS 
    # queries around the tunnel over port 53, and force them to the loopback
    iifname != $NYM_IF udp dport 53 redirect to :53
    iifname != $NYM_IF tcp dport 53 redirect to :53
}

}

to create the complete adaption from openwrt with all features its a little bit out of my scope/knowledge sorry.
u can test the nym tables first and then make some leaks tests and may to improve in order to complete ur nft config.

hope that helps
regards

1 Like