Skip to content

Commit

Permalink
Allow use of custom port value in Alt-Svc header.
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronriekenberg committed Sep 11, 2021
1 parent ebcd98e commit ce8167c
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 12 deletions.
8 changes: 7 additions & 1 deletion example/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down Expand Up @@ -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},
Expand Down
41 changes: 30 additions & 11 deletions http3/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{}
Expand Down Expand Up @@ -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
}
portInt, err := net.LookupPort("tcp", portStr)
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)
}
port = uint32(portInt)

atomic.StoreUint32(&s.port, port)
}

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit ce8167c

Please sign in to comment.