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 }