/
instance_chain_creator.go
141 lines (113 loc) · 5.08 KB
/
instance_chain_creator.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
package iptables
import (
"fmt"
"net"
"os/exec"
"code.cloudfoundry.org/lager/v3"
)
type InstanceChainCreator struct {
iptables *IPTablesController
}
func NewInstanceChainCreator(iptables *IPTablesController) *InstanceChainCreator {
return &InstanceChainCreator{
iptables: iptables,
}
}
func (cc *InstanceChainCreator) Create(logger lager.Logger, handle, instanceId, bridgeName string, ip net.IP, network *net.IPNet) error {
instanceChain := cc.iptables.InstanceChain(instanceId)
if err := cc.iptables.CreateChain("nat", instanceChain); err != nil {
return err
}
// Bind nat instance chain to nat prerouting chain
cmd := exec.Command(cc.iptables.iptablesBinPath, "--wait", "--table", "nat", "-A", cc.iptables.preroutingChain, "--jump", instanceChain, "-m", "comment", "--comment", handle)
if err := cc.iptables.run("create-instance-chains", cmd); err != nil {
return err
}
// Enable NAT for traffic coming from containers
cmd = exec.Command("sh", "-c", fmt.Sprintf(
`(%s --wait --table nat -S %s | grep "\-j MASQUERADE\b" | grep -q -F -- "-s %s") || %s --wait --table nat -A %s --source %s ! --destination %s --jump MASQUERADE -m comment --comment %s`,
cc.iptables.iptablesBinPath, cc.iptables.postroutingChain, network.String(), cc.iptables.iptablesBinPath, cc.iptables.postroutingChain,
network.String(), network.String(), handle,
))
if err := cc.iptables.run("create-instance-chains", cmd); err != nil {
return err
}
// Create filter instance chain
if err := cc.iptables.CreateChain("filter", instanceChain); err != nil {
return err
}
// Allow intra-subnet traffic (Linux ethernet bridging goes through ip stack)
cmd = exec.Command(cc.iptables.iptablesBinPath, "--wait", "-A", instanceChain, "-s", network.String(), "-d", network.String(), "-j", "ACCEPT", "-m", "comment", "--comment", handle)
if err := cc.iptables.run("create-instance-chains", cmd); err != nil {
return err
}
// Otherwise, use the default filter chain
cmd = exec.Command(cc.iptables.iptablesBinPath, "--wait", "-A", instanceChain, "--goto", cc.iptables.defaultChain, "-m", "comment", "--comment", handle)
if err := cc.iptables.run("create-instance-chains", cmd); err != nil {
return err
}
// Bind filter instance chain to filter forward chain
cmd = exec.Command(cc.iptables.iptablesBinPath, "--wait", "-I", cc.iptables.forwardChain, "2", "--in-interface", bridgeName, "--source", ip.String(), "--goto", instanceChain, "-m", "comment", "--comment", handle)
if err := cc.iptables.run("create-instance-chains", cmd); err != nil {
return err
}
// Create Logging Chain
return cc.createLoggingChain(logger, handle, instanceId)
}
func (cc *InstanceChainCreator) createLoggingChain(logger lager.Logger, handle, instanceId string) error {
instanceChain := cc.iptables.InstanceChain(instanceId)
loggingChain := fmt.Sprintf("%s-log", instanceChain)
if err := cc.iptables.CreateChain("filter", loggingChain); err != nil {
return err
}
logPrefix := handle
if len(logPrefix) > 28 {
logPrefix = logPrefix[0:28]
}
logPrefix = logPrefix + " "
cmd := exec.Command(cc.iptables.iptablesBinPath, "--wait", "-A", loggingChain, "-m", "conntrack", "--ctstate", "NEW,UNTRACKED,INVALID", "--protocol", "all", "--jump", "LOG", "--log-prefix", logPrefix, "-m", "comment", "--comment", handle)
if err := cc.iptables.run("create-instance-chains", cmd); err != nil {
return err
}
cmd = exec.Command(cc.iptables.iptablesBinPath, "--wait", "-A", loggingChain, "--jump", "RETURN", "-m", "comment", "--comment", handle)
if err := cc.iptables.run("create-instance-chains", cmd); err != nil {
return err
}
return nil
}
func (cc *InstanceChainCreator) Destroy(logger lager.Logger, instanceId string) error {
instanceChain := cc.iptables.InstanceChain(instanceId)
// Prune nat prerouting chain
cmd := exec.Command("sh", "-c", fmt.Sprintf(
`%s --wait --table nat -S %s 2> /dev/null | grep "\-j %s\b" | sed -e "s/-A/-D/" | xargs --no-run-if-empty --max-lines=1 %s --wait --table nat`,
cc.iptables.iptablesBinPath, cc.iptables.preroutingChain, instanceChain, cc.iptables.iptablesBinPath,
))
if err := cc.iptables.run("prune-prerouting-chain", cmd); err != nil {
return err
}
// Flush instance chain
if err := cc.iptables.FlushChain("nat", instanceChain); err != nil {
return err
}
// Delete nat instance chain
if err := cc.iptables.DeleteChain("nat", instanceChain); err != nil {
return err
}
// Prune forward chain
cmd = exec.Command("sh", "-c", fmt.Sprintf(
`%s --wait -S %s 2> /dev/null | grep "\-g %s\b" | sed -e "s/-A/-D/" | xargs --no-run-if-empty --max-lines=1 %s --wait`,
cc.iptables.iptablesBinPath, cc.iptables.forwardChain, instanceChain, cc.iptables.iptablesBinPath,
))
if err := cc.iptables.run("prune-forward-chain", cmd); err != nil {
return err
}
// Flush instance chain
cc.iptables.FlushChain("filter", instanceChain)
// delete instance chain
cc.iptables.DeleteChain("filter", instanceChain)
// delete the logging chain
instanceLoggingChain := fmt.Sprintf("%s-log", instanceChain)
cc.iptables.FlushChain("filter", instanceLoggingChain)
cc.iptables.DeleteChain("filter", instanceLoggingChain)
return nil
}