summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorAlejandro Soto <alejandro@34project.org>2025-08-25 16:03:33 -0600
committerAlejandro Soto <alejandro@34project.org>2025-08-25 16:06:35 -0600
commit377749b2902b67b4262c5be3c0c48c05785dc0f2 (patch)
tree560d69fd38eaf34e85f0419d47c1b2ee03c6e992 /sys
parent07cca17fd5168805d4c270e05833184247812a62 (diff)
sys/ns/rr: format
Diffstat (limited to 'sys')
-rw-r--r--sys/ns/rr.nix611
1 files changed, 306 insertions, 305 deletions
diff --git a/sys/ns/rr.nix b/sys/ns/rr.nix
index 8b4d119..7f089d1 100644
--- a/sys/ns/rr.nix
+++ b/sys/ns/rr.nix
@@ -79,366 +79,367 @@ in {
zones = mkOption {
default = {};
- type = with lib.types; attrsOf (submodule ({
- config,
- name,
- ...
- }: let
- nameOption = args @ {
- defaultZone ? "${name}.",
- permitRelative ? true,
+ type = with lib.types;
+ attrsOf (submodule ({
+ config,
+ name,
...
- }:
- mkOption (removeAttrs args ["defaultZone" "permitRelative"]
- // {
- type = domainRefType;
-
- apply = value: let
- zone =
- throwIfNot
- (hasSuffix "." defaultZone)
- "zone expression '${defaultZone}' must be absolute, not relative"
- defaultZone;
- in
- if value == "@"
- then zone
- else if hasSuffix "." value
- then value
- else if permitRelative
- then "${value}.${zone}"
- else throw "zone expression '${value}' in zone '${zone}' must be absolute, not relative";
- });
-
- rrType = options:
- mkOption {
- default = [];
- type = listOf (submodule {
- options =
- options
- // {
- name = nameOption {};
-
- ttl = mkOption {
- type = int;
- default = config.defaultTTL;
- };
- };
- });
- };
-
- rrConfig = {
- rrs,
- type,
- format,
- applyName ? (rr: rr.name),
- }: (map
- (rr: {
- inherit type;
- inherit (rr) ttl;
-
- data = format rr;
- name = applyName rr;
- })
- rrs);
- in {
- options = {
- local = mkOption {
- type = unspecified;
- default = globalConfig.local;
- readOnly = true;
- };
+ }: let
+ nameOption = args @ {
+ defaultZone ? "${name}.",
+ permitRelative ? true,
+ ...
+ }:
+ mkOption (removeAttrs args ["defaultZone" "permitRelative"]
+ // {
+ type = domainRefType;
+
+ apply = value: let
+ zone =
+ throwIfNot
+ (hasSuffix "." defaultZone)
+ "zone expression '${defaultZone}' must be absolute, not relative"
+ defaultZone;
+ in
+ if value == "@"
+ then zone
+ else if hasSuffix "." value
+ then value
+ else if permitRelative
+ then "${value}.${zone}"
+ else throw "zone expression '${value}' in zone '${zone}' must be absolute, not relative";
+ });
- defaultTTL = mkOption {
- type = int;
- default = 3600;
- };
+ rrType = options:
+ mkOption {
+ default = [];
+ type = listOf (submodule {
+ options =
+ options
+ // {
+ name = nameOption {};
+
+ ttl = mkOption {
+ type = int;
+ default = config.defaultTTL;
+ };
+ };
+ });
+ };
- ptrName = mkOption {
- type = nullOr str;
- default = null;
- };
+ rrConfig = {
+ rrs,
+ type,
+ format,
+ applyName ? (rr: rr.name),
+ }: (map
+ (rr: {
+ inherit type;
+ inherit (rr) ttl;
+
+ data = format rr;
+ name = applyName rr;
+ })
+ rrs);
+ in {
+ options = {
+ local = mkOption {
+ type = unspecified;
+ default = globalConfig.local;
+ readOnly = true;
+ };
- defaultPtr = {
- v4 = mkOption {
- type = nullOr str;
- default = null;
+ defaultTTL = mkOption {
+ type = int;
+ default = 3600;
};
- v6 = mkOption {
+ ptrName = mkOption {
type = nullOr str;
default = null;
};
- };
-
- nsdConfig = mkOption {
- type = attrsOf unspecified;
- default = {};
- };
-
- content = mkOption {
- type = lines;
- readOnly = true;
- };
-
- nullSerialHash = mkOption {
- type = nullOr str;
- default = null;
- };
-
- rr = mkOption {
- default = [];
- type =
- listOf
- (submodule {
- options = {
- name = nameOption {};
-
- ttl = mkOption {
- type = int;
- };
-
- class = mkOption {
- type = enum ["IN"];
- default = "IN";
- };
-
- type = mkOption {
- type = enum rrTypes;
- };
-
- data = mkOption {
- type = listOf (either int str);
- default = [];
- };
- };
- });
- };
- soa = {
- authorityZone = nameOption {
- default = "@";
- permitRelative = false;
- };
+ defaultPtr = {
+ v4 = mkOption {
+ type = nullOr str;
+ default = null;
+ };
- ttl = mkOption {
- type = int;
- default = config.defaultTTL;
+ v6 = mkOption {
+ type = nullOr str;
+ default = null;
+ };
};
- primary = nameOption {
- default = "ns1";
- defaultZone = config.soa.authorityZone;
+ nsdConfig = mkOption {
+ type = attrsOf unspecified;
+ default = {};
};
- hostmaster = mkOption {
- type = emailType;
- default = "hostmaster";
-
- apply = address: let
- split = splitString "@" address;
-
- user = head split;
- domain =
- if length split == 2
- then head (tail split)
- else removeSuffix "." config.soa.authorityZone;
- in
- if hasSuffix "." address
- then address
- else "${replaceStrings ["."] ["\\."] user}.${domain}.";
+ content = mkOption {
+ type = lines;
+ readOnly = true;
};
- serial = mkOption {
- type = nullOr int;
+ nullSerialHash = mkOption {
+ type = nullOr str;
default = null;
};
- refresh = mkOption {
- type = int;
- default = 3 * 3600;
+ rr = mkOption {
+ default = [];
+ type =
+ listOf
+ (submodule {
+ options = {
+ name = nameOption {};
+
+ ttl = mkOption {
+ type = int;
+ };
+
+ class = mkOption {
+ type = enum ["IN"];
+ default = "IN";
+ };
+
+ type = mkOption {
+ type = enum rrTypes;
+ };
+
+ data = mkOption {
+ type = listOf (either int str);
+ default = [];
+ };
+ };
+ });
};
- retry = mkOption {
- type = int;
- default = 3600;
- };
+ soa = {
+ authorityZone = nameOption {
+ default = "@";
+ permitRelative = false;
+ };
- expire = mkOption {
- type = int;
- default = 7 * 24 * 3600;
- };
+ ttl = mkOption {
+ type = int;
+ default = config.defaultTTL;
+ };
- negativeTTL = mkOption {
- type = int;
- default = 3600;
- };
- };
+ primary = nameOption {
+ default = "ns1";
+ defaultZone = config.soa.authorityZone;
+ };
- a = rrType {
- ipv4 = mkOption {
- type = str;
- };
+ hostmaster = mkOption {
+ type = emailType;
+ default = "hostmaster";
- ptr = mkOption {
- type = nullOr str;
- default = config.defaultPtr.v4;
- };
- };
+ apply = address: let
+ split = splitString "@" address;
- aaaa = rrType {
- ipv6 = mkOption {
- type = str;
- };
+ user = head split;
+ domain =
+ if length split == 2
+ then head (tail split)
+ else removeSuffix "." config.soa.authorityZone;
+ in
+ if hasSuffix "." address
+ then address
+ else "${replaceStrings ["."] ["\\."] user}.${domain}.";
+ };
- ptr = mkOption {
- type = nullOr str;
- default = config.defaultPtr.v6;
- };
- };
+ serial = mkOption {
+ type = nullOr int;
+ default = null;
+ };
- cname = rrType {
- target = nameOption {};
- };
+ refresh = mkOption {
+ type = int;
+ default = 3 * 3600;
+ };
- mx = rrType {
- host = nameOption {};
+ retry = mkOption {
+ type = int;
+ default = 3600;
+ };
- priority = mkOption {
- type = int;
+ expire = mkOption {
+ type = int;
+ default = 7 * 24 * 3600;
+ };
+
+ negativeTTL = mkOption {
+ type = int;
+ default = 3600;
+ };
};
- };
- ns = rrType {
- host = nameOption {};
- };
+ a = rrType {
+ ipv4 = mkOption {
+ type = str;
+ };
- ptr = rrType {
- target = nameOption {};
- };
+ ptr = mkOption {
+ type = nullOr str;
+ default = config.defaultPtr.v4;
+ };
+ };
- srv = rrType {
- host = nameOption {};
+ aaaa = rrType {
+ ipv6 = mkOption {
+ type = str;
+ };
- port = mkOption {
- type = port;
+ ptr = mkOption {
+ type = nullOr str;
+ default = config.defaultPtr.v6;
+ };
};
- priority = mkOption {
- type = int;
+ cname = rrType {
+ target = nameOption {};
};
- proto = mkOption {
- type = enum ["tcp" "udp"];
- };
+ mx = rrType {
+ host = nameOption {};
- service = mkOption {
- type = str;
+ priority = mkOption {
+ type = int;
+ };
};
- weight = mkOption {
- type = int;
+ ns = rrType {
+ host = nameOption {};
};
- };
- txt = rrType {
- text = mkOption {
- type = strMatching "[^\"\n\\]*\n?";
- apply = removeSuffix "\n";
+ ptr = rrType {
+ target = nameOption {};
};
- };
- };
-
- config = {
- nsdConfig.data = config.content;
-
- content = let
- rrLine = rr: concatMapStringsSep " " toString ([rr.name rr.ttl rr.class rr.type] ++ rr.data);
- in
- ''
- $ORIGIN ${name}.
- $TTL ${toString config.defaultTTL}
- ''
- + concatLines (map rrLine config.rr);
-
- rr = mkMerge [
- (mkOrder 0 (singleton {
- inherit (config.soa) ttl;
-
- name = "${name}.";
- type = "SOA";
-
- data = with config.soa; [
- primary
- hostmaster
- (throwIf (serial == null) "No serial defined for zone ${name}" serial)
- refresh
- retry
- expire
- negativeTTL
- ];
- }))
-
- (mkOrder 1 (rrConfig {
- rrs = config.ns;
- type = "NS";
- format = rr: [rr.host];
- }))
-
- (rrConfig {
- rrs = config.a;
- type = "A";
- format = rr: [rr.ipv4];
- })
- (rrConfig {
- rrs = config.aaaa;
- type = "AAAA";
- format = rr: [rr.ipv6];
- })
+ srv = rrType {
+ host = nameOption {};
- (rrConfig {
- rrs = config.cname;
- type = "CNAME";
- format = rr: [rr.target];
- })
+ port = mkOption {
+ type = port;
+ };
- (rrConfig {
- rrs = config.mx;
- type = "MX";
- format = rr: [rr.priority rr.host];
- })
+ priority = mkOption {
+ type = int;
+ };
- (rrConfig {
- rrs = config.ptr;
- type = "PTR";
- format = rr: [rr.target];
- })
+ proto = mkOption {
+ type = enum ["tcp" "udp"];
+ };
- (rrConfig {
- rrs = config.srv;
- type = "SRV";
+ service = mkOption {
+ type = str;
+ };
- format = rr: [rr.priority rr.weight rr.port rr.host];
- applyName = rr: "_${rr.service}._${rr.proto}.${rr.name}";
- })
+ weight = mkOption {
+ type = int;
+ };
+ };
- (rrConfig {
- rrs = config.txt;
- type = "TXT";
+ txt = rrType {
+ text = mkOption {
+ type = strMatching "[^\"\n\\]*\n?";
+ apply = removeSuffix "\n";
+ };
+ };
+ };
- format = rr: let
- # nsd-zonecheck: text string is longer than 255 characters, try splitting it into multiple parts
- txtFragments = text: let
- max = 255;
- length = stringLength text;
+ config = {
+ nsdConfig.data = config.content;
+
+ content = let
+ rrLine = rr: concatMapStringsSep " " toString ([rr.name rr.ttl rr.class rr.type] ++ rr.data);
+ in
+ ''
+ $ORIGIN ${name}.
+ $TTL ${toString config.defaultTTL}
+ ''
+ + concatLines (map rrLine config.rr);
+
+ rr = mkMerge [
+ (mkOrder 0 (singleton {
+ inherit (config.soa) ttl;
+
+ name = "${name}.";
+ type = "SOA";
+
+ data = with config.soa; [
+ primary
+ hostmaster
+ (throwIf (serial == null) "No serial defined for zone ${name}" serial)
+ refresh
+ retry
+ expire
+ negativeTTL
+ ];
+ }))
+
+ (mkOrder 1 (rrConfig {
+ rrs = config.ns;
+ type = "NS";
+ format = rr: [rr.host];
+ }))
+
+ (rrConfig {
+ rrs = config.a;
+ type = "A";
+ format = rr: [rr.ipv4];
+ })
+
+ (rrConfig {
+ rrs = config.aaaa;
+ type = "AAAA";
+ format = rr: [rr.ipv6];
+ })
+
+ (rrConfig {
+ rrs = config.cname;
+ type = "CNAME";
+ format = rr: [rr.target];
+ })
+
+ (rrConfig {
+ rrs = config.mx;
+ type = "MX";
+ format = rr: [rr.priority rr.host];
+ })
+
+ (rrConfig {
+ rrs = config.ptr;
+ type = "PTR";
+ format = rr: [rr.target];
+ })
+
+ (rrConfig {
+ rrs = config.srv;
+ type = "SRV";
+
+ format = rr: [rr.priority rr.weight rr.port rr.host];
+ applyName = rr: "_${rr.service}._${rr.proto}.${rr.name}";
+ })
+
+ (rrConfig {
+ rrs = config.txt;
+ type = "TXT";
+
+ format = rr: let
+ # nsd-zonecheck: text string is longer than 255 characters, try splitting it into multiple parts
+ txtFragments = text: let
+ max = 255;
+ length = stringLength text;
+ in
+ singleton (substring 0 max text) ++ optionals (length > max) (txtFragments (substring max length text));
in
- singleton (substring 0 max text) ++ optionals (length > max) (txtFragments (substring max length text));
- in
- map (fragment: "\"${fragment}\"") (txtFragments rr.text);
- })
- ];
- };
- }));
+ map (fragment: "\"${fragment}\"") (txtFragments rr.text);
+ })
+ ];
+ };
+ }));
};
};