diff --git a/controller.go b/controller.go index a62d4fb980..aa75609256 100644 --- a/controller.go +++ b/controller.go @@ -719,6 +719,10 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ... } }() + c.Lock() + arrangeUserFilterRule() + c.Unlock() + // First store the endpoint count, then the network. To avoid to // end up with a datastore containing a network and not an epCnt, // in case of an ungraceful shutdown during this function call. diff --git a/drivers/bridge/setup_ip_tables.go b/drivers/bridge/setup_ip_tables.go index 1ac7fbc808..d087f0c547 100644 --- a/drivers/bridge/setup_ip_tables.go +++ b/drivers/bridge/setup_ip_tables.go @@ -52,7 +52,7 @@ func setupIPChains(config *configuration) (*iptables.ChainInfo, *iptables.ChainI return nil, nil, nil, fmt.Errorf("failed to create FILTER isolation chain: %v", err) } - if err := addReturnRule(IsolationChain); err != nil { + if err := iptables.AddReturnRule(IsolationChain); err != nil { return nil, nil, nil, err } @@ -116,7 +116,7 @@ func (n *bridgeNetwork) setupIPTables(config *networkConfiguration, i *bridgeInt } d.Lock() - err = ensureJumpRule("FORWARD", IsolationChain) + err = iptables.EnsureJumpRule("FORWARD", IsolationChain) d.Unlock() if err != nil { return err @@ -285,46 +285,6 @@ func setINC(iface1, iface2 string, enable bool) error { return nil } -func addReturnRule(chain string) error { - var ( - table = iptables.Filter - args = []string{"-j", "RETURN"} - ) - - if iptables.Exists(table, chain, args...) { - return nil - } - - err := iptables.RawCombinedOutput(append([]string{"-I", chain}, args...)...) - if err != nil { - return fmt.Errorf("unable to add return rule in %s chain: %s", chain, err.Error()) - } - - return nil -} - -// Ensure the jump rule is on top -func ensureJumpRule(fromChain, toChain string) error { - var ( - table = iptables.Filter - args = []string{"-j", toChain} - ) - - if iptables.Exists(table, fromChain, args...) { - err := iptables.RawCombinedOutput(append([]string{"-D", fromChain}, args...)...) - if err != nil { - return fmt.Errorf("unable to remove jump to %s rule in %s chain: %s", toChain, fromChain, err.Error()) - } - } - - err := iptables.RawCombinedOutput(append([]string{"-I", fromChain}, args...)...) - if err != nil { - return fmt.Errorf("unable to insert jump to %s rule in %s chain: %s", toChain, fromChain, err.Error()) - } - - return nil -} - func removeIPChains() { for _, chainInfo := range []iptables.ChainInfo{ {Name: DockerChain, Table: iptables.Nat}, diff --git a/iptables/iptables.go b/iptables/iptables.go index d4f4aa23dd..57edaff43f 100644 --- a/iptables/iptables.go +++ b/iptables/iptables.go @@ -465,3 +465,43 @@ func parseVersionNumbers(input string) (major, minor, micro int) { func supportsCOption(mj, mn, mc int) bool { return mj > 1 || (mj == 1 && (mn > 4 || (mn == 4 && mc >= 11))) } + +func AddReturnRule(chain string) error { + var ( + table = Filter + args = []string{"-j", "RETURN"} + ) + + if Exists(table, chain, args...) { + return nil + } + + err := RawCombinedOutput(append([]string{"-I", chain}, args...)...) + if err != nil { + return fmt.Errorf("unable to add return rule in %s chain: %s", chain, err.Error()) + } + + return nil +} + +// Ensure the jump rule is on top +func EnsureJumpRule(fromChain, toChain string) error { + var ( + table = Filter + args = []string{"-j", toChain} + ) + + if Exists(table, fromChain, args...) { + err := RawCombinedOutput(append([]string{"-D", fromChain}, args...)...) + if err != nil { + return fmt.Errorf("unable to remove jump to %s rule in %s chain: %s", toChain, fromChain, err.Error()) + } + } + + err := RawCombinedOutput(append([]string{"-I", fromChain}, args...)...) + if err != nil { + return fmt.Errorf("unable to insert jump to %s rule in %s chain: %s", toChain, fromChain, err.Error()) + } + + return nil +} diff --git a/service_linux.go b/service_linux.go index 2bcb6de5eb..164391eb04 100644 --- a/service_linux.go +++ b/service_linux.go @@ -260,6 +260,7 @@ func (sb *sandbox) rmLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*Po } } +const userChain = "DOCKER-USER" const ingressChain = "DOCKER-INGRESS" var ( @@ -449,6 +450,27 @@ func arrangeIngressFilterRule() { } } +// This chain allow users to configure firewall policies in a way that persists +// docker operations/restarts. Docker will not delete or modify any pre-existing +// rules from the DOCKER-USER filter chain. +func arrangeUserFilterRule() { + _, err := iptables.NewChain(userChain, iptables.Filter, false) + if err != nil { + logrus.Warnf("Failed to create %s chain: %v", userChain, err) + return + } + + if err = iptables.AddReturnRule(userChain); err != nil { + logrus.Warnf("Failed to add the RETURN rule for %s: %v", userChain, err) + return + } + + err = iptables.EnsureJumpRule("FORWARD", userChain) + if err != nil { + logrus.Warnf("Failed to create the jump rule for %s: %v", userChain, err) + } +} + func findOIFName(ip net.IP) (string, error) { nlh := ns.NlHandle() diff --git a/service_unsupported.go b/service_unsupported.go index 37b9828191..049e1065db 100644 --- a/service_unsupported.go +++ b/service_unsupported.go @@ -23,3 +23,6 @@ func (sb *sandbox) populateLoadbalancers(ep *endpoint) { func arrangeIngressFilterRule() { } + +func arrangeUserFilterRule() { +} diff --git a/service_windows.go b/service_windows.go index 6fe521ef99..264a75c782 100644 --- a/service_windows.go +++ b/service_windows.go @@ -13,3 +13,6 @@ func (sb *sandbox) populateLoadbalancers(ep *endpoint) { func arrangeIngressFilterRule() { } + +func arrangeUserFilterRule() { +}