diff --git a/docs/config.yaml b/docs/config.yaml index 7a41f00c..d5b028e0 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -642,11 +642,11 @@ proxies: # socks5 # (native/xorpub 的 XTLS Vision 可以 Splice。只使用 1-RTT 模式 / 若服务端发的 ticket 中秒数不为零则 0-RTT 复用) # / 是只能选一个,后面 base64 至少一个,无限串联,使用 mihomo generate vless-x25519 和 mihomo generate vless-mlkem768 生成,替换值时需去掉括号 # - # Padding 是可选的参数,仅作用于 1-RTT 以消除握手的长度特征,双端默认值均为 "111-1111.111--66.3333--1234",它的含义是: - # 在 1-RTT client/server hello 后粘上随机 111 到 1111 字节的 padding - # 等待随机 111 到负 66 毫秒,若随机到了负值则不等待 - # 再次发送随机 3333 到负 1234 字节的 padding,若随机到了负值则不发送 - # 服务端、客户端可以设置不同的 padding 参数,正数写在左边,按 len、gap 的顺序无限串联,第一个 padding 需大于 16 字节 + # Padding 是可选的参数,仅作用于 1-RTT 以消除握手的长度特征,双端默认值均为 "100-111-1111.75-0-111.50-0-3333": + # 在 1-RTT client/server hello 后以 100% 的概率粘上随机 111 到 1111 字节的 padding + # 以 75% 的概率等待随机 0 到 111 毫秒("probability-from-to") + # 再次以 50% 的概率发送随机 0 到 3333 字节的 padding(若为 0 则不 Write()) + # 服务端、客户端可以设置不同的 padding 参数,按 len、gap 的顺序无限串联,第一个 padding 需概率 100%、至少 35 字节 # ------------------------- encryption: "mlkem768x25519plus.native/xorpub/random.1rtt/0rtt.(padding len).(padding gap).(X25519 Password).(ML-KEM-768 Client)..." tls: false #可以不开启tls @@ -1373,11 +1373,11 @@ listeners: # (原生外观 / 只 XOR 公钥 / 全随机数。只允许 1-RTT 模式 / 同时允许 1-RTT 模式与 600 秒复用的 0-RTT 模式) # / 是只能选一个,后面 base64 至少一个,无限串联,使用 mihomo generate vless-x25519 和 mihomo generate vless-mlkem768 生成,替换值时需去掉括号 # - # Padding 是可选的参数,仅作用于 1-RTT 以消除握手的长度特征,双端默认值均为 "111-1111.111--66.3333--1234",它的含义是: - # 在 1-RTT client/server hello 后粘上随机 111 到 1111 字节的 padding - # 等待随机 111 到负 66 毫秒,若随机到了负值则不等待 - # 再次发送随机 3333 到负 1234 字节的 padding,若随机到了负值则不发送 - # 服务端、客户端可以设置不同的 padding 参数,正数写在左边,按 len、gap 的顺序无限串联,第一个 padding 需大于 16 字节 + # Padding 是可选的参数,仅作用于 1-RTT 以消除握手的长度特征,双端默认值均为 "100-111-1111.75-0-111.50-0-3333": + # 在 1-RTT client/server hello 后以 100% 的概率粘上随机 111 到 1111 字节的 padding + # 以 75% 的概率等待随机 0 到 111 毫秒("probability-from-to") + # 再次以 50% 的概率发送随机 0 到 3333 字节的 padding(若为 0 则不 Write()) + # 服务端、客户端可以设置不同的 padding 参数,按 len、gap 的顺序无限串联,第一个 padding 需概率 100%、至少 35 字节 # ------------------------- # decryption: "mlkem768x25519plus.native/xorpub/random.1rtt/600s.(padding len).(padding gap).(X25519 PrivateKey).(ML-KEM-768 Seed)..." # 下面两项如果填写则开启 tls(需要同时填写) diff --git a/listener/inbound/vless_test.go b/listener/inbound/vless_test.go index e7dabee4..b465565f 100644 --- a/listener/inbound/vless_test.go +++ b/listener/inbound/vless_test.go @@ -104,9 +104,9 @@ func TestInboundVless_Encryption(t *testing.T) { data string }{ {"unconfigured-padding", ""}, - {"default-padding", "111-1111.111--66.3333--1234."}, - {"old-padding", "100-1000."}, // Xray-core v25.8.29 - {"custom-padding", "7890-1234.1111--999.6666--3333.777--777."}, + {"default-padding", "100-111-1111.75-0-111.50-0-3333."}, + {"old-padding", "100-100-1000."}, // Xray-core v25.8.29 + {"custom-padding", "100-1234-7890.33-0-1111.66-0-6666.55-111-777."}, } var modes = []string{ "native", diff --git a/transport/vless/encryption/client.go b/transport/vless/encryption/client.go index c7f4e256..9c029ed7 100644 --- a/transport/vless/encryption/client.go +++ b/transport/vless/encryption/client.go @@ -33,8 +33,8 @@ type ClientInstance struct { RelaysLength int XorMode uint32 Seconds uint32 - PaddingLens [][2]int - PaddingGaps [][2]int + PaddingLens [][3]int + PaddingGaps [][3]int RWLock sync.RWMutex Expire time.Time diff --git a/transport/vless/encryption/common.go b/transport/vless/encryption/common.go index e74af737..8a71f719 100644 --- a/transport/vless/encryption/common.go +++ b/transport/vless/encryption/common.go @@ -217,50 +217,61 @@ func DecodeHeader(h []byte) (l int, err error) { return } -func ParsePadding(padding string, paddingLens, paddingGaps *[][2]int) (err error) { +func ParsePadding(padding string, paddingLens, paddingGaps *[][3]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] == "" { + x := strings.Split(s, "-") + if len(x) < 3 || x[0] == "" || x[1] == "" || x[2] == "" { return errors.New("invalid padding lenth/gap parameter: " + s) } - y := [2]int{} + y := [3]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 y[2], err = strconv.Atoi(x[2]); err != nil { + return + } + if i == 0 && (y[0] < 100 || y[1] < 18+17 || y[2] < 18+17) { + return errors.New("first padding length must not be smaller than 35") } if i%2 == 0 { *paddingLens = append(*paddingLens, y) - maxLen += max(y[0], y[1]) + maxLen += max(y[1], y[2]) } else { *paddingGaps = append(*paddingGaps, y) } } - if maxLen > 65535 { - return errors.New("total padding length must be smaller than 65536") + if maxLen > 18+65535 { + return errors.New("total padding length must not be larger than 65553") } return } -func CreatPadding(paddingLens, paddingGaps [][2]int) (length int, lens []int, gaps []time.Duration) { +func CreatPadding(paddingLens, paddingGaps [][3]int) (length int, lens []int, gaps []time.Duration) { if len(paddingLens) == 0 { - paddingLens = [][2]int{{111, 1111}, {3333, -1234}} - paddingGaps = [][2]int{{111, -66}} + paddingLens = [][3]int{{100, 111, 1111}, {50, 0, 3333}} + paddingGaps = [][3]int{{75, 0, 111}} } - for _, l := range paddingLens { - lens = append(lens, int(max(0, randBetween(int64(l[0]), int64(l[1]))))) - length += lens[len(lens)-1] + for _, y := range paddingLens { + l := 0 + if y[0] >= int(randBetween(0, 100)) { + l = int(randBetween(int64(y[1]), int64(y[2]))) + } + lens = append(lens, l) + length += l } - for _, g := range paddingGaps { - gaps = append(gaps, time.Duration(max(0, randBetween(int64(g[0]), int64(g[1]))))*time.Millisecond) + for _, y := range paddingGaps { + g := 0 + if y[0] >= int(randBetween(0, 100)) { + g = int(randBetween(int64(y[1]), int64(y[2]))) + } + gaps = append(gaps, time.Duration(g)*time.Millisecond) } return } diff --git a/transport/vless/encryption/doc.go b/transport/vless/encryption/doc.go index c9a92c34..86bf80d0 100644 --- a/transport/vless/encryption/doc.go +++ b/transport/vless/encryption/doc.go @@ -23,4 +23,5 @@ // https://github.com/XTLS/Xray-core/commit/b0b220985c9c1bc832665458d5fd6e0c287b67ae // https://github.com/XTLS/Xray-core/commit/82ea7a3cc5ff23280b87e3052f0f83b04f0267fa // https://github.com/XTLS/Xray-core/commit/e8b02cd6649f14889841e8ab8ee6b2acca71dbe6 +// https://github.com/XTLS/Xray-core/commit/6768a22f676c9121cfc9dc4f51181a8a07837c8d package encryption diff --git a/transport/vless/encryption/server.go b/transport/vless/encryption/server.go index 05179aa8..8b4d6a4e 100644 --- a/transport/vless/encryption/server.go +++ b/transport/vless/encryption/server.go @@ -29,8 +29,8 @@ type ServerInstance struct { RelaysLength int XorMode uint32 Seconds uint32 - PaddingLens [][2]int - PaddingGaps [][2]int + PaddingLens [][3]int + PaddingGaps [][3]int RWLock sync.RWMutex Sessions map[[16]byte]*ServerSession