11package networking
22
33import (
4+ "bytes"
45 "context"
56 "fmt"
67 "net"
@@ -16,10 +17,12 @@ import (
1617
1718 containertypes "github.com/docker/docker/api/types/container"
1819 networktypes "github.com/docker/docker/api/types/network"
20+ "github.com/docker/docker/client"
1921 "github.com/docker/docker/integration/internal/container"
2022 "github.com/docker/docker/integration/internal/network"
2123 "github.com/docker/docker/internal/testutils/networking"
2224 "github.com/docker/docker/libnetwork/drivers/bridge"
25+ "github.com/docker/docker/pkg/stdcopy"
2326 "github.com/docker/docker/testutil"
2427 "github.com/docker/docker/testutil/daemon"
2528 "github.com/docker/go-connections/nat"
@@ -781,3 +784,106 @@ func TestDirectRoutingOpenPorts(t *testing.T) {
781784 })
782785 }
783786}
787+
788+ // TestAccessPublishedPortFromAnotherNetwork checks that a container can access
789+ // ports published on the host by a container attached to a different network
790+ // using both its gateway IP address, and the host IP address.
791+ //
792+ // Regression test for https://github.com/moby/moby/pull/49310.
793+ func TestAccessPublishedPortFromAnotherNetwork (t * testing.T ) {
794+ skip .If (t , testEnv .IsRootless , "rootlesskit maps ports on loopback in its own netns" )
795+
796+ ctx := setupTest (t )
797+
798+ d := daemon .New (t )
799+ d .StartWithBusybox (ctx , t )
800+ defer d .Stop (t )
801+
802+ c := d .NewClientT (t )
803+ defer c .Close ()
804+
805+ const servnet = "servnet"
806+ network .CreateNoError (ctx , t , c , servnet ,
807+ network .WithDriver ("bridge" ),
808+ network .WithOption (bridge .BridgeName , servnet ),
809+ network .WithIPv6 (),
810+ )
811+ defer network .RemoveNoError (ctx , t , c , servnet )
812+
813+ const clientnet = "clientnet"
814+ network .CreateNoError (ctx , t , c , clientnet ,
815+ network .WithDriver ("bridge" ),
816+ network .WithOption (bridge .BridgeName , clientnet ),
817+ network .WithIPv6 (),
818+ network .WithIPAM ("192.168.123.0/24" , "192.168.123.1" ),
819+ network .WithIPAM ("fde5:4427:8b32::/64" , "fde5:4427:8b32::1" ),
820+ )
821+ defer network .RemoveNoError (ctx , t , c , clientnet )
822+
823+ const (
824+ hostIPv4 = "10.0.128.2"
825+ hostIPv6 = "fd3f:69a1:3233::2"
826+ )
827+
828+ defer enableIPv6OnAll (t )()
829+ // Add well-known addresses to the host.
830+ assert .NilError (t , exec .Command ("ip" , "addr" , "add" , hostIPv4 + "/24" , "dev" , "eth0" ).Run ())
831+ defer exec .Command ("ip" , "addr" , "del" , hostIPv4 + "/24" , "dev" , "eth0" ).Run ()
832+ assert .NilError (t , exec .Command ("ip" , "addr" , "add" , hostIPv6 + "/64" , "dev" , "eth0" ).Run ())
833+ defer exec .Command ("ip" , "addr" , "del" , hostIPv6 + "/64" , "dev" , "eth0" ).Run ()
834+
835+ for _ , tc := range []struct {
836+ name string
837+ daddr string
838+ }{
839+ {
840+ name : "IPv4/Gateway" ,
841+ daddr : "192.168.123.1" ,
842+ },
843+ {
844+ name : "IPv6/Gateway" ,
845+ daddr : "fde5:4427:8b32::1" ,
846+ },
847+ {
848+ name : "IPv4/Host" ,
849+ daddr : hostIPv4 ,
850+ },
851+ {
852+ name : "IPv6/Host" ,
853+ daddr : hostIPv6 ,
854+ },
855+ } {
856+ t .Run (tc .name , func (t * testing.T ) {
857+ serverID := container .Run (ctx , t , c ,
858+ container .WithName ("server" ),
859+ container .WithCmd ("nc" , "-lp" , "5000" ),
860+ container .WithExposedPorts ("5000/tcp" ),
861+ container .WithPortMap (nat.PortMap {"5000/tcp" : {{HostPort : "5000" }}}),
862+ container .WithNetworkMode (servnet ))
863+ defer c .ContainerRemove (ctx , serverID , containertypes.RemoveOptions {Force : true })
864+
865+ clientID := container .Run (ctx , t , c ,
866+ container .WithName ("client" ),
867+ container .WithCmd ("/bin/sh" , "-c" , fmt .Sprintf ("echo foobar | nc -w1 %s 5000" , tc .daddr )),
868+ container .WithNetworkMode (clientnet ))
869+ defer c .ContainerRemove (ctx , clientID , containertypes.RemoveOptions {Force : true })
870+
871+ logs := getContainerStdout (t , ctx , c , serverID )
872+ assert .Assert (t , is .Contains (logs , "foobar" ), "Payload was not received by the server container" )
873+ })
874+ }
875+ }
876+
877+ func getContainerStdout (t * testing.T , ctx context.Context , c * client.Client , ctrID string ) string {
878+ logReader , err := c .ContainerLogs (ctx , ctrID , containertypes.LogsOptions {
879+ ShowStdout : true ,
880+ })
881+ assert .NilError (t , err )
882+ defer logReader .Close ()
883+
884+ var logs bytes.Buffer
885+ _ , err = stdcopy .StdCopy (& logs , nil , logReader )
886+ assert .NilError (t , err )
887+
888+ return logs .String ()
889+ }
0 commit comments