From 56175949d5025fedd099212662c3ce64bf679fbd Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Wed, 8 Jul 2020 16:12:22 +0200 Subject: [PATCH] vendor: libnetwork 9e99af28df21367340c95a3863e31808d689c92a full diff: https://github.com/docker/libnetwork/compare/2e24aed516bd5c836e11378bb457dd612aa868ed...9e99af28df21367340c95a3863e31808d689c92a - docker/libnetwork#2548 Add docker interfaces to firewalld docker zone - fixes docker/for-linux#957 DNS Not Resolving under Network [CentOS8] - fixes docker/libnetwork#2496 Port Forwarding does not work on RHEL 8 with Firewalld running with FirewallBackend=nftables - store.getNetworksFromStore() remove unused error return - docker/libnetwork#2554 Fix 'failed to get network during CreateEndpoint' - fixes/addresses docker/for-linux#888 failed to get network during CreateEndpoint - docker/libnetwork#2558 [master] bridge: disable IPv6 router advertisements - docker/libnetwork#2563 log error instead if disabling IPv6 router advertisement failed - fixes docker/for-linux#1033 Shouldn't be fatal: Unable to disable IPv6 router advertisement: open /proc/sys/net/ipv6/conf/docker0/accept_ra: read-only file system Signed-off-by: Sebastiaan van Stijn Upstream-commit: 219e7e7ddcf5f0314578d2a517fc0832f03622c1 Component: engine --- .../hack/dockerfile/install/proxy.installer | 2 +- components/engine/vendor.conf | 2 +- .../docker/libnetwork/controller.go | 7 +- .../libnetwork/drivers/bridge/bridge.go | 6 + .../libnetwork/drivers/bridge/setup_device.go | 19 +++ .../docker/libnetwork/iptables/firewalld.go | 156 ++++++++++++++++-- .../docker/libnetwork/iptables/iptables.go | 13 ++ .../github.com/docker/libnetwork/network.go | 3 +- .../github.com/docker/libnetwork/store.go | 29 +--- 9 files changed, 197 insertions(+), 40 deletions(-) diff --git a/components/engine/hack/dockerfile/install/proxy.installer b/components/engine/hack/dockerfile/install/proxy.installer index 91203661431..f7caa1bfb9f 100755 --- a/components/engine/hack/dockerfile/install/proxy.installer +++ b/components/engine/hack/dockerfile/install/proxy.installer @@ -3,7 +3,7 @@ # LIBNETWORK_COMMIT is used to build the docker-userland-proxy binary. When # updating the binary version, consider updating github.com/docker/libnetwork # in vendor.conf accordingly -: "${LIBNETWORK_COMMIT:=2e24aed516bd5c836e11378bb457dd612aa868ed}" +: "${LIBNETWORK_COMMIT:=9e99af28df21367340c95a3863e31808d689c92a}" install_proxy() { case "$1" in diff --git a/components/engine/vendor.conf b/components/engine/vendor.conf index a1d0d03cec0..015bf3f54c6 100644 --- a/components/engine/vendor.conf +++ b/components/engine/vendor.conf @@ -41,7 +41,7 @@ github.com/grpc-ecosystem/go-grpc-middleware 3c51f7f332123e8be5a157c0802a # libnetwork # When updating, also update LIBNETWORK_COMMIT in hack/dockerfile/install/proxy.installer accordingly -github.com/docker/libnetwork 2e24aed516bd5c836e11378bb457dd612aa868ed +github.com/docker/libnetwork 9e99af28df21367340c95a3863e31808d689c92a github.com/docker/go-events e31b211e4f1cd09aa76fe4ac244571fab96ae47f github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80 github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec diff --git a/components/engine/vendor/github.com/docker/libnetwork/controller.go b/components/engine/vendor/github.com/docker/libnetwork/controller.go index 642198524d1..53f779aa6c6 100644 --- a/components/engine/vendor/github.com/docker/libnetwork/controller.go +++ b/components/engine/vendor/github.com/docker/libnetwork/controller.go @@ -1020,12 +1020,7 @@ func (c *controller) addNetwork(n *network) error { func (c *controller) Networks() []Network { var list []Network - networks, err := c.getNetworksFromStore() - if err != nil { - logrus.Error(err) - } - - for _, n := range networks { + for _, n := range c.getNetworksFromStore() { if n.inDelete { continue } diff --git a/components/engine/vendor/github.com/docker/libnetwork/drivers/bridge/bridge.go b/components/engine/vendor/github.com/docker/libnetwork/drivers/bridge/bridge.go index 734390c1651..88fbafaea35 100644 --- a/components/engine/vendor/github.com/docker/libnetwork/drivers/bridge/bridge.go +++ b/components/engine/vendor/github.com/docker/libnetwork/drivers/bridge/bridge.go @@ -689,6 +689,12 @@ func (d *driver) createNetwork(config *networkConfiguration) (err error) { bridgeAlreadyExists := bridgeIface.exists() if !bridgeAlreadyExists { bridgeSetup.queueStep(setupDevice) + bridgeSetup.queueStep(setupDefaultSysctl) + } + + // For the default bridge, set expected sysctls + if config.DefaultBridge { + bridgeSetup.queueStep(setupDefaultSysctl) } // Even if a bridge exists try to setup IPv4. diff --git a/components/engine/vendor/github.com/docker/libnetwork/drivers/bridge/setup_device.go b/components/engine/vendor/github.com/docker/libnetwork/drivers/bridge/setup_device.go index 548ad951dfa..fa9d8b334d3 100644 --- a/components/engine/vendor/github.com/docker/libnetwork/drivers/bridge/setup_device.go +++ b/components/engine/vendor/github.com/docker/libnetwork/drivers/bridge/setup_device.go @@ -2,6 +2,9 @@ package bridge import ( "fmt" + "io/ioutil" + "os" + "path/filepath" "github.com/docker/docker/pkg/parsers/kernel" "github.com/docker/libnetwork/netutils" @@ -49,6 +52,22 @@ func setupDevice(config *networkConfiguration, i *bridgeInterface) error { return err } +func setupDefaultSysctl(config *networkConfiguration, i *bridgeInterface) error { + // Disable IPv6 router advertisements originating on the bridge + sysPath := filepath.Join("/proc/sys/net/ipv6/conf/", config.BridgeName, "accept_ra") + if _, err := os.Stat(sysPath); err != nil { + logrus. + WithField("bridge", config.BridgeName). + WithField("syspath", sysPath). + Info("failed to read ipv6 net.ipv6.conf..accept_ra") + return nil + } + if err := ioutil.WriteFile(sysPath, []byte{'0', '\n'}, 0644); err != nil { + logrus.WithError(err).Warn("unable to disable IPv6 router advertisement") + } + return nil +} + // SetupDeviceUp ups the given bridge interface. func setupDeviceUp(config *networkConfiguration, i *bridgeInterface) error { err := i.nlh.LinkSetUp(i.Link) diff --git a/components/engine/vendor/github.com/docker/libnetwork/iptables/firewalld.go b/components/engine/vendor/github.com/docker/libnetwork/iptables/firewalld.go index f7bf1db6e7a..8746b220f55 100644 --- a/components/engine/vendor/github.com/docker/libnetwork/iptables/firewalld.go +++ b/components/engine/vendor/github.com/docker/libnetwork/iptables/firewalld.go @@ -19,20 +19,46 @@ const ( // Ebtables point to bridge table Ebtables IPV = "eb" ) + const ( - dbusInterface = "org.fedoraproject.FirewallD1" - dbusPath = "/org/fedoraproject/FirewallD1" + dbusInterface = "org.fedoraproject.FirewallD1" + dbusPath = "/org/fedoraproject/FirewallD1" + dbusConfigPath = "/org/fedoraproject/FirewallD1/config" + dockerZone = "docker" ) // Conn is a connection to firewalld dbus endpoint. type Conn struct { - sysconn *dbus.Conn - sysobj dbus.BusObject - signal chan *dbus.Signal + sysconn *dbus.Conn + sysObj dbus.BusObject + sysConfObj dbus.BusObject + signal chan *dbus.Signal +} + +// ZoneSettings holds the firewalld zone settings, documented in +// https://firewalld.org/documentation/man-pages/firewalld.dbus.html +type ZoneSettings struct { + version string + name string + description string + unused bool + target string + services []string + ports [][]interface{} + icmpBlocks []string + masquerade bool + forwardPorts [][]interface{} + interfaces []string + sourceAddresses []string + richRules []string + protocols []string + sourcePorts [][]interface{} + icmpBlockInversion bool } var ( - connection *Conn + connection *Conn + firewalldRunning bool // is Firewalld service running onReloaded []*func() // callbacks when Firewalld has been reloaded ) @@ -51,6 +77,9 @@ func FirewalldInit() error { } if connection != nil { go signalHandler() + if err := setupDockerZone(); err != nil { + return err + } } return nil @@ -76,8 +105,8 @@ func (c *Conn) initConnection() error { } // This never fails, even if the service is not running atm. - c.sysobj = c.sysconn.Object(dbusInterface, dbus.ObjectPath(dbusPath)) - + c.sysObj = c.sysconn.Object(dbusInterface, dbus.ObjectPath(dbusPath)) + c.sysConfObj = c.sysconn.Object(dbusInterface, dbus.ObjectPath(dbusConfigPath)) rule := fmt.Sprintf("type='signal',path='%s',interface='%s',sender='%s',member='Reloaded'", dbusPath, dbusInterface, dbusInterface) c.sysconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, rule) @@ -150,7 +179,7 @@ func checkRunning() bool { var err error if connection != nil { - err = connection.sysobj.Call(dbusInterface+".getDefaultZone", 0).Store(&zone) + err = connection.sysObj.Call(dbusInterface+".getDefaultZone", 0).Store(&zone) return err == nil } return false @@ -160,8 +189,115 @@ func checkRunning() bool { func Passthrough(ipv IPV, args ...string) ([]byte, error) { var output string logrus.Debugf("Firewalld passthrough: %s, %s", ipv, args) - if err := connection.sysobj.Call(dbusInterface+".direct.passthrough", 0, ipv, args).Store(&output); err != nil { + if err := connection.sysObj.Call(dbusInterface+".direct.passthrough", 0, ipv, args).Store(&output); err != nil { return nil, err } return []byte(output), nil } + +// getDockerZoneSettings converts the ZoneSettings struct into a interface slice +func getDockerZoneSettings() []interface{} { + settings := ZoneSettings{ + version: "1.0", + name: dockerZone, + description: "zone for docker bridge network interfaces", + target: "ACCEPT", + } + slice := []interface{}{ + settings.version, + settings.name, + settings.description, + settings.unused, + settings.target, + settings.services, + settings.ports, + settings.icmpBlocks, + settings.masquerade, + settings.forwardPorts, + settings.interfaces, + settings.sourceAddresses, + settings.richRules, + settings.protocols, + settings.sourcePorts, + settings.icmpBlockInversion, + } + return slice + +} + +// setupDockerZone creates a zone called docker in firewalld which includes docker interfaces to allow +// container networking +func setupDockerZone() error { + var zones []string + // Check if zone exists + if err := connection.sysObj.Call(dbusInterface+".zone.getZones", 0).Store(&zones); err != nil { + return err + } + if contains(zones, dockerZone) { + logrus.Infof("Firewalld: %s zone already exists, returning", dockerZone) + return nil + } + logrus.Debugf("Firewalld: creating %s zone", dockerZone) + + settings := getDockerZoneSettings() + // Permanent + if err := connection.sysConfObj.Call(dbusInterface+".config.addZone", 0, dockerZone, settings).Err; err != nil { + return err + } + // Reload for change to take effect + if err := connection.sysObj.Call(dbusInterface+".reload", 0).Err; err != nil { + return err + } + + return nil +} + +// AddInterfaceFirewalld adds the interface to the trusted zone +func AddInterfaceFirewalld(intf string) error { + var intfs []string + // Check if interface is already added to the zone + if err := connection.sysObj.Call(dbusInterface+".zone.getInterfaces", 0, dockerZone).Store(&intfs); err != nil { + return err + } + // Return if interface is already part of the zone + if contains(intfs, intf) { + logrus.Infof("Firewalld: interface %s already part of %s zone, returning", intf, dockerZone) + return nil + } + + logrus.Debugf("Firewalld: adding %s interface to %s zone", intf, dockerZone) + // Runtime + if err := connection.sysObj.Call(dbusInterface+".zone.addInterface", 0, dockerZone, intf).Err; err != nil { + return err + } + return nil +} + +// DelInterfaceFirewalld removes the interface from the trusted zone +func DelInterfaceFirewalld(intf string) error { + var intfs []string + // Check if interface is part of the zone + if err := connection.sysObj.Call(dbusInterface+".zone.getInterfaces", 0, dockerZone).Store(&intfs); err != nil { + return err + } + // Remove interface if it exists + if !contains(intfs, intf) { + return fmt.Errorf("Firewalld: unable to find interface %s in %s zone", intf, dockerZone) + } + + logrus.Debugf("Firewalld: removing %s interface from %s zone", intf, dockerZone) + // Runtime + if err := connection.sysObj.Call(dbusInterface+".zone.removeInterface", 0, dockerZone, intf).Err; err != nil { + return err + } + return nil +} + +func contains(list []string, val string) bool { + for _, v := range list { + if v == val { + return true + } + } + return false +} diff --git a/components/engine/vendor/github.com/docker/libnetwork/iptables/iptables.go b/components/engine/vendor/github.com/docker/libnetwork/iptables/iptables.go index 5523c4858c0..bd262eb86c0 100644 --- a/components/engine/vendor/github.com/docker/libnetwork/iptables/iptables.go +++ b/components/engine/vendor/github.com/docker/libnetwork/iptables/iptables.go @@ -146,6 +146,19 @@ func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode, enable bool) err return errors.New("Could not program chain, missing chain name") } + // Either add or remove the interface from the firewalld zone + if firewalldRunning { + if enable { + if err := AddInterfaceFirewalld(bridgeName); err != nil { + return err + } + } else { + if err := DelInterfaceFirewalld(bridgeName); err != nil { + return err + } + } + } + switch c.Table { case Nat: preroute := []string{ diff --git a/components/engine/vendor/github.com/docker/libnetwork/network.go b/components/engine/vendor/github.com/docker/libnetwork/network.go index 1f79577395a..a7a6d0748b4 100644 --- a/components/engine/vendor/github.com/docker/libnetwork/network.go +++ b/components/engine/vendor/github.com/docker/libnetwork/network.go @@ -1181,7 +1181,8 @@ func (n *network) createEndpoint(name string, options ...EndpointOption) (Endpoi ep.locator = n.getController().clusterHostID() ep.network, err = ep.getNetworkFromStore() if err != nil { - return nil, fmt.Errorf("failed to get network during CreateEndpoint: %v", err) + logrus.Errorf("failed to get network during CreateEndpoint: %v", err) + return nil, err } n = ep.network diff --git a/components/engine/vendor/github.com/docker/libnetwork/store.go b/components/engine/vendor/github.com/docker/libnetwork/store.go index 621bf507b9a..1b850104e97 100644 --- a/components/engine/vendor/github.com/docker/libnetwork/store.go +++ b/components/engine/vendor/github.com/docker/libnetwork/store.go @@ -80,16 +80,12 @@ func (c *controller) getStores() []datastore.DataStore { } func (c *controller) getNetworkFromStore(nid string) (*network, error) { - ns, err := c.getNetworksFromStore() - if err != nil { - return nil, err - } - for _, n := range ns { + for _, n := range c.getNetworksFromStore() { if n.id == nid { return n, nil } } - return nil, fmt.Errorf("network %s not found", nid) + return nil, ErrNoSuchNetwork(nid) } func (c *controller) getNetworksForScope(scope string) ([]*network, error) { @@ -128,12 +124,11 @@ func (c *controller) getNetworksForScope(scope string) ([]*network, error) { return nl, nil } -func (c *controller) getNetworksFromStore() ([]*network, error) { +func (c *controller) getNetworksFromStore() []*network { var nl []*network for _, store := range c.getStores() { - kvol, err := store.List(datastore.Key(datastore.NetworkKeyPrefix), - &network{ctrlr: c}) + kvol, err := store.List(datastore.Key(datastore.NetworkKeyPrefix), &network{ctrlr: c}) // Continue searching in the next store if no keys found in this store if err != nil { if err != datastore.ErrKeyNotFound { @@ -143,10 +138,8 @@ func (c *controller) getNetworksFromStore() ([]*network, error) { } kvep, err := store.Map(datastore.Key(epCntKeyPrefix), &endpointCnt{}) - if err != nil { - if err != datastore.ErrKeyNotFound { - logrus.Warnf("failed to get endpoint_count map for scope %s: %v", store.Scope(), err) - } + if err != nil && err != datastore.ErrKeyNotFound { + logrus.Warnf("failed to get endpoint_count map for scope %s: %v", store.Scope(), err) } for _, kvo := range kvol { @@ -168,7 +161,7 @@ func (c *controller) getNetworksFromStore() ([]*network, error) { } } - return nl, nil + return nl } func (n *network) getEndpointFromStore(eid string) (*endpoint, error) { @@ -455,13 +448,7 @@ func (c *controller) startWatch() { } func (c *controller) networkCleanup() { - networks, err := c.getNetworksFromStore() - if err != nil { - logrus.Warnf("Could not retrieve networks from store(s) during network cleanup: %v", err) - return - } - - for _, n := range networks { + for _, n := range c.getNetworksFromStore() { if n.inDelete { logrus.Infof("Removing stale network %s (%s)", n.Name(), n.ID()) if err := n.delete(true, true); err != nil {