WIP: Save agent roles integration work before CHORUS rebrand
- Agent roles and coordination features - Chat API integration testing - New configuration and workspace management 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
1
vendor/github.com/libp2p/go-cidranger/.gitignore
generated
vendored
Normal file
1
vendor/github.com/libp2p/go-cidranger/.gitignore
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
vendor
|
||||
31
vendor/github.com/libp2p/go-cidranger/.travis.yml
generated
vendored
Normal file
31
vendor/github.com/libp2p/go-cidranger/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
os:
|
||||
- linux
|
||||
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.14.x
|
||||
- 1.15.x
|
||||
|
||||
env:
|
||||
global:
|
||||
- GOTFLAGS="-race"
|
||||
matrix:
|
||||
- BUILD_DEPTYPE=gomod
|
||||
|
||||
|
||||
# disable travis install
|
||||
install:
|
||||
- true
|
||||
|
||||
script:
|
||||
- bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh)
|
||||
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $GOPATH/pkg/mod
|
||||
- $HOME/.cache/go-build
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
33
vendor/github.com/libp2p/go-cidranger/Gopkg.lock
generated
vendored
Normal file
33
vendor/github.com/libp2p/go-cidranger/Gopkg.lock
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a2c1d0e43bd3baaa071d1b9ed72c27d78169b2b269f71c105ac4ba34b1be4a39"
|
||||
name = "github.com/davecgh/go-spew"
|
||||
packages = ["spew"]
|
||||
pruneopts = "UT"
|
||||
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe"
|
||||
name = "github.com/pmezard/go-difflib"
|
||||
packages = ["difflib"]
|
||||
pruneopts = "UT"
|
||||
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:f85e109eda8f6080877185d1c39e98dd8795e1780c08beca28304b87fd855a1c"
|
||||
name = "github.com/stretchr/testify"
|
||||
packages = ["assert"]
|
||||
pruneopts = "UT"
|
||||
revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71"
|
||||
version = "v1.2.1"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
input-imports = ["github.com/stretchr/testify/assert"]
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
34
vendor/github.com/libp2p/go-cidranger/Gopkg.toml
generated
vendored
Normal file
34
vendor/github.com/libp2p/go-cidranger/Gopkg.toml
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
#
|
||||
# [prune]
|
||||
# non-go = false
|
||||
# go-tests = true
|
||||
# unused-packages = true
|
||||
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/stretchr/testify"
|
||||
version = "1.2.1"
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
||||
21
vendor/github.com/libp2p/go-cidranger/LICENSE
generated
vendored
Normal file
21
vendor/github.com/libp2p/go-cidranger/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Yulin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
110
vendor/github.com/libp2p/go-cidranger/README.md
generated
vendored
Normal file
110
vendor/github.com/libp2p/go-cidranger/README.md
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
# cidranger
|
||||
|
||||
Fast IP to CIDR block(s) lookup using trie in Golang, inspired by [IPv4 route lookup linux](https://vincent.bernat.im/en/blog/2017-ipv4-route-lookup-linux). Possible use cases include detecting if a IP address is from published cloud provider CIDR blocks (e.g. 52.95.110.1 is contained in published AWS Route53 CIDR 52.95.110.0/24), IP routing rules, etc.
|
||||
|
||||
Forked from https://github.com/yl2chen/cidranger due to upstream inactivity.
|
||||
|
||||
[](https://godoc.org/github.com/libp2p/go-cidranger)
|
||||
[](https://travis-ci.org/libp2p/go-cidranger)
|
||||
[](https://coveralls.io/github/libp2p/go-cidranger?branch=master)
|
||||
[](https://goreportcard.com/report/github.com/libp2p/go-cidranger)
|
||||
|
||||
This is visualization of a trie storing CIDR blocks `128.0.0.0/2` `192.0.0.0/2` `200.0.0.0/5` without path compression, the 0/1 number on the path indicates the bit value of the IP address at specified bit position, hence the path from root node to a child node represents a CIDR block that contains all IP ranges of its children, and children's children.
|
||||
<p align="left"><img src="http://i.imgur.com/vSKTEBb.png" width="600" /></p>
|
||||
|
||||
Visualization of trie storing same CIDR blocks with path compression, improving both lookup speed and memory footprint.
|
||||
<p align="left"><img src="http://i.imgur.com/JtaDlD4.png" width="600" /></p>
|
||||
|
||||
## Getting Started
|
||||
Configure imports.
|
||||
```go
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/libp2p/go-cidranger"
|
||||
)
|
||||
```
|
||||
Create a new ranger implemented using Path-Compressed prefix trie.
|
||||
```go
|
||||
ranger := NewPCTrieRanger()
|
||||
```
|
||||
Inserts CIDR blocks.
|
||||
```go
|
||||
_, network1, _ := net.ParseCIDR("192.168.1.0/24")
|
||||
_, network2, _ := net.ParseCIDR("128.168.1.0/24")
|
||||
ranger.Insert(NewBasicRangerEntry(*network1))
|
||||
ranger.Insert(NewBasicRangerEntry(*network2))
|
||||
```
|
||||
To attach any additional value(s) to the entry, simply create custom struct
|
||||
storing the desired value(s) that implements the RangerEntry interface:
|
||||
```go
|
||||
type RangerEntry interface {
|
||||
Network() net.IPNet
|
||||
}
|
||||
```
|
||||
The prefix trie can be visualized as:
|
||||
```
|
||||
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)
|
||||
```
|
||||
To test if given IP is contained in constructed ranger,
|
||||
```go
|
||||
contains, err = ranger.Contains(net.ParseIP("128.168.1.0")) // returns true, nil
|
||||
contains, err = ranger.Contains(net.ParseIP("192.168.2.0")) // returns false, nil
|
||||
```
|
||||
To get all the networks given is contained in,
|
||||
```go
|
||||
containingNetworks, err = ranger.ContainingNetworks(net.ParseIP("128.168.1.0"))
|
||||
```
|
||||
To get all networks in ranger,
|
||||
```go
|
||||
entries, err := ranger.CoveredNetworks(*AllIPv4) // for IPv4
|
||||
entries, err := ranger.CoveredNetworks(*AllIPv6) // for IPv6
|
||||
```
|
||||
|
||||
## Benchmark
|
||||
Compare hit/miss case for IPv4/IPv6 using PC trie vs brute force implementation, Ranger is initialized with published AWS ip ranges (889 IPv4 CIDR blocks and 360 IPv6)
|
||||
```go
|
||||
// Ipv4 lookup hit scenario
|
||||
BenchmarkPCTrieHitIPv4UsingAWSRanges-4 5000000 353 ns/op
|
||||
BenchmarkBruteRangerHitIPv4UsingAWSRanges-4 100000 13719 ns/op
|
||||
|
||||
// Ipv6 lookup hit scenario, counter-intuitively faster then IPv4 due to less IPv6 CIDR
|
||||
// blocks in the AWS dataset, hence the constructed trie has less path splits and depth.
|
||||
BenchmarkPCTrieHitIPv6UsingAWSRanges-4 10000000 143 ns/op
|
||||
BenchmarkBruteRangerHitIPv6UsingAWSRanges-4 300000 5178 ns/op
|
||||
|
||||
// Ipv4 lookup miss scenario
|
||||
BenchmarkPCTrieMissIPv4UsingAWSRanges-4 20000000 96.5 ns/op
|
||||
BenchmarkBruteRangerMissIPv4UsingAWSRanges-4 50000 24781 ns/op
|
||||
|
||||
// Ipv6 lookup miss scenario
|
||||
BenchmarkPCTrieHMissIPv6UsingAWSRanges-4 10000000 115 ns/op
|
||||
BenchmarkBruteRangerMissIPv6UsingAWSRanges-4 100000 10824 ns/op
|
||||
```
|
||||
|
||||
## Example of 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)
|
||||
```
|
||||
124
vendor/github.com/libp2p/go-cidranger/brute.go
generated
vendored
Normal file
124
vendor/github.com/libp2p/go-cidranger/brute.go
generated
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
package cidranger
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
rnet "github.com/libp2p/go-cidranger/net"
|
||||
)
|
||||
|
||||
// bruteRanger is a brute force implementation of Ranger. Insertion and
|
||||
// deletion of networks is performed on an internal storage in the form of
|
||||
// map[string]net.IPNet (constant time operations). However, inclusion tests are
|
||||
// always performed linearly at no guaranteed traversal order of recorded networks,
|
||||
// so one can assume a worst case performance of O(N). The performance can be
|
||||
// boosted many ways, e.g. changing usage of net.IPNet.Contains() to using masked
|
||||
// bits equality checking, but the main purpose of this implementation is for
|
||||
// testing because the correctness of this implementation can be easily guaranteed,
|
||||
// and used as the ground truth when running a wider range of 'random' tests on
|
||||
// other more sophisticated implementations.
|
||||
type bruteRanger struct {
|
||||
ipV4Entries map[string]RangerEntry
|
||||
ipV6Entries map[string]RangerEntry
|
||||
}
|
||||
|
||||
// newBruteRanger returns a new Ranger.
|
||||
func newBruteRanger() Ranger {
|
||||
return &bruteRanger{
|
||||
ipV4Entries: make(map[string]RangerEntry),
|
||||
ipV6Entries: make(map[string]RangerEntry),
|
||||
}
|
||||
}
|
||||
|
||||
// Insert inserts a RangerEntry into ranger.
|
||||
func (b *bruteRanger) Insert(entry RangerEntry) error {
|
||||
network := entry.Network()
|
||||
key := network.String()
|
||||
if _, found := b.ipV4Entries[key]; !found {
|
||||
entries, err := b.getEntriesByVersion(entry.Network().IP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
entries[key] = entry
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove removes a RangerEntry identified by given network from ranger.
|
||||
func (b *bruteRanger) Remove(network net.IPNet) (RangerEntry, error) {
|
||||
networks, err := b.getEntriesByVersion(network.IP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key := network.String()
|
||||
if networkToDelete, found := networks[key]; found {
|
||||
delete(networks, key)
|
||||
return networkToDelete, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Contains returns bool indicating whether given ip is contained by any
|
||||
// network in ranger.
|
||||
func (b *bruteRanger) Contains(ip net.IP) (bool, error) {
|
||||
entries, err := b.getEntriesByVersion(ip)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, entry := range entries {
|
||||
network := entry.Network()
|
||||
if network.Contains(ip) {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// ContainingNetworks returns all RangerEntry(s) that given ip contained in.
|
||||
func (b *bruteRanger) ContainingNetworks(ip net.IP) ([]RangerEntry, error) {
|
||||
entries, err := b.getEntriesByVersion(ip)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results := []RangerEntry{}
|
||||
for _, entry := range entries {
|
||||
network := entry.Network()
|
||||
if network.Contains(ip) {
|
||||
results = append(results, entry)
|
||||
}
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// CoveredNetworks returns the list of RangerEntry(s) the given ipnet
|
||||
// covers. That is, the networks that are completely subsumed by the
|
||||
// specified network.
|
||||
func (b *bruteRanger) CoveredNetworks(network net.IPNet) ([]RangerEntry, error) {
|
||||
entries, err := b.getEntriesByVersion(network.IP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var results []RangerEntry
|
||||
testNetwork := rnet.NewNetwork(network)
|
||||
for _, entry := range entries {
|
||||
entryNetwork := rnet.NewNetwork(entry.Network())
|
||||
if testNetwork.Covers(entryNetwork) {
|
||||
results = append(results, entry)
|
||||
}
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// Len returns number of networks in ranger.
|
||||
func (b *bruteRanger) Len() int {
|
||||
return len(b.ipV4Entries) + len(b.ipV6Entries)
|
||||
}
|
||||
|
||||
func (b *bruteRanger) getEntriesByVersion(ip net.IP) (map[string]RangerEntry, error) {
|
||||
if ip.To4() != nil {
|
||||
return b.ipV4Entries, nil
|
||||
}
|
||||
if ip.To16() != nil {
|
||||
return b.ipV6Entries, nil
|
||||
}
|
||||
return nil, ErrInvalidNetworkInput
|
||||
}
|
||||
99
vendor/github.com/libp2p/go-cidranger/cidranger.go
generated
vendored
Normal file
99
vendor/github.com/libp2p/go-cidranger/cidranger.go
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
Package cidranger provides utility to store CIDR blocks and perform ip
|
||||
inclusion tests against it.
|
||||
|
||||
To create a new instance of the path-compressed trie:
|
||||
|
||||
ranger := NewPCTrieRanger()
|
||||
|
||||
To insert or remove an entry (any object that satisfies the RangerEntry
|
||||
interface):
|
||||
|
||||
_, network, _ := net.ParseCIDR("192.168.0.0/24")
|
||||
ranger.Insert(NewBasicRangerEntry(*network))
|
||||
ranger.Remove(network)
|
||||
|
||||
If you desire for any value to be attached to the entry, simply
|
||||
create custom struct that satisfies the RangerEntry interface:
|
||||
|
||||
type RangerEntry interface {
|
||||
Network() net.IPNet
|
||||
}
|
||||
|
||||
To test whether an IP is contained in the constructed networks ranger:
|
||||
|
||||
// returns bool, error
|
||||
containsBool, err := ranger.Contains(net.ParseIP("192.168.0.1"))
|
||||
|
||||
To get a list of CIDR blocks in constructed ranger that contains IP:
|
||||
|
||||
// returns []RangerEntry, error
|
||||
entries, err := ranger.ContainingNetworks(net.ParseIP("192.168.0.1"))
|
||||
|
||||
To get a list of all IPv4/IPv6 rangers respectively:
|
||||
|
||||
// returns []RangerEntry, error
|
||||
entries, err := ranger.CoveredNetworks(*AllIPv4)
|
||||
entries, err := ranger.CoveredNetworks(*AllIPv6)
|
||||
|
||||
*/
|
||||
package cidranger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
// ErrInvalidNetworkInput is returned upon invalid network input.
|
||||
var ErrInvalidNetworkInput = fmt.Errorf("Invalid network input")
|
||||
|
||||
// ErrInvalidNetworkNumberInput is returned upon invalid network input.
|
||||
var ErrInvalidNetworkNumberInput = fmt.Errorf("Invalid network number input")
|
||||
|
||||
// AllIPv4 is a IPv4 CIDR that contains all networks
|
||||
var AllIPv4 = parseCIDRUnsafe("0.0.0.0/0")
|
||||
|
||||
// AllIPv6 is a IPv6 CIDR that contains all networks
|
||||
var AllIPv6 = parseCIDRUnsafe("0::0/0")
|
||||
|
||||
func parseCIDRUnsafe(s string) *net.IPNet {
|
||||
_, cidr, _ := net.ParseCIDR(s)
|
||||
return cidr
|
||||
}
|
||||
|
||||
// RangerEntry is an interface for insertable entry into a Ranger.
|
||||
type RangerEntry interface {
|
||||
Network() net.IPNet
|
||||
}
|
||||
|
||||
type basicRangerEntry struct {
|
||||
ipNet net.IPNet
|
||||
}
|
||||
|
||||
func (b *basicRangerEntry) Network() net.IPNet {
|
||||
return b.ipNet
|
||||
}
|
||||
|
||||
// NewBasicRangerEntry returns a basic RangerEntry that only stores the network
|
||||
// itself.
|
||||
func NewBasicRangerEntry(ipNet net.IPNet) RangerEntry {
|
||||
return &basicRangerEntry{
|
||||
ipNet: ipNet,
|
||||
}
|
||||
}
|
||||
|
||||
// Ranger is an interface for cidr block containment lookups.
|
||||
type Ranger interface {
|
||||
Insert(entry RangerEntry) error
|
||||
Remove(network net.IPNet) (RangerEntry, error)
|
||||
Contains(ip net.IP) (bool, error)
|
||||
ContainingNetworks(ip net.IP) ([]RangerEntry, error)
|
||||
CoveredNetworks(network net.IPNet) ([]RangerEntry, error)
|
||||
Len() int
|
||||
}
|
||||
|
||||
// NewPCTrieRanger returns a versionedRanger that supports both IPv4 and IPv6
|
||||
// using the path compressed trie implemention.
|
||||
func NewPCTrieRanger() Ranger {
|
||||
return newVersionedRanger(newRanger)
|
||||
}
|
||||
300
vendor/github.com/libp2p/go-cidranger/net/ip.go
generated
vendored
Normal file
300
vendor/github.com/libp2p/go-cidranger/net/ip.go
generated
vendored
Normal file
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
Package net provides utility functions for working with IPs (net.IP).
|
||||
*/
|
||||
package net
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math"
|
||||
"net"
|
||||
)
|
||||
|
||||
// IPVersion is version of IP address.
|
||||
type IPVersion string
|
||||
|
||||
// Helper constants.
|
||||
const (
|
||||
IPv4Uint32Count = 1
|
||||
IPv6Uint32Count = 4
|
||||
|
||||
BitsPerUint32 = 32
|
||||
BytePerUint32 = 4
|
||||
|
||||
IPv4 IPVersion = "IPv4"
|
||||
IPv6 IPVersion = "IPv6"
|
||||
)
|
||||
|
||||
// ErrInvalidBitPosition is returned when bits requested is not valid.
|
||||
var ErrInvalidBitPosition = fmt.Errorf("bit position not valid")
|
||||
|
||||
// ErrVersionMismatch is returned upon mismatch in network input versions.
|
||||
var ErrVersionMismatch = fmt.Errorf("Network input version mismatch")
|
||||
|
||||
// ErrNoGreatestCommonBit is an error returned when no greatest common bit
|
||||
// exists for the cidr ranges.
|
||||
var ErrNoGreatestCommonBit = fmt.Errorf("No greatest common bit")
|
||||
|
||||
// NetworkNumber represents an IP address using uint32 as internal storage.
|
||||
// IPv4 usings 1 uint32, while IPv6 uses 4 uint32.
|
||||
type NetworkNumber []uint32
|
||||
|
||||
// NewNetworkNumber returns a equivalent NetworkNumber to given IP address,
|
||||
// return nil if ip is neither IPv4 nor IPv6.
|
||||
func NewNetworkNumber(ip net.IP) NetworkNumber {
|
||||
if ip == nil {
|
||||
return nil
|
||||
}
|
||||
coercedIP := ip.To4()
|
||||
parts := 1
|
||||
if coercedIP == nil {
|
||||
coercedIP = ip.To16()
|
||||
parts = 4
|
||||
}
|
||||
if coercedIP == nil {
|
||||
return nil
|
||||
}
|
||||
nn := make(NetworkNumber, parts)
|
||||
for i := 0; i < parts; i++ {
|
||||
idx := i * net.IPv4len
|
||||
nn[i] = binary.BigEndian.Uint32(coercedIP[idx : idx+net.IPv4len])
|
||||
}
|
||||
return nn
|
||||
}
|
||||
|
||||
// ToV4 returns ip address if ip is IPv4, returns nil otherwise.
|
||||
func (n NetworkNumber) ToV4() NetworkNumber {
|
||||
if len(n) != IPv4Uint32Count {
|
||||
return nil
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// ToV6 returns ip address if ip is IPv6, returns nil otherwise.
|
||||
func (n NetworkNumber) ToV6() NetworkNumber {
|
||||
if len(n) != IPv6Uint32Count {
|
||||
return nil
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// ToIP returns equivalent net.IP.
|
||||
func (n NetworkNumber) ToIP() net.IP {
|
||||
ip := make(net.IP, len(n)*BytePerUint32)
|
||||
for i := 0; i < len(n); i++ {
|
||||
idx := i * net.IPv4len
|
||||
binary.BigEndian.PutUint32(ip[idx:idx+net.IPv4len], n[i])
|
||||
}
|
||||
if len(ip) == net.IPv4len {
|
||||
ip = net.IPv4(ip[0], ip[1], ip[2], ip[3])
|
||||
}
|
||||
return ip
|
||||
}
|
||||
|
||||
// Equal is the equality test for 2 network numbers.
|
||||
func (n NetworkNumber) Equal(n1 NetworkNumber) bool {
|
||||
if len(n) != len(n1) {
|
||||
return false
|
||||
}
|
||||
if n[0] != n1[0] {
|
||||
return false
|
||||
}
|
||||
if len(n) == IPv6Uint32Count {
|
||||
return n[1] == n1[1] && n[2] == n1[2] && n[3] == n1[3]
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Next returns the next logical network number.
|
||||
func (n NetworkNumber) Next() NetworkNumber {
|
||||
newIP := make(NetworkNumber, len(n))
|
||||
copy(newIP, n)
|
||||
for i := len(newIP) - 1; i >= 0; i-- {
|
||||
newIP[i]++
|
||||
if newIP[i] > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return newIP
|
||||
}
|
||||
|
||||
// Previous returns the previous logical network number.
|
||||
func (n NetworkNumber) Previous() NetworkNumber {
|
||||
newIP := make(NetworkNumber, len(n))
|
||||
copy(newIP, n)
|
||||
for i := len(newIP) - 1; i >= 0; i-- {
|
||||
newIP[i]--
|
||||
if newIP[i] < math.MaxUint32 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return newIP
|
||||
}
|
||||
|
||||
// Bit returns uint32 representing the bit value at given position, e.g.,
|
||||
// "128.0.0.0" has bit value of 1 at position 31, and 0 for positions 30 to 0.
|
||||
func (n NetworkNumber) Bit(position uint) (uint32, error) {
|
||||
if int(position) > len(n)*BitsPerUint32-1 {
|
||||
return 0, ErrInvalidBitPosition
|
||||
}
|
||||
idx := len(n) - 1 - int(position/BitsPerUint32)
|
||||
// Mod 31 to get array index.
|
||||
rShift := position & (BitsPerUint32 - 1)
|
||||
return (n[idx] >> rShift) & 1, nil
|
||||
}
|
||||
|
||||
// LeastCommonBitPosition returns the smallest position of the preceding common
|
||||
// bits of the 2 network numbers, and returns an error ErrNoGreatestCommonBit
|
||||
// if the two network number diverges from the first bit.
|
||||
// e.g., if the network number diverges after the 1st bit, it returns 131 for
|
||||
// IPv6 and 31 for IPv4 .
|
||||
func (n NetworkNumber) LeastCommonBitPosition(n1 NetworkNumber) (uint, error) {
|
||||
if len(n) != len(n1) {
|
||||
return 0, ErrVersionMismatch
|
||||
}
|
||||
for i := 0; i < len(n); i++ {
|
||||
mask := uint32(1) << 31
|
||||
pos := uint(31)
|
||||
for ; mask > 0; mask >>= 1 {
|
||||
if n[i]&mask != n1[i]&mask {
|
||||
if i == 0 && pos == 31 {
|
||||
return 0, ErrNoGreatestCommonBit
|
||||
}
|
||||
return (pos + 1) + uint(BitsPerUint32)*uint(len(n)-i-1), nil
|
||||
}
|
||||
pos--
|
||||
}
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// Network represents a block of network numbers, also known as CIDR.
|
||||
type Network struct {
|
||||
Number NetworkNumber
|
||||
Mask NetworkNumberMask
|
||||
}
|
||||
|
||||
// NewNetwork returns Network built using given net.IPNet.
|
||||
func NewNetwork(ipNet net.IPNet) Network {
|
||||
ones, _ := ipNet.Mask.Size()
|
||||
return Network{
|
||||
Number: NewNetworkNumber(ipNet.IP),
|
||||
Mask: NetworkNumberMask(ones),
|
||||
}
|
||||
}
|
||||
|
||||
// Masked returns a new network conforming to new mask.
|
||||
func (n Network) Masked(ones int) Network {
|
||||
mask := NetworkNumberMask(ones)
|
||||
return Network{
|
||||
Number: mask.Mask(n.Number),
|
||||
Mask: mask,
|
||||
}
|
||||
}
|
||||
|
||||
func sub(a, b uint8) uint8 {
|
||||
res := a - b
|
||||
if res > a {
|
||||
res = 0
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func mask(m NetworkNumberMask) (mask1, mask2, mask3, mask4 uint32) {
|
||||
// We're relying on overflow here.
|
||||
const ones uint32 = 0xFFFFFFFF
|
||||
mask1 = ones << sub(1*32, uint8(m))
|
||||
mask2 = ones << sub(2*32, uint8(m))
|
||||
mask3 = ones << sub(3*32, uint8(m))
|
||||
mask4 = ones << sub(4*32, uint8(m))
|
||||
return
|
||||
}
|
||||
|
||||
// Contains returns true if NetworkNumber is in range of Network, false
|
||||
// otherwise.
|
||||
func (n Network) Contains(nn NetworkNumber) bool {
|
||||
if len(n.Number) != len(nn) {
|
||||
return false
|
||||
}
|
||||
const ones uint32 = 0xFFFFFFFF
|
||||
|
||||
mask1, mask2, mask3, mask4 := mask(n.Mask)
|
||||
switch len(n.Number) {
|
||||
case IPv4Uint32Count:
|
||||
return nn[0]&mask1 == n.Number[0]
|
||||
case IPv6Uint32Count:
|
||||
return nn[0]&mask1 == n.Number[0] &&
|
||||
nn[1]&mask2 == n.Number[1] &&
|
||||
nn[2]&mask3 == n.Number[2] &&
|
||||
nn[3]&mask4 == n.Number[3]
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Contains returns true if Network covers o, false otherwise
|
||||
func (n Network) Covers(o Network) bool {
|
||||
return n.Contains(o.Number) && n.Mask <= o.Mask
|
||||
}
|
||||
|
||||
// LeastCommonBitPosition returns the smallest position of the preceding common
|
||||
// bits of the 2 networks, and returns an error ErrNoGreatestCommonBit
|
||||
// if the two network number diverges from the first bit.
|
||||
func (n Network) LeastCommonBitPosition(n1 Network) (uint, error) {
|
||||
maskSize := n.Mask
|
||||
if n1.Mask < n.Mask {
|
||||
maskSize = n1.Mask
|
||||
}
|
||||
maskPosition := len(n1.Number)*BitsPerUint32 - int(maskSize)
|
||||
lcb, err := n.Number.LeastCommonBitPosition(n1.Number)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint(math.Max(float64(maskPosition), float64(lcb))), nil
|
||||
}
|
||||
|
||||
// Equal is the equality test for 2 networks.
|
||||
func (n Network) Equal(n1 Network) bool {
|
||||
return n.Number.Equal(n1.Number) && n.Mask == n1.Mask
|
||||
}
|
||||
|
||||
func (n Network) String() string {
|
||||
return fmt.Sprintf("%s/%d", n.Number.ToIP(), n.Mask)
|
||||
}
|
||||
|
||||
func (n Network) IPNet() net.IPNet {
|
||||
return net.IPNet{
|
||||
IP: n.Number.ToIP(),
|
||||
Mask: net.CIDRMask(int(n.Mask), len(n.Number)*32),
|
||||
}
|
||||
}
|
||||
|
||||
// NetworkNumberMask is an IP address.
|
||||
type NetworkNumberMask int
|
||||
|
||||
// Mask returns a new masked NetworkNumber from given NetworkNumber.
|
||||
func (m NetworkNumberMask) Mask(n NetworkNumber) NetworkNumber {
|
||||
mask1, mask2, mask3, mask4 := mask(m)
|
||||
|
||||
result := make(NetworkNumber, len(n))
|
||||
switch len(n) {
|
||||
case IPv4Uint32Count:
|
||||
result[0] = n[0] & mask1
|
||||
case IPv6Uint32Count:
|
||||
result[0] = n[0] & mask1
|
||||
result[1] = n[1] & mask2
|
||||
result[2] = n[2] & mask3
|
||||
result[3] = n[3] & mask4
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// NextIP returns the next sequential ip.
|
||||
func NextIP(ip net.IP) net.IP {
|
||||
return NewNetworkNumber(ip).Next().ToIP()
|
||||
}
|
||||
|
||||
// PreviousIP returns the previous sequential ip.
|
||||
func PreviousIP(ip net.IP) net.IP {
|
||||
return NewNetworkNumber(ip).Previous().ToIP()
|
||||
}
|
||||
404
vendor/github.com/libp2p/go-cidranger/trie.go
generated
vendored
Normal file
404
vendor/github.com/libp2p/go-cidranger/trie.go
generated
vendored
Normal file
@@ -0,0 +1,404 @@
|
||||
package cidranger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
rnet "github.com/libp2p/go-cidranger/net"
|
||||
)
|
||||
|
||||
// prefixTrie is a path-compressed (PC) trie implementation of the
|
||||
// ranger interface inspired by this blog post:
|
||||
// https://vincent.bernat.im/en/blog/2017-ipv4-route-lookup-linux
|
||||
//
|
||||
// CIDR blocks are stored using a prefix tree structure where each node has its
|
||||
// parent as prefix, and the path from the root node represents current CIDR
|
||||
// block.
|
||||
//
|
||||
// For IPv4, the trie structure guarantees max depth of 32 as IPv4 addresses are
|
||||
// 32 bits long and each bit represents a prefix tree starting at that bit. This
|
||||
// property also guarantees constant lookup time in Big-O notation.
|
||||
//
|
||||
// Path compression compresses a string of node with only 1 child into a single
|
||||
// node, decrease the amount of lookups necessary during containment tests.
|
||||
//
|
||||
// Level compression dictates the amount of direct children of a node by
|
||||
// allowing it to handle multiple bits in the path. The heuristic (based on
|
||||
// children population) to decide when the compression and decompression happens
|
||||
// is outlined in the prior linked blog, and will be experimented with in more
|
||||
// depth in this project in the future.
|
||||
//
|
||||
// Note: Can not insert both IPv4 and IPv6 network addresses into the same
|
||||
// prefix trie, use versionedRanger wrapper instead.
|
||||
//
|
||||
// TODO: Implement level-compressed component of the LPC trie.
|
||||
type prefixTrie struct {
|
||||
parent *prefixTrie
|
||||
children [2]*prefixTrie
|
||||
|
||||
numBitsSkipped uint
|
||||
numBitsHandled uint
|
||||
|
||||
network rnet.Network
|
||||
entry RangerEntry
|
||||
|
||||
size int // This is only maintained in the root trie.
|
||||
}
|
||||
|
||||
var ip4ZeroCIDR, ip6ZeroCIDR net.IPNet
|
||||
|
||||
func init() {
|
||||
_, v4, _ := net.ParseCIDR("0.0.0.0/0")
|
||||
_, v6, _ := net.ParseCIDR("0::0/0")
|
||||
ip4ZeroCIDR = *v4
|
||||
ip6ZeroCIDR = *v6
|
||||
}
|
||||
|
||||
func newRanger(version rnet.IPVersion) Ranger {
|
||||
return newPrefixTree(version)
|
||||
}
|
||||
|
||||
// newPrefixTree creates a new prefixTrie.
|
||||
func newPrefixTree(version rnet.IPVersion) *prefixTrie {
|
||||
rootNet := ip4ZeroCIDR
|
||||
if version == rnet.IPv6 {
|
||||
rootNet = ip6ZeroCIDR
|
||||
}
|
||||
return &prefixTrie{
|
||||
numBitsSkipped: 0,
|
||||
numBitsHandled: 1,
|
||||
network: rnet.NewNetwork(rootNet),
|
||||
}
|
||||
}
|
||||
|
||||
func newPathprefixTrie(network rnet.Network, numBitsSkipped uint) *prefixTrie {
|
||||
version := rnet.IPv4
|
||||
if len(network.Number) == rnet.IPv6Uint32Count {
|
||||
version = rnet.IPv6
|
||||
}
|
||||
path := newPrefixTree(version)
|
||||
path.numBitsSkipped = numBitsSkipped
|
||||
path.network = network.Masked(int(numBitsSkipped))
|
||||
return path
|
||||
}
|
||||
|
||||
func newEntryTrie(network rnet.Network, entry RangerEntry) *prefixTrie {
|
||||
leaf := newPathprefixTrie(network, uint(network.Mask))
|
||||
leaf.entry = entry
|
||||
return leaf
|
||||
}
|
||||
|
||||
// Insert inserts a RangerEntry into prefix trie.
|
||||
func (p *prefixTrie) Insert(entry RangerEntry) error {
|
||||
network := entry.Network()
|
||||
sizeIncreased, err := p.insert(rnet.NewNetwork(network), entry)
|
||||
if sizeIncreased {
|
||||
p.size++
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Remove removes RangerEntry identified by given network from trie.
|
||||
func (p *prefixTrie) Remove(network net.IPNet) (RangerEntry, error) {
|
||||
entry, err := p.remove(rnet.NewNetwork(network))
|
||||
if entry != nil {
|
||||
p.size--
|
||||
}
|
||||
return entry, err
|
||||
}
|
||||
|
||||
// Contains returns boolean indicating whether given ip is contained in any
|
||||
// of the inserted networks.
|
||||
func (p *prefixTrie) Contains(ip net.IP) (bool, error) {
|
||||
nn := rnet.NewNetworkNumber(ip)
|
||||
if nn == nil {
|
||||
return false, ErrInvalidNetworkNumberInput
|
||||
}
|
||||
return p.contains(nn)
|
||||
}
|
||||
|
||||
// ContainingNetworks returns the list of RangerEntry(s) the given ip is
|
||||
// contained in in ascending prefix order.
|
||||
func (p *prefixTrie) ContainingNetworks(ip net.IP) ([]RangerEntry, error) {
|
||||
nn := rnet.NewNetworkNumber(ip)
|
||||
if nn == nil {
|
||||
return nil, ErrInvalidNetworkNumberInput
|
||||
}
|
||||
return p.containingNetworks(nn)
|
||||
}
|
||||
|
||||
// CoveredNetworks returns the list of RangerEntry(s) the given ipnet
|
||||
// covers. That is, the networks that are completely subsumed by the
|
||||
// specified network.
|
||||
func (p *prefixTrie) CoveredNetworks(network net.IPNet) ([]RangerEntry, error) {
|
||||
net := rnet.NewNetwork(network)
|
||||
return p.coveredNetworks(net)
|
||||
}
|
||||
|
||||
// Len returns number of networks in ranger.
|
||||
func (p *prefixTrie) Len() int {
|
||||
return p.size
|
||||
}
|
||||
|
||||
// String returns string representation of trie, mainly for visualization and
|
||||
// debugging.
|
||||
func (p *prefixTrie) String() string {
|
||||
children := []string{}
|
||||
padding := strings.Repeat("| ", p.level()+1)
|
||||
for bits, child := range p.children {
|
||||
if child == nil {
|
||||
continue
|
||||
}
|
||||
childStr := fmt.Sprintf("\n%s%d--> %s", padding, bits, child.String())
|
||||
children = append(children, childStr)
|
||||
}
|
||||
return fmt.Sprintf("%s (target_pos:%d:has_entry:%t)%s", p.network,
|
||||
p.targetBitPosition(), p.hasEntry(), strings.Join(children, ""))
|
||||
}
|
||||
|
||||
func (p *prefixTrie) contains(number rnet.NetworkNumber) (bool, error) {
|
||||
if !p.network.Contains(number) {
|
||||
return false, nil
|
||||
}
|
||||
if p.hasEntry() {
|
||||
return true, nil
|
||||
}
|
||||
if p.targetBitPosition() < 0 {
|
||||
return false, nil
|
||||
}
|
||||
bit, err := p.targetBitFromIP(number)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
child := p.children[bit]
|
||||
if child != nil {
|
||||
return child.contains(number)
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (p *prefixTrie) containingNetworks(number rnet.NetworkNumber) ([]RangerEntry, error) {
|
||||
results := []RangerEntry{}
|
||||
if !p.network.Contains(number) {
|
||||
return results, nil
|
||||
}
|
||||
if p.hasEntry() {
|
||||
results = []RangerEntry{p.entry}
|
||||
}
|
||||
if p.targetBitPosition() < 0 {
|
||||
return results, nil
|
||||
}
|
||||
bit, err := p.targetBitFromIP(number)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
child := p.children[bit]
|
||||
if child != nil {
|
||||
ranges, err := child.containingNetworks(number)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(ranges) > 0 {
|
||||
if len(results) > 0 {
|
||||
results = append(results, ranges...)
|
||||
} else {
|
||||
results = ranges
|
||||
}
|
||||
}
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (p *prefixTrie) coveredNetworks(network rnet.Network) ([]RangerEntry, error) {
|
||||
var results []RangerEntry
|
||||
if network.Covers(p.network) {
|
||||
for entry := range p.walkDepth() {
|
||||
results = append(results, entry)
|
||||
}
|
||||
} else if p.targetBitPosition() >= 0 {
|
||||
bit, err := p.targetBitFromIP(network.Number)
|
||||
if err != nil {
|
||||
return results, err
|
||||
}
|
||||
child := p.children[bit]
|
||||
if child != nil {
|
||||
return child.coveredNetworks(network)
|
||||
}
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (p *prefixTrie) insert(network rnet.Network, entry RangerEntry) (bool, error) {
|
||||
if p.network.Equal(network) {
|
||||
sizeIncreased := p.entry == nil
|
||||
p.entry = entry
|
||||
return sizeIncreased, nil
|
||||
}
|
||||
|
||||
bit, err := p.targetBitFromIP(network.Number)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
existingChild := p.children[bit]
|
||||
|
||||
// No existing child, insert new leaf trie.
|
||||
if existingChild == nil {
|
||||
p.appendTrie(bit, newEntryTrie(network, entry))
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Check whether it is necessary to insert additional path prefix between current trie and existing child,
|
||||
// in the case that inserted network diverges on its path to existing child.
|
||||
lcb, err := network.LeastCommonBitPosition(existingChild.network)
|
||||
divergingBitPos := int(lcb) - 1
|
||||
if divergingBitPos > existingChild.targetBitPosition() {
|
||||
pathPrefix := newPathprefixTrie(network, p.totalNumberOfBits()-lcb)
|
||||
err := p.insertPrefix(bit, pathPrefix, existingChild)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// Update new child
|
||||
existingChild = pathPrefix
|
||||
}
|
||||
return existingChild.insert(network, entry)
|
||||
}
|
||||
|
||||
func (p *prefixTrie) appendTrie(bit uint32, prefix *prefixTrie) {
|
||||
p.children[bit] = prefix
|
||||
prefix.parent = p
|
||||
}
|
||||
|
||||
func (p *prefixTrie) insertPrefix(bit uint32, pathPrefix, child *prefixTrie) error {
|
||||
// Set parent/child relationship between current trie and inserted pathPrefix
|
||||
p.children[bit] = pathPrefix
|
||||
pathPrefix.parent = p
|
||||
|
||||
// Set parent/child relationship between inserted pathPrefix and original child
|
||||
pathPrefixBit, err := pathPrefix.targetBitFromIP(child.network.Number)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pathPrefix.children[pathPrefixBit] = child
|
||||
child.parent = pathPrefix
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *prefixTrie) remove(network rnet.Network) (RangerEntry, error) {
|
||||
if p.hasEntry() && p.network.Equal(network) {
|
||||
entry := p.entry
|
||||
p.entry = nil
|
||||
|
||||
err := p.compressPathIfPossible()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return entry, nil
|
||||
}
|
||||
bit, err := p.targetBitFromIP(network.Number)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
child := p.children[bit]
|
||||
if child != nil {
|
||||
return child.remove(network)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (p *prefixTrie) qualifiesForPathCompression() bool {
|
||||
// Current prefix trie can be path compressed if it meets all following.
|
||||
// 1. records no CIDR entry
|
||||
// 2. has single or no child
|
||||
// 3. is not root trie
|
||||
return !p.hasEntry() && p.childrenCount() <= 1 && p.parent != nil
|
||||
}
|
||||
|
||||
func (p *prefixTrie) compressPathIfPossible() error {
|
||||
if !p.qualifiesForPathCompression() {
|
||||
// Does not qualify to be compressed
|
||||
return nil
|
||||
}
|
||||
|
||||
// Find lone child.
|
||||
var loneChild *prefixTrie
|
||||
for _, child := range p.children {
|
||||
if child != nil {
|
||||
loneChild = child
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Find root of currnt single child lineage.
|
||||
parent := p.parent
|
||||
for ; parent.qualifiesForPathCompression(); parent = parent.parent {
|
||||
}
|
||||
parentBit, err := parent.targetBitFromIP(p.network.Number)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
parent.children[parentBit] = loneChild
|
||||
|
||||
// Attempts to furthur apply path compression at current lineage parent, in case current lineage
|
||||
// compressed into parent.
|
||||
return parent.compressPathIfPossible()
|
||||
}
|
||||
|
||||
func (p *prefixTrie) childrenCount() int {
|
||||
count := 0
|
||||
for _, child := range p.children {
|
||||
if child != nil {
|
||||
count++
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func (p *prefixTrie) totalNumberOfBits() uint {
|
||||
return rnet.BitsPerUint32 * uint(len(p.network.Number))
|
||||
}
|
||||
|
||||
func (p *prefixTrie) targetBitPosition() int {
|
||||
return int(p.totalNumberOfBits()-p.numBitsSkipped) - 1
|
||||
}
|
||||
|
||||
func (p *prefixTrie) targetBitFromIP(n rnet.NetworkNumber) (uint32, error) {
|
||||
// This is a safe uint boxing of int since we should never attempt to get
|
||||
// target bit at a negative position.
|
||||
return n.Bit(uint(p.targetBitPosition()))
|
||||
}
|
||||
|
||||
func (p *prefixTrie) hasEntry() bool {
|
||||
return p.entry != nil
|
||||
}
|
||||
|
||||
func (p *prefixTrie) level() int {
|
||||
if p.parent == nil {
|
||||
return 0
|
||||
}
|
||||
return p.parent.level() + 1
|
||||
}
|
||||
|
||||
// walkDepth walks the trie in depth order, for unit testing.
|
||||
func (p *prefixTrie) walkDepth() <-chan RangerEntry {
|
||||
entries := make(chan RangerEntry)
|
||||
go func() {
|
||||
if p.hasEntry() {
|
||||
entries <- p.entry
|
||||
}
|
||||
childEntriesList := []<-chan RangerEntry{}
|
||||
for _, trie := range p.children {
|
||||
if trie == nil {
|
||||
continue
|
||||
}
|
||||
childEntriesList = append(childEntriesList, trie.walkDepth())
|
||||
}
|
||||
for _, childEntries := range childEntriesList {
|
||||
for entry := range childEntries {
|
||||
entries <- entry
|
||||
}
|
||||
}
|
||||
close(entries)
|
||||
}()
|
||||
return entries
|
||||
}
|
||||
77
vendor/github.com/libp2p/go-cidranger/version.go
generated
vendored
Normal file
77
vendor/github.com/libp2p/go-cidranger/version.go
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
package cidranger
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
rnet "github.com/libp2p/go-cidranger/net"
|
||||
)
|
||||
|
||||
type rangerFactory func(rnet.IPVersion) Ranger
|
||||
|
||||
type versionedRanger struct {
|
||||
ipV4Ranger Ranger
|
||||
ipV6Ranger Ranger
|
||||
}
|
||||
|
||||
func newVersionedRanger(factory rangerFactory) Ranger {
|
||||
return &versionedRanger{
|
||||
ipV4Ranger: factory(rnet.IPv4),
|
||||
ipV6Ranger: factory(rnet.IPv6),
|
||||
}
|
||||
}
|
||||
|
||||
func (v *versionedRanger) Insert(entry RangerEntry) error {
|
||||
network := entry.Network()
|
||||
ranger, err := v.getRangerForIP(network.IP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ranger.Insert(entry)
|
||||
}
|
||||
|
||||
func (v *versionedRanger) Remove(network net.IPNet) (RangerEntry, error) {
|
||||
ranger, err := v.getRangerForIP(network.IP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ranger.Remove(network)
|
||||
}
|
||||
|
||||
func (v *versionedRanger) Contains(ip net.IP) (bool, error) {
|
||||
ranger, err := v.getRangerForIP(ip)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return ranger.Contains(ip)
|
||||
}
|
||||
|
||||
func (v *versionedRanger) ContainingNetworks(ip net.IP) ([]RangerEntry, error) {
|
||||
ranger, err := v.getRangerForIP(ip)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ranger.ContainingNetworks(ip)
|
||||
}
|
||||
|
||||
func (v *versionedRanger) CoveredNetworks(network net.IPNet) ([]RangerEntry, error) {
|
||||
ranger, err := v.getRangerForIP(network.IP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ranger.CoveredNetworks(network)
|
||||
}
|
||||
|
||||
// Len returns number of networks in ranger.
|
||||
func (v *versionedRanger) Len() int {
|
||||
return v.ipV4Ranger.Len() + v.ipV6Ranger.Len()
|
||||
}
|
||||
|
||||
func (v *versionedRanger) getRangerForIP(ip net.IP) (Ranger, error) {
|
||||
if ip.To4() != nil {
|
||||
return v.ipV4Ranger, nil
|
||||
}
|
||||
if ip.To16() != nil {
|
||||
return v.ipV6Ranger, nil
|
||||
}
|
||||
return nil, ErrInvalidNetworkNumberInput
|
||||
}
|
||||
Reference in New Issue
Block a user