golang快速IP到CIDR查找插件库cidranger的使用
golang快速IP到CIDR查找插件库cidranger的使用
cidranger是一个使用trie数据结构实现的快速IP到CIDR块查找的Golang库,灵感来自Linux IPv4路由查找。典型使用场景包括检测IP地址是否来自发布的云提供商CIDR块(例如52.95.110.1包含在AWS Route53发布的CIDR 52.95.110.0/24中)、IP路由规则等。
可视化示例
这是一个存储CIDR块128.0.0.0/2
、192.0.0.0/2
和200.0.0.0/5
的trie可视化,路径上的0/1数字表示IP地址在特定位位置上的位值:
这是相同CIDR块使用路径压缩后的trie可视化,提高了查找速度和内存效率:
快速开始
导入库
import (
"net"
"github.com/yl2chen/cidranger"
)
创建新的ranger
ranger := NewPCTrieRanger() // 使用路径压缩前缀trie实现
插入CIDR块
_, network1, _ := net.ParseCIDR("192.168.1.0/24")
_, network2, _ := net.ParseCIDR("128.168.1.0/24")
ranger.Insert(NewBasicRangerEntry(*network1))
ranger.Insert(NewBasicRangerEntry(*network2))
自定义RangerEntry
要附加任何额外值到条目,只需创建一个存储所需值的自定义结构体并实现RangerEntry接口:
type RangerEntry interface {
Network() net.IPNet
}
前缀trie可视化
构造的前缀trie可以可视化为:
0.0.0.0/0 (target_pos:31:has_entry:false)
| 1--> 128.0.0.0/1 (target_pos:30:has_entry:false)
| | 0--> 128.168.1.0/24 (target_pos:7:has_entry:true)
| | 1--> 192.168.1.0/24 (target_pos:7:has_entry:true)
测试IP是否包含在ranger中
contains, err = ranger.Contains(net.ParseIP("128.168.1.0")) // 返回true, nil
contains, err = ranger.Contains(net.ParseIP("192.168.2.0")) // 返回false, nil
获取IP包含的所有网络
containingNetworks, err = ranger.ContainingNetworks(net.ParseIP("128.168.1.0"))
获取ranger中的所有网络
entries, err := ranger.CoveredNetworks(*AllIPv4) // 获取IPv4网络
entries, err := ranger.CoveredNetworks(*AllIPv6) // 获取IPv6网络
完整示例代码
package main
import (
"fmt"
"net"
"github.com/yl2chen/cidranger"
)
func main() {
// 创建新的ranger
ranger := cidranger.NewPCTrieRanger()
// 插入CIDR块
_, network1, _ := net.ParseCIDR("192.168.1.0/24")
_, network2, _ := net.ParseCIDR("128.168.1.0/24")
ranger.Insert(cidranger.NewBasicRangerEntry(*network1))
ranger.Insert(cidranger.NewBasicRangerEntry(*network2))
// 测试IP是否在CIDR块中
ip := net.ParseIP("192.168.1.1")
contains, err := ranger.Contains(ip)
if err != nil {
fmt.Printf("Error checking IP: %v\n", err)
return
}
fmt.Printf("IP %s is in ranger: %t\n", ip, contains)
// 获取包含IP的所有网络
networks, err := ranger.ContainingNetworks(ip)
if err != nil {
fmt.Printf("Error getting containing networks: %v\n", err)
return
}
for _, network := range networks {
fmt.Printf("IP %s is in network: %s\n", ip, network.Network())
}
// 获取所有IPv4网络
allIPv4 := net.IPNet{IP: net.IPv4zero, Mask: net.CIDRMask(0, 32)}
entries, err := ranger.CoveredNetworks(allIPv4)
if err != nil {
fmt.Printf("Error getting all networks: %v\n", err)
return
}
fmt.Println("All IPv4 networks in ranger:")
for _, entry := range entries {
fmt.Println(entry.Network())
}
}
性能基准
比较使用PC trie与暴力实现在IPv4/IPv6上的命中/未命中情况,Ranger使用发布的AWS IP范围初始化(889个IPv4 CIDR块和360个IPv6):
// IPv4查找命中场景
BenchmarkPCTrieHitIPv4UsingAWSRanges-4 5000000 353 ns/op
BenchmarkBruteRangerHitIPv4UsingAWSRanges-4 100000 13719 ns/op
// IPv6查找命中场景,由于AWS数据集中IPv6 CIDR块较少,构造的trie路径分割和深度更小,因此比IPv4更快
BenchmarkPCTrieHitIPv6UsingAWSRanges-4 10000000 143 ns/op
BenchmarkBruteRangerHitIPv6UsingAWSRanges-4 300000 5178 ns/op
// IPv4查找未命中场景
BenchmarkPCTrieMissIPv4UsingAWSRanges-4 20000000 96.5 ns/op
BenchmarkBruteRangerMissIPv4UsingAWSRanges-4 50000 24781 ns/op
// IPv6查找未命中场景
BenchmarkPCTrieHMissIPv6UsingAWSRanges-4 10000000 115 ns/op
BenchmarkBruteRangerMissIPv6UsingAWSRanges-4 100000 10824 ns/op
IPv6 trie示例
::/0 (target_pos:127:has_entry:false)
| 0--> 2400::/14 (target_pos:113:has_entry:false)
| | 0--> 2400:6400::/22 (target_pos:105:has_entry:false)
| | | 0--> 2400:6500::/32 (target_pos:95:has_entry:false)
| | | | 0--> 2400:6500::/39 (target_pos:88:has_entry:false)
| | | | | 0--> 2400:6500:0:7000::/53 (target_pos:74:has_entry:false)
| | | | | | 0--> 2400:6500:0:7000::/54 (target_pos:73:has_entry:false)
| | | | | | | 0--> 2400:6500:0:7000::/55 (target_pos:72:has_entry:false)
| | | | | | | | 0--> 2400:6500:0:7000::/56 (target_pos:71:has_entry:true)
| | | | | | | | 1--> 2400:6500:0:7100::/56 (target_pos:71:has_entry:true)
| | | | | | | 1--> 2400:6500:0:7200::/56 (target_pos:71:has_entry:true)
| | | | | | 1--> 2400:6500:0:7400::/55 (target_pos:72:has_entry:false)
| | | | | | | 0--> 2400:6500:0:7400::/56 (target_pos:71:has_entry:true)
| | | | | | | 1--> 2400:6500:0:7500::/56 (target_pos:71:has_entry:true)
| | | | | 1--> 2400:6500:100:7000::/54 (target_pos:73:has_entry:false)
| | | | | | 0--> 2400:6500:100:7100::/56 (target_pos:71:has_entry:true)
| | | | | | 1--> 2400:6500:100:7200::/56 (target_pos:71:has_entry:true)
| | | | 1--> 2400:6500:ff00::/64 (target_pos:63:has_entry:true)
| | | 1--> 2400:6700:ff00::/64 (target_pos:63:has_entry:true)
| | 1--> 2403:b300:ff00::/64 (target_pos:63:has_entry:true)
更多关于golang快速IP到CIDR查找插件库cidranger的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang快速IP到CIDR查找插件库cidranger的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang快速IP到CIDR查找插件库cidranger使用指南
cidranger
是一个高效的Golang库,用于快速进行IP地址到CIDR块的查找操作。它特别适合需要处理大量CIDR范围并进行快速IP匹配的场景,如防火墙规则检查、地理位置查找等。
安装
go get github.com/yl2chen/cidranger
基本使用
1. 创建Ranger实例
package main
import (
"fmt"
"net"
"github.com/yl2chen/cidranger"
)
func main() {
// 创建一个新的PrefixTrie ranger (支持IPv4和IPv6)
ranger := cidranger.NewPCTrieRanger()
// 或者只支持IPv4
// ranger := cidranger.NewPCTrieRanger(cidranger.IPv4)
// 或者只支持IPv6
// ranger := cidranger.NewPCTrieRanger(cidranger.IPv6)
}
2. 插入CIDR网络
_, network1, _ := net.ParseCIDR("192.168.1.0/24")
_, network2, _ := net.ParseCIDR("10.0.0.0/8")
_, network3, _ := net.ParseCIDR("2001:db8::/32")
// 插入CIDR网络,可以附加任意数据
ranger.Insert(cidranger.NewBasicRangerEntry(*network1))
ranger.Insert(cidranger.NewBasicRangerEntry(*network2))
ranger.Insert(cidranger.NewBasicRangerEntry(*network3))
3. 查找IP是否在CIDR范围内
ip := net.ParseIP("192.168.1.10")
// 检查IP是否在任何CIDR范围内
contains, err := ranger.Contains(ip)
if err != nil {
panic(err)
}
fmt.Printf("Contains IP: %v\n", contains) // true
// 获取包含该IP的所有CIDR条目
entries, err := ranger.ContainingNetworks(ip)
if err != nil {
panic(err)
}
for _, entry := range entries {
fmt.Printf("IP is contained in network: %s\n", entry.Network())
}
4. 获取覆盖某个IP的所有CIDR网络
ip := net.ParseIP("192.168.1.15")
networks, err := ranger.ContainingNetworks(ip)
if err != nil {
panic(err)
}
for _, network := range networks {
fmt.Printf("IP is in network: %s\n", network.Network())
}
高级功能
1. 自定义条目类型
可以创建自定义类型来存储额外的CIDR信息:
type customRangerEntry struct {
net.IPNet
Data string
}
func (e *customRangerEntry) Network() net.IPNet {
return e.IPNet
}
// 使用自定义条目
_, network, _ := net.ParseCIDR("172.16.0.0/16")
customEntry := &customRangerEntry{
IPNet: *network,
Data: "This is a private network",
}
ranger.Insert(customEntry)
// 查找时获取自定义数据
ip := net.ParseIP("172.16.1.1")
entries, _ := ranger.ContainingNetworks(ip)
for _, entry := range entries {
if custom, ok := entry.(*customRangerEntry); ok {
fmt.Printf("Network: %s, Data: %s\n", custom.Network(), custom.Data)
}
}
2. 删除CIDR网络
_, network, _ := net.ParseCIDR("192.168.1.0/24")
entry := cidranger.NewBasicRangerEntry(*network)
ranger.Insert(entry)
// 删除网络
deleted, err := ranger.Remove(*network)
if err != nil {
panic(err)
}
fmt.Printf("Deleted: %v\n", deleted) // true
3. 获取所有CIDR网络
entries, err := ranger.CoveredNetworks(*net.IPv4zero, 0)
if err != nil {
panic(err)
}
for _, entry := range entries {
fmt.Println(entry.Network())
}
性能考虑
cidranger
使用前缀压缩的Trie数据结构(PCTrie),具有以下特点:
- 查找时间复杂度为O(k),其中k是IP地址的位数(IPv4为32,IPv6为128)
- 内存效率高,共享相同前缀的CIDR块会共享存储
- 支持快速插入和删除操作
对于大多数应用场景,cidranger
提供了足够高的性能,可以处理数十万甚至数百万个CIDR块的快速查找。
完整示例
package main
import (
"fmt"
"log"
"net"
"github.com/yl2chen/cidranger"
)
func main() {
// 创建ranger
ranger := cidranger.NewPCTrieRanger()
// 插入一些CIDR网络
networks := []string{
"10.0.0.0/8",
"192.168.1.0/24",
"172.16.0.0/12",
"2001:db8::/32",
}
for _, n := range networks {
_, network, err := net.ParseCIDR(n)
if err != nil {
log.Fatal(err)
}
ranger.Insert(cidranger.NewBasicRangerEntry(*network))
}
// 测试IP
ips := []string{
"10.1.2.3",
"192.168.1.15",
"172.16.100.200",
"2001:db8::1",
"8.8.8.8",
}
for _, ipStr := range ips {
ip := net.ParseIP(ipStr)
contains, err := ranger.Contains(ip)
if err != nil {
log.Fatal(err)
}
fmt.Printf("IP %s is in any network: %v\n", ipStr, contains)
if contains {
entries, err := ranger.ContainingNetworks(ip)
if err != nil {
log.Fatal(err)
}
for _, entry := range entries {
fmt.Printf(" - Contained in: %s\n", entry.Network())
}
}
}
}
cidranger
是一个简单而强大的库,可以轻松集成到需要IP-CIDR查找功能的Golang应用中。