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 }