2
2
lib ? ( import <nixpkgs> { } ) . lib ,
3
3
} :
4
4
let
5
- leftShift = num : n : if n == 0 then num else leftShift ( num * 2 ) ( n - 1 ) ;
6
-
7
- hexChars = lib . stringToCharacters "0123456789abcdef" ;
5
+ inherit ( builtins )
6
+ bitAnd
7
+ bitOr
8
+ bitXor
9
+ elemAt
10
+ genList
11
+ hashString
12
+ head
13
+ substring
14
+ tail
15
+ ;
16
+
17
+ inherit ( lib )
18
+ concatMapStringsSep
19
+ findFirst
20
+ fixedWidthNumber
21
+ flatten
22
+ flip
23
+ foldl
24
+ length
25
+ min
26
+ mod
27
+ optional
28
+ range
29
+ splitString
30
+ stringToCharacters
31
+ sublist
32
+ toHexString
33
+ toInt
34
+ toLower
35
+ zipLists
36
+ zipListsWith
37
+ ;
38
+
39
+ power' =
40
+ product : base : exp :
41
+ if exp == 0 then product else power' ( product * base ) base ( exp - 1 ) ;
42
+
43
+ power = power' 1 ;
44
+
45
+ leftShift = flip power' 2 ;
46
+
47
+ hexChars = stringToCharacters "0123456789abcdef" ;
8
48
9
49
# Return an integer between 0 and 15 representing the hex digit
10
50
fromHexDigit =
11
- c :
12
- ( lib . findFirst ( x : x . fst == c ) c ( lib . zipLists hexChars ( lib . range 0 ( lib . length hexChars - 1 ) ) ) )
13
- . snd ;
51
+ c : ( findFirst ( x : x . fst == c ) c ( zipLists hexChars ( range 0 ( length hexChars - 1 ) ) ) ) . snd ;
14
52
15
- fromHex = s : lib . foldl ( a : b : a * 16 + fromHexDigit b ) 0 ( lib . stringToCharacters ( lib . toLower s ) ) ;
53
+ fromHex = s : foldl ( a : b : a * 16 + fromHexDigit b ) 0 ( stringToCharacters ( toLower s ) ) ;
16
54
17
- toNetworkHexString = num : lib . toLower ( lib . toHexString num ) ;
55
+ toNetworkHexString = num : toLower ( toHexString num ) ;
18
56
19
- toHextetString = hextetNum : lib . fixedWidthNumber 4 ( toNetworkHexString hextetNum ) ;
57
+ toHextetString = hextetNum : fixedWidthNumber 4 ( toNetworkHexString hextetNum ) ;
20
58
in
21
59
rec {
22
- inherit leftShift ;
60
+ inherit leftShift power ;
61
+
62
+ generateHextets =
63
+ value :
64
+ let
65
+ hash = hashString "sha256" value ;
66
+ in
67
+ genList ( x : fromHex ( substring x 4 hash ) ) 8 ;
23
68
24
69
# Parse an IPv6 network address in CIDR form.
25
70
#
@@ -28,34 +73,32 @@ rec {
28
73
parseIpv6Network =
29
74
networkCidr :
30
75
let
31
- split = lib . splitString "/" networkCidr ;
76
+ split = splitString "/" networkCidr ;
32
77
33
- prefixLength = lib . toInt ( lib . elemAt split 1 ) ;
78
+ prefixLength = toInt ( elemAt split 1 ) ;
34
79
35
- unfilledHextets = map ( lib . splitString ":" ) ( lib . splitString "::" ( lib . elemAt split 0 ) ) ;
80
+ unfilledHextets = map ( splitString ":" ) ( splitString "::" ( elemAt split 0 ) ) ;
36
81
37
- numNeededHextets = lib . foldl ( sum : xs : sum + lib . length xs ) 0 unfilledHextets ;
82
+ numNeededHextets = foldl ( sum : xs : sum + length xs ) 0 unfilledHextets ;
38
83
39
- unmodifiedHextets = lib . flatten [
40
- ( map fromHex ( lib . elemAt unfilledHextets 0 ) )
41
- ( builtins . genList ( _ : 0 ) numNeededHextets )
42
- ( map fromHex ( lib . elemAt unfilledHextets 1 ) )
84
+ unmodifiedHextets = flatten [
85
+ ( map fromHex ( elemAt unfilledHextets 0 ) )
86
+ ( genList ( _ : 0 ) numNeededHextets )
87
+ ( map fromHex ( elemAt unfilledHextets 1 ) )
43
88
] ;
44
89
45
- fullHextets = lib . sublist 0 ( prefixLength / 16 ) unmodifiedHextets ;
90
+ fullHextets = sublist 0 ( prefixLength / 16 ) unmodifiedHextets ;
46
91
47
- nextHextetBits = lib . mod prefixLength 16 ;
92
+ nextHextetBits = mod prefixLength 16 ;
48
93
49
- partialHextet = lib . optional ( nextHextetBits != 0 ) (
50
- lib . bitAnd ( lib . elemAt unmodifiedHextets ( lib . length fullHextets ) ) (
94
+ partialHextet = optional ( nextHextetBits != 0 ) (
95
+ bitAnd ( elemAt unmodifiedHextets ( length fullHextets ) ) (
51
96
leftShift ( ( leftShift 1 nextHextetBits ) - 1 ) ( 16 - nextHextetBits )
52
97
)
53
98
) ;
54
99
55
100
hextets =
56
- fullHextets
57
- ++ partialHextet
58
- ++ builtins . genList ( _ : 0 ) ( 8 - ( lib . length fullHextets ) - ( lib . length partialHextet ) ) ;
101
+ fullHextets ++ partialHextet ++ genList ( _ : 0 ) ( 8 - ( length fullHextets ) - ( length partialHextet ) ) ;
59
102
in
60
103
{
61
104
inherit prefixLength hextets ;
67
110
# => "2001:0db8:0000:0000:0000:0000:0000:0001"
68
111
mkIpv6Address =
69
112
networkHextets : hostHextets :
70
- assert lib . length networkHextets == 8 ;
71
- assert lib . length hostHextets == 8 ;
72
- lib . concatMapStringsSep ":" toHextetString ( lib . zipListsWith lib . bitOr networkHextets hostHextets ) ;
113
+ assert length networkHextets == 8 ;
114
+ assert length hostHextets == 8 ;
115
+ concatMapStringsSep ":" toHextetString ( zipListsWith bitOr networkHextets hostHextets ) ;
73
116
74
117
# Generates the hextets of an IPv6 address with the last 64 bits populated
75
118
# based on the host's MAC address.
@@ -82,16 +125,63 @@ rec {
82
125
ff = fromHex "ff" ;
83
126
fe = fromHex "fe" ;
84
127
85
- macNums = map fromHex ( lib . splitString ":" macAddress ) ;
128
+ macNums = map fromHex ( splitString ":" macAddress ) ;
86
129
87
- mkHextet = upper : lower : lib . bitOr ( leftShift upper 8 ) lower ;
130
+ mkHextet = upper : lower : bitOr ( leftShift upper 8 ) lower ;
88
131
in
89
- assert lib . length macNums == 6 ; # ensure the MAC address is the correct length
90
- ( builtins . genList ( _ : 0 ) 4 )
132
+ assert length macNums == 6 ; # ensure the MAC address is the correct length
133
+ ( genList ( _ : 0 ) 4 )
91
134
++ [
92
- ( mkHextet ( builtins . bitXor ( builtins . elemAt macNums 0 ) 2 ) ( builtins . elemAt macNums 1 ) )
93
- ( mkHextet ( builtins . elemAt macNums 2 ) ff )
94
- ( mkHextet fe ( builtins . elemAt macNums 3 ) )
95
- ( mkHextet ( builtins . elemAt macNums 4 ) ( builtins . elemAt macNums 5 ) )
135
+ ( mkHextet ( bitXor ( elemAt macNums 0 ) 2 ) ( elemAt macNums 1 ) )
136
+ ( mkHextet ( elemAt macNums 2 ) ff )
137
+ ( mkHextet fe ( elemAt macNums 3 ) )
138
+ ( mkHextet ( elemAt macNums 4 ) ( elemAt macNums 5 ) )
96
139
] ;
140
+
141
+ # Generate a list of hextets for a network address from a prefix length.
142
+ #
143
+ # Example: networkMaskHextets 64
144
+ # => [ 65535 65535 65535 65535 0 0 0 0 ]
145
+ networkMaskHextets =
146
+ let
147
+ networkMaskHextets' =
148
+ hextets : bits :
149
+ let
150
+ bits' = bits - 16 ;
151
+ in
152
+ if bits' < 0 then
153
+ hextets ++ genList ( _ : 0 ) ( 8 - length hextets )
154
+ else
155
+ networkMaskHextets' (
156
+ hextets
157
+ ++ [
158
+ ( ( leftShift 1 ( min 16 bits ) ) - 1 )
159
+ ]
160
+ ) bits' ;
161
+ in
162
+ networkMaskHextets' [ ] ;
163
+
164
+ # A ULA address is any address in the fc00::/7 network.
165
+ mkUlaNetwork =
166
+ hextets : prefixLength :
167
+ let
168
+ firstHextet = fromHex "fc00" ;
169
+
170
+ firstHextet' = (
171
+ bitOr firstHextet (
172
+ # take the last 9 bits of the first hextet
173
+ bitAnd 511 ( head hextets )
174
+ )
175
+ ) ;
176
+
177
+ hextets' = [ firstHextet' ] ++ ( sublist 0 7 ( tail hextets ) ) ;
178
+
179
+ address = mkIpv6Address (
180
+ # This isn't entirely necessary, but makes the address look normal in
181
+ # config files.
182
+ zipListsWith bitAnd hextets' ( networkMaskHextets prefixLength )
183
+ ) ( genList ( _ : 0 ) 8 ) ;
184
+ in
185
+ assert length hextets == 8 ;
186
+ "${ address } /${ toString prefixLength } " ;
97
187
}
0 commit comments