Files
sing-box-extended-mirror/common/tls/client.go
T

140 lines
4.2 KiB
Go
Raw Normal View History

2022-09-09 18:45:10 +08:00
package tls
import (
"context"
2025-08-11 21:18:34 +08:00
"crypto/tls"
"errors"
2022-09-09 18:45:10 +08:00
"net"
"os"
2023-12-20 20:00:00 +08:00
"github.com/sagernet/sing-box/common/badtls"
2022-09-09 18:45:10 +08:00
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option"
2025-09-07 21:03:32 +08:00
"github.com/sagernet/sing/common/logger"
2022-09-09 18:45:10 +08:00
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
2023-02-28 11:30:46 +08:00
aTLS "github.com/sagernet/sing/common/tls"
2022-09-09 18:45:10 +08:00
)
2025-09-07 21:03:32 +08:00
func NewDialerFromOptions(ctx context.Context, logger logger.ContextLogger, dialer N.Dialer, serverAddress string, options option.OutboundTLSOptions) (N.Dialer, error) {
2022-11-13 11:24:37 +08:00
if !options.Enabled {
return dialer, nil
}
config, err := NewClientWithOptions(ClientOptions{
Context: ctx,
Logger: logger,
ServerAddress: serverAddress,
Options: options,
})
2022-09-09 18:45:10 +08:00
if err != nil {
return nil, err
}
return NewDialer(dialer, config), nil
}
2025-09-07 21:03:32 +08:00
func NewClient(ctx context.Context, logger logger.ContextLogger, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
return NewClientWithOptions(ClientOptions{
Context: ctx,
Logger: logger,
ServerAddress: serverAddress,
Options: options,
})
}
type ClientOptions struct {
Context context.Context
Logger logger.ContextLogger
ServerAddress string
Options option.OutboundTLSOptions
KTLSCompatible bool
}
func NewClientWithOptions(options ClientOptions) (Config, error) {
if !options.Options.Enabled {
2022-11-13 11:24:37 +08:00
return nil, nil
}
if !options.KTLSCompatible {
if options.Options.KernelTx {
options.Logger.Warn("enabling kTLS TX in current scenarios will definitely reduce performance, please checkout https://sing-box.sagernet.org/configuration/shared/tls/#kernel_tx")
}
}
if options.Options.KernelRx {
options.Logger.Warn("enabling kTLS RX will definitely reduce performance, please checkout https://sing-box.sagernet.org/configuration/shared/tls/#kernel_rx")
}
if options.Options.Reality != nil && options.Options.Reality.Enabled {
return NewRealityClient(options.Context, options.Logger, options.ServerAddress, options.Options)
} else if options.Options.UTLS != nil && options.Options.UTLS.Enabled {
return NewUTLSClient(options.Context, options.Logger, options.ServerAddress, options.Options)
2022-09-09 18:19:50 +08:00
}
return NewSTDClient(options.Context, options.Logger, options.ServerAddress, options.Options)
2022-09-09 18:45:10 +08:00
}
func ClientHandshake(ctx context.Context, conn net.Conn, config Config) (Conn, error) {
2022-09-09 18:45:10 +08:00
ctx, cancel := context.WithTimeout(ctx, C.TCPTimeout)
defer cancel()
2023-12-20 20:00:00 +08:00
tlsConn, err := aTLS.ClientHandshake(ctx, conn, config)
if err != nil {
return nil, err
}
readWaitConn, err := badtls.NewReadWaitConn(tlsConn)
if err == nil {
return readWaitConn, nil
} else if err != os.ErrInvalid {
return nil, err
}
return tlsConn, nil
2022-09-09 18:45:10 +08:00
}
2025-10-07 13:41:25 +08:00
type Dialer interface {
N.Dialer
DialTLSContext(ctx context.Context, destination M.Socksaddr) (Conn, error)
}
type defaultDialer struct {
2022-09-09 18:45:10 +08:00
dialer N.Dialer
config Config
}
2025-10-07 13:41:25 +08:00
func NewDialer(dialer N.Dialer, config Config) Dialer {
return &defaultDialer{dialer, config}
2022-09-09 18:45:10 +08:00
}
2025-10-07 13:41:25 +08:00
func (d *defaultDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
if N.NetworkName(network) != N.NetworkTCP {
2022-09-09 18:45:10 +08:00
return nil, os.ErrInvalid
}
2025-10-07 13:41:25 +08:00
return d.DialTLSContext(ctx, destination)
}
func (d *defaultDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
return nil, os.ErrInvalid
}
func (d *defaultDialer) DialTLSContext(ctx context.Context, destination M.Socksaddr) (Conn, error) {
2025-08-11 21:18:34 +08:00
return d.dialContext(ctx, destination, true)
2025-10-07 13:41:25 +08:00
}
2025-08-11 21:18:34 +08:00
func (d *defaultDialer) dialContext(ctx context.Context, destination M.Socksaddr, echRetry bool) (Conn, error) {
2025-10-07 13:41:25 +08:00
conn, err := d.dialer.DialContext(ctx, N.NetworkTCP, destination)
if err != nil {
return nil, err
}
tlsConn, err := aTLS.ClientHandshake(ctx, conn, d.config)
2025-10-07 13:19:57 +08:00
if err != nil {
conn.Close()
2025-08-11 21:18:34 +08:00
var echErr *tls.ECHRejectionError
2025-10-07 13:19:57 +08:00
if echRetry && errors.As(err, &echErr) && len(echErr.RetryConfigList) > 0 {
2025-08-11 21:18:34 +08:00
if echConfig, isECH := d.config.(ECHCapableConfig); isECH {
echConfig.SetECHConfigList(echErr.RetryConfigList)
2025-10-07 13:19:57 +08:00
return d.dialContext(ctx, destination, false)
2025-08-11 21:18:34 +08:00
}
}
2025-10-07 13:19:57 +08:00
return nil, err
2025-08-11 21:18:34 +08:00
}
2025-10-07 13:19:57 +08:00
return tlsConn, nil
2022-09-09 18:45:10 +08:00
}
2025-10-07 13:41:25 +08:00
func (d *defaultDialer) Upstream() any {
return d.dialer
2022-09-09 18:45:10 +08:00
}