1/* See: https://github.com/djacu/nixpkgs/blob/adb22cf/lib/network.nix */
2{ lib, ... }:
3
4let
5 /*
6 Converts an IP address from a list of ints to a string.
7
8 Type: prettyIp :: [ Int ] -> String
9
10 Examples:
11 prettyIp [ 192 168 70 9 ]
12 => "192.168.70.9"
13 */
14 prettyIp = addr:
15 lib.concatStringsSep "." (builtins.map builtins.toString addr);
16
17 /*
18 Given a bit mask, return the associated subnet mask.
19
20 Type: bitMaskToSubnetMask :: Int -> [ Int ]
21
22 Examples:
23 bitMaskToSubnetMask 15
24 => [ 255 254 0 0 ]
25 bitMaskToSubnetMask 24
26 => [ 255 255 255 0 ]
27 */
28 bitMaskToSubnetMask = bitMask: let
29 numOctets = 4;
30 octetBits = 8;
31 octetMin = 0;
32 octetMax = 255;
33 # How many initial parts of the mask are full (=255)
34 fullParts = bitMask / octetBits;
35 in
36 lib.genList (
37 idx:
38 # Fill up initial full parts
39 if idx < fullParts
40 then octetMax
41 # If we're above the first non-full part, fill with 0
42 else if fullParts < idx
43 then octetMin
44 # First non-full part generation
45 else _genPartialMask (lib.mod bitMask octetBits)
46 )
47 numOctets;
48
49 /*
50 Generate a the partial portion of a subnet mask.
51
52 Type: _genPartialMask :: Int -> Int
53
54 Examples:
55 _genPartialMask 0
56 => 0
57 _genPartialMask 1
58 => 128
59 _genPartialMask 2
60 => 192
61 _genPartialMask 3
62 => 224
63 _genPartialMask 4
64 => 240
65 _genPartialMask 5
66 => 248
67 _genPartialMask 6
68 => 252
69 _genPartialMask 7
70 => 254
71 */
72 _genPartialMask = n:
73 if n == 0
74 then 0
75 else _genPartialMask (n - 1) / 2 + 128;
76
77 /*
78 Given a subnet mask, return the associated bit mask.
79
80 Type: subnetMaskToBitMask :: [ Int ] -> Int
81
82 Examples:
83 subnetMaskToBitMask [ 255 254 0 0 ]
84 => 15
85 subnetMaskToBitMask [ 255 255 255 0 ]
86 => 24
87 */
88 subnetMaskToBitMask = subnetMask: let
89 partialBits = octet:
90 if octet == 0
91 then 0
92 else (lib.mod octet 2) + partialBits (octet / 2);
93 in
94 builtins.foldl'
95 (x: y: x + y)
96 0
97 (builtins.map partialBits subnetMask);
98
99 /*
100 Given a CIDR, return the IP Address.
101
102 Type: cidrToIpAddress :: String -> [ Int ]
103
104 Examples:
105 cidrToIpAddress "192.168.70.9/15"
106 => [ 192 168 70 9 ]
107 */
108 cidrToIpAddress = cidr: let
109 splitParts = lib.splitString "/" cidr;
110 addr = lib.elemAt splitParts 0;
111 parsed =
112 builtins.map
113 lib.toInt
114 (builtins.match "([0-9]+)\\.([0-9]+)\\.([0-9]+)\\.([0-9]+)" addr);
115 checkBounds = octet:
116 (octet >= 0) && (octet <= 255);
117 in
118 if (builtins.all checkBounds parsed)
119 then parsed
120 else builtins.throw "IP ${prettyIp addr} has out of bounds octet(s)";
121
122 /*
123 Given a CIDR, return the bitmask.
124
125 Type: cidrToBitMask :: String -> Int
126
127 Examples:
128 cidrToBitMask "192.168.70.9/15"
129 => 15
130 */
131 cidrToBitMask = cidr: let
132 splitParts = lib.splitString "/" cidr;
133 mask = lib.toInt (lib.elemAt splitParts 1);
134 checkBounds = mask:
135 (mask >= 0) && (mask <= 32);
136 in
137 if (checkBounds mask)
138 then mask
139 else builtins.throw "Bitmask ${builtins.toString mask} is invalid.";
140
141 /*
142 Given a CIDR, return the associated subnet mask.
143
144 Type: cidrToSubnetMask :: String -> [ Int ]
145
146 Examples:
147 cidrToSubnetMask "192.168.70.9/15"
148 => [ 255 254 0 0 ]
149 */
150 cidrToSubnetMask = cidr:
151 bitMaskToSubnetMask (cidrToBitMask cidr);
152
153 /*
154 Given a CIDR, return the associated network ID.
155
156 Type: cidrToNetworkId :: String -> [ Int ]
157
158 Examples:
159 cidrToNetworkId "192.168.70.9/15"
160 => [ 192 168 0 0 ]
161 */
162 cidrToNetworkId = cidr: let
163 ip = cidrToIpAddress cidr;
164 subnetMask = cidrToSubnetMask cidr;
165 in
166 lib.zipListsWith lib.bitAnd ip subnetMask;
167
168 /*
169 Given a CIDR, return the associated first usable IP address.
170
171 Type: cidrToFirstUsableIp :: String -> [ Int ]
172
173 Examples:
174 cidrToFirstUsableIp "192.168.70.9/15"
175 => [ 192 168 0 1 ]
176 */
177 cidrToFirstUsableIp = cidr: let
178 networkId = cidrToNetworkId cidr;
179 in
180 incrementIp networkId 1;
181
182 /*
183 Given a CIDR, return the associated broadcast address.
184
185 Type: cidrToBroadcastAddress :: String -> [ Int ]
186
187 Examples:
188 cidrToBroadcastAddress "192.168.70.9/15"
189 => [ 192 169 255 255 ]
190 */
191 cidrToBroadcastAddress = cidr: let
192 subnetMask = cidrToSubnetMask cidr;
193 networkId = cidrToNetworkId cidr;
194 in
195 getBroadcastAddress networkId subnetMask;
196
197 /*
198 Given a network ID and subnet mask, return the associated broadcast address.
199
200 Type: getBroadcastAddress :: [ Int ] -> [ Int ] -> [ Int ]
201
202 Examples:
203 getBroadcastAddress [ 192 168 0 0 ] [ 255 254 0 0 ]
204 => [ 192 169 255 255 ]
205 */
206 getBroadcastAddress = networkId: subnetMask:
207 lib.zipListsWith (nid: mask: 255 - mask + nid) networkId subnetMask;
208
209 /*
210 Given a CIDR, return the associated last usable IP address.
211
212 Type: cidrToLastUsableIp :: String -> [ Int ]
213
214 Examples:
215 cidrToLastUsableIp "192.168.70.9/15"
216 => [ 192 169 255 254 ]
217 */
218 cidrToLastUsableIp = cidr: let
219 broadcast = cidrToBroadcastAddress cidr;
220 in
221 incrementIp broadcast (-1);
222
223 /*
224 Increment the last octet of a given IP address.
225
226 Type: incrementIp :: [ Int ] -> Int -> [ Int ]
227
228 Examples:
229 incrementIp [ 192 168 70 9 ] 3
230 => [ 192 168 70 12 ]
231 incrementIp [ 192 168 70 9 ] (-2)
232 => [ 192 168 70 7 ]
233 */
234 incrementIp = addr: offset: let
235 lastOctet = lib.last addr;
236 firstThree = lib.init addr;
237 in
238 firstThree ++ [(lastOctet + offset)];
239
240 /*
241 Given an IP address and bit mask, return the associated CIDR.
242
243 Type: ipAndBitMaskToCidr :: [ Int ] -> Int -> String
244
245 Examples:
246 ipAndBitMaskToCidr [ 192 168 70 9 ] 15
247 => "192.168.70.9/15"
248 */
249 ipAndBitMaskToCidr = addr: bitMask:
250 lib.concatStringsSep "/"
251 [
252 (prettyIp addr)
253 (builtins.toString bitMask)
254 ];
255
256 /*
257 Given an IP address and subnet mask, return the associated CIDR.
258
259 Type: ipAndSubnetMaskToCidr :: [ Int ] -> Int -> String
260
261 Examples:
262 ipAndSubnetMaskToCidr [ 192 168 70 9 ] [ 255 254 0 0 ]
263 => "192.168.70.9/15"
264 */
265 ipAndSubnetMaskToCidr = addr: subnetMask:
266 ipAndBitMaskToCidr addr (subnetMaskToBitMask subnetMask);
267
268 /*
269 Given a CIDR, return an attribute set of:
270 the IP Address,
271 the bit mask,
272 the first usable IP address,
273 the last usable IP address,
274 the network ID,
275 the subnet mask,
276 the broadcast address.
277
278 Type: getNetworkProperties :: str -> attrset
279
280 Examples:
281 getNetworkProperties "192.168.70.9/15"
282 => {
283 bitMask = 15;
284 broadcast = "192.169.255.255";
285 firstUsableIp = "192.168.0.1";
286 ipAddress = "192.168.70.9";
287 lastUsableIp = "192.169.255.254";
288 networkId = "192.168.0.0";
289 subnetMask = "255.254.0.0";
290 }
291 */
292 getNetworkProperties = cidr: let
293 ipAddress = prettyIp (cidrToIpAddress cidr);
294 bitMask = cidrToBitMask cidr;
295 firstUsableIp = prettyIp (cidrToFirstUsableIp cidr);
296 lastUsableIp = prettyIp (cidrToLastUsableIp cidr);
297 networkId = prettyIp (cidrToNetworkId cidr);
298 subnetMask = prettyIp (cidrToSubnetMask cidr);
299 broadcast = prettyIp (cidrToBroadcastAddress cidr);
300 in {inherit ipAddress bitMask firstUsableIp lastUsableIp networkId subnetMask broadcast;};
301in {
302 ipv4 = {
303 inherit
304 prettyIp
305 incrementIp
306 bitMaskToSubnetMask
307 subnetMaskToBitMask
308 ipAndBitMaskToCidr
309 ipAndSubnetMaskToCidr
310 cidrToIpAddress
311 cidrToBitMask
312 cidrToFirstUsableIp
313 cidrToLastUsableIp
314 cidrToNetworkId
315 cidrToSubnetMask
316 cidrToBroadcastAddress
317 getNetworkProperties
318 ;
319 };
320}