Last active
March 28, 2022 18:08
-
-
Save nikita-petko/cfdc1e8ac3bb0270c1b050ea0be14be6 to your computer and use it in GitHub Desktop.
Calculate Smallest CIDR from IPv4 Ranges.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 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]) | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I literally can't do IPv6 because there's no uint128 and I don't want to write one myself.