-
Notifications
You must be signed in to change notification settings - Fork 881
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Alec Benson <albenson@redhat.com>
- Loading branch information
Alec Benson
committed
Jul 8, 2015
1 parent
0517cea
commit 0e373fc
Showing
3 changed files
with
177 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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.FixedCIDR != 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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
} | ||
} |