forked from multiformats/go-multiaddr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfilter.go
179 lines (155 loc) · 4.46 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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
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
}
// AddDialFilter adds a deny rule to this Filters set. Hosts
// matching the given net.IPNet filter will be denied, unless
// another rule is added which states that they should be accepted.
//
// No effort is made to prevent duplication of filters, or to simplify
// the filters list.
//
// Deprecated: Use AddFilter().
func (fs *Filters) AddDialFilter(f *net.IPNet) {
fs.AddFilter(*f, ActionDeny)
}
// 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.
//
// Deprecated: use RemoveLiteral() instead.
func (fs *Filters) Remove(ipnet *net.IPNet) (removed bool) {
return fs.RemoveLiteral(*ipnet)
}
// 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
}
// Filters returns the list of DENY net.IPNet masks. For backwards compatibility.
//
// A copy of the filters is made prior to returning, so the inner state is not exposed.
//
// Deprecated: Use FiltersForAction().
func (fs *Filters) Filters() (result []*net.IPNet) {
ffa := fs.FiltersForAction(ActionDeny)
for _, res := range ffa {
res := res // allocate a new copy
result = append(result, &res)
}
return result
}
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
}