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