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  }