mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-12-13 13:19:48 +04:00
VLESS Encryption: Add customizable 1-RTT padding parameters; Decrease memory using; Chores
Completes https://github.com/XTLS/Xray-core/pull/5067 --------- Co-authored-by: wwqgtxx <wwqgtxx@gmail.com>
This commit is contained in:
@@ -7,10 +7,12 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/xtls/xray-core/common/crypto"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
"lukechampine.com/blake3"
|
||||
@@ -31,15 +33,14 @@ type CommonConn struct {
|
||||
AEAD *AEAD
|
||||
PeerAEAD *AEAD
|
||||
PeerPadding []byte
|
||||
PeerInBytes []byte
|
||||
PeerCache []byte
|
||||
rawInput bytes.Buffer
|
||||
input bytes.Reader
|
||||
}
|
||||
|
||||
func NewCommonConn(conn net.Conn, useAES bool) *CommonConn {
|
||||
return &CommonConn{
|
||||
Conn: conn,
|
||||
UseAES: useAES,
|
||||
PeerInBytes: make([]byte, 5+17000), // no need to use sync.Pool, because we are always reading
|
||||
Conn: conn,
|
||||
UseAES: useAES,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,16 +100,14 @@ func (c *CommonConn) Read(b []byte) (int, error) {
|
||||
}
|
||||
c.PeerPadding = nil
|
||||
}
|
||||
if len(c.PeerCache) > 0 {
|
||||
n := copy(b, c.PeerCache)
|
||||
c.PeerCache = c.PeerCache[n:]
|
||||
return n, nil
|
||||
if c.input.Len() > 0 {
|
||||
return c.input.Read(b)
|
||||
}
|
||||
peerHeader := c.PeerInBytes[:5]
|
||||
if _, err := io.ReadFull(c.Conn, peerHeader); err != nil {
|
||||
peerHeader := [5]byte{}
|
||||
if _, err := io.ReadFull(c.Conn, peerHeader[:]); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
l, err := DecodeHeader(c.PeerInBytes[:5]) // l: 17~17000
|
||||
l, err := DecodeHeader(peerHeader[:]) // l: 17~17000
|
||||
if err != nil {
|
||||
if c.Client != nil && strings.Contains(err.Error(), "invalid header: ") { // client's 0-RTT
|
||||
c.Client.RWLock.Lock()
|
||||
@@ -121,7 +120,10 @@ func (c *CommonConn) Read(b []byte) (int, error) {
|
||||
return 0, err
|
||||
}
|
||||
c.Client = nil
|
||||
peerData := c.PeerInBytes[5 : 5+l]
|
||||
if c.rawInput.Cap() < l {
|
||||
c.rawInput.Grow(l) // no need to use sync.Pool, because we are always reading
|
||||
}
|
||||
peerData := c.rawInput.Bytes()[:l]
|
||||
if _, err := io.ReadFull(c.Conn, peerData); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -131,9 +133,9 @@ func (c *CommonConn) Read(b []byte) (int, error) {
|
||||
}
|
||||
var newAEAD *AEAD
|
||||
if bytes.Equal(c.PeerAEAD.Nonce[:], MaxNonce) {
|
||||
newAEAD = NewAEAD(c.PeerInBytes[:5+l], c.UnitedKey, c.UseAES)
|
||||
newAEAD = NewAEAD(append(peerHeader[:], peerData...), c.UnitedKey, c.UseAES)
|
||||
}
|
||||
_, err = c.PeerAEAD.Open(dst[:0], nil, peerData, peerHeader)
|
||||
_, err = c.PeerAEAD.Open(dst[:0], nil, peerData, peerHeader[:])
|
||||
if newAEAD != nil {
|
||||
c.PeerAEAD = newAEAD
|
||||
}
|
||||
@@ -141,7 +143,7 @@ func (c *CommonConn) Read(b []byte) (int, error) {
|
||||
return 0, err
|
||||
}
|
||||
if len(dst) > len(b) {
|
||||
c.PeerCache = dst[copy(b, dst):]
|
||||
c.input.Reset(dst[copy(b, dst):])
|
||||
dst = b // for len(dst)
|
||||
}
|
||||
return len(dst), nil
|
||||
@@ -213,7 +215,55 @@ func DecodeHeader(h []byte) (l int, err error) {
|
||||
l = 0
|
||||
}
|
||||
if l < 17 || l > 17000 { // TODO: TLSv1.3 max length
|
||||
err = errors.New("invalid header: ", fmt.Sprintf("%v", h[:5])) // DO NOT CHANGE: relied by client's Read()
|
||||
err = errors.New("invalid header: " + fmt.Sprintf("%v", h[:5])) // DO NOT CHANGE: relied by client's Read()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ParsePadding(padding string, paddingLens, paddingGaps *[][2]int) (err error) {
|
||||
if padding == "" {
|
||||
return
|
||||
}
|
||||
maxLen := 0
|
||||
for i, s := range strings.Split(padding, ".") {
|
||||
x := strings.SplitN(s, "-", 2)
|
||||
if len(x) != 2 || x[0] == "" || x[1] == "" {
|
||||
return errors.New("invalid padding lenth/gap parameter: " + s)
|
||||
}
|
||||
y := [2]int{}
|
||||
if y[0], err = strconv.Atoi(x[0]); err != nil {
|
||||
return
|
||||
}
|
||||
if y[1], err = strconv.Atoi(x[1]); err != nil {
|
||||
return
|
||||
}
|
||||
if i == 0 && (y[0] < 17 || y[1] < 17) {
|
||||
return errors.New("first padding length must be larger than 16")
|
||||
}
|
||||
if i%2 == 0 {
|
||||
*paddingLens = append(*paddingLens, y)
|
||||
maxLen += max(y[0], y[1])
|
||||
} else {
|
||||
*paddingGaps = append(*paddingGaps, y)
|
||||
}
|
||||
}
|
||||
if maxLen > 65535 {
|
||||
return errors.New("total padding length must be smaller than 65536")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func CreatPadding(paddingLens, paddingGaps [][2]int) (length int, lens []int, gaps []time.Duration) {
|
||||
if len(paddingLens) == 0 {
|
||||
paddingLens = [][2]int{{111, 1111}, {3333, -1234}}
|
||||
paddingGaps = [][2]int{{111, -66}}
|
||||
}
|
||||
for _, l := range paddingLens {
|
||||
lens = append(lens, int(max(0, crypto.RandBetween(int64(l[0]), int64(l[1])))))
|
||||
length += lens[len(lens)-1]
|
||||
}
|
||||
for _, g := range paddingGaps {
|
||||
gaps = append(gaps, time.Duration(max(0, crypto.RandBetween(int64(g[0]), int64(g[1]))))*time.Millisecond)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user