-
Notifications
You must be signed in to change notification settings - Fork 51
/
acl.go
141 lines (112 loc) · 2.9 KB
/
acl.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
package acls
import (
"errors"
"fmt"
"net"
"strconv"
"strings"
"go.aporeto.io/trireme-lib/controller/constants"
"go.aporeto.io/trireme-lib/policy"
"go.aporeto.io/trireme-lib/utils/ipprefix"
)
// acl holds all the ACLS in an internal DB
type acl struct {
cache ipprefix.IPcache
}
func newACL() *acl {
return &acl{
cache: ipprefix.NewIPCache(),
}
}
// errNoMatchFromRule must stop the LPM check
var errNoMatchFromRule = errors.New("No Match")
var errNotFound = errors.New("No Match")
func (a *acl) addToCache(ip net.IP, mask int, port string, policy *policy.FlowPolicy, nomatch bool) error {
var err error
var portList portActionList
r, err := newPortAction(port, policy, nomatch)
if err != nil {
return fmt.Errorf("unable to create port action: %s", err)
}
val, exists := a.cache.Get(ip, mask)
if !exists {
portList = portActionList{}
} else {
portList = val.(portActionList)
}
/* check if this is duplicate entry */
for _, portAction := range portList {
if *r == *portAction {
return nil
}
}
portList = append(portList, r)
a.cache.Put(ip, mask, portList)
return nil
}
func (a *acl) removeIPMask(ip net.IP, mask int) {
a.cache.Put(ip, mask, nil)
}
func (a *acl) matchRule(ip net.IP, port uint16, preReport *policy.FlowPolicy) (report *policy.FlowPolicy, packet *policy.FlowPolicy, err error) {
report = preReport
err = errNotFound
lookup := func(val interface{}) bool {
if val != nil {
portList := val.(portActionList)
report, packet, err = portList.lookup(port, report)
if err == nil || err == errNoMatchFromRule {
return true
}
}
return false
}
a.cache.RunFuncOnLpmIP(ip, lookup)
return report, packet, err
}
func (a *acl) addRule(rule policy.IPRule) (err error) {
addCache := func(address, port string) error {
var mask int
parts := strings.Split(address, "/")
nomatch := strings.HasPrefix(parts[0], "!")
if nomatch {
parts[0] = parts[0][1:]
}
ip := net.ParseIP(parts[0])
if ip == nil {
return fmt.Errorf("invalid ip address: %s", parts[0])
}
if len(parts) == 1 {
if ip.To4() != nil {
mask = 32
} else {
mask = 128
}
} else {
mask, err = strconv.Atoi(parts[1])
if err != nil {
return fmt.Errorf("invalid address: %s", err)
}
}
if err := a.addToCache(ip, mask, port, rule.Policy, nomatch); err != nil {
return err
}
return nil
}
for _, proto := range rule.Protocols {
if strings.ToLower(proto) != constants.TCPProtoNum {
continue
}
for _, address := range rule.Addresses {
for _, port := range rule.Ports {
if err := addCache(address, port); err != nil {
return err
}
}
}
}
return nil
}
// getMatchingAction does lookup in acl in a common way for accept/reject rules.
func (a *acl) getMatchingAction(ip net.IP, port uint16, preReport *policy.FlowPolicy) (report *policy.FlowPolicy, packet *policy.FlowPolicy, err error) {
return a.matchRule(ip, port, preReport)
}