Browse code

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 <github@gone.nl>

Sebastiaan van Stijn authored on 2020/07/08 23:12:22
Showing 9 changed files
... ...
@@ -3,7 +3,7 @@
3 3
 # LIBNETWORK_COMMIT is used to build the docker-userland-proxy binary. When
4 4
 # updating the binary version, consider updating github.com/docker/libnetwork
5 5
 # in vendor.conf accordingly
6
-: "${LIBNETWORK_COMMIT:=2e24aed516bd5c836e11378bb457dd612aa868ed}"
6
+: "${LIBNETWORK_COMMIT:=9e99af28df21367340c95a3863e31808d689c92a}"
7 7
 
8 8
 install_proxy() {
9 9
 	case "$1" in
... ...
@@ -41,7 +41,7 @@ github.com/grpc-ecosystem/go-grpc-middleware        3c51f7f332123e8be5a157c0802a
41 41
 # libnetwork
42 42
 
43 43
 # When updating, also update LIBNETWORK_COMMIT in hack/dockerfile/install/proxy.installer accordingly
44
-github.com/docker/libnetwork                        2e24aed516bd5c836e11378bb457dd612aa868ed
44
+github.com/docker/libnetwork                        9e99af28df21367340c95a3863e31808d689c92a
45 45
 github.com/docker/go-events                         e31b211e4f1cd09aa76fe4ac244571fab96ae47f
46 46
 github.com/armon/go-radix                           e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
47 47
 github.com/armon/go-metrics                         eb0af217e5e9747e41dd5303755356b62d28e3ec
... ...
@@ -1020,12 +1020,7 @@ func (c *controller) addNetwork(n *network) error {
1020 1020
 func (c *controller) Networks() []Network {
1021 1021
 	var list []Network
1022 1022
 
1023
-	networks, err := c.getNetworksFromStore()
1024
-	if err != nil {
1025
-		logrus.Error(err)
1026
-	}
1027
-
1028
-	for _, n := range networks {
1023
+	for _, n := range c.getNetworksFromStore() {
1029 1024
 		if n.inDelete {
1030 1025
 			continue
1031 1026
 		}
... ...
@@ -689,6 +689,12 @@ func (d *driver) createNetwork(config *networkConfiguration) (err error) {
689 689
 	bridgeAlreadyExists := bridgeIface.exists()
690 690
 	if !bridgeAlreadyExists {
691 691
 		bridgeSetup.queueStep(setupDevice)
692
+		bridgeSetup.queueStep(setupDefaultSysctl)
693
+	}
694
+
695
+	// For the default bridge, set expected sysctls
696
+	if config.DefaultBridge {
697
+		bridgeSetup.queueStep(setupDefaultSysctl)
692 698
 	}
693 699
 
694 700
 	// Even if a bridge exists try to setup IPv4.
... ...
@@ -2,6 +2,9 @@ package bridge
2 2
 
3 3
 import (
4 4
 	"fmt"
5
+	"io/ioutil"
6
+	"os"
7
+	"path/filepath"
5 8
 
6 9
 	"github.com/docker/docker/pkg/parsers/kernel"
7 10
 	"github.com/docker/libnetwork/netutils"
... ...
@@ -49,6 +52,22 @@ func setupDevice(config *networkConfiguration, i *bridgeInterface) error {
49 49
 	return err
50 50
 }
51 51
 
52
+func setupDefaultSysctl(config *networkConfiguration, i *bridgeInterface) error {
53
+	// Disable IPv6 router advertisements originating on the bridge
54
+	sysPath := filepath.Join("/proc/sys/net/ipv6/conf/", config.BridgeName, "accept_ra")
55
+	if _, err := os.Stat(sysPath); err != nil {
56
+		logrus.
57
+			WithField("bridge", config.BridgeName).
58
+			WithField("syspath", sysPath).
59
+			Info("failed to read ipv6 net.ipv6.conf.<bridge>.accept_ra")
60
+		return nil
61
+	}
62
+	if err := ioutil.WriteFile(sysPath, []byte{'0', '\n'}, 0644); err != nil {
63
+		logrus.WithError(err).Warn("unable to disable IPv6 router advertisement")
64
+	}
65
+	return nil
66
+}
67
+
52 68
 // SetupDeviceUp ups the given bridge interface.
53 69
 func setupDeviceUp(config *networkConfiguration, i *bridgeInterface) error {
54 70
 	err := i.nlh.LinkSetUp(i.Link)
... ...
@@ -19,20 +19,46 @@ const (
19 19
 	// Ebtables point to bridge table
20 20
 	Ebtables IPV = "eb"
21 21
 )
22
+
22 23
 const (
23
-	dbusInterface = "org.fedoraproject.FirewallD1"
24
-	dbusPath      = "/org/fedoraproject/FirewallD1"
24
+	dbusInterface  = "org.fedoraproject.FirewallD1"
25
+	dbusPath       = "/org/fedoraproject/FirewallD1"
26
+	dbusConfigPath = "/org/fedoraproject/FirewallD1/config"
27
+	dockerZone     = "docker"
25 28
 )
26 29
 
27 30
 // Conn is a connection to firewalld dbus endpoint.
28 31
 type Conn struct {
29
-	sysconn *dbus.Conn
30
-	sysobj  dbus.BusObject
31
-	signal  chan *dbus.Signal
32
+	sysconn    *dbus.Conn
33
+	sysObj     dbus.BusObject
34
+	sysConfObj dbus.BusObject
35
+	signal     chan *dbus.Signal
36
+}
37
+
38
+// ZoneSettings holds the firewalld zone settings, documented in
39
+// https://firewalld.org/documentation/man-pages/firewalld.dbus.html
40
+type ZoneSettings struct {
41
+	version            string
42
+	name               string
43
+	description        string
44
+	unused             bool
45
+	target             string
46
+	services           []string
47
+	ports              [][]interface{}
48
+	icmpBlocks         []string
49
+	masquerade         bool
50
+	forwardPorts       [][]interface{}
51
+	interfaces         []string
52
+	sourceAddresses    []string
53
+	richRules          []string
54
+	protocols          []string
55
+	sourcePorts        [][]interface{}
56
+	icmpBlockInversion bool
32 57
 }
33 58
 
34 59
 var (
35
-	connection       *Conn
60
+	connection *Conn
61
+
36 62
 	firewalldRunning bool      // is Firewalld service running
37 63
 	onReloaded       []*func() // callbacks when Firewalld has been reloaded
38 64
 )
... ...
@@ -51,6 +77,9 @@ func FirewalldInit() error {
51 51
 	}
52 52
 	if connection != nil {
53 53
 		go signalHandler()
54
+		if err := setupDockerZone(); err != nil {
55
+			return err
56
+		}
54 57
 	}
55 58
 
56 59
 	return nil
... ...
@@ -76,8 +105,8 @@ func (c *Conn) initConnection() error {
76 76
 	}
77 77
 
78 78
 	// This never fails, even if the service is not running atm.
79
-	c.sysobj = c.sysconn.Object(dbusInterface, dbus.ObjectPath(dbusPath))
80
-
79
+	c.sysObj = c.sysconn.Object(dbusInterface, dbus.ObjectPath(dbusPath))
80
+	c.sysConfObj = c.sysconn.Object(dbusInterface, dbus.ObjectPath(dbusConfigPath))
81 81
 	rule := fmt.Sprintf("type='signal',path='%s',interface='%s',sender='%s',member='Reloaded'",
82 82
 		dbusPath, dbusInterface, dbusInterface)
83 83
 	c.sysconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, rule)
... ...
@@ -150,7 +179,7 @@ func checkRunning() bool {
150 150
 	var err error
151 151
 
152 152
 	if connection != nil {
153
-		err = connection.sysobj.Call(dbusInterface+".getDefaultZone", 0).Store(&zone)
153
+		err = connection.sysObj.Call(dbusInterface+".getDefaultZone", 0).Store(&zone)
154 154
 		return err == nil
155 155
 	}
156 156
 	return false
... ...
@@ -160,8 +189,115 @@ func checkRunning() bool {
160 160
 func Passthrough(ipv IPV, args ...string) ([]byte, error) {
161 161
 	var output string
162 162
 	logrus.Debugf("Firewalld passthrough: %s, %s", ipv, args)
163
-	if err := connection.sysobj.Call(dbusInterface+".direct.passthrough", 0, ipv, args).Store(&output); err != nil {
163
+	if err := connection.sysObj.Call(dbusInterface+".direct.passthrough", 0, ipv, args).Store(&output); err != nil {
164 164
 		return nil, err
165 165
 	}
166 166
 	return []byte(output), nil
167 167
 }
168
+
169
+// getDockerZoneSettings converts the ZoneSettings struct into a interface slice
170
+func getDockerZoneSettings() []interface{} {
171
+	settings := ZoneSettings{
172
+		version:     "1.0",
173
+		name:        dockerZone,
174
+		description: "zone for docker bridge network interfaces",
175
+		target:      "ACCEPT",
176
+	}
177
+	slice := []interface{}{
178
+		settings.version,
179
+		settings.name,
180
+		settings.description,
181
+		settings.unused,
182
+		settings.target,
183
+		settings.services,
184
+		settings.ports,
185
+		settings.icmpBlocks,
186
+		settings.masquerade,
187
+		settings.forwardPorts,
188
+		settings.interfaces,
189
+		settings.sourceAddresses,
190
+		settings.richRules,
191
+		settings.protocols,
192
+		settings.sourcePorts,
193
+		settings.icmpBlockInversion,
194
+	}
195
+	return slice
196
+
197
+}
198
+
199
+// setupDockerZone creates a zone called docker in firewalld which includes docker interfaces to allow
200
+// container networking
201
+func setupDockerZone() error {
202
+	var zones []string
203
+	// Check if zone exists
204
+	if err := connection.sysObj.Call(dbusInterface+".zone.getZones", 0).Store(&zones); err != nil {
205
+		return err
206
+	}
207
+	if contains(zones, dockerZone) {
208
+		logrus.Infof("Firewalld: %s zone already exists, returning", dockerZone)
209
+		return nil
210
+	}
211
+	logrus.Debugf("Firewalld: creating %s zone", dockerZone)
212
+
213
+	settings := getDockerZoneSettings()
214
+	// Permanent
215
+	if err := connection.sysConfObj.Call(dbusInterface+".config.addZone", 0, dockerZone, settings).Err; err != nil {
216
+		return err
217
+	}
218
+	// Reload for change to take effect
219
+	if err := connection.sysObj.Call(dbusInterface+".reload", 0).Err; err != nil {
220
+		return err
221
+	}
222
+
223
+	return nil
224
+}
225
+
226
+// AddInterfaceFirewalld adds the interface to the trusted zone
227
+func AddInterfaceFirewalld(intf string) error {
228
+	var intfs []string
229
+	// Check if interface is already added to the zone
230
+	if err := connection.sysObj.Call(dbusInterface+".zone.getInterfaces", 0, dockerZone).Store(&intfs); err != nil {
231
+		return err
232
+	}
233
+	// Return if interface is already part of the zone
234
+	if contains(intfs, intf) {
235
+		logrus.Infof("Firewalld: interface %s already part of %s zone, returning", intf, dockerZone)
236
+		return nil
237
+	}
238
+
239
+	logrus.Debugf("Firewalld: adding %s interface to %s zone", intf, dockerZone)
240
+	// Runtime
241
+	if err := connection.sysObj.Call(dbusInterface+".zone.addInterface", 0, dockerZone, intf).Err; err != nil {
242
+		return err
243
+	}
244
+	return nil
245
+}
246
+
247
+// DelInterfaceFirewalld removes the interface from the trusted zone
248
+func DelInterfaceFirewalld(intf string) error {
249
+	var intfs []string
250
+	// Check if interface is part of the zone
251
+	if err := connection.sysObj.Call(dbusInterface+".zone.getInterfaces", 0, dockerZone).Store(&intfs); err != nil {
252
+		return err
253
+	}
254
+	// Remove interface if it exists
255
+	if !contains(intfs, intf) {
256
+		return fmt.Errorf("Firewalld: unable to find interface %s in %s zone", intf, dockerZone)
257
+	}
258
+
259
+	logrus.Debugf("Firewalld: removing %s interface from %s zone", intf, dockerZone)
260
+	// Runtime
261
+	if err := connection.sysObj.Call(dbusInterface+".zone.removeInterface", 0, dockerZone, intf).Err; err != nil {
262
+		return err
263
+	}
264
+	return nil
265
+}
266
+
267
+func contains(list []string, val string) bool {
268
+	for _, v := range list {
269
+		if v == val {
270
+			return true
271
+		}
272
+	}
273
+	return false
274
+}
... ...
@@ -146,6 +146,19 @@ func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode, enable bool) err
146 146
 		return errors.New("Could not program chain, missing chain name")
147 147
 	}
148 148
 
149
+	// Either add or remove the interface from the firewalld zone
150
+	if firewalldRunning {
151
+		if enable {
152
+			if err := AddInterfaceFirewalld(bridgeName); err != nil {
153
+				return err
154
+			}
155
+		} else {
156
+			if err := DelInterfaceFirewalld(bridgeName); err != nil {
157
+				return err
158
+			}
159
+		}
160
+	}
161
+
149 162
 	switch c.Table {
150 163
 	case Nat:
151 164
 		preroute := []string{
... ...
@@ -1181,7 +1181,8 @@ func (n *network) createEndpoint(name string, options ...EndpointOption) (Endpoi
1181 1181
 	ep.locator = n.getController().clusterHostID()
1182 1182
 	ep.network, err = ep.getNetworkFromStore()
1183 1183
 	if err != nil {
1184
-		return nil, fmt.Errorf("failed to get network during CreateEndpoint: %v", err)
1184
+		logrus.Errorf("failed to get network during CreateEndpoint: %v", err)
1185
+		return nil, err
1185 1186
 	}
1186 1187
 	n = ep.network
1187 1188
 
... ...
@@ -80,16 +80,12 @@ func (c *controller) getStores() []datastore.DataStore {
80 80
 }
81 81
 
82 82
 func (c *controller) getNetworkFromStore(nid string) (*network, error) {
83
-	ns, err := c.getNetworksFromStore()
84
-	if err != nil {
85
-		return nil, err
86
-	}
87
-	for _, n := range ns {
83
+	for _, n := range c.getNetworksFromStore() {
88 84
 		if n.id == nid {
89 85
 			return n, nil
90 86
 		}
91 87
 	}
92
-	return nil, fmt.Errorf("network %s not found", nid)
88
+	return nil, ErrNoSuchNetwork(nid)
93 89
 }
94 90
 
95 91
 func (c *controller) getNetworksForScope(scope string) ([]*network, error) {
... ...
@@ -128,12 +124,11 @@ func (c *controller) getNetworksForScope(scope string) ([]*network, error) {
128 128
 	return nl, nil
129 129
 }
130 130
 
131
-func (c *controller) getNetworksFromStore() ([]*network, error) {
131
+func (c *controller) getNetworksFromStore() []*network {
132 132
 	var nl []*network
133 133
 
134 134
 	for _, store := range c.getStores() {
135
-		kvol, err := store.List(datastore.Key(datastore.NetworkKeyPrefix),
136
-			&network{ctrlr: c})
135
+		kvol, err := store.List(datastore.Key(datastore.NetworkKeyPrefix), &network{ctrlr: c})
137 136
 		// Continue searching in the next store if no keys found in this store
138 137
 		if err != nil {
139 138
 			if err != datastore.ErrKeyNotFound {
... ...
@@ -143,10 +138,8 @@ func (c *controller) getNetworksFromStore() ([]*network, error) {
143 143
 		}
144 144
 
145 145
 		kvep, err := store.Map(datastore.Key(epCntKeyPrefix), &endpointCnt{})
146
-		if err != nil {
147
-			if err != datastore.ErrKeyNotFound {
148
-				logrus.Warnf("failed to get endpoint_count map for scope %s: %v", store.Scope(), err)
149
-			}
146
+		if err != nil && err != datastore.ErrKeyNotFound {
147
+			logrus.Warnf("failed to get endpoint_count map for scope %s: %v", store.Scope(), err)
150 148
 		}
151 149
 
152 150
 		for _, kvo := range kvol {
... ...
@@ -168,7 +161,7 @@ func (c *controller) getNetworksFromStore() ([]*network, error) {
168 168
 		}
169 169
 	}
170 170
 
171
-	return nl, nil
171
+	return nl
172 172
 }
173 173
 
174 174
 func (n *network) getEndpointFromStore(eid string) (*endpoint, error) {
... ...
@@ -455,13 +448,7 @@ func (c *controller) startWatch() {
455 455
 }
456 456
 
457 457
 func (c *controller) networkCleanup() {
458
-	networks, err := c.getNetworksFromStore()
459
-	if err != nil {
460
-		logrus.Warnf("Could not retrieve networks from store(s) during network cleanup: %v", err)
461
-		return
462
-	}
463
-
464
-	for _, n := range networks {
458
+	for _, n := range c.getNetworksFromStore() {
465 459
 		if n.inDelete {
466 460
 			logrus.Infof("Removing stale network %s (%s)", n.Name(), n.ID())
467 461
 			if err := n.delete(true, true); err != nil {