|
@@ -5,6 +5,7 @@ import (
|
|
"fmt"
|
|
"fmt"
|
|
"net"
|
|
"net"
|
|
"os/exec"
|
|
"os/exec"
|
|
|
|
+ "regexp"
|
|
"strconv"
|
|
"strconv"
|
|
"strings"
|
|
"strings"
|
|
"sync"
|
|
"sync"
|
|
@@ -36,6 +37,7 @@ const (
|
|
var (
|
|
var (
|
|
iptablesPath string
|
|
iptablesPath string
|
|
supportsXlock = false
|
|
supportsXlock = false
|
|
|
|
+ supportsCOpt = false
|
|
// 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
|
|
// ErrIptablesNotFound is returned when the rule is not found.
|
|
// ErrIptablesNotFound is returned when the rule is not found.
|
|
@@ -60,7 +62,6 @@ func (e ChainError) Error() string {
|
|
}
|
|
}
|
|
|
|
|
|
func initCheck() error {
|
|
func initCheck() error {
|
|
-
|
|
|
|
if iptablesPath == "" {
|
|
if iptablesPath == "" {
|
|
path, err := exec.LookPath("iptables")
|
|
path, err := exec.LookPath("iptables")
|
|
if err != nil {
|
|
if err != nil {
|
|
@@ -68,6 +69,12 @@ func initCheck() error {
|
|
}
|
|
}
|
|
iptablesPath = path
|
|
iptablesPath = path
|
|
supportsXlock = exec.Command(iptablesPath, "--wait", "-L", "-n").Run() == nil
|
|
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 nil
|
|
|
|
+ }
|
|
|
|
+ supportsCOpt = supportsCOption(mj, mn, mc)
|
|
}
|
|
}
|
|
return nil
|
|
return nil
|
|
}
|
|
}
|
|
@@ -299,20 +306,19 @@ func Exists(table Table, chain string, rule ...string) bool {
|
|
table = Filter
|
|
table = Filter
|
|
}
|
|
}
|
|
|
|
|
|
- // iptables -C, --check option was added in v.1.4.11
|
|
|
|
- // http://ftp.netfilter.org/pub/iptables/changes-iptables-1.4.11.txt
|
|
|
|
-
|
|
|
|
- // try -C
|
|
|
|
- // if exit status is 0 then return true, the rule exists
|
|
|
|
- if _, err := Raw(append([]string{
|
|
|
|
- "-t", string(table), "-C", chain}, rule...)...); err == nil {
|
|
|
|
- return true
|
|
|
|
|
|
+ if supportsCOpt {
|
|
|
|
+ // if exit status is 0 then return true, the rule exists
|
|
|
|
+ _, err := Raw(append([]string{"-t", string(table), "-C", chain}, rule...)...)
|
|
|
|
+ return err == nil
|
|
}
|
|
}
|
|
|
|
|
|
- // parse "iptables -S" for the rule (this checks rules in a specific chain
|
|
|
|
- // in a specific table)
|
|
|
|
- ruleString := strings.Join(rule, " ")
|
|
|
|
- ruleString = chain + " " + ruleString
|
|
|
|
|
|
+ // parse "iptables -S" for the rule (it checks rules in a specific chain
|
|
|
|
+ // in a specific table and it is very unreliable)
|
|
|
|
+ return existsRaw(table, chain, rule...)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func existsRaw(table Table, chain string, rule ...string) bool {
|
|
|
|
+ ruleString := fmt.Sprintf("%s %s\n", chain, strings.Join(rule, " "))
|
|
existingRules, _ := exec.Command(iptablesPath, "-t", string(table), "-S", chain).Output()
|
|
existingRules, _ := exec.Command(iptablesPath, "-t", string(table), "-S", chain).Output()
|
|
|
|
|
|
return strings.Contains(string(existingRules), ruleString)
|
|
return strings.Contains(string(existingRules), ruleString)
|
|
@@ -380,3 +386,25 @@ func ExistChain(chain string, table Table) bool {
|
|
}
|
|
}
|
|
return false
|
|
return false
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+// GetVersion reads the iptables version numbers
|
|
|
|
+func GetVersion() (major, minor, micro int, err error) {
|
|
|
|
+ out, err := Raw("--version")
|
|
|
|
+ if err == nil {
|
|
|
|
+ major, minor, micro = parseVersionNumbers(string(out))
|
|
|
|
+ }
|
|
|
|
+ return
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+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)))
|
|
|
|
+}
|