1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Add internal network support for bridge networks

Signed-off-by: Chun Chen <ramichen@tencent.com>
This commit is contained in:
Chun Chen 2016-01-06 21:06:23 +08:00
parent 88040e2e05
commit 7b64b1c293
4 changed files with 89 additions and 40 deletions

View file

@ -68,6 +68,7 @@ type networkConfiguration struct {
DefaultGatewayIPv6 net.IP DefaultGatewayIPv6 net.IP
dbIndex uint64 dbIndex uint64
dbExists bool dbExists bool
Internal bool
} }
// endpointConfiguration represents the user specified configuration for the sandbox endpoint // endpointConfiguration represents the user specified configuration for the sandbox endpoint
@ -280,16 +281,25 @@ func (n *bridgeNetwork) getEndpoint(eid string) (*bridgeEndpoint, error) {
// from each of the other networks // from each of the other networks
func (n *bridgeNetwork) isolateNetwork(others []*bridgeNetwork, enable bool) error { func (n *bridgeNetwork) isolateNetwork(others []*bridgeNetwork, enable bool) error {
n.Lock() n.Lock()
thisIface := n.config.BridgeName thisConfig := n.config
n.Unlock() n.Unlock()
if thisConfig.Internal {
return nil
}
// Install the rules to isolate this networks against each of the other networks // Install the rules to isolate this networks against each of the other networks
for _, o := range others { for _, o := range others {
o.Lock() o.Lock()
otherIface := o.config.BridgeName otherConfig := o.config
o.Unlock() o.Unlock()
if thisIface != otherIface {
if err := setINC(thisIface, otherIface, enable); err != nil { if otherConfig.Internal {
continue
}
if thisConfig.BridgeName != otherConfig.BridgeName {
if err := setINC(thisConfig.BridgeName, otherConfig.BridgeName, enable); err != nil {
return err return err
} }
} }
@ -483,7 +493,7 @@ func parseNetworkOptions(id string, option options.Generic) (*networkConfigurati
if val, ok := option[netlabel.Internal]; ok { if val, ok := option[netlabel.Internal]; ok {
if internal, ok := val.(bool); ok && internal { if internal, ok := val.(bool); ok && internal {
return nil, &driverapi.ErrNotImplemented{} config.Internal = true
} }
} }

View file

@ -82,38 +82,46 @@ func (n *bridgeNetwork) setupIPTables(config *networkConfiguration, i *bridgeInt
IP: ipnet.IP.Mask(ipnet.Mask), IP: ipnet.IP.Mask(ipnet.Mask),
Mask: ipnet.Mask, Mask: ipnet.Mask,
} }
if err = setupIPTablesInternal(config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, true); err != nil { if config.Internal {
return fmt.Errorf("Failed to Setup IP tables: %s", err.Error()) if err = setupInternalNetworkRules(config.BridgeName, maskedAddrv4, true); err != nil {
} return fmt.Errorf("Failed to Setup IP tables: %s", err.Error())
n.registerIptCleanFunc(func() error { }
return setupIPTablesInternal(config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, false) n.registerIptCleanFunc(func() error {
}) return setupInternalNetworkRules(config.BridgeName, maskedAddrv4, false)
})
} else {
if err = setupIPTablesInternal(config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, true); err != nil {
return fmt.Errorf("Failed to Setup IP tables: %s", err.Error())
}
n.registerIptCleanFunc(func() error {
return setupIPTablesInternal(config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, false)
})
natChain, filterChain, _, err := n.getDriverChains()
if err != nil {
return fmt.Errorf("Failed to setup IP tables, cannot acquire chain info %s", err.Error())
}
natChain, filterChain, _, err := n.getDriverChains() err = iptables.ProgramChain(natChain, config.BridgeName, hairpinMode, true)
if err != nil { if err != nil {
return fmt.Errorf("Failed to setup IP tables, cannot acquire chain info %s", err.Error()) return fmt.Errorf("Failed to program NAT chain: %s", err.Error())
} }
err = iptables.ProgramChain(natChain, config.BridgeName, hairpinMode, true) err = iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, true)
if err != nil { if err != nil {
return fmt.Errorf("Failed to program NAT chain: %s", err.Error()) return fmt.Errorf("Failed to program FILTER chain: %s", err.Error())
} }
err = iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, true) n.registerIptCleanFunc(func() error {
if err != nil { return iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, false)
return fmt.Errorf("Failed to program FILTER chain: %s", err.Error()) })
n.portMapper.SetIptablesChain(filterChain, n.getNetworkBridgeName())
} }
if err := ensureJumpRule("FORWARD", IsolationChain); err != nil { if err := ensureJumpRule("FORWARD", IsolationChain); err != nil {
return err return err
} }
n.registerIptCleanFunc(func() error {
return iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, false)
})
n.portMapper.SetIptablesChain(filterChain, n.getNetworkBridgeName())
return nil return nil
} }
@ -312,12 +320,26 @@ func ensureJumpRule(fromChain, toChain string) error {
func removeIPChains() { func removeIPChains() {
for _, chainInfo := range []iptables.ChainInfo{ for _, chainInfo := range []iptables.ChainInfo{
iptables.ChainInfo{Name: DockerChain, Table: iptables.Nat}, {Name: DockerChain, Table: iptables.Nat},
iptables.ChainInfo{Name: DockerChain, Table: iptables.Filter}, {Name: DockerChain, Table: iptables.Filter},
iptables.ChainInfo{Name: IsolationChain, Table: iptables.Filter}, {Name: IsolationChain, Table: iptables.Filter},
} { } {
if err := chainInfo.Remove(); err != nil { if err := chainInfo.Remove(); err != nil {
logrus.Warnf("Failed to remove existing iptables entries in table %s chain %s : %v", chainInfo.Table, chainInfo.Name, err) logrus.Warnf("Failed to remove existing iptables entries in table %s chain %s : %v", chainInfo.Table, chainInfo.Name, err)
} }
} }
} }
func setupInternalNetworkRules(bridgeIface string, addr net.Addr, insert bool) error {
var (
inDropRule = iptRule{table: iptables.Filter, chain: IsolationChain, args: []string{"-i", bridgeIface, "!", "-d", addr.String(), "-j", "DROP"}}
outDropRule = iptRule{table: iptables.Filter, chain: IsolationChain, args: []string{"-o", bridgeIface, "!", "-s", addr.String(), "-j", "DROP"}}
)
if err := programChainRule(inDropRule, "DROP INCOMING", insert); err != nil {
return err
}
if err := programChainRule(outDropRule, "DROP OUTGOING", insert); err != nil {
return err
}
return nil
}

View file

@ -2352,10 +2352,3 @@ func TestParallel2(t *testing.T) {
func TestParallel3(t *testing.T) { func TestParallel3(t *testing.T) {
runParallelTests(t, 3) runParallelTests(t, 3)
} }
func TestNetworkInternal(t *testing.T) {
_, err := controller.NewNetwork(bridgeNetType, "testnetworkinternal", libnetwork.NetworkOptionInternalNetwork())
if err == nil || err.Error() != (&driverapi.ErrNotImplemented{}).Error() {
t.Fatal("bridge network can't be internal")
}
}

View file

@ -20,8 +20,10 @@ function test_single_network_connectivity() {
# Now test connectivity between all the containers using service names # Now test connectivity between all the containers using service names
for i in `seq ${start} ${end}`; for i in `seq ${start} ${end}`;
do do
runc $(dnet_container_name 1 bridge) $(get_sbox_id 1 container_${i}) \ if [ "${nw_name}" != "internal" ]; then
"ping -c 1 www.google.com" runc $(dnet_container_name 1 bridge) $(get_sbox_id 1 container_${i}) \
"ping -c 1 www.google.com"
fi
for j in `seq ${start} ${end}`; for j in `seq ${start} ${end}`;
do do
if [ "$i" -eq "$j" ]; then if [ "$i" -eq "$j" ]; then
@ -250,6 +252,7 @@ function test_single_network_connectivity() {
dnet_cmd $(inst_id2port 1) network rm br1 dnet_cmd $(inst_id2port 1) network rm br1
} }
@test "Test bridge network global alias support" { @test "Test bridge network global alias support" {
skip_for_circleci skip_for_circleci
dnet_cmd $(inst_id2port 1) network create -d bridge br1 dnet_cmd $(inst_id2port 1) network create -d bridge br1
@ -279,3 +282,24 @@ function test_single_network_connectivity() {
dnet_cmd $(inst_id2port 1) network rm br1 dnet_cmd $(inst_id2port 1) network rm br1
} }
@test "Test bridge network internal network" {
skip_for_circleci
echo $(docker ps)
dnet_cmd $(inst_id2port 1) network create -d bridge --internal internal
dnet_cmd $(inst_id2port 1) container create container_1
# connects to internal network, confirm it can't conmunicate with outside world
net_connect 1 container_1 internal
run runc $(dnet_container_name 1 bridge) $(get_sbox_id 1 container_1) "ping -c 1 www.google.com"
[[ "$output" == *"1 packets transmitted, 0 packets received, 100% packet loss"* ]]
net_disconnect 1 container_1 internal
# connects to bridge network, confirm it can conmunicate with outside world
net_connect 1 container_1 bridge
runc $(dnet_container_name 1 bridge) $(get_sbox_id 1 container_1) "ping -c 1 www.google.com"
net_disconnect 1 container_1 bridge
dnet_cmd $(inst_id2port 1) container rm container_1
# test conmunications within internal network
test_single_network_connectivity internal 3
dnet_cmd $(inst_id2port 1) network rm internal
}