// 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 main import ( "fmt" "math/big" "net" ) // 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)) } //NoOverlap takes a list subnets and supernet (CIDRBlock) and verifies //none of the subnets overlap and all subnets are in the supernet //it returns an error if any of those conditions are not satisfied func NoOverlap(subnets []*net.IPNet) error { firstLastIP := make([][]net.IP, len(subnets)) for i, s := range subnets { first, last := AddressRange(s) firstLastIP[i] = []net.IP{first, last} } for i, s := range subnets { for j := range subnets { if i == j { continue } first := firstLastIP[j][0] last := firstLastIP[j][1] if s.Contains(first) || s.Contains(last) { return fmt.Errorf("%s overlaps with %s", subnets[j].String(), s.String()) } } } return nil }