forked from upbound/function-cidr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cidrsubnets.go
76 lines (63 loc) · 2.02 KB
/
cidrsubnets.go
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
package main
import (
"fmt"
"net"
"github.com/apparentlymart/go-cidr/cidr"
"github.com/pkg/errors"
)
const Bits32 = 32
const Bits128 = 128
func CidrSubnets(prefix string, newbits ...int) ([][]byte, error) {
_, network, err := net.ParseCIDR(prefix)
if err != nil {
return nil, err
}
startPrefixLen, _ := network.Mask.Size()
prefixLengthArgs := newbits
if len(prefixLengthArgs) == 0 {
return nil, nil
}
var firstLength int
firstLength = newbits[0]
firstLength += startPrefixLen
retVals := make([][]byte, len(prefixLengthArgs))
current, _ := cidr.PreviousSubnet(network, firstLength)
for i, lengthArg := range prefixLengthArgs {
var length int
length = lengthArg
if length < 1 {
return nil, errors.New("must extend prefix by at least one bit")
}
// For portability with 32-bit systems where the subnet number
// will be a 32-bit int, we only allow extension of 32 bits in
// one call even if we're running on a 64-bit machine.
// (Of course, this is significant only for IPv6.)
if length > Bits32 {
return nil, errors.New("may not extend prefix by more than 32 bits")
}
length += startPrefixLen
if length > (len(network.IP) * 8) {
protocol := "IP"
switch len(network.IP) * 8 {
case Bits32:
protocol = "IPv4"
case Bits128:
protocol = "IPv6"
}
errTxt := fmt.Sprintf("would extend prefix to %d bits, which is too long for an %s address", length, protocol)
return nil, errors.New(errTxt)
}
next, rollover := cidr.NextSubnet(current, length)
if rollover || !network.Contains(next.IP) {
// If we run out of suffix bits in the base CIDR prefix then
// NextSubnet will start incrementing the prefix bits, which
// we don't allow because it would then allocate addresses
// outside of the caller's given prefix.
errTxt := fmt.Sprintf("not enough remaining address space for a subnet with a prefix of %d bits after %s", length, current.String())
return nil, errors.New(errTxt)
}
current = next
retVals[i] = []byte(current.String())
}
return retVals, nil
}