# Thank you: https://gist.github.com/petabyteboy/558ffddb9aeb24e1eab2d5d6d021b5d7 with import <nixpkgs/lib>; rec { # FIXME: add case for negative numbers pow = base: exponent: if exponent == 0 then 1 else fold ( x: y: y * base ) base ( range 2 exponent ); fromHexString = hex: foldl ( x: y: 16 * x + ( ( listToAttrs ( map ( x: nameValuePair ( toString x ) x ) ( range 0 9 ) ) // { "a" = 10; "b" = 11; "c" = 12; "d" = 13; "e" = 14; "f" = 15; } ).${y} ) ) 0 ( stringToCharacters ( removePrefix "0x" ( hex ) ) ); ipv4 = rec { decode = address: foldl ( x: y: 256 * x + y ) 0 ( map toInt ( splitString "." address ) ); encode = num: concatStringsSep "." ( map ( x: toString (mod (num / x) 256) ) ( reverseList ( genList ( x: pow 2 (x * 8) ) 4 ) ) ); netmask = prefixLength: ( foldl ( x: y: 2 * x + 1 ) 0 ( range 1 prefixLength ) ) * ( pow 2 ( 32 - prefixLength ) ); reverseZone = net: ( concatStringsSep "." ( reverseList ( splitString "." net ) ) ) + ".in-addr.arpa"; eachAddress = net: prefixLength: genList ( x: decode ( x + ( decode net ) ) ) ( pow 2 ( 32 - prefixLength ) ); networkOf = address: prefixLength: encode ( bitAnd ( decode address ) ( netmask prefixLength ) ); isInNetwork = net: address: networkOf address == net; /* nixos-specific stuff */ findOwnAddress = config: net: head ( filter ( isInNetwork net ) ( configuredAddresses config ) ); configuredAddresses = config: concatLists ( mapAttrsToList ( name: iface: iface.ipv4.addresses ) config.networking.interfaces ); }; ipv6 = rec { expand = address: ( replaceStrings ["::"] [( concatStringsSep "0" ( genList (x: ":") ( 9 - (count (x: x == ":") (stringToCharacters address)) ) ) )] address ) + ( if hasSuffix "::" address then "0" else "" ); decode = address: map fromHexString ( splitString ":" ( expand address ) ); encode = address: toLower ( concatStringsSep ":" ( map toHexString address ) ); netmask = prefixLength: map ( x: if prefixLength > x + 16 then (pow 2 16) - 1 else if prefixLength < x then 0 else ( foldl ( x: y: 2 * x + 1 ) 0 ( range 1 (prefixLength - x) ) ) * ( pow 2 ( 16 - (prefixLength - x) ) ) ) ( genList ( x: x * 16 ) 8 ); reverseZone = net: ( concatStringsSep "." ( concatLists ( reverseList ( map ( x: stringToCharacters (fixedWidthString 4 "0" x) ) ( splitString ":" ( expand net ) ) ) ) ) ) + ".ip6.arpa"; networkOf = address: prefixLength: encode ( zipListsWith bitAnd ( decode address ) ( netmask prefixLength ) ); isInNetwork = net: address: networkOf address == (expand net); /* nixos-specific stuff */ findOwnAddress = config: net: head ( filter ( isInNetwork net ) ( configuredAddresses config ) ); configuredAddresses = config: concatLists ( mapAttrsToList ( name: iface: iface.ipv6.addresses ) config.networking.interfaces ); }; }