172 lines
5.9 KiB
Nix
172 lines
5.9 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
...
|
|
}: let
|
|
cfg = config.services.crab-hole;
|
|
in {
|
|
options.services.crab-hole = {
|
|
port = lib.mkOption {
|
|
type = lib.types.port;
|
|
default = 8080;
|
|
description = "Port for the crab-hole API to listen on.";
|
|
};
|
|
|
|
openFirewall = lib.mkOption {
|
|
type = lib.types.bool;
|
|
default = false;
|
|
description = "Whether to open the firewall for the crab-hole API port.";
|
|
};
|
|
|
|
listen = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "0.0.0.0";
|
|
description = "Address for the crab-hole API to listen on.";
|
|
};
|
|
|
|
show_doc = lib.mkEnableOption "OpenAPI documentation (loads content from third party websites)";
|
|
|
|
downstreams = {
|
|
host = {
|
|
enable = lib.mkEnableOption "host downstream DNS server accessible from network on all interfaces";
|
|
port = lib.mkOption {
|
|
type = lib.types.port;
|
|
default = 53;
|
|
description = "Port for the host downstream DNS server to listen on.";
|
|
};
|
|
openFirewall = lib.mkEnableOption "automatic port forwarding for the host downstream";
|
|
disableSystemdResolved = lib.mkOption {
|
|
type = lib.types.bool;
|
|
default = true;
|
|
description = "Whether to automatically disable systemd-resolved when using port 53. Set to false if you want to handle the conflict manually.";
|
|
};
|
|
};
|
|
};
|
|
|
|
extraDownstreams = lib.mkOption {
|
|
type = lib.types.listOf (lib.types.submodule {
|
|
options = {
|
|
protocol = lib.mkOption {
|
|
type = lib.types.enum ["udp" "tcp" "tls" "https" "quic"];
|
|
description = "Protocol for the downstream server.";
|
|
};
|
|
|
|
listen = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = "Address to listen on for downstream connections.";
|
|
};
|
|
|
|
port = lib.mkOption {
|
|
type = lib.types.port;
|
|
description = "Port to listen on for downstream connections.";
|
|
};
|
|
};
|
|
});
|
|
default = [];
|
|
description = "List of additional downstream DNS server configurations.";
|
|
};
|
|
|
|
upstreams = {
|
|
cloudFlare = {
|
|
enable = lib.mkEnableOption "Cloudflare DNS over TLS upstream servers (1.1.1.1 and 1.0.0.1)";
|
|
};
|
|
};
|
|
|
|
extraUpstreams = lib.mkOption {
|
|
type = lib.types.listOf (lib.types.submodule {
|
|
options = {
|
|
socket_addr = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = "Socket address of the upstream DNS server (e.g., \"1.1.1.1:853\" or \"[2606:4700:4700::1111]:853\").";
|
|
};
|
|
|
|
protocol = lib.mkOption {
|
|
type = lib.types.enum ["udp" "tcp" "tls" "https" "quic"];
|
|
description = "Protocol to use for upstream DNS queries.";
|
|
};
|
|
};
|
|
});
|
|
default = [];
|
|
description = "List of additional upstream DNS server configurations.";
|
|
};
|
|
};
|
|
|
|
config = lib.mkIf cfg.enable {
|
|
# Assertions for proper configuration
|
|
assertions = [
|
|
{
|
|
assertion = !(cfg.downstreams.host.enable && cfg.downstreams.host.port == 53 && config.services.resolved.enable && cfg.downstreams.host.disableSystemdResolved);
|
|
message = "crab-hole host downstream cannot use port 53 while systemd-resolved is enabled. Either disable systemd-resolved or use a different port.";
|
|
}
|
|
{
|
|
assertion = !(cfg.downstreams.host.enable && cfg.downstreams.host.port == 53 && !cfg.downstreams.host.disableSystemdResolved && config.services.resolved.enable);
|
|
message = "crab-hole host downstream is configured to use port 53 but systemd-resolved is still enabled and disableSystemdResolved is false. Set disableSystemdResolved = true or manually disable systemd-resolved.";
|
|
}
|
|
];
|
|
|
|
# Automatically disable systemd-resolved if using port 53
|
|
services.resolved.enable = lib.mkIf (cfg.downstreams.host.enable && cfg.downstreams.host.port == 53 && cfg.downstreams.host.disableSystemdResolved) (lib.mkForce false);
|
|
|
|
# Configure DNS nameservers when disabling systemd-resolved
|
|
networking.nameservers = lib.mkIf (cfg.downstreams.host.enable && cfg.downstreams.host.port == 53 && cfg.downstreams.host.disableSystemdResolved) (lib.mkDefault ["127.0.0.1" "1.1.1.1" "8.8.8.8"]);
|
|
|
|
services.crab-hole.settings = lib.mkMerge [
|
|
{
|
|
api = {
|
|
port = cfg.port;
|
|
listen = cfg.listen;
|
|
show_doc = cfg.show_doc;
|
|
};
|
|
downstream = cfg.extraDownstreams;
|
|
upstream.name_servers = cfg.extraUpstreams;
|
|
}
|
|
(lib.mkIf cfg.downstreams.host.enable {
|
|
downstream = [
|
|
{
|
|
protocol = "udp";
|
|
listen = "0.0.0.0";
|
|
port = cfg.downstreams.host.port;
|
|
}
|
|
];
|
|
})
|
|
(lib.mkIf cfg.upstreams.cloudFlare.enable {
|
|
upstream.name_servers = [
|
|
{
|
|
socket_addr = "1.1.1.1:853";
|
|
protocol = "tls";
|
|
tls_dns_name = "1dot1dot1dot1.cloudflare-dns.com";
|
|
trust_nx_responses = false;
|
|
}
|
|
{
|
|
socket_addr = "1.0.0.1:853";
|
|
protocol = "tls";
|
|
tls_dns_name = "1dot1dot1dot1.cloudflare-dns.com";
|
|
trust_nx_responses = false;
|
|
}
|
|
{
|
|
socket_addr = "[2606:4700:4700::1111]:853";
|
|
protocol = "tls";
|
|
tls_dns_name = "1dot1dot1dot1.cloudflare-dns.com";
|
|
trust_nx_responses = false;
|
|
}
|
|
{
|
|
socket_addr = "[2606:4700:4700::1001]:853";
|
|
protocol = "tls";
|
|
tls_dns_name = "1dot1dot1dot1.cloudflare-dns.com";
|
|
trust_nx_responses = false;
|
|
}
|
|
];
|
|
})
|
|
];
|
|
|
|
# Open firewall if requested
|
|
networking.firewall = lib.mkMerge [
|
|
(lib.mkIf cfg.openFirewall {
|
|
allowedTCPPorts = [cfg.port];
|
|
})
|
|
(lib.mkIf (cfg.downstreams.host.enable && cfg.downstreams.host.openFirewall) {
|
|
allowedUDPPorts = [cfg.downstreams.host.port];
|
|
})
|
|
];
|
|
};
|
|
}
|