1package multiaddr
2
3import (
4	"net"
5	"sync"
6)
7
8// Action is an enum modelling all possible filter actions.
9type Action int32
10
11const (
12	ActionNone Action = iota // zero value.
13	ActionAccept
14	ActionDeny
15)
16
17type filterEntry struct {
18	f      net.IPNet
19	action Action
20}
21
22// Filters is a structure representing a collection of accept/deny
23// net.IPNet filters, together with the DefaultAction flag, which
24// represents the default filter policy.
25//
26// Note that the last policy added to the Filters is authoritative.
27type Filters struct {
28	DefaultAction Action
29
30	mu      sync.RWMutex
31	filters []*filterEntry
32}
33
34// NewFilters constructs and returns a new set of net.IPNet filters.
35// By default, the new filter accepts all addresses.
36func NewFilters() *Filters {
37	return &Filters{
38		DefaultAction: ActionAccept,
39		filters:       make([]*filterEntry, 0),
40	}
41}
42
43func (fs *Filters) find(ipnet net.IPNet) (int, *filterEntry) {
44	s := ipnet.String()
45	for idx, ft := range fs.filters {
46		if ft.f.String() == s {
47			return idx, ft
48		}
49	}
50	return -1, nil
51}
52
53// AddDialFilter adds a deny rule to this Filters set. Hosts
54// matching the given net.IPNet filter will be denied, unless
55// another rule is added which states that they should be accepted.
56//
57// No effort is made to prevent duplication of filters, or to simplify
58// the filters list.
59//
60// Deprecated: Use AddFilter().
61func (fs *Filters) AddDialFilter(f *net.IPNet) {
62	fs.AddFilter(*f, ActionDeny)
63}
64
65// AddFilter adds a rule to the Filters set, enforcing the desired action for
66// the provided IPNet mask.
67func (fs *Filters) AddFilter(ipnet net.IPNet, action Action) {
68	fs.mu.Lock()
69	defer fs.mu.Unlock()
70
71	if _, f := fs.find(ipnet); f != nil {
72		f.action = action
73	} else {
74		fs.filters = append(fs.filters, &filterEntry{ipnet, action})
75	}
76}
77
78// RemoveLiteral removes the first filter associated with the supplied IPNet,
79// returning whether something was removed or not. It makes no distinction
80// between whether the rule is an accept or a deny.
81//
82// Deprecated: use RemoveLiteral() instead.
83func (fs *Filters) Remove(ipnet *net.IPNet) (removed bool) {
84	return fs.RemoveLiteral(*ipnet)
85}
86
87// RemoveLiteral removes the first filter associated with the supplied IPNet,
88// returning whether something was removed or not. It makes no distinction
89// between whether the rule is an accept or a deny.
90func (fs *Filters) RemoveLiteral(ipnet net.IPNet) (removed bool) {
91	fs.mu.Lock()
92	defer fs.mu.Unlock()
93
94	if idx, _ := fs.find(ipnet); idx != -1 {
95		fs.filters = append(fs.filters[:idx], fs.filters[idx+1:]...)
96		return true
97	}
98	return false
99}
100
101// AddrBlocked parses a ma.Multiaddr and, if a valid netip is found, it applies the
102// Filter set rules, returning true if the given address should be denied, and false if
103// the given address is accepted.
104//
105// If a parsing error occurs, or no filter matches, the Filters'
106// default is returned.
107//
108// TODO: currently, the last filter to match wins always, but it shouldn't be that way.
109//  Instead, the highest-specific last filter should win; that way more specific filters
110//  override more general ones.
111func (fs *Filters) AddrBlocked(a Multiaddr) (deny bool) {
112	var (
113		netip net.IP
114		found bool
115	)
116
117	ForEach(a, func(c Component) bool {
118		switch c.Protocol().Code {
119		case P_IP6ZONE:
120			return true
121		case P_IP6, P_IP4:
122			found = true
123			netip = net.IP(c.RawValue())
124			return false
125		default:
126			return false
127		}
128	})
129
130	if !found {
131		return fs.DefaultAction == ActionDeny
132	}
133
134	fs.mu.RLock()
135	defer fs.mu.RUnlock()
136
137	action := fs.DefaultAction
138	for _, ft := range fs.filters {
139		if ft.f.Contains(netip) {
140			action = ft.action
141		}
142	}
143
144	return action == ActionDeny
145}
146
147// Filters returns the list of DENY net.IPNet masks. For backwards compatibility.
148//
149// A copy of the filters is made prior to returning, so the inner state is not exposed.
150//
151// Deprecated: Use FiltersForAction().
152func (fs *Filters) Filters() (result []*net.IPNet) {
153	ffa := fs.FiltersForAction(ActionDeny)
154	for _, res := range ffa {
155		res := res // allocate a new copy
156		result = append(result, &res)
157	}
158	return result
159}
160
161func (fs *Filters) ActionForFilter(ipnet net.IPNet) (action Action, ok bool) {
162	if _, f := fs.find(ipnet); f != nil {
163		return f.action, true
164	}
165	return ActionNone, false
166}
167
168// FiltersForAction returns the filters associated with the indicated action.
169func (fs *Filters) FiltersForAction(action Action) (result []net.IPNet) {
170	fs.mu.RLock()
171	defer fs.mu.RUnlock()
172
173	for _, ff := range fs.filters {
174		if ff.action == action {
175			result = append(result, ff.f)
176		}
177	}
178	return result
179}
180