forked from multiformats/go-multiaddr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
filter.go
145 lines (124 loc) · 3.31 KB
/
filter.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package multiaddr
import (
"net"
"sync"
)
// Action is an enum modelling all possible filter actions.
type Action int32
const (
ActionNone Action = iota // zero value.
ActionAccept
ActionDeny
)
type filterEntry struct {
f net.IPNet
action Action
}
// Filters is a structure representing a collection of accept/deny
// net.IPNet filters, together with the DefaultAction flag, which
// represents the default filter policy.
//
// Note that the last policy added to the Filters is authoritative.
type Filters struct {
DefaultAction Action
mu sync.RWMutex
filters []*filterEntry
}
// NewFilters constructs and returns a new set of net.IPNet filters.
// By default, the new filter accepts all addresses.
func NewFilters() *Filters {
return &Filters{
DefaultAction: ActionAccept,
filters: make([]*filterEntry, 0),
}
}
func (fs *Filters) find(ipnet net.IPNet) (int, *filterEntry) {
s := ipnet.String()
for idx, ft := range fs.filters {
if ft.f.String() == s {
return idx, ft
}
}
return -1, nil
}
// AddFilter adds a rule to the Filters set, enforcing the desired action for
// the provided IPNet mask.
func (fs *Filters) AddFilter(ipnet net.IPNet, action Action) {
fs.mu.Lock()
defer fs.mu.Unlock()
if _, f := fs.find(ipnet); f != nil {
f.action = action
} else {
fs.filters = append(fs.filters, &filterEntry{ipnet, action})
}
}
// RemoveLiteral removes the first filter associated with the supplied IPNet,
// returning whether something was removed or not. It makes no distinction
// between whether the rule is an accept or a deny.
func (fs *Filters) RemoveLiteral(ipnet net.IPNet) (removed bool) {
fs.mu.Lock()
defer fs.mu.Unlock()
if idx, _ := fs.find(ipnet); idx != -1 {
fs.filters = append(fs.filters[:idx], fs.filters[idx+1:]...)
return true
}
return false
}
// AddrBlocked parses a ma.Multiaddr and, if a valid netip is found, it applies the
// Filter set rules, returning true if the given address should be denied, and false if
// the given address is accepted.
//
// If a parsing error occurs, or no filter matches, the Filters'
// default is returned.
//
// TODO: currently, the last filter to match wins always, but it shouldn't be that way.
//
// Instead, the highest-specific last filter should win; that way more specific filters
// override more general ones.
func (fs *Filters) AddrBlocked(a Multiaddr) (deny bool) {
var (
netip net.IP
found bool
)
ForEach(a, func(c Component) bool {
switch c.Protocol().Code {
case P_IP6ZONE:
return true
case P_IP6, P_IP4:
found = true
netip = net.IP(c.RawValue())
return false
default:
return false
}
})
if !found {
return fs.DefaultAction == ActionDeny
}
fs.mu.RLock()
defer fs.mu.RUnlock()
action := fs.DefaultAction
for _, ft := range fs.filters {
if ft.f.Contains(netip) {
action = ft.action
}
}
return action == ActionDeny
}
func (fs *Filters) ActionForFilter(ipnet net.IPNet) (action Action, ok bool) {
if _, f := fs.find(ipnet); f != nil {
return f.action, true
}
return ActionNone, false
}
// FiltersForAction returns the filters associated with the indicated action.
func (fs *Filters) FiltersForAction(action Action) (result []net.IPNet) {
fs.mu.RLock()
defer fs.mu.RUnlock()
for _, ff := range fs.filters {
if ff.action == action {
result = append(result, ff.f)
}
}
return result
}