Skip to content

Instantly share code, notes, and snippets.

@nikita-petko
Last active March 28, 2022 18:08
Show Gist options
  • Select an option

  • Save nikita-petko/cfdc1e8ac3bb0270c1b050ea0be14be6 to your computer and use it in GitHub Desktop.

Select an option

Save nikita-petko/cfdc1e8ac3bb0270c1b050ea0be14be6 to your computer and use it in GitHub Desktop.
Calculate Smallest CIDR from IPv4 Ranges.
// This caluculates the smallest CIDR block that can be used to cover the given IP range.
package main
import (
"flag"
"fmt"
"net"
)
var startIp = flag.String("start", "", "Start IP address")
var endIp = flag.String("end", "", "End IP address")
func main() {
flag.Usage = func() {
println("Usage:")
println(" -start=<start_ip> -end=<end_ip>")
}
flag.Parse()
if *startIp == "" || *endIp == "" {
flag.Usage()
return
}
// Determine if the start and end IPs are valid
start := net.ParseIP(*startIp)
end := net.ParseIP(*endIp)
if start == nil || end == nil {
println("Invalid IP address")
flag.Usage()
return
}
// Ip can only be ipv4
start = start.To4()
end = end.To4()
if start == nil || end == nil {
println("Invalid IP address")
flag.Usage()
return
}
// Convert the IPs to integers
startInt := ipToInt(start)
endInt := ipToInt(end)
// Determine all bits that are different between the two IPs with a bitwise XOR
diff := startInt ^ endInt
// Now count the number of consecutive zero bits starting at the most significant
bits := 32
mask := 0
for diff != 0 {
// We keep shifting diffs right until it's zero (i.e. we've shifted all the non-zero bits off)
diff >>= 1
// Every time we shift, that's one fewer consecutive zero bits in the prefix
bits--
// Accumulate a mask which will have zeros in the consecutive zeros of the prefix and ones elsewhere
mask = (mask << 1) | 1
}
// Construct the root of the range by inverting the mask and ANDing it with the start address
root := startInt & uint32(^mask)
// Print the range
fmt.Printf("%d.%d.%d.%d/%d\n", root>>24, (root>>16)&0xff, (root>>8)&0xff, root&0xff, bits)
}
func ipToInt(ip net.IP) uint32 {
return uint32(ip[0])<<24 + uint32(ip[1])<<16 + uint32(ip[2])<<8 + uint32(ip[3])
}
@nikita-petko
Copy link
Author

I literally can't do IPv6 because there's no uint128 and I don't want to write one myself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment