4
4
"context"
5
5
"flag"
6
6
"fmt"
7
+ "net"
7
8
"os/exec"
8
9
"regexp"
9
10
"strconv"
@@ -17,6 +18,7 @@ import (
17
18
"github.com/docker/docker/integration/internal/container"
18
19
"github.com/docker/docker/integration/internal/network"
19
20
n "github.com/docker/docker/integration/network"
21
+ "github.com/docker/docker/internal/testutils/networking"
20
22
"github.com/docker/docker/libnetwork/drivers/bridge"
21
23
"github.com/docker/docker/libnetwork/netlabel"
22
24
"github.com/docker/docker/testutil"
@@ -340,6 +342,153 @@ func TestBridgeINC(t *testing.T) {
340
342
}
341
343
}
342
344
345
+ // TestBridgeINCRouted makes sure a container on a gateway-mode=nat network can establish
346
+ // a connection to a container on a gateway-mode=routed network, but not vice-versa.
347
+ func TestBridgeINCRouted (t * testing.T ) {
348
+ ctx := setupTest (t )
349
+
350
+ d := daemon .New (t )
351
+ d .StartWithBusybox (ctx , t )
352
+ t .Cleanup (func () { d .Stop (t ) })
353
+
354
+ c := d .NewClientT (t )
355
+ t .Cleanup (func () { c .Close () })
356
+
357
+ type ctrDesc struct {
358
+ id string
359
+ ipv4 string
360
+ ipv6 string
361
+ }
362
+
363
+ // Create a network and run a container on it.
364
+ // Run http servers on ports 80 and 81, but only map/open port 80.
365
+ createNet := func (gwMode string ) ctrDesc {
366
+ netName := "test-" + gwMode
367
+ network .CreateNoError (ctx , t , c , netName ,
368
+ network .WithDriver ("bridge" ),
369
+ network .WithIPv6 (),
370
+ network .WithOption (bridge .BridgeName , "br-" + gwMode ),
371
+ network .WithOption (bridge .IPv4GatewayMode , gwMode ),
372
+ network .WithOption (bridge .IPv6GatewayMode , gwMode ),
373
+ )
374
+ t .Cleanup (func () {
375
+ network .RemoveNoError (ctx , t , c , netName )
376
+ })
377
+
378
+ ctrId := container .Run (ctx , t , c ,
379
+ container .WithNetworkMode (netName ),
380
+ container .WithName ("ctr-" + gwMode ),
381
+ container .WithExposedPorts ("80/tcp" ),
382
+ container .WithPortMap (nat.PortMap {"80/tcp" : {}}),
383
+ )
384
+ t .Cleanup (func () {
385
+ c .ContainerRemove (ctx , ctrId , containertypes.RemoveOptions {Force : true })
386
+ })
387
+
388
+ container .ExecT (ctx , t , c , ctrId , []string {"httpd" , "-p" , "80" })
389
+ container .ExecT (ctx , t , c , ctrId , []string {"httpd" , "-p" , "81" })
390
+
391
+ insp := container .Inspect (ctx , t , c , ctrId )
392
+ return ctrDesc {
393
+ id : ctrId ,
394
+ ipv4 : insp .NetworkSettings .Networks [netName ].IPAddress ,
395
+ ipv6 : insp .NetworkSettings .Networks [netName ].GlobalIPv6Address ,
396
+ }
397
+ }
398
+
399
+ natDesc := createNet ("nat" )
400
+ routedDesc := createNet ("routed" )
401
+
402
+ const (
403
+ httpSuccess = "404 Not Found"
404
+ httpFail = "download timed out"
405
+ pingSuccess = 0
406
+ pingFail = 1
407
+ )
408
+
409
+ testcases := []struct {
410
+ name string
411
+ from ctrDesc
412
+ to ctrDesc
413
+ port string
414
+ expPingExit int
415
+ expHttpStderr string
416
+ }{
417
+ {
418
+ name : "nat to routed open port" ,
419
+ from : natDesc ,
420
+ to : routedDesc ,
421
+ port : "80" ,
422
+ expPingExit : pingSuccess ,
423
+ expHttpStderr : httpSuccess ,
424
+ },
425
+ {
426
+ name : "nat to routed closed port" ,
427
+ from : natDesc ,
428
+ to : routedDesc ,
429
+ port : "81" ,
430
+ expPingExit : pingSuccess ,
431
+ expHttpStderr : httpFail ,
432
+ },
433
+ {
434
+ name : "routed to nat open port" ,
435
+ from : routedDesc ,
436
+ to : natDesc ,
437
+ port : "80" ,
438
+ expPingExit : pingFail ,
439
+ expHttpStderr : httpFail ,
440
+ },
441
+ {
442
+ name : "routed to nat closed port" ,
443
+ from : routedDesc ,
444
+ to : natDesc ,
445
+ port : "81" ,
446
+ expPingExit : pingFail ,
447
+ expHttpStderr : httpFail ,
448
+ },
449
+ }
450
+
451
+ for _ , fwdPolicy := range []string {"ACCEPT" , "DROP" } {
452
+ networking .SetFilterForwardPolicies (t , fwdPolicy )
453
+ t .Run (fwdPolicy , func (t * testing.T ) {
454
+ for _ , tc := range testcases {
455
+ t .Run (tc .name + "/v4/ping" , func (t * testing.T ) {
456
+ t .Parallel ()
457
+ ctx := testutil .StartSpan (ctx , t )
458
+ pingRes4 := container .ExecT (ctx , t , c , tc .from .id , []string {
459
+ "ping" , "-4" , "-c1" , "-W3" , tc .to .ipv4 ,
460
+ })
461
+ assert .Check (t , is .Equal (pingRes4 .ExitCode , tc .expPingExit ))
462
+ })
463
+ t .Run (tc .name + "/v6/ping" , func (t * testing.T ) {
464
+ t .Parallel ()
465
+ ctx := testutil .StartSpan (ctx , t )
466
+ pingRes6 := container .ExecT (ctx , t , c , tc .from .id , []string {
467
+ "ping" , "-6" , "-c1" , "-W3" , tc .to .ipv6 ,
468
+ })
469
+ assert .Check (t , is .Equal (pingRes6 .ExitCode , tc .expPingExit ))
470
+ })
471
+ t .Run (tc .name + "/v4/http" , func (t * testing.T ) {
472
+ t .Parallel ()
473
+ ctx := testutil .StartSpan (ctx , t )
474
+ httpRes4 := container .ExecT (ctx , t , c , tc .from .id , []string {
475
+ "wget" , "-T3" , "http://" + net .JoinHostPort (tc .to .ipv4 , tc .port ),
476
+ })
477
+ assert .Check (t , is .Contains (httpRes4 .Stderr (), tc .expHttpStderr ))
478
+ })
479
+ t .Run (tc .name + "/v6/http" , func (t * testing.T ) {
480
+ t .Parallel ()
481
+ ctx := testutil .StartSpan (ctx , t )
482
+ httpRes6 := container .ExecT (ctx , t , c , tc .from .id , []string {
483
+ "wget" , "-T3" , "http://" + net .JoinHostPort (tc .to .ipv6 , tc .port ),
484
+ })
485
+ assert .Check (t , is .Contains (httpRes6 .Stderr (), tc .expHttpStderr ))
486
+ })
487
+ }
488
+ })
489
+ }
490
+ }
491
+
343
492
func TestDefaultBridgeIPv6 (t * testing.T ) {
344
493
ctx := setupTest (t )
345
494
0 commit comments