github.com/pmorton/docker@v1.5.0/pkg/proxy/network_proxy_test.go (about) 1 package proxy 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "net" 8 "strings" 9 "testing" 10 "time" 11 ) 12 13 var testBuf = []byte("Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo") 14 var testBufSize = len(testBuf) 15 16 type EchoServer interface { 17 Run() 18 Close() 19 LocalAddr() net.Addr 20 } 21 22 type TCPEchoServer struct { 23 listener net.Listener 24 testCtx *testing.T 25 } 26 27 type UDPEchoServer struct { 28 conn net.PacketConn 29 testCtx *testing.T 30 } 31 32 func NewEchoServer(t *testing.T, proto, address string) EchoServer { 33 var server EchoServer 34 if strings.HasPrefix(proto, "tcp") { 35 listener, err := net.Listen(proto, address) 36 if err != nil { 37 t.Fatal(err) 38 } 39 server = &TCPEchoServer{listener: listener, testCtx: t} 40 } else { 41 socket, err := net.ListenPacket(proto, address) 42 if err != nil { 43 t.Fatal(err) 44 } 45 server = &UDPEchoServer{conn: socket, testCtx: t} 46 } 47 return server 48 } 49 50 func (server *TCPEchoServer) Run() { 51 go func() { 52 for { 53 client, err := server.listener.Accept() 54 if err != nil { 55 return 56 } 57 go func(client net.Conn) { 58 if _, err := io.Copy(client, client); err != nil { 59 server.testCtx.Logf("can't echo to the client: %v\n", err.Error()) 60 } 61 client.Close() 62 }(client) 63 } 64 }() 65 } 66 67 func (server *TCPEchoServer) LocalAddr() net.Addr { return server.listener.Addr() } 68 func (server *TCPEchoServer) Close() { server.listener.Addr() } 69 70 func (server *UDPEchoServer) Run() { 71 go func() { 72 readBuf := make([]byte, 1024) 73 for { 74 read, from, err := server.conn.ReadFrom(readBuf) 75 if err != nil { 76 return 77 } 78 for i := 0; i != read; { 79 written, err := server.conn.WriteTo(readBuf[i:read], from) 80 if err != nil { 81 break 82 } 83 i += written 84 } 85 } 86 }() 87 } 88 89 func (server *UDPEchoServer) LocalAddr() net.Addr { return server.conn.LocalAddr() } 90 func (server *UDPEchoServer) Close() { server.conn.Close() } 91 92 func testProxyAt(t *testing.T, proto string, proxy Proxy, addr string) { 93 defer proxy.Close() 94 go proxy.Run() 95 client, err := net.Dial(proto, addr) 96 if err != nil { 97 t.Fatalf("Can't connect to the proxy: %v", err) 98 } 99 defer client.Close() 100 client.SetDeadline(time.Now().Add(10 * time.Second)) 101 if _, err = client.Write(testBuf); err != nil { 102 t.Fatal(err) 103 } 104 recvBuf := make([]byte, testBufSize) 105 if _, err = client.Read(recvBuf); err != nil { 106 t.Fatal(err) 107 } 108 if !bytes.Equal(testBuf, recvBuf) { 109 t.Fatal(fmt.Errorf("Expected [%v] but got [%v]", testBuf, recvBuf)) 110 } 111 } 112 113 func testProxy(t *testing.T, proto string, proxy Proxy) { 114 testProxyAt(t, proto, proxy, proxy.FrontendAddr().String()) 115 } 116 117 func TestTCP4Proxy(t *testing.T) { 118 backend := NewEchoServer(t, "tcp", "127.0.0.1:0") 119 defer backend.Close() 120 backend.Run() 121 frontendAddr := &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0} 122 proxy, err := NewProxy(frontendAddr, backend.LocalAddr()) 123 if err != nil { 124 t.Fatal(err) 125 } 126 testProxy(t, "tcp", proxy) 127 } 128 129 func TestTCP6Proxy(t *testing.T) { 130 backend := NewEchoServer(t, "tcp", "[::1]:0") 131 defer backend.Close() 132 backend.Run() 133 frontendAddr := &net.TCPAddr{IP: net.IPv6loopback, Port: 0} 134 proxy, err := NewProxy(frontendAddr, backend.LocalAddr()) 135 if err != nil { 136 t.Fatal(err) 137 } 138 testProxy(t, "tcp", proxy) 139 } 140 141 func TestTCPDualStackProxy(t *testing.T) { 142 // If I understand `godoc -src net favoriteAddrFamily` (used by the 143 // net.Listen* functions) correctly this should work, but it doesn't. 144 t.Skip("No support for dual stack yet") 145 backend := NewEchoServer(t, "tcp", "[::1]:0") 146 defer backend.Close() 147 backend.Run() 148 frontendAddr := &net.TCPAddr{IP: net.IPv6loopback, Port: 0} 149 proxy, err := NewProxy(frontendAddr, backend.LocalAddr()) 150 if err != nil { 151 t.Fatal(err) 152 } 153 ipv4ProxyAddr := &net.TCPAddr{ 154 IP: net.IPv4(127, 0, 0, 1), 155 Port: proxy.FrontendAddr().(*net.TCPAddr).Port, 156 } 157 testProxyAt(t, "tcp", proxy, ipv4ProxyAddr.String()) 158 } 159 160 func TestUDP4Proxy(t *testing.T) { 161 backend := NewEchoServer(t, "udp", "127.0.0.1:0") 162 defer backend.Close() 163 backend.Run() 164 frontendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0} 165 proxy, err := NewProxy(frontendAddr, backend.LocalAddr()) 166 if err != nil { 167 t.Fatal(err) 168 } 169 testProxy(t, "udp", proxy) 170 } 171 172 func TestUDP6Proxy(t *testing.T) { 173 backend := NewEchoServer(t, "udp", "[::1]:0") 174 defer backend.Close() 175 backend.Run() 176 frontendAddr := &net.UDPAddr{IP: net.IPv6loopback, Port: 0} 177 proxy, err := NewProxy(frontendAddr, backend.LocalAddr()) 178 if err != nil { 179 t.Fatal(err) 180 } 181 testProxy(t, "udp", proxy) 182 } 183 184 func TestUDPWriteError(t *testing.T) { 185 frontendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0} 186 // Hopefully, this port will be free: */ 187 backendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 25587} 188 proxy, err := NewProxy(frontendAddr, backendAddr) 189 if err != nil { 190 t.Fatal(err) 191 } 192 defer proxy.Close() 193 go proxy.Run() 194 client, err := net.Dial("udp", "127.0.0.1:25587") 195 if err != nil { 196 t.Fatalf("Can't connect to the proxy: %v", err) 197 } 198 defer client.Close() 199 // Make sure the proxy doesn't stop when there is no actual backend: 200 client.Write(testBuf) 201 client.Write(testBuf) 202 backend := NewEchoServer(t, "udp", "127.0.0.1:25587") 203 defer backend.Close() 204 backend.Run() 205 client.SetDeadline(time.Now().Add(10 * time.Second)) 206 if _, err = client.Write(testBuf); err != nil { 207 t.Fatal(err) 208 } 209 recvBuf := make([]byte, testBufSize) 210 if _, err = client.Read(recvBuf); err != nil { 211 t.Fatal(err) 212 } 213 if !bytes.Equal(testBuf, recvBuf) { 214 t.Fatal(fmt.Errorf("Expected [%v] but got [%v]", testBuf, recvBuf)) 215 } 216 }