mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-06-09 19:13:26 +03:00
nixos/pihole-ftl: init
Add a module for pihole-ftl, which allows declaratively defining the pihole.toml config file. Also provide options for adlists to use, which can be added through the pihole script (packaged as "pihole"). Other state such as clients and groups require complex database operations, which is normally performed by the pihole webapp (packaged as "pihole-web"). Extend the dnsmasq module to avoid duplication, since pihole-ftl is a soft-fork of dnsmasq which maintains compatibility. Provide the pihole script in `environment.systemPackages` so pihole-ftl can be easily administrated.
This commit is contained in:
parent
4bdf75f1cb
commit
8f5d24c1b2
6 changed files with 711 additions and 0 deletions
|
@ -56,6 +56,12 @@
|
|||
"module-services-opencloud-basic-usage": [
|
||||
"index.html#module-services-opencloud-basic-usage"
|
||||
],
|
||||
"module-services-networking-pihole-ftl-configuration-inherit-dnsmasq": [
|
||||
"index.html#module-services-networking-pihole-ftl-configuration-inherit-dnsmasq"
|
||||
],
|
||||
"module-services-networking-pihole-ftl-configuration-multiple-interfaces": [
|
||||
"index.html#module-services-networking-pihole-ftl-configuration-multiple-interfaces"
|
||||
],
|
||||
"module-services-strfry": [
|
||||
"index.html#module-services-strfry"
|
||||
],
|
||||
|
@ -1448,6 +1454,15 @@
|
|||
"module-services-input-methods-kime": [
|
||||
"index.html#module-services-input-methods-kime"
|
||||
],
|
||||
"module-services-networking-pihole-ftl": [
|
||||
"index.html#module-services-networking-pihole-ftl"
|
||||
],
|
||||
"module-services-networking-pihole-ftl-administration": [
|
||||
"index.html#module-services-networking-pihole-ftl-administration"
|
||||
],
|
||||
"module-services-networking-pihole-ftl-configuration": [
|
||||
"index.html#module-services-networking-pihole-ftl-configuration"
|
||||
],
|
||||
"ch-profiles": [
|
||||
"index.html#ch-profiles"
|
||||
],
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
- [gtklock](https://github.com/jovanlanik/gtklock), a GTK-based lockscreen for Wayland. Available as [programs.gtklock](#opt-programs.gtklock.enable).
|
||||
- [Chrysalis](https://github.com/keyboardio/Chrysalis), a graphical configurator for Kaleidoscope-powered keyboards. Available as [programs.chrysalis](#opt-programs.chrysalis.enable).
|
||||
|
||||
- [Pi-hole](https://pi-hole.net/), a DNS sinkhole for advertisements based on Dnsmasq. Available as [services.pihole-ftl](#opt-services.pihole-ftl.enable), and [services.pihole-web](#opt-services.pihole-web.enable) for the web GUI and API.
|
||||
|
||||
- [FileBrowser](https://filebrowser.org/), a web application for managing and sharing files. Available as [services.filebrowser](#opt-services.filebrowser.enable).
|
||||
|
||||
- [LACT](https://github.com/ilya-zlobintsev/LACT), a GPU monitoring and configuration tool, can now be enabled through [services.lact.enable](#opt-services.lact.enable).
|
||||
|
|
|
@ -1268,6 +1268,7 @@
|
|||
./services/networking/pdnsd.nix
|
||||
./services/networking/peroxide.nix
|
||||
./services/networking/picosnitch.nix
|
||||
./services/networking/pihole-ftl.nix
|
||||
./services/networking/pixiecore.nix
|
||||
./services/networking/pleroma.nix
|
||||
./services/networking/powerdns.nix
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
{
|
||||
cfg,
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
}:
|
||||
|
||||
let
|
||||
pihole = pkgs.pihole;
|
||||
makePayload =
|
||||
list:
|
||||
builtins.toJSON {
|
||||
inherit (list) type enabled;
|
||||
address = list.url;
|
||||
comment = list.description;
|
||||
};
|
||||
payloads = map makePayload cfg.lists;
|
||||
in
|
||||
''
|
||||
# Can't use -u (unset) because api.sh uses API_URL before it is set
|
||||
set -eo pipefail
|
||||
pihole="${lib.getExe pihole}"
|
||||
jq="${lib.getExe pkgs.jq}"
|
||||
|
||||
# If the database doesn't exist, it needs to be created with gravity.sh
|
||||
if [ ! -f '${cfg.stateDirectory}'/gravity.db ]; then
|
||||
$pihole -g
|
||||
# Send SIGRTMIN to FTL, which makes it reload the database, opening the newly created one
|
||||
${pkgs.procps}/bin/kill -s SIGRTMIN $(systemctl show --property MainPID --value ${config.systemd.services.pihole-ftl.name})
|
||||
fi
|
||||
|
||||
source ${pihole}/usr/share/pihole/advanced/Scripts/api.sh
|
||||
source ${pihole}/usr/share/pihole/advanced/Scripts/utils.sh
|
||||
|
||||
any_failed=0
|
||||
|
||||
addList() {
|
||||
local payload="$1"
|
||||
|
||||
echo "Adding list: $payload"
|
||||
local result=$(PostFTLData "lists" "$payload")
|
||||
|
||||
local error="$($jq '.error' <<< "$result")"
|
||||
if [[ "$error" != "null" ]]; then
|
||||
echo "Error: $error"
|
||||
any_failed=1
|
||||
return
|
||||
fi
|
||||
|
||||
id="$($jq '.lists.[].id?' <<< "$result")"
|
||||
if [[ "$id" == "null" ]]; then
|
||||
any_failed=1
|
||||
error="$($jq '.processed.errors.[].error' <<< "$result")"
|
||||
echo "Error: $error"
|
||||
return
|
||||
fi
|
||||
|
||||
echo "Added list ID $id: $result"
|
||||
}
|
||||
|
||||
for i in 1 2 3; do
|
||||
(TestAPIAvailability) && break
|
||||
echo "Retrying API shortly..."
|
||||
${pkgs.coreutils}/bin/sleep .5s
|
||||
done;
|
||||
|
||||
LoginAPI
|
||||
|
||||
${builtins.concatStringsSep "\n" (
|
||||
map (
|
||||
payload:
|
||||
lib.pipe payload [
|
||||
lib.strings.escapeShellArg
|
||||
(payload: "addList ${payload}")
|
||||
]
|
||||
) payloads
|
||||
)}
|
||||
|
||||
# Run gravity.sh to load any new lists
|
||||
$pihole -g
|
||||
exit $any_failed
|
||||
''
|
128
nixos/modules/services/networking/pihole-ftl.md
Normal file
128
nixos/modules/services/networking/pihole-ftl.md
Normal file
|
@ -0,0 +1,128 @@
|
|||
# pihole-FTL {#module-services-networking-pihole-ftl}
|
||||
|
||||
*Upstream documentation*: <https://docs.pi-hole.net/ftldns/>
|
||||
|
||||
pihole-FTL is a fork of [Dnsmasq](index.html#module-services-networking-dnsmasq),
|
||||
providing some additional features, including an API for analysis and
|
||||
statistics.
|
||||
|
||||
Note that pihole-FTL and Dnsmasq cannot be enabled at
|
||||
the same time.
|
||||
|
||||
## Configuration {#module-services-networking-pihole-ftl-configuration}
|
||||
|
||||
pihole-FTL can be configured with [{option}`services.pihole-ftl.settings`](options.html#opt-services.pihole-ftl.settings), which controls the content of `pihole.toml`.
|
||||
|
||||
The template pihole.toml is provided in `pihole-ftl.passthru.settingsTemplate`,
|
||||
which describes all settings.
|
||||
|
||||
Example configuration:
|
||||
|
||||
```nix
|
||||
{
|
||||
services.pihole-ftl = {
|
||||
enable = true;
|
||||
openFirewallDHCP = true;
|
||||
queryLogDeleter.enable = true;
|
||||
lists = [
|
||||
{
|
||||
url = "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts";
|
||||
# Alternatively, use the file from nixpkgs. Note its contents won't be
|
||||
# automatically updated by Pi-hole, as it would with an online URL.
|
||||
# url = "file://${pkgs.stevenblack-blocklist}/hosts";
|
||||
description = "Steven Black's unified adlist";
|
||||
}
|
||||
];
|
||||
settings = {
|
||||
dns = {
|
||||
domainNeeded = true;
|
||||
expandHosts = true;
|
||||
interface = "br-lan";
|
||||
listeningMode = "BIND";
|
||||
upstreams = [ "127.0.0.1#5053" ];
|
||||
};
|
||||
dhcp = {
|
||||
active = true;
|
||||
router = "192.168.10.1";
|
||||
start = "192.168.10.2";
|
||||
end = "192.168.10.254";
|
||||
leaseTime = "1d";
|
||||
ipv6 = true;
|
||||
multiDNS = true;
|
||||
hosts = [
|
||||
# Static address for the current host
|
||||
"aa:bb:cc:dd:ee:ff,192.168.10.1,${config.networking.hostName},infinite"
|
||||
];
|
||||
rapidCommit = true;
|
||||
};
|
||||
misc.dnsmasq_lines = [
|
||||
# This DHCP server is the only one on the network
|
||||
"dhcp-authoritative"
|
||||
# Source: https://data.iana.org/root-anchors/root-anchors.xml
|
||||
"trust-anchor=.,38696,8,2,683D2D0ACB8C9B712A1948B27F741219298D0A450D612C483AF444A4C0FB2B16"
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Inheriting configuration from Dnsmasq {#module-services-networking-pihole-ftl-configuration-inherit-dnsmasq}
|
||||
|
||||
If [{option}`services.pihole-ftl.useDnsmasqConfig`](options.html#opt-services.pihole-ftl.useDnsmasqConfig) is enabled, the configuration [options of the Dnsmasq
|
||||
module](index.html#module-services-networking-dnsmasq) will be automatically
|
||||
used by pihole-FTL. Note that this may cause duplicate option errors
|
||||
depending on pihole-FTL settings.
|
||||
|
||||
See the [Dnsmasq
|
||||
example](index.html#module-services-networking-dnsmasq-configuration-home) for
|
||||
an exemplar Dnsmasq configuration. Make sure to set
|
||||
[{option}`services.dnsmasq.enable`](options.html#opt-services.dnsmasq.enable) to false and
|
||||
[{option}`services.pihole-ftl.enable`](options.html#opt-services.pihole-ftl.enable) to true instead:
|
||||
|
||||
```nix
|
||||
{
|
||||
services.pihole-ftl = {
|
||||
enable = true;
|
||||
useDnsmasqConfig = true;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Serving on multiple interfaces {#module-services-networking-pihole-ftl-configuration-multiple-interfaces}
|
||||
|
||||
Pi-hole's configuration only supports specifying a single interface. If you want
|
||||
to configure additional interfaces with different configuration, use
|
||||
`misc.dnsmasq_lines` to append extra Dnsmasq options.
|
||||
|
||||
```nix
|
||||
{
|
||||
services.pihole-ftl = {
|
||||
settings.misc.dnsmasq_lines = [
|
||||
# Specify the secondary interface
|
||||
"interface=enp1s0"
|
||||
# A different device is the router on this network, e.g. the one
|
||||
# provided by your ISP
|
||||
"dhcp-option=enp1s0,option:router,192.168.0.1"
|
||||
# Specify the IPv4 ranges to allocate, with a 1-day lease time
|
||||
"dhcp-range=enp1s0,192.168.0.10,192.168.0.253,1d"
|
||||
# Enable IPv6
|
||||
"dhcp-range=::f,::ff,constructor:enp1s0,ra-names,ra-stateless"
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Administration {#module-services-networking-pihole-ftl-administration}
|
||||
|
||||
*pihole command documentation*: <https://docs.pi-hole.net/main/pihole-command>
|
||||
|
||||
Enabling pihole-FTL provides the `pihole` command, which can be used to control
|
||||
the daemon and some configuration.
|
||||
|
||||
Note that in NixOS the script has been patched to remove the reinstallation,
|
||||
update, and Dnsmasq configuration commands. In NixOS, Pi-hole's configuration is
|
||||
immutable and must be done with NixOS options.
|
||||
|
||||
For more convenient administration and monitoring, see [Pi-hole
|
||||
Dashboard](#module-services-web-apps-pihole-web)
|
483
nixos/modules/services/networking/pihole-ftl.nix
Normal file
483
nixos/modules/services/networking/pihole-ftl.nix
Normal file
|
@ -0,0 +1,483 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
with {
|
||||
inherit (lib)
|
||||
elemAt
|
||||
getExe
|
||||
hasAttrByPath
|
||||
mkEnableOption
|
||||
mkIf
|
||||
mkOption
|
||||
strings
|
||||
types
|
||||
;
|
||||
};
|
||||
|
||||
let
|
||||
mkDefaults = lib.mapAttrsRecursive (n: v: lib.mkDefault v);
|
||||
|
||||
cfg = config.services.pihole-ftl;
|
||||
|
||||
piholeScript = pkgs.writeScriptBin "pihole" ''
|
||||
sudo=exec
|
||||
if [[ "$USER" != '${cfg.user}' ]]; then
|
||||
sudo='exec /run/wrappers/bin/sudo -u ${cfg.user}'
|
||||
fi
|
||||
$sudo ${getExe cfg.piholePackage} "$@"
|
||||
'';
|
||||
|
||||
settingsFormat = pkgs.formats.toml { };
|
||||
settingsFile = settingsFormat.generate "pihole.toml" cfg.settings;
|
||||
in
|
||||
{
|
||||
options.services.pihole-ftl = {
|
||||
enable = mkEnableOption "Pi-hole FTL";
|
||||
|
||||
package = lib.mkPackageOption pkgs "pihole-ftl" { };
|
||||
piholePackage = lib.mkPackageOption pkgs "pihole" { };
|
||||
|
||||
privacyLevel = mkOption {
|
||||
type = types.numbers.between 0 3;
|
||||
description = ''
|
||||
Level of detail in generated statistics. 0 enables full statistics, 3
|
||||
shows only anonymous statistics.
|
||||
|
||||
See [the documentation](https://docs.pi-hole.net/ftldns/privacylevels).
|
||||
|
||||
Also see services.dnsmasq.settings.log-queries to completely disable
|
||||
query logging.
|
||||
'';
|
||||
default = 0;
|
||||
example = "3";
|
||||
};
|
||||
|
||||
openFirewallDHCP = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Open ports in the firewall for pihole-FTL's DHCP server.";
|
||||
};
|
||||
|
||||
openFirewallWebserver = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Open ports in the firewall for pihole-FTL's webserver, as configured in `settings.webserver.port`.
|
||||
'';
|
||||
};
|
||||
|
||||
configDirectory = mkOption {
|
||||
type = types.path;
|
||||
default = "/etc/pihole";
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
description = ''
|
||||
Path for pihole configuration.
|
||||
pihole does not currently support any path other than /etc/pihole.
|
||||
'';
|
||||
};
|
||||
|
||||
stateDirectory = mkOption {
|
||||
type = types.path;
|
||||
default = "/var/lib/pihole";
|
||||
description = ''
|
||||
Path for pihole state files.
|
||||
'';
|
||||
};
|
||||
|
||||
logDirectory = mkOption {
|
||||
type = types.path;
|
||||
default = "/var/log/pihole";
|
||||
description = "Path for Pi-hole log files";
|
||||
};
|
||||
|
||||
settings = mkOption {
|
||||
type = settingsFormat.type;
|
||||
description = ''
|
||||
Configuration options for pihole.toml.
|
||||
See the upstream [documentation](https://docs.pi-hole.net/ftldns/configfile).
|
||||
'';
|
||||
};
|
||||
|
||||
useDnsmasqConfig = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Import options defined in [](#opt-services.dnsmasq.settings) via
|
||||
misc.dnsmasq_lines in Pi-hole's config.
|
||||
'';
|
||||
};
|
||||
|
||||
pihole = mkOption {
|
||||
type = types.package;
|
||||
default = piholeScript;
|
||||
internal = true;
|
||||
description = "Pi-hole admin script";
|
||||
};
|
||||
|
||||
lists =
|
||||
let
|
||||
adlistType = types.submodule {
|
||||
options = {
|
||||
url = mkOption {
|
||||
type = types.str;
|
||||
description = "URL of the domain list";
|
||||
};
|
||||
type = mkOption {
|
||||
type = types.enum [
|
||||
"allow"
|
||||
"block"
|
||||
];
|
||||
default = "block";
|
||||
description = "Whether domains on this list should be explicitly allowed, or blocked";
|
||||
};
|
||||
enabled = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Whether this list is enabled";
|
||||
};
|
||||
description = mkOption {
|
||||
type = types.str;
|
||||
description = "Description of the list";
|
||||
default = "";
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
mkOption {
|
||||
type = with types; listOf adlistType;
|
||||
description = "Deny (or allow) domain lists to use";
|
||||
default = [ ];
|
||||
example = [
|
||||
{
|
||||
url = "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts";
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = "pihole";
|
||||
description = "User to run the service as.";
|
||||
};
|
||||
|
||||
group = mkOption {
|
||||
type = types.str;
|
||||
default = "pihole";
|
||||
description = "Group to run the service as.";
|
||||
};
|
||||
|
||||
queryLogDeleter = {
|
||||
enable = mkEnableOption ("Pi-hole FTL DNS query log deleter");
|
||||
|
||||
age = mkOption {
|
||||
type = types.int;
|
||||
default = 90;
|
||||
description = ''
|
||||
Delete DNS query logs older than this many days, if
|
||||
[](#opt-services.pihole-ftl.queryLogDeleter.enable) is on.
|
||||
'';
|
||||
};
|
||||
|
||||
interval = mkOption {
|
||||
type = types.str;
|
||||
default = "weekly";
|
||||
description = ''
|
||||
How often the query log deleter is run. See systemd.time(7) for more
|
||||
information about the format.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = !config.services.dnsmasq.enable;
|
||||
message = "pihole-ftl conflicts with dnsmasq. Please disable one of them.";
|
||||
}
|
||||
|
||||
{
|
||||
assertion =
|
||||
builtins.length cfg.lists == 0
|
||||
|| (
|
||||
(hasAttrByPath [ "webserver" "port" ] cfg.settings)
|
||||
&& !builtins.elem cfg.settings.webserver.port [
|
||||
""
|
||||
null
|
||||
]
|
||||
);
|
||||
message = ''
|
||||
The Pi-hole webserver must be enabled for lists set in services.pihole-ftl.lists to be automatically loaded on startup via the web API.
|
||||
services.pihole-ftl.settings.port must be defined, e.g. by enabling services.pihole-web.enable and defining services.pihole-web.port.
|
||||
'';
|
||||
}
|
||||
|
||||
{
|
||||
assertion =
|
||||
builtins.length cfg.lists == 0
|
||||
|| !(hasAttrByPath [ "webserver" "api" "cli_pw" ] cfg.settings)
|
||||
|| cfg.settings.webserver.api.cli_pw == true;
|
||||
message = ''
|
||||
services.pihole-ftl.settings.webserver.api.cli_pw must be true for lists set in services.pihole-ftl.lists to be automatically loaded on startup.
|
||||
This enables an ephemeral password used by the pihole command.
|
||||
'';
|
||||
}
|
||||
];
|
||||
|
||||
services.pihole-ftl.settings = lib.mkMerge [
|
||||
# Defaults
|
||||
(mkDefaults {
|
||||
misc.readOnly = true; # Prevent config changes via API or CLI by default
|
||||
webserver.port = ""; # Disable the webserver by default
|
||||
misc.privacyLevel = cfg.privacyLevel;
|
||||
})
|
||||
|
||||
# Move state files to cfg.stateDirectory
|
||||
{
|
||||
# TODO: Pi-hole currently hardcodes dhcp-leasefile this in its
|
||||
# generated dnsmasq.conf, and we can't override it
|
||||
misc.dnsmasq_lines = [
|
||||
# "dhcp-leasefile=${cfg.stateDirectory}/dhcp.leases"
|
||||
# "hostsdir=${cfg.stateDirectory}/hosts"
|
||||
];
|
||||
|
||||
files = {
|
||||
database = "${cfg.stateDirectory}/pihole-FTL.db";
|
||||
gravity = "${cfg.stateDirectory}/gravity.db";
|
||||
macvendor = "${cfg.stateDirectory}/gravity.db";
|
||||
log.ftl = "${cfg.logDirectory}/FTL.log";
|
||||
log.dnsmasq = "${cfg.logDirectory}/pihole.log";
|
||||
log.webserver = "${cfg.logDirectory}/webserver.log";
|
||||
};
|
||||
|
||||
webserver.tls = "${cfg.stateDirectory}/tls.pem";
|
||||
}
|
||||
|
||||
(lib.optionalAttrs cfg.useDnsmasqConfig {
|
||||
misc.dnsmasq_lines = lib.pipe config.services.dnsmasq.configFile [
|
||||
builtins.readFile
|
||||
(lib.strings.splitString "\n")
|
||||
(builtins.filter (s: s != ""))
|
||||
];
|
||||
})
|
||||
];
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
"d ${cfg.configDirectory} 0700 ${cfg.user} ${cfg.group} - -"
|
||||
"d ${cfg.stateDirectory} 0700 ${cfg.user} ${cfg.group} - -"
|
||||
"d ${cfg.logDirectory} 0700 ${cfg.user} ${cfg.group} - -"
|
||||
];
|
||||
|
||||
systemd.services = {
|
||||
pihole-ftl =
|
||||
let
|
||||
setupService = config.systemd.services.pihole-ftl-setup.name;
|
||||
in
|
||||
{
|
||||
description = "Pi-hole FTL";
|
||||
|
||||
after = [ "network.target" ];
|
||||
before = [ setupService ];
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ setupService ];
|
||||
|
||||
environment = {
|
||||
# Currently unused, but allows the service to be reloaded
|
||||
# automatically when the config is changed.
|
||||
PIHOLE_CONFIG = settingsFile;
|
||||
|
||||
# pihole is executed by the /actions/gravity API endpoint
|
||||
PATH = lib.mkForce (
|
||||
lib.makeBinPath [
|
||||
cfg.piholePackage
|
||||
]
|
||||
);
|
||||
};
|
||||
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
AmbientCapabilities = [
|
||||
"CAP_NET_BIND_SERVICE"
|
||||
"CAP_NET_RAW"
|
||||
"CAP_NET_ADMIN"
|
||||
"CAP_SYS_NICE"
|
||||
"CAP_IPC_LOCK"
|
||||
"CAP_CHOWN"
|
||||
"CAP_SYS_TIME"
|
||||
];
|
||||
ExecStart = "${getExe cfg.package} no-daemon";
|
||||
Restart = "on-failure";
|
||||
RestartSec = 1;
|
||||
# Hardening
|
||||
NoNewPrivileges = true;
|
||||
PrivateTmp = true;
|
||||
PrivateDevices = true;
|
||||
DevicePolicy = "closed";
|
||||
ProtectSystem = "strict";
|
||||
ProtectHome = "read-only";
|
||||
ProtectControlGroups = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ReadWritePaths = [
|
||||
cfg.configDirectory
|
||||
cfg.stateDirectory
|
||||
cfg.logDirectory
|
||||
];
|
||||
RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
LockPersonality = true;
|
||||
};
|
||||
};
|
||||
|
||||
pihole-ftl-setup = {
|
||||
description = "Pi-hole FTL setup";
|
||||
# Wait for network so lists can be downloaded
|
||||
after = [ "network-online.target" ];
|
||||
requires = [ "network-online.target" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
|
||||
# Hardening
|
||||
NoNewPrivileges = true;
|
||||
PrivateTmp = true;
|
||||
PrivateDevices = true;
|
||||
DevicePolicy = "closed";
|
||||
ProtectSystem = "strict";
|
||||
ProtectHome = "read-only";
|
||||
ProtectControlGroups = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ReadWritePaths = [
|
||||
cfg.configDirectory
|
||||
cfg.stateDirectory
|
||||
cfg.logDirectory
|
||||
];
|
||||
RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
LockPersonality = true;
|
||||
};
|
||||
script = import ./pihole-ftl-setup-script.nix {
|
||||
inherit
|
||||
cfg
|
||||
config
|
||||
lib
|
||||
pkgs
|
||||
;
|
||||
};
|
||||
};
|
||||
|
||||
pihole-ftl-log-deleter = mkIf cfg.queryLogDeleter.enable {
|
||||
description = "Pi-hole FTL DNS query log deleter";
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
# Hardening
|
||||
NoNewPrivileges = true;
|
||||
PrivateTmp = true;
|
||||
PrivateDevices = true;
|
||||
DevicePolicy = "closed";
|
||||
ProtectSystem = "strict";
|
||||
ProtectHome = "read-only";
|
||||
ProtectControlGroups = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ReadWritePaths = [ cfg.stateDirectory ];
|
||||
RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
LockPersonality = true;
|
||||
};
|
||||
script =
|
||||
let
|
||||
days = toString cfg.queryLogDeleter.age;
|
||||
database = "${cfg.stateDirectory}/pihole-FTL.db";
|
||||
in
|
||||
''
|
||||
set -euo pipefail
|
||||
|
||||
echo "Deleting query logs older than ${days} days"
|
||||
${getExe cfg.package} sqlite3 "${database}" "DELETE FROM query_storage WHERE timestamp <= CAST(strftime('%s', date('now', '-${days} day')) AS INT); select changes() from query_storage limit 1"
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
systemd.timers.pihole-ftl-log-deleter = mkIf cfg.queryLogDeleter.enable {
|
||||
description = "Pi-hole FTL DNS query log deleter";
|
||||
before = [
|
||||
config.systemd.services.pihole-ftl.name
|
||||
config.systemd.services.pihole-ftl-setup.name
|
||||
];
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig = {
|
||||
OnCalendar = cfg.queryLogDeleter.interval;
|
||||
Unit = "pihole-ftl-log-deleter.service";
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall = lib.mkMerge [
|
||||
(mkIf cfg.openFirewallDHCP {
|
||||
allowedUDPPorts = [ 53 ];
|
||||
allowedTCPPorts = [ 53 ];
|
||||
})
|
||||
|
||||
(mkIf cfg.openFirewallWebserver {
|
||||
allowedTCPPorts = lib.pipe cfg.settings.webserver.port [
|
||||
(lib.splitString ",")
|
||||
(map (
|
||||
port:
|
||||
lib.pipe port [
|
||||
(builtins.split "[[:alpha:]]+")
|
||||
builtins.head
|
||||
lib.toInt
|
||||
]
|
||||
))
|
||||
];
|
||||
})
|
||||
];
|
||||
|
||||
users.users.${cfg.user} = {
|
||||
group = cfg.group;
|
||||
isSystemUser = true;
|
||||
};
|
||||
|
||||
users.groups.${cfg.group} = { };
|
||||
|
||||
environment.etc."pihole/pihole.toml" = {
|
||||
source = settingsFile;
|
||||
user = cfg.user;
|
||||
group = cfg.group;
|
||||
mode = "400";
|
||||
};
|
||||
|
||||
environment.systemPackages = [ cfg.pihole ];
|
||||
|
||||
services.logrotate.settings.pihole-ftl = {
|
||||
enable = true;
|
||||
files = [ "${cfg.logDirectory}/FTL.log" ];
|
||||
};
|
||||
};
|
||||
|
||||
meta = {
|
||||
doc = ./pihole-ftl.md;
|
||||
maintainers = with lib.maintainers; [ williamvds ];
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue