mirror of
https://github.com/smcquay/cidr/
synced 2024-12-04 13:49:35 -08:00
83 lines
2.7 KiB
Go
83 lines
2.7 KiB
Go
// 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
|
|
}
|