Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flow: XTLS-Segaro-Vision #3738

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions common/buf/buffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,35 @@ func (b *Buffer) WriteByte(v byte) error {
return nil
}


// WriteAtBeginning writes data at the beginning of the buffer.
func (b *Buffer) WriteAtBeginning(data []byte) (int, error) {
dataLen := len(data)
if dataLen == 0 {
return 0, nil
}
if int32(dataLen) > int32(len(b.v))-b.end {
return 0, errors.New("not enough space in buffer")
}
if b.end > 0 {
copy(b.v[dataLen:], b.v[:b.end])
}
nBytes := copy(b.v[:], data)
b.end += int32(nBytes)
return nBytes, nil
}


// ResetStart set the start position to zero.
func (b *Buffer) ResetStart() {
b.start = 0
}

// GetStart return the start position value.
func (b *Buffer) GetStart() int32{
return b.start
}

// WriteString implements io.StringWriter.
func (b *Buffer) WriteString(s string) (int, error) {
return b.Write([]byte(s))
Expand Down
7 changes: 7 additions & 0 deletions common/buf/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@ func NewBufferedWriter(writer Writer) *BufferedWriter {
}
}


// GetBuffer implements a way to access the internal buffer.
func (w *BufferedWriter) GetBuffer() *Buffer {
return w.buffer
}


// WriteByte implements io.ByteWriter.
func (w *BufferedWriter) WriteByte(c byte) error {
return common.Error2(w.Write([]byte{c}))
Expand Down
58 changes: 58 additions & 0 deletions infra/conf/transport_internet.go
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,11 @@ type REALITYConfig struct {
MaxTimeDiff uint64 `json:"maxTimeDiff"`
ShortIds []string `json:"shortIds"`

RandPacket string `json:"randPacket"`
SplitPacket string `json:"splitPacket"`
PaddingSize uint32 `json:"paddingSize"`
SubchunkSize uint32 `json:"subchunkSize"`

Fingerprint string `json:"fingerprint"`
ServerName string `json:"serverName"`
PublicKey string `json:"publicKey"`
Expand Down Expand Up @@ -673,6 +678,59 @@ func (c *REALITYConfig) Build() (proto.Message, error) {
config.SpiderX = u.String()
config.ServerName = c.ServerName
}

if len(c.RandPacket) != 0 {
if strings.Contains(c.RandPacket, "-") {
randPacket := strings.Split(c.RandPacket, "-")
if len(randPacket) != 2 {
return nil, errors.New(`incorrect range of "randPacket"`)
}
min, err := strconv.Atoi(randPacket[0])
if err != nil {
return nil, errors.New(`incorrect range of "randPacket" min value`)
}
max, err := strconv.Atoi(randPacket[1])
if err != nil {
return nil, errors.New(`incorrect range of "randPacket" max value`)
}
if min > max {
return nil, errors.New(`incorrect randPacket min > max`)
}
} else {
if _, err := strconv.Atoi(c.RandPacket); err != nil {
return nil, errors.New(`incorrect "randPacket" value`)
}
}
}

if len(c.SplitPacket) != 0 {
if strings.Contains(c.SplitPacket, "-") {
splitPacket := strings.Split(c.SplitPacket, "-")
if len(splitPacket) != 2 {
return nil, errors.New(`incorrect range of "splitPacket"`)
}
min, err := strconv.Atoi(splitPacket[0])
if err != nil {
return nil, errors.New(`incorrect range of "splitPacket" min value`)
}
max, err := strconv.Atoi(splitPacket[1])
if err != nil {
return nil, errors.New(`incorrect range of "splitPacket" max value`)
}
if min > max {
return nil, errors.New(`incorrect splitPacket min > max`)
}
} else {
if _, err := strconv.Atoi(c.SplitPacket); err != nil {
return nil, errors.New(`incorrect "splitPacket" value`)
}
}
}
config.SplitPacket = c.SplitPacket
config.RandPacket = c.RandPacket
config.PaddingSize = c.PaddingSize
config.SubchunkSize = c.SubchunkSize

return config, nil
}

Expand Down
4 changes: 2 additions & 2 deletions infra/conf/vless.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
account.Id = u.String()

switch account.Flow {
case "", vless.XRV:
case "", vless.XRV, vless.XSV:
default:
return nil, errors.New(`VLESS clients: "flow" doesn't support "` + account.Flow + `" in this version`)
}
Expand Down Expand Up @@ -180,7 +180,7 @@ func (c *VLessOutboundConfig) Build() (proto.Message, error) {
account.Id = u.String()

switch account.Flow {
case "", vless.XRV, vless.XRV + "-udp443":
case "", vless.XRV, vless.XRV + "-udp443", vless.XSV:
default:
return nil, errors.New(`VLESS users: "flow" doesn't support "` + account.Flow + `" in this version`)
}
Expand Down
4 changes: 4 additions & 0 deletions proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ var (
TlsClientHandShakeStart = []byte{0x16, 0x03}
TlsServerHandShakeStart = []byte{0x16, 0x03, 0x03}
TlsApplicationDataStart = []byte{0x17, 0x03, 0x03}
TlsChangeCipherSpecStart = []byte{0x14, 0x03, 0x03}

Tls13CipherSuiteDic = map[uint16]string{
0x1301: "TLS_AES_128_GCM_SHA256",
Expand Down Expand Up @@ -110,6 +111,9 @@ type TrafficState struct {
// write link state
IsPadding bool
WriterSwitchToDirectCopy bool

// temporary cache the buffers
CacheBuffer []buf.MultiBuffer
}

func NewTrafficState(userUUID []byte) *TrafficState {
Expand Down
8 changes: 6 additions & 2 deletions proxy/vless/encoding/addons.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/proxy"
"github.com/xtls/xray-core/proxy/vless"
"github.com/xtls/xray-core/transport/internet/reality/segaro"
"google.golang.org/protobuf/proto"
)

Expand Down Expand Up @@ -61,13 +62,16 @@ func DecodeHeaderAddons(buffer *buf.Buffer, reader io.Reader) (*Addons, error) {
}

// EncodeBodyAddons returns a Writer that auto-encrypt content written by caller.
func EncodeBodyAddons(writer io.Writer, request *protocol.RequestHeader, requestAddons *Addons, state *proxy.TrafficState, context context.Context) buf.Writer {
func EncodeBodyAddons(writer io.Writer, request *protocol.RequestHeader, requestAddons *Addons, state *proxy.TrafficState, context context.Context, segaroConfig *segaro.SegaroConfig) buf.Writer {
if request.Command == protocol.RequestCommandUDP {
return NewMultiLengthPacketWriter(writer.(buf.Writer))
}
w := buf.NewWriter(writer)
if requestAddons.Flow == vless.XRV {
switch requestAddons.Flow {
case vless.XRV:
w = proxy.NewVisionWriter(w, state, context)
case vless.XSV:
w = segaro.NewSegaroWriter(w, state, segaroConfig)
}
return w
}
Expand Down
63 changes: 54 additions & 9 deletions proxy/vless/inbound/inbound.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"time"
"unsafe"

goReality "github.com/xtls/reality"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/errors"
Expand All @@ -32,6 +33,7 @@ import (
"github.com/xtls/xray-core/proxy/vless"
"github.com/xtls/xray-core/proxy/vless/encoding"
"github.com/xtls/xray-core/transport/internet/reality"
"github.com/xtls/xray-core/transport/internet/reality/segaro"
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls"
)
Expand Down Expand Up @@ -197,6 +199,11 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
Buffer: buf.MultiBuffer{first},
}

inbound := session.InboundFromContext(ctx)
if inbound == nil {
panic("no inbound metadata")
}
var segaroConfig *segaro.SegaroConfig
var request *protocol.RequestHeader
var requestAddons *encoding.Addons
var err error
Expand All @@ -208,6 +215,36 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
err = errors.New("fallback directly")
} else {
request, requestAddons, isfb, err = encoding.DecodeRequestHeader(isfb, first, reader, h.validator)

// Try to decode as xtls-segaro-vision
if err != nil {
storeStartPosition := first.GetStart()
first.ResetStart()
first.Advance(4) // Skip chunk header
var realityConfig *goReality.Config
realityConfig, err = segaro.GetRealityServerConfig(&inbound.Conn)
if err != nil {
return errors.New("can not get goReality.Config")
}
segaroConfig = &segaro.SegaroConfig{GoRealityConfig: realityConfig}
paddingSize := int(segaroConfig.GetPaddingSize())
subChunkSize := int(segaroConfig.GetSubChunkSize())

decodedBuff := segaro.SegaroRemovePadding(buf.MultiBuffer{first}, paddingSize, subChunkSize)

decodedBuff.Advance(2) // Skip requestHeader content-length
request, requestAddons, isfb, err = encoding.DecodeRequestHeader(isfb, decodedBuff, decodedBuff, h.validator)
first.ResetStart()
if err != nil {
// Decode fail, Revert back
first.Advance(storeStartPosition)
} else {
// Decode success
requestAddons.Flow = vless.XSV
}
decodedBuff.Release()
decodedBuff = nil
}
}

if err != nil {
Expand Down Expand Up @@ -429,10 +466,6 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
}
errors.LogInfo(ctx, "received request for ", request.Destination())

inbound := session.InboundFromContext(ctx)
if inbound == nil {
panic("no inbound metadata")
}
inbound.Name = "vless"
inbound.User = request.User

Expand Down Expand Up @@ -476,6 +509,8 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
} else {
return errors.New(account.ID.String() + " is not able to use " + requestAddons.Flow).AtWarning()
}
case vless.XSV:
inbound.CanSpliceCopy = 3
case "":
inbound.CanSpliceCopy = 3
if account.Flow == vless.XRV && (request.Command == protocol.RequestCommandTCP || isMuxAndNotXUDP(request, first)) {
Expand Down Expand Up @@ -519,11 +554,17 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s

var err error

if requestAddons.Flow == vless.XRV {
switch requestAddons.Flow {
case 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, nil, ctx1)
} else {

case vless.XSV:
clientReader = segaro.NewSegaroReader(clientReader, trafficState)
err = segaro.SegaroRead(clientReader, serverWriter, timer, connection, trafficState, true, segaroConfig)

default:
// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBuffer
err = buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer))
}
Expand All @@ -544,7 +585,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
}

// default: clientWriter := bufferWriter
clientWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons, trafficState, ctx)
clientWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons, trafficState, ctx, segaroConfig)
multiBuffer, err1 := serverReader.ReadMultiBuffer()
if err1 != nil {
return err1 // ...
Expand All @@ -558,9 +599,13 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
}

var err error
if requestAddons.Flow == vless.XRV {

switch requestAddons.Flow {
case vless.XRV:
err = encoding.XtlsWrite(serverReader, clientWriter, timer, connection, trafficState, nil, ctx)
} else {
case vless.XSV:
err = segaro.SegaroWrite(serverReader, clientWriter, timer, connection, segaroConfig)
default:
// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBuffer
err = buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer))
}
Expand Down
Loading