Not sure where I got this from, it's not mine. This is apparently an ipv4/ipv6 parser written in Nix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
with import <nixpkgs> {}; | |
with lib; | |
let | |
script = '' | |
#!/usr/bin/env bash | |
echo hi | |
''; | |
shellCheck = script: | |
runCommand "shellcheck" {} '' | |
${shellcheck}/bin/shellcheck ${writeText "script" script} && touch $out | |
''; | |
parseErlIpAddr = addr: let | |
throwInvalid = throw "Invalid IPv4 or IPv6 address: ${addr}"; | |
tuplize = val: "{${concatStringsSep ", " val}}"; | |
v4DigitRe = "(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])"; | |
v6DigitRe = "([0-9a-fA-F]{0,4})"; | |
v4Re = "${v4DigitRe}\\.${v4DigitRe}\\.${v4DigitRe}\\.${v4DigitRe}"; | |
v4Parse = builtins.match v4Re addr; | |
v6Expanded = let | |
splitted = let | |
sanityCheck = builtins.match ".*(PAD|:::).*" addr != null; | |
splitter = val: let | |
result = builtins.match "([^:]*):(.*)" val; | |
iter = [ (head result) ] ++ splitter (last result); | |
in if result == null then [ val ] else iter; | |
prepared = splitter (replaceStrings ["::"] [":PAD:"] addr); | |
tooManyPads = length (filter (x: x == "PAD") prepared) > 1; | |
simple = if tooManyPads || sanityCheck then throwInvalid else prepared; | |
v4mapped = builtins.match v4Re (last simple); | |
rewritten = init simple ++ [ (take 2 v4mapped) (drop 2 v4mapped) ]; | |
in if v4mapped != null then rewritten else simple; | |
folder = acc: digit: let | |
afterAcc = length splitted - length acc; | |
accLen = length acc; | |
invalid = padLen < 1 && afterAcc > 2 && accLen > 1; | |
padLen = 8 - accLen - afterAcc + 1; | |
pad = genList (const "0") (if invalid then throwInvalid else padLen); | |
in if digit == "PAD" then acc ++ pad else acc ++ [ digit ]; | |
result = foldl' folder [] splitted; | |
in if length result != 8 then throwInvalid else result; | |
v6Parse = let | |
digitizeV6 = digit: let | |
chars = stringToCharacters (toLower digit); | |
padded = genList (const "0") (4 - length chars) ++ chars; | |
table = zipLists (stringToCharacters "0123456789abcdef") (range 0 15); | |
toDec = c: (findFirst (conv: conv.fst == c) throwInvalid table).snd; | |
d1 = toDec (head padded); | |
d2 = toDec (head (tail padded)); | |
d3 = toDec (last (init padded)); | |
d4 = toDec (last padded); | |
converted = toString (d1 * 4096 + d2 * 256 + d3 * 16 + d4); | |
in if digit == "" then "0" else converted; | |
digitizeV4 = d: toString (toInt (head d) * 256 + toInt (last d)); | |
convert = digit: let | |
result = builtins.match v6DigitRe digit; | |
v6 = if result != null then digitizeV6 (head result) else throwInvalid; | |
in if isList digit then digitizeV4 digit else v6; | |
in tuplize (map convert v6Expanded); | |
in if v4Parse != null then tuplize v4Parse else v6Parse; | |
in | |
parseErlIpAddr "7.2.6.7" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment