python312Packages.aiohomeconnect: 0.10.0 -> 0.11.0 (#374011)
[NixPkgs.git] / nixos / modules / services / networking / crab-hole.nix
blob7e68c649ad5b2eefb9f058d21ff32bb3f9444170
2   config,
3   lib,
4   pkgs,
5   ...
6 }:
7 let
8   cfg = config.services.crab-hole;
10   settingsFormat = pkgs.formats.toml { };
12   checkConfig =
13     file:
14     pkgs.runCommand "check-config"
15       {
16         nativeBuildInputs = [
17           cfg.package
18           pkgs.cacert
19           pkgs.dig
20         ];
21       }
22       ''
23         ln -s ${file} $out
25         ln -s ${file} ./config.toml
26         export CRAB_HOLE_DIR=$(pwd)
28         ${lib.getExe cfg.package} validate-config
29       '';
32   options = {
33     services.crab-hole = {
34       enable = lib.mkEnableOption "Crab-hole Service";
36       package = lib.mkPackageOption pkgs "crab-hole" { };
38       supplementaryGroups = lib.mkOption {
39         type = lib.types.listOf lib.types.str;
40         default = [ ];
41         example = [ "acme" ];
42         description = "Adds additional groups to the crab-hole service. Can be useful to prevent permission issues.";
43       };
45       settings = lib.mkOption {
46         description = "Crab-holes config. See big example https://github.com/LuckyTurtleDev/crab-hole/blob/main/example-config.toml";
48         example = {
49           downstream = [
50             {
51               listen = "localhost";
52               port = 8080;
53               protocol = "udp";
54             }
55             {
56               certificate = "dns.example.com.crt";
57               dns_hostname = "dns.example.com";
58               key = "dns.example.com.key";
59               listen = "[::]";
60               port = 8055;
61               protocol = "https";
62               timeout_ms = 3000;
63             }
64           ];
65           api = {
66             admin_key = "1234";
67             listen = "127.0.0.1";
68             port = 8080;
69             show_doc = true;
70           };
71           blocklist = {
72             allow_list = [
73               "file:///allowed.txt"
74             ];
75             include_subdomains = true;
76             lists = [
77               "https://raw.githubusercontent.com/StevenBlack/hosts/master/alternates/fakenews-gambling-porn/hosts"
78               "https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt"
79               "file:///blocked.txt"
80             ];
81           };
82           upstream = {
83             name_servers = [
84               {
85                 protocol = "tls";
86                 socket_addr = "[2606:4700:4700::1111]:853";
87                 tls_dns_name = "1dot1dot1dot1.cloudflare-dns.com";
88                 trust_nx_responses = false;
89               }
90               {
91                 protocol = "tls";
92                 socket_addr = "1.1.1.1:853";
93                 tls_dns_name = "1dot1dot1dot1.cloudflare-dns.com";
94                 trust_nx_responses = false;
95               }
96             ];
97             options = {
98               validate = false;
99             };
100           };
101         };
103         type = lib.types.submodule {
104           freeformType = settingsFormat.type;
105           options = {
106             blocklist =
107               let
108                 listOption =
109                   name:
110                   lib.mkOption {
111                     type = lib.types.listOf (lib.types.either lib.types.str lib.types.path);
112                     default = [ ];
113                     description = "List of ${name}. If files are added via url, make sure the service has access to them!";
114                     apply = map (v: if builtins.isPath v then "file://${v}" else v);
115                   };
116               in
117               {
118                 include_subdomains = lib.mkEnableOption "Include subdomains";
119                 lists = listOption "blocklists";
120                 allow_list = listOption "allowlists";
121               };
122           };
123         };
124       };
126       configFile = lib.mkOption {
127         type = lib.types.path;
128         description = ''
129           The config file of crab-hole.
131           If files are added via url, make sure the service has access to them.
132           Setting this option will override any configuration applied by the settings option.
133         '';
134       };
135     };
136   };
138   config = lib.mkIf cfg.enable {
139     # Warning due to DNSSec issue in crab-hole
140     warnings = lib.optional (cfg.settings.upstream.options.validate or false) ''
141       Validate options will ONLY allow DNSSec domains. See https://github.com/LuckyTurtleDev/crab-hole/issues/29
142     '';
144     services.crab-hole.configFile = lib.mkDefault (
145       checkConfig (settingsFormat.generate "crab-hole.toml" cfg.settings)
146     );
147     environment.etc."crab-hole.toml".source = cfg.configFile;
149     systemd.services.crab-hole = {
150       wantedBy = [ "multi-user.target" ];
151       after = [ "network-online.target" ];
152       wants = [ "network-online.target" ];
153       description = "Crab-hole dns server";
154       environment.HOME = "/var/lib/crab-hole";
155       restartTriggers = [ cfg.configFile ];
156       serviceConfig = {
157         Type = "simple";
158         DynamicUser = true;
159         SupplementaryGroups = cfg.supplementaryGroups;
161         StateDirectory = "crab-hole";
162         WorkingDirectory = "/var/lib/crab-hole";
164         ExecStart = lib.getExe cfg.package;
166         AmbientCapabilities = "CAP_NET_BIND_SERVICE";
167         CapabilityBoundingSet = "CAP_NET_BIND_SERVICE";
169         Restart = "on-failure";
170         RestartSec = 1;
171       };
172     };
173   };
175   meta.maintainers = [
176     lib.maintainers.NiklasVousten
177   ];
178   # Readme from upstream
179   meta.doc = ./crab-hole.md;