forked from weaveworks/weave
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ipblock.go
116 lines (95 loc) · 2.75 KB
/
ipblock.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
package npc
import (
"fmt"
"sort"
"strings"
networkingv1 "k8s.io/api/networking/v1"
"k8s.io/apimachinery/pkg/types"
"github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/net/ipset"
)
type ipBlockSpec struct {
key string
ipsetName ipset.Name // ipset for storing excepted CIDRs
ipBlock *networkingv1.IPBlock
nsName string // Namespace name
}
func newIPBlockSpec(ipb *networkingv1.IPBlock, nsName string) *ipBlockSpec {
spec := &ipBlockSpec{ipBlock: ipb, nsName: nsName}
if len(ipb.Except) > 0 {
sort.Strings(ipb.Except)
spec.key = strings.Join(ipb.Except, " ")
spec.ipsetName = ipset.Name(IpsetNamePrefix + shortName(nsName+":"+"ipblock-except:"+spec.key))
}
return spec
}
func (spec *ipBlockSpec) getRuleSpec(src bool) ([]string, string) {
dir, dirOpt := "dst", "-d"
if src {
dir, dirOpt = "src", "-s"
}
if spec.key == "" {
rule := []string{dirOpt, spec.ipBlock.CIDR}
comment := fmt.Sprintf("cidr: %s", spec.ipBlock.CIDR)
return rule, comment
}
rule := []string{dirOpt, spec.ipBlock.CIDR,
"-m", "set", "!", "--match-set", string(spec.ipsetName), dir}
comment := fmt.Sprintf("cidr: %s except [%s]", spec.ipBlock.CIDR, spec.key)
return rule, comment
}
type ipBlockSet struct {
ips ipset.Interface
users map[string]map[types.UID]struct{}
}
func newIPBlockSet(ips ipset.Interface) *ipBlockSet {
return &ipBlockSet{
ips: ips,
users: make(map[string]map[types.UID]struct{}),
}
}
func (s *ipBlockSet) deprovision(user types.UID, current, desired map[string]*ipBlockSpec) error {
for key, spec := range current {
if key == "" {
continue
}
if _, found := desired[key]; !found {
delete(s.users[key], user)
if len(s.users[key]) == 0 {
common.Log.Infof("destroying ipset: %#v", spec)
if err := s.ips.Destroy(spec.ipsetName); err != nil {
return err
}
delete(s.users, key)
}
}
}
return nil
}
func (s *ipBlockSet) provision(user types.UID, current, desired map[string]*ipBlockSpec) (err error) {
for key, spec := range desired {
if key == "" {
// No need to provision an ipBlock with empty list of excepted CIDRs
// (i.e. no ipset is needed for the related iptables rule).
continue
}
if _, found := current[key]; !found {
if _, found := s.users[key]; !found {
common.Log.Infof("creating ipset: %#v", spec)
if err := s.ips.Create(spec.ipsetName, ipset.HashNet); err != nil {
return err
}
// TODO(brb) Pass comment to ips.Create instead.
comment := "excepted from " + spec.ipBlock.CIDR
for _, cidr := range spec.ipBlock.Except {
if err = s.ips.AddEntry(user, spec.ipsetName, cidr, comment); err != nil {
return err
}
}
s.users[key] = make(map[types.UID]struct{})
}
s.users[key][user] = struct{}{}
}
}
return nil
}