Nixpkgs version
Describe the bug
On Pop!_OS I was using
define EXCLUDED_IPS = {
192.168.0.0/16
}
table inet MullvadExcludeTraffic {
chain excludeOutgoing {
type route hook output priority 0; policy accept;
ip daddr $EXCLUDED_IPS ct mark set 0x00000f41 meta mark set 0x6d6f6c65;
}
}
from https://mullvad.net/en/help/split-tunneling-with-linux-advanced to allow local network communications. But now with networking.firewall.enable = true; on NixOS it doesn't work. I didn't speak iptables, and I sure don't speak nftables.
full ruleset
table inet nixos-fw {
set temp-ports {
type inet_proto . inet_service
flags interval
auto-merge
comment "Temporarily opened ports"
}
chain rpfilter {
type filter hook prerouting priority mangle + 10; policy drop;
meta nfproto ipv4 udp sport . udp dport { 68 . 67, 67 . 68 } accept comment "DHCPv4 client/server"
fib saddr . mark . iif oif exists accept
jump rpfilter-allow
}
chain rpfilter-allow {
}
chain input {
type filter hook input priority filter; policy drop;
iifname "lo" accept comment "trusted interfaces"
ct state vmap { invalid : drop, established : accept, related : accept, new : jump input-allow, untracked : jump input-allow }
tcp flags & (fin | syn | rst | ack) == syn log prefix "refused connection: " level info
}
chain input-allow {
udp dport 5353 accept
meta l4proto . th dport @temp-ports accept
icmp type echo-request accept comment "allow ping"
icmpv6 type != { nd-redirect, 139 } accept comment "Accept all ICMPv6 messages except redirects and node information queries (type 139). See RFC 4890, section 4.4."
ip6 daddr fe80::/64 udp dport 546 accept comment "DHCPv6 client"
}
}
table inet MullvadExcludeTraffic {
chain excludeOutgoing {
type route hook output priority filter; policy accept;
ip daddr 192.168.0.0/16 ct mark set 0x00000f41 meta mark set 0x6d6f6c65
}
}
table inet mangle {
chain output {
type route hook output priority mangle; policy accept;
meta l4proto != tcp ct state related,new queue flags bypass to 0
tcp flags & (fin | syn | rst | ack) == syn queue flags bypass to 0
}
}
table inet filter {
chain input {
type filter hook input priority filter; policy accept;
udp sport 53 queue flags bypass to 0
}
}
table inet mullvad {
chain prerouting {
type filter hook prerouting priority -199; policy accept;
iif != "wg0-mullvad" ct mark 0x00000f41 meta mark set 0x6d6f6c65
ip saddr 149.88.104.2 udp sport 41113 meta mark set 0x6d6f6c65
}
chain output {
type filter hook output priority filter; policy drop;
oif "lo" accept
ct mark 0x00000f41 accept
udp sport 68 ip daddr 255.255.255.255 udp dport 67 accept
ip6 saddr fe80::/10 udp sport 546 ip6 daddr ff02::1:2 udp dport 547 accept
ip6 saddr fe80::/10 udp sport 546 ip6 daddr ff05::1:3 udp dport 547 accept
ip6 daddr ff02::2 icmpv6 type nd-router-solicit icmpv6 code 0 accept
ip6 daddr ff02::1:ff00:0/104 icmpv6 type nd-neighbor-solicit icmpv6 code 0 accept
ip6 daddr fe80::/10 icmpv6 type nd-neighbor-solicit icmpv6 code 0 accept
ip6 daddr fe80::/10 icmpv6 type nd-neighbor-advert icmpv6 code 0 accept
ip daddr 149.88.104.2 udp dport 41113 meta mark 0x6d6f6c65 accept
oif "wg0-mullvad" udp dport 53 ip daddr 10.64.0.1 accept
oif "wg0-mullvad" tcp dport 53 ip daddr 10.64.0.1 accept
udp dport 53 reject
tcp dport 53 reject with tcp reset
oif "wg0-mullvad" accept
reject
}
chain input {
type filter hook input priority filter; policy drop;
iif "lo" accept
ct mark 0x00000f41 accept
udp sport 67 udp dport 68 accept
ip6 saddr fe80::/10 udp sport 547 ip6 daddr fe80::/10 udp dport 546 accept
ip6 saddr fe80::/10 icmpv6 type nd-router-advert icmpv6 code 0 accept
ip6 saddr fe80::/10 icmpv6 type nd-redirect icmpv6 code 0 accept
ip6 saddr fe80::/10 icmpv6 type nd-neighbor-solicit icmpv6 code 0 accept
icmpv6 type nd-neighbor-advert icmpv6 code 0 accept
ip saddr 149.88.104.2 udp sport 41113 ct state established accept
iif "wg0-mullvad" accept
}
chain forward {
type filter hook forward priority filter; policy drop;
ct mark 0x00000f41 accept
udp sport 68 ip daddr 255.255.255.255 udp dport 67 accept
udp sport 67 udp dport 68 accept
ip6 saddr fe80::/10 udp sport 546 ip6 daddr ff02::1:2 udp dport 547 accept
ip6 saddr fe80::/10 udp sport 546 ip6 daddr ff05::1:3 udp dport 547 accept
ip6 saddr fe80::/10 udp sport 547 ip6 daddr fe80::/10 udp dport 546 accept
ip6 daddr ff02::2 icmpv6 type nd-router-solicit icmpv6 code 0 accept
ip6 saddr fe80::/10 icmpv6 type nd-router-advert icmpv6 code 0 accept
ip6 saddr fe80::/10 icmpv6 type nd-redirect icmpv6 code 0 accept
ip6 daddr ff02::1:ff00:0/104 icmpv6 type nd-neighbor-solicit icmpv6 code 0 accept
ip6 daddr fe80::/10 icmpv6 type nd-neighbor-solicit icmpv6 code 0 accept
ip6 saddr fe80::/10 icmpv6 type nd-neighbor-solicit icmpv6 code 0 accept
ip6 daddr fe80::/10 icmpv6 type nd-neighbor-advert icmpv6 code 0 accept
icmpv6 type nd-neighbor-advert icmpv6 code 0 accept
oif "wg0-mullvad" udp dport 53 ip daddr 10.64.0.1 accept
oif "wg0-mullvad" tcp dport 53 ip daddr 10.64.0.1 accept
udp dport 53 reject
tcp dport 53 reject with tcp reset
oif "wg0-mullvad" accept
iif "wg0-mullvad" ct state established accept
reject
}
chain mangle {
type route hook output priority mangle; policy accept;
oif "wg0-mullvad" udp dport 53 ip daddr 10.64.0.1 accept
oif "wg0-mullvad" tcp dport 53 ip daddr 10.64.0.1 accept
meta cgroup 5087041 ct mark set 0x00000f41 meta mark set 0x6d6f6c65
}
chain nat {
type nat hook postrouting priority srcnat; policy accept;
oif "wg0-mullvad" ct mark 0x00000f41 drop
oif != "lo" ct mark 0x00000f41 masquerade
}
}
config
services.mullvad-vpn.enable = true;
networking.nftables = {
enable = true;
ruleset = "
define EXCLUDED_IPS = {
192.168.0.0/16
}
table inet MullvadExcludeTraffic {
chain excludeOutgoing {
type route hook output priority 0; policy accept;
ip daddr $EXCLUDED_IPS ct mark set 0x00000f41 meta mark set 0x6d6f6c65;
}
}
";
};
Steps to reproduce
nixos-rebuild switch --use-remote-sudo
- connect to Mullvad VPN
- ping localnode
Expected behaviour
I should be able to access nodes in the local network.
Screenshots
No response
Relevant log output
Additional context
I think that an appropriate option should be added for such exclusion method and link to https://mullvad.net/en/help/split-tunneling-with-linux-advanced in the documentation. This will make the set up experience very smooth.
System metadata
- system:
"x86_64-linux"
- host os:
Linux 6.12.11, NixOS, 25.05 (Warbler), 25.05.20250129.9d3ae80
- multi-user?:
yes
- sandbox:
yes
- version:
nix-env (Nix) 2.24.12
- nixpkgs:
/nix/store/pgg4vm83q0kr4hxzcwhdgdiv2yfnh3dw-source
Notify maintainers
Note for maintainers: Please tag this issue in your pull request description. (i.e. Resolves #ISSUE.)
I assert that this issue is relevant for Nixpkgs
Is this issue important to you?
Add a 👍 reaction to issues you find important.
Nixpkgs version
Describe the bug
On Pop!_OS I was using
from https://mullvad.net/en/help/split-tunneling-with-linux-advanced to allow local network communications. But now with
networking.firewall.enable = true;on NixOS it doesn't work. I didn't speak iptables, and I sure don't speak nftables.full ruleset
config
Steps to reproduce
nixos-rebuild switch --use-remote-sudoExpected behaviour
I should be able to access nodes in the local network.
Screenshots
No response
Relevant log output
Additional context
I think that an appropriate option should be added for such exclusion method and link to https://mullvad.net/en/help/split-tunneling-with-linux-advanced in the documentation. This will make the set up experience very smooth.
System metadata
"x86_64-linux"Linux 6.12.11, NixOS, 25.05 (Warbler), 25.05.20250129.9d3ae80yesyesnix-env (Nix) 2.24.12/nix/store/pgg4vm83q0kr4hxzcwhdgdiv2yfnh3dw-sourceNotify maintainers
@arcuru @ymarkus
Note for maintainers: Please tag this issue in your pull request description. (i.e.
Resolves #ISSUE.)I assert that this issue is relevant for Nixpkgs
Is this issue important to you?
Add a 👍 reaction to issues you find important.