Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Coveringnetworks #47

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions brute.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,48 @@ func (b *bruteRanger) CoveredNetworks(network net.IPNet) ([]RangerEntry, error)
return results, nil
}

// CoveringOrCoveredNetworks returns the list of RangerEntry(s) the given ipnet
// covers or list of RangerEntry(s) covered by the ipnet.
func (b *bruteRanger) CoveringOrCoveredNetworks(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) || entryNetwork.Covers(testNetwork) {
results = append(results, entry)
}
}
return results, nil
}

// CoveringNetworks returns the list of RangerEntry(s) covering the given ipnet
// That is, the networks that are completely subsumed by the
// specified network.
func (b *bruteRanger) CoveringNetworks(network net.IPNet) ([]RangerEntry, error) {
n_ones, _ := network.Mask.Size()
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())
e_ones, _ := entryNetwork.IPNet.Mask.Size()
if uint(e_ones) > uint(n_ones) {
continue
}
if entryNetwork.Covers(testNetwork) {
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)
Expand Down
30 changes: 30 additions & 0 deletions brute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,33 @@ func TestCoveredNetworks(t *testing.T) {
})
}
}

func TestCoveringNetworks(t *testing.T) {
for _, tc := range coveringNetworkTests {
t.Run(tc.name, func(t *testing.T) {
ranger := newBruteRanger()
for _, insert := range tc.inserts {
_, network, _ := net.ParseCIDR(insert)
err := ranger.Insert(NewBasicRangerEntry(*network))
assert.NoError(t, err)
}
var expectedEntries []string
for _, network := range tc.networks {
expectedEntries = append(expectedEntries, network)
}
sort.Strings(expectedEntries)
_, snet, _ := net.ParseCIDR(tc.search)
networks, err := ranger.CoveringNetworks(*snet)
assert.NoError(t, err)

var results []string
for _, result := range networks {
net := result.Network()
results = append(results, net.String())
}
sort.Strings(results)

assert.Equal(t, expectedEntries, results)
})
}
}
40 changes: 25 additions & 15 deletions cidranger.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,37 @@ inclusion tests against it.

To create a new instance of the path-compressed trie:

ranger := NewPCTrieRanger()
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)
_, 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
}
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"))
// 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"))
// 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)

// returns []RangerEntry, error
entries, err := ranger.CoveredNetworks(*AllIPv4)
entries, err := ranger.CoveredNetworks(*AllIPv6)
*/
package cidranger

Expand Down Expand Up @@ -88,7 +87,18 @@ type Ranger interface {
Remove(network net.IPNet) (RangerEntry, error)
Contains(ip net.IP) (bool, error)
ContainingNetworks(ip net.IP) ([]RangerEntry, error)
// returns the list of RangerEntry(s) covered by "network".
// i.e. CoveredNetworks("1.1.1.0/24") would return "1.1.1.1/32" if it's in the cidranger list,
// but CoveredNetworks("1.1.1.0/24") would never return "1.1.0.0/16".
CoveredNetworks(network net.IPNet) ([]RangerEntry, error)
// returns the list of RangerEntry(s) covering "network".
// i.e. CoveringNetworks("1.1.1.0/24") would return "1.1.0.0/16" if it's in the cidranger list,
// but CoveringNetworks("1.1.1.0/24") would never return "1.1.1.1/32".
CoveringNetworks(network net.IPNet) ([]RangerEntry, error)
// returns the list of RangerEntry(s) that are either covering "network" or covered by "network".
// i.e. CoveringOrCoveredNetworks("1.1.1.0/24") would return "1.1.0.0/16" if it's in the cidranger list,
// and CoveringOrCoveredNetworks("1.1.1.0/24") would return "1.1.1.1/32" if it's also in the cidranger list.
CoveringOrCoveredNetworks(network net.IPNet) ([]RangerEntry, error)
Len() int
}

Expand Down
71 changes: 71 additions & 0 deletions trie.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,21 @@ func (p *prefixTrie) CoveredNetworks(network net.IPNet) ([]RangerEntry, error) {
return p.coveredNetworks(net)
}

// CoveringNetworks returns the list of RangerEntry(s) covering the given ipnet
// That is, the networks that are completely subsumed by the
// specified network.
func (p *prefixTrie) CoveringNetworks(network net.IPNet) ([]RangerEntry, error) {
net := rnet.NewNetwork(network)
return p.coveringNetworks(net)
}

// CoveringOrCoveredNetworks returns the list of RangerEntry(s) the given ipnet
// covers or list of RangerEntry(s) covered by the ipnet.
func (p *prefixTrie) CoveringOrCoveredNetworks(network net.IPNet) ([]RangerEntry, error) {
net := rnet.NewNetwork(network)
return p.coveringOrCoveredNetworks(net)
}

// Len returns number of networks in ranger.
func (p *prefixTrie) Len() int {
return p.size
Expand Down Expand Up @@ -217,6 +232,62 @@ func (p *prefixTrie) coveredNetworks(network rnet.Network) ([]RangerEntry, error
return results, nil
}

func (p *prefixTrie) coveringOrCoveredNetworks(network rnet.Network) ([]RangerEntry, error) {
var results []RangerEntry
n_ones, _ := network.IPNet.Mask.Size()
p_ones, _ := p.network.IPNet.Mask.Size()
if p_ones < n_ones {
if p.hasEntry() && p.network.Covers(network) {
results = append(results, p.entry)
}
}

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 {
if p_ones < n_ones {
childs, err := child.coveringOrCoveredNetworks(network)
results = append(results, childs...)
return results, err
}
}
}
return results, nil
}

func (p *prefixTrie) coveringNetworks(network rnet.Network) ([]RangerEntry, error) {
var results []RangerEntry
n_ones, _ := network.IPNet.Mask.Size()
p_ones, _ := p.network.IPNet.Mask.Size()
if p_ones > n_ones {
return results, nil
}
if p.hasEntry() && p.network.Covers(network) {
results = append(results, p.entry)
}
if p.targetBitPosition() >= 0 {
bit, err := p.targetBitFromIP(network.Number)
if err != nil {
return results, err
}
child := p.children[bit]
if child != nil {
childs, err := child.coveringNetworks(network)
results = append(results, childs...)
return results, err
}
}
return results, nil
}

func (p *prefixTrie) insert(network rnet.Network, entry RangerEntry) (bool, error) {
if p.network.Equal(network) {
sizeIncreased := p.entry == nil
Expand Down
Loading