From ce8167c3cf1d263511400bf964753eb0c5bcab06 Mon Sep 17 00:00:00 2001 From: Aaron Riekenberg Date: Sat, 11 Sep 2021 10:43:37 -0500 Subject: [PATCH 1/4] Allow use of custom port value in Alt-Svc header. --- example/main.go | 8 +++++++- http3/server.go | 41 ++++++++++++++++++++++++++++++----------- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/example/main.go b/example/main.go index 9f53b5f9d..d29097de4 100644 --- a/example/main.go +++ b/example/main.go @@ -144,6 +144,7 @@ func main() { flag.Var(&bs, "bind", "bind to") www := flag.String("www", "", "www data") tcp := flag.Bool("tcp", false, "also listen on TCP") + customAltSvcPort := flag.Uint("customAltSvcPort", 0, "use custom Alt-Svc header port value") enableQlog := flag.Bool("qlog", false, "output a qlog (in the same directory)") flag.Parse() @@ -182,7 +183,12 @@ func main() { var err error if *tcp { certFile, keyFile := testdata.GetCertificatePaths() - err = http3.ListenAndServe(bCap, certFile, keyFile, handler) + if *customAltSvcPort != 0 { + logger.Infof("using customAltSvcPort = %v", *customAltSvcPort) + err = http3.ListenAndServeWithCustomAltSvcPort(bCap, certFile, keyFile, handler, uint32(*customAltSvcPort)) + } else { + err = http3.ListenAndServe(bCap, certFile, keyFile, handler) + } } else { server := http3.Server{ Server: &http.Server{Handler: handler, Addr: bCap}, diff --git a/http3/server.go b/http3/server.go index b798abd42..df3584cc1 100644 --- a/http3/server.go +++ b/http3/server.go @@ -92,7 +92,8 @@ type Server struct { // See https://www.ietf.org/archive/id/draft-schinazi-masque-h3-datagram-02.html. EnableDatagrams bool - port uint32 // used atomically + port uint32 // used atomically + customAltSvcPort uint32 // custom port used for Alt-Svc response header mutex sync.Mutex listeners map[*quic.EarlyListener]struct{} @@ -439,16 +440,22 @@ func (s *Server) SetQuicHeaders(hdr http.Header) error { port := atomic.LoadUint32(&s.port) if port == 0 { - // Extract port from s.Server.Addr - _, portStr, err := net.SplitHostPort(s.Server.Addr) - if err != nil { - return err + if s.customAltSvcPort != 0 { + // Use customAltSvcPort if set + port = s.customAltSvcPort + } else { + // Extract port from s.Server.Addr + _, portStr, err := net.SplitHostPort(s.Server.Addr) + if err != nil { + return err + } + portInt, err := net.LookupPort("tcp", portStr) + if err != nil { + return err + } + port = uint32(portInt) } - portInt, err := net.LookupPort("tcp", portStr) - if err != nil { - return err - } - port = uint32(portInt) + atomic.StoreUint32(&s.port, port) } @@ -486,6 +493,17 @@ func ListenAndServeQUIC(addr, certFile, keyFile string, handler http.Handler) er // http.DefaultServeMux is used when handler is nil. // The correct Alt-Svc headers for QUIC are set. func ListenAndServe(addr, certFile, keyFile string, handler http.Handler) error { + return ListenAndServeWithCustomAltSvcPort(addr, certFile, keyFile, handler, 0) +} + +// ListenAndServeWithCustomAltSvcPort listens on the given network address for both, TLS and QUIC +// connetions in parallel. It returns if one of the two returns an error. +// http.DefaultServeMux is used when handler is nil. +// The correct Alt-Svc headers for QUIC are set. +// customAltSvcPort is used to override the default port value in the Alt-Svc response header. +// This is useful when a Layer 4 firewall is redirecting UDP traffic and clients must use +// a port different from the port the QUIC server itself is listening on. +func ListenAndServeWithCustomAltSvcPort(addr, certFile, keyFile string, handler http.Handler, customAltSvcPort uint32) error { // Load certs var err error certs := make([]tls.Certificate, 1) @@ -530,7 +548,8 @@ func ListenAndServe(addr, certFile, keyFile string, handler http.Handler) error } quicServer := &Server{ - Server: httpServer, + Server: httpServer, + customAltSvcPort: customAltSvcPort, } if handler == nil { From 8b56e7d2b53e21e2e6e54096aca6805966d59aba Mon Sep 17 00:00:00 2001 From: Aaron Riekenberg Date: Sat, 18 Sep 2021 10:22:57 -0500 Subject: [PATCH 2/4] Revert "Allow use of custom port value in Alt-Svc header." This reverts commit ce8167c3cf1d263511400bf964753eb0c5bcab06. --- example/main.go | 8 +------- http3/server.go | 41 +++++++++++------------------------------ 2 files changed, 12 insertions(+), 37 deletions(-) diff --git a/example/main.go b/example/main.go index d29097de4..9f53b5f9d 100644 --- a/example/main.go +++ b/example/main.go @@ -144,7 +144,6 @@ func main() { flag.Var(&bs, "bind", "bind to") www := flag.String("www", "", "www data") tcp := flag.Bool("tcp", false, "also listen on TCP") - customAltSvcPort := flag.Uint("customAltSvcPort", 0, "use custom Alt-Svc header port value") enableQlog := flag.Bool("qlog", false, "output a qlog (in the same directory)") flag.Parse() @@ -183,12 +182,7 @@ func main() { var err error if *tcp { certFile, keyFile := testdata.GetCertificatePaths() - if *customAltSvcPort != 0 { - logger.Infof("using customAltSvcPort = %v", *customAltSvcPort) - err = http3.ListenAndServeWithCustomAltSvcPort(bCap, certFile, keyFile, handler, uint32(*customAltSvcPort)) - } else { - err = http3.ListenAndServe(bCap, certFile, keyFile, handler) - } + err = http3.ListenAndServe(bCap, certFile, keyFile, handler) } else { server := http3.Server{ Server: &http.Server{Handler: handler, Addr: bCap}, diff --git a/http3/server.go b/http3/server.go index df3584cc1..b798abd42 100644 --- a/http3/server.go +++ b/http3/server.go @@ -92,8 +92,7 @@ type Server struct { // See https://www.ietf.org/archive/id/draft-schinazi-masque-h3-datagram-02.html. EnableDatagrams bool - port uint32 // used atomically - customAltSvcPort uint32 // custom port used for Alt-Svc response header + port uint32 // used atomically mutex sync.Mutex listeners map[*quic.EarlyListener]struct{} @@ -440,22 +439,16 @@ func (s *Server) SetQuicHeaders(hdr http.Header) error { port := atomic.LoadUint32(&s.port) if port == 0 { - if s.customAltSvcPort != 0 { - // Use customAltSvcPort if set - port = s.customAltSvcPort - } else { - // Extract port from s.Server.Addr - _, portStr, err := net.SplitHostPort(s.Server.Addr) - if err != nil { - return err - } - portInt, err := net.LookupPort("tcp", portStr) - if err != nil { - return err - } - port = uint32(portInt) + // Extract port from s.Server.Addr + _, portStr, err := net.SplitHostPort(s.Server.Addr) + if err != nil { + return err } - + portInt, err := net.LookupPort("tcp", portStr) + if err != nil { + return err + } + port = uint32(portInt) atomic.StoreUint32(&s.port, port) } @@ -493,17 +486,6 @@ func ListenAndServeQUIC(addr, certFile, keyFile string, handler http.Handler) er // http.DefaultServeMux is used when handler is nil. // The correct Alt-Svc headers for QUIC are set. func ListenAndServe(addr, certFile, keyFile string, handler http.Handler) error { - return ListenAndServeWithCustomAltSvcPort(addr, certFile, keyFile, handler, 0) -} - -// ListenAndServeWithCustomAltSvcPort listens on the given network address for both, TLS and QUIC -// connetions in parallel. It returns if one of the two returns an error. -// http.DefaultServeMux is used when handler is nil. -// The correct Alt-Svc headers for QUIC are set. -// customAltSvcPort is used to override the default port value in the Alt-Svc response header. -// This is useful when a Layer 4 firewall is redirecting UDP traffic and clients must use -// a port different from the port the QUIC server itself is listening on. -func ListenAndServeWithCustomAltSvcPort(addr, certFile, keyFile string, handler http.Handler, customAltSvcPort uint32) error { // Load certs var err error certs := make([]tls.Certificate, 1) @@ -548,8 +530,7 @@ func ListenAndServeWithCustomAltSvcPort(addr, certFile, keyFile string, handler } quicServer := &Server{ - Server: httpServer, - customAltSvcPort: customAltSvcPort, + Server: httpServer, } if handler == nil { From 43ee0c6757b8a4caa0582863a4cb114fb951c2c6 Mon Sep 17 00:00:00 2001 From: Aaron Riekenberg Date: Sat, 18 Sep 2021 10:29:37 -0500 Subject: [PATCH 3/4] Export http3.Server.Port. --- http3/server.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/http3/server.go b/http3/server.go index b798abd42..ce5bc909f 100644 --- a/http3/server.go +++ b/http3/server.go @@ -92,7 +92,11 @@ type Server struct { // See https://www.ietf.org/archive/id/draft-schinazi-masque-h3-datagram-02.html. EnableDatagrams bool - port uint32 // used atomically + // The port to use in Alt-Svc response headers. + // If needed Port can be manually set when the Server is created. + // This is useful when a Layer 4 firewall is redirecting UDP traffic and clients must use + // a port different from the port the Server is listening on. + Port uint32 mutex sync.Mutex listeners map[*quic.EarlyListener]struct{} @@ -436,7 +440,7 @@ func (s *Server) CloseGracefully(timeout time.Duration) error { // The values that are set depend on the port information from s.Server.Addr, and currently look like this (if Addr has port 443): // Alt-Svc: quic=":443"; ma=2592000; v="33,32,31,30" func (s *Server) SetQuicHeaders(hdr http.Header) error { - port := atomic.LoadUint32(&s.port) + port := atomic.LoadUint32(&s.Port) if port == 0 { // Extract port from s.Server.Addr @@ -449,7 +453,7 @@ func (s *Server) SetQuicHeaders(hdr http.Header) error { return err } port = uint32(portInt) - atomic.StoreUint32(&s.port, port) + atomic.StoreUint32(&s.Port, port) } // This code assumes that we will use protocol.SupportedVersions if no quic.Config is passed. From afbe993b4c6720cfb8f21ad15c8da7cf00174433 Mon Sep 17 00:00:00 2001 From: Aaron Riekenberg Date: Sun, 19 Sep 2021 15:51:09 -0500 Subject: [PATCH 4/4] Add test setting http3.Server.Port. --- http3/server_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/http3/server_test.go b/http3/server_test.go index 04896ad39..02e9c4166 100644 --- a/http3/server_test.go +++ b/http3/server_test.go @@ -591,6 +591,14 @@ var _ = Describe("Server", func() { Expect(s.SetQuicHeaders(hdr)).To(Succeed()) Expect(hdr).To(Equal(http.Header{"Alt-Svc": {`h3=":443"; ma=2592000,h3-29=":443"; ma=2592000`}})) }) + + It("uses s.Port if set to a non-zero value", func() { + s.Server.Addr = ":443" + s.Port = 8443 + hdr := http.Header{} + Expect(s.SetQuicHeaders(hdr)).To(Succeed()) + Expect(hdr).To(Equal(http.Header{"Alt-Svc": {`h3-29=":8443"; ma=2592000`}})) + }) }) It("errors when ListenAndServe is called with s.Server nil", func() {