brute.go 3.52 KB
Newer Older
1
package cidranger
yl2chen's avatar
yl2chen committed
2

3 4
import (
	"net"
5

Steven Allen's avatar
Steven Allen committed
6
	rnet "github.com/libp2p/go-cidranger/net"
7
)
yl2chen's avatar
yl2chen committed
8

9 10 11 12 13 14 15 16 17 18 19
// 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 {
20 21
	ipV4Entries map[string]RangerEntry
	ipV6Entries map[string]RangerEntry
yl2chen's avatar
yl2chen committed
22 23
}

24 25 26
// newBruteRanger returns a new Ranger.
func newBruteRanger() Ranger {
	return &bruteRanger{
27 28
		ipV4Entries: make(map[string]RangerEntry),
		ipV6Entries: make(map[string]RangerEntry),
yl2chen's avatar
yl2chen committed
29 30 31
	}
}

32 33 34
// Insert inserts a RangerEntry into ranger.
func (b *bruteRanger) Insert(entry RangerEntry) error {
	network := entry.Network()
yl2chen's avatar
yl2chen committed
35
	key := network.String()
36 37
	if _, found := b.ipV4Entries[key]; !found {
		entries, err := b.getEntriesByVersion(entry.Network().IP)
38 39 40
		if err != nil {
			return err
		}
41
		entries[key] = entry
yl2chen's avatar
yl2chen committed
42 43 44 45
	}
	return nil
}

46 47 48
// 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)
49 50 51
	if err != nil {
		return nil, err
	}
yl2chen's avatar
yl2chen committed
52
	key := network.String()
53 54
	if networkToDelete, found := networks[key]; found {
		delete(networks, key)
55
		return networkToDelete, nil
yl2chen's avatar
yl2chen committed
56 57 58 59 60 61
	}
	return nil, nil
}

// Contains returns bool indicating whether given ip is contained by any
// network in ranger.
62
func (b *bruteRanger) Contains(ip net.IP) (bool, error) {
63
	entries, err := b.getEntriesByVersion(ip)
64 65 66
	if err != nil {
		return false, err
	}
67 68
	for _, entry := range entries {
		network := entry.Network()
yl2chen's avatar
yl2chen committed
69 70 71 72 73 74 75
		if network.Contains(ip) {
			return true, nil
		}
	}
	return false, nil
}

76 77 78
// ContainingNetworks returns all RangerEntry(s) that given ip contained in.
func (b *bruteRanger) ContainingNetworks(ip net.IP) ([]RangerEntry, error) {
	entries, err := b.getEntriesByVersion(ip)
79 80 81
	if err != nil {
		return nil, err
	}
82 83 84
	results := []RangerEntry{}
	for _, entry := range entries {
		network := entry.Network()
yl2chen's avatar
yl2chen committed
85
		if network.Contains(ip) {
86
			results = append(results, entry)
yl2chen's avatar
yl2chen committed
87 88
		}
	}
89 90 91
	return results, nil
}

Rob Adams's avatar
Rob Adams committed
92 93 94 95 96 97 98 99 100
// 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
101
	testNetwork := rnet.NewNetwork(network)
Rob Adams's avatar
Rob Adams committed
102
	for _, entry := range entries {
103 104
		entryNetwork := rnet.NewNetwork(entry.Network())
		if testNetwork.Covers(entryNetwork) {
Rob Adams's avatar
Rob Adams committed
105 106 107 108 109 110
			results = append(results, entry)
		}
	}
	return results, nil
}

Yulin Chen's avatar
Yulin Chen committed
111 112 113 114 115
// Len returns number of networks in ranger.
func (b *bruteRanger) Len() int {
	return len(b.ipV4Entries) + len(b.ipV6Entries)
}

116
func (b *bruteRanger) getEntriesByVersion(ip net.IP) (map[string]RangerEntry, error) {
117
	if ip.To4() != nil {
118
		return b.ipV4Entries, nil
119 120
	}
	if ip.To16() != nil {
121
		return b.ipV6Entries, nil
122
	}
123
	return nil, ErrInvalidNetworkInput
yl2chen's avatar
yl2chen committed
124
}