فهرست منبع

Always use iptables -C to look for rules

iptables -C flag was introduced in v1.4.11, which was released ten
years ago. Thus, there're no more Linux distributions supported by
Docker using this version. As such, this commit removes the old way of
checking if an iptables rule exists (by using substring matching).

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
Albin Kerouanton 3 سال پیش
والد
کامیت
799cc143c9
2فایلهای تغییر یافته به همراه7 افزوده شده و 82 حذف شده
  1. 5 51
      libnetwork/iptables/iptables.go
  2. 2 31
      libnetwork/iptables/iptables_test.go

+ 5 - 51
libnetwork/iptables/iptables.go

@@ -8,7 +8,6 @@ import (
 	"fmt"
 	"fmt"
 	"net"
 	"net"
 	"os/exec"
 	"os/exec"
-	"regexp"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 	"sync"
 	"sync"
@@ -56,7 +55,6 @@ var (
 	iptablesPath  string
 	iptablesPath  string
 	ip6tablesPath string
 	ip6tablesPath string
 	supportsXlock = false
 	supportsXlock = false
-	supportsCOpt  = false
 	xLockWaitMsg  = "Another app is currently holding the xtables lock"
 	xLockWaitMsg  = "Another app is currently holding the xtables lock"
 	// used to lock iptables commands if xtables lock is not supported
 	// used to lock iptables commands if xtables lock is not supported
 	bestEffortLock sync.Mutex
 	bestEffortLock sync.Mutex
@@ -96,19 +94,14 @@ func detectIptables() {
 	}
 	}
 	iptablesPath = path
 	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 {
 	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)))
 		logrus.WithError(err).Infof("unable to detect if iptables supports xlock: 'iptables --wait -L -n': `%s`", strings.TrimSpace(string(out)))
 	} else {
 	} else {
 		supportsXlock = true
 		supportsXlock = true
 	}
 	}
 
 
-	mj, mn, mc, err := GetVersion()
-	if err != nil {
-		logrus.Warnf("Failed to read iptables version: %v", err)
-	} else {
-		supportsCOpt = supportsCOption(mj, mn, mc)
-	}
-
 	path, err = exec.LookPath("ip6tables")
 	path, err = exec.LookPath("ip6tables")
 	if err != nil {
 	if err != nil {
 		logrus.WithError(err).Warnf("unable to find ip6tables")
 		logrus.WithError(err).Warnf("unable to find ip6tables")
@@ -463,26 +456,9 @@ func (iptable IPTable) exists(native bool, table Table, chain string, rule ...st
 		return false
 		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
 // Maximum duration that an iptables operation can take
@@ -580,15 +556,6 @@ func (iptable IPTable) ExistChain(chain string, table Table) bool {
 	return false
 	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
 // SetDefaultPolicy sets the passed default policy for the table/chain
 func (iptable IPTable) SetDefaultPolicy(table Table, chain string, policy Policy) error {
 func (iptable IPTable) SetDefaultPolicy(table Table, chain string, policy Policy) error {
 	if err := iptable.RawCombinedOutput("-t", string(table), "-P", chain, string(policy)); err != nil {
 	if err := iptable.RawCombinedOutput("-t", string(table), "-P", chain, string(policy)); err != nil {
@@ -597,19 +564,6 @@ func (iptable IPTable) SetDefaultPolicy(table Table, chain string, policy Policy
 	return nil
 	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, &micro)
-	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
 // AddReturnRule adds a return rule for the chain in the filter table
 func (iptable IPTable) AddReturnRule(chain string) error {
 func (iptable IPTable) AddReturnRule(chain string) error {
 	var (
 	var (

+ 2 - 31
libnetwork/iptables/iptables_test.go

@@ -284,44 +284,15 @@ func TestExistsRaw(t *testing.T) {
 		if err != nil {
 		if err != nil {
 			t.Fatalf("i=%d, err: %v", i, err)
 			t.Fatalf("i=%d, err: %v", i, err)
 		}
 		}
-		if !iptable.existsRaw(Filter, testChain1, r.rule...) {
+		if !iptable.exists(true, Filter, testChain1, r.rule...) {
 			t.Fatalf("Failed to detect rule. i=%d", i)
 			t.Fatalf("Failed to detect rule. i=%d", i)
 		}
 		}
 		// Truncate the rule
 		// Truncate the rule
 		trg := r.rule[len(r.rule)-1]
 		trg := r.rule[len(r.rule)-1]
 		trg = trg[:len(trg)-2]
 		trg = trg[:len(trg)-2]
 		r.rule[len(r.rule)-1] = trg
 		r.rule[len(r.rule)-1] = trg
-		if iptable.existsRaw(Filter, testChain1, r.rule...) {
+		if iptable.exists(true, Filter, testChain1, r.rule...) {
 			t.Fatalf("Invalid detection. i=%d", i)
 			t.Fatalf("Invalid detection. i=%d", i)
 		}
 		}
 	}
 	}
 }
 }
-
-func TestGetVersion(t *testing.T) {
-	mj, mn, mc := parseVersionNumbers("iptables v1.4.19.1-alpha")
-	if mj != 1 || mn != 4 || mc != 19 {
-		t.Fatal("Failed to parse version numbers")
-	}
-}
-
-func TestSupportsCOption(t *testing.T) {
-	input := []struct {
-		mj int
-		mn int
-		mc int
-		ok bool
-	}{
-		{1, 4, 11, true},
-		{1, 4, 12, true},
-		{1, 5, 0, true},
-		{0, 4, 11, false},
-		{0, 5, 12, false},
-		{1, 3, 12, false},
-		{1, 4, 10, false},
-	}
-	for ind, inp := range input {
-		if inp.ok != supportsCOption(inp.mj, inp.mn, inp.mc) {
-			t.Fatalf("Incorrect check: %d", ind)
-		}
-	}
-}