Finalmask: Add header-custom (TCP & UDP), fragment (TCP), noise (UDP); Support dialer-proxy, XHTTP/3; Fix XDNS, XICMP potential panic (#5657)

https://github.com/XTLS/Xray-core/pull/5657#issuecomment-4016609446
This commit is contained in:
LjhAUMEM
2026-03-07 23:42:18 +08:00
committed by GitHub
parent ea87941b77
commit a204873d79
62 changed files with 3045 additions and 1367 deletions
@@ -7,10 +7,10 @@ import (
func (c *Config) UDP() {
}
func (c *Config) WrapPacketConnClient(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return NewConnClient(c, raw, first, leaveSize)
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
return NewConnClient(c, raw)
}
func (c *Config) WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return NewConnServer(c, raw, first, leaveSize)
func (c *Config) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
return NewConnServer(c, raw)
}
@@ -1,99 +1,77 @@
package aes128gcm
import (
"context"
"crypto/cipher"
"crypto/rand"
"crypto/sha256"
"io"
"net"
sync "sync"
"time"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/crypto"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/transport/internet/finalmask"
)
type aes128gcmConn struct {
first bool
leaveSize int32
conn net.PacketConn
net.PacketConn
aead cipher.AEAD
readBuf []byte
readMutex sync.Mutex
writeBuf []byte
writeMutex sync.Mutex
}
func NewConnClient(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
func NewConnClient(c *Config, raw net.PacketConn) (net.PacketConn, error) {
hashedPsk := sha256.Sum256([]byte(c.Password))
conn := &aes128gcmConn{
first: first,
leaveSize: leaveSize,
conn: raw,
aead: crypto.NewAesGcm(hashedPsk[:16]),
}
if first {
conn.readBuf = make([]byte, 8192)
conn.writeBuf = make([]byte, 8192)
PacketConn: raw,
aead: crypto.NewAesGcm(hashedPsk[:16]),
}
return conn, nil
}
func NewConnServer(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
return NewConnClient(c, raw, first, leaveSize)
}
func (c *aes128gcmConn) Size() int32 {
return int32(c.aead.NonceSize()) + int32(c.aead.Overhead())
func NewConnServer(c *Config, raw net.PacketConn) (net.PacketConn, error) {
return NewConnClient(c, raw)
}
func (c *aes128gcmConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
if c.first {
c.readMutex.Lock()
if len(p) < finalmask.UDPSize {
buf := make([]byte, finalmask.UDPSize)
n, addr, err = c.conn.ReadFrom(c.readBuf)
if err != nil {
c.readMutex.Unlock()
n, addr, err = c.PacketConn.ReadFrom(buf)
if err != nil || n == 0 {
return n, addr, err
}
if n < int(c.Size()) {
c.readMutex.Unlock()
return 0, addr, errors.New("aead").Base(io.ErrShortBuffer)
}
if len(p) < n-int(c.Size()) {
c.readMutex.Unlock()
return 0, addr, errors.New("aead").Base(io.ErrShortBuffer)
if n < c.aead.NonceSize()+c.aead.Overhead() {
errors.LogDebug(context.Background(), addr, " mask read err aead short lenth ", n)
return 0, addr, nil
}
nonceSize := c.aead.NonceSize()
nonce := c.readBuf[:nonceSize]
ciphertext := c.readBuf[nonceSize:n]
_, err = c.aead.Open(p[:0], nonce, ciphertext, nil)
nonce := buf[:nonceSize]
ciphertext := buf[nonceSize:n]
plaintext, err := c.aead.Open(p[:0], nonce, ciphertext, nil)
if err != nil {
c.readMutex.Unlock()
return 0, addr, errors.New("aead open").Base(err)
errors.LogDebug(context.Background(), addr, " mask read err aead open ", err)
return 0, addr, nil
}
c.readMutex.Unlock()
return n - int(c.Size()), addr, nil
if len(plaintext) > len(p) {
errors.LogDebug(context.Background(), addr, " mask read err short buffer ", len(p), " ", len(plaintext))
return 0, addr, nil
}
return n - c.aead.NonceSize() - c.aead.Overhead(), addr, nil
}
n, addr, err = c.conn.ReadFrom(p)
if err != nil {
n, addr, err = c.PacketConn.ReadFrom(p)
if err != nil || n == 0 {
return n, addr, err
}
if n < int(c.Size()) {
return 0, addr, errors.New("aead").Base(io.ErrShortBuffer)
if n < c.aead.NonceSize()+c.aead.Overhead() {
errors.LogDebug(context.Background(), addr, " mask read err aead short lenth ", n)
return 0, addr, nil
}
nonceSize := c.aead.NonceSize()
@@ -101,74 +79,40 @@ func (c *aes128gcmConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
ciphertext := p[nonceSize:n]
_, err = c.aead.Open(ciphertext[:0], nonce, ciphertext, nil)
if err != nil {
return 0, addr, errors.New("aead open").Base(err)
errors.LogDebug(context.Background(), addr, " mask read err aead open ", err)
return 0, addr, nil
}
copy(p, p[nonceSize:n-c.aead.Overhead()])
return n - int(c.Size()), addr, nil
return n - c.aead.NonceSize() - c.aead.Overhead(), addr, nil
}
func (c *aes128gcmConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
if c.first {
if c.leaveSize+c.Size()+int32(len(p)) > 8192 {
return 0, errors.New("too many masks")
}
if c.aead.NonceSize()+c.aead.Overhead()+len(p) > finalmask.UDPSize {
errors.LogDebug(context.Background(), addr, " mask write err short write ", c.aead.NonceSize()+c.aead.Overhead()+len(p), " ", finalmask.UDPSize)
return 0, nil
}
c.writeMutex.Lock()
n = copy(c.writeBuf[c.leaveSize+int32(c.aead.NonceSize()):], p)
// n = copy(c.writeBuf[c.leaveSize+c.Size():], p)
n += int(c.leaveSize) + int(c.Size())
nonceSize := c.aead.NonceSize()
nonce := c.writeBuf[c.leaveSize : c.leaveSize+int32(nonceSize)]
common.Must2(rand.Read(nonce))
// copy(c.writeBuf[c.leaveSize+int32(nonceSize):], c.writeBuf[c.leaveSize+c.Size():n])
plaintext := c.writeBuf[c.leaveSize+int32(nonceSize) : n-c.aead.Overhead()]
_ = c.aead.Seal(plaintext[:0], nonce, plaintext, nil)
nn, err := c.conn.WriteTo(c.writeBuf[:n], addr)
if err != nil {
c.writeMutex.Unlock()
return 0, err
}
if nn != n {
c.writeMutex.Unlock()
return 0, errors.New("nn != n")
}
c.writeMutex.Unlock()
return len(p), nil
var buf []byte
if cap(p) != finalmask.UDPSize {
buf = make([]byte, finalmask.UDPSize)
} else {
buf = p[:c.aead.NonceSize()+c.aead.Overhead()+len(p)]
copy(buf[c.aead.NonceSize():], p)
p = buf[c.aead.NonceSize() : c.aead.NonceSize()+len(p)]
}
nonceSize := c.aead.NonceSize()
nonce := p[c.leaveSize : c.leaveSize+int32(nonceSize)]
nonce := buf[:nonceSize]
common.Must2(rand.Read(nonce))
copy(p[c.leaveSize+int32(nonceSize):], p[c.leaveSize+c.Size():])
plaintext := p[c.leaveSize+int32(nonceSize) : len(p)-c.aead.Overhead()]
_ = c.aead.Seal(plaintext[:0], nonce, plaintext, nil)
ciphertext := buf[nonceSize : c.aead.NonceSize()+c.aead.Overhead()+len(p)]
_ = c.aead.Seal(ciphertext[:0], nonce, p, nil)
return c.conn.WriteTo(p, addr)
}
_, err = c.PacketConn.WriteTo(buf[:c.aead.NonceSize()+c.aead.Overhead()+len(p)], addr)
if err != nil {
return 0, err
}
func (c *aes128gcmConn) Close() error {
return c.conn.Close()
}
func (c *aes128gcmConn) LocalAddr() net.Addr {
return c.conn.LocalAddr()
}
func (c *aes128gcmConn) SetDeadline(t time.Time) error {
return c.conn.SetDeadline(t)
}
func (c *aes128gcmConn) SetReadDeadline(t time.Time) error {
return c.conn.SetReadDeadline(t)
}
func (c *aes128gcmConn) SetWriteDeadline(t time.Time) error {
return c.conn.SetWriteDeadline(t)
return len(p), nil
}
@@ -7,10 +7,10 @@ import (
func (c *Config) UDP() {
}
func (c *Config) WrapPacketConnClient(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return NewConnClient(c, raw, first, leaveSize)
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
return NewConnClient(c, raw)
}
func (c *Config) WrapPacketConnServer(raw net.PacketConn, first bool, leaveSize int32, end bool) (net.PacketConn, error) {
return NewConnServer(c, raw, first, leaveSize)
func (c *Config) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
return NewConnServer(c, raw)
}
@@ -1,16 +1,15 @@
package original
import (
"context"
"crypto/cipher"
"encoding/binary"
"hash/fnv"
"io"
"net"
sync "sync"
"time"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/transport/internet/finalmask"
)
type simple struct{}
@@ -75,151 +74,77 @@ func (a *simple) Open(dst, nonce, cipherText, extra []byte) ([]byte, error) {
}
type simpleConn struct {
first bool
leaveSize int32
conn net.PacketConn
net.PacketConn
aead cipher.AEAD
readBuf []byte
readMutex sync.Mutex
writeBuf []byte
writeMutex sync.Mutex
}
func NewConnClient(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
func NewConnClient(c *Config, raw net.PacketConn) (net.PacketConn, error) {
conn := &simpleConn{
first: first,
leaveSize: leaveSize,
conn: raw,
aead: &simple{},
}
if first {
conn.readBuf = make([]byte, 8192)
conn.writeBuf = make([]byte, 8192)
PacketConn: raw,
aead: &simple{},
}
return conn, nil
}
func NewConnServer(c *Config, raw net.PacketConn, first bool, leaveSize int32) (net.PacketConn, error) {
return NewConnClient(c, raw, first, leaveSize)
}
func (c *simpleConn) Size() int32 {
return int32(c.aead.NonceSize()) + int32(c.aead.Overhead())
func NewConnServer(c *Config, raw net.PacketConn) (net.PacketConn, error) {
return NewConnClient(c, raw)
}
func (c *simpleConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
if c.first {
c.readMutex.Lock()
n, addr, err = c.conn.ReadFrom(c.readBuf)
if err != nil {
c.readMutex.Unlock()
return n, addr, err
}
if n < int(c.Size()) {
c.readMutex.Unlock()
return 0, addr, errors.New("aead").Base(io.ErrShortBuffer)
}
if len(p) < n-int(c.Size()) {
c.readMutex.Unlock()
return 0, addr, errors.New("aead").Base(io.ErrShortBuffer)
}
ciphertext := c.readBuf[:n]
opened, err := c.aead.Open(nil, nil, ciphertext, nil)
if err != nil {
c.readMutex.Unlock()
return 0, addr, errors.New("aead open").Base(err)
}
copy(p, opened)
c.readMutex.Unlock()
return n - int(c.Size()), addr, nil
buf := p
if len(p) < finalmask.UDPSize {
buf = make([]byte, finalmask.UDPSize)
}
n, addr, err = c.conn.ReadFrom(p)
if err != nil {
n, addr, err = c.PacketConn.ReadFrom(buf)
if err != nil || n == 0 {
return n, addr, err
}
if n < int(c.Size()) {
return 0, addr, errors.New("aead").Base(io.ErrShortBuffer)
if n < c.aead.Overhead() {
errors.LogDebug(context.Background(), addr, " mask read err aead short lenth ", n)
return 0, addr, nil
}
ciphertext := p[:n]
ciphertext := buf[:n]
opened, err := c.aead.Open(nil, nil, ciphertext, nil)
if err != nil {
c.readMutex.Unlock()
return 0, addr, errors.New("aead open").Base(err)
errors.LogDebug(context.Background(), addr, " mask read err aead open ", err)
return 0, addr, nil
}
if len(opened) > len(p) {
errors.LogDebug(context.Background(), addr, " mask read err short buffer ", len(p), " ", len(opened))
return 0, addr, nil
}
copy(p, opened)
return n - int(c.Size()), addr, nil
return n - c.aead.Overhead(), addr, nil
}
func (c *simpleConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
if c.first {
if c.leaveSize+c.Size()+int32(len(p)) > 8192 {
return 0, errors.New("too many masks")
}
c.writeMutex.Lock()
n = copy(c.writeBuf[c.leaveSize+c.Size():], p)
n += int(c.leaveSize) + int(c.Size())
plaintext := c.writeBuf[c.leaveSize+c.Size() : n]
sealed := c.aead.Seal(nil, nil, plaintext, nil)
copy(c.writeBuf[c.leaveSize:], sealed)
nn, err := c.conn.WriteTo(c.writeBuf[:n], addr)
if err != nil {
c.writeMutex.Unlock()
return 0, err
}
if nn != n {
c.writeMutex.Unlock()
return 0, errors.New("nn != n")
}
c.writeMutex.Unlock()
return len(p), nil
if c.aead.Overhead()+len(p) > finalmask.UDPSize {
errors.LogDebug(context.Background(), addr, " mask write err short write ", c.aead.Overhead()+len(p), " ", finalmask.UDPSize)
return 0, nil
}
plaintext := p[c.leaveSize+c.Size():]
sealed := c.aead.Seal(nil, nil, plaintext, nil)
copy(p[c.leaveSize:], sealed)
var buf []byte
if cap(p) != finalmask.UDPSize {
buf = make([]byte, finalmask.UDPSize)
} else {
buf = p[:c.aead.Overhead()+len(p)]
copy(buf[c.aead.Overhead():], p)
p = buf[c.aead.Overhead() : c.aead.Overhead()+len(p)]
}
return c.conn.WriteTo(p, addr)
}
_ = c.aead.Seal(buf[:0], nil, p, nil)
func (c *simpleConn) Close() error {
return c.conn.Close()
}
_, err = c.PacketConn.WriteTo(buf[:c.aead.Overhead()+len(p)], addr)
if err != nil {
return 0, err
}
func (c *simpleConn) LocalAddr() net.Addr {
return c.conn.LocalAddr()
}
func (c *simpleConn) SetDeadline(t time.Time) error {
return c.conn.SetDeadline(t)
}
func (c *simpleConn) SetReadDeadline(t time.Time) error {
return c.conn.SetReadDeadline(t)
}
func (c *simpleConn) SetWriteDeadline(t time.Time) error {
return c.conn.SetWriteDeadline(t)
return len(p), nil
}
@@ -8,6 +8,22 @@ import (
"github.com/xtls/xray-core/transport/internet/finalmask/mkcp/original"
)
func TestSimpleSealInPlace(t *testing.T) {
aead := original.NewSimple()
text := []byte("0123456789012")
buf := make([]byte, 8192)
copy(buf[aead.Overhead():], text)
plaintext := buf[aead.Overhead() : aead.Overhead()+len(text)]
sealed := aead.Seal(nil, nil, plaintext, nil)
_ = aead.Seal(buf[:0], nil, plaintext, nil)
assert.Equal(t, sealed, buf[:aead.Overhead()+len(text)])
}
func TestOriginalBounce(t *testing.T) {
aead := original.NewSimple()
buf := make([]byte, aead.NonceSize()+aead.Overhead())