forked from weaveworks/weave
/
rule.go
129 lines (112 loc) · 3.42 KB
/
rule.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
package npc
import (
"fmt"
"reflect"
"strings"
"k8s.io/apimachinery/pkg/types"
"github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/npc/iptables"
)
type ruleHost interface {
// getRuleSpec returns source or destination specification and comment which
// are used in an iptables rule.
//
// If src=true then the rulespec is for source, otherwise - for destination.
getRuleSpec(src bool) ([]string, string)
}
type ruleSpec struct {
key string
args []string
policyType policyType
}
func newRuleSpec(policyType policyType, proto *string, srcHost, dstHost ruleHost, dstPort *string) *ruleSpec {
args := []string{}
if proto != nil {
args = append(args, "-p", *proto)
}
srcComment := "anywhere"
if srcHost != nil && !reflect.ValueOf(srcHost).IsNil() {
rule, comment := srcHost.getRuleSpec(true)
args = append(args, rule...)
srcComment = comment
}
dstComment := "anywhere"
if dstHost != nil && !reflect.ValueOf(dstHost).IsNil() {
rule, comment := dstHost.getRuleSpec(false)
args = append(args, rule...)
dstComment = comment
}
if dstPort != nil {
args = append(args, "--dport", *dstPort)
}
// NOTE: if you remove the comment bellow, then embed `policyType` into `key`.
// Otherwise, the rule won't be provisioned if it exists for other policy type.
args = append(args, "-m", "comment", "--comment", fmt.Sprintf("%s -> %s (%s)", srcComment, dstComment, policyTypeStr(policyType)))
key := strings.Join(args, " ")
return &ruleSpec{key, args, policyType}
}
func (spec *ruleSpec) iptChain() string {
if spec.policyType == policyTypeEgress {
return EgressCustomChain
}
return IngressChain
}
func (spec *ruleSpec) iptRuleSpecs() [][]string {
if spec.policyType == policyTypeIngress {
rule := make([]string, len(spec.args))
copy(rule, spec.args)
rule = append(rule, "-j", "ACCEPT")
return [][]string{rule}
}
// policyTypeEgress
ruleMark := make([]string, len(spec.args))
copy(ruleMark, spec.args)
ruleMark = append(ruleMark, "-j", EgressMarkChain)
ruleReturn := make([]string, len(spec.args))
copy(ruleReturn, spec.args)
ruleReturn = append(ruleReturn, "-j", "RETURN")
return [][]string{ruleMark, ruleReturn}
}
type ruleSet struct {
ipt iptables.Interface
users map[string]map[types.UID]struct{}
}
func newRuleSet(ipt iptables.Interface) *ruleSet {
return &ruleSet{ipt, make(map[string]map[types.UID]struct{})}
}
func (rs *ruleSet) deprovision(user types.UID, current, desired map[string]*ruleSpec) error {
for key, spec := range current {
if _, found := desired[key]; !found {
delete(rs.users[key], user)
if len(rs.users[key]) == 0 {
chain := spec.iptChain()
for _, rule := range spec.iptRuleSpecs() {
common.Log.Infof("deleting rule %v from %q chain", rule, chain)
if err := rs.ipt.Delete(TableFilter, chain, rule...); err != nil {
return err
}
}
delete(rs.users, key)
}
}
}
return nil
}
func (rs *ruleSet) provision(user types.UID, current, desired map[string]*ruleSpec) error {
for key, spec := range desired {
if _, found := current[key]; !found {
if _, found := rs.users[key]; !found {
chain := spec.iptChain()
for _, rule := range spec.iptRuleSpecs() {
common.Log.Infof("adding rule %v to %q chain", rule, chain)
if err := rs.ipt.Append(TableFilter, chain, rule...); err != nil {
return err
}
}
rs.users[key] = make(map[types.UID]struct{})
}
rs.users[key][user] = struct{}{}
}
}
return nil
}