Skip to content

Instantly share code, notes, and snippets.

@infinisil
Created May 18, 2018 12:07
Show Gist options
  • Save infinisil/842168e1db442a70f18563dee1da7c4c to your computer and use it in GitHub Desktop.
Save infinisil/842168e1db442a70f18563dee1da7c4c to your computer and use it in GitHub Desktop.
Not sure where I got this from, it's not mine. This is apparently an ipv4/ipv6 parser written in Nix
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