github.com/ooni/psiphon/tunnel-core@v0.0.0-20230105123940-fe12a24c96ee/oovendor/quic-go/http3/server.go (about) 1 package http3 2 3 import ( 4 "bytes" 5 "context" 6 "crypto/tls" 7 "errors" 8 "fmt" 9 "io" 10 "net" 11 "net/http" 12 "runtime" 13 "strings" 14 "sync" 15 "time" 16 17 "github.com/ooni/psiphon/tunnel-core/oovendor/quic-go" 18 "github.com/ooni/psiphon/tunnel-core/oovendor/quic-go/internal/handshake" 19 "github.com/ooni/psiphon/tunnel-core/oovendor/quic-go/internal/protocol" 20 "github.com/ooni/psiphon/tunnel-core/oovendor/quic-go/internal/utils" 21 "github.com/ooni/psiphon/tunnel-core/oovendor/quic-go/quicvarint" 22 "github.com/marten-seemann/qpack" 23 ) 24 25 // allows mocking of quic.Listen and quic.ListenAddr 26 var ( 27 quicListen = quic.ListenEarly 28 quicListenAddr = quic.ListenAddrEarly 29 ) 30 31 const ( 32 nextProtoH3Draft29 = "h3-29" 33 nextProtoH3 = "h3" 34 ) 35 36 const ( 37 streamTypeControlStream = 0 38 streamTypePushStream = 1 39 streamTypeQPACKEncoderStream = 2 40 streamTypeQPACKDecoderStream = 3 41 ) 42 43 func versionToALPN(v protocol.VersionNumber) string { 44 if v == protocol.Version1 { 45 return nextProtoH3 46 } 47 if v == protocol.VersionTLS || v == protocol.VersionDraft29 { 48 return nextProtoH3Draft29 49 } 50 return "" 51 } 52 53 // ConfigureTLSConfig creates a new tls.Config which can be used 54 // to create a quic.Listener meant for serving http3. The created 55 // tls.Config adds the functionality of detecting the used QUIC version 56 // in order to set the correct ALPN value for the http3 connection. 57 func ConfigureTLSConfig(tlsConf *tls.Config) *tls.Config { 58 // The tls.Config used to setup the quic.Listener needs to have the GetConfigForClient callback set. 59 // That way, we can get the QUIC version and set the correct ALPN value. 60 return &tls.Config{ 61 GetConfigForClient: func(ch *tls.ClientHelloInfo) (*tls.Config, error) { 62 // determine the ALPN from the QUIC version used 63 proto := nextProtoH3Draft29 64 if qconn, ok := ch.Conn.(handshake.ConnWithVersion); ok { 65 if qconn.GetQUICVersion() == protocol.Version1 { 66 proto = nextProtoH3 67 } 68 } 69 config := tlsConf 70 if tlsConf.GetConfigForClient != nil { 71 getConfigForClient := tlsConf.GetConfigForClient 72 var err error 73 conf, err := getConfigForClient(ch) 74 if err != nil { 75 return nil, err 76 } 77 if conf != nil { 78 config = conf 79 } 80 } 81 if config == nil { 82 return nil, nil 83 } 84 config = config.Clone() 85 config.NextProtos = []string{proto} 86 return config, nil 87 }, 88 } 89 } 90 91 // contextKey is a value for use with context.WithValue. It's used as 92 // a pointer so it fits in an interface{} without allocation. 93 type contextKey struct { 94 name string 95 } 96 97 func (k *contextKey) String() string { return "quic-go/http3 context value " + k.name } 98 99 // ServerContextKey is a context key. It can be used in HTTP 100 // handlers with Context.Value to access the server that 101 // started the handler. The associated value will be of 102 // type *http3.Server. 103 var ServerContextKey = &contextKey{"http3-server"} 104 105 type requestError struct { 106 err error 107 streamErr errorCode 108 connErr errorCode 109 } 110 111 func newStreamError(code errorCode, err error) requestError { 112 return requestError{err: err, streamErr: code} 113 } 114 115 func newConnError(code errorCode, err error) requestError { 116 return requestError{err: err, connErr: code} 117 } 118 119 // listenerInfo contains info about specific listener added with addListener 120 type listenerInfo struct { 121 port int // 0 means that no info about port is available 122 } 123 124 // Server is a HTTP/3 server. 125 type Server struct { 126 *http.Server 127 128 // By providing a quic.Config, it is possible to set parameters of the QUIC connection. 129 // If nil, it uses reasonable default values. 130 QuicConfig *quic.Config 131 132 // Enable support for HTTP/3 datagrams. 133 // If set to true, QuicConfig.EnableDatagram will be set. 134 // See https://www.ietf.org/archive/id/draft-schinazi-masque-h3-datagram-02.html. 135 EnableDatagrams bool 136 137 // The port to use in Alt-Svc response headers. 138 // If needed Port can be manually set when the Server is created. 139 // This is useful when a Layer 4 firewall is redirecting UDP traffic and clients must use 140 // a port different from the port the Server is listening on. 141 Port int 142 143 mutex sync.RWMutex 144 listeners map[*quic.EarlyListener]listenerInfo 145 closed utils.AtomicBool 146 147 altSvcHeader string 148 149 loggerOnce sync.Once 150 logger utils.Logger 151 } 152 153 // ListenAndServe listens on the UDP address s.Addr and calls s.Handler to handle HTTP/3 requests on incoming connections. 154 func (s *Server) ListenAndServe() error { 155 if s.Server == nil { 156 return errors.New("use of http3.Server without http.Server") 157 } 158 return s.serveConn(s.TLSConfig, nil) 159 } 160 161 // ListenAndServeTLS listens on the UDP address s.Addr and calls s.Handler to handle HTTP/3 requests on incoming connections. 162 func (s *Server) ListenAndServeTLS(certFile, keyFile string) error { 163 var err error 164 certs := make([]tls.Certificate, 1) 165 certs[0], err = tls.LoadX509KeyPair(certFile, keyFile) 166 if err != nil { 167 return err 168 } 169 // We currently only use the cert-related stuff from tls.Config, 170 // so we don't need to make a full copy. 171 config := &tls.Config{ 172 Certificates: certs, 173 } 174 return s.serveConn(config, nil) 175 } 176 177 // Serve an existing UDP connection. 178 // It is possible to reuse the same connection for outgoing connections. 179 // Closing the server does not close the packet conn. 180 func (s *Server) Serve(conn net.PacketConn) error { 181 return s.serveConn(s.TLSConfig, conn) 182 } 183 184 // Serve an existing QUIC listener. 185 // Make sure you use http3.ConfigureTLSConfig to configure a tls.Config 186 // and use it to construct a http3-friendly QUIC listener. 187 // Closing the server does close the listener. 188 func (s *Server) ServeListener(listener quic.EarlyListener) error { 189 return s.serveImpl(func() (quic.EarlyListener, error) { return listener, nil }) 190 } 191 192 func (s *Server) serveConn(tlsConf *tls.Config, conn net.PacketConn) error { 193 return s.serveImpl(func() (quic.EarlyListener, error) { 194 baseConf := ConfigureTLSConfig(tlsConf) 195 quicConf := s.QuicConfig 196 if quicConf == nil { 197 quicConf = &quic.Config{} 198 } else { 199 quicConf = s.QuicConfig.Clone() 200 } 201 if s.EnableDatagrams { 202 quicConf.EnableDatagrams = true 203 } 204 205 var ln quic.EarlyListener 206 var err error 207 if conn == nil { 208 ln, err = quicListenAddr(s.Addr, baseConf, quicConf) 209 } else { 210 ln, err = quicListen(conn, baseConf, quicConf) 211 } 212 if err != nil { 213 return nil, err 214 } 215 return ln, nil 216 }) 217 } 218 219 func (s *Server) serveImpl(startListener func() (quic.EarlyListener, error)) error { 220 if s.closed.Get() { 221 return http.ErrServerClosed 222 } 223 if s.Server == nil { 224 return errors.New("use of http3.Server without http.Server") 225 } 226 s.loggerOnce.Do(func() { 227 s.logger = utils.DefaultLogger.WithPrefix("server") 228 }) 229 230 ln, err := startListener() 231 if err != nil { 232 return err 233 } 234 s.addListener(&ln) 235 defer s.removeListener(&ln) 236 237 for { 238 sess, err := ln.Accept(context.Background()) 239 if err != nil { 240 return err 241 } 242 go s.handleConn(sess) 243 } 244 } 245 246 func extractPort(addr string) (int, error) { 247 _, portStr, err := net.SplitHostPort(addr) 248 if err != nil { 249 return 0, err 250 } 251 252 portInt, err := net.LookupPort("tcp", portStr) 253 if err != nil { 254 return 0, err 255 } 256 return portInt, nil 257 } 258 259 func (s *Server) generateAltSvcHeader() { 260 if len(s.listeners) == 0 { 261 // Don't announce any ports since no one is listening for connections 262 s.altSvcHeader = "" 263 return 264 } 265 266 // This code assumes that we will use protocol.SupportedVersions if no quic.Config is passed. 267 supportedVersions := protocol.SupportedVersions 268 if s.QuicConfig != nil && len(s.QuicConfig.Versions) > 0 { 269 supportedVersions = s.QuicConfig.Versions 270 } 271 var versionStrings []string 272 for _, version := range supportedVersions { 273 if v := versionToALPN(version); len(v) > 0 { 274 versionStrings = append(versionStrings, v) 275 } 276 } 277 278 var altSvc []string 279 addPort := func(port int) { 280 for _, v := range versionStrings { 281 altSvc = append(altSvc, fmt.Sprintf(`%s=":%d"; ma=2592000`, v, port)) 282 } 283 } 284 285 if s.Port != 0 { 286 // if Port is specified, we must use it instead of the 287 // listener addresses since there's a reason it's specified. 288 addPort(s.Port) 289 } else { 290 // if we have some listeners assigned, try to find ports 291 // which we can announce, otherwise nothing should be announced 292 validPortsFound := false 293 for _, info := range s.listeners { 294 if info.port != 0 { 295 addPort(info.port) 296 validPortsFound = true 297 } 298 } 299 if !validPortsFound { 300 if port, err := extractPort(s.Addr); err == nil { 301 addPort(port) 302 } 303 } 304 } 305 306 s.altSvcHeader = strings.Join(altSvc, ",") 307 } 308 309 // We store a pointer to interface in the map set. This is safe because we only 310 // call trackListener via Serve and can track+defer untrack the same pointer to 311 // local variable there. We never need to compare a Listener from another caller. 312 func (s *Server) addListener(l *quic.EarlyListener) { 313 s.mutex.Lock() 314 if s.listeners == nil { 315 s.listeners = make(map[*quic.EarlyListener]listenerInfo) 316 } 317 318 if port, err := extractPort((*l).Addr().String()); err == nil { 319 s.listeners[l] = listenerInfo{port} 320 } else { 321 s.logger.Errorf( 322 "Unable to extract port from listener %+v, will not be announced using SetQuicHeaders: %s", err) 323 s.listeners[l] = listenerInfo{} 324 } 325 s.generateAltSvcHeader() 326 327 s.mutex.Unlock() 328 } 329 330 func (s *Server) removeListener(l *quic.EarlyListener) { 331 s.mutex.Lock() 332 delete(s.listeners, l) 333 s.generateAltSvcHeader() 334 s.mutex.Unlock() 335 } 336 337 func (s *Server) handleConn(sess quic.EarlySession) { 338 decoder := qpack.NewDecoder(nil) 339 340 // send a SETTINGS frame 341 str, err := sess.OpenUniStream() 342 if err != nil { 343 s.logger.Debugf("Opening the control stream failed.") 344 return 345 } 346 buf := &bytes.Buffer{} 347 quicvarint.Write(buf, streamTypeControlStream) // stream type 348 (&settingsFrame{Datagram: s.EnableDatagrams}).Write(buf) 349 str.Write(buf.Bytes()) 350 351 go s.handleUnidirectionalStreams(sess) 352 353 // Process all requests immediately. 354 // It's the client's responsibility to decide which requests are eligible for 0-RTT. 355 for { 356 str, err := sess.AcceptStream(context.Background()) 357 if err != nil { 358 s.logger.Debugf("Accepting stream failed: %s", err) 359 return 360 } 361 go func() { 362 rerr := s.handleRequest(sess, str, decoder, func() { 363 sess.CloseWithError(quic.ApplicationErrorCode(errorFrameUnexpected), "") 364 }) 365 if rerr.err != nil || rerr.streamErr != 0 || rerr.connErr != 0 { 366 s.logger.Debugf("Handling request failed: %s", err) 367 if rerr.streamErr != 0 { 368 str.CancelWrite(quic.StreamErrorCode(rerr.streamErr)) 369 } 370 if rerr.connErr != 0 { 371 var reason string 372 if rerr.err != nil { 373 reason = rerr.err.Error() 374 } 375 sess.CloseWithError(quic.ApplicationErrorCode(rerr.connErr), reason) 376 } 377 return 378 } 379 str.Close() 380 }() 381 } 382 } 383 384 func (s *Server) handleUnidirectionalStreams(sess quic.EarlySession) { 385 for { 386 str, err := sess.AcceptUniStream(context.Background()) 387 if err != nil { 388 s.logger.Debugf("accepting unidirectional stream failed: %s", err) 389 return 390 } 391 392 go func(str quic.ReceiveStream) { 393 streamType, err := quicvarint.Read(quicvarint.NewReader(str)) 394 if err != nil { 395 s.logger.Debugf("reading stream type on stream %d failed: %s", str.StreamID(), err) 396 return 397 } 398 // We're only interested in the control stream here. 399 switch streamType { 400 case streamTypeControlStream: 401 case streamTypeQPACKEncoderStream, streamTypeQPACKDecoderStream: 402 // Our QPACK implementation doesn't use the dynamic table yet. 403 // TODO: check that only one stream of each type is opened. 404 return 405 case streamTypePushStream: // only the server can push 406 sess.CloseWithError(quic.ApplicationErrorCode(errorStreamCreationError), "") 407 return 408 default: 409 str.CancelRead(quic.StreamErrorCode(errorStreamCreationError)) 410 return 411 } 412 f, err := parseNextFrame(str) 413 if err != nil { 414 sess.CloseWithError(quic.ApplicationErrorCode(errorFrameError), "") 415 return 416 } 417 sf, ok := f.(*settingsFrame) 418 if !ok { 419 sess.CloseWithError(quic.ApplicationErrorCode(errorMissingSettings), "") 420 return 421 } 422 if !sf.Datagram { 423 return 424 } 425 // If datagram support was enabled on our side as well as on the client side, 426 // we can expect it to have been negotiated both on the transport and on the HTTP/3 layer. 427 // Note: ConnectionState() will block until the handshake is complete (relevant when using 0-RTT). 428 if s.EnableDatagrams && !sess.ConnectionState().SupportsDatagrams { 429 sess.CloseWithError(quic.ApplicationErrorCode(errorSettingsError), "missing QUIC Datagram support") 430 } 431 }(str) 432 } 433 } 434 435 func (s *Server) maxHeaderBytes() uint64 { 436 if s.Server.MaxHeaderBytes <= 0 { 437 return http.DefaultMaxHeaderBytes 438 } 439 return uint64(s.Server.MaxHeaderBytes) 440 } 441 442 func (s *Server) handleRequest(sess quic.Session, str quic.Stream, decoder *qpack.Decoder, onFrameError func()) requestError { 443 frame, err := parseNextFrame(str) 444 if err != nil { 445 return newStreamError(errorRequestIncomplete, err) 446 } 447 hf, ok := frame.(*headersFrame) 448 if !ok { 449 return newConnError(errorFrameUnexpected, errors.New("expected first frame to be a HEADERS frame")) 450 } 451 if hf.Length > s.maxHeaderBytes() { 452 return newStreamError(errorFrameError, fmt.Errorf("HEADERS frame too large: %d bytes (max: %d)", hf.Length, s.maxHeaderBytes())) 453 } 454 headerBlock := make([]byte, hf.Length) 455 if _, err := io.ReadFull(str, headerBlock); err != nil { 456 return newStreamError(errorRequestIncomplete, err) 457 } 458 hfs, err := decoder.DecodeFull(headerBlock) 459 if err != nil { 460 // TODO: use the right error code 461 return newConnError(errorGeneralProtocolError, err) 462 } 463 req, err := requestFromHeaders(hfs) 464 if err != nil { 465 // TODO: use the right error code 466 return newStreamError(errorGeneralProtocolError, err) 467 } 468 469 req.RemoteAddr = sess.RemoteAddr().String() 470 req.Body = newRequestBody(str, onFrameError) 471 472 if s.logger.Debug() { 473 s.logger.Infof("%s %s%s, on stream %d", req.Method, req.Host, req.RequestURI, str.StreamID()) 474 } else { 475 s.logger.Infof("%s %s%s", req.Method, req.Host, req.RequestURI) 476 } 477 478 ctx := str.Context() 479 ctx = context.WithValue(ctx, ServerContextKey, s) 480 ctx = context.WithValue(ctx, http.LocalAddrContextKey, sess.LocalAddr()) 481 req = req.WithContext(ctx) 482 r := newResponseWriter(str, s.logger) 483 defer func() { 484 if !r.usedDataStream() { 485 r.Flush() 486 } 487 }() 488 handler := s.Handler 489 if handler == nil { 490 handler = http.DefaultServeMux 491 } 492 493 var panicked bool 494 func() { 495 defer func() { 496 if p := recover(); p != nil { 497 // Copied from net/http/server.go 498 const size = 64 << 10 499 buf := make([]byte, size) 500 buf = buf[:runtime.Stack(buf, false)] 501 s.logger.Errorf("http: panic serving: %v\n%s", p, buf) 502 panicked = true 503 } 504 }() 505 handler.ServeHTTP(r, req) 506 }() 507 508 if !r.usedDataStream() { 509 if panicked { 510 r.WriteHeader(500) 511 } else { 512 r.WriteHeader(200) 513 } 514 // If the EOF was read by the handler, CancelRead() is a no-op. 515 str.CancelRead(quic.StreamErrorCode(errorNoError)) 516 } 517 return requestError{} 518 } 519 520 // Close the server immediately, aborting requests and sending CONNECTION_CLOSE frames to connected clients. 521 // Close in combination with ListenAndServe() (instead of Serve()) may race if it is called before a UDP socket is established. 522 func (s *Server) Close() error { 523 s.closed.Set(true) 524 525 s.mutex.Lock() 526 defer s.mutex.Unlock() 527 528 var err error 529 for ln := range s.listeners { 530 if cerr := (*ln).Close(); cerr != nil && err == nil { 531 err = cerr 532 } 533 } 534 return err 535 } 536 537 // CloseGracefully shuts down the server gracefully. The server sends a GOAWAY frame first, then waits for either timeout to trigger, or for all running requests to complete. 538 // CloseGracefully in combination with ListenAndServe() (instead of Serve()) may race if it is called before a UDP socket is established. 539 func (s *Server) CloseGracefully(timeout time.Duration) error { 540 // TODO: implement 541 return nil 542 } 543 544 // ErrNoAltSvcPort is the error returned by SetQuicHeaders when no port was found 545 // for Alt-Svc to announce. This can happen if listening on a PacketConn without a port 546 // (UNIX socket, for example) and no port is specified in Server.Port or Server.Addr. 547 var ErrNoAltSvcPort = errors.New("no port can be announced, specify it explicitly using Server.Port or Server.Addr") 548 549 // SetQuicHeaders can be used to set the proper headers that announce that this server supports HTTP/3. 550 // The values set by default advertise all of the ports the server is listening on, but can be 551 // changed to a specific port by setting Server.Port before launching the serverr. 552 // If no listener's Addr().String() returns an address with a valid port, Server.Addr will be used 553 // to extract the port, if specified. 554 // For example, a server launched using ListenAndServe on an address with port 443 would set: 555 // Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 556 func (s *Server) SetQuicHeaders(hdr http.Header) error { 557 s.mutex.RLock() 558 defer s.mutex.RUnlock() 559 560 if s.altSvcHeader == "" { 561 return ErrNoAltSvcPort 562 } 563 // use the map directly to avoid constant canonicalization 564 // since the key is already canonicalized 565 hdr["Alt-Svc"] = append(hdr["Alt-Svc"], s.altSvcHeader) 566 return nil 567 } 568 569 // ListenAndServeQUIC listens on the UDP network address addr and calls the 570 // handler for HTTP/3 requests on incoming connections. http.DefaultServeMux is 571 // used when handler is nil. 572 func ListenAndServeQUIC(addr, certFile, keyFile string, handler http.Handler) error { 573 server := &Server{ 574 Server: &http.Server{ 575 Addr: addr, 576 Handler: handler, 577 }, 578 } 579 return server.ListenAndServeTLS(certFile, keyFile) 580 } 581 582 // ListenAndServe listens on the given network address for both, TLS and QUIC 583 // connections in parallel. It returns if one of the two returns an error. 584 // http.DefaultServeMux is used when handler is nil. 585 // The correct Alt-Svc headers for QUIC are set. 586 func ListenAndServe(addr, certFile, keyFile string, handler http.Handler) error { 587 // Load certs 588 var err error 589 certs := make([]tls.Certificate, 1) 590 certs[0], err = tls.LoadX509KeyPair(certFile, keyFile) 591 if err != nil { 592 return err 593 } 594 // We currently only use the cert-related stuff from tls.Config, 595 // so we don't need to make a full copy. 596 config := &tls.Config{ 597 Certificates: certs, 598 } 599 600 // Open the listeners 601 udpAddr, err := net.ResolveUDPAddr("udp", addr) 602 if err != nil { 603 return err 604 } 605 udpConn, err := net.ListenUDP("udp", udpAddr) 606 if err != nil { 607 return err 608 } 609 defer udpConn.Close() 610 611 tcpAddr, err := net.ResolveTCPAddr("tcp", addr) 612 if err != nil { 613 return err 614 } 615 tcpConn, err := net.ListenTCP("tcp", tcpAddr) 616 if err != nil { 617 return err 618 } 619 defer tcpConn.Close() 620 621 tlsConn := tls.NewListener(tcpConn, config) 622 defer tlsConn.Close() 623 624 // Start the servers 625 httpServer := &http.Server{ 626 Addr: addr, 627 TLSConfig: config, 628 } 629 630 quicServer := &Server{ 631 Server: httpServer, 632 } 633 634 if handler == nil { 635 handler = http.DefaultServeMux 636 } 637 httpServer.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 638 quicServer.SetQuicHeaders(w.Header()) 639 handler.ServeHTTP(w, r) 640 }) 641 642 hErr := make(chan error) 643 qErr := make(chan error) 644 go func() { 645 hErr <- httpServer.Serve(tlsConn) 646 }() 647 go func() { 648 qErr <- quicServer.Serve(udpConn) 649 }() 650 651 select { 652 case err := <-hErr: 653 quicServer.Close() 654 return err 655 case err := <-qErr: 656 // Cannot close the HTTP server or wait for requests to complete properly :/ 657 return err 658 } 659 }