1 // Package cidr is a collection of assorted utilities for computing
2 // network and host addresses within network ranges.
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.
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.
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.
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
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) {
34 parentLen, addrLen := mask.Size()
35 newPrefixLen := parentLen + newBits
37 if newPrefixLen > addrLen {
38 return nil, fmt.Errorf("insufficient address space to extend prefix of %d by %d", parentLen, newBits)
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)
47 IP: insertNumIntoIP(ip, num, newPrefixLen),
48 Mask: net.CIDRMask(newPrefixLen, addrLen),
52 // Host takes a parent CIDR range and turns it into a host IP address with
53 // the given host number.
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) {
60 parentLen, addrLen := mask.Size()
61 hostLen := addrLen - parentLen
63 maxHostNum := uint64(1<<uint64(hostLen)) - 1
65 numUint64 := uint64(num)
67 numUint64 = uint64(-num) - 1
68 num = int(maxHostNum - numUint64)
71 if numUint64 > maxHostNum {
72 return nil, fmt.Errorf("prefix of %d does not accommodate a host numbered %d", parentLen, num)
75 return insertNumIntoIP(ip, num, 32), nil
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
83 // the last IP is the network address OR NOT the mask address
84 prefixLen, bits := network.Mask.Size()
85 if prefixLen == bits {
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))
91 return firstIP, lastIP
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)
101 return firstIP, intToIP(lastIPInt, bits)
104 // AddressCount returns the number of distinct host addresses within the given
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))