package handshake import ( "errors" "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol" "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/qerr" "v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils" "v2ray.com/core/external/github.com/marten-seemann/qtls" ) type extensionHandlerServer struct { ourParams *TransportParameters paramsChan chan<- TransportParameters version protocol.VersionNumber supportedVersions []protocol.VersionNumber logger utils.Logger } var _ tlsExtensionHandler = &extensionHandlerServer{} // newExtensionHandlerServer creates a new extension handler for the server func newExtensionHandlerServer( params *TransportParameters, supportedVersions []protocol.VersionNumber, version protocol.VersionNumber, logger utils.Logger, ) (tlsExtensionHandler, <-chan TransportParameters) { // Processing the ClientHello is performed statelessly (and from a single go-routine). // Therefore, we have to use a buffered chan to pass the transport parameters to that go routine. paramsChan := make(chan TransportParameters) return &extensionHandlerServer{ ourParams: params, paramsChan: paramsChan, supportedVersions: supportedVersions, version: version, logger: logger, }, paramsChan } func (h *extensionHandlerServer) GetExtensions(msgType uint8) []qtls.Extension { if messageType(msgType) != typeEncryptedExtensions { return nil } h.logger.Debugf("Sending Transport Parameters: %s", h.ourParams) return []qtls.Extension{{ Type: quicTLSExtensionType, Data: (&encryptedExtensionsTransportParameters{ NegotiatedVersion: h.version, SupportedVersions: protocol.GetGreasedVersions(h.supportedVersions), Parameters: *h.ourParams, }).Marshal(), }} } func (h *extensionHandlerServer) ReceivedExtensions(msgType uint8, exts []qtls.Extension) error { if messageType(msgType) != typeClientHello { return nil } var found bool chtp := &clientHelloTransportParameters{} for _, ext := range exts { if ext.Type != quicTLSExtensionType { continue } if err := chtp.Unmarshal(ext.Data); err != nil { return err } found = true } if !found { return errors.New("ClientHello didn't contain a QUIC extension") } // perform the stateless version negotiation validation: // make sure that we would have sent a Version Negotiation Packet if the client offered the initial version // this is the case if and only if the initial version is not contained in the supported versions if chtp.InitialVersion != h.version && protocol.IsSupportedVersion(h.supportedVersions, chtp.InitialVersion) { return qerr.Error(qerr.VersionNegotiationMismatch, "Client should have used the initial version") } h.logger.Debugf("Received Transport Parameters: %s", &chtp.Parameters) h.paramsChan <- chtp.Parameters return nil }