This repository has been archived by the owner on Oct 12, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 255
/
iptables.go
176 lines (154 loc) · 4.79 KB
/
iptables.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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
package iptables
import (
"errors"
"strings"
"github.com/coreos/go-iptables/iptables"
"k8s.io/klog/v2"
)
var (
tablename = "nat"
customchainname = "aad-metadata"
localhost = "127.0.0.1/32"
)
// AddCustomChain adds the rule to the host's nat table custom chain
// all tcp requests NOT originating from localhost destined to
// destIp:destPort are routed to targetIP:targetPort
func AddCustomChain(destIP, destPort, targetip, targetport string) error {
if destIP == "" {
return errors.New("destIP must be set")
}
if destPort == "" {
return errors.New("destPort must be set")
}
if targetip == "" {
return errors.New("targetip must be set")
}
if targetport == "" {
return errors.New("targetport must be set")
}
ipt, err := iptables.New()
if err != nil {
return err
}
if err := ensureCustomChain(ipt, destIP, destPort, targetip, targetport); err != nil {
return err
}
if err := placeCustomChainInChain(ipt, tablename, "PREROUTING"); err != nil {
return err
}
return nil
}
// LogCustomChain logs added rules to the custom chain
func LogCustomChain() error {
ipt, err := iptables.New()
if err != nil {
return err
}
rules, err := ipt.List(tablename, customchainname)
if err != nil {
return err
}
klog.V(5).Infof("rules for table(%s) chain(%s) rules(%+v)", tablename, customchainname, strings.Join(rules, ", "))
return nil
}
// iptables -t nat -I "chain" 1 -j "customchainname"
func placeCustomChainInChain(ipt *iptables.IPTables, table, chain string) error {
exists, err := ipt.Exists(table, chain, "-j", customchainname)
if err != nil || !exists {
if err := ipt.Insert(table, chain, 1, "-j", customchainname); err != nil {
return err
}
}
return nil
}
func ensureCustomChain(ipt *iptables.IPTables, destIP, destPort, targetip, targetport string) error {
rules, err := ipt.List(tablename, customchainname)
if err != nil {
err = ipt.NewChain(tablename, customchainname)
if err != nil {
return err
}
}
/*
iptables -t nat -S aad-metadata returns 3 rules
-N aad-metadata
-A aad-metadata ! -s 127.0.0.1/32 -d 169.254.169.254/32 -p tcp -m tcp --dport 80 -j DNAT --to-destination 127.0.0.1:<nmi port>
-A aad-metadata -j RETURN
For this reason we check if the length of rules is 3. If not 3, then we flush and create chain again.
*/
expectedRules := map[string]struct{}{
"-N aad-metadata": {},
"-A aad-metadata ! -s 127.0.0.1/32 -d " + destIP + "/32 -p tcp -m tcp --dport " + destPort + " -j DNAT --to-destination " + targetip + ":" + targetport: {},
"-A aad-metadata -j RETURN": {},
}
matchingRules := 0
// ensure all the rules are as expected with the right IPs
// if any rule has been changed, then we need to flush the
// entire chain and reconcile with the correct IPs
for _, rule := range rules {
if _, ok := expectedRules[rule]; !ok {
break
}
matchingRules++
}
// all the required rules exist, so no need to flush custom chain
if matchingRules == len(expectedRules) {
return nil
}
if err := flushCreateCustomChainrules(ipt, destIP, destPort,
targetip, targetport); err != nil {
return err
}
return nil
}
func flushCreateCustomChainrules(ipt *iptables.IPTables, destIP, destPort, targetip, targetport string) error {
klog.Warning("flushing iptables to add aad-metadata custom chains")
if err := ipt.ClearChain(tablename, customchainname); err != nil {
return err
}
if err := ipt.AppendUnique(
tablename, customchainname, "-p", "tcp", "!", "-s", localhost, "-d", destIP, "--dport", destPort,
"-j", "DNAT", "--to-destination", targetip+":"+targetport); err != nil {
return err
}
if err := ipt.AppendUnique(
tablename, customchainname, "-j", "RETURN"); err != nil {
return err
}
return nil
}
// DeleteCustomChain removes the custom chain aad-metadata reference from PREROUTING
// chain and then removes the chain aad-metadata from nat table
func DeleteCustomChain() error {
ipt, err := iptables.New()
if err != nil {
return err
}
if err := removeCustomChainReference(ipt, tablename, "PREROUTING"); err != nil {
return err
}
if err := removeCustomChain(ipt, tablename); err != nil {
return err
}
return nil
}
// removeCustomChainReference - iptables -t "table" -D "chain" -j "customchainname"
func removeCustomChainReference(ipt *iptables.IPTables, table, chain string) error {
exists, err := ipt.Exists(table, chain, "-j", customchainname)
if err == nil && exists {
return ipt.Delete(table, chain, "-j", customchainname)
}
return nil
}
// removeCustomChain - flush and then delete custom chain
// iptables -t "table" -F "customchainname"
// iptables -t "table" -X "customchainname"
func removeCustomChain(ipt *iptables.IPTables, table string) error {
if err := ipt.ClearChain(table, customchainname); err != nil {
return err
}
if err := ipt.DeleteChain(table, customchainname); err != nil {
return err
}
return nil
}