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

     1  package outbound
     2  
     3  import (
     4  	"context"
     5  	"net"
     6  
     7  	"github.com/sagernet/sing-box/adapter"
     8  	"github.com/sagernet/sing-box/common/dialer"
     9  	"github.com/sagernet/sing-box/common/tls"
    10  	C "github.com/sagernet/sing-box/constant"
    11  	"github.com/sagernet/sing-box/log"
    12  	"github.com/sagernet/sing-box/option"
    13  	"github.com/sagernet/sing-box/transport/v2ray"
    14  	"github.com/sagernet/sing-box/transport/vless"
    15  	"github.com/sagernet/sing-vmess/packetaddr"
    16  	"github.com/sagernet/sing/common"
    17  	"github.com/sagernet/sing/common/bufio"
    18  	E "github.com/sagernet/sing/common/exceptions"
    19  	M "github.com/sagernet/sing/common/metadata"
    20  	N "github.com/sagernet/sing/common/network"
    21  )
    22  
    23  var _ adapter.Outbound = (*VLESS)(nil)
    24  
    25  type VLESS struct {
    26  	myOutboundAdapter
    27  	dialer     N.Dialer
    28  	client     *vless.Client
    29  	serverAddr M.Socksaddr
    30  	tlsConfig  tls.Config
    31  	transport  adapter.V2RayClientTransport
    32  	packetAddr bool
    33  	xudp       bool
    34  }
    35  
    36  func NewVLESS(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.VLESSOutboundOptions) (*VLESS, error) {
    37  	outbound := &VLESS{
    38  		myOutboundAdapter: myOutboundAdapter{
    39  			protocol: C.TypeVLESS,
    40  			network:  options.Network.Build(),
    41  			router:   router,
    42  			logger:   logger,
    43  			tag:      tag,
    44  		},
    45  		dialer:     dialer.New(router, options.DialerOptions),
    46  		serverAddr: options.ServerOptions.Build(),
    47  	}
    48  	var err error
    49  	if options.TLS != nil {
    50  		outbound.tlsConfig, err = tls.NewClient(router, options.Server, common.PtrValueOrDefault(options.TLS))
    51  		if err != nil {
    52  			return nil, err
    53  		}
    54  	}
    55  	if options.Transport != nil {
    56  		outbound.transport, err = v2ray.NewClientTransport(ctx, outbound.dialer, outbound.serverAddr, common.PtrValueOrDefault(options.Transport), outbound.tlsConfig)
    57  		if err != nil {
    58  			return nil, E.Cause(err, "create client transport: ", options.Transport.Type)
    59  		}
    60  	}
    61  	if options.PacketEncoding == nil {
    62  		outbound.xudp = true
    63  	} else {
    64  		switch *options.PacketEncoding {
    65  		case "":
    66  		case "packetaddr":
    67  			outbound.packetAddr = true
    68  		case "xudp":
    69  			outbound.xudp = true
    70  		default:
    71  			return nil, E.New("unknown packet encoding: ", options.PacketEncoding)
    72  		}
    73  	}
    74  	outbound.client, err = vless.NewClient(options.UUID, options.Flow, logger)
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  	return outbound, nil
    79  }
    80  
    81  func (h *VLESS) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
    82  	ctx, metadata := adapter.AppendContext(ctx)
    83  	metadata.Outbound = h.tag
    84  	metadata.Destination = destination
    85  	var conn net.Conn
    86  	var err error
    87  	if h.transport != nil {
    88  		conn, err = h.transport.DialContext(ctx)
    89  	} else {
    90  		conn, err = h.dialer.DialContext(ctx, N.NetworkTCP, h.serverAddr)
    91  		if err == nil && h.tlsConfig != nil {
    92  			conn, err = tls.ClientHandshake(ctx, conn, h.tlsConfig)
    93  		}
    94  	}
    95  	if err != nil {
    96  		return nil, err
    97  	}
    98  	switch N.NetworkName(network) {
    99  	case N.NetworkTCP:
   100  		h.logger.InfoContext(ctx, "outbound connection to ", destination)
   101  		return h.client.DialEarlyConn(conn, destination)
   102  	case N.NetworkUDP:
   103  		h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
   104  		if h.xudp {
   105  			return h.client.DialEarlyXUDPPacketConn(conn, destination)
   106  		} else if h.packetAddr {
   107  			if destination.IsFqdn() {
   108  				return nil, E.New("packetaddr: domain destination is not supported")
   109  			}
   110  			packetConn, err := h.client.DialEarlyPacketConn(conn, M.Socksaddr{Fqdn: packetaddr.SeqPacketMagicAddress})
   111  			if err != nil {
   112  				return nil, err
   113  			}
   114  			return bufio.NewBindPacketConn(packetaddr.NewConn(packetConn, destination), destination), nil
   115  		} else {
   116  			return h.client.DialEarlyPacketConn(conn, destination)
   117  		}
   118  	default:
   119  		return nil, E.Extend(N.ErrUnknownNetwork, network)
   120  	}
   121  }
   122  
   123  func (h *VLESS) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
   124  	h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
   125  	ctx, metadata := adapter.AppendContext(ctx)
   126  	metadata.Outbound = h.tag
   127  	metadata.Destination = destination
   128  	var conn net.Conn
   129  	var err error
   130  	if h.transport != nil {
   131  		conn, err = h.transport.DialContext(ctx)
   132  	} else {
   133  		conn, err = h.dialer.DialContext(ctx, N.NetworkTCP, h.serverAddr)
   134  		if err == nil && h.tlsConfig != nil {
   135  			conn, err = tls.ClientHandshake(ctx, conn, h.tlsConfig)
   136  		}
   137  	}
   138  	if err != nil {
   139  		common.Close(conn)
   140  		return nil, err
   141  	}
   142  	if h.xudp {
   143  		return h.client.DialEarlyXUDPPacketConn(conn, destination)
   144  	} else if h.packetAddr {
   145  		if destination.IsFqdn() {
   146  			return nil, E.New("packetaddr: domain destination is not supported")
   147  		}
   148  		conn, err := h.client.DialEarlyPacketConn(conn, M.Socksaddr{Fqdn: packetaddr.SeqPacketMagicAddress})
   149  		if err != nil {
   150  			return nil, err
   151  		}
   152  		return packetaddr.NewConn(conn, destination), nil
   153  	} else {
   154  		return h.client.DialEarlyPacketConn(conn, destination)
   155  	}
   156  }
   157  
   158  func (h *VLESS) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
   159  	return NewConnection(ctx, h, conn, metadata)
   160  }
   161  
   162  func (h *VLESS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
   163  	return NewPacketConnection(ctx, h, conn, metadata)
   164  }
   165  
   166  func (h *VLESS) Close() error {
   167  	return common.Close(h.transport)
   168  }