github.com/TugasAkhir-QUIC/quic-go@v0.0.2-0.20240215011318-d20e25a9054c/transport_test.go (about) 1 package quic 2 3 import ( 4 "bytes" 5 "context" 6 "crypto/rand" 7 "crypto/tls" 8 "errors" 9 "net" 10 "syscall" 11 "time" 12 13 mocklogging "github.com/TugasAkhir-QUIC/quic-go/internal/mocks/logging" 14 "github.com/TugasAkhir-QUIC/quic-go/internal/protocol" 15 "github.com/TugasAkhir-QUIC/quic-go/internal/wire" 16 "github.com/TugasAkhir-QUIC/quic-go/logging" 17 18 . "github.com/onsi/ginkgo/v2" 19 . "github.com/onsi/gomega" 20 "go.uber.org/mock/gomock" 21 ) 22 23 var _ = Describe("Transport", func() { 24 type packetToRead struct { 25 addr net.Addr 26 data []byte 27 err error 28 } 29 30 getPacketWithPacketType := func(connID protocol.ConnectionID, t protocol.PacketType, length protocol.ByteCount) []byte { 31 b, err := (&wire.ExtendedHeader{ 32 Header: wire.Header{ 33 Type: t, 34 DestConnectionID: connID, 35 Length: length, 36 Version: protocol.Version1, 37 }, 38 PacketNumberLen: protocol.PacketNumberLen2, 39 }).Append(nil, protocol.Version1) 40 Expect(err).ToNot(HaveOccurred()) 41 return b 42 } 43 44 getPacket := func(connID protocol.ConnectionID) []byte { 45 return getPacketWithPacketType(connID, protocol.PacketTypeHandshake, 2) 46 } 47 48 newMockPacketConn := func(packetChan <-chan packetToRead) *MockPacketConn { 49 conn := NewMockPacketConn(mockCtrl) 50 conn.EXPECT().LocalAddr().Return(&net.UDPAddr{}).AnyTimes() 51 conn.EXPECT().ReadFrom(gomock.Any()).DoAndReturn(func(b []byte) (int, net.Addr, error) { 52 p, ok := <-packetChan 53 if !ok { 54 return 0, nil, errors.New("closed") 55 } 56 return copy(b, p.data), p.addr, p.err 57 }).AnyTimes() 58 // for shutdown 59 conn.EXPECT().SetReadDeadline(gomock.Any()).AnyTimes() 60 return conn 61 } 62 63 It("handles packets for different packet handlers on the same packet conn", func() { 64 packetChan := make(chan packetToRead) 65 tr := &Transport{Conn: newMockPacketConn(packetChan)} 66 tr.init(true) 67 phm := NewMockPacketHandlerManager(mockCtrl) 68 tr.handlerMap = phm 69 connID1 := protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5, 6, 7, 8}) 70 connID2 := protocol.ParseConnectionID([]byte{8, 7, 6, 5, 4, 3, 2, 1}) 71 72 handled := make(chan struct{}, 2) 73 phm.EXPECT().Get(connID1).DoAndReturn(func(protocol.ConnectionID) (packetHandler, bool) { 74 h := NewMockPacketHandler(mockCtrl) 75 h.EXPECT().handlePacket(gomock.Any()).Do(func(p receivedPacket) { 76 defer GinkgoRecover() 77 connID, err := wire.ParseConnectionID(p.data, 0) 78 Expect(err).ToNot(HaveOccurred()) 79 Expect(connID).To(Equal(connID1)) 80 handled <- struct{}{} 81 }) 82 return h, true 83 }) 84 phm.EXPECT().Get(connID2).DoAndReturn(func(protocol.ConnectionID) (packetHandler, bool) { 85 h := NewMockPacketHandler(mockCtrl) 86 h.EXPECT().handlePacket(gomock.Any()).Do(func(p receivedPacket) { 87 defer GinkgoRecover() 88 connID, err := wire.ParseConnectionID(p.data, 0) 89 Expect(err).ToNot(HaveOccurred()) 90 Expect(connID).To(Equal(connID2)) 91 handled <- struct{}{} 92 }) 93 return h, true 94 }) 95 96 packetChan <- packetToRead{data: getPacket(connID1)} 97 packetChan <- packetToRead{data: getPacket(connID2)} 98 99 Eventually(handled).Should(Receive()) 100 Eventually(handled).Should(Receive()) 101 102 // shutdown 103 phm.EXPECT().Close(gomock.Any()) 104 close(packetChan) 105 tr.Close() 106 }) 107 108 It("closes listeners", func() { 109 packetChan := make(chan packetToRead) 110 tr := &Transport{Conn: newMockPacketConn(packetChan)} 111 defer tr.Close() 112 ln, err := tr.Listen(&tls.Config{}, nil) 113 Expect(err).ToNot(HaveOccurred()) 114 phm := NewMockPacketHandlerManager(mockCtrl) 115 tr.handlerMap = phm 116 117 Expect(ln.Close()).To(Succeed()) 118 119 // shutdown 120 phm.EXPECT().Close(gomock.Any()) 121 close(packetChan) 122 tr.Close() 123 }) 124 125 It("drops unparseable QUIC packets", func() { 126 addr := &net.UDPAddr{IP: net.IPv4(9, 8, 7, 6), Port: 1234} 127 packetChan := make(chan packetToRead) 128 t, tracer := mocklogging.NewMockTracer(mockCtrl) 129 tr := &Transport{ 130 Conn: newMockPacketConn(packetChan), 131 ConnectionIDLength: 10, 132 Tracer: t, 133 } 134 tr.init(true) 135 dropped := make(chan struct{}) 136 tracer.EXPECT().DroppedPacket(addr, logging.PacketTypeNotDetermined, protocol.ByteCount(4), logging.PacketDropHeaderParseError).Do(func(net.Addr, logging.PacketType, protocol.ByteCount, logging.PacketDropReason) { close(dropped) }) 137 packetChan <- packetToRead{ 138 addr: addr, 139 data: []byte{0x40 /* set the QUIC bit */, 1, 2, 3}, 140 } 141 Eventually(dropped).Should(BeClosed()) 142 143 // shutdown 144 tracer.EXPECT().Close() 145 close(packetChan) 146 tr.Close() 147 }) 148 149 It("closes when reading from the conn fails", func() { 150 packetChan := make(chan packetToRead) 151 tr := Transport{Conn: newMockPacketConn(packetChan)} 152 defer tr.Close() 153 phm := NewMockPacketHandlerManager(mockCtrl) 154 tr.init(true) 155 tr.handlerMap = phm 156 157 done := make(chan struct{}) 158 phm.EXPECT().Close(gomock.Any()).Do(func(error) { close(done) }) 159 packetChan <- packetToRead{err: errors.New("read failed")} 160 Eventually(done).Should(BeClosed()) 161 162 // shutdown 163 close(packetChan) 164 tr.Close() 165 }) 166 167 It("continues listening after temporary errors", func() { 168 packetChan := make(chan packetToRead) 169 tr := Transport{Conn: newMockPacketConn(packetChan)} 170 defer tr.Close() 171 phm := NewMockPacketHandlerManager(mockCtrl) 172 tr.init(true) 173 tr.handlerMap = phm 174 175 tempErr := deadlineError{} 176 Expect(tempErr.Temporary()).To(BeTrue()) 177 packetChan <- packetToRead{err: tempErr} 178 // don't expect any calls to phm.Close 179 time.Sleep(50 * time.Millisecond) 180 181 // shutdown 182 phm.EXPECT().Close(gomock.Any()) 183 close(packetChan) 184 tr.Close() 185 }) 186 187 It("handles short header packets resets", func() { 188 connID := protocol.ParseConnectionID([]byte{2, 3, 4, 5}) 189 packetChan := make(chan packetToRead) 190 tr := Transport{ 191 Conn: newMockPacketConn(packetChan), 192 ConnectionIDLength: connID.Len(), 193 } 194 tr.init(true) 195 defer tr.Close() 196 phm := NewMockPacketHandlerManager(mockCtrl) 197 tr.handlerMap = phm 198 199 var token protocol.StatelessResetToken 200 rand.Read(token[:]) 201 202 var b []byte 203 b, err := wire.AppendShortHeader(b, connID, 1337, 2, protocol.KeyPhaseOne) 204 Expect(err).ToNot(HaveOccurred()) 205 b = append(b, token[:]...) 206 conn := NewMockPacketHandler(mockCtrl) 207 gomock.InOrder( 208 phm.EXPECT().Get(connID).Return(conn, true), 209 conn.EXPECT().handlePacket(gomock.Any()).Do(func(p receivedPacket) { 210 Expect(p.data).To(Equal(b)) 211 Expect(p.rcvTime).To(BeTemporally("~", time.Now(), time.Second)) 212 }), 213 ) 214 packetChan <- packetToRead{data: b} 215 216 // shutdown 217 phm.EXPECT().Close(gomock.Any()) 218 close(packetChan) 219 tr.Close() 220 }) 221 222 It("handles stateless resets", func() { 223 connID := protocol.ParseConnectionID([]byte{2, 3, 4, 5}) 224 packetChan := make(chan packetToRead) 225 tr := Transport{ 226 Conn: newMockPacketConn(packetChan), 227 ConnectionIDLength: connID.Len(), 228 } 229 tr.init(true) 230 defer tr.Close() 231 phm := NewMockPacketHandlerManager(mockCtrl) 232 tr.handlerMap = phm 233 234 var token protocol.StatelessResetToken 235 rand.Read(token[:]) 236 237 var b []byte 238 b, err := wire.AppendShortHeader(b, connID, 1337, 2, protocol.KeyPhaseOne) 239 Expect(err).ToNot(HaveOccurred()) 240 b = append(b, token[:]...) 241 conn := NewMockPacketHandler(mockCtrl) 242 destroyed := make(chan struct{}) 243 gomock.InOrder( 244 phm.EXPECT().Get(connID), 245 phm.EXPECT().GetByResetToken(token).Return(conn, true), 246 conn.EXPECT().destroy(gomock.Any()).Do(func(err error) { 247 Expect(err).To(MatchError(&StatelessResetError{Token: token})) 248 close(destroyed) 249 }), 250 ) 251 packetChan <- packetToRead{data: b} 252 Eventually(destroyed).Should(BeClosed()) 253 254 // shutdown 255 phm.EXPECT().Close(gomock.Any()) 256 close(packetChan) 257 tr.Close() 258 }) 259 260 It("sends stateless resets", func() { 261 connID := protocol.ParseConnectionID([]byte{2, 3, 4, 5}) 262 packetChan := make(chan packetToRead) 263 conn := newMockPacketConn(packetChan) 264 tr := Transport{ 265 Conn: conn, 266 StatelessResetKey: &StatelessResetKey{1, 2, 3, 4}, 267 ConnectionIDLength: connID.Len(), 268 } 269 tr.init(true) 270 defer tr.Close() 271 phm := NewMockPacketHandlerManager(mockCtrl) 272 tr.handlerMap = phm 273 274 var b []byte 275 b, err := wire.AppendShortHeader(b, connID, 1337, 2, protocol.KeyPhaseOne) 276 Expect(err).ToNot(HaveOccurred()) 277 b = append(b, make([]byte, protocol.MinStatelessResetSize-len(b)+1)...) 278 279 var token protocol.StatelessResetToken 280 rand.Read(token[:]) 281 written := make(chan struct{}) 282 gomock.InOrder( 283 phm.EXPECT().Get(connID), 284 phm.EXPECT().GetByResetToken(gomock.Any()), 285 phm.EXPECT().GetStatelessResetToken(connID).Return(token), 286 conn.EXPECT().WriteTo(gomock.Any(), gomock.Any()).Do(func(b []byte, _ net.Addr) (int, error) { 287 defer close(written) 288 Expect(bytes.Contains(b, token[:])).To(BeTrue()) 289 return len(b), nil 290 }), 291 ) 292 packetChan <- packetToRead{data: b} 293 Eventually(written).Should(BeClosed()) 294 295 // shutdown 296 phm.EXPECT().Close(gomock.Any()) 297 close(packetChan) 298 tr.Close() 299 }) 300 301 It("closes uninitialized Transport and closes underlying PacketConn", func() { 302 packetChan := make(chan packetToRead) 303 pconn := newMockPacketConn(packetChan) 304 305 tr := &Transport{ 306 Conn: pconn, 307 createdConn: true, // owns pconn 308 } 309 // NO init 310 311 // shutdown 312 close(packetChan) 313 pconn.EXPECT().Close() 314 Expect(tr.Close()).To(Succeed()) 315 }) 316 317 It("doesn't add the PacketConn to the multiplexer if (*Transport).init fails", func() { 318 packetChan := make(chan packetToRead) 319 pconn := newMockPacketConn(packetChan) 320 syscallconn := &mockSyscallConn{pconn} 321 322 tr := &Transport{ 323 Conn: syscallconn, 324 } 325 326 err := tr.init(false) 327 Expect(err).To(HaveOccurred()) 328 conns := getMultiplexer().(*connMultiplexer).conns 329 Expect(len(conns)).To(BeZero()) 330 }) 331 332 It("allows receiving non-QUIC packets", func() { 333 remoteAddr := &net.UDPAddr{IP: net.IPv4(9, 8, 7, 6), Port: 1234} 334 packetChan := make(chan packetToRead) 335 tr := &Transport{ 336 Conn: newMockPacketConn(packetChan), 337 ConnectionIDLength: 10, 338 } 339 tr.init(true) 340 receivedPacketChan := make(chan []byte) 341 go func() { 342 defer GinkgoRecover() 343 b := make([]byte, 100) 344 n, addr, err := tr.ReadNonQUICPacket(context.Background(), b) 345 Expect(err).ToNot(HaveOccurred()) 346 Expect(addr).To(Equal(remoteAddr)) 347 receivedPacketChan <- b[:n] 348 }() 349 // Receiving of non-QUIC packets is enabled when ReadNonQUICPacket is called. 350 // Give the Go routine some time to spin up. 351 time.Sleep(scaleDuration(50 * time.Millisecond)) 352 packetChan <- packetToRead{ 353 addr: remoteAddr, 354 data: []byte{0 /* don't set the QUIC bit */, 1, 2, 3}, 355 } 356 357 Eventually(receivedPacketChan).Should(Receive(Equal([]byte{0, 1, 2, 3}))) 358 359 // shutdown 360 close(packetChan) 361 tr.Close() 362 }) 363 364 It("drops non-QUIC packet if the application doesn't process them quickly enough", func() { 365 remoteAddr := &net.UDPAddr{IP: net.IPv4(9, 8, 7, 6), Port: 1234} 366 packetChan := make(chan packetToRead) 367 t, tracer := mocklogging.NewMockTracer(mockCtrl) 368 tr := &Transport{ 369 Conn: newMockPacketConn(packetChan), 370 ConnectionIDLength: 10, 371 Tracer: t, 372 } 373 tr.init(true) 374 375 ctx, cancel := context.WithCancel(context.Background()) 376 cancel() 377 _, _, err := tr.ReadNonQUICPacket(ctx, make([]byte, 10)) 378 Expect(err).To(MatchError(context.Canceled)) 379 380 for i := 0; i < maxQueuedNonQUICPackets; i++ { 381 packetChan <- packetToRead{ 382 addr: remoteAddr, 383 data: []byte{0 /* don't set the QUIC bit */, 1, 2, 3}, 384 } 385 } 386 387 done := make(chan struct{}) 388 tracer.EXPECT().DroppedPacket(remoteAddr, logging.PacketTypeNotDetermined, protocol.ByteCount(4), logging.PacketDropDOSPrevention).Do(func(net.Addr, logging.PacketType, protocol.ByteCount, logging.PacketDropReason) { 389 close(done) 390 }) 391 packetChan <- packetToRead{ 392 addr: remoteAddr, 393 data: []byte{0 /* don't set the QUIC bit */, 1, 2, 3}, 394 } 395 Eventually(done).Should(BeClosed()) 396 397 // shutdown 398 tracer.EXPECT().Close() 399 close(packetChan) 400 tr.Close() 401 }) 402 403 remoteAddr := &net.UDPAddr{IP: net.IPv4(1, 3, 5, 7), Port: 1234} 404 DescribeTable("setting the tls.Config.ServerName", 405 func(expected string, conf *tls.Config, addr net.Addr, host string) { 406 setTLSConfigServerName(conf, addr, host) 407 Expect(conf.ServerName).To(Equal(expected)) 408 }, 409 Entry("uses the value from the config", "foo.bar", &tls.Config{ServerName: "foo.bar"}, remoteAddr, "baz.foo"), 410 Entry("uses the hostname", "golang.org", &tls.Config{}, remoteAddr, "golang.org"), 411 Entry("removes the port from the hostname", "golang.org", &tls.Config{}, remoteAddr, "golang.org:1234"), 412 Entry("uses the IP", "1.3.5.7", &tls.Config{}, remoteAddr, ""), 413 ) 414 }) 415 416 type mockSyscallConn struct { 417 net.PacketConn 418 } 419 420 func (c *mockSyscallConn) SyscallConn() (syscall.RawConn, error) { 421 return nil, errors.New("mocked") 422 }