diff --git a/libnetwork/pkg/iptables/firewalld.go b/libnetwork/pkg/iptables/firewalld.go index ee3fac5a7b..f2b57ae650 100644 --- a/libnetwork/pkg/iptables/firewalld.go +++ b/libnetwork/pkg/iptables/firewalld.go @@ -38,19 +38,18 @@ var ( ) // FirewalldInit initializes firewalld management code. -func FirewalldInit() { +func FirewalldInit() error { var err error - connection, err = newConnection() - - if err != nil { - logrus.Errorf("Failed to connect to D-Bus system bus: %s", err) + if connection, err = newConnection(); err != nil { + return fmt.Errorf("Failed to connect to D-Bus system bus: %v", err) } if connection != nil { go signalHandler() } firewalldRunning = checkRunning() + return nil } // New() establishes a connection to the system bus. @@ -151,7 +150,6 @@ func checkRunning() bool { logrus.Infof("Firewalld running: %t", err == nil) return err == nil } - logrus.Info("Firewalld not running") return false } @@ -160,10 +158,8 @@ func Passthrough(ipv IPV, args ...string) ([]byte, error) { var output string logrus.Debugf("Firewalld passthrough: %s, %s", ipv, args) - err := connection.sysobj.Call(dbusInterface+".direct.passthrough", 0, ipv, args).Store(&output) - if output != "" { - logrus.Debugf("passthrough output: %s", output) + if err := connection.sysobj.Call(dbusInterface+".direct.passthrough", 0, ipv, args).Store(&output); err != nil { + return nil, err } - - return []byte(output), err + return []byte(output), nil } diff --git a/libnetwork/pkg/iptables/iptables.go b/libnetwork/pkg/iptables/iptables.go index 77e117359c..75c539a815 100644 --- a/libnetwork/pkg/iptables/iptables.go +++ b/libnetwork/pkg/iptables/iptables.go @@ -8,6 +8,7 @@ import ( "regexp" "strconv" "strings" + "sync" "github.com/Sirupsen/logrus" ) @@ -36,6 +37,8 @@ const ( var ( iptablesPath string supportsXlock = false + // used to lock iptables commands if xtables lock is not supported + bestEffortLock sync.Mutex //ErrIptablesNotFound is returned when the rule is not found. ErrIptablesNotFound = errors.New("Iptables not found") ) @@ -303,6 +306,9 @@ func Raw(args ...string) ([]byte, error) { } if supportsXlock { args = append([]string{"--wait"}, args...) + } else { + bestEffortLock.Lock() + defer bestEffortLock.Unlock() } logrus.Debugf("%s, %v", iptablesPath, args) diff --git a/libnetwork/pkg/iptables/iptables_test.go b/libnetwork/pkg/iptables/iptables_test.go index f5f79c7096..594493a3ab 100644 --- a/libnetwork/pkg/iptables/iptables_test.go +++ b/libnetwork/pkg/iptables/iptables_test.go @@ -5,6 +5,7 @@ import ( "os/exec" "strconv" "strings" + "sync" "testing" _ "github.com/docker/libnetwork/netutils" @@ -171,6 +172,45 @@ func TestOutput(t *testing.T) { } } +func TestConcurrencyWithWait(t *testing.T) { + RunConcurrencyTest(t, true) +} + +func TestConcurrencyNoWait(t *testing.T) { + RunConcurrencyTest(t, false) +} + +// Runs 10 concurrent rule additions. This will fail if iptables +// is actually invoked simultaneously without --wait. +// Note that if iptables does not support the xtable lock on this +// system, then allowXlock has no effect -- it will always be off. +func RunConcurrencyTest(t *testing.T, allowXlock bool) { + var wg sync.WaitGroup + + if !allowXlock && supportsXlock { + supportsXlock = false + defer func() { supportsXlock = true }() + } + + ip := net.ParseIP("192.168.1.1") + port := 1234 + dstAddr := "172.17.0.1" + dstPort := 4321 + proto := "tcp" + + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + defer wg.Done() + err := natChain.Forward(Append, ip, port, proto, dstAddr, dstPort) + if err != nil { + t.Fatal(err) + } + }() + } + wg.Wait() +} + func TestCleanup(t *testing.T) { var err error var rules []byte diff --git a/libnetwork/pkg/resolvconf/dns/resolvconf.go b/libnetwork/pkg/resolvconf/dns/resolvconf.go new file mode 100644 index 0000000000..d581a1913d --- /dev/null +++ b/libnetwork/pkg/resolvconf/dns/resolvconf.go @@ -0,0 +1,17 @@ +package dns + +import ( + "regexp" +) + +// IPLocalhost is a regex patter for localhost IP address range. +const IPLocalhost = `((127\.([0-9]{1,3}.){2}[0-9]{1,3})|(::1))` + +var localhostIPRegexp = regexp.MustCompile(IPLocalhost) + +// IsLocalhost returns true if ip matches the localhost IP regular expression. +// Used for determining if nameserver settings are being passed which are +// localhost addresses +func IsLocalhost(ip string) bool { + return localhostIPRegexp.MatchString(ip) +} diff --git a/libnetwork/pkg/resolvconf/resolvconf.go b/libnetwork/pkg/resolvconf/resolvconf.go index d491fddad2..ae6c4e676d 100644 --- a/libnetwork/pkg/resolvconf/resolvconf.go +++ b/libnetwork/pkg/resolvconf/resolvconf.go @@ -10,6 +10,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/ioutils" + "github.com/docker/libnetwork/pkg/resolvconf/dns" ) var ( @@ -24,10 +25,8 @@ var ( // For readability and sufficiency for Docker purposes this seemed more reasonable than a // 1000+ character regexp with exact and complete IPv6 validation ipv6Address = `([0-9A-Fa-f]{0,4}:){2,7}([0-9A-Fa-f]{0,4})` - ipLocalhost = `((127\.([0-9]{1,3}.){2}[0-9]{1,3})|(::1))` - localhostIPRegexp = regexp.MustCompile(ipLocalhost) - localhostNSRegexp = regexp.MustCompile(`(?m)^nameserver\s+` + ipLocalhost + `\s*\n*`) + localhostNSRegexp = regexp.MustCompile(`(?m)^nameserver\s+` + dns.IPLocalhost + `\s*\n*`) nsIPv6Regexp = regexp.MustCompile(`(?m)^nameserver\s+` + ipv6Address + `\s*\n*`) nsRegexp = regexp.MustCompile(`^\s*nameserver\s*((` + ipv4Address + `)|(` + ipv6Address + `))\s*$`) searchRegexp = regexp.MustCompile(`^\s*search\s*(([^\s]+\s*)*)$`) @@ -128,13 +127,6 @@ func getLines(input []byte, commentMarker []byte) [][]byte { return output } -// IsLocalhost returns true if ip matches the localhost IP regular expression. -// Used for determining if nameserver settings are being passed which are -// localhost addresses -func IsLocalhost(ip string) bool { - return localhostIPRegexp.MatchString(ip) -} - // GetNameservers returns nameservers (if any) listed in /etc/resolv.conf func GetNameservers(resolvConf []byte) []string { nameservers := []string{}