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