github.com/sagernet/sing-box@v1.2.7/outbound/shadowtls.go (about)

     1  package outbound
     2  
     3  import (
     4  	"context"
     5  	"net"
     6  	"os"
     7  
     8  	"github.com/sagernet/sing-box/adapter"
     9  	"github.com/sagernet/sing-box/common/dialer"
    10  	"github.com/sagernet/sing-box/common/tls"
    11  	C "github.com/sagernet/sing-box/constant"
    12  	"github.com/sagernet/sing-box/log"
    13  	"github.com/sagernet/sing-box/option"
    14  	"github.com/sagernet/sing-shadowtls"
    15  	"github.com/sagernet/sing/common"
    16  	M "github.com/sagernet/sing/common/metadata"
    17  	N "github.com/sagernet/sing/common/network"
    18  )
    19  
    20  var _ adapter.Outbound = (*ShadowTLS)(nil)
    21  
    22  type ShadowTLS struct {
    23  	myOutboundAdapter
    24  	client *shadowtls.Client
    25  }
    26  
    27  func NewShadowTLS(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowTLSOutboundOptions) (*ShadowTLS, error) {
    28  	outbound := &ShadowTLS{
    29  		myOutboundAdapter: myOutboundAdapter{
    30  			protocol: C.TypeShadowTLS,
    31  			network:  []string{N.NetworkTCP},
    32  			router:   router,
    33  			logger:   logger,
    34  			tag:      tag,
    35  		},
    36  	}
    37  	if options.TLS == nil || !options.TLS.Enabled {
    38  		return nil, C.ErrTLSRequired
    39  	}
    40  
    41  	if options.Version == 0 {
    42  		options.Version = 1
    43  	}
    44  
    45  	if options.Version == 1 {
    46  		options.TLS.MinVersion = "1.2"
    47  		options.TLS.MaxVersion = "1.2"
    48  	}
    49  	tlsConfig, err := tls.NewClient(router, options.Server, common.PtrValueOrDefault(options.TLS))
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  
    54  	var tlsHandshakeFunc shadowtls.TLSHandshakeFunc
    55  	switch options.Version {
    56  	case 1, 2:
    57  		tlsHandshakeFunc = func(ctx context.Context, conn net.Conn, _ shadowtls.TLSSessionIDGeneratorFunc) error {
    58  			return common.Error(tls.ClientHandshake(ctx, conn, tlsConfig))
    59  		}
    60  	case 3:
    61  		if idConfig, loaded := tlsConfig.(tls.WithSessionIDGenerator); loaded {
    62  			tlsHandshakeFunc = func(ctx context.Context, conn net.Conn, sessionIDGenerator shadowtls.TLSSessionIDGeneratorFunc) error {
    63  				idConfig.SetSessionIDGenerator(sessionIDGenerator)
    64  				return common.Error(tls.ClientHandshake(ctx, conn, tlsConfig))
    65  			}
    66  		} else {
    67  			stdTLSConfig, err := tlsConfig.Config()
    68  			if err != nil {
    69  				return nil, err
    70  			}
    71  			tlsHandshakeFunc = shadowtls.DefaultTLSHandshakeFunc(options.Password, stdTLSConfig)
    72  		}
    73  	}
    74  	client, err := shadowtls.NewClient(shadowtls.ClientConfig{
    75  		Version:      options.Version,
    76  		Password:     options.Password,
    77  		Server:       options.ServerOptions.Build(),
    78  		Dialer:       dialer.New(router, options.DialerOptions),
    79  		TLSHandshake: tlsHandshakeFunc,
    80  		Logger:       logger,
    81  	})
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  	outbound.client = client
    86  	return outbound, nil
    87  }
    88  
    89  func (h *ShadowTLS) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
    90  	ctx, metadata := adapter.AppendContext(ctx)
    91  	metadata.Outbound = h.tag
    92  	metadata.Destination = destination
    93  	switch N.NetworkName(network) {
    94  	case N.NetworkTCP:
    95  		return h.client.DialContext(ctx)
    96  	default:
    97  		return nil, os.ErrInvalid
    98  	}
    99  }
   100  
   101  func (h *ShadowTLS) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
   102  	return nil, os.ErrInvalid
   103  }
   104  
   105  func (h *ShadowTLS) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
   106  	return NewConnection(ctx, h, conn, metadata)
   107  }
   108  
   109  func (h *ShadowTLS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
   110  	return os.ErrInvalid
   111  }