select the H3 ALPN based on the QUIC version in use (for the H3 server)

This commit is contained in:
Marten Seemann
2020-10-29 13:08:16 +07:00
parent b7652887d2
commit c968b18a21
10 changed files with 134 additions and 62 deletions

View File

@@ -10,11 +10,13 @@ import (
"net"
"net/http"
"runtime"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/lucas-clemente/quic-go"
"github.com/lucas-clemente/quic-go/internal/handshake"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/marten-seemann/qpack"
)
@@ -25,7 +27,12 @@ var (
quicListenAddr = quic.ListenAddrEarly
)
const nextProtoH3 = "h3-29"
const (
nextProtoH3Draft29 = "h3-29"
nextProtoH3Draft32 = "h3-32"
)
var supportedVersions = []string{nextProtoH3Draft29, nextProtoH3Draft32}
// contextKey is a value for use with context.WithValue. It's used as
// a pointer so it fits in an interface{} without allocation.
@@ -115,32 +122,36 @@ func (s *Server) serveImpl(tlsConf *tls.Config, conn net.PacketConn) error {
s.logger = utils.DefaultLogger.WithPrefix("server")
})
if tlsConf == nil {
tlsConf = &tls.Config{}
} else {
tlsConf = tlsConf.Clone()
}
// Replace existing ALPNs by H3
tlsConf.NextProtos = []string{nextProtoH3}
if tlsConf.GetConfigForClient != nil {
getConfigForClient := tlsConf.GetConfigForClient
tlsConf.GetConfigForClient = func(ch *tls.ClientHelloInfo) (*tls.Config, error) {
conf, err := getConfigForClient(ch)
if err != nil || conf == nil {
return conf, err
// The tls.Config we pass to Listen needs to have the GetConfigForClient callback set.
// That way, we can get the QUIC version and set the correct ALPN value.
baseConf := &tls.Config{
GetConfigForClient: func(ch *tls.ClientHelloInfo) (*tls.Config, error) {
// determine the ALPN from the QUIC version used
proto := nextProtoH3Draft29
if qconn, ok := ch.Conn.(handshake.ConnWithVersion); ok && qconn.GetQUICVersion() == quic.VersionDraft32 {
proto = nextProtoH3Draft32
}
conf := tlsConf
if tlsConf.GetConfigForClient != nil {
getConfigForClient := tlsConf.GetConfigForClient
var err error
conf, err = getConfigForClient(ch)
if err != nil {
return nil, err
}
}
conf = conf.Clone()
conf.NextProtos = []string{nextProtoH3}
conf.NextProtos = []string{proto}
return conf, nil
}
},
}
var ln quic.EarlyListener
var err error
if conn == nil {
ln, err = quicListenAddr(s.Addr, tlsConf, s.QuicConfig)
ln, err = quicListenAddr(s.Addr, baseConf, s.QuicConfig)
} else {
ln, err = quicListen(conn, tlsConf, s.QuicConfig)
ln, err = quicListen(conn, baseConf, s.QuicConfig)
}
if err != nil {
return err
@@ -344,8 +355,11 @@ func (s *Server) SetQuicHeaders(hdr http.Header) error {
atomic.StoreUint32(&s.port, port)
}
hdr.Add("Alt-Svc", fmt.Sprintf(`%s=":%d"; ma=2592000`, nextProtoH3, port))
altSvc := make([]string, len(supportedVersions))
for i, v := range supportedVersions {
altSvc[i] = fmt.Sprintf(`%s=":%d"; ma=2592000`, v, port)
}
hdr.Add("Alt-Svc", strings.Join(altSvc, ","))
return nil
}