123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- package tls
- import (
- "context"
- "crypto/tls"
- "errors"
- "net"
- "os"
- "github.com/sagernet/sing-box/common/badtls"
- C "github.com/sagernet/sing-box/constant"
- "github.com/sagernet/sing-box/option"
- "github.com/sagernet/sing/common/logger"
- M "github.com/sagernet/sing/common/metadata"
- N "github.com/sagernet/sing/common/network"
- aTLS "github.com/sagernet/sing/common/tls"
- )
- func NewDialerFromOptions(ctx context.Context, logger logger.ContextLogger, dialer N.Dialer, serverAddress string, options option.OutboundTLSOptions) (N.Dialer, error) {
- if !options.Enabled {
- return dialer, nil
- }
- config, err := NewClient(ctx, logger, serverAddress, options)
- if err != nil {
- return nil, err
- }
- return NewDialer(dialer, config), nil
- }
- func NewClient(ctx context.Context, logger logger.ContextLogger, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
- if !options.Enabled {
- return nil, nil
- }
- if options.Reality != nil && options.Reality.Enabled {
- return NewRealityClient(ctx, logger, serverAddress, options)
- } else if options.UTLS != nil && options.UTLS.Enabled {
- return NewUTLSClient(ctx, logger, serverAddress, options)
- }
- return NewSTDClient(ctx, logger, serverAddress, options)
- }
- func ClientHandshake(ctx context.Context, conn net.Conn, config Config) (Conn, error) {
- ctx, cancel := context.WithTimeout(ctx, C.TCPTimeout)
- defer cancel()
- 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
- }
- type Dialer interface {
- N.Dialer
- DialTLSContext(ctx context.Context, destination M.Socksaddr) (Conn, error)
- }
- type defaultDialer struct {
- dialer N.Dialer
- config Config
- }
- func NewDialer(dialer N.Dialer, config Config) Dialer {
- return &defaultDialer{dialer, config}
- }
- func (d *defaultDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
- if N.NetworkName(network) != N.NetworkTCP {
- return nil, os.ErrInvalid
- }
- 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) {
- return d.dialContext(ctx, destination, true)
- }
- func (d *defaultDialer) dialContext(ctx context.Context, destination M.Socksaddr, echRetry bool) (Conn, error) {
- conn, err := d.dialer.DialContext(ctx, N.NetworkTCP, destination)
- if err != nil {
- return nil, err
- }
- tlsConn, err := aTLS.ClientHandshake(ctx, conn, d.config)
- if err != nil {
- conn.Close()
- var echErr *tls.ECHRejectionError
- if echRetry && errors.As(err, &echErr) && len(echErr.RetryConfigList) > 0 {
- if echConfig, isECH := d.config.(ECHCapableConfig); isECH {
- echConfig.SetECHConfigList(echErr.RetryConfigList)
- return d.dialContext(ctx, destination, false)
- }
- }
- return nil, err
- }
- return tlsConn, nil
- }
- func (d *defaultDialer) Upstream() any {
- return d.dialer
- }
|