From 90a410eb3d3672967d58a0561c3212b7833379ee Mon Sep 17 00:00:00 2001 From: Alec Benson Date: Wed, 8 Jul 2015 10:15:08 -0400 Subject: [PATCH] Refactor of docker PR #11405 Signed-off-by: Alec Benson --- libnetwork/drivers/bridge/bridge.go | 3 + .../bridge/setup_bridgenetfiltering.go | 162 ++++++++++++++++++ .../bridge/setup_bridgenetfiltering_test.go | 12 ++ 3 files changed, 177 insertions(+) create mode 100644 libnetwork/drivers/bridge/setup_bridgenetfiltering.go create mode 100644 libnetwork/drivers/bridge/setup_bridgenetfiltering_test.go diff --git a/libnetwork/drivers/bridge/bridge.go b/libnetwork/drivers/bridge/bridge.go index a0960986a0..b0ec3f22c3 100644 --- a/libnetwork/drivers/bridge/bridge.go +++ b/libnetwork/drivers/bridge/bridge.go @@ -669,6 +669,9 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err // Add inter-network communication rules. {config.EnableIPTables, setupNetworkIsolationRules}, + + //Configure bridge networking filtering if ICC is off and IP tables are enabled + {!config.EnableICC && config.EnableIPTables, setupBridgeNetFiltering}, } { if step.Condition { bridgeSetup.queueStep(step.Fn) diff --git a/libnetwork/drivers/bridge/setup_bridgenetfiltering.go b/libnetwork/drivers/bridge/setup_bridgenetfiltering.go new file mode 100644 index 0000000000..e7a5f4b077 --- /dev/null +++ b/libnetwork/drivers/bridge/setup_bridgenetfiltering.go @@ -0,0 +1,162 @@ +package bridge + +import ( + "fmt" + "io/ioutil" + "os" + "syscall" + + "github.com/Sirupsen/logrus" +) + +// Enumeration type saying which versions of IP protocol to process. +type ipVersion int + +const ( + ipvnone ipVersion = iota + ipv4 + ipv6 + ipvboth +) + +//Gets the IP version in use ( [ipv4], [ipv6] or [ipv4 and ipv6] ) +func getIPVersion(config *networkConfiguration) ipVersion { + ipVersion := ipv4 + if config.FixedCIDRv6 != nil || config.EnableIPv6 { + ipVersion |= ipv6 + } + return ipVersion +} + +func setupBridgeNetFiltering(config *networkConfiguration, i *bridgeInterface) error { + err := checkBridgeNetFiltering(config, i) + if err != nil { + if ptherr, ok := err.(*os.PathError); ok { + if errno, ok := ptherr.Err.(syscall.Errno); ok && errno == syscall.ENOENT { + if isRunningInContainer() { + logrus.Warnf("running inside docker container, ignoring missing kernel params: %v", err) + err = nil + } else { + err = fmt.Errorf("please ensure that br_netfilter kernel module is loaded") + } + } + } + if err != nil { + return fmt.Errorf("cannot restrict inter-container communication: %v", err) + } + } + return nil +} + +//Enable bridge net filtering if ip forwarding is enabled. See github issue #11404 +func checkBridgeNetFiltering(config *networkConfiguration, i *bridgeInterface) error { + ipVer := getIPVersion(config) + iface := config.BridgeName + doEnable := func(ipVer ipVersion) error { + var ipVerName string + if ipVer == ipv4 { + ipVerName = "IPv4" + } else { + ipVerName = "IPv6" + } + enabled, err := isPacketForwardingEnabled(ipVer, iface) + if err != nil { + logrus.Warnf("failed to check %s forwarding: %v", ipVerName, err) + } else if enabled { + enabled, err := getKernelBoolParam(getBridgeNFKernelParam(ipVer)) + if err != nil || enabled { + return err + } + return setKernelBoolParam(getBridgeNFKernelParam(ipVer), true) + } + return nil + } + + switch ipVer { + case ipv4, ipv6: + return doEnable(ipVer) + case ipvboth: + v4err := doEnable(ipv4) + v6err := doEnable(ipv6) + if v4err == nil { + return v6err + } + return v4err + default: + return nil + } +} + +// Get kernel param path saying whether IPv${ipVer} traffic is being forwarded +// on particular interface. Interface may be specified for IPv6 only. If +// `iface` is empty, `default` will be assumed, which represents default value +// for new interfaces. +func getForwardingKernelParam(ipVer ipVersion, iface string) string { + switch ipVer { + case ipv4: + return "/proc/sys/net/ipv4/ip_forward" + case ipv6: + if iface == "" { + iface = "default" + } + return fmt.Sprintf("/proc/sys/net/ipv6/conf/%s/forwarding", iface) + default: + return "" + } +} + +// Get kernel param path saying whether bridged IPv${ipVer} traffic shall be +// passed to ip${ipVer}tables' chains. +func getBridgeNFKernelParam(ipVer ipVersion) string { + switch ipVer { + case ipv4: + return "/proc/sys/net/bridge/bridge-nf-call-iptables" + case ipv6: + return "/proc/sys/net/bridge/bridge-nf-call-ip6tables" + default: + return "" + } +} + +//Gets the value of the kernel parameters located at the given path +func getKernelBoolParam(path string) (bool, error) { + enabled := false + line, err := ioutil.ReadFile(path) + if err != nil { + return false, err + } + if len(line) > 0 { + enabled = line[0] == '1' + } + return enabled, err +} + +//Sets the value of the kernel parameter located at the given path +func setKernelBoolParam(path string, on bool) error { + value := byte('0') + if on { + value = byte('1') + } + return ioutil.WriteFile(path, []byte{value, '\n'}, 0644) +} + +//Checks to see if packet forwarding is enabled +func isPacketForwardingEnabled(ipVer ipVersion, iface string) (bool, error) { + switch ipVer { + case ipv4, ipv6: + return getKernelBoolParam(getForwardingKernelParam(ipVer, iface)) + case ipvboth: + enabled, err := getKernelBoolParam(getForwardingKernelParam(ipv4, "")) + if err != nil || !enabled { + return enabled, err + } + return getKernelBoolParam(getForwardingKernelParam(ipv6, iface)) + default: + return true, nil + } +} + +func isRunningInContainer() bool { + _, err := os.Stat("/.dockerinit") + return !os.IsNotExist(err) +} diff --git a/libnetwork/drivers/bridge/setup_bridgenetfiltering_test.go b/libnetwork/drivers/bridge/setup_bridgenetfiltering_test.go new file mode 100644 index 0000000000..4ff5fed8af --- /dev/null +++ b/libnetwork/drivers/bridge/setup_bridgenetfiltering_test.go @@ -0,0 +1,12 @@ +package bridge + +import "testing" + +func TestIPConstantValues(t *testing.T) { + if ipv4|ipv6 != ipvboth { + t.Fatalf("bitwise or of ipv4(%04b) and ipv6(%04b) must yield ipvboth(%04b)", ipv4, ipv6, ipvboth) + } + if ipvboth&(^(ipv4 | ipv6)) != ipvnone { + t.Fatalf("ipvboth(%04b) with unset ipv4(%04b) and ipv6(%04b) bits shall equal to ipvnone", ipvboth, ipv4, ipv6) + } +}