mirror of
https://github.com/XTLS/Xray-core.git
synced 2024-11-04 14:13:03 +00:00
Add XTLS RPRX's Vision (#1235)
* Add XTLS RPRX's Vision * Add helpful warning when security is wrong * Add XTLS padding (draft) * Fix number of packet to filter * Xtls padding version 1.0 and unpadding logic
This commit is contained in:
parent
341d317d0c
commit
5e695327b1
@ -203,6 +203,19 @@ func SplitSize(mb MultiBuffer, size int32) (MultiBuffer, MultiBuffer) {
|
|||||||
return mb, r
|
return mb, r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SplitMulti splits the beginning of the MultiBuffer into first one, the index i and after into second one
|
||||||
|
func SplitMulti(mb MultiBuffer, i int) (MultiBuffer, MultiBuffer) {
|
||||||
|
mb2 := make(MultiBuffer, 0, len(mb))
|
||||||
|
if i < len(mb) && i >= 0 {
|
||||||
|
mb2 = append(mb2, mb[i:]...)
|
||||||
|
for j := i; j < len(mb); j++ {
|
||||||
|
mb[j] = nil
|
||||||
|
}
|
||||||
|
mb = mb[:i]
|
||||||
|
}
|
||||||
|
return mb, mb2
|
||||||
|
}
|
||||||
|
|
||||||
// WriteMultiBuffer writes all buffers from the MultiBuffer to the Writer one by one, and return error if any, with leftover MultiBuffer.
|
// WriteMultiBuffer writes all buffers from the MultiBuffer to the Writer one by one, and return error if any, with leftover MultiBuffer.
|
||||||
func WriteMultiBuffer(writer io.Writer, mb MultiBuffer) (MultiBuffer, error) {
|
func WriteMultiBuffer(writer io.Writer, mb MultiBuffer) (MultiBuffer, error) {
|
||||||
for {
|
for {
|
||||||
|
@ -53,8 +53,8 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
|
|||||||
account.Id = u.String()
|
account.Id = u.String()
|
||||||
|
|
||||||
switch account.Flow {
|
switch account.Flow {
|
||||||
case "", "xtls-rprx-origin", "xtls-rprx-direct":
|
case "", vless.XRO, vless.XRD, vless.XRV:
|
||||||
case "xtls-rprx-splice":
|
case vless.XRS:
|
||||||
return nil, newError(`VLESS clients: inbound doesn't support "xtls-rprx-splice" in this version, please use "xtls-rprx-direct" instead`)
|
return nil, newError(`VLESS clients: inbound doesn't support "xtls-rprx-splice" in this version, please use "xtls-rprx-direct" instead`)
|
||||||
default:
|
default:
|
||||||
return nil, newError(`VLESS clients: "flow" doesn't support "` + account.Flow + `" in this version`)
|
return nil, newError(`VLESS clients: "flow" doesn't support "` + account.Flow + `" in this version`)
|
||||||
@ -182,8 +182,8 @@ func (c *VLessOutboundConfig) Build() (proto.Message, error) {
|
|||||||
account.Id = u.String()
|
account.Id = u.String()
|
||||||
|
|
||||||
switch account.Flow {
|
switch account.Flow {
|
||||||
case "", "xtls-rprx-origin", "xtls-rprx-origin-udp443", "xtls-rprx-direct", "xtls-rprx-direct-udp443":
|
case "", vless.XRO, vless.XRO + "-udp443", vless.XRD, vless.XRD + "-udp443", vless.XRV, vless.XRV + "-udp443":
|
||||||
case "xtls-rprx-splice", "xtls-rprx-splice-udp443":
|
case vless.XRS, vless.XRS + "-udp443":
|
||||||
if runtime.GOOS != "linux" && runtime.GOOS != "android" {
|
if runtime.GOOS != "linux" && runtime.GOOS != "android" {
|
||||||
return nil, newError(`VLESS users: "` + account.Flow + `" only support linux in this version`)
|
return nil, newError(`VLESS users: "` + account.Flow + `" only support linux in this version`)
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
|
|
||||||
func EncodeHeaderAddons(buffer *buf.Buffer, addons *Addons) error {
|
func EncodeHeaderAddons(buffer *buf.Buffer, addons *Addons) error {
|
||||||
switch addons.Flow {
|
switch addons.Flow {
|
||||||
case vless.XRO, vless.XRD:
|
case vless.XRO, vless.XRD, vless.XRV:
|
||||||
bytes, err := proto.Marshal(addons)
|
bytes, err := proto.Marshal(addons)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return newError("failed to marshal addons protobuf value").Base(err)
|
return newError("failed to marshal addons protobuf value").Base(err)
|
||||||
|
@ -3,11 +3,15 @@ package encoding
|
|||||||
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
|
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/rand"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"math/big"
|
||||||
"runtime"
|
"runtime"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/buf"
|
"github.com/xtls/xray-core/common/buf"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
@ -18,6 +22,7 @@ import (
|
|||||||
"github.com/xtls/xray-core/features/stats"
|
"github.com/xtls/xray-core/features/stats"
|
||||||
"github.com/xtls/xray-core/proxy/vless"
|
"github.com/xtls/xray-core/proxy/vless"
|
||||||
"github.com/xtls/xray-core/transport/internet/stat"
|
"github.com/xtls/xray-core/transport/internet/stat"
|
||||||
|
"github.com/xtls/xray-core/transport/internet/tls"
|
||||||
"github.com/xtls/xray-core/transport/internet/xtls"
|
"github.com/xtls/xray-core/transport/internet/xtls"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -25,6 +30,11 @@ const (
|
|||||||
Version = byte(0)
|
Version = byte(0)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var tls13SupportedVersions = []byte{0x00, 0x2b, 0x00, 0x02, 0x03, 0x04}
|
||||||
|
var tlsClientHandShakeStart = []byte{0x16, 0x03}
|
||||||
|
var tlsServerHandShakeStart = []byte{0x16, 0x03, 0x03}
|
||||||
|
var tlsApplicationDataStart = []byte{0x17, 0x03, 0x03}
|
||||||
|
|
||||||
var addrParser = protocol.NewAddressParser(
|
var addrParser = protocol.NewAddressParser(
|
||||||
protocol.AddressFamilyByte(byte(protocol.AddressTypeIPv4), net.AddressFamilyIPv4),
|
protocol.AddressFamilyByte(byte(protocol.AddressTypeIPv4), net.AddressFamilyIPv4),
|
||||||
protocol.AddressFamilyByte(byte(protocol.AddressTypeDomain), net.AddressFamilyDomain),
|
protocol.AddressFamilyByte(byte(protocol.AddressTypeDomain), net.AddressFamilyDomain),
|
||||||
@ -176,40 +186,36 @@ func DecodeResponseHeader(reader io.Reader, request *protocol.RequestHeader) (*A
|
|||||||
return responseAddons, nil
|
return responseAddons, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadV(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn *xtls.Conn, rawConn syscall.RawConn, counter stats.Counter, sctx context.Context) error {
|
func ReadV(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn *xtls.Conn, rawConn syscall.RawConn, counter stats.Counter, ctx context.Context) error {
|
||||||
err := func() error {
|
err := func() error {
|
||||||
var ct stats.Counter
|
var ct stats.Counter
|
||||||
for {
|
for {
|
||||||
if conn.DirectIn {
|
if conn.DirectIn {
|
||||||
conn.DirectIn = false
|
conn.DirectIn = false
|
||||||
if sctx != nil {
|
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Conn != nil {
|
||||||
if inbound := session.InboundFromContext(sctx); inbound != nil && inbound.Conn != nil {
|
iConn := inbound.Conn
|
||||||
iConn := inbound.Conn
|
statConn, ok := iConn.(*stat.CounterConnection)
|
||||||
statConn, ok := iConn.(*stat.CounterConnection)
|
if ok {
|
||||||
if ok {
|
iConn = statConn.Connection
|
||||||
iConn = statConn.Connection
|
}
|
||||||
|
if xc, ok := iConn.(*xtls.Conn); ok {
|
||||||
|
iConn = xc.NetConn()
|
||||||
|
}
|
||||||
|
if tc, ok := iConn.(*net.TCPConn); ok {
|
||||||
|
if conn.SHOW {
|
||||||
|
fmt.Println(conn.MARK, "Splice")
|
||||||
}
|
}
|
||||||
if xc, ok := iConn.(*xtls.Conn); ok {
|
runtime.Gosched() // necessary
|
||||||
iConn = xc.NetConn()
|
w, err := tc.ReadFrom(conn.NetConn())
|
||||||
|
if counter != nil {
|
||||||
|
counter.Add(w)
|
||||||
}
|
}
|
||||||
if tc, ok := iConn.(*net.TCPConn); ok {
|
if statConn != nil && statConn.WriteCounter != nil {
|
||||||
if conn.SHOW {
|
statConn.WriteCounter.Add(w)
|
||||||
fmt.Println(conn.MARK, "Splice")
|
|
||||||
}
|
|
||||||
runtime.Gosched() // necessary
|
|
||||||
w, err := tc.ReadFrom(conn.NetConn())
|
|
||||||
if counter != nil {
|
|
||||||
counter.Add(w)
|
|
||||||
}
|
|
||||||
if statConn != nil && statConn.WriteCounter != nil {
|
|
||||||
statConn.WriteCounter.Add(w)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
panic("XTLS Splice: not TCP inbound")
|
|
||||||
}
|
}
|
||||||
|
return err
|
||||||
} else {
|
} else {
|
||||||
// panic("XTLS Splice: nil inbound or nil inbound.Conn")
|
panic("XTLS Splice: not TCP inbound")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
reader = buf.NewReadVReader(conn.NetConn(), rawConn, nil)
|
reader = buf.NewReadVReader(conn.NetConn(), rawConn, nil)
|
||||||
@ -238,3 +244,280 @@ func ReadV(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, c
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XtlsRead filter and read xtls protocol
|
||||||
|
func XtlsRead(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn *tls.Conn, rawConn syscall.RawConn, counter stats.Counter, ctx context.Context, userUUID []byte, numberOfPacketToFilter *int, isTLS13 *bool, isTLS12 *bool, isTLS *bool) error {
|
||||||
|
err := func() error {
|
||||||
|
var ct stats.Counter
|
||||||
|
filterUUID := true
|
||||||
|
shouldSwitchToDirectCopy := false
|
||||||
|
var remainingContent int32 = -1
|
||||||
|
var remainingPadding int32 = -1
|
||||||
|
currentCommand := 0
|
||||||
|
for {
|
||||||
|
if shouldSwitchToDirectCopy {
|
||||||
|
shouldSwitchToDirectCopy = false
|
||||||
|
if runtime.GOOS == "linux" || runtime.GOOS == "android" {
|
||||||
|
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Conn != nil {
|
||||||
|
iConn := inbound.Conn
|
||||||
|
statConn, ok := iConn.(*stat.CounterConnection)
|
||||||
|
if ok {
|
||||||
|
iConn = statConn.Connection
|
||||||
|
}
|
||||||
|
if xc, ok := iConn.(*tls.Conn); ok {
|
||||||
|
iConn = xc.NetConn()
|
||||||
|
}
|
||||||
|
if tc, ok := iConn.(*net.TCPConn); ok {
|
||||||
|
newError("XtlsRead splice").WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
runtime.Gosched() // necessary
|
||||||
|
w, err := tc.ReadFrom(conn.NetConn())
|
||||||
|
if counter != nil {
|
||||||
|
counter.Add(w)
|
||||||
|
}
|
||||||
|
if statConn != nil && statConn.WriteCounter != nil {
|
||||||
|
statConn.WriteCounter.Add(w)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
panic("XTLS Splice: not TCP inbound")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// panic("XTLS Splice: nil inbound or nil inbound.Conn")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reader = buf.NewReadVReader(conn.NetConn(), rawConn, nil)
|
||||||
|
ct = counter
|
||||||
|
newError("XtlsRead readV").WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
}
|
||||||
|
buffer, err := reader.ReadMultiBuffer()
|
||||||
|
if !buffer.IsEmpty() {
|
||||||
|
if filterUUID && (*isTLS || *numberOfPacketToFilter > 0) {
|
||||||
|
buffer = XtlsUnpadding(ctx, buffer, userUUID, &remainingContent, &remainingPadding, ¤tCommand)
|
||||||
|
if remainingContent == 0 && remainingPadding == 0 {
|
||||||
|
if currentCommand == 1 {
|
||||||
|
filterUUID = false
|
||||||
|
} else if currentCommand == 2 {
|
||||||
|
filterUUID = false
|
||||||
|
shouldSwitchToDirectCopy = true
|
||||||
|
} else if currentCommand != 0 {
|
||||||
|
newError("XtlsRead unknown command ", currentCommand, buffer.Len()).WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if *numberOfPacketToFilter > 0 {
|
||||||
|
XtlsFilterTls13(buffer, numberOfPacketToFilter, isTLS13, isTLS12, isTLS, ctx)
|
||||||
|
}
|
||||||
|
if ct != nil {
|
||||||
|
ct.Add(int64(buffer.Len()))
|
||||||
|
}
|
||||||
|
timer.Update()
|
||||||
|
if werr := writer.WriteMultiBuffer(buffer); werr != nil {
|
||||||
|
return werr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if err != nil && errors.Cause(err) != io.EOF {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// XtlsWrite filter and write xtls protocol
|
||||||
|
func XtlsWrite(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn *tls.Conn, counter stats.Counter, ctx context.Context, userUUID *[]byte, numberOfPacketToFilter *int, isTLS13 *bool, isTLS12 *bool, isTLS *bool) error {
|
||||||
|
err := func() error {
|
||||||
|
var ct stats.Counter
|
||||||
|
filterTlsApplicationData := true
|
||||||
|
shouldSwitchToDirectCopy := false
|
||||||
|
for {
|
||||||
|
buffer, err := reader.ReadMultiBuffer()
|
||||||
|
if !buffer.IsEmpty() {
|
||||||
|
if *numberOfPacketToFilter > 0 {
|
||||||
|
XtlsFilterTls13(buffer, numberOfPacketToFilter, isTLS13, isTLS12, isTLS, ctx)
|
||||||
|
}
|
||||||
|
if filterTlsApplicationData && *isTLS {
|
||||||
|
var xtlsSpecIndex int
|
||||||
|
for i, b := range buffer {
|
||||||
|
if b.Len() >= 6 && bytes.Equal(tlsApplicationDataStart, b.BytesTo(3)) {
|
||||||
|
var command byte = 0x01
|
||||||
|
if *isTLS13 {
|
||||||
|
shouldSwitchToDirectCopy = true
|
||||||
|
xtlsSpecIndex = i
|
||||||
|
command = 0x02
|
||||||
|
}
|
||||||
|
filterTlsApplicationData = false
|
||||||
|
buffer[i] = XtlsPadding(b, command, userUUID, ctx)
|
||||||
|
break
|
||||||
|
} else if !*isTLS12 && !*isTLS13 && *numberOfPacketToFilter <= 0 {
|
||||||
|
//maybe tls 1.1 or 1.0
|
||||||
|
filterTlsApplicationData = false
|
||||||
|
buffer[i] = XtlsPadding(b, 0x01, userUUID, ctx)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
buffer[i] = XtlsPadding(b, 0x00, userUUID, ctx)
|
||||||
|
}
|
||||||
|
if shouldSwitchToDirectCopy {
|
||||||
|
encryptBuffer, directBuffer := buf.SplitMulti(buffer, xtlsSpecIndex+1)
|
||||||
|
length := encryptBuffer.Len()
|
||||||
|
if !encryptBuffer.IsEmpty() {
|
||||||
|
timer.Update()
|
||||||
|
if werr := writer.WriteMultiBuffer(encryptBuffer); werr != nil {
|
||||||
|
return werr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer = directBuffer
|
||||||
|
writer = buf.NewWriter(conn.NetConn())
|
||||||
|
ct = counter
|
||||||
|
newError("XtlsWrite writeV ", xtlsSpecIndex, " ", length, " ", buffer.Len()).WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
time.Sleep(5 * time.Millisecond) // for some device, the first xtls direct packet fails without this delay
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !buffer.IsEmpty() {
|
||||||
|
if ct != nil {
|
||||||
|
ct.Add(int64(buffer.Len()))
|
||||||
|
}
|
||||||
|
timer.Update()
|
||||||
|
if werr := writer.WriteMultiBuffer(buffer); werr != nil {
|
||||||
|
return werr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if err != nil && errors.Cause(err) != io.EOF {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// XtlsFilterTls13 filter and recognize tls 1.3
|
||||||
|
func XtlsFilterTls13(buffer buf.MultiBuffer, numberOfPacketToFilter *int, isTLS13 *bool, isTLS12 *bool, isTLS *bool, ctx context.Context) {
|
||||||
|
for _, b := range buffer {
|
||||||
|
*numberOfPacketToFilter--
|
||||||
|
if b.Len() >= 6 {
|
||||||
|
startsBytes := b.BytesTo(6)
|
||||||
|
if bytes.Equal(tlsServerHandShakeStart, startsBytes[:3]) && startsBytes[5] == 0x02 {
|
||||||
|
total := (int(startsBytes[3])<<8 | int(startsBytes[4])) + 5
|
||||||
|
if b.Len() >= int32(total) {
|
||||||
|
if bytes.Contains(b.BytesTo(int32(total)), tls13SupportedVersions) {
|
||||||
|
*isTLS13 = true
|
||||||
|
*isTLS = true
|
||||||
|
newError("XtlsFilterTls13 found tls 1.3! ", buffer.Len()).WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
} else {
|
||||||
|
*isTLS12 = true
|
||||||
|
*isTLS = true
|
||||||
|
newError("XtlsFilterTls13 found tls 1.2! ", buffer.Len()).WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
}
|
||||||
|
*numberOfPacketToFilter = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if bytes.Equal(tlsClientHandShakeStart, startsBytes[:2]) && startsBytes[5] == 0x01 {
|
||||||
|
*isTLS = true
|
||||||
|
newError("XtlsFilterTls13 found tls client hello! ", buffer.Len()).WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if *numberOfPacketToFilter <= 0 {
|
||||||
|
newError("XtlsFilterTls13 stop filtering", buffer.Len()).WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// XtlsPadding add padding to eliminate length siganature during tls handshake
|
||||||
|
func XtlsPadding(b *buf.Buffer, command byte, userUUID *[]byte, ctx context.Context) *buf.Buffer {
|
||||||
|
var length int32 = 0
|
||||||
|
if b.Len() < 900 {
|
||||||
|
l, err := rand.Int(rand.Reader, big.NewInt(500))
|
||||||
|
if err != nil {
|
||||||
|
newError("failed to generate padding").Base(err).WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
}
|
||||||
|
length = int32(l.Int64()) + 900 - b.Len()
|
||||||
|
}
|
||||||
|
newbuffer := buf.New()
|
||||||
|
if userUUID != nil {
|
||||||
|
newbuffer.Write(*userUUID)
|
||||||
|
*userUUID = nil
|
||||||
|
}
|
||||||
|
newbuffer.Write([]byte{command, byte(b.Len() >> 8), byte(b.Len()), byte(length >> 8), byte(length)})
|
||||||
|
newbuffer.Write(b.Bytes())
|
||||||
|
newbuffer.Extend(length)
|
||||||
|
newError("XtlsPadding ", b.Len(), " ", length, " ", command).WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
b.Release()
|
||||||
|
b = nil
|
||||||
|
return newbuffer
|
||||||
|
}
|
||||||
|
|
||||||
|
// XtlsUnpadding remove padding and parse command
|
||||||
|
func XtlsUnpadding(ctx context.Context, buffer buf.MultiBuffer, userUUID []byte, remainingContent *int32, remainingPadding *int32, currentCommand *int) buf.MultiBuffer {
|
||||||
|
posindex := 0
|
||||||
|
var posByte int32 = 0
|
||||||
|
if *remainingContent == -1 && *remainingPadding == -1 {
|
||||||
|
for i, b := range buffer {
|
||||||
|
if b.Len() >= 21 && bytes.Equal(userUUID, b.BytesTo(16)) {
|
||||||
|
posindex = i
|
||||||
|
posByte = 16
|
||||||
|
*remainingContent = 0
|
||||||
|
*remainingPadding = 0
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if *remainingContent == -1 && *remainingPadding == -1 {
|
||||||
|
return buffer
|
||||||
|
}
|
||||||
|
mb2 := make(buf.MultiBuffer, 0, len(buffer))
|
||||||
|
for i := 0; i < posindex; i++ {
|
||||||
|
newbuffer := buf.New()
|
||||||
|
newbuffer.Write(buffer[i].Bytes())
|
||||||
|
mb2 = append(mb2, newbuffer)
|
||||||
|
}
|
||||||
|
for i := posindex; i < len(buffer); i++ {
|
||||||
|
b := buffer[i]
|
||||||
|
for posByte < b.Len() {
|
||||||
|
if *remainingContent <= 0 && *remainingPadding <= 0 {
|
||||||
|
if *currentCommand == 1 {
|
||||||
|
len := b.Len() - posByte
|
||||||
|
newbuffer := buf.New()
|
||||||
|
newbuffer.Write(b.BytesRange(posByte, posByte+len))
|
||||||
|
mb2 = append(mb2, newbuffer)
|
||||||
|
posByte += len
|
||||||
|
} else {
|
||||||
|
paddingInfo := b.BytesRange(posByte, posByte+5)
|
||||||
|
*currentCommand = int(paddingInfo[0])
|
||||||
|
*remainingContent = int32(paddingInfo[1])<<8 | int32(paddingInfo[2])
|
||||||
|
*remainingPadding = int32(paddingInfo[3])<<8 | int32(paddingInfo[4])
|
||||||
|
newError("Xtls Unpadding new block", i, " ", posByte, " content ", *remainingContent, " padding ", *remainingPadding, " ", paddingInfo[0]).WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
posByte += 5
|
||||||
|
}
|
||||||
|
} else if *remainingContent > 0 {
|
||||||
|
len := *remainingContent
|
||||||
|
if b.Len() < posByte+*remainingContent {
|
||||||
|
len = b.Len() - posByte
|
||||||
|
}
|
||||||
|
newbuffer := buf.New()
|
||||||
|
newbuffer.Write(b.BytesRange(posByte, posByte+len))
|
||||||
|
mb2 = append(mb2, newbuffer)
|
||||||
|
*remainingContent -= len
|
||||||
|
posByte += len
|
||||||
|
} else { // remainingPadding > 0
|
||||||
|
len := *remainingPadding
|
||||||
|
if b.Len() < posByte+*remainingPadding {
|
||||||
|
len = b.Len() - posByte
|
||||||
|
}
|
||||||
|
*remainingPadding -= len
|
||||||
|
posByte += len
|
||||||
|
}
|
||||||
|
if posByte == b.Len() {
|
||||||
|
posByte = 0
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf.ReleaseMulti(buffer)
|
||||||
|
return mb2
|
||||||
|
}
|
||||||
|
@ -442,7 +442,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
var rawConn syscall.RawConn
|
var rawConn syscall.RawConn
|
||||||
|
|
||||||
switch requestAddons.Flow {
|
switch requestAddons.Flow {
|
||||||
case vless.XRO, vless.XRD:
|
case vless.XRO, vless.XRD, vless.XRV:
|
||||||
if account.Flow == requestAddons.Flow {
|
if account.Flow == requestAddons.Flow {
|
||||||
switch request.Command {
|
switch request.Command {
|
||||||
case protocol.RequestCommandMux:
|
case protocol.RequestCommandMux:
|
||||||
@ -450,7 +450,14 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
case protocol.RequestCommandUDP:
|
case protocol.RequestCommandUDP:
|
||||||
return newError(requestAddons.Flow + " doesn't support UDP").AtWarning()
|
return newError(requestAddons.Flow + " doesn't support UDP").AtWarning()
|
||||||
case protocol.RequestCommandTCP:
|
case protocol.RequestCommandTCP:
|
||||||
if xtlsConn, ok := iConn.(*xtls.Conn); ok {
|
if requestAddons.Flow == vless.XRV {
|
||||||
|
if _, ok := iConn.(*xtls.Conn); ok {
|
||||||
|
return newError(`failed to use ` + requestAddons.Flow + `, vision "security" must be "tls"`).AtWarning()
|
||||||
|
}
|
||||||
|
if sc, ok := iConn.(*tls.Conn).NetConn().(syscall.Conn); ok {
|
||||||
|
rawConn, _ = sc.SyscallConn()
|
||||||
|
}
|
||||||
|
} else if xtlsConn, ok := iConn.(*xtls.Conn); ok {
|
||||||
xtlsConn.RPRX = true
|
xtlsConn.RPRX = true
|
||||||
xtlsConn.SHOW = xtls_show
|
xtlsConn.SHOW = xtls_show
|
||||||
xtlsConn.MARK = "XTLS"
|
xtlsConn.MARK = "XTLS"
|
||||||
@ -494,6 +501,10 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
|
|
||||||
serverReader := link.Reader // .(*pipe.Reader)
|
serverReader := link.Reader // .(*pipe.Reader)
|
||||||
serverWriter := link.Writer // .(*pipe.Writer)
|
serverWriter := link.Writer // .(*pipe.Writer)
|
||||||
|
isTLS13 := false
|
||||||
|
isTLS12 := false
|
||||||
|
isTLS := false
|
||||||
|
numberOfPacketToFilter := 8
|
||||||
|
|
||||||
postRequest := func() error {
|
postRequest := func() error {
|
||||||
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
|
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
|
||||||
@ -508,7 +519,13 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
if statConn != nil {
|
if statConn != nil {
|
||||||
counter = statConn.ReadCounter
|
counter = statConn.ReadCounter
|
||||||
}
|
}
|
||||||
err = encoding.ReadV(clientReader, serverWriter, timer, iConn.(*xtls.Conn), rawConn, counter, nil)
|
if requestAddons.Flow == vless.XRV {
|
||||||
|
//TODO enable splice
|
||||||
|
ctx = session.ContextWithInbound(ctx, nil)
|
||||||
|
err = encoding.XtlsRead(clientReader, serverWriter, timer, iConn.(*tls.Conn), rawConn, counter, ctx, account.ID.Bytes(), &numberOfPacketToFilter, &isTLS13, &isTLS12, &isTLS)
|
||||||
|
} else {
|
||||||
|
err = encoding.ReadV(clientReader, serverWriter, timer, iConn.(*xtls.Conn), rawConn, counter, ctx)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBufer
|
// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBufer
|
||||||
err = buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer))
|
err = buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer))
|
||||||
@ -531,26 +548,42 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
|
|
||||||
// default: clientWriter := bufferWriter
|
// default: clientWriter := bufferWriter
|
||||||
clientWriter := encoding.EncodeBodyAddons(bufferWriter, request, responseAddons)
|
clientWriter := encoding.EncodeBodyAddons(bufferWriter, request, responseAddons)
|
||||||
{
|
userUUID := account.ID.Bytes()
|
||||||
multiBuffer, err := serverReader.ReadMultiBuffer()
|
multiBuffer, err1 := serverReader.ReadMultiBuffer()
|
||||||
if err != nil {
|
if err1 != nil {
|
||||||
return err // ...
|
return err1 // ...
|
||||||
}
|
}
|
||||||
if err := clientWriter.WriteMultiBuffer(multiBuffer); err != nil {
|
if requestAddons.Flow == vless.XRV {
|
||||||
return err // ...
|
encoding.XtlsFilterTls13(multiBuffer, &numberOfPacketToFilter, &isTLS13, &isTLS12, &isTLS, ctx)
|
||||||
|
if isTLS {
|
||||||
|
for i, b := range multiBuffer {
|
||||||
|
|
||||||
|
multiBuffer[i] = encoding.XtlsPadding(b, 0x00, &userUUID, ctx)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if err := clientWriter.WriteMultiBuffer(multiBuffer); err != nil {
|
||||||
|
return err // ...
|
||||||
|
}
|
||||||
// Flush; bufferWriter.WriteMultiBufer now is bufferWriter.writer.WriteMultiBuffer
|
// Flush; bufferWriter.WriteMultiBufer now is bufferWriter.writer.WriteMultiBuffer
|
||||||
if err := bufferWriter.SetBuffered(false); err != nil {
|
if err := bufferWriter.SetBuffered(false); err != nil {
|
||||||
return newError("failed to write A response payload").Base(err).AtWarning()
|
return newError("failed to write A response payload").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer
|
var err error
|
||||||
if err := buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer)); err != nil {
|
if rawConn != nil && requestAddons.Flow == vless.XRV {
|
||||||
|
var counter stats.Counter
|
||||||
|
if statConn != nil {
|
||||||
|
counter = statConn.WriteCounter
|
||||||
|
}
|
||||||
|
err = encoding.XtlsWrite(serverReader, clientWriter, timer, iConn.(*tls.Conn), counter, ctx, &userUUID, &numberOfPacketToFilter, &isTLS13, &isTLS12, &isTLS)
|
||||||
|
} else {
|
||||||
|
// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer
|
||||||
|
err = buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer))
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
return newError("failed to transfer response payload").Base(err).AtInfo()
|
return newError("failed to transfer response payload").Base(err).AtInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Indicates the end of response payload.
|
// Indicates the end of response payload.
|
||||||
switch responseAddons.Flow {
|
switch responseAddons.Flow {
|
||||||
default:
|
default:
|
||||||
|
@ -5,7 +5,6 @@ package outbound
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/buf"
|
"github.com/xtls/xray-core/common/buf"
|
||||||
@ -25,6 +24,7 @@ import (
|
|||||||
"github.com/xtls/xray-core/transport"
|
"github.com/xtls/xray-core/transport"
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
"github.com/xtls/xray-core/transport/internet/stat"
|
"github.com/xtls/xray-core/transport/internet/stat"
|
||||||
|
"github.com/xtls/xray-core/transport/internet/tls"
|
||||||
"github.com/xtls/xray-core/transport/internet/xtls"
|
"github.com/xtls/xray-core/transport/internet/xtls"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -128,15 +128,13 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
}
|
}
|
||||||
|
|
||||||
var rawConn syscall.RawConn
|
var rawConn syscall.RawConn
|
||||||
var sctx context.Context
|
|
||||||
|
|
||||||
allowUDP443 := false
|
allowUDP443 := false
|
||||||
switch requestAddons.Flow {
|
switch requestAddons.Flow {
|
||||||
case vless.XRO + "-udp443", vless.XRD + "-udp443", vless.XRS + "-udp443":
|
case vless.XRO + "-udp443", vless.XRD + "-udp443", vless.XRS + "-udp443", vless.XRV + "-udp443":
|
||||||
allowUDP443 = true
|
allowUDP443 = true
|
||||||
requestAddons.Flow = requestAddons.Flow[:16]
|
requestAddons.Flow = requestAddons.Flow[:16]
|
||||||
fallthrough
|
fallthrough
|
||||||
case vless.XRO, vless.XRD, vless.XRS:
|
case vless.XRO, vless.XRD, vless.XRS, vless.XRV:
|
||||||
switch request.Command {
|
switch request.Command {
|
||||||
case protocol.RequestCommandMux:
|
case protocol.RequestCommandMux:
|
||||||
return newError(requestAddons.Flow + " doesn't support Mux").AtWarning()
|
return newError(requestAddons.Flow + " doesn't support Mux").AtWarning()
|
||||||
@ -146,12 +144,18 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
}
|
}
|
||||||
requestAddons.Flow = ""
|
requestAddons.Flow = ""
|
||||||
case protocol.RequestCommandTCP:
|
case protocol.RequestCommandTCP:
|
||||||
if xtlsConn, ok := iConn.(*xtls.Conn); ok {
|
if requestAddons.Flow == vless.XRV {
|
||||||
|
if _, ok := iConn.(*xtls.Conn); ok {
|
||||||
|
return newError(`failed to use ` + requestAddons.Flow + `, vision "security" must be "tls"`).AtWarning()
|
||||||
|
}
|
||||||
|
if sc, ok := iConn.(*tls.Conn).NetConn().(syscall.Conn); ok {
|
||||||
|
rawConn, _ = sc.SyscallConn()
|
||||||
|
}
|
||||||
|
} else if xtlsConn, ok := iConn.(*xtls.Conn); ok {
|
||||||
xtlsConn.RPRX = true
|
xtlsConn.RPRX = true
|
||||||
xtlsConn.SHOW = xtls_show
|
xtlsConn.SHOW = xtls_show
|
||||||
xtlsConn.MARK = "XTLS"
|
xtlsConn.MARK = "XTLS"
|
||||||
if requestAddons.Flow == vless.XRS {
|
if requestAddons.Flow == vless.XRS {
|
||||||
sctx = ctx
|
|
||||||
requestAddons.Flow = vless.XRD
|
requestAddons.Flow = vless.XRD
|
||||||
}
|
}
|
||||||
if requestAddons.Flow == vless.XRD {
|
if requestAddons.Flow == vless.XRD {
|
||||||
@ -176,6 +180,10 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
|
|
||||||
clientReader := link.Reader // .(*pipe.Reader)
|
clientReader := link.Reader // .(*pipe.Reader)
|
||||||
clientWriter := link.Writer // .(*pipe.Writer)
|
clientWriter := link.Writer // .(*pipe.Writer)
|
||||||
|
isTLS13 := false
|
||||||
|
isTLS12 := false
|
||||||
|
isTLS := false
|
||||||
|
numberOfPacketToFilter := 8
|
||||||
|
|
||||||
if request.Command == protocol.RequestCommandUDP && h.cone && request.Port != 53 && request.Port != 443 {
|
if request.Command == protocol.RequestCommandUDP && h.cone && request.Port != 53 && request.Port != 443 {
|
||||||
request.Command = protocol.RequestCommandMux
|
request.Command = protocol.RequestCommandMux
|
||||||
@ -196,17 +204,39 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
if request.Command == protocol.RequestCommandMux && request.Port == 666 {
|
if request.Command == protocol.RequestCommandMux && request.Port == 666 {
|
||||||
serverWriter = xudp.NewPacketWriter(serverWriter, target)
|
serverWriter = xudp.NewPacketWriter(serverWriter, target)
|
||||||
}
|
}
|
||||||
if err := buf.CopyOnceTimeout(clientReader, serverWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout {
|
userUUID := account.ID.Bytes()
|
||||||
|
multiBuffer, err1 := clientReader.ReadMultiBuffer()
|
||||||
|
if err1 != nil {
|
||||||
|
return err1 // ...
|
||||||
|
}
|
||||||
|
if requestAddons.Flow == vless.XRV {
|
||||||
|
encoding.XtlsFilterTls13(multiBuffer, &numberOfPacketToFilter, &isTLS13, &isTLS12, &isTLS, ctx)
|
||||||
|
if isTLS {
|
||||||
|
for i, b := range multiBuffer {
|
||||||
|
multiBuffer[i] = encoding.XtlsPadding(b, 0x00, &userUUID, ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := serverWriter.WriteMultiBuffer(multiBuffer); err != nil {
|
||||||
return err // ...
|
return err // ...
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush; bufferWriter.WriteMultiBufer now is bufferWriter.writer.WriteMultiBuffer
|
// Flush; bufferWriter.WriteMultiBufer now is bufferWriter.writer.WriteMultiBuffer
|
||||||
if err := bufferWriter.SetBuffered(false); err != nil {
|
if err := bufferWriter.SetBuffered(false); err != nil {
|
||||||
return newError("failed to write A request payload").Base(err).AtWarning()
|
return newError("failed to write A request payload").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBufer
|
var err error
|
||||||
if err := buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer)); err != nil {
|
if rawConn != nil && requestAddons.Flow == vless.XRV {
|
||||||
|
var counter stats.Counter
|
||||||
|
if statConn != nil {
|
||||||
|
counter = statConn.WriteCounter
|
||||||
|
}
|
||||||
|
err = encoding.XtlsWrite(clientReader, serverWriter, timer, iConn.(*tls.Conn), counter, ctx, &userUUID, &numberOfPacketToFilter, &isTLS13, &isTLS12, &isTLS)
|
||||||
|
} else {
|
||||||
|
// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBufer
|
||||||
|
err = buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer))
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
return newError("failed to transfer request payload").Base(err).AtInfo()
|
return newError("failed to transfer request payload").Base(err).AtInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,7 +266,11 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
if statConn != nil {
|
if statConn != nil {
|
||||||
counter = statConn.ReadCounter
|
counter = statConn.ReadCounter
|
||||||
}
|
}
|
||||||
err = encoding.ReadV(serverReader, clientWriter, timer, iConn.(*xtls.Conn), rawConn, counter, sctx)
|
if requestAddons.Flow == vless.XRV {
|
||||||
|
err = encoding.XtlsRead(serverReader, clientWriter, timer, iConn.(*tls.Conn), rawConn, counter, ctx, account.ID.Bytes(), &numberOfPacketToFilter, &isTLS13, &isTLS12, &isTLS)
|
||||||
|
} else {
|
||||||
|
err = encoding.ReadV(serverReader, clientWriter, timer, iConn.(*xtls.Conn), rawConn, counter, ctx)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer
|
// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer
|
||||||
err = buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer))
|
err = buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer))
|
||||||
|
@ -11,4 +11,5 @@ const (
|
|||||||
XRO = "xtls-rprx-origin"
|
XRO = "xtls-rprx-origin"
|
||||||
XRD = "xtls-rprx-direct"
|
XRD = "xtls-rprx-direct"
|
||||||
XRS = "xtls-rprx-splice"
|
XRS = "xtls-rprx-splice"
|
||||||
|
XRV = "xtls-rprx-vision"
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user