Skip to content

Instantly share code, notes, and snippets.

@elseym
Created May 28, 2021 12:57
Show Gist options
  • Save elseym/5c0e45d8cc0e47e53c4eb64ebdeb5a59 to your computer and use it in GitHub Desktop.
Save elseym/5c0e45d8cc0e47e53c4eb64ebdeb5a59 to your computer and use it in GitHub Desktop.
kotenpflaumen
{ config, pkgs, lib, unstable, ... }:
with lib;
let
cfg = config.pflaumen.dns.server;
fmt = pkgs.formats.knotConf {};
overlay = _: flip recursiveUpdate { inherit formats; };
formats.knotConf = {}: rec {
sectionType = with types;
attrsOf (oneOf ((p: p ++ [ (listOf (oneOf p)) ]) [ bool str int float ]))
// { description = "knot.conf value"; };
type = with types;
oneOf [ (attrsOf (listOf sectionType)) sectionType ]
// { description = "knot.conf"; };
generateString = settings: let
order = [ "domain" "id" "target" ];
attrNamesOrdered = s: intersectLists (attrNames s) order ++ subtractLists order (attrNames s);
mkSection = n: v:
concatStringsSep (if isList v then "\n- " else "\n ") ([ "${n}:" ] ++ (
if isList v then if v == [] then [] else map mkPairs v
else if isAttrs v then if v == {} then [] else singleton (mkPairs v)
else abort "unsupported section type ${n}=" + (generators.toPretty {} v)
));
mkPairs = v: concatStringsSep "\n " (flatten (map (e: mkPair e v.${e}) (attrNamesOrdered v)));
mkPair = n: v:
if isList v then map (mkPair n) v
else singleton ("${n}: " + (
if isBool v then if true == v then "true" else "false"
else if strings.isCoercibleToString v then toString v
else abort "unsupported value type ${n}=" + (generators.toPretty {} v)
));
in concatStringsSep "\n" (mapAttrsToList mkSection settings);
generate = name: value: pkgs.runCommandNoCC name {
nativeBuildInputs = [ config.services.knot.package ];
value = generateString value;
passAsFile = [ "value" ];
} ''
knotc --config "$valuePath" conf-export >$out
'';
};
in {
options.pflaumen.dns.server = {
enable = mkEnableOption "knot as authoritative dns server";
settings = mkOption { type = types.submodule {
freeformType = fmt.type;
options.server = mkOption { type = types.submodule {
freeformType = fmt.sectionType;
options.listen = mkOption { type = with types; listOf str; apply = map (l: if hasInfix "@" l then l else "${l}@53"); };
}; default.listen = [ "0.0.0.0@53" "::@53" ]; };
options.log = mkOption { type = types.listOf (types.submodule {
freeformType = fmt.sectionType;
options.target = mkOption { type = with types; either str (enum [ "stdout" "stderr" "syslog" ]); };
options.any = mkOption { type = types.enum [ "critical" "error" "warning" "notice" "info" "debug" ]; };
}); default = []; };
options.remote = mkOption { type = types.listOf (types.submodule {
freeformType = fmt.sectionType;
options.id = mkOption { type = types.str; };
options.address = mkOption { type = with types; listOf str; };
}); default = []; };
options.acl = mkOption { type = types.listOf (types.submodule {
freeformType = fmt.sectionType;
options.id = mkOption { type = types.str; };
options.address = mkOption { type = with types; listOf str; };
options.action = mkOption { type = with types; listOf (enum [ "notify" "transfer" "update" ]); };
}); default = []; };
options.zone = mkOption { type = types.listOf (types.submodule {
freeformType = fmt.sectionType;
options.domain = mkOption { type = types.str; };
options.file = mkOption { type = with types; either str path; };
options.notify = mkOption { type = with types; listOf str; default = []; };
options.acl = mkOption { type = with types; listOf str; default = []; };
}); default = []; };
}; };
};
config = mkIf cfg.enable {
networking.firewall.allowedTCPPorts = [ 53 ];
networking.firewall.allowedUDPPorts = [ 53 ];
nixpkgs.overlays = [ overlay ];
services.knot.enable = true;
services.knot.package = unstable.knot-dns;
services.knot.extraConfig = fmt.generateString cfg.settings;
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment