Signed-off-by: Chun Chen <ramichen@tencent.com>
| ... | ... |
@@ -68,6 +68,7 @@ type networkConfiguration struct {
|
| 68 | 68 |
DefaultGatewayIPv6 net.IP |
| 69 | 69 |
dbIndex uint64 |
| 70 | 70 |
dbExists bool |
| 71 |
+ Internal bool |
|
| 71 | 72 |
} |
| 72 | 73 |
|
| 73 | 74 |
// endpointConfiguration represents the user specified configuration for the sandbox endpoint |
| ... | ... |
@@ -280,16 +281,25 @@ func (n *bridgeNetwork) getEndpoint(eid string) (*bridgeEndpoint, error) {
|
| 280 | 280 |
// from each of the other networks |
| 281 | 281 |
func (n *bridgeNetwork) isolateNetwork(others []*bridgeNetwork, enable bool) error {
|
| 282 | 282 |
n.Lock() |
| 283 |
- thisIface := n.config.BridgeName |
|
| 283 |
+ thisConfig := n.config |
|
| 284 | 284 |
n.Unlock() |
| 285 | 285 |
|
| 286 |
+ if thisConfig.Internal {
|
|
| 287 |
+ return nil |
|
| 288 |
+ } |
|
| 289 |
+ |
|
| 286 | 290 |
// Install the rules to isolate this networks against each of the other networks |
| 287 | 291 |
for _, o := range others {
|
| 288 | 292 |
o.Lock() |
| 289 |
- otherIface := o.config.BridgeName |
|
| 293 |
+ otherConfig := o.config |
|
| 290 | 294 |
o.Unlock() |
| 291 |
- if thisIface != otherIface {
|
|
| 292 |
- if err := setINC(thisIface, otherIface, enable); err != nil {
|
|
| 295 |
+ |
|
| 296 |
+ if otherConfig.Internal {
|
|
| 297 |
+ continue |
|
| 298 |
+ } |
|
| 299 |
+ |
|
| 300 |
+ if thisConfig.BridgeName != otherConfig.BridgeName {
|
|
| 301 |
+ if err := setINC(thisConfig.BridgeName, otherConfig.BridgeName, enable); err != nil {
|
|
| 293 | 302 |
return err |
| 294 | 303 |
} |
| 295 | 304 |
} |
| ... | ... |
@@ -483,7 +493,7 @@ func parseNetworkOptions(id string, option options.Generic) (*networkConfigurati |
| 483 | 483 |
|
| 484 | 484 |
if val, ok := option[netlabel.Internal]; ok {
|
| 485 | 485 |
if internal, ok := val.(bool); ok && internal {
|
| 486 |
- return nil, &driverapi.ErrNotImplemented{}
|
|
| 486 |
+ config.Internal = true |
|
| 487 | 487 |
} |
| 488 | 488 |
} |
| 489 | 489 |
|
| ... | ... |
@@ -82,38 +82,46 @@ func (n *bridgeNetwork) setupIPTables(config *networkConfiguration, i *bridgeInt |
| 82 | 82 |
IP: ipnet.IP.Mask(ipnet.Mask), |
| 83 | 83 |
Mask: ipnet.Mask, |
| 84 | 84 |
} |
| 85 |
- if err = setupIPTablesInternal(config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, true); err != nil {
|
|
| 86 |
- return fmt.Errorf("Failed to Setup IP tables: %s", err.Error())
|
|
| 87 |
- } |
|
| 88 |
- n.registerIptCleanFunc(func() error {
|
|
| 89 |
- return setupIPTablesInternal(config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, false) |
|
| 90 |
- }) |
|
| 85 |
+ if config.Internal {
|
|
| 86 |
+ if err = setupInternalNetworkRules(config.BridgeName, maskedAddrv4, true); err != nil {
|
|
| 87 |
+ return fmt.Errorf("Failed to Setup IP tables: %s", err.Error())
|
|
| 88 |
+ } |
|
| 89 |
+ n.registerIptCleanFunc(func() error {
|
|
| 90 |
+ return setupInternalNetworkRules(config.BridgeName, maskedAddrv4, false) |
|
| 91 |
+ }) |
|
| 92 |
+ } else {
|
|
| 93 |
+ if err = setupIPTablesInternal(config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, true); err != nil {
|
|
| 94 |
+ return fmt.Errorf("Failed to Setup IP tables: %s", err.Error())
|
|
| 95 |
+ } |
|
| 96 |
+ n.registerIptCleanFunc(func() error {
|
|
| 97 |
+ return setupIPTablesInternal(config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, false) |
|
| 98 |
+ }) |
|
| 99 |
+ natChain, filterChain, _, err := n.getDriverChains() |
|
| 100 |
+ if err != nil {
|
|
| 101 |
+ return fmt.Errorf("Failed to setup IP tables, cannot acquire chain info %s", err.Error())
|
|
| 102 |
+ } |
|
| 91 | 103 |
|
| 92 |
- natChain, filterChain, _, err := n.getDriverChains() |
|
| 93 |
- if err != nil {
|
|
| 94 |
- return fmt.Errorf("Failed to setup IP tables, cannot acquire chain info %s", err.Error())
|
|
| 95 |
- } |
|
| 104 |
+ err = iptables.ProgramChain(natChain, config.BridgeName, hairpinMode, true) |
|
| 105 |
+ if err != nil {
|
|
| 106 |
+ return fmt.Errorf("Failed to program NAT chain: %s", err.Error())
|
|
| 107 |
+ } |
|
| 96 | 108 |
|
| 97 |
- err = iptables.ProgramChain(natChain, config.BridgeName, hairpinMode, true) |
|
| 98 |
- if err != nil {
|
|
| 99 |
- return fmt.Errorf("Failed to program NAT chain: %s", err.Error())
|
|
| 100 |
- } |
|
| 109 |
+ err = iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, true) |
|
| 110 |
+ if err != nil {
|
|
| 111 |
+ return fmt.Errorf("Failed to program FILTER chain: %s", err.Error())
|
|
| 112 |
+ } |
|
| 101 | 113 |
|
| 102 |
- err = iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, true) |
|
| 103 |
- if err != nil {
|
|
| 104 |
- return fmt.Errorf("Failed to program FILTER chain: %s", err.Error())
|
|
| 114 |
+ n.registerIptCleanFunc(func() error {
|
|
| 115 |
+ return iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, false) |
|
| 116 |
+ }) |
|
| 117 |
+ |
|
| 118 |
+ n.portMapper.SetIptablesChain(filterChain, n.getNetworkBridgeName()) |
|
| 105 | 119 |
} |
| 106 | 120 |
|
| 107 | 121 |
if err := ensureJumpRule("FORWARD", IsolationChain); err != nil {
|
| 108 | 122 |
return err |
| 109 | 123 |
} |
| 110 | 124 |
|
| 111 |
- n.registerIptCleanFunc(func() error {
|
|
| 112 |
- return iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, false) |
|
| 113 |
- }) |
|
| 114 |
- |
|
| 115 |
- n.portMapper.SetIptablesChain(filterChain, n.getNetworkBridgeName()) |
|
| 116 |
- |
|
| 117 | 125 |
return nil |
| 118 | 126 |
} |
| 119 | 127 |
|
| ... | ... |
@@ -312,12 +320,26 @@ func ensureJumpRule(fromChain, toChain string) error {
|
| 312 | 312 |
|
| 313 | 313 |
func removeIPChains() {
|
| 314 | 314 |
for _, chainInfo := range []iptables.ChainInfo{
|
| 315 |
- iptables.ChainInfo{Name: DockerChain, Table: iptables.Nat},
|
|
| 316 |
- iptables.ChainInfo{Name: DockerChain, Table: iptables.Filter},
|
|
| 317 |
- iptables.ChainInfo{Name: IsolationChain, Table: iptables.Filter},
|
|
| 315 |
+ {Name: DockerChain, Table: iptables.Nat},
|
|
| 316 |
+ {Name: DockerChain, Table: iptables.Filter},
|
|
| 317 |
+ {Name: IsolationChain, Table: iptables.Filter},
|
|
| 318 | 318 |
} {
|
| 319 | 319 |
if err := chainInfo.Remove(); err != nil {
|
| 320 | 320 |
logrus.Warnf("Failed to remove existing iptables entries in table %s chain %s : %v", chainInfo.Table, chainInfo.Name, err)
|
| 321 | 321 |
} |
| 322 | 322 |
} |
| 323 | 323 |
} |
| 324 |
+ |
|
| 325 |
+func setupInternalNetworkRules(bridgeIface string, addr net.Addr, insert bool) error {
|
|
| 326 |
+ var ( |
|
| 327 |
+ inDropRule = iptRule{table: iptables.Filter, chain: IsolationChain, args: []string{"-i", bridgeIface, "!", "-d", addr.String(), "-j", "DROP"}}
|
|
| 328 |
+ outDropRule = iptRule{table: iptables.Filter, chain: IsolationChain, args: []string{"-o", bridgeIface, "!", "-s", addr.String(), "-j", "DROP"}}
|
|
| 329 |
+ ) |
|
| 330 |
+ if err := programChainRule(inDropRule, "DROP INCOMING", insert); err != nil {
|
|
| 331 |
+ return err |
|
| 332 |
+ } |
|
| 333 |
+ if err := programChainRule(outDropRule, "DROP OUTGOING", insert); err != nil {
|
|
| 334 |
+ return err |
|
| 335 |
+ } |
|
| 336 |
+ return nil |
|
| 337 |
+} |
| ... | ... |
@@ -2352,10 +2352,3 @@ func TestParallel2(t *testing.T) {
|
| 2352 | 2352 |
func TestParallel3(t *testing.T) {
|
| 2353 | 2353 |
runParallelTests(t, 3) |
| 2354 | 2354 |
} |
| 2355 |
- |
|
| 2356 |
-func TestNetworkInternal(t *testing.T) {
|
|
| 2357 |
- _, err := controller.NewNetwork(bridgeNetType, "testnetworkinternal", libnetwork.NetworkOptionInternalNetwork()) |
|
| 2358 |
- if err == nil || err.Error() != (&driverapi.ErrNotImplemented{}).Error() {
|
|
| 2359 |
- t.Fatal("bridge network can't be internal")
|
|
| 2360 |
- } |
|
| 2361 |
-} |
| ... | ... |
@@ -20,8 +20,10 @@ function test_single_network_connectivity() {
|
| 20 | 20 |
# Now test connectivity between all the containers using service names |
| 21 | 21 |
for i in `seq ${start} ${end}`;
|
| 22 | 22 |
do |
| 23 |
- runc $(dnet_container_name 1 bridge) $(get_sbox_id 1 container_${i}) \
|
|
| 24 |
- "ping -c 1 www.google.com" |
|
| 23 |
+ if [ "${nw_name}" != "internal" ]; then
|
|
| 24 |
+ runc $(dnet_container_name 1 bridge) $(get_sbox_id 1 container_${i}) \
|
|
| 25 |
+ "ping -c 1 www.google.com" |
|
| 26 |
+ fi |
|
| 25 | 27 |
for j in `seq ${start} ${end}`;
|
| 26 | 28 |
do |
| 27 | 29 |
if [ "$i" -eq "$j" ]; then |
| ... | ... |
@@ -250,6 +252,7 @@ function test_single_network_connectivity() {
|
| 250 | 250 |
dnet_cmd $(inst_id2port 1) network rm br1 |
| 251 | 251 |
} |
| 252 | 252 |
|
| 253 |
+ |
|
| 253 | 254 |
@test "Test bridge network global alias support" {
|
| 254 | 255 |
skip_for_circleci |
| 255 | 256 |
dnet_cmd $(inst_id2port 1) network create -d bridge br1 |
| ... | ... |
@@ -279,3 +282,24 @@ function test_single_network_connectivity() {
|
| 279 | 279 |
|
| 280 | 280 |
dnet_cmd $(inst_id2port 1) network rm br1 |
| 281 | 281 |
} |
| 282 |
+ |
|
| 283 |
+@test "Test bridge network internal network" {
|
|
| 284 |
+ skip_for_circleci |
|
| 285 |
+ |
|
| 286 |
+ echo $(docker ps) |
|
| 287 |
+ dnet_cmd $(inst_id2port 1) network create -d bridge --internal internal |
|
| 288 |
+ dnet_cmd $(inst_id2port 1) container create container_1 |
|
| 289 |
+ # connects to internal network, confirm it can't conmunicate with outside world |
|
| 290 |
+ net_connect 1 container_1 internal |
|
| 291 |
+ run runc $(dnet_container_name 1 bridge) $(get_sbox_id 1 container_1) "ping -c 1 www.google.com" |
|
| 292 |
+ [[ "$output" == *"1 packets transmitted, 0 packets received, 100% packet loss"* ]] |
|
| 293 |
+ net_disconnect 1 container_1 internal |
|
| 294 |
+ # connects to bridge network, confirm it can conmunicate with outside world |
|
| 295 |
+ net_connect 1 container_1 bridge |
|
| 296 |
+ runc $(dnet_container_name 1 bridge) $(get_sbox_id 1 container_1) "ping -c 1 www.google.com" |
|
| 297 |
+ net_disconnect 1 container_1 bridge |
|
| 298 |
+ dnet_cmd $(inst_id2port 1) container rm container_1 |
|
| 299 |
+ # test conmunications within internal network |
|
| 300 |
+ test_single_network_connectivity internal 3 |
|
| 301 |
+ dnet_cmd $(inst_id2port 1) network rm internal |
|
| 302 |
+} |