Skip to content

Instantly share code, notes, and snippets.

@corpix
Last active December 24, 2017 22:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save corpix/2fbebeb2da8c9d69ea782b1e12f356b4 to your computer and use it in GitHub Desktop.
Save corpix/2fbebeb2da8c9d69ea782b1e12f356b4 to your computer and use it in GitHub Desktop.
Simple firewall helper service to open/reject ports for specific interfaces with user defined protocols
let
internalInterfaces = {
enp3s0 = {
ip4 = [
{
address = "10.0.10.1";
prefixLength = 24;
}
];
ip6 = [];
};
};
in {
services.firewall = with lib; {
enable = true;
accept = [
{
ports = [80];
protocols = ["tcp"];
interfaces = attrNames internalInterfaces;
}
{
ports = [69];
protocols = ["udp"];
interfaces = attrNames internalInterfaces;
}
];
};
}
{ config, lib, pkgs, ... }:
with lib;
let
name = "firewall";
cfg = config.services."${name}";
in {
options = with types; {
services."${name}" = {
enable = mkEnableOption "Firewall helper service";
reject = mkOption {
type = listOf attrs;
default = [];
example = [ { ports = [22]; protocols = ["tcp"]; interfaces = ["enp3s0"]; } ];
description =
''
List of attrs with port number, protocols and interface to reject traffic on.
'';
};
rejectSilently = mkOption {
type = listOf attrs;
default = [];
example = [ { ports = [22]; protocols = ["tcp"]; interfaces = ["enp3s0"]; } ];
description =
''
List of attrs with port number, protocols and interface to reject traffic on without logging.
'';
};
accept = mkOption {
type = listOf attrs;
default = [];
example = [ { ports = [22]; protocols = ["tcp"]; interfaces = ["enp3s0"]; } ];
description =
''
List of attrs with port number, protocols and interface to accept.
'';
};
};
};
config = with lib; let
rejectChain = silent:
if silent
then "nixos-fw-refuse"
else "nixos-fw-log-refuse";
ifNotEmptyString = s: v:
if (stringLength s) == 0
then ""
else v;
foldRecord = fn: record:
foldl
(acc: interfaces:
foldl
(acc: protocols:
foldl
(acc: ports: acc ++ [ports])
acc
protocols)
acc
interfaces)
[]
(map
(interface: map
(protocol: map (port: fn port protocol interface) record.ports)
(attrByPath ["protocols"] [ "tcp" "udp" ] record))
(attrByPath ["interfaces"] [""] record));
mkReject = port: protocol: interface: silent:
"ip46tables -A nixos-fw ${ifNotEmptyString interface "-i ${interface}"} -p ${protocol} --dport ${toString port} -j ${rejectChain silent}";
mkAccept = port: protocol: interface:
"ip46tables -A nixos-fw ${ifNotEmptyString interface "-i ${interface}"} -p ${protocol} --dport ${toString port} -j nixos-fw-accept";
in mkIf cfg.enable {
networking.firewall.extraCommands = concatStringsSep
"\n"
((foldl (acc: v: acc ++ v) [] (map (foldRecord mkAccept) cfg.accept))
++ (foldl (acc: fns: acc ++ (map (fn: fn false) fns)) [] (map (foldRecord mkReject) cfg.reject))
++ (foldl (acc: fns: acc ++ (map (fn: fn true) fns)) [] (map (foldRecord mkReject) cfg.rejectSilently)));
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment