func (runner *runner) checkRuleUsingCheck(args []string) (bool, error) {
	out, err := runner.run(opCheckRule, args)
	if err == nil {
		return true, nil
	}
	if ee, ok := err.(utilexec.ExitError); ok {
		if ee.Exited() && ee.ExitStatus() == 1 {
			return false, nil
		}
	}
	return false, fmt.Errorf("error checking rule: %v: %s", err, out)
}
Executes the rule check using the "-C" flag
package iptables
import (
	"fmt"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
	utilexec "github.com/GoogleCloudPlatform/kubernetes/pkg/util/exec"
	"github.com/golang/glog"
)
type Interface interface {
	EnsureChain(table Table, chain Chain) (bool, error)
	FlushChain(table Table, chain Chain) error
	DeleteChain(table Table, chain Chain) error
	EnsureRule(table Table, chain Chain, args ...string) (bool, error)
	DeleteRule(table Table, chain Chain, args ...string) error
	IsIpv6() bool
}
type Protocol byte
const (
	ProtocolIpv4 Protocol = iota + 1
	ProtocolIpv6
)
type Table string
const (
	TableNAT Table = "nat"
)
type Chain string
const (
	ChainPostrouting Chain = "POSTROUTING"
	ChainPrerouting  Chain = "PREROUTING"
	ChainOutput      Chain = "OUTPUT"
)
type runner struct {
	mu       sync.Mutex
	exec     utilexec.Interface
	protocol Protocol
}
func New(exec utilexec.Interface, protocol Protocol) Interface {
	return &runner{exec: exec, protocol: protocol}
}
func (runner *runner) EnsureChain(table Table, chain Chain) (bool, error) {
	fullArgs := makeFullArgs(table, chain)
	runner.mu.Lock()
	defer runner.mu.Unlock()
	out, err := runner.run(opCreateChain, fullArgs)
	if err != nil {
		if ee, ok := err.(utilexec.ExitError); ok {
			if ee.Exited() && ee.ExitStatus() == 1 {
				return true, nil
			}
		}
		return false, fmt.Errorf("error creating chain %q: %v: %s", chain, err, out)
	}
	return false, nil
}
func (runner *runner) FlushChain(table Table, chain Chain) error {
	fullArgs := makeFullArgs(table, chain)
	runner.mu.Lock()
	defer runner.mu.Unlock()
	out, err := runner.run(opFlushChain, fullArgs)
	if err != nil {
		return fmt.Errorf("error flushing chain %q: %v: %s", chain, err, out)
	}
	return nil
}
func (runner *runner) DeleteChain(table Table, chain Chain) error {
	fullArgs := makeFullArgs(table, chain)
	runner.mu.Lock()
	defer runner.mu.Unlock()
	out, err := runner.run(opDeleteChain, fullArgs)
	if err != nil {
		return fmt.Errorf("error deleting chain %q: %v: %s", chain, err, out)
	}
	return nil
}
func (runner *runner) EnsureRule(table Table, chain Chain, args ...string) (bool, error) {
	fullArgs := makeFullArgs(table, chain, args...)
	runner.mu.Lock()
	defer runner.mu.Unlock()
	exists, err := runner.checkRule(table, chain, args...)
	if err != nil {
		return false, err
	}
	if exists {
		return true, nil
	}
	out, err := runner.run(opAppendRule, fullArgs)
	if err != nil {
		return false, fmt.Errorf("error appending rule: %v: %s", err, out)
	}
	return false, nil
}
func (runner *runner) DeleteRule(table Table, chain Chain, args ...string) error {
	fullArgs := makeFullArgs(table, chain, args...)
	runner.mu.Lock()
	defer runner.mu.Unlock()
	exists, err := runner.checkRule(table, chain, args...)
	if err != nil {
		return err
	}
	if !exists {
		return nil
	}
	out, err := runner.run(opDeleteRule, fullArgs)
	if err != nil {
		return fmt.Errorf("error deleting rule: %v: %s", err, out)
	}
	return nil
}
func (runner *runner) IsIpv6() bool {
	return runner.protocol == ProtocolIpv6
}
func (runner *runner) iptablesCommand() string {
	if runner.IsIpv6() {
		return "ip6tables"
	} else {
		return "iptables"
	}
}
func (runner *runner) run(op operation, args []string) ([]byte, error) {
	iptablesCmd := runner.iptablesCommand()
	fullArgs := append([]string{string(op)}, args...)
	glog.V(4).Infof("running iptables %s %v", string(op), args)
	return runner.exec.Command(iptablesCmd, fullArgs...).CombinedOutput()
}
func (runner *runner) checkRule(table Table, chain Chain, args ...string) (bool, error) {
	checkPresent, err := getIptablesHasCheckCommand(runner.exec)
	if err != nil {
		glog.Warning("Error checking iptables version, assuming version at least 1.4.11: %v", err)
		checkPresent = true
	}
	if checkPresent {
		return runner.checkRuleUsingCheck(makeFullArgs(table, chain, args...))
	} else {
		return runner.checkRuleWithoutCheck(table, chain, args...)
	}
}
func (runner *runner) checkRuleWithoutCheck(table Table, chain Chain, args ...string) (bool, error) {
	glog.V(1).Infof("running iptables-save -t %s", string(table))
	out, err := runner.exec.Command("iptables-save", "-t", string(table)).CombinedOutput()
	if err != nil {
		return false, fmt.Errorf("error checking rule: %v", err)
	}
	argsCopy := make([]string, len(args))
	copy(argsCopy, args)
	for i := range argsCopy {
		unquote(&argsCopy[i])
	}
	argset := util.NewStringSet(argsCopy...)
	for _, line := range strings.Split(string(out), "\n") {
		var fields = strings.Fields(line)
		if !strings.HasPrefix(line, fmt.Sprintf("-A %s", string(chain))) || len(fields) != len(args)+2 {
			continue
		}
		for i := range fields {
			unquote(&fields[i])
		}
		if util.NewStringSet(fields...).IsSuperset(argset) {
			return true, nil
		}
		glog.V(5).Infof("DBG: fields is not a superset of args: fields=%v  args=%v", fields, args)
	}
	return false, nil
}
func unquote(strp *string) {
	if len(*strp) >= 2 && (*strp)[0] == '"' && (*strp)[len(*strp)-1] == '"' {
		*strp = strings.TrimPrefix(strings.TrimSuffix(*strp, `"`), `"`)
	}
}