diff --git a/modules/default.nix b/modules/default.nix index 2096759..231b916 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -3,6 +3,7 @@ { imports = [ ./yate + ./forward-filter ./fieldpoc ]; } diff --git a/modules/forward-filter/default.nix b/modules/forward-filter/default.nix new file mode 100644 index 0000000..de55f51 --- /dev/null +++ b/modules/forward-filter/default.nix @@ -0,0 +1,162 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.clerie.forward-filter; + + startScript = pkgs.writeScriptBin "forward-filter-start" '' + #! ${pkgs.runtimeShell} -e + + ip46tables() { + iptables -w "$@" + ip6tables -w "$@" + } + + ip46tables -D FORWARD -j forward-filter 2> /dev/null || true + ip46tables -F forward-filter 2> /dev/null || true + ip46tables -X forward-filter 2> /dev/null || true + + ip46tables -N forward-filter + + ip46tables -A forward-filter -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT + + ${concatStrings (mapAttrsToList (iface: ifacecfg: '' + ${concatMapStrings (rule: if (rule.sourceAddress != null || rule.destinationAddress != null ) then '' + iptables -A forward-filter -o ${iface} ${optionalString (rule.incomingInterface != null) "-i ${rule.incomingInterface}"} ${optionalString (rule.sourceAddress != null) "-s ${rule.sourceAddress}"} ${optionalString (rule.destinationAddress != null) "-d ${rule.destinationAddress}"} ${optionalString (rule.jump != null) "-j ${rule.jump}"} + '' else if (rule.sourceAddress6 != null || rule.destinationAddress6 != null ) then '' + ip6tables -A forward-filter -o ${iface} ${optionalString (rule.incomingInterface != null) "-i ${rule.incomingInterface}"} ${optionalString (rule.sourceAddress6 != null) "-s ${rule.sourceAddress6}"} ${optionalString (rule.destinationAddress6 != null) "-d ${rule.destinationAddress6}"} ${optionalString (rule.jump != null) "-j ${rule.jump}"} + '' else '' + ip46tables -A forward-filter -o ${iface} ${optionalString (rule.incomingInterface != null) "-i ${rule.incomingInterface}"} ${optionalString (rule.jump != null) "-j ${rule.jump}"} + '' + ) ifacecfg.rules} + ${optionalString (ifacecfg.default != null) '' + ip46tables -A forward-filter -o ${iface} -j ${ifacecfg.default} + ''} + '') cfg.interfaces)} + + ip46tables -A FORWARD -j forward-filter + ''; + + stopScript = pkgs.writeScriptBin "forward-filter-stop" '' + #! ${pkgs.runtimeShell} -e + + ip46tables() { + iptables -w "$@" + ip6tables -w "$@" + } + + ip46tables -D FORWARD -j forward-filter 2> /dev/null || true + ip46tables -F forward-filter 2> /dev/null || true + ip46tables -X forward-filter 2> /dev/null || true + ''; + +in + +{ + + options = { + + clerie.forward-filter = { + enable = mkOption { + type = types.bool; + default = true; + description = + '' + Whether to enable the forward-filter. It gives basic control about + blocking and allowing forward between interfaces. + ''; + }; + + interfaces = mkOption { + default = { }; + type = with types; attrsOf (submodule { + options = { + rules = mkOption { + type = with types; listOf (submodule { + options = { + sourceAddress = mkOption { + type = types.nullOr types.str; + default = null; + example = "192.168.0.0/24"; + description = ""; + }; + sourceAddress6 = mkOption { + type = types.nullOr types.str; + default = null; + example = "fd00::/64"; + description = ""; + }; + destinationAddress = mkOption { + type = types.nullOr types.str; + default = null; + example = "192.168.0.0/24"; + description = ""; + }; + destinationAddress6 = mkOption { + type = types.nullOr types.str; + default = null; + example = "fd00::/64"; + description = ""; + }; + incomingInterface = mkOption { + type = types.nullOr types.str; + default = null; + example = "ens18"; + description = ""; + }; + jump = mkOption { + type = types.nullOr types.str; + default = "ACCEPT"; + example = "DROP"; + description = ""; + }; + }; + }); + description = "List of rules to filter forwarding."; + }; + default = mkOption { + type = types.nullOr types.str; + default = "DROP"; + example = "ACCEPT"; + description = ""; + }; + }; + }); + description = + '' + Interface filter options. + ''; + }; + }; + + }; + + config = mkIf cfg.enable { + + environment.systemPackages = [ pkgs.iptables ]; + + systemd.services.forward-filter = { + description = "Forward Filter"; + wantedBy = [ "sysinit.target" ]; + wants = [ "network-pre.target" ]; + before = [ "network-pre.target" ]; + after = [ "systemd-modules-load.service" ]; + + path = [ pkgs.iptables ]; + + unitConfig.ConditionCapability = "CAP_NET_ADMIN"; + unitConfig.DefaultDependencies = false; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = "@${startScript}/bin/forward-filter-start forward-filter-start"; + ExecStop = "@${stopScript}/bin/forward-filter-stop forward-filter-stop"; + }; + }; + + }; + +}