uquic/server_tls.go
2018-10-26 16:18:49 +07:00

166 lines
4.6 KiB
Go

package quic
import (
"bytes"
"crypto/tls"
"errors"
"net"
"github.com/lucas-clemente/quic-go/internal/handshake"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/internal/wire"
)
type tlsSession struct {
connID protocol.ConnectionID
sess quicSession
}
type serverTLS struct {
conn net.PacketConn
config *Config
tlsConf *tls.Config
params *handshake.TransportParameters
cookieGenerator *handshake.CookieGenerator
newSession func(connection, sessionRunner, protocol.ConnectionID, protocol.ConnectionID, protocol.ConnectionID, protocol.PacketNumber, *Config, *tls.Config, *handshake.TransportParameters, utils.Logger, protocol.VersionNumber) (quicSession, error)
sessionRunner sessionRunner
sessionChan chan<- tlsSession
logger utils.Logger
}
func newServerTLS(
conn net.PacketConn,
config *Config,
runner sessionRunner,
tlsConf *tls.Config,
logger utils.Logger,
) (*serverTLS, <-chan tlsSession, error) {
cookieGenerator, err := handshake.NewCookieGenerator()
if err != nil {
return nil, nil, err
}
params := &handshake.TransportParameters{
StreamFlowControlWindow: protocol.ReceiveStreamFlowControlWindow,
ConnectionFlowControlWindow: protocol.ReceiveConnectionFlowControlWindow,
IdleTimeout: config.IdleTimeout,
MaxBidiStreams: uint16(config.MaxIncomingStreams),
MaxUniStreams: uint16(config.MaxIncomingUniStreams),
DisableMigration: true,
// TODO(#855): generate a real token
StatelessResetToken: bytes.Repeat([]byte{42}, 16),
}
sessionChan := make(chan tlsSession)
s := &serverTLS{
conn: conn,
config: config,
tlsConf: tlsConf,
sessionRunner: runner,
sessionChan: sessionChan,
cookieGenerator: cookieGenerator,
params: params,
newSession: newTLSServerSession,
logger: logger,
}
return s, sessionChan, nil
}
func (s *serverTLS) HandleInitial(p *receivedPacket) {
// TODO: add a check that DestConnID == SrcConnID
s.logger.Debugf("<- Received Initial packet.")
sess, connID, err := s.handleInitialImpl(p)
if err != nil {
s.logger.Errorf("Error occurred handling initial packet: %s", err)
return
}
if sess == nil { // a stateless reset was done
return
}
s.sessionChan <- tlsSession{
connID: connID,
sess: sess,
}
}
func (s *serverTLS) handleInitialImpl(p *receivedPacket) (quicSession, protocol.ConnectionID, error) {
hdr := p.header
if len(hdr.Token) == 0 && hdr.DestConnectionID.Len() < protocol.MinConnectionIDLenInitial {
return nil, nil, errors.New("dropping Initial packet with too short connection ID")
}
if len(hdr.Raw)+len(p.data) < protocol.MinInitialPacketSize {
return nil, nil, errors.New("dropping too small Initial packet")
}
var cookie *handshake.Cookie
if len(hdr.Token) > 0 {
c, err := s.cookieGenerator.DecodeToken(hdr.Token)
if err == nil {
cookie = c
}
}
if !s.config.AcceptCookie(p.remoteAddr, cookie) {
// Log the Initial packet now.
// If no Retry is sent, the packet will be logged by the session.
p.header.Log(s.logger)
return nil, nil, s.sendRetry(p.remoteAddr, hdr)
}
connID, err := protocol.GenerateConnectionID(s.config.ConnectionIDLength)
if err != nil {
return nil, nil, err
}
s.logger.Debugf("Changing connection ID to %s.", connID)
sess, err := s.newSession(
&conn{pconn: s.conn, currentAddr: p.remoteAddr},
s.sessionRunner,
hdr.DestConnectionID,
hdr.SrcConnectionID,
connID,
1,
s.config,
s.tlsConf,
s.params,
s.logger,
hdr.Version,
)
if err != nil {
return nil, nil, err
}
go sess.run()
sess.handlePacket(p)
return sess, connID, nil
}
func (s *serverTLS) sendRetry(remoteAddr net.Addr, hdr *wire.Header) error {
token, err := s.cookieGenerator.NewToken(remoteAddr)
if err != nil {
return err
}
connID, err := protocol.GenerateConnectionID(s.config.ConnectionIDLength)
if err != nil {
return err
}
replyHdr := &wire.Header{
IsLongHeader: true,
Type: protocol.PacketTypeRetry,
Version: hdr.Version,
SrcConnectionID: connID,
DestConnectionID: hdr.SrcConnectionID,
OrigDestConnectionID: hdr.DestConnectionID,
Token: token,
}
s.logger.Debugf("Changing connection ID to %s.\n-> Sending Retry", connID)
replyHdr.Log(s.logger)
buf := &bytes.Buffer{}
if err := replyHdr.Write(buf, protocol.PerspectiveServer, hdr.Version); err != nil {
return err
}
if _, err := s.conn.WriteTo(buf.Bytes(), remoteAddr); err != nil {
s.logger.Debugf("Error sending Retry: %s", err)
}
return nil
}