diff --git a/lib/default.nix b/lib/default.nix index 1008025d8d18..6baea4de0413 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -571,6 +571,9 @@ let inherit (self.versions) splitVersion ; + inherit (self.network.ipv6) + mkEUI64Suffix + ; } ); in diff --git a/lib/network/default.nix b/lib/network/default.nix index e0c583ee7506..822abc9abf53 100644 --- a/lib/network/default.nix +++ b/lib/network/default.nix @@ -1,6 +1,14 @@ { lib }: let inherit (import ./internal.nix { inherit lib; }) _ipv6; + inherit (lib.strings) match concatStringsSep toLower; + inherit (lib.trivial) + pipe + bitXor + fromHexString + toHexString + ; + inherit (lib.lists) elemAt; in { ipv6 = { @@ -45,5 +53,60 @@ in { inherit address prefixLength; }; + + /** + Converts a 48-bit MAC address into a EUI-64 IPv6 address suffix. + + # Example + + ```nix + mkEUI64Suffix "66:75:63:6B:20:75" + => "6475:63ff:fe6b:2075" + ``` + + # Type + + ``` + mkEUI64Suffix :: String -> String + ``` + + # Inputs + + mac + : The MAC address (may contain these delimiters: `:`, `-` or `.` but it's not necessary) + */ + mkEUI64Suffix = + mac: + pipe mac [ + # match mac address + (match "^([0-9A-Fa-f]{2})[-:.]?([0-9A-Fa-f]{2})[-:.]?([0-9A-Fa-f]{2})[-:.]?([0-9A-Fa-f]{2})[-:.]?([0-9A-Fa-f]{2})[-:.]?([0-9A-Fa-f]{2})$") + + # check if there are matches + ( + matches: + if matches == null then + throw ''"${mac}" is not a valid MAC address (expected 6 octets of hex digits)'' + else + matches + ) + + # transform to result hextets + (octets: [ + # combine 1st and 2nd octets into first hextet, flip U/L bit, 512 = 0x200 + (toHexString (bitXor 512 (fromHexString ((elemAt octets 0) + (elemAt octets 1))))) + + # combine 3rd and 4th octets, combine them, insert fffe pattern in between to get next two hextets + "${elemAt octets 2}ff" + "fe${elemAt octets 3}" + + # combine 5th and 6th octets into the last hextet + ((elemAt octets 4) + (elemAt octets 5)) + ]) + + # concat to result suffix + (concatStringsSep ":") + + toLower + ]; }; } diff --git a/lib/tests/network.sh b/lib/tests/network.sh index 54ca476d2deb..543a75c0f565 100755 --- a/lib/tests/network.sh +++ b/lib/tests/network.sh @@ -114,4 +114,48 @@ expectFailure '(internal._ipv6.split "/::/").prefixLength' "is not a valid IPv expectSuccess 'lib.network.ipv6.fromString "2001:DB8::ffff/64"' '{"address":"2001:db8:0:0:0:0:0:ffff","prefixLength":64}' expectSuccess 'lib.network.ipv6.fromString "1234:5678:90ab:cdef:fedc:ba09:8765:4321/44"' '{"address":"1234:5678:90ab:cdef:fedc:ba09:8765:4321","prefixLength":44}' +expectSuccess 'mkEUI64Suffix "00:11:22:AA:BB:CC"' '"211:22ff:feaa:bbcc"' +expectSuccess 'mkEUI64Suffix "00-11-22-AA-BB-CC"' '"211:22ff:feaa:bbcc"' +expectSuccess 'mkEUI64Suffix "00.11.22.AA.BB.CC"' '"211:22ff:feaa:bbcc"' +expectSuccess 'mkEUI64Suffix "00:11:22:aa:bb:cc"' '"211:22ff:feaa:bbcc"' +expectSuccess 'mkEUI64Suffix "00-11-22-aa-bb-cc"' '"211:22ff:feaa:bbcc"' +expectSuccess 'mkEUI64Suffix "00.11.22.aa.bb.cc"' '"211:22ff:feaa:bbcc"' + +expectSuccess 'mkEUI64Suffix "12:34:56:78:9A:bc"' '"1034:56ff:fe78:9abc"' +expectSuccess 'mkEUI64Suffix "123456789ABC"' '"1034:56ff:fe78:9abc"' + +expectSuccess 'mkEUI64Suffix "001122AABBCC"' '"211:22ff:feaa:bbcc"' +expectSuccess 'mkEUI64Suffix "001122aabbcc"' '"211:22ff:feaa:bbcc"' + +expectSuccess 'mkEUI64Suffix "ff-ff-ff-ff-ff-ff"' '"fdff:ffff:feff:ffff"' +expectSuccess 'mkEUI64Suffix "ffffffffffff"' '"fdff:ffff:feff:ffff"' +expectSuccess 'mkEUI64Suffix "00.00.00.00.00.00"' '"200:00ff:fe00:0000"' +expectSuccess 'mkEUI64Suffix "000000000000"' '"200:00ff:fe00:0000"' + +expectFailure 'mkEUI64Suffix "123456789AB"' "is not a valid MAC address \(expected 6 octets of hex digits\)" +expectFailure 'mkEUI64Suffix "123456789A"' "is not a valid MAC address \(expected 6 octets of hex digits\)" +expectFailure 'mkEUI64Suffix "123456789"' "is not a valid MAC address \(expected 6 octets of hex digits\)" +expectFailure 'mkEUI64Suffix "12345678"' "is not a valid MAC address \(expected 6 octets of hex digits\)" +expectFailure 'mkEUI64Suffix "1234567"' "is not a valid MAC address \(expected 6 octets of hex digits\)" +expectFailure 'mkEUI64Suffix "123456"' "is not a valid MAC address \(expected 6 octets of hex digits\)" +expectFailure 'mkEUI64Suffix "12345"' "is not a valid MAC address \(expected 6 octets of hex digits\)" +expectFailure 'mkEUI64Suffix "1234"' "is not a valid MAC address \(expected 6 octets of hex digits\)" +expectFailure 'mkEUI64Suffix "123"' "is not a valid MAC address \(expected 6 octets of hex digits\)" +expectFailure 'mkEUI64Suffix "12"' "is not a valid MAC address \(expected 6 octets of hex digits\)" +expectFailure 'mkEUI64Suffix "1"' "is not a valid MAC address \(expected 6 octets of hex digits\)" +expectFailure 'mkEUI64Suffix ""' "is not a valid MAC address \(expected 6 octets of hex digits\)" +expectFailure 'mkEUI64Suffix "------------"' "is not a valid MAC address \(expected 6 octets of hex digits\)" +expectFailure 'mkEUI64Suffix "............"' "is not a valid MAC address \(expected 6 octets of hex digits\)" +expectFailure 'mkEUI64Suffix "::::::::::::"' "is not a valid MAC address \(expected 6 octets of hex digits\)" +expectFailure 'mkEUI64Suffix "1:2:3:4:5:6"' "is not a valid MAC address \(expected 6 octets of hex digits\)" +expectFailure 'mkEUI64Suffix "0.0.0.0.0.0"' "is not a valid MAC address \(expected 6 octets of hex digits\)" +expectFailure 'mkEUI64Suffix "00:11:-2:AA:BB:CC"' "is not a valid MAC address \(expected 6 octets of hex digits\)" +expectFailure 'mkEUI64Suffix "00:-11:22:AA:BB:CC"' "is not a valid MAC address \(expected 6 octets of hex digits\)" +expectFailure 'mkEUI64Suffix "ab:cd:ef:g0:12:34"' "is not a valid MAC address \(expected 6 octets of hex digits\)" +expectFailure 'mkEUI64Suffix "AB:CD:EF:G0:12:34"' "is not a valid MAC address \(expected 6 octets of hex digits\)" +expectFailure 'mkEUI64Suffix "ab:cd:ef:gh:jk:lm"' "is not a valid MAC address \(expected 6 octets of hex digits\)" +expectFailure 'mkEUI64Suffix "AB:CD:EF:GH:JK:LM"' "is not a valid MAC address \(expected 6 octets of hex digits\)" +expectFailure 'mkEUI64Suffix "01:23:3a:bc:de:fg"' "is not a valid MAC address \(expected 6 octets of hex digits\)" +expectFailure 'mkEUI64Suffix "01:23:3A:BC:DE:FG"' "is not a valid MAC address \(expected 6 octets of hex digits\)" + echo >&2 tests ok