{ pkgs, lib, config, ... }:
let
  inherit (builtins) hasAttr readFile;
  inherit (pkgs.lib) unlinesAttrs;
  inherit (config.users) users;
  inherit (config.services) shorewall shorewall6;
  fw2net = ''
    # By protocol
    Ping(ACCEPT)   $FW net

    # By port
    DNS(ACCEPT)    $FW net {user=${users.unbound.name}}
    Git(ACCEPT)    $FW net
    HKP(ACCEPT)    $FW net {user=${users.julm.name}}
    HTTP(ACCEPT)   $FW net
    HTTPS(ACCEPT)  $FW net
    ACCEPT         $FW net {proto=tcp, dport=8080}
    IRCS(ACCEPT)   $FW net {user=${users.julm.name}}
    NTP(ACCEPT)    $FW net {user=${users.systemd-timesync.name}}
    SMTP(ACCEPT)   $FW net
    SMTPS(ACCEPT)  $FW net
    SSH(ACCEPT)    $FW net
  '';
  net2fw = ''
    # By protocol
    Ping(ACCEPT)   net $FW

    # By port
    DNS(ACCEPT)    net $FW
    HTTP(ACCEPT)   net $FW
    HTTPS(ACCEPT)  net $FW
    IMAPS(ACCEPT)  net $FW
    Mosh(ACCEPT)   net $FW
    POP3S(ACCEPT)  net $FW
    SMTP(ACCEPT)   net $FW
    SMTPS(ACCEPT)  net $FW
    SSH(ACCEPT)    net $FW {rate=s:1/min:10}
    Sieve(ACCEPT)  net $FW
  '';
  macros = {
    "macro.Git" = ''
      ?FORMAT 2
      #ACTION SOURCE  DEST    PROTO   DEST    SOURCE  RATE    USER/
      #                               PORT(S) PORT(S) LIMIT   GROUP
      PARAM   -       -       tcp     9418
    '';
    "macro.IRCS" = ''
      ?FORMAT 2
      #ACTION SOURCE  DEST    PROTO   DEST    SOURCE  RATE    USER/
      #                               PORT(S) PORT(S) LIMIT   GROUP
      PARAM   -       -       tcp     6697
    '';
    "macro.Mosh" = ''
      ?FORMAT 2
      #ACTION SOURCE  DEST    PROTO   DEST    SOURCE  RATE    USER/
      #                               PORT(S) PORT(S) LIMIT   GROUP
      PARAM   -       -       udp     60000-61000
    '';
  };
in
{
  services.shorewall = {
    enable  = true;
    configs = macros // {
      "shorewall.conf" = ''
        ${readFile "${shorewall.package}/etc-example/shorewall/shorewall.conf"}
        #
        ## Custom config
        ###
        STARTUP_ENABLED=Yes
        ZONE2ZONE=2
      '';
      zones = ''
        # DOC: shorewall-zones(5)
        fw firewall
        net    ipv4
        wet    ipv4
      '';
      interfaces = ''
        # DOC: shorewall-interfaces(5)
        ?FORMAT 2
        net   enp5s0 arp_filter,nosmurfs,routefilter=1,tcpflags
        wet   wlp4s0 arp_filter,nosmurfs,routefilter=1,tcpflags
      '';
      policy = ''
        # DOC: shorewall-policy(5)
        $FW    all DROP
        net    all DROP   none
        wet    all DROP   none
        # WARNING: the following policy must be last
        all    all REJECT none
      '';
      rules = ''
        # DOC: shorewall-rules(5)
        #SECTION ALL
        #SECTION ESTABLISHED
        #SECTION RELATED
        ?SECTION NEW

        ${fw2net}
        ${net2fw}
      '';
    };
  };
  services.shorewall6 = {
    enable  = true;
    configs = macros // {
      "shorewall6.conf" = ''
        ${readFile "${shorewall6.package}/etc-example/shorewall6/shorewall6.conf"}
        #
        ## Custom config
        ###
        STARTUP_ENABLED=Yes
        ZONE2ZONE=2
        '';
      zones = ''
        # DOC: shorewall-zones(5)
        fw firewall
        net    ipv6
        wet    ipv6
      '';
      interfaces = ''
        # DOC: shorewall-interfaces(5)
        ?FORMAT 2
        net    enp5s0 nosmurfs,tcpflags
        wet    wlp4s0 nosmurfs,tcpflags
      '';
      policy = ''
        # DOC: shorewall-policy(5)
        $FW    all DROP
        net    all DROP   none
        wet    all DROP   none
        # WARNING: the following policy must be last
        all    all REJECT none
      '';
      rules = ''
        # DOC: shorewall-rules(5)
        #SECTION ALL
        #SECTION ESTABLISHED
        #SECTION RELATED
        ?SECTION NEW

        ${fw2net}
        ${net2fw}
      '';
    };
  };
}