github.com/xraypb/Xray-core@v1.8.1/proxy/vless/outbound/outbound.go (about) 1 package outbound 2 3 //go:generate go run github.com/xraypb/Xray-core/common/errors/errorgen 4 5 import ( 6 "bytes" 7 "context" 8 gotls "crypto/tls" 9 "reflect" 10 "syscall" 11 "time" 12 "unsafe" 13 14 utls "github.com/refraction-networking/utls" 15 "github.com/xraypb/Xray-core/common" 16 "github.com/xraypb/Xray-core/common/buf" 17 "github.com/xraypb/Xray-core/common/net" 18 "github.com/xraypb/Xray-core/common/protocol" 19 "github.com/xraypb/Xray-core/common/retry" 20 "github.com/xraypb/Xray-core/common/session" 21 "github.com/xraypb/Xray-core/common/signal" 22 "github.com/xraypb/Xray-core/common/task" 23 "github.com/xraypb/Xray-core/common/xudp" 24 "github.com/xraypb/Xray-core/core" 25 "github.com/xraypb/Xray-core/features/policy" 26 "github.com/xraypb/Xray-core/features/stats" 27 "github.com/xraypb/Xray-core/proxy/vless" 28 "github.com/xraypb/Xray-core/proxy/vless/encoding" 29 "github.com/xraypb/Xray-core/transport" 30 "github.com/xraypb/Xray-core/transport/internet" 31 "github.com/xraypb/Xray-core/transport/internet/reality" 32 "github.com/xraypb/Xray-core/transport/internet/stat" 33 "github.com/xraypb/Xray-core/transport/internet/tls" 34 ) 35 36 func init() { 37 common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { 38 return New(ctx, config.(*Config)) 39 })) 40 } 41 42 // Handler is an outbound connection handler for VLess protocol. 43 type Handler struct { 44 serverList *protocol.ServerList 45 serverPicker protocol.ServerPicker 46 policyManager policy.Manager 47 cone bool 48 } 49 50 // New creates a new VLess outbound handler. 51 func New(ctx context.Context, config *Config) (*Handler, error) { 52 serverList := protocol.NewServerList() 53 for _, rec := range config.Vnext { 54 s, err := protocol.NewServerSpecFromPB(rec) 55 if err != nil { 56 return nil, newError("failed to parse server spec").Base(err).AtError() 57 } 58 serverList.AddServer(s) 59 } 60 61 v := core.MustFromContext(ctx) 62 handler := &Handler{ 63 serverList: serverList, 64 serverPicker: protocol.NewRoundRobinServerPicker(serverList), 65 policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager), 66 cone: ctx.Value("cone").(bool), 67 } 68 69 return handler, nil 70 } 71 72 // Process implements proxy.Outbound.Process(). 73 func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error { 74 var rec *protocol.ServerSpec 75 var conn stat.Connection 76 77 if err := retry.ExponentialBackoff(5, 200).On(func() error { 78 rec = h.serverPicker.PickServer() 79 var err error 80 conn, err = dialer.Dial(ctx, rec.Destination()) 81 if err != nil { 82 return err 83 } 84 return nil 85 }); err != nil { 86 return newError("failed to find an available destination").Base(err).AtWarning() 87 } 88 defer conn.Close() 89 90 iConn := conn 91 statConn, ok := iConn.(*stat.CounterConnection) 92 if ok { 93 iConn = statConn.Connection 94 } 95 96 outbound := session.OutboundFromContext(ctx) 97 if outbound == nil || !outbound.Target.IsValid() { 98 return newError("target not specified").AtError() 99 } 100 101 target := outbound.Target 102 newError("tunneling request to ", target, " via ", rec.Destination().NetAddr()).AtInfo().WriteToLog(session.ExportIDToError(ctx)) 103 104 command := protocol.RequestCommandTCP 105 if target.Network == net.Network_UDP { 106 command = protocol.RequestCommandUDP 107 } 108 if target.Address.Family().IsDomain() && target.Address.Domain() == "v1.mux.cool" { 109 command = protocol.RequestCommandMux 110 } 111 112 request := &protocol.RequestHeader{ 113 Version: encoding.Version, 114 User: rec.PickUser(), 115 Command: command, 116 Address: target.Address, 117 Port: target.Port, 118 } 119 120 account := request.User.Account.(*vless.MemoryAccount) 121 122 requestAddons := &encoding.Addons{ 123 Flow: account.Flow, 124 } 125 126 var netConn net.Conn 127 var rawConn syscall.RawConn 128 var input *bytes.Reader 129 var rawInput *bytes.Buffer 130 allowUDP443 := false 131 switch requestAddons.Flow { 132 case vless.XRV + "-udp443": 133 allowUDP443 = true 134 requestAddons.Flow = requestAddons.Flow[:16] 135 fallthrough 136 case vless.XRV: 137 switch request.Command { 138 case protocol.RequestCommandMux: 139 return newError(requestAddons.Flow + " doesn't support Mux").AtWarning() 140 case protocol.RequestCommandUDP: 141 if !allowUDP443 && request.Port == 443 { 142 return newError(requestAddons.Flow + " stopped UDP/443").AtInfo() 143 } 144 requestAddons.Flow = "" 145 case protocol.RequestCommandTCP: 146 var t reflect.Type 147 var p uintptr 148 if tlsConn, ok := iConn.(*tls.Conn); ok { 149 netConn = tlsConn.NetConn() 150 t = reflect.TypeOf(tlsConn.Conn).Elem() 151 p = uintptr(unsafe.Pointer(tlsConn.Conn)) 152 } else if utlsConn, ok := iConn.(*tls.UConn); ok { 153 netConn = utlsConn.NetConn() 154 t = reflect.TypeOf(utlsConn.Conn).Elem() 155 p = uintptr(unsafe.Pointer(utlsConn.Conn)) 156 } else if realityConn, ok := iConn.(*reality.UConn); ok { 157 netConn = realityConn.NetConn() 158 t = reflect.TypeOf(realityConn.Conn).Elem() 159 p = uintptr(unsafe.Pointer(realityConn.Conn)) 160 } else { 161 return newError("XTLS only supports TCP, mKCP and DomainSocket for now.").AtWarning() 162 } 163 if sc, ok := netConn.(syscall.Conn); ok { 164 rawConn, _ = sc.SyscallConn() 165 } 166 i, _ := t.FieldByName("input") 167 r, _ := t.FieldByName("rawInput") 168 input = (*bytes.Reader)(unsafe.Pointer(p + i.Offset)) 169 rawInput = (*bytes.Buffer)(unsafe.Pointer(p + r.Offset)) 170 } 171 } 172 173 var newCtx context.Context 174 var newCancel context.CancelFunc 175 if session.TimeoutOnlyFromContext(ctx) { 176 newCtx, newCancel = context.WithCancel(context.Background()) 177 } 178 179 sessionPolicy := h.policyManager.ForLevel(request.User.Level) 180 ctx, cancel := context.WithCancel(ctx) 181 timer := signal.CancelAfterInactivity(ctx, func() { 182 cancel() 183 if newCancel != nil { 184 newCancel() 185 } 186 }, sessionPolicy.Timeouts.ConnectionIdle) 187 188 clientReader := link.Reader // .(*pipe.Reader) 189 clientWriter := link.Writer // .(*pipe.Writer) 190 enableXtls := false 191 isTLS12orAbove := false 192 isTLS := false 193 var cipher uint16 = 0 194 var remainingServerHello int32 = -1 195 numberOfPacketToFilter := 8 196 197 if request.Command == protocol.RequestCommandUDP && h.cone && request.Port != 53 && request.Port != 443 { 198 request.Command = protocol.RequestCommandMux 199 request.Address = net.DomainAddress("v1.mux.cool") 200 request.Port = net.Port(666) 201 } 202 203 postRequest := func() error { 204 defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly) 205 206 bufferWriter := buf.NewBufferedWriter(buf.NewWriter(conn)) 207 if err := encoding.EncodeRequestHeader(bufferWriter, request, requestAddons); err != nil { 208 return newError("failed to encode request header").Base(err).AtWarning() 209 } 210 211 // default: serverWriter := bufferWriter 212 serverWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons) 213 if request.Command == protocol.RequestCommandMux && request.Port == 666 { 214 serverWriter = xudp.NewPacketWriter(serverWriter, target, xudp.GetGlobalID(ctx)) 215 } 216 userUUID := account.ID.Bytes() 217 timeoutReader, ok := clientReader.(buf.TimeoutReader) 218 if ok { 219 multiBuffer, err1 := timeoutReader.ReadMultiBufferTimeout(time.Millisecond * 500) 220 if err1 == nil { 221 if requestAddons.Flow == vless.XRV { 222 encoding.XtlsFilterTls(multiBuffer, &numberOfPacketToFilter, &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello, ctx) 223 multiBuffer = encoding.ReshapeMultiBuffer(ctx, multiBuffer) 224 for i, b := range multiBuffer { 225 multiBuffer[i] = encoding.XtlsPadding(b, encoding.CommandPaddingContinue, &userUUID, isTLS, ctx) 226 } 227 } 228 if err := serverWriter.WriteMultiBuffer(multiBuffer); err != nil { 229 return err // ... 230 } 231 } else if err1 != buf.ErrReadTimeout { 232 return err1 233 } else if requestAddons.Flow == vless.XRV { 234 mb := make(buf.MultiBuffer, 1) 235 mb[0] = encoding.XtlsPadding(nil, encoding.CommandPaddingContinue, &userUUID, true, ctx) // we do a long padding to hide vless header 236 newError("Insert padding with empty content to camouflage VLESS header ", mb.Len()).WriteToLog(session.ExportIDToError(ctx)) 237 if err := serverWriter.WriteMultiBuffer(mb); err != nil { 238 return err 239 } 240 } 241 } else { 242 newError("Reader is not timeout reader, will send out vless header separately from first payload").AtDebug().WriteToLog(session.ExportIDToError(ctx)) 243 } 244 // Flush; bufferWriter.WriteMultiBufer now is bufferWriter.writer.WriteMultiBuffer 245 if err := bufferWriter.SetBuffered(false); err != nil { 246 return newError("failed to write A request payload").Base(err).AtWarning() 247 } 248 249 var err error 250 if rawConn != nil && requestAddons.Flow == vless.XRV { 251 if tlsConn, ok := iConn.(*tls.Conn); ok { 252 if tlsConn.ConnectionState().Version != gotls.VersionTLS13 { 253 return newError(`failed to use `+requestAddons.Flow+`, found outer tls version `, tlsConn.ConnectionState().Version).AtWarning() 254 } 255 } else if utlsConn, ok := iConn.(*tls.UConn); ok { 256 if utlsConn.ConnectionState().Version != utls.VersionTLS13 { 257 return newError(`failed to use `+requestAddons.Flow+`, found outer tls version `, utlsConn.ConnectionState().Version).AtWarning() 258 } 259 } 260 var counter stats.Counter 261 if statConn != nil { 262 counter = statConn.WriteCounter 263 } 264 err = encoding.XtlsWrite(clientReader, serverWriter, timer, netConn, counter, ctx, &numberOfPacketToFilter, 265 &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello) 266 } else { 267 // from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBufer 268 err = buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer)) 269 } 270 if err != nil { 271 return newError("failed to transfer request payload").Base(err).AtInfo() 272 } 273 274 // Indicates the end of request payload. 275 switch requestAddons.Flow { 276 default: 277 } 278 return nil 279 } 280 281 getResponse := func() error { 282 defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly) 283 284 responseAddons, err := encoding.DecodeResponseHeader(conn, request) 285 if err != nil { 286 return newError("failed to decode response header").Base(err).AtInfo() 287 } 288 289 // default: serverReader := buf.NewReader(conn) 290 serverReader := encoding.DecodeBodyAddons(conn, request, responseAddons) 291 if request.Command == protocol.RequestCommandMux && request.Port == 666 { 292 serverReader = xudp.NewPacketReader(conn) 293 } 294 295 if rawConn != nil { 296 var counter stats.Counter 297 if statConn != nil { 298 counter = statConn.ReadCounter 299 } 300 err = encoding.XtlsRead(serverReader, clientWriter, timer, netConn, rawConn, input, rawInput, counter, ctx, account.ID.Bytes(), 301 &numberOfPacketToFilter, &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello) 302 } else { 303 // from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer 304 err = buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer)) 305 } 306 307 if err != nil { 308 return newError("failed to transfer response payload").Base(err).AtInfo() 309 } 310 311 return nil 312 } 313 314 if newCtx != nil { 315 ctx = newCtx 316 } 317 318 if err := task.Run(ctx, postRequest, task.OnSuccess(getResponse, task.Close(clientWriter))); err != nil { 319 return newError("connection ends").Base(err).AtInfo() 320 } 321 322 return nil 323 }