github.com/EagleQL/Xray-core@v1.4.3/proxy/vless/outbound/outbound.go (about) 1 package outbound 2 3 //go:generate go run github.com/xtls/xray-core/common/errors/errorgen 4 5 import ( 6 "context" 7 "syscall" 8 "time" 9 10 "github.com/xtls/xray-core/common" 11 "github.com/xtls/xray-core/common/buf" 12 "github.com/xtls/xray-core/common/net" 13 "github.com/xtls/xray-core/common/platform" 14 "github.com/xtls/xray-core/common/protocol" 15 "github.com/xtls/xray-core/common/retry" 16 "github.com/xtls/xray-core/common/session" 17 "github.com/xtls/xray-core/common/signal" 18 "github.com/xtls/xray-core/common/task" 19 "github.com/xtls/xray-core/common/xudp" 20 core "github.com/xtls/xray-core/core" 21 "github.com/xtls/xray-core/features/policy" 22 "github.com/xtls/xray-core/features/stats" 23 "github.com/xtls/xray-core/proxy/vless" 24 "github.com/xtls/xray-core/proxy/vless/encoding" 25 "github.com/xtls/xray-core/transport" 26 "github.com/xtls/xray-core/transport/internet" 27 "github.com/xtls/xray-core/transport/internet/xtls" 28 ) 29 30 var ( 31 xtls_show = false 32 ) 33 34 func init() { 35 common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { 36 return New(ctx, config.(*Config)) 37 })) 38 39 const defaultFlagValue = "NOT_DEFINED_AT_ALL" 40 41 xtlsShow := platform.NewEnvFlag("xray.vless.xtls.show").GetValue(func() string { return defaultFlagValue }) 42 if xtlsShow == "true" { 43 xtls_show = true 44 } 45 } 46 47 // Handler is an outbound connection handler for VLess protocol. 48 type Handler struct { 49 serverList *protocol.ServerList 50 serverPicker protocol.ServerPicker 51 policyManager policy.Manager 52 cone bool 53 } 54 55 // New creates a new VLess outbound handler. 56 func New(ctx context.Context, config *Config) (*Handler, error) { 57 serverList := protocol.NewServerList() 58 for _, rec := range config.Vnext { 59 s, err := protocol.NewServerSpecFromPB(rec) 60 if err != nil { 61 return nil, newError("failed to parse server spec").Base(err).AtError() 62 } 63 serverList.AddServer(s) 64 } 65 66 v := core.MustFromContext(ctx) 67 handler := &Handler{ 68 serverList: serverList, 69 serverPicker: protocol.NewRoundRobinServerPicker(serverList), 70 policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager), 71 cone: ctx.Value("cone").(bool), 72 } 73 74 return handler, nil 75 } 76 77 // Process implements proxy.Outbound.Process(). 78 func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error { 79 var rec *protocol.ServerSpec 80 var conn internet.Connection 81 82 if err := retry.ExponentialBackoff(5, 200).On(func() error { 83 rec = h.serverPicker.PickServer() 84 var err error 85 conn, err = dialer.Dial(ctx, rec.Destination()) 86 if err != nil { 87 return err 88 } 89 return nil 90 }); err != nil { 91 return newError("failed to find an available destination").Base(err).AtWarning() 92 } 93 defer conn.Close() 94 95 iConn := conn 96 statConn, ok := iConn.(*internet.StatCouterConnection) 97 if ok { 98 iConn = statConn.Connection 99 } 100 101 outbound := session.OutboundFromContext(ctx) 102 if outbound == nil || !outbound.Target.IsValid() { 103 return newError("target not specified").AtError() 104 } 105 106 target := outbound.Target 107 newError("tunneling request to ", target, " via ", rec.Destination()).AtInfo().WriteToLog(session.ExportIDToError(ctx)) 108 109 command := protocol.RequestCommandTCP 110 if target.Network == net.Network_UDP { 111 command = protocol.RequestCommandUDP 112 } 113 if target.Address.Family().IsDomain() && target.Address.Domain() == "v1.mux.cool" { 114 command = protocol.RequestCommandMux 115 } 116 117 request := &protocol.RequestHeader{ 118 Version: encoding.Version, 119 User: rec.PickUser(), 120 Command: command, 121 Address: target.Address, 122 Port: target.Port, 123 } 124 125 account := request.User.Account.(*vless.MemoryAccount) 126 127 requestAddons := &encoding.Addons{ 128 Flow: account.Flow, 129 } 130 131 var rawConn syscall.RawConn 132 var sctx context.Context 133 134 allowUDP443 := false 135 switch requestAddons.Flow { 136 case vless.XRO + "-udp443", vless.XRD + "-udp443", vless.XRS + "-udp443": 137 allowUDP443 = true 138 requestAddons.Flow = requestAddons.Flow[:16] 139 fallthrough 140 case vless.XRO, vless.XRD, vless.XRS: 141 switch request.Command { 142 case protocol.RequestCommandMux: 143 return newError(requestAddons.Flow + " doesn't support Mux").AtWarning() 144 case protocol.RequestCommandUDP: 145 if !allowUDP443 && request.Port == 443 { 146 return newError(requestAddons.Flow + " stopped UDP/443").AtInfo() 147 } 148 requestAddons.Flow = "" 149 case protocol.RequestCommandTCP: 150 if xtlsConn, ok := iConn.(*xtls.Conn); ok { 151 xtlsConn.RPRX = true 152 xtlsConn.SHOW = xtls_show 153 xtlsConn.MARK = "XTLS" 154 if requestAddons.Flow == vless.XRS { 155 sctx = ctx 156 requestAddons.Flow = vless.XRD 157 } 158 if requestAddons.Flow == vless.XRD { 159 xtlsConn.DirectMode = true 160 if sc, ok := xtlsConn.Connection.(syscall.Conn); ok { 161 rawConn, _ = sc.SyscallConn() 162 } 163 } 164 } else { 165 return newError(`failed to use ` + requestAddons.Flow + `, maybe "security" is not "xtls"`).AtWarning() 166 } 167 } 168 default: 169 if _, ok := iConn.(*xtls.Conn); ok { 170 panic(`To avoid misunderstanding, you must fill in VLESS "flow" when using XTLS.`) 171 } 172 } 173 174 sessionPolicy := h.policyManager.ForLevel(request.User.Level) 175 ctx, cancel := context.WithCancel(ctx) 176 timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle) 177 178 clientReader := link.Reader // .(*pipe.Reader) 179 clientWriter := link.Writer // .(*pipe.Writer) 180 181 if request.Command == protocol.RequestCommandUDP && h.cone && request.Port != 53 && request.Port != 443 { 182 request.Command = protocol.RequestCommandMux 183 request.Address = net.DomainAddress("v1.mux.cool") 184 request.Port = net.Port(666) 185 } 186 187 postRequest := func() error { 188 defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly) 189 190 bufferWriter := buf.NewBufferedWriter(buf.NewWriter(conn)) 191 if err := encoding.EncodeRequestHeader(bufferWriter, request, requestAddons); err != nil { 192 return newError("failed to encode request header").Base(err).AtWarning() 193 } 194 195 // default: serverWriter := bufferWriter 196 serverWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons) 197 if request.Command == protocol.RequestCommandMux && request.Port == 666 { 198 serverWriter = xudp.NewPacketWriter(serverWriter, target) 199 } 200 if err := buf.CopyOnceTimeout(clientReader, serverWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout { 201 return err // ... 202 } 203 204 // Flush; bufferWriter.WriteMultiBufer now is bufferWriter.writer.WriteMultiBuffer 205 if err := bufferWriter.SetBuffered(false); err != nil { 206 return newError("failed to write A request payload").Base(err).AtWarning() 207 } 208 209 // from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBufer 210 if err := buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer)); err != nil { 211 return newError("failed to transfer request payload").Base(err).AtInfo() 212 } 213 214 // Indicates the end of request payload. 215 switch requestAddons.Flow { 216 default: 217 } 218 return nil 219 } 220 221 getResponse := func() error { 222 defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly) 223 224 responseAddons, err := encoding.DecodeResponseHeader(conn, request) 225 if err != nil { 226 return newError("failed to decode response header").Base(err).AtInfo() 227 } 228 229 // default: serverReader := buf.NewReader(conn) 230 serverReader := encoding.DecodeBodyAddons(conn, request, responseAddons) 231 if request.Command == protocol.RequestCommandMux && request.Port == 666 { 232 serverReader = xudp.NewPacketReader(conn) 233 } 234 235 if rawConn != nil { 236 var counter stats.Counter 237 if statConn != nil { 238 counter = statConn.ReadCounter 239 } 240 err = encoding.ReadV(serverReader, clientWriter, timer, iConn.(*xtls.Conn), rawConn, counter, sctx) 241 } else { 242 // from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer 243 err = buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer)) 244 } 245 246 if err != nil { 247 return newError("failed to transfer response payload").Base(err).AtInfo() 248 } 249 250 return nil 251 } 252 253 if err := task.Run(ctx, postRequest, task.OnSuccess(getResponse, task.Close(clientWriter))); err != nil { 254 return newError("connection ends").Base(err).AtInfo() 255 } 256 257 return nil 258 }