mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-04-30 09:18:34 +00:00
Add session context outbounds as slice (#3356)
* Add session context outbounds as slice slice is needed for dialer proxy where two outbounds work on top of each other There are two sets of target addr for example It also enable Xtls to correctly do splice copy by checking both outbounds are ready to do direct copy * Fill outbound tag info * Splice now checks capalibility from all outbounds * Fix unit tests
This commit is contained in:
parent
0735053348
commit
017f53b5fc
42 changed files with 303 additions and 236 deletions
|
@ -31,10 +31,9 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
|
|||
|
||||
// Process implements OutboundHandler.Dispatch().
|
||||
func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
if outbound != nil {
|
||||
outbound.Name = "blackhole"
|
||||
}
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds) - 1]
|
||||
ob.Name = "blackhole"
|
||||
|
||||
nBytes := h.response.WriteTo(link.Writer)
|
||||
if nBytes > 0 {
|
||||
|
|
|
@ -7,13 +7,15 @@ import (
|
|||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/serial"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/proxy/blackhole"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
"github.com/xtls/xray-core/transport/pipe"
|
||||
)
|
||||
|
||||
func TestBlackholeHTTPResponse(t *testing.T) {
|
||||
handler, err := blackhole.New(context.Background(), &blackhole.Config{
|
||||
ctx := session.ContextWithOutbounds(context.Background(), []*session.Outbound{{}})
|
||||
handler, err := blackhole.New(ctx, &blackhole.Config{
|
||||
Response: serial.ToTypedMessage(&blackhole.HTTPResponse{}),
|
||||
})
|
||||
common.Must(err)
|
||||
|
@ -32,7 +34,7 @@ func TestBlackholeHTTPResponse(t *testing.T) {
|
|||
Reader: reader,
|
||||
Writer: writer,
|
||||
}
|
||||
common.Must(handler.Process(context.Background(), &link, nil))
|
||||
common.Must(handler.Process(ctx, &link, nil))
|
||||
common.Must(rerr)
|
||||
if mb.IsEmpty() {
|
||||
t.Error("expect http response, but nothing")
|
||||
|
|
|
@ -96,15 +96,16 @@ func parseIPQuery(b []byte) (r bool, domain string, id uint16, qType dnsmessage.
|
|||
|
||||
// Process implements proxy.Outbound.
|
||||
func (h *Handler) Process(ctx context.Context, link *transport.Link, d internet.Dialer) error {
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
if outbound == nil || !outbound.Target.IsValid() {
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds) - 1]
|
||||
if !ob.Target.IsValid() {
|
||||
return newError("invalid outbound")
|
||||
}
|
||||
outbound.Name = "dns"
|
||||
ob.Name = "dns"
|
||||
|
||||
srcNetwork := outbound.Target.Network
|
||||
srcNetwork := ob.Target.Network
|
||||
|
||||
dest := outbound.Target
|
||||
dest := ob.Target
|
||||
if h.server.Network != net.Network_Unknown {
|
||||
dest.Network = h.server.Network
|
||||
}
|
||||
|
|
|
@ -86,10 +86,15 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn st
|
|||
|
||||
destinationOverridden := false
|
||||
if d.config.FollowRedirect {
|
||||
if outbound := session.OutboundFromContext(ctx); outbound != nil && outbound.Target.IsValid() {
|
||||
dest = outbound.Target
|
||||
destinationOverridden = true
|
||||
} else if handshake, ok := conn.(hasHandshakeAddressContext); ok {
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
if len(outbounds) > 0 {
|
||||
ob := outbounds[len(outbounds) - 1]
|
||||
if ob.Target.IsValid() {
|
||||
dest = ob.Target
|
||||
destinationOverridden = true
|
||||
}
|
||||
}
|
||||
if handshake, ok := conn.(hasHandshakeAddressContext); ok && !destinationOverridden {
|
||||
addr := handshake.HandshakeAddressContext(ctx)
|
||||
if addr != nil {
|
||||
dest.Address = addr
|
||||
|
@ -103,7 +108,7 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn st
|
|||
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
inbound.Name = "dokodemo-door"
|
||||
inbound.SetCanSpliceCopy(1)
|
||||
inbound.CanSpliceCopy = 1
|
||||
inbound.User = &protocol.MemoryUser{
|
||||
Level: d.config.UserLevel,
|
||||
}
|
||||
|
|
|
@ -106,16 +106,16 @@ func isValidAddress(addr *net.IPOrDomain) bool {
|
|||
|
||||
// Process implements proxy.Outbound.
|
||||
func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
if outbound == nil || !outbound.Target.IsValid() {
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds) - 1]
|
||||
if !ob.Target.IsValid() {
|
||||
return newError("target not specified.")
|
||||
}
|
||||
outbound.Name = "freedom"
|
||||
ob.Name = "freedom"
|
||||
ob.CanSpliceCopy = 1
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
if inbound != nil {
|
||||
inbound.SetCanSpliceCopy(1)
|
||||
}
|
||||
destination := outbound.Target
|
||||
|
||||
destination := ob.Target
|
||||
UDPOverride := net.UDPDestination(nil, 0)
|
||||
if h.config.DestinationOverride != nil {
|
||||
server := h.config.DestinationOverride.Server
|
||||
|
|
|
@ -69,16 +69,14 @@ func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
|
|||
|
||||
// Process implements proxy.Outbound.Process. We first create a socket tunnel via HTTP CONNECT method, then redirect all inbound traffic to that tunnel.
|
||||
func (c *Client) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
if outbound == nil || !outbound.Target.IsValid() {
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds) - 1]
|
||||
if !ob.Target.IsValid() {
|
||||
return newError("target not specified.")
|
||||
}
|
||||
outbound.Name = "http"
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
if inbound != nil {
|
||||
inbound.SetCanSpliceCopy(2)
|
||||
}
|
||||
target := outbound.Target
|
||||
ob.Name = "http"
|
||||
ob.CanSpliceCopy = 2
|
||||
target := ob.Target
|
||||
targetAddr := target.NetAddr()
|
||||
|
||||
if target.Network == net.Network_UDP {
|
||||
|
@ -175,9 +173,10 @@ func fillRequestHeader(ctx context.Context, header []*Header) ([]*Header, error)
|
|||
}
|
||||
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds) - 1]
|
||||
|
||||
if inbound == nil || outbound == nil {
|
||||
if inbound == nil || ob == nil {
|
||||
return nil, newError("missing inbound or outbound metadata from context")
|
||||
}
|
||||
|
||||
|
@ -186,7 +185,7 @@ func fillRequestHeader(ctx context.Context, header []*Header) ([]*Header, error)
|
|||
Target net.Destination
|
||||
}{
|
||||
Source: inbound.Source,
|
||||
Target: outbound.Target,
|
||||
Target: ob.Target,
|
||||
}
|
||||
|
||||
filled := make([]*Header, len(header))
|
||||
|
|
|
@ -85,7 +85,7 @@ type readerOnly struct {
|
|||
func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Connection, dispatcher routing.Dispatcher) error {
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
inbound.Name = "http"
|
||||
inbound.SetCanSpliceCopy(2)
|
||||
inbound.CanSpliceCopy = 2
|
||||
inbound.User = &protocol.MemoryUser{
|
||||
Level: s.config.UserLevel,
|
||||
}
|
||||
|
|
|
@ -22,12 +22,13 @@ type Loopback struct {
|
|||
}
|
||||
|
||||
func (l *Loopback) Process(ctx context.Context, link *transport.Link, _ internet.Dialer) error {
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
if outbound == nil || !outbound.Target.IsValid() {
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds) - 1]
|
||||
if !ob.Target.IsValid() {
|
||||
return newError("target not specified.")
|
||||
}
|
||||
outbound.Name = "loopback"
|
||||
destination := outbound.Target
|
||||
ob.Name = "loopback"
|
||||
destination := ob.Target
|
||||
|
||||
newError("opening connection to ", destination).WriteToLog(session.ExportIDToError(ctx))
|
||||
|
||||
|
|
102
proxy/proxy.go
102
proxy/proxy.go
|
@ -474,45 +474,73 @@ func CopyRawConnIfExist(ctx context.Context, readerConn net.Conn, writerConn net
|
|||
readerConn, readCounter, _ := UnwrapRawConn(readerConn)
|
||||
writerConn, _, writeCounter := UnwrapRawConn(writerConn)
|
||||
reader := buf.NewReader(readerConn)
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||
if tc, ok := writerConn.(*net.TCPConn); ok && readerConn != nil && writerConn != nil && (runtime.GOOS == "linux" || runtime.GOOS == "android") {
|
||||
for inbound.CanSpliceCopy != 3 {
|
||||
if inbound.CanSpliceCopy == 1 {
|
||||
newError("CopyRawConn splice").WriteToLog(session.ExportIDToError(ctx))
|
||||
statWriter, _ := writer.(*dispatcher.SizeStatWriter)
|
||||
//runtime.Gosched() // necessary
|
||||
time.Sleep(time.Millisecond) // without this, there will be a rare ssl error for freedom splice
|
||||
w, err := tc.ReadFrom(readerConn)
|
||||
if readCounter != nil {
|
||||
readCounter.Add(w) // outbound stats
|
||||
}
|
||||
if writeCounter != nil {
|
||||
writeCounter.Add(w) // inbound stats
|
||||
}
|
||||
if statWriter != nil {
|
||||
statWriter.Counter.Add(w) // user stats
|
||||
}
|
||||
if err != nil && errors.Cause(err) != io.EOF {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
buffer, err := reader.ReadMultiBuffer()
|
||||
if !buffer.IsEmpty() {
|
||||
if readCounter != nil {
|
||||
readCounter.Add(int64(buffer.Len()))
|
||||
}
|
||||
timer.Update()
|
||||
if werr := writer.WriteMultiBuffer(buffer); werr != nil {
|
||||
return werr
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if runtime.GOOS != "linux" && runtime.GOOS != "android" {
|
||||
return readV(ctx, reader, writer, timer, readCounter)
|
||||
}
|
||||
tc, ok := writerConn.(*net.TCPConn)
|
||||
if !ok || readerConn == nil || writerConn == nil {
|
||||
return readV(ctx, reader, writer, timer, readCounter)
|
||||
}
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
if inbound == nil || inbound.CanSpliceCopy == 3 {
|
||||
return readV(ctx, reader, writer, timer, readCounter)
|
||||
}
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
if len(outbounds) == 0 {
|
||||
return readV(ctx, reader, writer, timer, readCounter)
|
||||
}
|
||||
for _, ob := range outbounds {
|
||||
if ob.CanSpliceCopy == 3 {
|
||||
return readV(ctx, reader, writer, timer, readCounter)
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
var splice = inbound.CanSpliceCopy == 1
|
||||
for _, ob := range outbounds {
|
||||
if ob.CanSpliceCopy != 1 {
|
||||
splice = false
|
||||
}
|
||||
}
|
||||
if splice {
|
||||
newError("CopyRawConn splice").WriteToLog(session.ExportIDToError(ctx))
|
||||
statWriter, _ := writer.(*dispatcher.SizeStatWriter)
|
||||
//runtime.Gosched() // necessary
|
||||
time.Sleep(time.Millisecond) // without this, there will be a rare ssl error for freedom splice
|
||||
w, err := tc.ReadFrom(readerConn)
|
||||
if readCounter != nil {
|
||||
readCounter.Add(w) // outbound stats
|
||||
}
|
||||
if writeCounter != nil {
|
||||
writeCounter.Add(w) // inbound stats
|
||||
}
|
||||
if statWriter != nil {
|
||||
statWriter.Counter.Add(w) // user stats
|
||||
}
|
||||
if err != nil && errors.Cause(err) != io.EOF {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
buffer, err := reader.ReadMultiBuffer()
|
||||
if !buffer.IsEmpty() {
|
||||
if readCounter != nil {
|
||||
readCounter.Add(int64(buffer.Len()))
|
||||
}
|
||||
timer.Update()
|
||||
if werr := writer.WriteMultiBuffer(buffer); werr != nil {
|
||||
return werr
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func readV(ctx context.Context, reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, readCounter stats.Counter) error {
|
||||
newError("CopyRawConn readv").WriteToLog(session.ExportIDToError(ctx))
|
||||
if err := buf.Copy(reader, writer, buf.UpdateActivity(timer), buf.AddToStatCounter(readCounter)); err != nil {
|
||||
return newError("failed to process response").Base(err)
|
||||
|
|
|
@ -49,16 +49,14 @@ func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
|
|||
|
||||
// Process implements OutboundHandler.Process().
|
||||
func (c *Client) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
if outbound == nil || !outbound.Target.IsValid() {
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds) - 1]
|
||||
if !ob.Target.IsValid() {
|
||||
return newError("target not specified")
|
||||
}
|
||||
outbound.Name = "shadowsocks"
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
if inbound != nil {
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
}
|
||||
destination := outbound.Target
|
||||
ob.Name = "shadowsocks"
|
||||
ob.CanSpliceCopy = 3
|
||||
destination := ob.Target
|
||||
network := destination.Network
|
||||
|
||||
var server *protocol.ServerSpec
|
||||
|
|
|
@ -73,7 +73,7 @@ func (s *Server) Network() []net.Network {
|
|||
func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Connection, dispatcher routing.Dispatcher) error {
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
inbound.Name = "shadowsocks"
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
inbound.CanSpliceCopy = 3
|
||||
|
||||
switch network {
|
||||
case net.Network_TCP:
|
||||
|
|
|
@ -66,7 +66,7 @@ func (i *Inbound) Network() []net.Network {
|
|||
func (i *Inbound) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error {
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
inbound.Name = "shadowsocks-2022"
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
inbound.CanSpliceCopy = 3
|
||||
|
||||
var metadata M.Metadata
|
||||
if inbound.Source.IsValid() {
|
||||
|
|
|
@ -155,7 +155,7 @@ func (i *MultiUserInbound) Network() []net.Network {
|
|||
func (i *MultiUserInbound) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error {
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
inbound.Name = "shadowsocks-2022-multi"
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
inbound.CanSpliceCopy = 3
|
||||
|
||||
var metadata M.Metadata
|
||||
if inbound.Source.IsValid() {
|
||||
|
|
|
@ -87,7 +87,7 @@ func (i *RelayInbound) Network() []net.Network {
|
|||
func (i *RelayInbound) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error {
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
inbound.Name = "shadowsocks-2022-relay"
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
inbound.CanSpliceCopy = 3
|
||||
|
||||
var metadata M.Metadata
|
||||
if inbound.Source.IsValid() {
|
||||
|
|
|
@ -65,15 +65,16 @@ func (o *Outbound) Process(ctx context.Context, link *transport.Link, dialer int
|
|||
inbound := session.InboundFromContext(ctx)
|
||||
if inbound != nil {
|
||||
inboundConn = inbound.Conn
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
}
|
||||
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
if outbound == nil || !outbound.Target.IsValid() {
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds) - 1]
|
||||
if !ob.Target.IsValid() {
|
||||
return newError("target not specified")
|
||||
}
|
||||
outbound.Name = "shadowsocks-2022"
|
||||
destination := outbound.Target
|
||||
ob.Name = "shadowsocks-2022"
|
||||
ob.CanSpliceCopy = 3
|
||||
destination := ob.Target
|
||||
network := destination.Network
|
||||
|
||||
newError("tunneling request to ", destination, " via ", o.server.NetAddr()).WriteToLog(session.ExportIDToError(ctx))
|
||||
|
|
|
@ -57,17 +57,15 @@ func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
|
|||
|
||||
// Process implements proxy.Outbound.Process.
|
||||
func (c *Client) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
if outbound == nil || !outbound.Target.IsValid() {
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds) - 1]
|
||||
if !ob.Target.IsValid() {
|
||||
return newError("target not specified.")
|
||||
}
|
||||
outbound.Name = "socks"
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
if inbound != nil {
|
||||
inbound.SetCanSpliceCopy(2)
|
||||
}
|
||||
ob.Name = "socks"
|
||||
ob.CanSpliceCopy = 2
|
||||
// Destination of the inner request.
|
||||
destination := outbound.Target
|
||||
destination := ob.Target
|
||||
|
||||
// Outbound server.
|
||||
var server *protocol.ServerSpec
|
||||
|
|
|
@ -65,7 +65,7 @@ func (s *Server) Network() []net.Network {
|
|||
func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Connection, dispatcher routing.Dispatcher) error {
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
inbound.Name = "socks"
|
||||
inbound.SetCanSpliceCopy(2)
|
||||
inbound.CanSpliceCopy = 2
|
||||
inbound.User = &protocol.MemoryUser{
|
||||
Level: s.config.UserLevel,
|
||||
}
|
||||
|
|
|
@ -50,16 +50,14 @@ func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
|
|||
|
||||
// Process implements OutboundHandler.Process().
|
||||
func (c *Client) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
if outbound == nil || !outbound.Target.IsValid() {
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds) - 1]
|
||||
if !ob.Target.IsValid() {
|
||||
return newError("target not specified")
|
||||
}
|
||||
outbound.Name = "trojan"
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
if inbound != nil {
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
}
|
||||
destination := outbound.Target
|
||||
ob.Name = "trojan"
|
||||
ob.CanSpliceCopy = 3
|
||||
destination := ob.Target
|
||||
network := destination.Network
|
||||
|
||||
var server *protocol.ServerSpec
|
||||
|
|
|
@ -215,7 +215,7 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Con
|
|||
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
inbound.Name = "trojan"
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
inbound.CanSpliceCopy = 3
|
||||
inbound.User = user
|
||||
sessionPolicy = s.policyManager.ForLevel(user.Level)
|
||||
|
||||
|
|
|
@ -174,15 +174,18 @@ func DecodeResponseHeader(reader io.Reader, request *protocol.RequestHeader) (*A
|
|||
}
|
||||
|
||||
// XtlsRead filter and read xtls protocol
|
||||
func XtlsRead(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn net.Conn, input *bytes.Reader, rawInput *bytes.Buffer, trafficState *proxy.TrafficState, ctx context.Context) error {
|
||||
func XtlsRead(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn net.Conn, input *bytes.Reader, rawInput *bytes.Buffer, trafficState *proxy.TrafficState, ob *session.Outbound, ctx context.Context) error {
|
||||
err := func() error {
|
||||
for {
|
||||
if trafficState.ReaderSwitchToDirectCopy {
|
||||
var writerConn net.Conn
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Conn != nil {
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Conn != nil && ob != nil {
|
||||
writerConn = inbound.Conn
|
||||
if inbound.CanSpliceCopy == 2 {
|
||||
inbound.CanSpliceCopy = 1 // force the value to 1, don't use setter
|
||||
inbound.CanSpliceCopy = 1
|
||||
}
|
||||
if ob.CanSpliceCopy == 2 { // ob need to be passed in due to context can change
|
||||
ob.CanSpliceCopy = 1
|
||||
}
|
||||
}
|
||||
return proxy.CopyRawConnIfExist(ctx, conn, writerConn, writer, timer)
|
||||
|
@ -219,14 +222,19 @@ func XtlsRead(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater
|
|||
}
|
||||
|
||||
// XtlsWrite filter and write xtls protocol
|
||||
func XtlsWrite(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn net.Conn, trafficState *proxy.TrafficState, ctx context.Context) error {
|
||||
func XtlsWrite(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn net.Conn, trafficState *proxy.TrafficState, ob *session.Outbound, ctx context.Context) error {
|
||||
err := func() error {
|
||||
var ct stats.Counter
|
||||
for {
|
||||
buffer, err := reader.ReadMultiBuffer()
|
||||
if trafficState.WriterSwitchToDirectCopy {
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.CanSpliceCopy == 2 {
|
||||
inbound.CanSpliceCopy = 1 // force the value to 1, don't use setter
|
||||
if inbound := session.InboundFromContext(ctx); inbound != nil && ob != nil {
|
||||
if inbound.CanSpliceCopy == 2 {
|
||||
inbound.CanSpliceCopy = 1
|
||||
}
|
||||
if ob.CanSpliceCopy == 2 {
|
||||
ob.CanSpliceCopy = 1
|
||||
}
|
||||
}
|
||||
rawConn, _, writerCounter := proxy.UnwrapRawConn(conn)
|
||||
writer = buf.NewWriter(rawConn)
|
||||
|
|
|
@ -449,7 +449,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||
switch requestAddons.Flow {
|
||||
case vless.XRV:
|
||||
if account.Flow == requestAddons.Flow {
|
||||
inbound.SetCanSpliceCopy(2)
|
||||
inbound.CanSpliceCopy = 2
|
||||
switch request.Command {
|
||||
case protocol.RequestCommandUDP:
|
||||
return newError(requestAddons.Flow + " doesn't support UDP").AtWarning()
|
||||
|
@ -479,7 +479,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||
return newError(account.ID.String() + " is not able to use " + requestAddons.Flow).AtWarning()
|
||||
}
|
||||
case "":
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
inbound.CanSpliceCopy = 3
|
||||
if account.Flow == vless.XRV && (request.Command == protocol.RequestCommandTCP || isMuxAndNotXUDP(request, first)) {
|
||||
return newError(account.ID.String() + " is not able to use \"\". Note that the pure TLS proxy has certain TLS in TLS characters.").AtWarning()
|
||||
}
|
||||
|
@ -523,7 +523,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||
if requestAddons.Flow == vless.XRV {
|
||||
ctx1 := session.ContextWithInbound(ctx, nil) // TODO enable splice
|
||||
clientReader = proxy.NewVisionReader(clientReader, trafficState, ctx1)
|
||||
err = encoding.XtlsRead(clientReader, serverWriter, timer, connection, input, rawInput, trafficState, ctx1)
|
||||
err = encoding.XtlsRead(clientReader, serverWriter, timer, connection, input, rawInput, trafficState, nil, ctx1)
|
||||
} else {
|
||||
// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBufer
|
||||
err = buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer))
|
||||
|
@ -560,7 +560,9 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||
|
||||
var err error
|
||||
if requestAddons.Flow == vless.XRV {
|
||||
err = encoding.XtlsWrite(serverReader, clientWriter, timer, connection, trafficState, ctx)
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds) - 1]
|
||||
err = encoding.XtlsWrite(serverReader, clientWriter, timer, connection, trafficState, ob, ctx)
|
||||
} else {
|
||||
// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer
|
||||
err = buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer))
|
||||
|
|
|
@ -70,12 +70,12 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
|
|||
|
||||
// Process implements proxy.Outbound.Process().
|
||||
func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
if outbound == nil || !outbound.Target.IsValid() {
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds) - 1]
|
||||
if !ob.Target.IsValid() {
|
||||
return newError("target not specified").AtError()
|
||||
}
|
||||
outbound.Name = "vless"
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
ob.Name = "vless"
|
||||
|
||||
var rec *protocol.ServerSpec
|
||||
var conn stat.Connection
|
||||
|
@ -96,7 +96,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||
if statConn, ok := iConn.(*stat.CounterConnection); ok {
|
||||
iConn = statConn.Connection
|
||||
}
|
||||
target := outbound.Target
|
||||
target := ob.Target
|
||||
newError("tunneling request to ", target, " via ", rec.Destination().NetAddr()).AtInfo().WriteToLog(session.ExportIDToError(ctx))
|
||||
|
||||
command := protocol.RequestCommandTCP
|
||||
|
@ -130,9 +130,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||
requestAddons.Flow = requestAddons.Flow[:16]
|
||||
fallthrough
|
||||
case vless.XRV:
|
||||
if inbound != nil {
|
||||
inbound.SetCanSpliceCopy(2)
|
||||
}
|
||||
ob.CanSpliceCopy = 2
|
||||
switch request.Command {
|
||||
case protocol.RequestCommandUDP:
|
||||
if !allowUDP443 && request.Port == 443 {
|
||||
|
@ -161,9 +159,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||
rawInput = (*bytes.Buffer)(unsafe.Pointer(p + r.Offset))
|
||||
}
|
||||
default:
|
||||
if inbound != nil {
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
}
|
||||
ob.CanSpliceCopy = 3
|
||||
}
|
||||
|
||||
var newCtx context.Context
|
||||
|
@ -238,8 +234,8 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||
return newError(`failed to use `+requestAddons.Flow+`, found outer tls version `, utlsConn.ConnectionState().Version).AtWarning()
|
||||
}
|
||||
}
|
||||
ctx1 := session.ContextWithOutbound(ctx, nil) // TODO enable splice
|
||||
err = encoding.XtlsWrite(clientReader, serverWriter, timer, conn, trafficState, ctx1)
|
||||
ctx1 := session.ContextWithInbound(ctx, nil) // TODO enable splice
|
||||
err = encoding.XtlsWrite(clientReader, serverWriter, timer, conn, trafficState, ob, ctx1)
|
||||
} else {
|
||||
// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBufer
|
||||
err = buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer))
|
||||
|
@ -277,7 +273,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||
}
|
||||
|
||||
if requestAddons.Flow == vless.XRV {
|
||||
err = encoding.XtlsRead(serverReader, clientWriter, timer, conn, input, rawInput, trafficState, ctx)
|
||||
err = encoding.XtlsRead(serverReader, clientWriter, timer, conn, input, rawInput, trafficState, ob, ctx)
|
||||
} else {
|
||||
// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer
|
||||
err = buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer))
|
||||
|
|
|
@ -257,7 +257,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
inbound.Name = "vmess"
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
inbound.CanSpliceCopy = 3
|
||||
inbound.User = request.User
|
||||
|
||||
sessionPolicy = h.policyManager.ForLevel(request.User.Level)
|
||||
|
|
|
@ -60,15 +60,13 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
|
|||
|
||||
// Process implements proxy.Outbound.Process().
|
||||
func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
if outbound == nil || !outbound.Target.IsValid() {
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds) - 1]
|
||||
if !ob.Target.IsValid() {
|
||||
return newError("target not specified").AtError()
|
||||
}
|
||||
outbound.Name = "vmess"
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
if inbound != nil {
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
}
|
||||
ob.Name = "vmess"
|
||||
ob.CanSpliceCopy = 3
|
||||
|
||||
var rec *protocol.ServerSpec
|
||||
var conn stat.Connection
|
||||
|
@ -87,7 +85,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||
}
|
||||
defer conn.Close()
|
||||
|
||||
target := outbound.Target
|
||||
target := ob.Target
|
||||
newError("tunneling request to ", target, " via ", rec.Destination().NetAddr()).WriteToLog(session.ExportIDToError(ctx))
|
||||
|
||||
command := protocol.RequestCommandTCP
|
||||
|
|
|
@ -127,22 +127,20 @@ func (h *Handler) processWireGuard(dialer internet.Dialer) (err error) {
|
|||
|
||||
// Process implements OutboundHandler.Dispatch().
|
||||
func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
|
||||
outbound := session.OutboundFromContext(ctx)
|
||||
if outbound == nil || !outbound.Target.IsValid() {
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds) - 1]
|
||||
if !ob.Target.IsValid() {
|
||||
return newError("target not specified")
|
||||
}
|
||||
outbound.Name = "wireguard"
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
if inbound != nil {
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
}
|
||||
ob.Name = "wireguard"
|
||||
ob.CanSpliceCopy = 3
|
||||
|
||||
if err := h.processWireGuard(dialer); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Destination of the inner request.
|
||||
destination := outbound.Target
|
||||
destination := ob.Target
|
||||
command := protocol.RequestCommandTCP
|
||||
if destination.Network == net.Network_UDP {
|
||||
command = protocol.RequestCommandUDP
|
||||
|
|
|
@ -79,13 +79,15 @@ func (*Server) Network() []net.Network {
|
|||
func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Connection, dispatcher routing.Dispatcher) error {
|
||||
inbound := session.InboundFromContext(ctx)
|
||||
inbound.Name = "wireguard"
|
||||
inbound.SetCanSpliceCopy(3)
|
||||
inbound.CanSpliceCopy = 3
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds) - 1]
|
||||
|
||||
s.info = routingInfo{
|
||||
ctx: core.ToBackgroundDetachedContext(ctx),
|
||||
dispatcher: dispatcher,
|
||||
inboundTag: session.InboundFromContext(ctx),
|
||||
outboundTag: session.OutboundFromContext(ctx),
|
||||
outboundTag: ob,
|
||||
contentTag: session.ContentFromContext(ctx),
|
||||
}
|
||||
|
||||
|
@ -145,7 +147,7 @@ func (s *Server) forwardConnection(dest net.Destination, conn net.Conn) {
|
|||
ctx = session.ContextWithInbound(ctx, s.info.inboundTag)
|
||||
}
|
||||
if s.info.outboundTag != nil {
|
||||
ctx = session.ContextWithOutbound(ctx, s.info.outboundTag)
|
||||
ctx = session.ContextWithOutbounds(ctx, []*session.Outbound{s.info.outboundTag})
|
||||
}
|
||||
if s.info.contentTag != nil {
|
||||
ctx = session.ContextWithContent(ctx, s.info.contentTag)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue