diff --git a/modules/clan/gw-router/firewall.nix b/modules/clan/gw-router/firewall.nix new file mode 100644 index 0000000..d6ebab7 --- /dev/null +++ b/modules/clan/gw-router/firewall.nix @@ -0,0 +1,64 @@ +{ + roles.default.perInstance = { settings, ... }: { + nixosModule = + { + config, + lib, + ... + }: + let + + dir = config.clan.core.settings.directory; + instance = "zerotier"; + + networkId = builtins.readFile "${dir}/vars/shared/zerotier-network-${instance}/network-id/value"; + full = "fd" + networkId + "9993"; + hextet = i: builtins.substring (i * 4) 4 full; + subnetZtier = "${hextet 0}:${hextet 1}:${hextet 2}:${hextet 3}:${hextet 4}:${builtins.substring 20 2 full}00::/88"; + + vlanIfs = lib.mapAttrsToList (name: _: "vlan-${name}") settings.vlans; + wanVlanIfs = lib.mapAttrsToList (name: _: "vlan-${name}") ( + lib.filterAttrs (_: vlan: vlan.allowWan) settings.vlans + ); + nonMgmtIfs = lib.filter (i: i != "vlan-mgmt") vlanIfs; + ifSet = ifs: "{ ${lib.concatStringsSep ", " (map (i: "\"${i}\"") ifs)} }"; + in + { + networking.nftables.enable = true; + + services.openssh.openFirewall = false; + + networking.firewall = { + enable = true; + filterForward = true; + trustedInterfaces = [ "vlan-mgmt" ]; + + interfaces = lib.genAttrs nonMgmtIfs (_: { + allowedTCPPorts = [ 53 ]; + allowedUDPPorts = [ + 53 + 67 + ]; + }); + + extraInputRules = '' + ip6 saddr ${subnetZtier} tcp dport 22 accept comment "admin ssh over the mesh" + ip6 saddr ${subnetZtier} tcp dport 4000 accept comment "blocky metrics scrape from control" + ''; + + extraForwardRules = '' + tcp flags syn tcp option maxseg size set rt mtu comment "MSS clamp for PPPoE mtu 1492" + iifname "vlan-mgmt" accept comment "mgmt reaches all VLANs and the WAN" + iifname ${ifSet wanVlanIfs} oifname "ppp0" accept comment "LAN to internet" + ''; + }; + + networking.nat = { + enable = true; + externalInterface = "ppp0"; + internalInterfaces = vlanIfs; + }; + + }; + }; +}