github.com/cloudfoundry-attic/garden-linux@v0.333.2-candidate/linux_container/iptables_manager/nat.go (about)

     1  package iptables_manager
     2  
     3  import (
     4  	"bytes"
     5  	"io/ioutil"
     6  	"net"
     7  
     8  	"os/exec"
     9  
    10  	"fmt"
    11  
    12  	"github.com/cloudfoundry-incubator/garden-linux/sysconfig"
    13  	"github.com/cloudfoundry/gunk/command_runner"
    14  	"github.com/pivotal-golang/lager"
    15  )
    16  
    17  type natChain struct {
    18  	cfg    *sysconfig.IPTablesNATConfig
    19  	runner command_runner.CommandRunner
    20  	logger lager.Logger
    21  }
    22  
    23  func NewNATChain(cfg *sysconfig.IPTablesNATConfig, runner command_runner.CommandRunner, logger lager.Logger) *natChain {
    24  	return &natChain{
    25  		cfg:    cfg,
    26  		runner: runner,
    27  		logger: logger,
    28  	}
    29  }
    30  
    31  func (mgr *natChain) Setup(containerID, bridgeName string, ip net.IP, network *net.IPNet) error {
    32  	instanceChain := mgr.cfg.InstancePrefix + containerID
    33  
    34  	commands := []*exec.Cmd{
    35  		// Create nat instance chain
    36  		exec.Command("iptables", "--wait", "--table", "nat", "-N", instanceChain),
    37  		// Bind nat instance chain to nat prerouting chain
    38  		exec.Command("iptables", "--wait", "--table", "nat", "-A", mgr.cfg.PreroutingChain, "--jump", instanceChain),
    39  		// Enable NAT for traffic coming from containers
    40  		exec.Command("sh", "-c", fmt.Sprintf(
    41  			`(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`,
    42  			mgr.cfg.PostroutingChain, network.String(), mgr.cfg.PostroutingChain,
    43  			network.String(), network.String(),
    44  		)),
    45  	}
    46  
    47  	for _, cmd := range commands {
    48  		if err := mgr.runner.Run(cmd); err != nil {
    49  			buffer := &bytes.Buffer{}
    50  			cmd.Stderr = buffer
    51  			logger := mgr.logger.Session("setup", lager.Data{"cmd": cmd})
    52  			logger.Debug("starting")
    53  			if err := mgr.runner.Run(cmd); err != nil {
    54  				stderr, _ := ioutil.ReadAll(buffer)
    55  				logger.Error("failed", err, lager.Data{"stderr": string(stderr)})
    56  				return fmt.Errorf("iptables_manager: nat: %s", err)
    57  			}
    58  			logger.Debug("ended")
    59  		}
    60  	}
    61  
    62  	return nil
    63  }
    64  
    65  func (mgr *natChain) Teardown(containerID string) error {
    66  	instanceChain := mgr.cfg.InstancePrefix + containerID
    67  
    68  	commands := []*exec.Cmd{
    69  		// Prune nat prerouting chain
    70  		exec.Command("sh", "-c", fmt.Sprintf(
    71  			`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`,
    72  			mgr.cfg.PreroutingChain, instanceChain,
    73  		)),
    74  		// Flush nat instance chain
    75  		exec.Command("sh", "-c", fmt.Sprintf(`iptables --wait --table nat -F %s 2> /dev/null || true`, instanceChain)),
    76  		// Delete nat instance chain
    77  		exec.Command("sh", "-c", fmt.Sprintf(`iptables --wait --table nat -X %s 2> /dev/null || true`, instanceChain)),
    78  	}
    79  
    80  	for _, cmd := range commands {
    81  		buffer := &bytes.Buffer{}
    82  		cmd.Stderr = buffer
    83  		logger := mgr.logger.Session("teardown", lager.Data{"cmd": cmd})
    84  		logger.Debug("starting")
    85  		if err := mgr.runner.Run(cmd); err != nil {
    86  			stderr, _ := ioutil.ReadAll(buffer)
    87  			logger.Error("failed", err, lager.Data{"stderr": string(stderr)})
    88  			return fmt.Errorf("iptables_manager: nat: %s", err)
    89  		}
    90  		logger.Debug("ended")
    91  	}
    92  
    93  	return nil
    94  }