// Package cidr is a collection of assorted utilities for computing // network and host addresses within network ranges. // // It expects a CIDR-type address structure where addresses are divided into // some number of prefix bits representing the network and then the remaining // suffix bits represent the host. // // For example, it can help to calculate addresses for sub-networks of a // parent network, or to calculate host addresses within a particular prefix. // // At present this package is prioritizing simplicity of implementation and // de-prioritizing speed and memory usage. Thus caution is advised before // using this package in performance-critical applications or hot codepaths. // Patches to improve the speed and memory usage may be accepted as long as // they do not result in a significant increase in code complexity. package cidr import ( "fmt" "math/big" "net" ) // Subnet takes a parent CIDR range and creates a subnet within it // with the given number of additional prefix bits and the given // network number. // // For example, 10.3.0.0/16, extended by 8 bits, with a network number // of 5, becomes 10.3.5.0/24 . func Subnet(base *net.IPNet, newBits int, num int) (*net.IPNet, error) { ip := base.IP mask := base.Mask parentLen, addrLen := mask.Size() newPrefixLen := parentLen + newBits if newPrefixLen > addrLen { return nil, fmt.Errorf("insufficient address space to extend prefix of %d by %d", parentLen, newBits) } maxNetNum := uint64(1< maxNetNum { return nil, fmt.Errorf("prefix extension of %d does not accommodate a subnet numbered %d", newBits, num) } return &net.IPNet{ IP: insertNumIntoIP(ip, num, newPrefixLen), Mask: net.CIDRMask(newPrefixLen, addrLen), }, nil } // Host takes a parent CIDR range and turns it into a host IP address with // the given host number. // // For example, 10.3.0.0/16 with a host number of 2 gives 10.3.0.2. func Host(base *net.IPNet, num int) (net.IP, error) { ip := base.IP mask := base.Mask parentLen, addrLen := mask.Size() hostLen := addrLen - parentLen maxHostNum := uint64(1< maxHostNum { return nil, fmt.Errorf("prefix of %d does not accommodate a host numbered %d", parentLen, num) } return insertNumIntoIP(ip, num, 32), nil } // AddressRange returns the first and last addresses in the given CIDR range. func AddressRange(network *net.IPNet) (net.IP, net.IP) { // the first IP is easy firstIP := network.IP // the last IP is the network address OR NOT the mask address prefixLen, bits := network.Mask.Size() if prefixLen == bits { // Easy! // But make sure that our two slices are distinct, since they // would be in all other cases. lastIP := make([]byte, len(firstIP)) copy(lastIP, firstIP) return firstIP, lastIP } firstIPInt, bits := ipToInt(firstIP) hostLen := uint(bits) - uint(prefixLen) lastIPInt := big.NewInt(1) lastIPInt.Lsh(lastIPInt, hostLen) lastIPInt.Sub(lastIPInt, big.NewInt(1)) lastIPInt.Or(lastIPInt, firstIPInt) return firstIP, intToIP(lastIPInt, bits) } // AddressCount returns the number of distinct host addresses within the given // CIDR range. // // Since the result is a uint64, this function returns meaningful information // only for IPv4 ranges and IPv6 ranges with a prefix size of at least 65. func AddressCount(network *net.IPNet) uint64 { prefixLen, bits := network.Mask.Size() return 1 << (uint64(bits) - uint64(prefixLen)) }