github.com/sagernet/sing-box@v1.9.0-rc.20/outbound/vmess.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/mux" 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-box/transport/v2ray" 15 "github.com/sagernet/sing-vmess" 16 "github.com/sagernet/sing-vmess/packetaddr" 17 "github.com/sagernet/sing/common" 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 "github.com/sagernet/sing/common/ntp" 22 ) 23 24 var _ adapter.Outbound = (*VMess)(nil) 25 26 type VMess struct { 27 myOutboundAdapter 28 dialer N.Dialer 29 client *vmess.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 NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.VMessOutboundOptions) (*VMess, error) { 39 outboundDialer, err := dialer.New(router, options.DialerOptions) 40 if err != nil { 41 return nil, err 42 } 43 outbound := &VMess{ 44 myOutboundAdapter: myOutboundAdapter{ 45 protocol: C.TypeVMess, 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 outbound.multiplexDialer, err = mux.NewClientWithOptions((*vmessDialer)(outbound), logger, common.PtrValueOrDefault(options.Multiplex)) 68 if err != nil { 69 return nil, err 70 } 71 switch options.PacketEncoding { 72 case "": 73 case "packetaddr": 74 outbound.packetAddr = true 75 case "xudp": 76 outbound.xudp = true 77 default: 78 return nil, E.New("unknown packet encoding: ", options.PacketEncoding) 79 } 80 var clientOptions []vmess.ClientOption 81 if timeFunc := ntp.TimeFuncFromContext(ctx); timeFunc != nil { 82 clientOptions = append(clientOptions, vmess.ClientWithTimeFunc(timeFunc)) 83 } 84 if options.GlobalPadding { 85 clientOptions = append(clientOptions, vmess.ClientWithGlobalPadding()) 86 } 87 if options.AuthenticatedLength { 88 clientOptions = append(clientOptions, vmess.ClientWithAuthenticatedLength()) 89 } 90 security := options.Security 91 if security == "" { 92 security = "auto" 93 } 94 if security == "auto" && outbound.tlsConfig != nil { 95 security = "zero" 96 } 97 client, err := vmess.NewClient(options.UUID, security, options.AlterId, clientOptions...) 98 if err != nil { 99 return nil, err 100 } 101 outbound.client = client 102 return outbound, nil 103 } 104 105 func (h *VMess) InterfaceUpdated() { 106 if h.multiplexDialer != nil { 107 h.multiplexDialer.Reset() 108 } 109 return 110 } 111 112 func (h *VMess) Close() error { 113 return common.Close(common.PtrOrNil(h.multiplexDialer), h.transport) 114 } 115 116 func (h *VMess) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { 117 if h.multiplexDialer == nil { 118 switch N.NetworkName(network) { 119 case N.NetworkTCP: 120 h.logger.InfoContext(ctx, "outbound connection to ", destination) 121 case N.NetworkUDP: 122 h.logger.InfoContext(ctx, "outbound packet connection to ", destination) 123 } 124 return (*vmessDialer)(h).DialContext(ctx, network, destination) 125 } else { 126 switch N.NetworkName(network) { 127 case N.NetworkTCP: 128 h.logger.InfoContext(ctx, "outbound multiplex connection to ", destination) 129 case N.NetworkUDP: 130 h.logger.InfoContext(ctx, "outbound multiplex packet connection to ", destination) 131 } 132 return h.multiplexDialer.DialContext(ctx, network, destination) 133 } 134 } 135 136 func (h *VMess) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { 137 if h.multiplexDialer == nil { 138 h.logger.InfoContext(ctx, "outbound packet connection to ", destination) 139 return (*vmessDialer)(h).ListenPacket(ctx, destination) 140 } else { 141 h.logger.InfoContext(ctx, "outbound multiplex packet connection to ", destination) 142 return h.multiplexDialer.ListenPacket(ctx, destination) 143 } 144 } 145 146 func (h *VMess) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { 147 return NewConnection(ctx, h, conn, metadata) 148 } 149 150 func (h *VMess) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error { 151 return NewPacketConnection(ctx, h, conn, metadata) 152 } 153 154 type vmessDialer VMess 155 156 func (h *vmessDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { 157 ctx, metadata := adapter.AppendContext(ctx) 158 metadata.Outbound = h.tag 159 metadata.Destination = destination 160 var conn net.Conn 161 var err error 162 if h.transport != nil { 163 conn, err = h.transport.DialContext(ctx) 164 } else { 165 conn, err = h.dialer.DialContext(ctx, N.NetworkTCP, h.serverAddr) 166 if err == nil && h.tlsConfig != nil { 167 conn, err = tls.ClientHandshake(ctx, conn, h.tlsConfig) 168 } 169 } 170 if err != nil { 171 common.Close(conn) 172 return nil, err 173 } 174 switch N.NetworkName(network) { 175 case N.NetworkTCP: 176 return h.client.DialEarlyConn(conn, destination), nil 177 case N.NetworkUDP: 178 return h.client.DialEarlyPacketConn(conn, destination), nil 179 default: 180 return nil, E.Extend(N.ErrUnknownNetwork, network) 181 } 182 } 183 184 func (h *vmessDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { 185 ctx, metadata := adapter.AppendContext(ctx) 186 metadata.Outbound = h.tag 187 metadata.Destination = destination 188 var conn net.Conn 189 var err error 190 if h.transport != nil { 191 conn, err = h.transport.DialContext(ctx) 192 } else { 193 conn, err = h.dialer.DialContext(ctx, N.NetworkTCP, h.serverAddr) 194 if err == nil && h.tlsConfig != nil { 195 conn, err = tls.ClientHandshake(ctx, conn, h.tlsConfig) 196 } 197 } 198 if err != nil { 199 return nil, err 200 } 201 if h.packetAddr { 202 if destination.IsFqdn() { 203 return nil, E.New("packetaddr: domain destination is not supported") 204 } 205 return packetaddr.NewConn(h.client.DialEarlyPacketConn(conn, M.Socksaddr{Fqdn: packetaddr.SeqPacketMagicAddress}), destination), nil 206 } else if h.xudp { 207 return h.client.DialEarlyXUDPPacketConn(conn, destination), nil 208 } else { 209 return h.client.DialEarlyPacketConn(conn, destination), nil 210 } 211 }