github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/engine/integration/container/nat_test.go (about)

     1  package container // import "github.com/docker/docker/integration/container"
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"io"
     8  	"net"
     9  	"strings"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/docker/docker/api/types"
    14  	"github.com/docker/docker/integration/internal/container"
    15  	"github.com/docker/go-connections/nat"
    16  	"gotest.tools/v3/assert"
    17  	is "gotest.tools/v3/assert/cmp"
    18  	"gotest.tools/v3/poll"
    19  	"gotest.tools/v3/skip"
    20  )
    21  
    22  func TestNetworkNat(t *testing.T) {
    23  	skip.If(t, testEnv.OSType == "windows", "FIXME")
    24  	skip.If(t, testEnv.IsRemoteDaemon)
    25  
    26  	defer setupTest(t)()
    27  
    28  	msg := "it works"
    29  	startServerContainer(t, msg, 8080)
    30  
    31  	endpoint := getExternalAddress(t)
    32  	conn, err := net.Dial("tcp", net.JoinHostPort(endpoint.String(), "8080"))
    33  	assert.NilError(t, err)
    34  	defer conn.Close()
    35  
    36  	data, err := io.ReadAll(conn)
    37  	assert.NilError(t, err)
    38  	assert.Check(t, is.Equal(msg, strings.TrimSpace(string(data))))
    39  }
    40  
    41  func TestNetworkLocalhostTCPNat(t *testing.T) {
    42  	skip.If(t, testEnv.IsRemoteDaemon)
    43  
    44  	defer setupTest(t)()
    45  
    46  	msg := "hi yall"
    47  	startServerContainer(t, msg, 8081)
    48  
    49  	conn, err := net.Dial("tcp", "localhost:8081")
    50  	assert.NilError(t, err)
    51  	defer conn.Close()
    52  
    53  	data, err := io.ReadAll(conn)
    54  	assert.NilError(t, err)
    55  	assert.Check(t, is.Equal(msg, strings.TrimSpace(string(data))))
    56  }
    57  
    58  func TestNetworkLoopbackNat(t *testing.T) {
    59  	skip.If(t, testEnv.OSType == "windows", "FIXME")
    60  	skip.If(t, testEnv.IsRemoteDaemon)
    61  
    62  	defer setupTest(t)()
    63  
    64  	msg := "it works"
    65  	serverContainerID := startServerContainer(t, msg, 8080)
    66  
    67  	endpoint := getExternalAddress(t)
    68  
    69  	client := testEnv.APIClient()
    70  	ctx := context.Background()
    71  
    72  	cID := container.Run(ctx, t, client,
    73  		container.WithCmd("sh", "-c", fmt.Sprintf("stty raw && nc -w 1 %s 8080", endpoint.String())),
    74  		container.WithTty(true),
    75  		container.WithNetworkMode("container:"+serverContainerID),
    76  	)
    77  
    78  	poll.WaitOn(t, container.IsStopped(ctx, client, cID), poll.WithDelay(100*time.Millisecond))
    79  
    80  	body, err := client.ContainerLogs(ctx, cID, types.ContainerLogsOptions{
    81  		ShowStdout: true,
    82  	})
    83  	assert.NilError(t, err)
    84  	defer body.Close()
    85  
    86  	var b bytes.Buffer
    87  	_, err = io.Copy(&b, body)
    88  	assert.NilError(t, err)
    89  
    90  	assert.Check(t, is.Equal(msg, strings.TrimSpace(b.String())))
    91  }
    92  
    93  func startServerContainer(t *testing.T, msg string, port int) string {
    94  	t.Helper()
    95  	client := testEnv.APIClient()
    96  	ctx := context.Background()
    97  
    98  	cID := container.Run(ctx, t, client,
    99  		container.WithName("server-"+t.Name()),
   100  		container.WithCmd("sh", "-c", fmt.Sprintf("echo %q | nc -lp %d", msg, port)),
   101  		container.WithExposedPorts(fmt.Sprintf("%d/tcp", port)),
   102  		func(c *container.TestContainerConfig) {
   103  			c.HostConfig.PortBindings = nat.PortMap{
   104  				nat.Port(fmt.Sprintf("%d/tcp", port)): []nat.PortBinding{
   105  					{
   106  						HostPort: fmt.Sprintf("%d", port),
   107  					},
   108  				},
   109  			}
   110  		})
   111  
   112  	poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
   113  
   114  	return cID
   115  }
   116  
   117  // getExternalAddress() returns the external IP-address from eth0. If eth0 has
   118  // multiple IP-addresses, it returns the first IPv4 IP-address; if no IPv4
   119  // address is present, it returns the first IP-address found.
   120  func getExternalAddress(t *testing.T) net.IP {
   121  	t.Helper()
   122  	iface, err := net.InterfaceByName("eth0")
   123  	skip.If(t, err != nil, "Test not running with `make test-integration`. Interface eth0 not found: %s", err)
   124  
   125  	ifaceAddrs, err := iface.Addrs()
   126  	assert.NilError(t, err)
   127  	assert.Check(t, 0 != len(ifaceAddrs))
   128  
   129  	if len(ifaceAddrs) > 1 {
   130  		// Prefer IPv4 address if multiple addresses found, as rootlesskit
   131  		// does not handle IPv6 currently https://github.com/moby/moby/pull/41908#issuecomment-774200001
   132  		for _, a := range ifaceAddrs {
   133  			ifaceIP, _, err := net.ParseCIDR(a.String())
   134  			assert.NilError(t, err)
   135  			if ifaceIP.To4() != nil {
   136  				return ifaceIP
   137  			}
   138  		}
   139  	}
   140  	ifaceIP, _, err := net.ParseCIDR(ifaceAddrs[0].String())
   141  	assert.NilError(t, err)
   142  
   143  	return ifaceIP
   144  }