{ lib, config, ... }: let services = { ssh = { tcp = [ 22 ]; }; dhcp = { udp = [ 67 68 ]; }; dns = { udp = [ 53 ]; }; web = { tcp = [ 80 443 ]; }; }; rulesForServices = enabledServices: lib.foldr (service: { allowedUDPPorts, allowedTCPPorts }: { allowedUDPPorts = allowedUDPPorts ++ services.${service}.udp or [ ]; allowedTCPPorts = allowedTCPPorts ++ services.${service}.tcp or [ ]; }) { allowedUDPPorts = [ ]; allowedTCPPorts = [ ]; } enabledServices; cfg = config.modules.firewall.rules; in { options.modules.firewall.rules = lib.mkOption { type = lib.types.attrsOf (lib.types.listOf (lib.types.enum (lib.attrNames services))); default = { }; }; config = lib.mkIf (lib.length (lib.attrNames cfg) > 0) { networking.firewall = { enable = lib.mkDefault true; interfaces = lib.mapAttrs (_: enabledServices: rulesForServices enabledServices) cfg; }; }; }