@@ -5,12 +5,15 @@ import (
5
5
"compress/gzip"
6
6
"io"
7
7
"io/ioutil"
8
+ "math/big"
9
+ "net"
8
10
"os"
9
11
"path/filepath"
10
12
"reflect"
11
13
"strings"
12
14
13
15
"github.com/VirtusLab/render/renderer/parameters"
16
+ "github.com/apparentlymart/go-cidr/cidr"
14
17
15
18
"github.com/VirtusLab/go-extended/pkg/files"
16
19
json2 "github.com/VirtusLab/go-extended/pkg/json"
@@ -215,3 +218,145 @@ func asBytes(input interface{}) ([]byte, error) {
215
218
return nil , errors .Errorf ("expected []byte or string, got: '%v'" , reflect .TypeOf (input ))
216
219
}
217
220
}
221
+
222
+ func parseCIDR (prefix interface {}) (* net.IPNet , error ) {
223
+ if n , ok := prefix .(* net.IPNet ); ok {
224
+ return n , nil
225
+ }
226
+ if n , ok := prefix .(string ); ok {
227
+ _ , network , err := net .ParseCIDR (n )
228
+ return network , err
229
+ }
230
+
231
+ return nil , errors .Errorf ("cannot parse CIDR: %v" , prefix )
232
+ }
233
+
234
+ func toInts (in ... interface {}) []int {
235
+ out := make ([]int , len (in ))
236
+ for i , v := range in {
237
+ if vv , ok := v .(int ); ok {
238
+ out [i ] = vv
239
+ }
240
+ }
241
+ return out
242
+ }
243
+
244
+ // CidrHost calculates a full host IP address within a given IP network address prefix.
245
+ func CidrHost (hostnum int , prefix interface {}) (* net.IP , error ) {
246
+ logrus .Debug ("hostnum: " , hostnum )
247
+ logrus .Debug ("prefix: " , prefix )
248
+
249
+ network , err := parseCIDR (prefix )
250
+ if err != nil {
251
+ return nil , err
252
+ }
253
+
254
+ ip , err := cidr .HostBig (network , big .NewInt (int64 (hostnum )))
255
+ return & ip , err
256
+ }
257
+
258
+ // CidrNetmask converts an IPv4 address prefix given in CIDR notation into a subnet mask address.
259
+ func CidrNetmask (prefix interface {}) (* net.IP , error ) {
260
+ logrus .Debug ("prefix: " , prefix )
261
+
262
+ network , err := parseCIDR (prefix )
263
+ if err != nil {
264
+ return nil , err
265
+ }
266
+
267
+ if len (network .IP ) != net .IPv4len {
268
+ return nil , errors .Errorf ("only IPv4 networks are supported" )
269
+ }
270
+
271
+ netmask := net .IP (network .Mask )
272
+ return & netmask , nil
273
+ }
274
+
275
+ // CidrSubnets calculates a subnet address within a given IP network address prefix.
276
+ func CidrSubnets (newbits int , prefix interface {}) ([]* net.IPNet , error ) {
277
+ logrus .Debug ("newbits: " , newbits )
278
+ logrus .Debug ("prefix: " , prefix )
279
+
280
+ network , err := parseCIDR (prefix )
281
+ if err != nil {
282
+ return nil , err
283
+ }
284
+
285
+ if newbits < 1 {
286
+ return nil , errors .Errorf ("must extend prefix by at least one bit" )
287
+ }
288
+
289
+ maxnetnum := int64 (1 << uint64 (newbits ))
290
+ retValues := make ([]* net.IPNet , maxnetnum )
291
+ for i := int64 (0 ); i < maxnetnum ; i ++ {
292
+ subnet , err := cidr .SubnetBig (network , newbits , big .NewInt (i ))
293
+ if err != nil {
294
+ return nil , err
295
+ }
296
+ retValues [i ] = subnet
297
+ }
298
+
299
+ return retValues , nil
300
+ }
301
+
302
+ // CidrSubnetSizes calculates a sequence of consecutive subnet prefixes that may
303
+ // be of different prefix lengths under a common base prefix.
304
+ func CidrSubnetSizes (args ... interface {}) ([]* net.IPNet , error ) {
305
+ logrus .Debug ("args: " , args )
306
+
307
+ if len (args ) < 2 {
308
+ return nil , errors .Errorf ("wrong number of args: want 2 or more, got %d" , len (args ))
309
+ }
310
+
311
+ network , err := parseCIDR (args [len (args )- 1 ])
312
+ if err != nil {
313
+ return nil , err
314
+ }
315
+ newbits := toInts (args [:len (args )- 1 ]... )
316
+
317
+ startPrefixLen , _ := network .Mask .Size ()
318
+ firstLength := newbits [0 ]
319
+
320
+ firstLength += startPrefixLen
321
+ retValues := make ([]* net.IPNet , len (newbits ))
322
+
323
+ current , _ := cidr .PreviousSubnet (network , firstLength )
324
+
325
+ for i , length := range newbits {
326
+ if length < 1 {
327
+ return nil , errors .Errorf ("must extend prefix by at least one bit" )
328
+ }
329
+ // For portability with 32-bit systems where the subnet number
330
+ // will be a 32-bit int, we only allow extension of 32 bits in
331
+ // one call even if we're running on a 64-bit machine.
332
+ // (Of course, this is significant only for IPv6.)
333
+ if length > 32 {
334
+ return nil , errors .Errorf ("may not extend prefix by more than 32 bits" )
335
+ }
336
+
337
+ length += startPrefixLen
338
+ if length > (len (network .IP ) * 8 ) {
339
+ protocol := "IP"
340
+ switch len (network .IP ) {
341
+ case net .IPv4len :
342
+ protocol = "IPv4"
343
+ case net .IPv6len :
344
+ protocol = "IPv6"
345
+ }
346
+ return nil , errors .Errorf ("would extend prefix to %d bits, which is too long for an %s address" , length , protocol )
347
+ }
348
+
349
+ next , rollover := cidr .NextSubnet (current , length )
350
+ if rollover || ! network .Contains (next .IP ) {
351
+ // If we run out of suffix bits in the base CIDR prefix then
352
+ // NextSubnet will start incrementing the prefix bits, which
353
+ // we don't allow because it would then allocate addresses
354
+ // outside of the caller's given prefix.
355
+ return nil , errors .Errorf ("not enough remaining address space for a subnet with a prefix of %d bits after %s" , length , current .String ())
356
+ }
357
+ current = next
358
+ retValues [i ] = current
359
+ }
360
+
361
+ return retValues , nil
362
+ }
0 commit comments