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>
| ... | ... |
@@ -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 {
|