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:
anthonyrawlins
2025-08-01 02:21:11 +10:00
parent 81b473d48f
commit 5978a0b8f5
3713 changed files with 1103925 additions and 59 deletions

1
vendor/github.com/libp2p/go-cidranger/.gitignore generated vendored Normal file
View File

@@ -0,0 +1 @@
vendor

31
vendor/github.com/libp2p/go-cidranger/.travis.yml generated vendored Normal file
View 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
View 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
View 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
View 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
View 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.
[![GoDoc Reference](https://img.shields.io/badge/godoc-reference-5272B4.svg?style=flat-square)](https://godoc.org/github.com/libp2p/go-cidranger)
[![Build Status](https://img.shields.io/travis/libp2p/go-cidranger.svg?branch=master&style=flat-square)](https://travis-ci.org/libp2p/go-cidranger)
[![Coverage Status](https://img.shields.io/coveralls/libp2p/go-cidranger.svg?branch=master&style=flat-square)](https://coveralls.io/github/libp2p/go-cidranger?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/libp2p/go-cidranger?&style=flat-square)](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
View 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
View 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
View 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
View 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
View 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
}