github.com/quic-go/quic-go@v0.44.0/transport.go (about) 1 package quic 2 3 import ( 4 "context" 5 "crypto/rand" 6 "crypto/tls" 7 "errors" 8 "net" 9 "sync" 10 "sync/atomic" 11 "time" 12 13 "github.com/quic-go/quic-go/internal/protocol" 14 "github.com/quic-go/quic-go/internal/utils" 15 "github.com/quic-go/quic-go/internal/wire" 16 "github.com/quic-go/quic-go/logging" 17 ) 18 19 var errListenerAlreadySet = errors.New("listener already set") 20 21 // The Transport is the central point to manage incoming and outgoing QUIC connections. 22 // QUIC demultiplexes connections based on their QUIC Connection IDs, not based on the 4-tuple. 23 // This means that a single UDP socket can be used for listening for incoming connections, as well as 24 // for dialing an arbitrary number of outgoing connections. 25 // A Transport handles a single net.PacketConn, and offers a range of configuration options 26 // compared to the simple helper functions like Listen and Dial that this package provides. 27 type Transport struct { 28 // A single net.PacketConn can only be handled by one Transport. 29 // Bad things will happen if passed to multiple Transports. 30 // 31 // A number of optimizations will be enabled if the connections implements the OOBCapablePacketConn interface, 32 // as a *net.UDPConn does. 33 // 1. It enables the Don't Fragment (DF) bit on the IP header. 34 // This is required to run DPLPMTUD (Path MTU Discovery, RFC 8899). 35 // 2. It enables reading of the ECN bits from the IP header. 36 // This allows the remote node to speed up its loss detection and recovery. 37 // 3. It uses batched syscalls (recvmmsg) to more efficiently receive packets from the socket. 38 // 4. It uses Generic Segmentation Offload (GSO) to efficiently send batches of packets (on Linux). 39 // 40 // After passing the connection to the Transport, it's invalid to call ReadFrom or WriteTo on the connection. 41 Conn net.PacketConn 42 43 // The length of the connection ID in bytes. 44 // It can be any value between 1 and 20. 45 // Due to the increased risk of collisions, it is not recommended to use connection IDs shorter than 4 bytes. 46 // If unset, a 4 byte connection ID will be used. 47 ConnectionIDLength int 48 49 // Use for generating new connection IDs. 50 // This allows the application to control of the connection IDs used, 51 // which allows routing / load balancing based on connection IDs. 52 // All Connection IDs returned by the ConnectionIDGenerator MUST 53 // have the same length. 54 ConnectionIDGenerator ConnectionIDGenerator 55 56 // The StatelessResetKey is used to generate stateless reset tokens. 57 // If no key is configured, sending of stateless resets is disabled. 58 // It is highly recommended to configure a stateless reset key, as stateless resets 59 // allow the peer to quickly recover from crashes and reboots of this node. 60 // See section 10.3 of RFC 9000 for details. 61 StatelessResetKey *StatelessResetKey 62 63 // The TokenGeneratorKey is used to encrypt session resumption tokens. 64 // If no key is configured, a random key will be generated. 65 // If multiple servers are authoritative for the same domain, they should use the same key, 66 // see section 8.1.3 of RFC 9000 for details. 67 TokenGeneratorKey *TokenGeneratorKey 68 69 // MaxTokenAge is the maximum age of the resumption token presented during the handshake. 70 // These tokens allow skipping address resumption when resuming a QUIC connection, 71 // and are especially useful when using 0-RTT. 72 // If not set, it defaults to 24 hours. 73 // See section 8.1.3 of RFC 9000 for details. 74 MaxTokenAge time.Duration 75 76 // DisableVersionNegotiationPackets disables the sending of Version Negotiation packets. 77 // This can be useful if version information is exchanged out-of-band. 78 // It has no effect for clients. 79 DisableVersionNegotiationPackets bool 80 81 // VerifySourceAddress decides if a connection attempt originating from unvalidated source 82 // addresses first needs to go through source address validation using QUIC's Retry mechanism, 83 // as described in RFC 9000 section 8.1.2. 84 // Note that the address passed to this callback is unvalidated, and might be spoofed in case 85 // of an attack. 86 // Validating the source address adds one additional network roundtrip to the handshake, 87 // and should therefore only be used if a suspiciously high number of incoming connection is recorded. 88 // For most use cases, wrapping the Allow function of a rate.Limiter will be a reasonable 89 // implementation of this callback (negating its return value). 90 VerifySourceAddress func(net.Addr) bool 91 92 // A Tracer traces events that don't belong to a single QUIC connection. 93 // Tracer.Close is called when the transport is closed. 94 Tracer *logging.Tracer 95 96 handlerMap packetHandlerManager 97 98 mutex sync.Mutex 99 initOnce sync.Once 100 initErr error 101 102 // Set in init. 103 // If no ConnectionIDGenerator is set, this is the ConnectionIDLength. 104 connIDLen int 105 // Set in init. 106 // If no ConnectionIDGenerator is set, this is set to a default. 107 connIDGenerator ConnectionIDGenerator 108 109 server *baseServer 110 111 conn rawConn 112 113 closeQueue chan closePacket 114 statelessResetQueue chan receivedPacket 115 116 listening chan struct{} // is closed when listen returns 117 closed bool 118 createdConn bool 119 isSingleUse bool // was created for a single server or client, i.e. by calling quic.Listen or quic.Dial 120 121 readingNonQUICPackets atomic.Bool 122 nonQUICPackets chan receivedPacket 123 124 logger utils.Logger 125 } 126 127 // Listen starts listening for incoming QUIC connections. 128 // There can only be a single listener on any net.PacketConn. 129 // Listen may only be called again after the current Listener was closed. 130 func (t *Transport) Listen(tlsConf *tls.Config, conf *Config) (*Listener, error) { 131 s, err := t.createServer(tlsConf, conf, false) 132 if err != nil { 133 return nil, err 134 } 135 return &Listener{baseServer: s}, nil 136 } 137 138 // ListenEarly starts listening for incoming QUIC connections. 139 // There can only be a single listener on any net.PacketConn. 140 // Listen may only be called again after the current Listener was closed. 141 func (t *Transport) ListenEarly(tlsConf *tls.Config, conf *Config) (*EarlyListener, error) { 142 s, err := t.createServer(tlsConf, conf, true) 143 if err != nil { 144 return nil, err 145 } 146 return &EarlyListener{baseServer: s}, nil 147 } 148 149 func (t *Transport) createServer(tlsConf *tls.Config, conf *Config, allow0RTT bool) (*baseServer, error) { 150 if tlsConf == nil { 151 return nil, errors.New("quic: tls.Config not set") 152 } 153 if err := validateConfig(conf); err != nil { 154 return nil, err 155 } 156 157 t.mutex.Lock() 158 defer t.mutex.Unlock() 159 160 if t.server != nil { 161 return nil, errListenerAlreadySet 162 } 163 conf = populateConfig(conf) 164 if err := t.init(false); err != nil { 165 return nil, err 166 } 167 s := newServer( 168 t.conn, 169 t.handlerMap, 170 t.connIDGenerator, 171 tlsConf, 172 conf, 173 t.Tracer, 174 t.closeServer, 175 *t.TokenGeneratorKey, 176 t.MaxTokenAge, 177 t.VerifySourceAddress, 178 t.DisableVersionNegotiationPackets, 179 allow0RTT, 180 ) 181 t.server = s 182 return s, nil 183 } 184 185 // Dial dials a new connection to a remote host (not using 0-RTT). 186 func (t *Transport) Dial(ctx context.Context, addr net.Addr, tlsConf *tls.Config, conf *Config) (Connection, error) { 187 return t.dial(ctx, addr, "", tlsConf, conf, false) 188 } 189 190 // DialEarly dials a new connection, attempting to use 0-RTT if possible. 191 func (t *Transport) DialEarly(ctx context.Context, addr net.Addr, tlsConf *tls.Config, conf *Config) (EarlyConnection, error) { 192 return t.dial(ctx, addr, "", tlsConf, conf, true) 193 } 194 195 func (t *Transport) dial(ctx context.Context, addr net.Addr, host string, tlsConf *tls.Config, conf *Config, use0RTT bool) (EarlyConnection, error) { 196 if err := validateConfig(conf); err != nil { 197 return nil, err 198 } 199 conf = populateConfig(conf) 200 if err := t.init(t.isSingleUse); err != nil { 201 return nil, err 202 } 203 var onClose func() 204 if t.isSingleUse { 205 onClose = func() { t.Close() } 206 } 207 tlsConf = tlsConf.Clone() 208 setTLSConfigServerName(tlsConf, addr, host) 209 return dial(ctx, newSendConn(t.conn, addr, packetInfo{}, utils.DefaultLogger), t.connIDGenerator, t.handlerMap, tlsConf, conf, onClose, use0RTT) 210 } 211 212 func (t *Transport) init(allowZeroLengthConnIDs bool) error { 213 t.initOnce.Do(func() { 214 var conn rawConn 215 if c, ok := t.Conn.(rawConn); ok { 216 conn = c 217 } else { 218 var err error 219 conn, err = wrapConn(t.Conn) 220 if err != nil { 221 t.initErr = err 222 return 223 } 224 } 225 226 t.logger = utils.DefaultLogger // TODO: make this configurable 227 t.conn = conn 228 t.handlerMap = newPacketHandlerMap(t.StatelessResetKey, t.enqueueClosePacket, t.logger) 229 t.listening = make(chan struct{}) 230 231 t.closeQueue = make(chan closePacket, 4) 232 t.statelessResetQueue = make(chan receivedPacket, 4) 233 if t.TokenGeneratorKey == nil { 234 var key TokenGeneratorKey 235 if _, err := rand.Read(key[:]); err != nil { 236 t.initErr = err 237 return 238 } 239 t.TokenGeneratorKey = &key 240 } 241 242 if t.ConnectionIDGenerator != nil { 243 t.connIDGenerator = t.ConnectionIDGenerator 244 t.connIDLen = t.ConnectionIDGenerator.ConnectionIDLen() 245 } else { 246 connIDLen := t.ConnectionIDLength 247 if t.ConnectionIDLength == 0 && !allowZeroLengthConnIDs { 248 connIDLen = protocol.DefaultConnectionIDLength 249 } 250 t.connIDLen = connIDLen 251 t.connIDGenerator = &protocol.DefaultConnectionIDGenerator{ConnLen: t.connIDLen} 252 } 253 254 getMultiplexer().AddConn(t.Conn) 255 go t.listen(conn) 256 go t.runSendQueue() 257 }) 258 return t.initErr 259 } 260 261 // WriteTo sends a packet on the underlying connection. 262 func (t *Transport) WriteTo(b []byte, addr net.Addr) (int, error) { 263 if err := t.init(false); err != nil { 264 return 0, err 265 } 266 return t.conn.WritePacket(b, addr, nil, 0, protocol.ECNUnsupported) 267 } 268 269 func (t *Transport) enqueueClosePacket(p closePacket) { 270 select { 271 case t.closeQueue <- p: 272 default: 273 // Oops, we're backlogged. 274 // Just drop the packet, sending CONNECTION_CLOSE copies is best effort anyway. 275 } 276 } 277 278 func (t *Transport) runSendQueue() { 279 for { 280 select { 281 case <-t.listening: 282 return 283 case p := <-t.closeQueue: 284 t.conn.WritePacket(p.payload, p.addr, p.info.OOB(), 0, protocol.ECNUnsupported) 285 case p := <-t.statelessResetQueue: 286 t.sendStatelessReset(p) 287 } 288 } 289 } 290 291 // Close closes the underlying connection. 292 // If any listener was started, it will be closed as well. 293 // It is invalid to start new listeners or connections after that. 294 func (t *Transport) Close() error { 295 t.close(errors.New("closing")) 296 if t.createdConn { 297 if err := t.Conn.Close(); err != nil { 298 return err 299 } 300 } else if t.conn != nil { 301 t.conn.SetReadDeadline(time.Now()) 302 defer func() { t.conn.SetReadDeadline(time.Time{}) }() 303 } 304 if t.listening != nil { 305 <-t.listening // wait until listening returns 306 } 307 return nil 308 } 309 310 func (t *Transport) closeServer() { 311 t.mutex.Lock() 312 t.server = nil 313 if t.isSingleUse { 314 t.closed = true 315 } 316 t.mutex.Unlock() 317 if t.createdConn { 318 t.Conn.Close() 319 } 320 if t.isSingleUse { 321 t.conn.SetReadDeadline(time.Now()) 322 defer func() { t.conn.SetReadDeadline(time.Time{}) }() 323 <-t.listening // wait until listening returns 324 } 325 } 326 327 func (t *Transport) close(e error) { 328 t.mutex.Lock() 329 defer t.mutex.Unlock() 330 if t.closed { 331 return 332 } 333 334 if t.handlerMap != nil { 335 t.handlerMap.Close(e) 336 } 337 if t.server != nil { 338 t.server.close(e, false) 339 } 340 if t.Tracer != nil && t.Tracer.Close != nil { 341 t.Tracer.Close() 342 } 343 t.closed = true 344 } 345 346 // only print warnings about the UDP receive buffer size once 347 var setBufferWarningOnce sync.Once 348 349 func (t *Transport) listen(conn rawConn) { 350 defer close(t.listening) 351 defer getMultiplexer().RemoveConn(t.Conn) 352 353 for { 354 p, err := conn.ReadPacket() 355 //nolint:staticcheck // SA1019 ignore this! 356 // TODO: This code is used to ignore wsa errors on Windows. 357 // Since net.Error.Temporary is deprecated as of Go 1.18, we should find a better solution. 358 // See https://github.com/quic-go/quic-go/issues/1737 for details. 359 if nerr, ok := err.(net.Error); ok && nerr.Temporary() { 360 t.mutex.Lock() 361 closed := t.closed 362 t.mutex.Unlock() 363 if closed { 364 return 365 } 366 t.logger.Debugf("Temporary error reading from conn: %w", err) 367 continue 368 } 369 if err != nil { 370 // Windows returns an error when receiving a UDP datagram that doesn't fit into the provided buffer. 371 if isRecvMsgSizeErr(err) { 372 continue 373 } 374 t.close(err) 375 return 376 } 377 t.handlePacket(p) 378 } 379 } 380 381 func (t *Transport) handlePacket(p receivedPacket) { 382 if len(p.data) == 0 { 383 return 384 } 385 if !wire.IsPotentialQUICPacket(p.data[0]) && !wire.IsLongHeaderPacket(p.data[0]) { 386 t.handleNonQUICPacket(p) 387 return 388 } 389 connID, err := wire.ParseConnectionID(p.data, t.connIDLen) 390 if err != nil { 391 t.logger.Debugf("error parsing connection ID on packet from %s: %s", p.remoteAddr, err) 392 if t.Tracer != nil && t.Tracer.DroppedPacket != nil { 393 t.Tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropHeaderParseError) 394 } 395 p.buffer.MaybeRelease() 396 return 397 } 398 399 // If there's a connection associated with the connection ID, pass the packet there. 400 if handler, ok := t.handlerMap.Get(connID); ok { 401 handler.handlePacket(p) 402 return 403 } 404 // RFC 9000 section 10.3.1 requires that the stateless reset detection logic is run for both 405 // packets that cannot be associated with any connections, and for packets that can't be decrypted. 406 // We deviate from the RFC and ignore the latter: If a packet's connection ID is associated with an 407 // existing connection, it is dropped there if if it can't be decrypted. 408 // Stateless resets use random connection IDs, and at reasonable connection ID lengths collisions are 409 // exceedingly rare. In the unlikely event that a stateless reset is misrouted to an existing connection, 410 // it is to be expected that the next stateless reset will be correctly detected. 411 if isStatelessReset := t.maybeHandleStatelessReset(p.data); isStatelessReset { 412 return 413 } 414 if !wire.IsLongHeaderPacket(p.data[0]) { 415 t.maybeSendStatelessReset(p) 416 return 417 } 418 419 t.mutex.Lock() 420 defer t.mutex.Unlock() 421 if t.server == nil { // no server set 422 t.logger.Debugf("received a packet with an unexpected connection ID %s", connID) 423 return 424 } 425 t.server.handlePacket(p) 426 } 427 428 func (t *Transport) maybeSendStatelessReset(p receivedPacket) { 429 if t.StatelessResetKey == nil { 430 p.buffer.Release() 431 return 432 } 433 434 // Don't send a stateless reset in response to very small packets. 435 // This includes packets that could be stateless resets. 436 if len(p.data) <= protocol.MinStatelessResetSize { 437 p.buffer.Release() 438 return 439 } 440 441 select { 442 case t.statelessResetQueue <- p: 443 default: 444 // it's fine to not send a stateless reset when we're busy 445 p.buffer.Release() 446 } 447 } 448 449 func (t *Transport) sendStatelessReset(p receivedPacket) { 450 defer p.buffer.Release() 451 452 connID, err := wire.ParseConnectionID(p.data, t.connIDLen) 453 if err != nil { 454 t.logger.Errorf("error parsing connection ID on packet from %s: %s", p.remoteAddr, err) 455 return 456 } 457 token := t.handlerMap.GetStatelessResetToken(connID) 458 t.logger.Debugf("Sending stateless reset to %s (connection ID: %s). Token: %#x", p.remoteAddr, connID, token) 459 data := make([]byte, protocol.MinStatelessResetSize-16, protocol.MinStatelessResetSize) 460 rand.Read(data) 461 data[0] = (data[0] & 0x7f) | 0x40 462 data = append(data, token[:]...) 463 if _, err := t.conn.WritePacket(data, p.remoteAddr, p.info.OOB(), 0, protocol.ECNUnsupported); err != nil { 464 t.logger.Debugf("Error sending Stateless Reset to %s: %s", p.remoteAddr, err) 465 } 466 } 467 468 func (t *Transport) maybeHandleStatelessReset(data []byte) bool { 469 // stateless resets are always short header packets 470 if wire.IsLongHeaderPacket(data[0]) { 471 return false 472 } 473 if len(data) < 17 /* type byte + 16 bytes for the reset token */ { 474 return false 475 } 476 477 token := *(*protocol.StatelessResetToken)(data[len(data)-16:]) 478 if conn, ok := t.handlerMap.GetByResetToken(token); ok { 479 t.logger.Debugf("Received a stateless reset with token %#x. Closing connection.", token) 480 go conn.destroy(&StatelessResetError{Token: token}) 481 return true 482 } 483 return false 484 } 485 486 func (t *Transport) handleNonQUICPacket(p receivedPacket) { 487 // Strictly speaking, this is racy, 488 // but we only care about receiving packets at some point after ReadNonQUICPacket has been called. 489 if !t.readingNonQUICPackets.Load() { 490 return 491 } 492 select { 493 case t.nonQUICPackets <- p: 494 default: 495 if t.Tracer != nil && t.Tracer.DroppedPacket != nil { 496 t.Tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropDOSPrevention) 497 } 498 } 499 } 500 501 const maxQueuedNonQUICPackets = 32 502 503 // ReadNonQUICPacket reads non-QUIC packets received on the underlying connection. 504 // The detection logic is very simple: Any packet that has the first and second bit of the packet set to 0. 505 // Note that this is stricter than the detection logic defined in RFC 9443. 506 func (t *Transport) ReadNonQUICPacket(ctx context.Context, b []byte) (int, net.Addr, error) { 507 if err := t.init(false); err != nil { 508 return 0, nil, err 509 } 510 if !t.readingNonQUICPackets.Load() { 511 t.nonQUICPackets = make(chan receivedPacket, maxQueuedNonQUICPackets) 512 t.readingNonQUICPackets.Store(true) 513 } 514 select { 515 case <-ctx.Done(): 516 return 0, nil, ctx.Err() 517 case p := <-t.nonQUICPackets: 518 n := copy(b, p.data) 519 return n, p.remoteAddr, nil 520 case <-t.listening: 521 return 0, nil, errors.New("closed") 522 } 523 } 524 525 func setTLSConfigServerName(tlsConf *tls.Config, addr net.Addr, host string) { 526 // If no ServerName is set, infer the ServerName from the host we're connecting to. 527 if tlsConf.ServerName != "" { 528 return 529 } 530 if host == "" { 531 if udpAddr, ok := addr.(*net.UDPAddr); ok { 532 tlsConf.ServerName = udpAddr.IP.String() 533 return 534 } 535 } 536 h, _, err := net.SplitHostPort(host) 537 if err != nil { // This happens if the host doesn't contain a port number. 538 tlsConf.ServerName = host 539 return 540 } 541 tlsConf.ServerName = h 542 }