0
0
mirror of https://github.com/XTLS/Xray-core.git synced 2025-08-29 18:05:31 +00:00

Merge branch 'XTLS:main' into target

This commit is contained in:
patterniha 2025-08-15 20:09:28 +02:00 committed by GitHub
commit b19469ffaf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 103 additions and 129 deletions

View File

@ -65,7 +65,7 @@ jobs:
echo "LATEST=$LATEST" >>${GITHUB_ENV}
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Set up QEMU
uses: docker/setup-qemu-action@v3

View File

@ -63,7 +63,7 @@ jobs:
CGO_ENABLED: 0
steps:
- name: Checkout codebase
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Show workflow information
run: |

View File

@ -153,7 +153,7 @@ jobs:
CGO_ENABLED: 0
steps:
- name: Checkout codebase
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Set up NDK
if: matrix.goos == 'android'

View File

@ -45,7 +45,7 @@ jobs:
os: [windows-latest, ubuntu-latest, macos-latest]
steps:
- name: Checkout codebase
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Set up Go
uses: actions/setup-go@v5
with:

View File

@ -18,31 +18,31 @@ func Test_parseResponse(t *testing.T) {
ans := new(dns.Msg)
ans.Id = 0
p = append(p, common.Must2(ans.Pack()).([]byte))
p = append(p, common.Must2(ans.Pack()))
p = append(p, []byte{})
ans = new(dns.Msg)
ans.Id = 1
ans.Answer = append(ans.Answer,
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")).(dns.RR),
common.Must2(dns.NewRR("google.com. IN CNAME fake.google.com")).(dns.RR),
common.Must2(dns.NewRR("google.com. IN A 8.8.8.8")).(dns.RR),
common.Must2(dns.NewRR("google.com. IN A 8.8.4.4")).(dns.RR),
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")),
common.Must2(dns.NewRR("google.com. IN CNAME fake.google.com")),
common.Must2(dns.NewRR("google.com. IN A 8.8.8.8")),
common.Must2(dns.NewRR("google.com. IN A 8.8.4.4")),
)
p = append(p, common.Must2(ans.Pack()).([]byte))
p = append(p, common.Must2(ans.Pack()))
ans = new(dns.Msg)
ans.Id = 2
ans.Answer = append(ans.Answer,
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")).(dns.RR),
common.Must2(dns.NewRR("google.com. IN CNAME fake.google.com")).(dns.RR),
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")).(dns.RR),
common.Must2(dns.NewRR("google.com. IN CNAME test.google.com")).(dns.RR),
common.Must2(dns.NewRR("google.com. IN AAAA 2001::123:8888")).(dns.RR),
common.Must2(dns.NewRR("google.com. IN AAAA 2001::123:8844")).(dns.RR),
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")),
common.Must2(dns.NewRR("google.com. IN CNAME fake.google.com")),
common.Must2(dns.NewRR("google.com. IN CNAME m.test.google.com")),
common.Must2(dns.NewRR("google.com. IN CNAME test.google.com")),
common.Must2(dns.NewRR("google.com. IN AAAA 2001::123:8888")),
common.Must2(dns.NewRR("google.com. IN AAAA 2001::123:8844")),
)
p = append(p, common.Must2(ans.Pack()).([]byte))
p = append(p, common.Must2(ans.Pack()))
tests := []struct {
name string

View File

@ -13,6 +13,8 @@ const (
Size = 8192
)
var ErrBufferFull = errors.New("buffer is full")
var zero = [Size * 10]byte{0}
var pool = bytespool.GetPool(Size)
@ -244,6 +246,14 @@ func (b *Buffer) Cap() int32 {
return int32(len(b.v))
}
// Available returns the available capacity of the buffer content.
func (b *Buffer) Available() int32 {
if b == nil {
return 0
}
return int32(len(b.v)) - b.end
}
// IsEmpty returns true if the buffer is empty.
func (b *Buffer) IsEmpty() bool {
return b.Len() == 0
@ -258,13 +268,16 @@ func (b *Buffer) IsFull() bool {
func (b *Buffer) Write(data []byte) (int, error) {
nBytes := copy(b.v[b.end:], data)
b.end += int32(nBytes)
if nBytes < len(data) {
return nBytes, ErrBufferFull
}
return nBytes, nil
}
// WriteByte writes a single byte into the buffer.
func (b *Buffer) WriteByte(v byte) error {
if b.IsFull() {
return errors.New("buffer full")
return ErrBufferFull
}
b.v[b.end] = v
b.end++

View File

@ -144,7 +144,7 @@ func Compact(mb MultiBuffer) MultiBuffer {
for i := 1; i < len(mb); i++ {
curr := mb[i]
if last.Len()+curr.Len() > Size {
if curr.Len() > last.Available() {
mb2 = append(mb2, last)
last = curr
} else {

View File

@ -175,6 +175,29 @@ func TestCompact(t *testing.T) {
}
}
func TestCompactWithConsumed(t *testing.T) {
// make a consumed buffer (a.Start != 0)
a := New()
for range 8192 {
common.Must2(a.WriteString("a"))
}
a.Read(make([]byte, 2))
b := New()
for range 2 {
common.Must2(b.WriteString("b"))
}
mb := MultiBuffer{a, b}
cmb := Compact(mb)
mbc := &MultiBufferContainer{mb}
mbc.Read(make([]byte, 8190))
if w := cmb.String(); w != "bb" {
t.Error("unexpected Compact result ", w)
}
}
func BenchmarkSplitBytes(b *testing.B) {
var mb MultiBuffer
raw := make([]byte, Size)

View File

@ -23,7 +23,9 @@ func Must(err error) {
}
// Must2 panics if the second parameter is not nil, otherwise returns the first parameter.
func Must2(v interface{}, err error) interface{} {
// This is useful when function returned "sth, err" and avoid many "if err != nil"
// Internal usage only, if user input can cause err, it must be handled
func Must2[T any](v T, err error) T {
Must(err)
return v
}

View File

@ -32,9 +32,7 @@ func NewAesCTRStream(key []byte, iv []byte) cipher.Stream {
// NewAesGcm creates a AEAD cipher based on AES-GCM.
func NewAesGcm(key []byte) cipher.AEAD {
block, err := aes.NewCipher(key)
common.Must(err)
aead, err := cipher.NewGCM(block)
common.Must(err)
block := common.Must2(aes.NewCipher(key))
aead := common.Must2(cipher.NewGCM(block))
return aead
}

View File

@ -2,8 +2,6 @@ package crypto_test
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"io"
"testing"
@ -18,11 +16,8 @@ import (
func TestAuthenticationReaderWriter(t *testing.T) {
key := make([]byte, 16)
rand.Read(key)
block, err := aes.NewCipher(key)
common.Must(err)
aead, err := cipher.NewGCM(block)
common.Must(err)
aead := NewAesGcm(key)
const payloadSize = 1024 * 80
rawPayload := make([]byte, payloadSize)
@ -71,7 +66,7 @@ func TestAuthenticationReaderWriter(t *testing.T) {
t.Error(r)
}
_, err = reader.ReadMultiBuffer()
_, err := reader.ReadMultiBuffer()
if err != io.EOF {
t.Error("error: ", err)
}
@ -80,11 +75,8 @@ func TestAuthenticationReaderWriter(t *testing.T) {
func TestAuthenticationReaderWriterPacket(t *testing.T) {
key := make([]byte, 16)
common.Must2(rand.Read(key))
block, err := aes.NewCipher(key)
common.Must(err)
aead, err := cipher.NewGCM(block)
common.Must(err)
aead := NewAesGcm(key)
cache := buf.New()
iv := make([]byte, 12)

2
go.mod
View File

@ -1,6 +1,6 @@
module github.com/xtls/xray-core
go 1.24
go 1.25
require (
github.com/cloudflare/circl v1.6.1

View File

@ -6,9 +6,7 @@ import (
"encoding/base64"
"fmt"
"net"
"reflect"
"strconv"
"unsafe"
"github.com/xtls/xray-core/main/commands/base"
. "github.com/xtls/xray-core/transport/internet/tls"
@ -139,14 +137,15 @@ func printCertificates(certs []*x509.Certificate) {
}
func printTLSConnDetail(tlsConn *gotls.Conn) {
connectionState := tlsConn.ConnectionState()
var tlsVersion string
if tlsConn.ConnectionState().Version == gotls.VersionTLS13 {
if connectionState.Version == gotls.VersionTLS13 {
tlsVersion = "TLS 1.3"
} else if tlsConn.ConnectionState().Version == gotls.VersionTLS12 {
} else if connectionState.Version == gotls.VersionTLS12 {
tlsVersion = "TLS 1.2"
}
fmt.Println("TLS Version: ", tlsVersion)
curveID := *(*gotls.CurveID)(unsafe.Pointer(reflect.ValueOf(tlsConn).Elem().FieldByName("curveID").UnsafeAddr()))
curveID := connectionState.CurveID
if curveID != 0 {
PostQuantum := (curveID == gotls.X25519MLKEM768)
fmt.Println("TLS Post-Quantum key exchange: ", PostQuantum, "("+curveID.String()+")")

View File

@ -91,7 +91,7 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn st
}
}
if dest.Port == 0 {
dest.Port = net.Port(common.Must2(strconv.Atoi(port)).(int))
dest.Port = net.Port(common.Must2(strconv.Atoi(port)))
}
if d.portMap != nil && d.portMap[port] != "" {
h, p, _ := net.SplitHostPort(d.portMap[port])
@ -99,7 +99,7 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn st
dest.Address = net.ParseAddress(h)
}
if len(p) > 0 {
dest.Port = net.Port(common.Must2(strconv.Atoi(p)).(int))
dest.Port = net.Port(common.Must2(strconv.Atoi(p)))
}
}
}

View File

@ -2,7 +2,6 @@ package shadowsocks
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/md5"
"crypto/sha1"
@ -58,11 +57,7 @@ func (a *MemoryAccount) CheckIV(iv []byte) error {
}
func createAesGcm(key []byte) cipher.AEAD {
block, err := aes.NewCipher(key)
common.Must(err)
gcm, err := cipher.NewGCM(block)
common.Must(err)
return gcm
return crypto.NewAesGcm(key)
}
func createChaCha20Poly1305(key []byte) cipher.AEAD {

View File

@ -2,14 +2,13 @@ package aead
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/binary"
"io"
"time"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/crypto"
)
func SealVMessAEADHeader(key [16]byte, data []byte) []byte {
@ -34,15 +33,7 @@ func SealVMessAEADHeader(key [16]byte, data []byte) []byte {
payloadHeaderLengthAEADNonce := KDF(key[:], KDFSaltConstVMessHeaderPayloadLengthAEADIV, string(generatedAuthID[:]), string(connectionNonce))[:12]
payloadHeaderLengthAEADAESBlock, err := aes.NewCipher(payloadHeaderLengthAEADKey)
if err != nil {
panic(err.Error())
}
payloadHeaderAEAD, err := cipher.NewGCM(payloadHeaderLengthAEADAESBlock)
if err != nil {
panic(err.Error())
}
payloadHeaderAEAD := crypto.NewAesGcm(payloadHeaderLengthAEADKey)
payloadHeaderLengthAEADEncrypted = payloadHeaderAEAD.Seal(nil, payloadHeaderLengthAEADNonce, aeadPayloadLengthSerializedByte, generatedAuthID[:])
}
@ -54,15 +45,7 @@ func SealVMessAEADHeader(key [16]byte, data []byte) []byte {
payloadHeaderAEADNonce := KDF(key[:], KDFSaltConstVMessHeaderPayloadAEADIV, string(generatedAuthID[:]), string(connectionNonce))[:12]
payloadHeaderAEADAESBlock, err := aes.NewCipher(payloadHeaderAEADKey)
if err != nil {
panic(err.Error())
}
payloadHeaderAEAD, err := cipher.NewGCM(payloadHeaderAEADAESBlock)
if err != nil {
panic(err.Error())
}
payloadHeaderAEAD := crypto.NewAesGcm(payloadHeaderAEADKey)
payloadHeaderAEADEncrypted = payloadHeaderAEAD.Seal(nil, payloadHeaderAEADNonce, data, generatedAuthID[:])
}
@ -104,15 +87,7 @@ func OpenVMessAEADHeader(key [16]byte, authid [16]byte, data io.Reader) ([]byte,
payloadHeaderLengthAEADNonce := KDF(key[:], KDFSaltConstVMessHeaderPayloadLengthAEADIV, string(authid[:]), string(nonce[:]))[:12]
payloadHeaderAEADAESBlock, err := aes.NewCipher(payloadHeaderLengthAEADKey)
if err != nil {
panic(err.Error())
}
payloadHeaderLengthAEAD, err := cipher.NewGCM(payloadHeaderAEADAESBlock)
if err != nil {
panic(err.Error())
}
payloadHeaderLengthAEAD := crypto.NewAesGcm(payloadHeaderLengthAEADKey)
decryptedAEADHeaderLengthPayload, erropenAEAD := payloadHeaderLengthAEAD.Open(nil, payloadHeaderLengthAEADNonce, payloadHeaderLengthAEADEncrypted[:], authid[:])
@ -145,15 +120,7 @@ func OpenVMessAEADHeader(key [16]byte, authid [16]byte, data io.Reader) ([]byte,
return nil, false, bytesRead, err
}
payloadHeaderAEADAESBlock, err := aes.NewCipher(payloadHeaderAEADKey)
if err != nil {
panic(err.Error())
}
payloadHeaderAEAD, err := cipher.NewGCM(payloadHeaderAEADAESBlock)
if err != nil {
panic(err.Error())
}
payloadHeaderAEAD := crypto.NewAesGcm(payloadHeaderAEADKey)
decryptedAEADHeaderPayload, erropenAEAD := payloadHeaderAEAD.Open(nil, payloadHeaderAEADNonce, payloadHeaderAEADEncrypted, authid[:])

View File

@ -3,8 +3,6 @@ package encoding
import (
"bytes"
"context"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha256"
"encoding/binary"
@ -182,8 +180,7 @@ func (c *ClientSession) DecodeResponseHeader(reader io.Reader) (*protocol.Respon
aeadResponseHeaderLengthEncryptionKey := vmessaead.KDF16(c.responseBodyKey[:], vmessaead.KDFSaltConstAEADRespHeaderLenKey)
aeadResponseHeaderLengthEncryptionIV := vmessaead.KDF(c.responseBodyIV[:], vmessaead.KDFSaltConstAEADRespHeaderLenIV)[:12]
aeadResponseHeaderLengthEncryptionKeyAESBlock := common.Must2(aes.NewCipher(aeadResponseHeaderLengthEncryptionKey)).(cipher.Block)
aeadResponseHeaderLengthEncryptionAEAD := common.Must2(cipher.NewGCM(aeadResponseHeaderLengthEncryptionKeyAESBlock)).(cipher.AEAD)
aeadResponseHeaderLengthEncryptionAEAD := crypto.NewAesGcm(aeadResponseHeaderLengthEncryptionKey)
var aeadEncryptedResponseHeaderLength [18]byte
var decryptedResponseHeaderLength int
@ -205,8 +202,7 @@ func (c *ClientSession) DecodeResponseHeader(reader io.Reader) (*protocol.Respon
aeadResponseHeaderPayloadEncryptionKey := vmessaead.KDF16(c.responseBodyKey[:], vmessaead.KDFSaltConstAEADRespHeaderPayloadKey)
aeadResponseHeaderPayloadEncryptionIV := vmessaead.KDF(c.responseBodyIV[:], vmessaead.KDFSaltConstAEADRespHeaderPayloadIV)[:12]
aeadResponseHeaderPayloadEncryptionKeyAESBlock := common.Must2(aes.NewCipher(aeadResponseHeaderPayloadEncryptionKey)).(cipher.Block)
aeadResponseHeaderPayloadEncryptionAEAD := common.Must2(cipher.NewGCM(aeadResponseHeaderPayloadEncryptionKeyAESBlock)).(cipher.AEAD)
aeadResponseHeaderPayloadEncryptionAEAD := crypto.NewAesGcm(aeadResponseHeaderPayloadEncryptionKey)
encryptedResponseHeaderBuffer := make([]byte, decryptedResponseHeaderLength+16)

View File

@ -2,8 +2,6 @@ package encoding
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/sha256"
"encoding/binary"
"hash/fnv"
@ -350,8 +348,7 @@ func (s *ServerSession) EncodeResponseHeader(header *protocol.ResponseHeader, wr
aeadResponseHeaderLengthEncryptionKey := vmessaead.KDF16(s.responseBodyKey[:], vmessaead.KDFSaltConstAEADRespHeaderLenKey)
aeadResponseHeaderLengthEncryptionIV := vmessaead.KDF(s.responseBodyIV[:], vmessaead.KDFSaltConstAEADRespHeaderLenIV)[:12]
aeadResponseHeaderLengthEncryptionKeyAESBlock := common.Must2(aes.NewCipher(aeadResponseHeaderLengthEncryptionKey)).(cipher.Block)
aeadResponseHeaderLengthEncryptionAEAD := common.Must2(cipher.NewGCM(aeadResponseHeaderLengthEncryptionKeyAESBlock)).(cipher.AEAD)
aeadResponseHeaderLengthEncryptionAEAD := crypto.NewAesGcm(aeadResponseHeaderLengthEncryptionKey)
aeadResponseHeaderLengthEncryptionBuffer := bytes.NewBuffer(nil)
@ -365,8 +362,7 @@ func (s *ServerSession) EncodeResponseHeader(header *protocol.ResponseHeader, wr
aeadResponseHeaderPayloadEncryptionKey := vmessaead.KDF16(s.responseBodyKey[:], vmessaead.KDFSaltConstAEADRespHeaderPayloadKey)
aeadResponseHeaderPayloadEncryptionIV := vmessaead.KDF(s.responseBodyIV[:], vmessaead.KDFSaltConstAEADRespHeaderPayloadIV)[:12]
aeadResponseHeaderPayloadEncryptionKeyAESBlock := common.Must2(aes.NewCipher(aeadResponseHeaderPayloadEncryptionKey)).(cipher.Block)
aeadResponseHeaderPayloadEncryptionAEAD := common.Must2(cipher.NewGCM(aeadResponseHeaderPayloadEncryptionKeyAESBlock)).(cipher.AEAD)
aeadResponseHeaderPayloadEncryptionAEAD := crypto.NewAesGcm(aeadResponseHeaderPayloadEncryptionKey)
aeadEncryptedHeaderPayload := aeadResponseHeaderPayloadEncryptionAEAD.Seal(nil, aeadResponseHeaderPayloadEncryptionIV, aeadEncryptedHeaderBuffer.Bytes(), nil)
common.Must2(io.Copy(writer, bytes.NewReader(aeadEncryptedHeaderPayload)))

View File

@ -1,15 +1,13 @@
package kcp
import (
"crypto/aes"
"crypto/cipher"
"crypto/sha256"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/crypto"
)
func NewAEADAESGCMBasedOnSeed(seed string) cipher.AEAD {
hashedSeed := sha256.Sum256([]byte(seed))
aesBlock := common.Must2(aes.NewCipher(hashedSeed[:16])).(cipher.Block)
return common.Must2(cipher.NewGCM(aesBlock)).(cipher.AEAD)
return crypto.NewAesGcm(hashedSeed[:])
}

View File

@ -3,8 +3,6 @@ package reality
import (
"bytes"
"context"
"crypto/aes"
"crypto/cipher"
"crypto/ecdh"
"crypto/ed25519"
"crypto/hmac"
@ -169,8 +167,7 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati
if _, err := hkdf.New(sha256.New, uConn.AuthKey, hello.Random[:20], []byte("REALITY")).Read(uConn.AuthKey); err != nil {
return nil, err
}
block, _ := aes.NewCipher(uConn.AuthKey)
aead, _ := cipher.NewGCM(block)
aead := crypto.NewAesGcm(uConn.AuthKey)
if config.Show {
fmt.Printf("REALITY localAddr: %v\tuConn.AuthKey[:16]: %v\tAEAD: %T\n", localAddr, uConn.AuthKey[:16], aead)
}

View File

@ -297,7 +297,7 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
if transportConfiguration.DownloadSettings != nil {
globalDialerAccess.Lock()
if streamSettings.DownloadSettings == nil {
streamSettings.DownloadSettings = common.Must2(internet.ToMemoryStreamConfig(transportConfiguration.DownloadSettings)).(*internet.MemoryStreamConfig)
streamSettings.DownloadSettings = common.Must2(internet.ToMemoryStreamConfig(transportConfiguration.DownloadSettings))
if streamSettings.SocketSettings != nil && streamSettings.SocketSettings.Penetrate {
streamSettings.DownloadSettings.SocketSettings = streamSettings.SocketSettings
}
@ -489,15 +489,16 @@ func (w uploadWriter) Write(b []byte) (int, error) {
}
*/
buffer := buf.New()
n, err := buffer.Write(b)
if err != nil {
return 0, err
}
buffer := buf.MultiBufferContainer{}
common.Must2(buffer.Write(b))
err = w.WriteMultiBuffer([]*buf.Buffer{buffer})
if err != nil {
return 0, err
var writed int
for _, buff := range buffer.MultiBuffer {
err := w.WriteMultiBuffer(buf.MultiBuffer{buff})
if err != nil {
return writed, err
}
writed += int(buff.Len())
}
return n, nil
return writed, nil
}

View File

@ -1,6 +1,7 @@
package splithttp_test
import (
"bytes"
"context"
"crypto/rand"
"fmt"
@ -421,18 +422,12 @@ func Test_maxUpload(t *testing.T) {
},
}
var uploadSize int
uploadReceived := make([]byte, 10001)
listen, err := ListenXH(context.Background(), net.LocalHostIP, listenPort, streamSettings, func(conn stat.Connection) {
go func(c stat.Connection) {
defer c.Close()
var b [10240]byte
c.SetReadDeadline(time.Now().Add(2 * time.Second))
n, err := c.Read(b[:])
if err != nil {
return
}
uploadSize = n
io.ReadFull(c, uploadReceived)
common.Must2(c.Write([]byte("Response")))
}(conn)
@ -441,10 +436,12 @@ func Test_maxUpload(t *testing.T) {
ctx := context.Background()
conn, err := Dial(ctx, net.TCPDestination(net.DomainAddress("localhost"), listenPort), streamSettings)
common.Must(err)
// send a slightly too large upload
var upload [10001]byte
_, err = conn.Write(upload[:])
upload := make([]byte, 10001)
rand.Read(upload)
_, err = conn.Write(upload)
common.Must(err)
var b [10240]byte
@ -455,8 +452,8 @@ func Test_maxUpload(t *testing.T) {
}
common.Must(conn.Close())
if uploadSize > 10000 || uploadSize == 0 {
t.Error("incorrect upload size: ", uploadSize)
if !bytes.Equal(upload, uploadReceived) {
t.Error("incorrect upload", upload, uploadReceived)
}
common.Must(listen.Close())