mirror of
https://github.com/XTLS/REALITY.git
synced 2026-10-12 09:18:14 +03:00
Sync upstream Go 1.27+; Add "[REALITY] SECTION" comments (#30)
https://github.com/XTLS/REALITY/pull/30#issuecomment-5579024460 https://github.com/XTLS/REALITY/pull/30#issuecomment-5594872257 https://github.com/XTLS/REALITY/pull/38#issuecomment-5752892932
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
// QUICEncryptionLevel represents a QUIC encryption level used to transmit
|
||||
@@ -56,6 +57,9 @@ type QUICConfig struct {
|
||||
// stored in the client session cache.
|
||||
// The application should use [QUICConn.StoreSession] to store sessions.
|
||||
EnableSessionEvents bool
|
||||
|
||||
// ClientHelloInfoConn is the net.Conn to use for the ClientHelloInfo.Conn field.
|
||||
ClientHelloInfoConn net.Conn
|
||||
}
|
||||
|
||||
// A QUICEventKind is a type of operation on a QUIC connection.
|
||||
@@ -117,6 +121,11 @@ const (
|
||||
// The application may modify the [SessionState] before storing it.
|
||||
// This event only occurs on client connections.
|
||||
QUICStoreSession
|
||||
|
||||
// QUICErrorEvent indicates that a fatal error has occurred.
|
||||
// The handshake cannot proceed and the connection must be closed.
|
||||
// QUICEvent.Err is set.
|
||||
QUICErrorEvent
|
||||
)
|
||||
|
||||
// A QUICEvent is an event occurring on a QUIC connection.
|
||||
@@ -138,6 +147,10 @@ type QUICEvent struct {
|
||||
|
||||
// Set for QUICResumeSession and QUICStoreSession.
|
||||
SessionState *SessionState
|
||||
|
||||
// Set for QUICErrorEvent.
|
||||
// The error will wrap AlertError.
|
||||
Err error
|
||||
}
|
||||
|
||||
type quicState struct {
|
||||
@@ -153,10 +166,11 @@ type quicState struct {
|
||||
started bool
|
||||
signalc chan struct{} // handshake data is available to be read
|
||||
blockedc chan struct{} // handshake is waiting for data, closed when done
|
||||
cancelc <-chan struct{} // handshake has been canceled
|
||||
ctx context.Context // handshake context
|
||||
cancel context.CancelFunc
|
||||
|
||||
waitingForDrain bool
|
||||
errorReturned bool
|
||||
|
||||
// readbuf is shared between HandleData and the handshake goroutine.
|
||||
// HandshakeCryptoData passes ownership to the handshake goroutine by
|
||||
@@ -166,23 +180,22 @@ type quicState struct {
|
||||
transportParams []byte // to send to the peer
|
||||
|
||||
enableSessionEvents bool
|
||||
clientHelloInfoConn net.Conn
|
||||
}
|
||||
|
||||
// QUICClient returns a new TLS client side connection using QUICTransport as the
|
||||
// underlying transport. The config cannot be nil.
|
||||
//
|
||||
// The config's MinVersion must be at least TLS 1.3.
|
||||
func QUICClient(config *QUICConfig) *QUICConn {
|
||||
return newQUICConn(Client(nil, config.TLSConfig), config)
|
||||
}
|
||||
|
||||
// QUICServer returns a new TLS server side connection using QUICTransport as the
|
||||
// underlying transport. The config cannot be nil.
|
||||
//
|
||||
// The config's MinVersion must be at least TLS 1.3.
|
||||
func QUICServer(config *QUICConfig) *QUICConn {
|
||||
//////////////////////////////////// [REALITY] SECTION: create Reality server
|
||||
c, _ := Server(context.Background(), nil, config.TLSConfig)
|
||||
return newQUICConn(c, config)
|
||||
//////////////////////////////////// [REALITY] SECTION END
|
||||
}
|
||||
|
||||
func newQUICConn(conn *Conn, config *QUICConfig) *QUICConn {
|
||||
@@ -190,6 +203,7 @@ func newQUICConn(conn *Conn, config *QUICConfig) *QUICConn {
|
||||
signalc: make(chan struct{}),
|
||||
blockedc: make(chan struct{}),
|
||||
enableSessionEvents: config.EnableSessionEvents,
|
||||
clientHelloInfoConn: config.ClientHelloInfoConn,
|
||||
}
|
||||
conn.quic.events = conn.quic.eventArr[:0]
|
||||
return &QUICConn{
|
||||
@@ -206,9 +220,6 @@ func (q *QUICConn) Start(ctx context.Context) error {
|
||||
return quicError(errors.New("tls: Start called more than once"))
|
||||
}
|
||||
q.conn.quic.started = true
|
||||
if q.conn.config.MinVersion < VersionTLS13 {
|
||||
return quicError(errors.New("tls: Config MinVersion must be at least TLS 1.3"))
|
||||
}
|
||||
go q.conn.HandshakeContext(ctx)
|
||||
if _, ok := <-q.conn.quic.blockedc; !ok {
|
||||
return q.conn.handshakeErr
|
||||
@@ -222,7 +233,7 @@ func (q *QUICConn) NextEvent() QUICEvent {
|
||||
qs := q.conn.quic
|
||||
if last := qs.nextEvent - 1; last >= 0 && len(qs.events[last].Data) > 0 {
|
||||
// Write over some of the previous event's data,
|
||||
// to catch callers erroniously retaining it.
|
||||
// to catch callers erroneously retaining it.
|
||||
qs.events[last].Data[0] = 0
|
||||
}
|
||||
if qs.nextEvent >= len(qs.events) && qs.waitingForDrain {
|
||||
@@ -230,6 +241,15 @@ func (q *QUICConn) NextEvent() QUICEvent {
|
||||
<-qs.signalc
|
||||
<-qs.blockedc
|
||||
}
|
||||
if err := q.conn.handshakeErr; err != nil {
|
||||
if qs.errorReturned {
|
||||
return QUICEvent{Kind: QUICNoEvent}
|
||||
}
|
||||
qs.errorReturned = true
|
||||
qs.events = nil
|
||||
qs.nextEvent = 0
|
||||
return QUICEvent{Kind: QUICErrorEvent, Err: q.conn.handshakeErr}
|
||||
}
|
||||
if qs.nextEvent >= len(qs.events) {
|
||||
qs.events = qs.events[:0]
|
||||
qs.nextEvent = 0
|
||||
@@ -243,10 +263,11 @@ func (q *QUICConn) NextEvent() QUICEvent {
|
||||
|
||||
// Close closes the connection and stops any in-progress handshake.
|
||||
func (q *QUICConn) Close() error {
|
||||
if q.conn.quic.cancel == nil {
|
||||
if q.conn.quic.ctx == nil {
|
||||
return nil // never started
|
||||
}
|
||||
q.conn.quic.cancel()
|
||||
<-q.conn.quic.signalc
|
||||
for range q.conn.quic.blockedc {
|
||||
// Wait for the handshake goroutine to return.
|
||||
}
|
||||
@@ -270,9 +291,9 @@ func (q *QUICConn) HandleData(level QUICEncryptionLevel, data []byte) error {
|
||||
// The handshake goroutine has exited.
|
||||
c.handshakeMutex.Lock()
|
||||
defer c.handshakeMutex.Unlock()
|
||||
c.hand.Write(c.quic.readbuf)
|
||||
c.handBuf().Write(c.quic.readbuf)
|
||||
c.quic.readbuf = nil
|
||||
for q.conn.hand.Len() >= 4 && q.conn.handshakeErr == nil {
|
||||
for q.conn.handLen() >= 4 && q.conn.handshakeErr == nil {
|
||||
b := q.conn.hand.Bytes()
|
||||
n := int(b[1])<<16 | int(b[2])<<8 | int(b[3])
|
||||
if n > maxHandshake {
|
||||
@@ -286,6 +307,7 @@ func (q *QUICConn) HandleData(level QUICEncryptionLevel, data []byte) error {
|
||||
q.conn.handshakeErr = err
|
||||
}
|
||||
}
|
||||
q.conn.releaseHand()
|
||||
if q.conn.handshakeErr != nil {
|
||||
return quicError(q.conn.handshakeErr)
|
||||
}
|
||||
@@ -303,6 +325,9 @@ type QUICSessionTicketOptions struct {
|
||||
// Currently, it can only be called once.
|
||||
func (q *QUICConn) SendSessionTicket(opts QUICSessionTicketOptions) error {
|
||||
c := q.conn
|
||||
if c.config.SessionTicketsDisabled {
|
||||
return nil
|
||||
}
|
||||
if !c.isHandshakeComplete.Load() {
|
||||
return quicError(errors.New("tls: SendSessionTicket called before handshake completed"))
|
||||
}
|
||||
@@ -360,12 +385,11 @@ func quicError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
var ae AlertError
|
||||
if errors.As(err, &ae) {
|
||||
if _, ok := errors.AsType[AlertError](err); ok {
|
||||
return err
|
||||
}
|
||||
var a alert
|
||||
if !errors.As(err, &a) {
|
||||
a, ok := errors.AsType[alert](err)
|
||||
if !ok {
|
||||
a = alertInternalError
|
||||
}
|
||||
// Return an error wrapping the original error and an AlertError.
|
||||
@@ -374,7 +398,7 @@ func quicError(err error) error {
|
||||
}
|
||||
|
||||
func (c *Conn) quicReadHandshakeBytes(n int) error {
|
||||
for c.hand.Len() < n {
|
||||
for c.handLen() < n {
|
||||
if err := c.quicWaitForSignal(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -382,13 +406,22 @@ func (c *Conn) quicReadHandshakeBytes(n int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Conn) quicSetReadSecret(level QUICEncryptionLevel, suite uint16, secret []byte) {
|
||||
func (c *Conn) quicSetReadSecret(level QUICEncryptionLevel, suite uint16, secret []byte) error {
|
||||
// Ensure that there are no buffered handshake messages before changing the
|
||||
// read keys, since that can cause messages to be parsed that were encrypted
|
||||
// using old keys which are no longer appropriate.
|
||||
// TODO(roland): we should merge this check with the similar one in setReadTrafficSecret.
|
||||
if c.handLen() != 0 {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return errors.New("tls: handshake buffer not empty before setting read traffic secret")
|
||||
}
|
||||
c.quic.events = append(c.quic.events, QUICEvent{
|
||||
Kind: QUICSetReadSecret,
|
||||
Level: level,
|
||||
Suite: suite,
|
||||
Data: secret,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Conn) quicSetWriteSecret(level QUICEncryptionLevel, suite uint16, secret []byte) {
|
||||
@@ -482,20 +515,16 @@ func (c *Conn) quicWaitForSignal() error {
|
||||
// Send on blockedc to notify the QUICConn that the handshake is blocked.
|
||||
// Exported methods of QUICConn wait for the handshake to become blocked
|
||||
// before returning to the user.
|
||||
select {
|
||||
case c.quic.blockedc <- struct{}{}:
|
||||
case <-c.quic.cancelc:
|
||||
return c.sendAlertLocked(alertCloseNotify)
|
||||
}
|
||||
c.quic.blockedc <- struct{}{}
|
||||
// The QUICConn reads from signalc to notify us that the handshake may
|
||||
// be able to proceed. (The QUICConn reads, because we close signalc to
|
||||
// indicate that the handshake has completed.)
|
||||
select {
|
||||
case c.quic.signalc <- struct{}{}:
|
||||
c.hand.Write(c.quic.readbuf)
|
||||
c.quic.readbuf = nil
|
||||
case <-c.quic.cancelc:
|
||||
c.quic.signalc <- struct{}{}
|
||||
if c.quic.ctx.Err() != nil {
|
||||
// The connection has been canceled.
|
||||
return c.sendAlertLocked(alertCloseNotify)
|
||||
}
|
||||
c.handBuf().Write(c.quic.readbuf)
|
||||
c.quic.readbuf = nil
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user