Unverified Commit 8f5d24c1 authored by williamvds's avatar williamvds
Browse files

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.
parent 4bdf75f1
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -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"
  ],
+2 −0
Original line number Diff line number Diff line
@@ -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).
+1 −0
Original line number Diff line number Diff line
@@ -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
+82 −0
Original line number Diff line number Diff line
{
  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 −0
Original line number Diff line number Diff line
# 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)
Loading