summaryrefslogtreecommitdiff
path: root/sys/net/options.nix
diff options
context:
space:
mode:
Diffstat (limited to 'sys/net/options.nix')
-rw-r--r--sys/net/options.nix278
1 files changed, 278 insertions, 0 deletions
diff --git a/sys/net/options.nix b/sys/net/options.nix
new file mode 100644
index 0000000..0608fb9
--- /dev/null
+++ b/sys/net/options.nix
@@ -0,0 +1,278 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ v4PtrHierarchy = address: bits: reverseList (sublist 0 (bits / 8) (splitString "." address));
+
+ v6PtrHierarchy = address: bits: let
+ separator = lists.findFirstIndex (hextet: hextet == "") null colonSplit;
+ colonSplit = splitString ":" address;
+
+ zeroFill = replicate (8 - length colonSplit + 1) "0000";
+ leftSplit = sublist 0 separator colonSplit;
+ rightSplit = sublist (separator + 1) (length colonSplit - separator - 1) colonSplit;
+
+ fullSplit =
+ if separator != null
+ then leftSplit ++ zeroFill ++ rightSplit
+ else colonSplit;
+
+ padded = map (hextet: strings.replicate (4 - stringLength hextet) "0" + hextet) fullSplit;
+ in
+ reverseList (sublist 0 (bits / 4) (flatten (map stringToCharacters padded)));
+
+ matchPtrRecordName = {
+ splitter,
+ netAddress,
+ netBits,
+ targetAddress,
+ targetBits,
+ }: let
+ netSplit = splitter netAddress netBits;
+ targetSplit = splitter targetAddress targetBits;
+
+ netLength = length netSplit;
+ lengthDelta = length targetSplit - netLength;
+
+ withinNet = lengthDelta >= 0 && sublist lengthDelta netLength targetSplit == netSplit;
+ throwMessage = "${targetAddress}/${toString targetBits} is not a subset of ${netAddress}/${toString netBits}";
+
+ recordHierarchy = sublist 0 lengthDelta targetSplit;
+
+ recordName =
+ if recordHierarchy != []
+ then concatStringsSep "." recordHierarchy
+ else "@";
+ in
+ throwIfNot withinNet throwMessage recordName;
+in {
+ options.local.nets = with lib.types;
+ mkOption {
+ readOnly = true;
+
+ type = attrsOf (submodule ({config, ...}: {
+ options = let
+ v4config = config.v4;
+ v6config = config.v6;
+ in {
+ hosts = mkOption {
+ default = {};
+
+ type = attrsOf (submodule {
+ options = {
+ v4 = mkOption {
+ default = null;
+
+ type = nullOr (submodule ({config, ...}: {
+ options = {
+ suffix = mkOption {
+ type = str;
+ };
+
+ address = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ cidr = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ single = mkOption {
+ type = str;
+ readOnly = true;
+ };
+ };
+
+ config = {
+ address =
+ if v4config.bits == 0
+ then config.suffix
+ else if v4config.bits == 32
+ then v4config.subnet
+ else "${v4config.prefix}.${config.suffix}";
+
+ cidr = "${config.address}/${toString v4config.bits}";
+ single = "${config.address}/32";
+ };
+ }));
+ };
+
+ v6 = mkOption {
+ default = null;
+
+ type = nullOr (submodule ({config, ...}: {
+ options = {
+ suffix = mkOption {
+ type = str;
+ };
+
+ address = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ cidr = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ single = mkOption {
+ type = str;
+ readOnly = true;
+ };
+ };
+
+ config = {
+ address = let
+ hextets = fragment: length (splitString ":" fragment);
+ separator =
+ if doubleColon
+ then "::"
+ else ":";
+ doubleColon = hextets v6config.prefix + hextets config.suffix < 8;
+
+ joined =
+ if v6config.bits == 128
+ then v6config.prefix
+ else if v6config.bits == 0
+ then config.suffix
+ else "${v6config.prefix}${separator}${config.suffix}";
+ in
+ joined;
+
+ cidr = "${config.address}/${toString v6config.bits}";
+ single = "${config.address}/128";
+ };
+ }));
+ };
+ };
+ });
+ };
+
+ v4 = mkOption {
+ default = null;
+
+ type = nullOr (submodule ({config, ...}: {
+ options = {
+ bits = mkOption {
+ type = enum [0 8 16 24 32];
+ };
+
+ prefix = mkOption {
+ type = str;
+ };
+
+ subnet = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ cidr = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ ptrDomain = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ ptrRecordName = mkOption {
+ type = functionTo (functionTo str);
+ readOnly = true;
+ };
+ };
+
+ config = {
+ cidr = "${config.subnet}/${toString config.bits}";
+
+ subnet =
+ if config.bits != 0
+ then config.prefix + strings.replicate (4 - config.bits / 8) ".0"
+ else "0.0.0.0";
+
+ ptrDomain = concatStrings (map (x: x + ".") (v4PtrHierarchy config.subnet config.bits)) + "in-addr.arpa";
+
+ ptrRecordName = address: bits:
+ matchPtrRecordName {
+ splitter = v4PtrHierarchy;
+
+ netBits = config.bits;
+ netAddress = config.subnet;
+
+ targetBits = bits;
+ targetAddress = address;
+ };
+ };
+ }));
+ };
+
+ v6 = mkOption {
+ default = null;
+
+ type = nullOr (submodule ({config, ...}: {
+ options = {
+ bits = mkOption {
+ type =
+ addCheck (ints.between 0 128) (b: mod b 4 == 0)
+ // {
+ description = "IPv6 subnet bits at nibble boundary";
+ };
+ };
+
+ prefix = mkOption {
+ type = str;
+ };
+
+ subnet = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ cidr = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ ptrDomain = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ ptrRecordName = mkOption {
+ type = functionTo (functionTo str);
+ readOnly = true;
+ };
+ };
+
+ config = {
+ cidr = "${config.subnet}/${toString config.bits}";
+
+ subnet =
+ if config.bits == 128 || length (splitString "::" config.prefix) > 1
+ then config.prefix
+ else "${config.prefix}::";
+
+ ptrDomain = concatStrings (map (x: x + ".") (v6PtrHierarchy config.subnet config.bits)) + "ip6.arpa";
+
+ ptrRecordName = address: bits:
+ matchPtrRecordName {
+ splitter = v6PtrHierarchy;
+
+ netBits = config.bits;
+ netAddress = config.subnet;
+
+ targetBits = bits;
+ targetAddress = address;
+ };
+ };
+ }));
+ };
+ };
+ }));
+ };
+}