github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/libnetwork/cmd/proxy/network_proxy_test.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	"net"
     9  	"strings"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/ishidawataru/sctp"
    14  	// this takes care of the incontainer flag
    15  	_ "github.com/docker/libnetwork/testutils"
    16  )
    17  
    18  var testBuf = []byte("Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo")
    19  var testBufSize = len(testBuf)
    20  
    21  type EchoServer interface {
    22  	Run()
    23  	Close()
    24  	LocalAddr() net.Addr
    25  }
    26  
    27  type EchoServerOptions struct {
    28  	TCPHalfClose bool
    29  }
    30  
    31  type StreamEchoServer struct {
    32  	listener net.Listener
    33  	testCtx  *testing.T
    34  	opts     EchoServerOptions
    35  }
    36  
    37  type UDPEchoServer struct {
    38  	conn    net.PacketConn
    39  	testCtx *testing.T
    40  }
    41  
    42  func NewEchoServer(t *testing.T, proto, address string, opts EchoServerOptions) EchoServer {
    43  	var server EchoServer
    44  	if !strings.HasPrefix(proto, "tcp") && opts.TCPHalfClose {
    45  		t.Fatalf("TCPHalfClose is not supported for %s", proto)
    46  	}
    47  
    48  	switch {
    49  	case strings.HasPrefix(proto, "tcp"):
    50  		listener, err := net.Listen(proto, address)
    51  		if err != nil {
    52  			t.Fatal(err)
    53  		}
    54  		server = &StreamEchoServer{listener: listener, testCtx: t, opts: opts}
    55  	case strings.HasPrefix(proto, "udp"):
    56  		socket, err := net.ListenPacket(proto, address)
    57  		if err != nil {
    58  			t.Fatal(err)
    59  		}
    60  		server = &UDPEchoServer{conn: socket, testCtx: t}
    61  	case strings.HasPrefix(proto, "sctp"):
    62  		addr, err := sctp.ResolveSCTPAddr(proto, address)
    63  		if err != nil {
    64  			t.Fatal(err)
    65  		}
    66  		listener, err := sctp.ListenSCTP(proto, addr)
    67  		if err != nil {
    68  			t.Fatal(err)
    69  		}
    70  		server = &StreamEchoServer{listener: listener, testCtx: t}
    71  	default:
    72  		t.Fatalf("unknown protocol: %s", proto)
    73  	}
    74  	return server
    75  }
    76  
    77  func (server *StreamEchoServer) Run() {
    78  	go func() {
    79  		for {
    80  			client, err := server.listener.Accept()
    81  			if err != nil {
    82  				return
    83  			}
    84  			go func(client net.Conn) {
    85  				if server.opts.TCPHalfClose {
    86  					data, err := ioutil.ReadAll(client)
    87  					if err != nil {
    88  						server.testCtx.Logf("io.ReadAll() failed for the client: %v\n", err.Error())
    89  					}
    90  					if _, err := client.Write(data); err != nil {
    91  						server.testCtx.Logf("can't echo to the client: %v\n", err.Error())
    92  					}
    93  					client.(*net.TCPConn).CloseWrite()
    94  				} else {
    95  					if _, err := io.Copy(client, client); err != nil {
    96  						server.testCtx.Logf("can't echo to the client: %v\n", err.Error())
    97  					}
    98  					client.Close()
    99  				}
   100  			}(client)
   101  		}
   102  	}()
   103  }
   104  
   105  func (server *StreamEchoServer) LocalAddr() net.Addr { return server.listener.Addr() }
   106  func (server *StreamEchoServer) Close()              { server.listener.Close() }
   107  
   108  func (server *UDPEchoServer) Run() {
   109  	go func() {
   110  		readBuf := make([]byte, 1024)
   111  		for {
   112  			read, from, err := server.conn.ReadFrom(readBuf)
   113  			if err != nil {
   114  				return
   115  			}
   116  			for i := 0; i != read; {
   117  				written, err := server.conn.WriteTo(readBuf[i:read], from)
   118  				if err != nil {
   119  					break
   120  				}
   121  				i += written
   122  			}
   123  		}
   124  	}()
   125  }
   126  
   127  func (server *UDPEchoServer) LocalAddr() net.Addr { return server.conn.LocalAddr() }
   128  func (server *UDPEchoServer) Close()              { server.conn.Close() }
   129  
   130  func testProxyAt(t *testing.T, proto string, proxy Proxy, addr string, halfClose bool) {
   131  	defer proxy.Close()
   132  	go proxy.Run()
   133  	var client net.Conn
   134  	var err error
   135  	if strings.HasPrefix(proto, "sctp") {
   136  		var a *sctp.SCTPAddr
   137  		a, err = sctp.ResolveSCTPAddr(proto, addr)
   138  		if err != nil {
   139  			t.Fatal(err)
   140  		}
   141  		client, err = sctp.DialSCTP(proto, nil, a)
   142  	} else {
   143  		client, err = net.Dial(proto, addr)
   144  	}
   145  
   146  	if err != nil {
   147  		t.Fatalf("Can't connect to the proxy: %v", err)
   148  	}
   149  	defer client.Close()
   150  	client.SetDeadline(time.Now().Add(10 * time.Second))
   151  	if _, err = client.Write(testBuf); err != nil {
   152  		t.Fatal(err)
   153  	}
   154  	if halfClose {
   155  		if proto != "tcp" {
   156  			t.Fatalf("halfClose is not supported for %s", proto)
   157  		}
   158  		client.(*net.TCPConn).CloseWrite()
   159  	}
   160  	recvBuf := make([]byte, testBufSize)
   161  	if _, err = client.Read(recvBuf); err != nil {
   162  		t.Fatal(err)
   163  	}
   164  	if !bytes.Equal(testBuf, recvBuf) {
   165  		t.Fatal(fmt.Errorf("Expected [%v] but got [%v]", testBuf, recvBuf))
   166  	}
   167  }
   168  
   169  func testProxy(t *testing.T, proto string, proxy Proxy, halfClose bool) {
   170  	testProxyAt(t, proto, proxy, proxy.FrontendAddr().String(), halfClose)
   171  }
   172  
   173  func testTCP4Proxy(t *testing.T, halfClose bool) {
   174  	backend := NewEchoServer(t, "tcp", "127.0.0.1:0", EchoServerOptions{TCPHalfClose: halfClose})
   175  	defer backend.Close()
   176  	backend.Run()
   177  	frontendAddr := &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0}
   178  	proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
   179  	if err != nil {
   180  		t.Fatal(err)
   181  	}
   182  	testProxy(t, "tcp", proxy, halfClose)
   183  }
   184  
   185  func TestTCP4Proxy(t *testing.T) {
   186  	testTCP4Proxy(t, false)
   187  }
   188  
   189  func TestTCP4ProxyHalfClose(t *testing.T) {
   190  	testTCP4Proxy(t, true)
   191  }
   192  
   193  func TestTCP6Proxy(t *testing.T) {
   194  	t.Skip("Need to start CI docker with --ipv6")
   195  	backend := NewEchoServer(t, "tcp", "[::1]:0", EchoServerOptions{})
   196  	defer backend.Close()
   197  	backend.Run()
   198  	frontendAddr := &net.TCPAddr{IP: net.IPv6loopback, Port: 0}
   199  	proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
   200  	if err != nil {
   201  		t.Fatal(err)
   202  	}
   203  	testProxy(t, "tcp", proxy, false)
   204  }
   205  
   206  func TestTCPDualStackProxy(t *testing.T) {
   207  	// If I understand `godoc -src net favoriteAddrFamily` (used by the
   208  	// net.Listen* functions) correctly this should work, but it doesn't.
   209  	t.Skip("No support for dual stack yet")
   210  	backend := NewEchoServer(t, "tcp", "[::1]:0", EchoServerOptions{})
   211  	defer backend.Close()
   212  	backend.Run()
   213  	frontendAddr := &net.TCPAddr{IP: net.IPv6loopback, Port: 0}
   214  	proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
   215  	if err != nil {
   216  		t.Fatal(err)
   217  	}
   218  	ipv4ProxyAddr := &net.TCPAddr{
   219  		IP:   net.IPv4(127, 0, 0, 1),
   220  		Port: proxy.FrontendAddr().(*net.TCPAddr).Port,
   221  	}
   222  	testProxyAt(t, "tcp", proxy, ipv4ProxyAddr.String(), false)
   223  }
   224  
   225  func TestUDP4Proxy(t *testing.T) {
   226  	backend := NewEchoServer(t, "udp", "127.0.0.1:0", EchoServerOptions{})
   227  	defer backend.Close()
   228  	backend.Run()
   229  	frontendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0}
   230  	proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
   231  	if err != nil {
   232  		t.Fatal(err)
   233  	}
   234  	testProxy(t, "udp", proxy, false)
   235  }
   236  
   237  func TestUDP6Proxy(t *testing.T) {
   238  	t.Skip("Need to start CI docker with --ipv6")
   239  	backend := NewEchoServer(t, "udp", "[::1]:0", EchoServerOptions{})
   240  	defer backend.Close()
   241  	backend.Run()
   242  	frontendAddr := &net.UDPAddr{IP: net.IPv6loopback, Port: 0}
   243  	proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
   244  	if err != nil {
   245  		t.Fatal(err)
   246  	}
   247  	testProxy(t, "udp", proxy, false)
   248  }
   249  
   250  func TestUDPWriteError(t *testing.T) {
   251  	frontendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0}
   252  	// Hopefully, this port will be free: */
   253  	backendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 25587}
   254  	proxy, err := NewProxy(frontendAddr, backendAddr)
   255  	if err != nil {
   256  		t.Fatal(err)
   257  	}
   258  	defer proxy.Close()
   259  	go proxy.Run()
   260  	client, err := net.Dial("udp", "127.0.0.1:25587")
   261  	if err != nil {
   262  		t.Fatalf("Can't connect to the proxy: %v", err)
   263  	}
   264  	defer client.Close()
   265  	// Make sure the proxy doesn't stop when there is no actual backend:
   266  	client.Write(testBuf)
   267  	client.Write(testBuf)
   268  	backend := NewEchoServer(t, "udp", "127.0.0.1:25587", EchoServerOptions{})
   269  	defer backend.Close()
   270  	backend.Run()
   271  	client.SetDeadline(time.Now().Add(10 * time.Second))
   272  	if _, err = client.Write(testBuf); err != nil {
   273  		t.Fatal(err)
   274  	}
   275  	recvBuf := make([]byte, testBufSize)
   276  	if _, err = client.Read(recvBuf); err != nil {
   277  		t.Fatal(err)
   278  	}
   279  	if !bytes.Equal(testBuf, recvBuf) {
   280  		t.Fatal(fmt.Errorf("Expected [%v] but got [%v]", testBuf, recvBuf))
   281  	}
   282  }
   283  
   284  func TestSCTP4Proxy(t *testing.T) {
   285  	backend := NewEchoServer(t, "sctp", "127.0.0.1:0", EchoServerOptions{})
   286  	defer backend.Close()
   287  	backend.Run()
   288  	frontendAddr := &sctp.SCTPAddr{IPAddrs: []net.IPAddr{{IP: net.IPv4(127, 0, 0, 1)}}, Port: 0}
   289  	proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
   290  	if err != nil {
   291  		t.Fatal(err)
   292  	}
   293  	testProxy(t, "sctp", proxy, false)
   294  }
   295  
   296  func TestSCTP6Proxy(t *testing.T) {
   297  	t.Skip("Need to start CI docker with --ipv6")
   298  	backend := NewEchoServer(t, "sctp", "[::1]:0", EchoServerOptions{})
   299  	defer backend.Close()
   300  	backend.Run()
   301  	frontendAddr := &sctp.SCTPAddr{IPAddrs: []net.IPAddr{{IP: net.IPv6loopback}}, Port: 0}
   302  	proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
   303  	if err != nil {
   304  		t.Fatal(err)
   305  	}
   306  	testProxy(t, "sctp", proxy, false)
   307  }