Skip to content

Instantly share code, notes, and snippets.

@unakatsuo
Created December 7, 2020 12:05
Show Gist options
  • Save unakatsuo/dd1b7c47cb6db45d423635b291e91556 to your computer and use it in GitHub Desktop.
Save unakatsuo/dd1b7c47cb6db45d423635b291e91556 to your computer and use it in GitHub Desktop.
IP range iteration utility for golang
// IterateIPRange calculates the sequence of IP address from beginAddr to endAddr
// then calls the callback cb for each address of the sequence.
// beginAddr value must be smaller than endAddr.
func IterateIPRange(beginAddr, endAddr net.IP, cb func(addr net.IP)) error {
incIP := func(ip net.IP) net.IP {
for j := len(ip) - 1; j >= 0; j-- {
ip[j]++
if ip[j] > 0 {
break
}
}
return ip
}
gtIP := func(a, b net.IP) bool {
for i := len(a) - 1; i >= 0; i-- {
if a[i] > b[i] {
return false
}
}
return true
}
if !gtIP(beginAddr, endAddr) {
return fmt.Errorf("beginIP must be smaller than endIP: begin=%s, end=%s", beginAddr, endAddr)
}
var addr = make(net.IP, len(beginAddr))
for copy(addr, beginAddr); gtIP(addr, endAddr); addr = incIP(addr) {
cb(addr)
}
return nil
}
// IterateIPSubnet walks through all the IP addresses in the subnet range.
func IterateIPSubnet(subnet *net.IPNet, cb func(addr net.IP)) {
startAddr := subnet.IP.Mask(subnet.Mask)
endAddr := make(net.IP, len(startAddr))
for i := 0; i <= len(startAddr)-1; i++ {
endAddr[i] = byte(startAddr[i]) | byte(subnet.Mask[i]^0xFF)
}
if err := IterateIPRange(startAddr, endAddr, cb); err != nil {
panic(err)
}
}
@maffe
Copy link

maffe commented May 10, 2025

endAddr[i] = byte(startAddr[i]) | byte(subnet.Mask[i]^0xFF)
can be simplified to
endAddr[i] = startAddr[i] | ^subnet.Mask[i]

Also it seems unneccessary to return and assign the address passed to incIP since the passed instance itself is modified.

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