github.com/tumi8/quic-go@v0.37.4-tum/transport.go (about)

     1  package quic
     2  
     3  import (
     4  	"context"
     5  	"crypto/rand"
     6  	"crypto/tls"
     7  	"errors"
     8  	"net"
     9  	"sync"
    10  	"time"
    11  
    12  	"github.com/tumi8/quic-go/noninternal/wire"
    13  
    14  	"github.com/tumi8/quic-go/noninternal/protocol"
    15  	"github.com/tumi8/quic-go/noninternal/utils"
    16  	"github.com/tumi8/quic-go/logging"
    17  )
    18  
    19  // The Transport is the central point to manage incoming and outgoing QUIC connections.
    20  // QUIC demultiplexes connections based on their QUIC Connection IDs, not based on the 4-tuple.
    21  // This means that a single UDP socket can be used for listening for incoming connections, as well as
    22  // for dialing an arbitrary number of outgoing connections.
    23  // A Transport handles a single net.PacketConn, and offers a range of configuration options
    24  // compared to the simple helper functions like Listen and Dial that this package provides.
    25  type Transport struct {
    26  	// A single net.PacketConn can only be handled by one Transport.
    27  	// Bad things will happen if passed to multiple Transports.
    28  	//
    29  	// A number of optimizations will be enabled if the connections implements the OOBCapablePacketConn interface,
    30  	// as a *net.UDPConn does.
    31  	// 1. It enables the Don't Fragment (DF) bit on the IP header.
    32  	//    This is required to run DPLPMTUD (Path MTU Discovery, RFC 8899).
    33  	// 2. It enables reading of the ECN bits from the IP header.
    34  	//    This allows the remote node to speed up its loss detection and recovery.
    35  	// 3. It uses batched syscalls (recvmmsg) to more efficiently receive packets from the socket.
    36  	// 4. It uses Generic Segmentation Offload (GSO) to efficiently send batches of packets (on Linux).
    37  	//
    38  	// After passing the connection to the Transport, it's invalid to call ReadFrom or WriteTo on the connection.
    39  	Conn net.PacketConn
    40  
    41  	// The length of the connection ID in bytes.
    42  	// It can be 0, or any value between 4 and 18.
    43  	// If unset, a 4 byte connection ID will be used.
    44  	ConnectionIDLength int
    45  
    46  	// Use for generating new connection IDs.
    47  	// This allows the application to control of the connection IDs used,
    48  	// which allows routing / load balancing based on connection IDs.
    49  	// All Connection IDs returned by the ConnectionIDGenerator MUST
    50  	// have the same length.
    51  	ConnectionIDGenerator ConnectionIDGenerator
    52  
    53  	// The StatelessResetKey is used to generate stateless reset tokens.
    54  	// If no key is configured, sending of stateless resets is disabled.
    55  	// It is highly recommended to configure a stateless reset key, as stateless resets
    56  	// allow the peer to quickly recover from crashes and reboots of this node.
    57  	// See section 10.3 of RFC 9000 for details.
    58  	StatelessResetKey *StatelessResetKey
    59  
    60  	// A Tracer traces events that don't belong to a single QUIC connection.
    61  	Tracer logging.Tracer
    62  
    63  	handlerMap packetHandlerManager
    64  
    65  	mutex    sync.Mutex
    66  	initOnce sync.Once
    67  	initErr  error
    68  
    69  	// Set in init.
    70  	// If no ConnectionIDGenerator is set, this is the ConnectionIDLength.
    71  	connIDLen int
    72  	// Set in init.
    73  	// If no ConnectionIDGenerator is set, this is set to a default.
    74  	connIDGenerator ConnectionIDGenerator
    75  
    76  	server unknownPacketHandler
    77  
    78  	conn rawConn
    79  
    80  	closeQueue          chan closePacket
    81  	statelessResetQueue chan receivedPacket
    82  
    83  	listening   chan struct{} // is closed when listen returns
    84  	closed      bool
    85  	createdConn bool
    86  	isSingleUse bool // was created for a single server or client, i.e. by calling quic.Listen or quic.Dial
    87  
    88  	logger utils.Logger
    89  }
    90  
    91  // Listen starts listening for incoming QUIC connections.
    92  // There can only be a single listener on any net.PacketConn.
    93  // Listen may only be called again after the current Listener was closed.
    94  func (t *Transport) Listen(tlsConf *tls.Config, conf *Config) (*Listener, error) {
    95  	if tlsConf == nil {
    96  		return nil, errors.New("quic: tls.Config not set")
    97  	}
    98  	if err := validateConfig(conf); err != nil {
    99  		return nil, err
   100  	}
   101  
   102  	t.mutex.Lock()
   103  	defer t.mutex.Unlock()
   104  
   105  	if t.server != nil {
   106  		return nil, errListenerAlreadySet
   107  	}
   108  	conf = populateServerConfig(conf)
   109  	if err := t.init(false); err != nil {
   110  		return nil, err
   111  	}
   112  	s, err := newServer(t.conn, t.handlerMap, t.connIDGenerator, tlsConf, conf, t.Tracer, t.closeServer, false)
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  	t.server = s
   117  	return &Listener{baseServer: s}, nil
   118  }
   119  
   120  // ListenEarly starts listening for incoming QUIC connections.
   121  // There can only be a single listener on any net.PacketConn.
   122  // Listen may only be called again after the current Listener was closed.
   123  func (t *Transport) ListenEarly(tlsConf *tls.Config, conf *Config) (*EarlyListener, error) {
   124  	if tlsConf == nil {
   125  		return nil, errors.New("quic: tls.Config not set")
   126  	}
   127  	if err := validateConfig(conf); err != nil {
   128  		return nil, err
   129  	}
   130  
   131  	t.mutex.Lock()
   132  	defer t.mutex.Unlock()
   133  
   134  	if t.server != nil {
   135  		return nil, errListenerAlreadySet
   136  	}
   137  	conf = populateServerConfig(conf)
   138  	if err := t.init(false); err != nil {
   139  		return nil, err
   140  	}
   141  	s, err := newServer(t.conn, t.handlerMap, t.connIDGenerator, tlsConf, conf, t.Tracer, t.closeServer, true)
   142  	if err != nil {
   143  		return nil, err
   144  	}
   145  	t.server = s
   146  	return &EarlyListener{baseServer: s}, nil
   147  }
   148  
   149  // Dial dials a new connection to a remote host (not using 0-RTT).
   150  func (t *Transport) Dial(ctx context.Context, addr net.Addr, tlsConf *tls.Config, conf *Config) (Connection, error) {
   151  	if err := validateConfig(conf); err != nil {
   152  		return nil, err
   153  	}
   154  	conf = populateConfig(conf)
   155  	if err := t.init(t.isSingleUse); err != nil {
   156  		return nil, err
   157  	}
   158  	var onClose func()
   159  	if t.isSingleUse {
   160  		onClose = func() { t.Close() }
   161  	}
   162  	tlsConf = tlsConf.Clone()
   163  	tlsConf.MinVersion = tls.VersionTLS13
   164  	return dial(ctx, newSendConn(t.conn, addr), t.connIDGenerator, t.handlerMap, tlsConf, conf, onClose, false)
   165  }
   166  
   167  // DialEarly dials a new connection, attempting to use 0-RTT if possible.
   168  func (t *Transport) DialEarly(ctx context.Context, addr net.Addr, tlsConf *tls.Config, conf *Config) (EarlyConnection, error) {
   169  	if err := validateConfig(conf); err != nil {
   170  		return nil, err
   171  	}
   172  	conf = populateConfig(conf)
   173  	if err := t.init(t.isSingleUse); err != nil {
   174  		return nil, err
   175  	}
   176  	var onClose func()
   177  	if t.isSingleUse {
   178  		onClose = func() { t.Close() }
   179  	}
   180  	tlsConf = tlsConf.Clone()
   181  	tlsConf.MinVersion = tls.VersionTLS13
   182  	return dial(ctx, newSendConn(t.conn, addr), t.connIDGenerator, t.handlerMap, tlsConf, conf, onClose, true)
   183  }
   184  
   185  func (t *Transport) init(allowZeroLengthConnIDs bool) error {
   186  	t.initOnce.Do(func() {
   187  		var conn rawConn
   188  		if c, ok := t.Conn.(rawConn); ok {
   189  			conn = c
   190  		} else {
   191  			var err error
   192  			conn, err = wrapConn(t.Conn)
   193  			if err != nil {
   194  				t.initErr = err
   195  				return
   196  			}
   197  		}
   198  		t.conn = conn
   199  
   200  		t.logger = utils.DefaultLogger // TODO: make this configurable
   201  		t.conn = conn
   202  		t.handlerMap = newPacketHandlerMap(t.StatelessResetKey, t.enqueueClosePacket, t.logger)
   203  		t.listening = make(chan struct{})
   204  
   205  		t.closeQueue = make(chan closePacket, 4)
   206  		t.statelessResetQueue = make(chan receivedPacket, 4)
   207  
   208  		if t.ConnectionIDGenerator != nil {
   209  			t.connIDGenerator = t.ConnectionIDGenerator
   210  			t.connIDLen = t.ConnectionIDGenerator.ConnectionIDLen()
   211  		} else {
   212  			connIDLen := t.ConnectionIDLength
   213  			if t.ConnectionIDLength == 0 && !allowZeroLengthConnIDs {
   214  				connIDLen = protocol.DefaultConnectionIDLength
   215  			}
   216  			t.connIDLen = connIDLen
   217  			t.connIDGenerator = &protocol.DefaultConnectionIDGenerator{ConnLen: t.connIDLen}
   218  		}
   219  
   220  		getMultiplexer().AddConn(t.Conn)
   221  		go t.listen(conn)
   222  		go t.runSendQueue()
   223  	})
   224  	return t.initErr
   225  }
   226  
   227  // WriteTo sends a packet on the underlying connection.
   228  func (t *Transport) WriteTo(b []byte, addr net.Addr) (int, error) {
   229  	if err := t.init(false); err != nil {
   230  		return 0, err
   231  	}
   232  	return t.conn.WritePacket(b, uint16(len(b)), addr, nil)
   233  }
   234  
   235  func (t *Transport) enqueueClosePacket(p closePacket) {
   236  	select {
   237  	case t.closeQueue <- p:
   238  	default:
   239  		// Oops, we're backlogged.
   240  		// Just drop the packet, sending CONNECTION_CLOSE copies is best effort anyway.
   241  	}
   242  }
   243  
   244  func (t *Transport) runSendQueue() {
   245  	for {
   246  		select {
   247  		case <-t.listening:
   248  			return
   249  		case p := <-t.closeQueue:
   250  			t.conn.WritePacket(p.payload, uint16(len(p.payload)), p.addr, p.info.OOB())
   251  		case p := <-t.statelessResetQueue:
   252  			t.sendStatelessReset(p)
   253  		}
   254  	}
   255  }
   256  
   257  // Close closes the underlying connection and waits until listen has returned.
   258  // It is invalid to start new listeners or connections after that.
   259  func (t *Transport) Close() error {
   260  	t.close(errors.New("closing"))
   261  	if t.createdConn {
   262  		if err := t.Conn.Close(); err != nil {
   263  			return err
   264  		}
   265  	} else if t.conn != nil {
   266  		t.conn.SetReadDeadline(time.Now())
   267  		defer func() { t.conn.SetReadDeadline(time.Time{}) }()
   268  	}
   269  	if t.listening != nil {
   270  		<-t.listening // wait until listening returns
   271  	}
   272  	return nil
   273  }
   274  
   275  func (t *Transport) closeServer() {
   276  	t.handlerMap.CloseServer()
   277  	t.mutex.Lock()
   278  	t.server = nil
   279  	if t.isSingleUse {
   280  		t.closed = true
   281  	}
   282  	t.mutex.Unlock()
   283  	if t.createdConn {
   284  		t.Conn.Close()
   285  	}
   286  	if t.isSingleUse {
   287  		t.conn.SetReadDeadline(time.Now())
   288  		defer func() { t.conn.SetReadDeadline(time.Time{}) }()
   289  		<-t.listening // wait until listening returns
   290  	}
   291  }
   292  
   293  func (t *Transport) close(e error) {
   294  	t.mutex.Lock()
   295  	defer t.mutex.Unlock()
   296  	if t.closed {
   297  		return
   298  	}
   299  
   300  	if t.handlerMap != nil {
   301  		t.handlerMap.Close(e)
   302  	}
   303  	if t.server != nil {
   304  		t.server.setCloseError(e)
   305  	}
   306  	t.closed = true
   307  }
   308  
   309  // only print warnings about the UDP receive buffer size once
   310  var setBufferWarningOnce sync.Once
   311  
   312  func (t *Transport) listen(conn rawConn) {
   313  	defer close(t.listening)
   314  	defer getMultiplexer().RemoveConn(t.Conn)
   315  
   316  	for {
   317  		p, err := conn.ReadPacket()
   318  		//nolint:staticcheck // SA1019 ignore this!
   319  		// TODO: This code is used to ignore wsa errors on Windows.
   320  		// Since net.Error.Temporary is deprecated as of Go 1.18, we should find a better solution.
   321  		// See https://github.com/tumi8/quic-go/issues/1737 for details.
   322  		if nerr, ok := err.(net.Error); ok && nerr.Temporary() {
   323  			t.mutex.Lock()
   324  			closed := t.closed
   325  			t.mutex.Unlock()
   326  			if closed {
   327  				return
   328  			}
   329  			t.logger.Debugf("Temporary error reading from conn: %w", err)
   330  			continue
   331  		}
   332  		if err != nil {
   333  			// Windows returns an error when receiving a UDP datagram that doesn't fit into the provided buffer.
   334  			if isRecvMsgSizeErr(err) {
   335  				continue
   336  			}
   337  			t.close(err)
   338  			return
   339  		}
   340  		t.handlePacket(p)
   341  	}
   342  }
   343  
   344  func (t *Transport) handlePacket(p receivedPacket) {
   345  	connID, err := wire.ParseConnectionID(p.data, t.connIDLen)
   346  	if err != nil {
   347  		t.logger.Debugf("error parsing connection ID on packet from %s: %s", p.remoteAddr, err)
   348  		if t.Tracer != nil {
   349  			t.Tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropHeaderParseError)
   350  		}
   351  		p.buffer.MaybeRelease()
   352  		return
   353  	}
   354  
   355  	if isStatelessReset := t.maybeHandleStatelessReset(p.data); isStatelessReset {
   356  		return
   357  	}
   358  	if handler, ok := t.handlerMap.Get(connID); ok {
   359  		handler.handlePacket(p)
   360  		return
   361  	}
   362  	if !wire.IsLongHeaderPacket(p.data[0]) {
   363  		t.maybeSendStatelessReset(p)
   364  		return
   365  	}
   366  
   367  	t.mutex.Lock()
   368  	defer t.mutex.Unlock()
   369  	if t.server == nil { // no server set
   370  		t.logger.Debugf("received a packet with an unexpected connection ID %s", connID)
   371  		return
   372  	}
   373  	t.server.handlePacket(p)
   374  }
   375  
   376  func (t *Transport) maybeSendStatelessReset(p receivedPacket) {
   377  	if t.StatelessResetKey == nil {
   378  		p.buffer.Release()
   379  		return
   380  	}
   381  
   382  	// Don't send a stateless reset in response to very small packets.
   383  	// This includes packets that could be stateless resets.
   384  	if len(p.data) <= protocol.MinStatelessResetSize {
   385  		p.buffer.Release()
   386  		return
   387  	}
   388  
   389  	select {
   390  	case t.statelessResetQueue <- p:
   391  	default:
   392  		// it's fine to not send a stateless reset when we're busy
   393  		p.buffer.Release()
   394  	}
   395  }
   396  
   397  func (t *Transport) sendStatelessReset(p receivedPacket) {
   398  	defer p.buffer.Release()
   399  
   400  	connID, err := wire.ParseConnectionID(p.data, t.connIDLen)
   401  	if err != nil {
   402  		t.logger.Errorf("error parsing connection ID on packet from %s: %s", p.remoteAddr, err)
   403  		return
   404  	}
   405  	token := t.handlerMap.GetStatelessResetToken(connID)
   406  	t.logger.Debugf("Sending stateless reset to %s (connection ID: %s). Token: %#x", p.remoteAddr, connID, token)
   407  	data := make([]byte, protocol.MinStatelessResetSize-16, protocol.MinStatelessResetSize)
   408  	rand.Read(data)
   409  	data[0] = (data[0] & 0x7f) | 0x40
   410  	data = append(data, token[:]...)
   411  	if _, err := t.conn.WritePacket(data, uint16(len(data)), p.remoteAddr, p.info.OOB()); err != nil {
   412  		t.logger.Debugf("Error sending Stateless Reset to %s: %s", p.remoteAddr, err)
   413  	}
   414  }
   415  
   416  func (t *Transport) maybeHandleStatelessReset(data []byte) bool {
   417  	// stateless resets are always short header packets
   418  	if wire.IsLongHeaderPacket(data[0]) {
   419  		return false
   420  	}
   421  	if len(data) < 17 /* type byte + 16 bytes for the reset token */ {
   422  		return false
   423  	}
   424  
   425  	token := *(*protocol.StatelessResetToken)(data[len(data)-16:])
   426  	if conn, ok := t.handlerMap.GetByResetToken(token); ok {
   427  		t.logger.Debugf("Received a stateless reset with token %#x. Closing connection.", token)
   428  		go conn.destroy(&StatelessResetError{Token: token})
   429  		return true
   430  	}
   431  	return false
   432  }