|
@@ -1,7 +1,13 @@
|
|
|
package ip
|
|
|
|
|
|
import (
|
|
|
+ "bytes"
|
|
|
+ "fmt"
|
|
|
+ log "github.com/coreos/flannel/Godeps/_workspace/src/github.com/golang/glog"
|
|
|
"os/exec"
|
|
|
+ "regexp"
|
|
|
+ "strconv"
|
|
|
+ "strings"
|
|
|
"syscall"
|
|
|
)
|
|
|
|
|
@@ -19,9 +25,19 @@ func NewIPTables() (*IPTables, error) {
|
|
|
}
|
|
|
|
|
|
func (ipt *IPTables) Exists(table string, args ...string) (bool, error) {
|
|
|
- cmd := append([]string{"-t", table, "-C"}, args...)
|
|
|
- err := exec.Command(ipt.path, cmd...).Run()
|
|
|
+ checkPresent, err := getIptablesHasCheckCommand()
|
|
|
+ if err != nil {
|
|
|
+ log.Warningf("Error checking iptables version, assuming version at least 1.4.11: %v\n", err)
|
|
|
+ checkPresent = true
|
|
|
+ }
|
|
|
|
|
|
+ if !checkPresent {
|
|
|
+ cmd := append([]string{"-A"}, args...)
|
|
|
+ return existsForOldIpTables(table, strings.Join(cmd, " "))
|
|
|
+ } else {
|
|
|
+ cmd := append([]string{"-t", table, "-C"}, args...)
|
|
|
+ err = exec.Command(ipt.path, cmd...).Run()
|
|
|
+ }
|
|
|
switch {
|
|
|
case err == nil:
|
|
|
return true, nil
|
|
@@ -66,3 +82,84 @@ func (ipt *IPTables) ClearChain(table, chain string) error {
|
|
|
return err
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+// Checks if iptables has the "-C" flag
|
|
|
+func getIptablesHasCheckCommand() (bool, error) {
|
|
|
+ vstring, err := getIptablesVersionString()
|
|
|
+ if err != nil {
|
|
|
+ return false, err
|
|
|
+ }
|
|
|
+
|
|
|
+ v1, v2, v3, err := extractIptablesVersion(vstring)
|
|
|
+ if err != nil {
|
|
|
+ return false, err
|
|
|
+ }
|
|
|
+
|
|
|
+ return iptablesHasCheckCommand(v1, v2, v3), nil
|
|
|
+}
|
|
|
+
|
|
|
+// getIptablesVersion returns the first three components of the iptables version.
|
|
|
+// e.g. "iptables v1.3.66" would return (1, 3, 66, nil)
|
|
|
+func extractIptablesVersion(str string) (int, int, int, error) {
|
|
|
+ versionMatcher := regexp.MustCompile("v([0-9]+)\\.([0-9]+)\\.([0-9]+)")
|
|
|
+ result := versionMatcher.FindStringSubmatch(str)
|
|
|
+ if result == nil {
|
|
|
+ return 0, 0, 0, fmt.Errorf("no iptables version found in string: %s", str)
|
|
|
+ }
|
|
|
+
|
|
|
+ v1, err := strconv.Atoi(result[1])
|
|
|
+ if err != nil {
|
|
|
+ return 0, 0, 0, err
|
|
|
+ }
|
|
|
+
|
|
|
+ v2, err := strconv.Atoi(result[2])
|
|
|
+ if err != nil {
|
|
|
+ return 0, 0, 0, err
|
|
|
+ }
|
|
|
+
|
|
|
+ v3, err := strconv.Atoi(result[3])
|
|
|
+ if err != nil {
|
|
|
+ return 0, 0, 0, err
|
|
|
+ }
|
|
|
+
|
|
|
+ return v1, v2, v3, nil
|
|
|
+}
|
|
|
+
|
|
|
+// Runs "iptables --version" to get the version string
|
|
|
+func getIptablesVersionString() (string, error) {
|
|
|
+ cmd := exec.Command("iptables", "--version")
|
|
|
+ var out bytes.Buffer
|
|
|
+ cmd.Stdout = &out
|
|
|
+ err := cmd.Run()
|
|
|
+ if err != nil {
|
|
|
+ return "", err
|
|
|
+ }
|
|
|
+ return out.String(), nil
|
|
|
+}
|
|
|
+
|
|
|
+// Checks if an iptables version is after 1.4.11, when --check was added
|
|
|
+func iptablesHasCheckCommand(v1 int, v2 int, v3 int) bool {
|
|
|
+ if v1 > 1 {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ if v1 == 1 && v2 > 4 {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ if v1 == 1 && v2 == 4 && v3 >= 11 {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ return false
|
|
|
+}
|
|
|
+
|
|
|
+// Checks if a rule specification exists for a table
|
|
|
+func existsForOldIpTables(table string, ruleSpec string) (bool, error) {
|
|
|
+ cmd := exec.Command("iptables", "-t", table, "-S")
|
|
|
+ var out bytes.Buffer
|
|
|
+ cmd.Stdout = &out
|
|
|
+ err := cmd.Run()
|
|
|
+ if err != nil {
|
|
|
+ return false, err
|
|
|
+ }
|
|
|
+ rules := out.String()
|
|
|
+ return strings.Contains(rules, ruleSpec), nil
|
|
|
+}
|