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