{ config, lib, pkgs, ... }: let cfg = config.services.prometheus.exporters.dnstt; inherit (lib) escapeShellArgs mkDefault mkEnableOption mkIf mkOption optionals types ; listenAddress = "${cfg.listenAddress}:${toString cfg.port}"; args = [ "-web.listen-address" listenAddress "-web.telemetry-path" cfg.telemetryPath "-dnstt.port" (toString cfg.dnsttPort) ] ++ lib.concatMap (domain: [ "-dnstt.domain" domain ]) cfg.domains ++ optionals (cfg.geoip.countryDatabase != null) [ "-geoip.country-database" cfg.geoip.countryDatabase ] ++ optionals (cfg.geoip.asnDatabase != null) [ "-geoip.asn-database" cfg.geoip.asnDatabase ] ++ cfg.extraFlags; in { options.services.prometheus.exporters.dnstt = { enable = mkEnableOption "the Prometheus DNSTT exporter"; package = mkOption { type = types.package; description = '' Package providing the `dnstt_exporter` binary. ''; }; domains = mkOption { type = types.nonEmptyListOf types.str; example = [ "tunnel.example.com" ]; description = '' DNSTT tunnel domains to observe. The exporter matches DNS query names below these domains and decodes DNSTT session IDs from the query prefix. ''; }; dnsttPort = mkOption { type = types.port; default = 53; description = '' UDP port where DNSTT DNS traffic is observed. ''; }; port = mkOption { type = types.port; default = 9713; description = '' Port to listen on for Prometheus metrics. ''; }; listenAddress = mkOption { type = types.str; default = "0.0.0.0"; description = '' Address to listen on for Prometheus metrics. ''; }; telemetryPath = mkOption { type = types.str; default = "/metrics"; description = '' HTTP path under which to expose Prometheus metrics. ''; }; geoip = { countryDatabase = mkOption { type = types.nullOr types.str; default = null; example = "/var/lib/GeoIP/GeoLite2-Country.mmdb"; description = '' Optional MaxMind GeoIP2 or GeoLite2 Country database path. When set, exported DNSTT metrics include a `country` label for the resolver address seen by the server. ''; }; asnDatabase = mkOption { type = types.nullOr types.str; default = null; example = "/var/lib/GeoIP/GeoLite2-ASN.mmdb"; description = '' Optional MaxMind GeoIP2 or GeoLite2 ASN database path. When set, exported DNSTT metrics include an `asn` label for the resolver address seen by the server. ''; }; }; extraFlags = mkOption { type = types.listOf types.str; default = [ ]; description = '' Extra command line flags to pass to `dnstt_exporter`. ''; }; openFirewall = mkOption { type = types.bool; default = false; description = '' Open the exporter metrics port in the firewall. ''; }; }; config = mkIf cfg.enable { assertions = [ { assertion = cfg.domains != [ ]; message = "services.prometheus.exporters.dnstt.domains must contain at least one DNSTT domain."; } ]; networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ]; systemd.services.prometheus-dnstt-exporter = { description = "Prometheus DNSTT exporter"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; serviceConfig = { ExecStart = "${cfg.package}/bin/dnstt_exporter ${escapeShellArgs args}"; Restart = "always"; DynamicUser = true; AmbientCapabilities = [ "CAP_NET_RAW" ]; CapabilityBoundingSet = [ "CAP_NET_RAW" ]; NoNewPrivileges = true; LockPersonality = true; MemoryDenyWriteExecute = true; PrivateDevices = mkDefault false; PrivateTmp = true; ProtectClock = true; ProtectControlGroups = true; ProtectHome = true; ProtectHostname = true; ProtectKernelLogs = true; ProtectKernelModules = true; ProtectKernelTunables = true; ProtectSystem = "strict"; RemoveIPC = true; RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_PACKET" ]; RestrictNamespaces = true; RestrictRealtime = true; RestrictSUIDSGID = true; SystemCallArchitectures = "native"; UMask = "0077"; }; }; }; meta.maintainers = [ ]; meta.doc = false; meta.buildDocsInSandbox = false; }