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