]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/apparentlymart/go-cidr/cidr/cidr.go
Initial transfer of provider code
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / apparentlymart / go-cidr / cidr / cidr.go
1 // Package cidr is a collection of assorted utilities for computing
2 // network and host addresses within network ranges.
3 //
4 // It expects a CIDR-type address structure where addresses are divided into
5 // some number of prefix bits representing the network and then the remaining
6 // suffix bits represent the host.
7 //
8 // For example, it can help to calculate addresses for sub-networks of a
9 // parent network, or to calculate host addresses within a particular prefix.
10 //
11 // At present this package is prioritizing simplicity of implementation and
12 // de-prioritizing speed and memory usage. Thus caution is advised before
13 // using this package in performance-critical applications or hot codepaths.
14 // Patches to improve the speed and memory usage may be accepted as long as
15 // they do not result in a significant increase in code complexity.
16 package cidr
17
18 import (
19 "fmt"
20 "math/big"
21 "net"
22 )
23
24 // Subnet takes a parent CIDR range and creates a subnet within it
25 // with the given number of additional prefix bits and the given
26 // network number.
27 //
28 // For example, 10.3.0.0/16, extended by 8 bits, with a network number
29 // of 5, becomes 10.3.5.0/24 .
30 func Subnet(base *net.IPNet, newBits int, num int) (*net.IPNet, error) {
31 ip := base.IP
32 mask := base.Mask
33
34 parentLen, addrLen := mask.Size()
35 newPrefixLen := parentLen + newBits
36
37 if newPrefixLen > addrLen {
38 return nil, fmt.Errorf("insufficient address space to extend prefix of %d by %d", parentLen, newBits)
39 }
40
41 maxNetNum := uint64(1<<uint64(newBits)) - 1
42 if uint64(num) > maxNetNum {
43 return nil, fmt.Errorf("prefix extension of %d does not accommodate a subnet numbered %d", newBits, num)
44 }
45
46 return &net.IPNet{
47 IP: insertNumIntoIP(ip, num, newPrefixLen),
48 Mask: net.CIDRMask(newPrefixLen, addrLen),
49 }, nil
50 }
51
52 // Host takes a parent CIDR range and turns it into a host IP address with
53 // the given host number.
54 //
55 // For example, 10.3.0.0/16 with a host number of 2 gives 10.3.0.2.
56 func Host(base *net.IPNet, num int) (net.IP, error) {
57 ip := base.IP
58 mask := base.Mask
59
60 parentLen, addrLen := mask.Size()
61 hostLen := addrLen - parentLen
62
63 maxHostNum := uint64(1<<uint64(hostLen)) - 1
64
65 numUint64 := uint64(num)
66 if num < 0 {
67 numUint64 = uint64(-num) - 1
68 num = int(maxHostNum - numUint64)
69 }
70
71 if numUint64 > maxHostNum {
72 return nil, fmt.Errorf("prefix of %d does not accommodate a host numbered %d", parentLen, num)
73 }
74
75 return insertNumIntoIP(ip, num, 32), nil
76 }
77
78 // AddressRange returns the first and last addresses in the given CIDR range.
79 func AddressRange(network *net.IPNet) (net.IP, net.IP) {
80 // the first IP is easy
81 firstIP := network.IP
82
83 // the last IP is the network address OR NOT the mask address
84 prefixLen, bits := network.Mask.Size()
85 if prefixLen == bits {
86 // Easy!
87 // But make sure that our two slices are distinct, since they
88 // would be in all other cases.
89 lastIP := make([]byte, len(firstIP))
90 copy(lastIP, firstIP)
91 return firstIP, lastIP
92 }
93
94 firstIPInt, bits := ipToInt(firstIP)
95 hostLen := uint(bits) - uint(prefixLen)
96 lastIPInt := big.NewInt(1)
97 lastIPInt.Lsh(lastIPInt, hostLen)
98 lastIPInt.Sub(lastIPInt, big.NewInt(1))
99 lastIPInt.Or(lastIPInt, firstIPInt)
100
101 return firstIP, intToIP(lastIPInt, bits)
102 }
103
104 // AddressCount returns the number of distinct host addresses within the given
105 // CIDR range.
106 //
107 // Since the result is a uint64, this function returns meaningful information
108 // only for IPv4 ranges and IPv6 ranges with a prefix size of at least 65.
109 func AddressCount(network *net.IPNet) uint64 {
110 prefixLen, bits := network.Mask.Size()
111 return 1 << (uint64(bits) - uint64(prefixLen))
112 }