This repository has been archived by the owner on Jan 25, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 37
/
nat.go
94 lines (80 loc) · 2.95 KB
/
nat.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
package iptables_manager
import (
"bytes"
"io/ioutil"
"net"
"os/exec"
"fmt"
"github.com/cloudfoundry-incubator/garden-linux/sysconfig"
"github.com/cloudfoundry/gunk/command_runner"
"github.com/pivotal-golang/lager"
)
type natChain struct {
cfg *sysconfig.IPTablesNATConfig
runner command_runner.CommandRunner
logger lager.Logger
}
func NewNATChain(cfg *sysconfig.IPTablesNATConfig, runner command_runner.CommandRunner, logger lager.Logger) *natChain {
return &natChain{
cfg: cfg,
runner: runner,
logger: logger,
}
}
func (mgr *natChain) Setup(containerID, bridgeName string, ip net.IP, network *net.IPNet) error {
instanceChain := mgr.cfg.InstancePrefix + containerID
commands := []*exec.Cmd{
// Create nat instance chain
exec.Command("iptables", "--wait", "--table", "nat", "-N", instanceChain),
// Bind nat instance chain to nat prerouting chain
exec.Command("iptables", "--wait", "--table", "nat", "-A", mgr.cfg.PreroutingChain, "--jump", instanceChain),
// Enable NAT for traffic coming from containers
exec.Command("sh", "-c", fmt.Sprintf(
`(iptables --wait --table nat -S %s | grep "\-j MASQUERADE\b" | grep -q -F -- "-s %s") || iptables --wait --table nat -A %s --source %s ! --destination %s --jump MASQUERADE`,
mgr.cfg.PostroutingChain, network.String(), mgr.cfg.PostroutingChain,
network.String(), network.String(),
)),
}
for _, cmd := range commands {
if err := mgr.runner.Run(cmd); err != nil {
buffer := &bytes.Buffer{}
cmd.Stderr = buffer
logger := mgr.logger.Session("setup", lager.Data{"cmd": cmd})
logger.Debug("starting")
if err := mgr.runner.Run(cmd); err != nil {
stderr, _ := ioutil.ReadAll(buffer)
logger.Error("failed", err, lager.Data{"stderr": string(stderr)})
return fmt.Errorf("iptables_manager: nat: %s", err)
}
logger.Debug("ended")
}
}
return nil
}
func (mgr *natChain) Teardown(containerID string) error {
instanceChain := mgr.cfg.InstancePrefix + containerID
commands := []*exec.Cmd{
// Prune nat prerouting chain
exec.Command("sh", "-c", fmt.Sprintf(
`iptables --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 iptables --wait --table nat`,
mgr.cfg.PreroutingChain, instanceChain,
)),
// Flush nat instance chain
exec.Command("sh", "-c", fmt.Sprintf(`iptables --wait --table nat -F %s 2> /dev/null || true`, instanceChain)),
// Delete nat instance chain
exec.Command("sh", "-c", fmt.Sprintf(`iptables --wait --table nat -X %s 2> /dev/null || true`, instanceChain)),
}
for _, cmd := range commands {
buffer := &bytes.Buffer{}
cmd.Stderr = buffer
logger := mgr.logger.Session("teardown", lager.Data{"cmd": cmd})
logger.Debug("starting")
if err := mgr.runner.Run(cmd); err != nil {
stderr, _ := ioutil.ReadAll(buffer)
logger.Error("failed", err, lager.Data{"stderr": string(stderr)})
return fmt.Errorf("iptables_manager: nat: %s", err)
}
logger.Debug("ended")
}
return nil
}