|
@@ -8,7 +8,6 @@ import (
|
|
|
"fmt"
|
|
|
"net"
|
|
|
"os/exec"
|
|
|
- "regexp"
|
|
|
"strconv"
|
|
|
"strings"
|
|
|
"sync"
|
|
@@ -57,7 +56,6 @@ var (
|
|
|
iptablesPath string
|
|
|
ip6tablesPath string
|
|
|
supportsXlock = false
|
|
|
- supportsCOpt = false
|
|
|
xLockWaitMsg = "Another app is currently holding the xtables lock"
|
|
|
// used to lock iptables commands if xtables lock is not supported
|
|
|
bestEffortLock sync.Mutex
|
|
@@ -89,19 +87,27 @@ func (e ChainError) Error() string {
|
|
|
return fmt.Sprintf("Error iptables %s: %s", e.Chain, string(e.Output))
|
|
|
}
|
|
|
|
|
|
-func probe() {
|
|
|
+func detectIptables() {
|
|
|
path, err := exec.LookPath("iptables")
|
|
|
if err != nil {
|
|
|
- logrus.Warnf("Failed to find iptables: %v", err)
|
|
|
+ logrus.WithError(err).Warnf("failed to find iptables")
|
|
|
return
|
|
|
}
|
|
|
- if out, err := exec.Command(path, "--wait", "-t", "nat", "-L", "-n").CombinedOutput(); err != nil {
|
|
|
- logrus.Warnf("Running iptables --wait -t nat -L -n failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
|
|
|
+ iptablesPath = path
|
|
|
+
|
|
|
+ // The --wait flag was added in iptables v1.6.0.
|
|
|
+ // TODO remove this check once we drop support for CentOS/RHEL 7, which uses an older version of iptables
|
|
|
+ if out, err := exec.Command(path, "--wait", "-L", "-n").CombinedOutput(); err != nil {
|
|
|
+ logrus.WithError(err).Infof("unable to detect if iptables supports xlock: 'iptables --wait -L -n': `%s`", strings.TrimSpace(string(out)))
|
|
|
+ } else {
|
|
|
+ supportsXlock = true
|
|
|
}
|
|
|
- _, err = exec.LookPath("ip6tables")
|
|
|
+
|
|
|
+ path, err = exec.LookPath("ip6tables")
|
|
|
if err != nil {
|
|
|
- logrus.Warnf("Failed to find ip6tables: %v", err)
|
|
|
- return
|
|
|
+ logrus.WithError(err).Warnf("unable to find ip6tables")
|
|
|
+ } else {
|
|
|
+ ip6tablesPath = path
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -113,32 +119,11 @@ func initFirewalld() {
|
|
|
return
|
|
|
}
|
|
|
if err := FirewalldInit(); err != nil {
|
|
|
- logrus.Debugf("Fail to initialize firewalld: %v, using raw iptables instead", err)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-func detectIptables() {
|
|
|
- path, err := exec.LookPath("iptables")
|
|
|
- if err != nil {
|
|
|
- return
|
|
|
- }
|
|
|
- iptablesPath = path
|
|
|
- path, err = exec.LookPath("ip6tables")
|
|
|
- if err != nil {
|
|
|
- return
|
|
|
+ logrus.WithError(err).Debugf("unable to initialize firewalld; using raw iptables instead")
|
|
|
}
|
|
|
- ip6tablesPath = path
|
|
|
- supportsXlock = exec.Command(iptablesPath, "--wait", "-L", "-n").Run() == nil
|
|
|
- mj, mn, mc, err := GetVersion()
|
|
|
- if err != nil {
|
|
|
- logrus.Warnf("Failed to read iptables version: %v", err)
|
|
|
- return
|
|
|
- }
|
|
|
- supportsCOpt = supportsCOption(mj, mn, mc)
|
|
|
}
|
|
|
|
|
|
func initDependencies() {
|
|
|
- probe()
|
|
|
initFirewalld()
|
|
|
detectIptables()
|
|
|
}
|
|
@@ -476,26 +461,9 @@ func (iptable IPTable) exists(native bool, table Table, chain string, rule ...st
|
|
|
return false
|
|
|
}
|
|
|
|
|
|
- if supportsCOpt {
|
|
|
- // if exit status is 0 then return true, the rule exists
|
|
|
- _, err := f(append([]string{"-t", string(table), "-C", chain}, rule...)...)
|
|
|
- return err == nil
|
|
|
- }
|
|
|
-
|
|
|
- // parse "iptables -S" for the rule (it checks rules in a specific chain
|
|
|
- // in a specific table and it is very unreliable)
|
|
|
- return iptable.existsRaw(table, chain, rule...)
|
|
|
-}
|
|
|
-
|
|
|
-func (iptable IPTable) existsRaw(table Table, chain string, rule ...string) bool {
|
|
|
- path := iptablesPath
|
|
|
- if iptable.Version == IPv6 {
|
|
|
- path = ip6tablesPath
|
|
|
- }
|
|
|
- ruleString := fmt.Sprintf("%s %s\n", chain, strings.Join(rule, " "))
|
|
|
- existingRules, _ := exec.Command(path, "-t", string(table), "-S", chain).Output()
|
|
|
-
|
|
|
- return strings.Contains(string(existingRules), ruleString)
|
|
|
+ // if exit status is 0 then return true, the rule exists
|
|
|
+ _, err := f(append([]string{"-t", string(table), "-C", chain}, rule...)...)
|
|
|
+ return err == nil
|
|
|
}
|
|
|
|
|
|
// Maximum duration that an iptables operation can take
|
|
@@ -549,6 +517,9 @@ func (iptable IPTable) raw(args ...string) ([]byte, error) {
|
|
|
path := iptablesPath
|
|
|
commandName := "iptables"
|
|
|
if iptable.Version == IPv6 {
|
|
|
+ if ip6tablesPath == "" {
|
|
|
+ return nil, fmt.Errorf("ip6tables is missing")
|
|
|
+ }
|
|
|
path = ip6tablesPath
|
|
|
commandName = "ip6tables"
|
|
|
}
|
|
@@ -590,15 +561,6 @@ func (iptable IPTable) ExistChain(chain string, table Table) bool {
|
|
|
return false
|
|
|
}
|
|
|
|
|
|
-// GetVersion reads the iptables version numbers during initialization
|
|
|
-func GetVersion() (major, minor, micro int, err error) {
|
|
|
- out, err := exec.Command(iptablesPath, "--version").CombinedOutput()
|
|
|
- if err == nil {
|
|
|
- major, minor, micro = parseVersionNumbers(string(out))
|
|
|
- }
|
|
|
- return
|
|
|
-}
|
|
|
-
|
|
|
// SetDefaultPolicy sets the passed default policy for the table/chain
|
|
|
func (iptable IPTable) SetDefaultPolicy(table Table, chain string, policy Policy) error {
|
|
|
if err := iptable.RawCombinedOutput("-t", string(table), "-P", chain, string(policy)); err != nil {
|
|
@@ -607,19 +569,6 @@ func (iptable IPTable) SetDefaultPolicy(table Table, chain string, policy Policy
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
-func parseVersionNumbers(input string) (major, minor, micro int) {
|
|
|
- re := regexp.MustCompile(`v\d*.\d*.\d*`)
|
|
|
- line := re.FindString(input)
|
|
|
- fmt.Sscanf(line, "v%d.%d.%d", &major, &minor, µ)
|
|
|
- return
|
|
|
-}
|
|
|
-
|
|
|
-// iptables -C, --check option was added in v.1.4.11
|
|
|
-// http://ftp.netfilter.org/pub/iptables/changes-iptables-1.4.11.txt
|
|
|
-func supportsCOption(mj, mn, mc int) bool {
|
|
|
- return mj > 1 || (mj == 1 && (mn > 4 || (mn == 4 && mc >= 11)))
|
|
|
-}
|
|
|
-
|
|
|
// AddReturnRule adds a return rule for the chain in the filter table
|
|
|
func (iptable IPTable) AddReturnRule(chain string) error {
|
|
|
var (
|