-
Notifications
You must be signed in to change notification settings - Fork 51
/
acl.go
133 lines (106 loc) · 2.79 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
package acls
import (
"encoding/binary"
"errors"
"fmt"
"net"
"sort"
"strconv"
"strings"
"go.aporeto.io/trireme-lib/policy"
)
func newACL() *acl {
return &acl{
sortedPrefixLens: make([]int, 0),
prefixLenMap: make(map[int]*prefixRules),
}
}
// acl holds all the ACLS in an internal DB
type acl struct {
sortedPrefixLens []int
prefixLenMap map[int]*prefixRules
}
func (a *acl) reverseSort() {
// Get reverse sorted prefix lengths for reject rules
for k := range a.prefixLenMap {
a.sortedPrefixLens = append(a.sortedPrefixLens, k)
}
sort.Sort(sort.Reverse(sort.IntSlice(a.sortedPrefixLens)))
}
func (a *acl) addRule(rule policy.IPRule) (err error) {
ruleAdd := func(address, port string, policy *policy.FlowPolicy) error {
var subnet, mask uint32
parts := strings.Split(address, "/")
subnetSlice := net.ParseIP(parts[0])
if subnetSlice == nil {
return fmt.Errorf("invalid ip address: %s", parts[0])
}
subnet = binary.BigEndian.Uint32(subnetSlice.To4())
maskValue := 0
switch len(parts) {
case 1:
mask = 0xFFFFFFFF
maskValue = 32
case 2:
maskValue, err = strconv.Atoi(parts[1])
if err != nil {
return fmt.Errorf("invalid address: %s", err)
}
if mask > 32 {
return fmt.Errorf("invalid mask value: %d", mask)
}
mask = binary.BigEndian.Uint32(net.CIDRMask(maskValue, 32))
default:
return fmt.Errorf("invalid address: %s", address)
}
plenRules, ok := a.prefixLenMap[maskValue]
if !ok {
plenRules = &prefixRules{
mask: mask,
rules: make(map[uint32]portActionList),
}
a.prefixLenMap[maskValue] = plenRules
}
r, err := newPortAction(port, policy)
if err != nil {
return fmt.Errorf("unable to create port action: %s", err)
}
subnet = subnet & mask
plenRules.rules[subnet] = append(plenRules.rules[subnet], r)
return nil
}
for _, proto := range rule.Protocols {
if strings.ToLower(proto) == "tcp" {
for _, address := range rule.Addresses {
for _, port := range rule.Ports {
if err := ruleAdd(address, port, rule.Policy); err != nil {
return err
}
}
}
}
}
return nil
}
// getMatchingAction does lookup in acl in a common way for accept/reject rules.
func (a *acl) getMatchingAction(ip []byte, port uint16, preReport *policy.FlowPolicy) (report *policy.FlowPolicy, packet *policy.FlowPolicy, err error) {
report = preReport
addr := binary.BigEndian.Uint32(ip)
// Iterate over all the bitmasks we have
for _, len := range a.sortedPrefixLens {
rules, ok := a.prefixLenMap[len]
if !ok {
continue
}
// Do a lookup as a hash to see if we have a match
actionList, ok := rules.rules[addr&rules.mask]
if !ok {
continue
}
report, packet, err = actionList.lookup(port, report)
if err == nil {
return
}
}
return report, packet, errors.New("No match")
}