Merge pull request #260962 from lunik1/inadyn-module

nixos/inadyn: init
This commit is contained in:
Sandro 2024-04-21 21:38:22 +02:00 committed by GitHub
commit 04a3a2a8fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 253 additions and 0 deletions

View file

@ -155,6 +155,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
- [microsocks](https://github.com/rofl0r/microsocks), a tiny, portable SOCKS5 server with very moderate resource usage. Available as [services.microsocks]($opt-services-microsocks.enable).
- [inadyn](https://github.com/troglobit/inadyn), a Dynamic DNS client with built-in support for multiple providers. Available as [services.inadyn](#opt-services.inadyn.enable).
- [Clevis](https://github.com/latchset/clevis), a pluggable framework for automated decryption, used to unlock encrypted devices in initrd. Available as [boot.initrd.clevis.enable](#opt-boot.initrd.clevis.enable).
- [fritz-exporter](https://github.com/pdreker/fritz_exporter), a Prometheus exporter for extracting metrics from [FRITZ!](https://avm.de/produkte/) devices. Available as [services.prometheus.exporters.fritz](#opt-services.prometheus.exporters.fritz.enable).

View file

@ -1012,6 +1012,7 @@
./services/networking/icecream/daemon.nix
./services/networking/icecream/scheduler.nix
./services/networking/imaginary.nix
./services/networking/inadyn.nix
./services/networking/inspircd.nix
./services/networking/iodine.nix
./services/networking/iperf3.nix

View file

@ -0,0 +1,250 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.inadyn;
# check if a value of an attrset is not null or an empty collection
nonEmptyValue = _: v: v != null && v != [ ] && v != { };
renderOption = k: v:
if builtins.elem k [ "provider" "custom" ] then
lib.concatStringsSep "\n"
(mapAttrsToList
(name: config: ''
${k} ${name} {
${lib.concatStringsSep "\n " (mapAttrsToList renderOption (filterAttrs nonEmptyValue config))}
}'')
v)
else if k == "include" then
"${k}(\"${v}\")"
else if k == "hostname" && builtins.isList v then
"${k} = { ${builtins.concatStringsSep ", " (map (s: "\"${s}\"") v)} }"
else if builtins.isBool v then
"${k} = ${boolToString v}"
else if builtins.isString v then
"${k} = \"${v}\""
else
"${k} = ${toString v}";
configFile' = pkgs.writeText "inadyn.conf"
''
# This file was generated by nix
# do not edit
${(lib.concatStringsSep "\n" (mapAttrsToList renderOption (filterAttrs nonEmptyValue cfg.settings)))}
'';
configFile = if (cfg.configFile != null) then cfg.configFile else configFile';
in
{
options.services.inadyn = with types;
let
providerOptions =
{
include = mkOption {
default = null;
description = mdDoc "File to include additional settings for this provider from.";
type = nullOr path;
};
ssl = mkOption {
default = true;
description = mdDoc "Whether to use HTTPS for this DDNS provider.";
type = bool;
};
username = mkOption {
default = null;
description = mdDoc "Username for this DDNS provider.";
type = nullOr str;
};
password = mkOption {
default = null;
description = mdDoc ''
Password for this DDNS provider.
WARNING: This will be world-readable in the nix store.
To store credentials securely, use the `include` or `configFile` options.
'';
type = nullOr str;
};
hostname = mkOption {
default = "*";
example = "your.cool-domain.com";
description = mdDoc "Hostname alias(es).";
type = either str (listOf str);
};
};
in
{
enable = mkEnableOption (mdDoc ''
synchronise your machine's IP address with a dynamic DNS provider using inadyn
'');
user = mkOption {
default = "inadyn";
type = types.str;
description = lib.mdDoc ''
User account under which inadyn runs.
::: {.note}
If left as the default value this user will automatically be created
on system activation, otherwise you are responsible for
ensuring the user exists before the inadyn service starts.
:::
'';
};
group = mkOption {
default = "inadyn";
type = types.str;
description = lib.mdDoc ''
Group account under which inadyn runs.
::: {.note}
If left as the default value this user will automatically be created
on system activation, otherwise you are responsible for
ensuring the user exists before the inadyn service starts.
:::
'';
};
interval = mkOption {
default = "*-*-* *:*:00";
description = mdDoc ''
How often to check the current IP.
Uses the format described in {manpage}`systemd.time(7)`";
'';
type = str;
};
logLevel = lib.mkOption {
type = lib.types.enum [ "none" "err" "warning" "info" "notice" "debug" ];
default = "notice";
description = lib.mdDoc "Set inadyn's log level.";
};
settings = mkOption {
default = { };
description = "See `inadyn.conf (5)`";
type = submodule {
freeformType = attrs;
options = {
allow-ipv6 = mkOption {
default = config.networking.enableIPv6;
defaultText = "`config.networking.enableIPv6`";
description = mdDoc "Whether to get IPv6 addresses from interfaces.";
type = bool;
};
forced-update = mkOption {
default = 2592000;
description = mdDoc "Duration (in seconds) after which an update is forced.";
type = ints.positive;
};
provider = mkOption {
default = { };
description = mdDoc ''
Settings for DDNS providers built-in to inadyn.
For a list of built-in providers, see `inadyn.conf (5)`.
'';
type = attrsOf (submodule {
freeformType = attrs;
options = providerOptions;
});
};
custom = mkOption {
default = { };
description = mdDoc ''
Settings for custom DNS providers.
'';
type = attrsOf (submodule {
freeformType = attrs;
options = providerOptions // {
ddns-server = mkOption {
description = mdDoc "DDNS server name.";
type = str;
};
ddns-path = mkOption {
description = mdDoc ''
DDNS server path.
See `inadnyn.conf (5)` for a list for format specifiers that can be used.
'';
example = "/update?user=%u&password=%p&domain=%h&myip=%i";
type = str;
};
};
});
};
};
};
};
configFile = mkOption {
default = null;
description = mdDoc ''
Configuration file for inadyn.
Setting this will override all other configuration options.
Passed to the inadyn service using LoadCredential.
'';
type = nullOr path;
};
};
config = lib.mkIf cfg.enable {
systemd = {
services.inadyn = {
description = "Update nameservers using inadyn";
documentation = [
"man:inadyn"
"man:inadyn.conf"
"file:${pkgs.inadyn}/share/doc/inadyn/README.md"
];
requires = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
startAt = cfg.interval;
serviceConfig = {
Type = "oneshot";
ExecStart = ''${lib.getExe pkgs.inadyn} -f ${configFile} --cache-dir ''${CACHE_DIRECTORY}/inadyn -1 --foreground -l ${cfg.logLevel}'';
LoadCredential = "config:${configFile}";
CacheDirectory = "inadyn";
User = cfg.user;
Group = cfg.group;
UMask = "0177";
LockPersonality = true;
MemoryDenyWriteExecute = true;
RestrictAddressFamilies = "AF_INET AF_INET6 AF_NETLINK";
NoNewPrivileges = true;
PrivateDevices = true;
PrivateTmp = true;
PrivateUsers = true;
ProtectSystem = "strict";
ProtectProc = "invisible";
ProtectHome = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallErrorNumber = "EPERM";
SystemCallFilter = "@system-service";
CapabilityBoundingSet = "";
};
};
timers.inadyn.timerConfig.Persistent = true;
};
users.users.inadyn = mkIf (cfg.user == "inadyn") {
group = cfg.group;
isSystemUser = true;
};
users.groups = mkIf (cfg.group == "inadyn") {
inadyn = { };
};
};
}