-
Notifications
You must be signed in to change notification settings - Fork 7.6k
/
ipset.go
143 lines (123 loc) · 3.93 KB
/
ipset.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
142
143
// Copyright Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ipset
import (
"errors"
"fmt"
"net/netip"
)
type IPSet struct {
V4Name string
V6Name string
Prefix string
Deps NetlinkIpsetDeps
}
const (
V4Name = "%s-v4"
V6Name = "%s-v6"
)
type NetlinkIpsetDeps interface {
ipsetIPHashCreate(name string, v6 bool) error
destroySet(name string) error
addIP(name string, ip netip.Addr, ipProto uint8, comment string, replace bool) error
deleteIP(name string, ip netip.Addr, ipProto uint8) error
flush(name string) error
clearEntriesWithComment(name string, comment string) error
clearEntriesWithIP(name string, ip netip.Addr) error
listEntriesByIP(name string) ([]netip.Addr, error)
}
// TODO this should actually create v6 and v6 subsets of type `hash:ip`, add them both to a
// superset of type `list:set` - we can then query the superset directly in iptables (with the same rule),
// and iptables will be smart enough to pick the correct underlying set (v4 or v6, based on context),
// reducing the # of rules we need.
//
// BUT netlink lib doesn't support adding things to `list:set` types yet, and current tagged release
// doesn't support creating `list:set` types yet (is in main branch tho).
// So this will actually create 2 underlying ipsets, one for v4 and one for v6
func NewIPSet(name string, v6 bool, deps NetlinkIpsetDeps) (IPSet, error) {
var err error
set := IPSet{
V4Name: fmt.Sprintf(V4Name, name),
Deps: deps,
Prefix: name,
}
err = deps.ipsetIPHashCreate(set.V4Name, false)
if v6 {
set.V6Name = fmt.Sprintf(V6Name, name)
v6err := deps.ipsetIPHashCreate(set.V6Name, true)
err = errors.Join(err, v6err)
}
return set, err
}
func (m *IPSet) DestroySet() error {
var err error
err = m.Deps.destroySet(m.V4Name)
if m.V6Name != "" {
v6err := m.Deps.destroySet(m.V6Name)
err = errors.Join(err, v6err)
}
return err
}
func (m *IPSet) AddIP(ip netip.Addr, ipProto uint8, comment string, replace bool) error {
ipToInsert := ip.Unmap()
// We have already Unmap'd, so we can do a simple IsV6 y/n check now
if ipToInsert.Is6() {
return m.Deps.addIP(m.V6Name, ipToInsert, ipProto, comment, replace)
}
return m.Deps.addIP(m.V4Name, ipToInsert, ipProto, comment, replace)
}
func (m *IPSet) DeleteIP(ip netip.Addr, ipProto uint8) error {
ipToDel := ip.Unmap()
// We have already Unmap'd, so we can do a simple IsV6 y/n check now
if ipToDel.Is6() {
return m.Deps.deleteIP(m.V6Name, ipToDel, ipProto)
}
return m.Deps.deleteIP(m.V4Name, ipToDel, ipProto)
}
func (m *IPSet) Flush() error {
var err error
err = m.Deps.flush(m.V4Name)
if m.V6Name != "" {
v6err := m.Deps.flush(m.V6Name)
err = errors.Join(err, v6err)
}
return err
}
func (m *IPSet) ClearEntriesWithComment(comment string) error {
var err error
err = m.Deps.clearEntriesWithComment(m.V4Name, comment)
if m.V6Name != "" {
v6err := m.Deps.clearEntriesWithComment(m.V6Name, comment)
err = errors.Join(err, v6err)
}
return err
}
func (m *IPSet) ClearEntriesWithIP(ip netip.Addr) error {
ipToClear := ip.Unmap()
if ipToClear.Is6() {
return m.Deps.clearEntriesWithIP(m.V6Name, ipToClear)
}
return m.Deps.clearEntriesWithIP(m.V4Name, ipToClear)
}
func (m *IPSet) ListEntriesByIP() ([]netip.Addr, error) {
var err error
var set []netip.Addr
set, err = m.Deps.listEntriesByIP(m.V4Name)
if m.V6Name != "" {
v6set, v6err := m.Deps.listEntriesByIP(m.V6Name)
err = errors.Join(err, v6err)
set = append(set, v6set...)
}
return set, err
}