summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2018-12-07 13:17:16 +0100
committertv <tv@krebsco.de>2018-12-07 13:21:54 +0100
commit232e4d8615cfe9f20915dec25f59679583e80183 (patch)
treea8d75db9c0f206767195e50872ccb6cd37846b20 /lib
parent0a904df833d4ef1a7cfbcbb4d1738946a3029bfa (diff)
lib.krebs.genipv6: init
Diffstat (limited to 'lib')
-rw-r--r--lib/krebs/genipv6.nix92
1 files changed, 92 insertions, 0 deletions
diff --git a/lib/krebs/genipv6.nix b/lib/krebs/genipv6.nix
new file mode 100644
index 0000000..8d5ca16
--- /dev/null
+++ b/lib/krebs/genipv6.nix
@@ -0,0 +1,92 @@
+lib:
+with lib;
+let {
+ body = netname: subnetname: suffix: rec {
+ address = let
+ suffix' =
+ if hasEmptyGroup (parseAddress suffix)
+ then suffix
+ else joinAddress "::" suffix;
+ in
+ checkAddress addressLength (joinAddress subnetPrefix suffix');
+ addressCIDR = "${address}/${toString addressLength}";
+ addressLength = 128;
+
+ inherit netname;
+ netCIDR = "${netAddress}/${toString netPrefixLength}";
+ netAddress = joinAddress netPrefix "::";
+ netHash = toString {
+ retiolum = 0;
+ wirelum = 1;
+ }.${netname};
+ netPrefix = "42:${netHash}";
+ netPrefixLength = {
+ retiolum = 32;
+ wirelum = 32;
+ }.${netname};
+
+ inherit subnetname;
+ subnetCIDR = "${subnetAddress}/${toString subnetPrefixLength}";
+ subnetAddress = joinAddress subnetPrefix "::";
+ subnetHash = hash subnetname;
+ subnetPrefix = joinAddress netPrefix subnetHash;
+ subnetPrefixLength = netPrefixLength + 16;
+
+ inherit suffix;
+ suffixLength = addressLength - subnetPrefixLength;
+ };
+
+ hash = s: head (match "0*(.*)" (substring 0 4 (hashString "sha256" s)));
+
+ dropLast = n: xs: reverseList (drop n (reverseList xs));
+ takeLast = n: xs: reverseList (take n (reverseList xs));
+
+ hasEmptyPrefix = xs: take 2 xs == ["" ""];
+ hasEmptySuffix = xs: takeLast 2 xs == ["" ""];
+ hasEmptyInfix = xs: any (x: x == "") (trimEmpty 2 xs);
+
+ hasEmptyGroup = xs:
+ any (p: p xs) [hasEmptyPrefix hasEmptyInfix hasEmptySuffix];
+
+ ltrimEmpty = n: xs: if hasEmptyPrefix xs then drop n xs else xs;
+ rtrimEmpty = n: xs: if hasEmptySuffix xs then dropLast n xs else xs;
+ trimEmpty = n: xs: rtrimEmpty n (ltrimEmpty n xs);
+
+ parseAddress = splitString ":";
+ formatAddress = concatStringsSep ":";
+
+ check = s: c: if !c then throw "${s}" else true;
+
+ checkAddress = maxaddrlen: addr: let
+ parsedaddr = parseAddress addr;
+ normalizedaddr = trimEmpty 1 parsedaddr;
+ in
+ assert (check "address malformed; lone leading colon: ${addr}" (
+ head parsedaddr == "" -> tail (take 2 parsedaddr) == ""
+ ));
+ assert (check "address malformed; lone trailing colon ${addr}" (
+ last parsedaddr == "" -> head (takeLast 2 parsedaddr) == ""
+ ));
+ assert (check "address malformed; too many successive colons: ${addr}" (
+ length (filter (x: x == "") normalizedaddr) > 1 -> addr == [""]
+ ));
+ assert (check "address malformed: ${addr}" (
+ all (test "[0-9a-f]{0,4}") parsedaddr
+ ));
+ assert (check "address is too long: ${addr}" (
+ length normalizedaddr * 16 <= maxaddrlen
+ ));
+ addr;
+
+ joinAddress = prefix: suffix: let
+ parsedPrefix = parseAddress prefix;
+ parsedSuffix = parseAddress suffix;
+ normalizePrefix = rtrimEmpty 2 parsedPrefix;
+ normalizeSuffix = ltrimEmpty 2 parsedSuffix;
+ delimiter =
+ optional (length (normalizePrefix ++ normalizeSuffix) < 8 &&
+ (hasEmptySuffix parsedPrefix || hasEmptyPrefix parsedSuffix))
+ "";
+ in
+ formatAddress (normalizePrefix ++ delimiter ++ normalizeSuffix);
+}