ipfilter provides a matcher to filter IP addresses based on a list of CIDR ranges.
The matcher is optimized for speed and can handle a large number of ranges efficiently.
$ go get github.com/paralleltree/ipfilter
import ( "fmt" "net" "github.com/paralleltree/ipfilter" ) func example() { matcher, err := ipfilter.NewIPMatcher([]string{ "192.168.0.0/24", "192.168.1.0/24", }) if err != nil { panic(err) } ips := []string{ "192.168.0.10", "192.168.20.10", } for _, ip := range ips { result := matcher.Match(net.ParseIP(ip)) fmt.Printf("%s: %v\n", ip, result) } // Output: // 192.168.0.10: true // 192.168.20.10: false }
The matcher groups the given CIDR ranges by their prefix(subnet mask) length. When matching an IP address, it tries to find the corresponding range from each group using a binary search.
flowchart LR
root(IPMatcher)
ipv4set[IPv4RangeSet]
ipv6set[IPv6RangeSet]
ipv4PrefixLength16[prefixLength=16]
ipv4PrefixLength24[prefixLength=24]
ipv6PrefixLength64[prefixLength=64]
ipv4PrefixLength24Range1([192.168.0.0/24])
ipv4PrefixLength24Range2([192.168.1.0/24])
ipv6PrefixLength16Range1([172.16.0.0/16])
ipv6PrefixLength64Range1([2001:db8::/64])
ipv6PrefixLength64Range2([78ab:920::/64])
root --- ipv4set
root --- ipv6set
ipv4set --- ipv4PrefixLength16
ipv4set --- ipv4PrefixLength24
ipv4PrefixLength16 --- ipv6PrefixLength16Range1
ipv4PrefixLength24 --- ipv4PrefixLength24Range1
ipv4PrefixLength24 --- ipv4PrefixLength24Range2
ipv6set --- ipv6PrefixLength64
ipv6PrefixLength64 --- ipv6PrefixLength64Range1
ipv6PrefixLength64 --- ipv6PrefixLength64Range2