anchor.diff:            Range of open UDP ports.
           '';
       };
  -
  -    networking.firewall.allowPing = mkOption {
  -      type = types.bool;
  -      default = true;
  -      description =
  -        ''
  -          Whether to respond to incoming ICMPv4 echo requests
  -          ("pings").  ICMPv6 pings are always allowed because the
  -          larger address space of IPv6 makes network scanning much
  -          less effective.
  -        '';
  -    };
  -
  -    networking.firewall.pingLimit = mkOption {
  -      type = types.nullOr (types.separatedString " ");
  -      default = null;
  -      example = "--limit 1/minute --limit-burst 5";
  -      description =
  -        ''
  -          If pings are allowed, this allows setting rate limits
  -          on them.  If non-null, this option should be in the form of
  -          flags like "--limit 1/minute --limit-burst 5"
  -        '';
  -    };
  -
  -    networking.firewall.checkReversePath = mkOption {
  -      type = types.either types.bool (types.enum ["strict" "loose"]);
  -      default = kernelHasRPFilter;
  -      example = "loose";
  -      description =
  -        ''
  -          Performs a reverse path filter test on a packet.  If a reply
  -          to the packet would not be sent via the same interface that
  -          the packet arrived on, it is refused.
  -
  -          If using asymmetric routing or other complicated routing, set
  -          this option to loose mode or disable it and setup your own
  -          counter-measures.
  -
  -          This option can be either true (or "strict"), "loose" (only
  -          drop the packet if the source address is not reachable via any
  -          interface) or false.  Defaults to the value of
  -          kernelHasRPFilter.
  -
  -          (needs kernel 3.3+)
  -        '';
  -    };
  -
  -    networking.firewall.logReversePathDrops = mkOption {
  -      type = types.bool;
  -      default = false;
  -      description =
  -        ''
  -          Logs dropped packets failing the reverse path filter test if
  -          the option networking.firewall.checkReversePath is enabled.
  -        '';
  -    };
  -
  -    networking.firewall.connectionTrackingModules = mkOption {
  -      type = types.listOf types.str;
  -      default = [ ];
  -      example = [ "ftp" "irc" "sane" "sip" "tftp" "amanda" "h323" "netbios_sn" "pptp" "snmp" ];
  -      description =
  -        ''
  -          List of connection-tracking helpers that are auto-loaded.
  -          The complete list of possible values is given in the example.
  -
  -          As helpers can pose as a security risk, it is advised to
  -          set this to an empty list and disable the setting
  -          networking.firewall.autoLoadConntrackHelpers unless you
  -          know what you are doing. Connection tracking is disabled
  -          by default.
  -
  -          Loading of helpers is recommended to be done through the
  -          CT target.  More info:
  -          https://home.regit.org/netfilter-en/secure-use-of-helpers/
  -        '';
  -    };
  -
  -    networking.firewall.autoLoadConntrackHelpers = mkOption {
  -      type = types.bool;
  -      default = false;
  -      description =
  -        ''
  -          Whether to auto-load connection-tracking helpers.
  -          See the description at networking.firewall.connectionTrackingModules
  -
  -          (needs kernel 3.5+)
  -        '';
  -    };
  -
  -    networking.firewall.extraCommands = mkOption {
  -      type = types.lines;
  -      default = "";
  -      example = "iptables -A INPUT -p icmp -j ACCEPT";
  -      description =
  -        ''
  -          Additional shell commands executed as part of the firewall
  -          initialisation script.  These are executed just before the
  -          final "reject" firewall rule is added, so they can be used
  -          to allow packets that would otherwise be refused.
  -        '';
  -    };
  -
  -    networking.firewall.extraPackages = mkOption {
  -      type = types.listOf types.package;
  -      default = [ ];
  -      example = literalExample "[ pkgs.ipset ]";
  -      description =
  -        ''
  -          Additional packages to be included in the environment of the system
  -          as well as the path of networking.firewall.extraCommands.
  -        '';
  -    };
  -
  -    networking.firewall.extraStopCommands = mkOption {
  -      type = types.lines;
  -      default = "";
  -      example = "iptables -P INPUT ACCEPT";
  -      description =
  -        ''
  -          Additional shell commands executed as part of the firewall
  -          shutdown script.  These are executed just after the removal
  -          of the NixOS input rule, or if the service enters a failed
  -          state.
  -        '';
  -    };
  +  };
  +
  +in
  +
  +{
  +
  +  ###### interface
  +
  +  options = {
  +
  +    networking.firewall = {
  +      enable = mkOption {
  +        type = types.bool;
  +        default = true;
  +        description =
  +          ''
  +            Whether to enable the firewall.  This is a simple stateful
  +            firewall that blocks connection attempts to unauthorised TCP
  +            or UDP ports on this machine.  It does not affect packet
  +            forwarding.
  +          '';
  +      };
  +
  +      logRefusedConnections = mkOption {
  +        type = types.bool;
  +        default = true;
  +        description =
  +          ''
  +            Whether to log rejected or dropped incoming connections.
  +          '';
  +      };
  +
  +      logRefusedPackets = mkOption {
  +        type = types.bool;
  +        default = false;
  +        description =
  +          ''
  +            Whether to log all rejected or dropped incoming packets.
  +            This tends to give a lot of log messages, so it's mostly
  +            useful for debugging.
  +          '';
  +      };
  +
  +      logRefusedUnicastsOnly = mkOption {
  +        type = types.bool;
  +        default = true;
  +        description =
  +          ''
  +            If <option>networking.firewall.logRefusedPackets</option>
  +            and this option are enabled, then only log packets
  +            specifically directed at this machine, i.e., not broadcasts
  +            or multicasts.
  +          '';
  +      };
  +
  +      rejectPackets = mkOption {
  +        type = types.bool;
  +        default = false;
  +        description =
  +          ''
  +            If set, refused packets are rejected rather than dropped
  +            (ignored).  This means that an ICMP "port unreachable" error
  +            message is sent back to the client (or a TCP RST packet in
  +            case of an existing connection).  Rejecting packets makes
  +            port scanning somewhat easier.
  +          '';
  +      };
  +
  +      trustedInterfaces = mkOption {
  +        type = types.listOf types.str;
  +        default = [ ];
  +        example = [ "enp0s2" ];
  +        description =
  +          ''
  +            Traffic coming in from these interfaces will be accepted
  +            unconditionally.  Traffic from the loopback (lo) interface
  +            will always be accepted.
  +          '';
  +      };
  +
  +      allowPing = mkOption {
  +        type = types.bool;
  +        default = true;
  +        description =
  +          ''
  +            Whether to respond to incoming ICMPv4 echo requests
  +            ("pings").  ICMPv6 pings are always allowed because the
  +            larger address space of IPv6 makes network scanning much
  +            less effective.
  +          '';
  +      };
  +
  +      pingLimit = mkOption {
  +        type = types.nullOr (types.separatedString " ");
  +        default = null;
  +        example = "--limit 1/minute --limit-burst 5";
  +        description =
  +          ''
  +            If pings are allowed, this allows setting rate limits
  +            on them.  If non-null, this option should be in the form of
  +            flags like "--limit 1/minute --limit-burst 5"
  +          '';
  +      };
  +
  +      checkReversePath = mkOption {
  +        type = types.either types.bool (types.enum ["strict" "loose"]);
  +        default = kernelHasRPFilter;
  +        example = "loose";
  +        description =
  +          ''
  +            Performs a reverse path filter test on a packet.  If a reply
  +            to the packet would not be sent via the same interface that
  +            the packet arrived on, it is refused.
  +
  +            If using asymmetric routing or other complicated routing, set
  +            this option to loose mode or disable it and setup your own
  +            counter-measures.
  +
  +            This option can be either true (or "strict"), "loose" (only
  +            drop the packet if the source address is not reachable via any
  +            interface) or false.  Defaults to the value of
  +            kernelHasRPFilter.
  +
  +            (needs kernel 3.3+)
  +          '';
  +      };
  +
  +      logReversePathDrops = mkOption {
  +        type = types.bool;
  +        default = false;
  +        description =
  +          ''
  +            Logs dropped packets failing the reverse path filter test if
  +            the option networking.firewall.checkReversePath is enabled.
  +          '';
  +      };
  +
  +      connectionTrackingModules = mkOption {
  +        type = types.listOf types.str;
  +        default = [ ];
  +        example = [ "ftp" "irc" "sane" "sip" "tftp" "amanda" "h323" "netbios_sn" "pptp" "snmp" ];
  +        description =
  +          ''
  +            List of connection-tracking helpers that are auto-loaded.
  +            The complete list of possible values is given in the example.
  +
  +            As helpers can pose as a security risk, it is advised to
  +            set this to an empty list and disable the setting
  +            networking.firewall.autoLoadConntrackHelpers unless you
  +            know what you are doing. Connection tracking is disabled
  +            by default.
  +
  +            Loading of helpers is recommended to be done through the
  +            CT target.  More info:
  +            https://home.regit.org/netfilter-en/secure-use-of-helpers/
  +          '';
  +      };
  +
  +      autoLoadConntrackHelpers = mkOption {
  +        type = types.bool;
  +        default = false;
  +        description =
  +          ''
  +            Whether to auto-load connection-tracking helpers.
  +            See the description at networking.firewall.connectionTrackingModules
  +
  +            (needs kernel 3.5+)
  +          '';
  +      };
  +
  +      extraCommands = mkOption {
  +        type = types.lines;
  +        default = "";
  +        example = "iptables -A INPUT -p icmp -j ACCEPT";
  +        description =
  +          ''
  +            Additional shell commands executed as part of the firewall
  +            initialisation script.  These are executed just before the
  +            final "reject" firewall rule is added, so they can be used
  +            to allow packets that would otherwise be refused.
  +          '';
  +      };
  +
  +      extraPackages = mkOption {
  +        type = types.listOf types.package;
  +        default = [ ];
  +        example = literalExample "[ pkgs.ipset ]";
  +        description =
  +          ''
  +            Additional packages to be included in the environment of the system
  +            as well as the path of networking.firewall.extraCommands.
  +          '';
  +      };
  +
  +      extraStopCommands = mkOption {
  +        type = types.lines;
  +        default = "";
  +        example = "iptables -P INPUT ACCEPT";
  +        description =
  +          ''
  +            Additional shell commands executed as part of the firewall
  +            shutdown script.  These are executed just after the removal
  +            of the NixOS input rule, or if the service enters a failed
  +            state.
  +          '';
  +      };
  +
  +      interfaces = mkOption {
  +        default = {
  +          default = mapAttrs (name: value: cfg."${name}") commonOptions;
  +        };
  +        type = with types; attrsOf (submodule [ { options = commonOptions; } ]);
  +        description =
  +          ''
  +            Interface-specific open ports. Setting this value will override
  +            all values of the <literal>networking.firewall.allowed*</literal>
  +            options.
  +          '';
  +      };
  +    } // commonOptions;
   
     };
   
  
positive.code:     fi
    '';
  
  in
  
  {
  
    ###### interface
  
    options = {
  
      networking.firewall.enable = mkOption {
        type = types.bool;
        default = true;
        description =
          ''
            Whether to enable the firewall.  This is a simple stateful
            firewall that blocks connection attempts to unauthorised TCP
            or UDP ports on this machine.  It does not affect packet
            forwarding.
          '';
      };
  
      networking.firewall.logRefusedConnections = mkOption {
        type = types.bool;
        default = true;
        description =
          ''
            Whether to log rejected or dropped incoming connections.
          '';
      };
  
      networking.firewall.logRefusedPackets = mkOption {
        type = types.bool;
        default = false;
        description =
          ''
            Whether to log all rejected or dropped incoming packets.
            This tends to give a lot of log messages, so it's mostly
            useful for debugging.
          '';
      };
  
      networking.firewall.logRefusedUnicastsOnly = mkOption {
        type = types.bool;
        default = true;
        description =
          ''
            If <option>networking.firewall.logRefusedPackets</option>
            and this option are enabled, then only log packets
            specifically directed at this machine, i.e., not broadcasts
            or multicasts.
          '';
      };
  
      networking.firewall.rejectPackets = mkOption {
        type = types.bool;
        default = false;
        description =
          ''
            If set, refused packets are rejected rather than dropped
            (ignored).  This means that an ICMP "port unreachable" error
            message is sent back to the client (or a TCP RST packet in
            case of an existing connection).  Rejecting packets makes
            port scanning somewhat easier.
          '';
      };
  
      networking.firewall.trustedInterfaces = mkOption {
        type = types.listOf types.str;
        default = [ ];
        example = [ "enp0s2" ];
        description =
          ''
            Traffic coming in from these interfaces will be accepted
            unconditionally.  Traffic from the loopback (lo) interface
            will always be accepted.
          '';
      };
  
      networking.firewall.allowedTCPPorts = mkOption {
        type = types.listOf types.int;
        default = [ ];
        example = [ 22 80 ];
        description =
          ''
            List of TCP ports on which incoming connections are
            accepted.
          '';
      };
  
      networking.firewall.allowedTCPPortRanges = mkOption {
        type = types.listOf (types.attrsOf types.int);
        default = [ ];
        example = [ { from = 8999; to = 9003; } ];
        description =
          ''
            A range of TCP ports on which incoming connections are
            accepted.
          '';
      };
  
      networking.firewall.allowedUDPPorts = mkOption {
        type = types.listOf types.int;
        default = [ ];
        example = [ 53 ];
  
negative.code:     ip46tables -A nixos-fw -m conntrack --ctstate ESTABLISHED,RELATED -j nixos-fw-accept
  
      # Accept connections to the allowed TCP ports.
      ${concatStrings (mapAttrsToList (iface: cfg:
        concatMapStrings (port:
          ''
            ip46tables -A nixos-fw -p tcp --dport ${toString port} -j nixos-fw-accept ${optionalString (iface != "default") "-i ${iface}"}
          ''
        ) cfg.allowedTCPPorts
      ) cfg.interfaces)}
  
      # Accept connections to the allowed TCP port ranges.
      ${concatStrings (mapAttrsToList (iface: cfg:
        concatMapStrings (rangeAttr:
          let range = toString rangeAttr.from + ":" + toString rangeAttr.to; in
          ''
            ip46tables -A nixos-fw -p tcp --dport ${range} -j nixos-fw-accept ${optionalString (iface != "default") "-i ${iface}"}
          ''
        ) cfg.allowedTCPPortRanges
      ) cfg.interfaces)}
  
      # Accept packets on the allowed UDP ports.
      ${concatStrings (mapAttrsToList (iface: cfg:
        concatMapStrings (port:
          ''
            ip46tables -A nixos-fw -p udp --dport ${toString port} -j nixos-fw-accept ${optionalString (iface != "default") "-i ${iface}"}
          ''
        ) cfg.allowedUDPPorts
      ) cfg.interfaces)}
  
      # Accept packets on the allowed UDP port ranges.
      ${concatStrings (mapAttrsToList (iface: cfg:
        concatMapStrings (rangeAttr:
          let range = toString rangeAttr.from + ":" + toString rangeAttr.to; in
          ''
            ip46tables -A nixos-fw -p udp --dport ${range} -j nixos-fw-accept ${optionalString (iface != "default") "-i ${iface}"}
          ''
        ) cfg.allowedUDPPortRanges
      ) cfg.interfaces)}
  
      # Accept IPv4 multicast.  Not a big security risk since
      # probably nobody is listening anyway.
  