Compare commits

..
2 Commits
Author SHA1 Message Date
Fangliding b77a91a574 xudp 2026-11-06 00:24:43 +08:00
Fangliding 4c6093c8ae Fix vless UDP 443 block 2026-11-05 16:32:23 +08:00
22 changed files with 175 additions and 47 deletions
+2 -2
View File
@@ -3,12 +3,12 @@ package burst
import (
"context"
"fmt"
"math/rand/v2"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/features/routing"
)
@@ -181,7 +181,7 @@ func (h *HealthPing) doCheck(ctx context.Context, tags []string, duration time.D
for i := 0; i < rounds; i++ {
delay := time.Duration(0)
if duration > 0 {
delay = rand.N(duration)
delay = time.Duration(dice.RollInt63n(int64(duration)))
}
timers = append(timers, time.AfterFunc(delay, func() {
errors.LogDebug(h.ctx, "checking ", handler)
+3 -2
View File
@@ -7,7 +7,7 @@ import (
"io"
"math/big"
mrand "math/rand/v2"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/app/proxyman"
"github.com/xtls/xray-core/common"
@@ -196,7 +196,7 @@ func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
}
} else {
unchangedDomain := ob.Target.Address.Domain()
ob.Target.Address = net.IPAddress(ips[mrand.N(len(ips))])
ob.Target.Address = net.IPAddress(ips[dice.Roll(len(ips))])
errors.LogInfo(ctx, "target: ", unchangedDomain, " resolved to: ", ob.Target.Address.String())
}
}
@@ -217,6 +217,7 @@ func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
if ob.Target.Network == net.Network_UDP && ob.Target.Port == 443 {
switch h.udp443 {
case "reject":
proxy.DropUDP(ctx, link.Reader)
test(errors.New("XUDP rejected UDP/443 traffic"))
return
case "skip":
+3 -2
View File
@@ -3,11 +3,12 @@ package reverse
import (
"crypto/rand"
"io"
mrand "math/rand/v2"
"github.com/xtls/xray-core/common/dice"
)
func (c *Control) FillInRandom() {
randomLength := mrand.N(64)
randomLength := dice.Roll(64)
randomLength++
c.Random = make([]byte, randomLength)
io.ReadFull(rand.Reader, c.Random)
+2 -2
View File
@@ -3,13 +3,13 @@ package router
import (
"context"
"math"
"math/rand/v2"
"slices"
"sort"
"time"
"github.com/xtls/xray-core/app/observatory"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/extension"
@@ -74,7 +74,7 @@ func (s *LeastLoadStrategy) PickOutbound(candidates []string) string {
// goes to fallbackTag
return ""
}
return selects[rand.N(count)].Tag
return selects[dice.Roll(count)].Tag
}
func (s *LeastLoadStrategy) pickOutbounds(candidates []string) []*node {
+2 -2
View File
@@ -2,10 +2,10 @@ package router
import (
"context"
"math/rand/v2"
"github.com/xtls/xray-core/app/observatory"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/extension"
)
@@ -63,5 +63,5 @@ func (s *RandomStrategy) PickOutbound(candidates []string) string {
// goes to fallbackTag
return ""
}
return candidates[rand.N(count)]
return candidates[dice.Roll(count)]
}
+55
View File
@@ -0,0 +1,55 @@
// Package dice contains common functions to generate random number.
// It also initialize math/rand with the time in seconds at launch time.
package dice // import "github.com/xtls/xray-core/common/dice"
import (
"math/rand"
)
// Roll returns a non-negative number between 0 (inclusive) and n (exclusive).
func Roll(n int) int {
if n == 1 {
return 0
}
return rand.Intn(n)
}
// RollInt63n returns a non-negative number between 0 (inclusive) and n (exclusive).
func RollInt63n(n int64) int64 {
if n == 1 {
return 0
}
return rand.Int63n(n)
}
// Roll returns a non-negative number between 0 (inclusive) and n (exclusive).
func RollDeterministic(n int, seed int64) int {
if n == 1 {
return 0
}
return rand.New(rand.NewSource(seed)).Intn(n)
}
// RollUint16 returns a random uint16 value.
func RollUint16() uint16 {
return uint16(rand.Int63() >> 47)
}
func RollUint64() uint64 {
return rand.Uint64()
}
func NewDeterministicDice(seed int64) *DeterministicDice {
return &DeterministicDice{rand.New(rand.NewSource(seed))}
}
type DeterministicDice struct {
*rand.Rand
}
func (dd *DeterministicDice) Roll(n int) int {
if n == 1 {
return 0
}
return dd.Intn(n)
}
+50
View File
@@ -0,0 +1,50 @@
package dice_test
import (
"math/rand"
"testing"
. "github.com/xtls/xray-core/common/dice"
)
func BenchmarkRoll1(b *testing.B) {
for i := 0; i < b.N; i++ {
Roll(1)
}
}
func BenchmarkRoll20(b *testing.B) {
for i := 0; i < b.N; i++ {
Roll(20)
}
}
func BenchmarkIntn1(b *testing.B) {
for i := 0; i < b.N; i++ {
rand.Intn(1)
}
}
func BenchmarkIntn20(b *testing.B) {
for i := 0; i < b.N; i++ {
rand.Intn(20)
}
}
func BenchmarkInt63(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = uint16(rand.Int63() >> 47)
}
}
func BenchmarkInt31(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = uint16(rand.Int31() >> 15)
}
}
func BenchmarkIntn(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = uint16(rand.Intn(65536))
}
}
+5 -5
View File
@@ -2,8 +2,8 @@ package drain
import (
"io"
"math/rand/v2"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/errors"
)
@@ -12,10 +12,10 @@ type BehaviorSeedLimitedDrainer struct {
}
func NewBehaviorSeedLimitedDrainer(behaviorSeed int64, drainFoundation, maxBaseDrainSize, maxRandDrain int) (Drainer, error) {
behaviorRand := rand.New(rand.NewPCG(uint64(behaviorSeed), 0))
BaseDrainSize := behaviorRand.N(maxBaseDrainSize)
RandDrainMax := behaviorRand.N(maxRandDrain) + 1
RandDrainRolled := rand.N(RandDrainMax)
behaviorRand := dice.NewDeterministicDice(behaviorSeed)
BaseDrainSize := behaviorRand.Roll(maxBaseDrainSize)
RandDrainMax := behaviorRand.Roll(maxRandDrain) + 1
RandDrainRolled := dice.Roll(RandDrainMax)
DrainSize := drainFoundation + BaseDrainSize + RandDrainRolled
return &BehaviorSeedLimitedDrainer{DrainSize: DrainSize}, nil
}
+3 -2
View File
@@ -1,8 +1,9 @@
package protocol
import (
"math/rand/v2"
"time"
"github.com/xtls/xray-core/common/dice"
)
type Timestamp int64
@@ -15,7 +16,7 @@ func NowTime() Timestamp {
func NewTimestampGenerator(base Timestamp, delta int) TimestampGenerator {
return func() Timestamp {
rangeInDelta := rand.N(delta*2) - delta
rangeInDelta := dice.Roll(delta*2) - delta
return base + Timestamp(rangeInDelta)
}
}
+2 -9
View File
@@ -4,7 +4,6 @@ package blackhole
import (
"bytes"
"context"
"math/rand/v2"
"net/http"
"time"
@@ -13,7 +12,7 @@ import (
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/proxy"
"github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet"
)
@@ -69,14 +68,8 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
}
defer common.Interrupt(link.Writer)
defer common.Interrupt(link.Reader)
// wait to drain all the possible incoming UDP data
if ob.Target.Network == net.Network_UDP {
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, func() {
cancel()
}, time.Duration(30+rand.N(61))*time.Second)
go buf.Copy(link.Reader, buf.Discard, buf.UpdateActivity(timer))
<-ctx.Done()
proxy.DropUDP(ctx, link.Reader)
}
return nil
}
+24
View File
@@ -0,0 +1,24 @@
package proxy
import (
"context"
"math/rand/v2"
"time"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/signal"
)
// wait to drain all the possible incoming UDP data
// because re-established QUIC UDP may bypass the sniffer
func DropUDP(ctx context.Context, reader buf.Reader) {
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, func() {
cancel()
}, time.Duration(30+rand.N(60))*time.Second)
context.AfterFunc(ctx, func() {
common.Interrupt(reader)
})
buf.Copy(reader, buf.Discard, buf.UpdateActivity(timer))
}
+3 -3
View File
@@ -12,6 +12,7 @@ import (
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/crypto"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/geodata"
"github.com/xtls/xray-core/common/log"
@@ -29,7 +30,6 @@ import (
"github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/stat"
mrand "math/rand/v2"
)
var (
@@ -228,7 +228,7 @@ func (r *FinalRule) blockDuration() time.Duration {
if max < min {
span = min - max
}
return time.Duration(min+mrand.N(span+1)) * time.Second
return time.Duration(min+uint64(dice.Roll(int(span+1)))) * time.Second
}
func (r *FinalRule) log(ctx context.Context, msg ...interface{}) {
@@ -634,7 +634,7 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
continue
}
} else {
ip = net.IPAddress(ips[mrand.N(len(ips))])
ip = net.IPAddress(ips[dice.Roll(len(ips))])
shouldUseSystemResolver = false
}
}
+2 -2
View File
@@ -5,10 +5,10 @@ import (
"crypto/hmac"
"crypto/sha256"
"hash/crc64"
"math/rand/v2"
"strings"
"sync"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/protocol"
)
@@ -158,7 +158,7 @@ func (v *Validator) GetBehaviorSeed() uint64 {
v.behaviorFused = true
if v.behaviorSeed == 0 {
v.behaviorSeed = rand.Uint64()
v.behaviorSeed = dice.RollUint64()
}
return v.behaviorSeed
}
+1
View File
@@ -254,6 +254,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
switch request.Command {
case protocol.RequestCommandUDP:
if !allowUDP443 && request.Port == 443 {
proxy.DropUDP(ctx, link.Reader)
return errors.New("XTLS rejected UDP/443 traffic")
}
case protocol.RequestCommandMux:
+2 -2
View File
@@ -13,13 +13,13 @@ import (
"github.com/xtls/xray-core/common/bitmask"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/crypto"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/drain"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/proxy/vmess"
vmessaead "github.com/xtls/xray-core/proxy/vmess/aead"
"golang.org/x/crypto/chacha20poly1305"
mrand "math/rand/v2"
)
// ClientSession stores connection session info for VMess client.
@@ -72,7 +72,7 @@ func (c *ClientSession) EncodeRequestHeader(header *protocol.RequestHeader, writ
common.Must(buffer.WriteByte(c.responseHeader))
common.Must(buffer.WriteByte(byte(header.Option)))
paddingLen := mrand.N(16)
paddingLen := dice.Roll(16)
security := byte(paddingLen<<4) | byte(header.Security)
common.Must2(buffer.Write([]byte{security, byte(0), byte(header.Command)}))
+2 -2
View File
@@ -4,10 +4,10 @@ import (
"crypto/hmac"
"crypto/sha256"
"hash/crc64"
"math/rand/v2"
"strings"
"sync"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/proxy/vmess/aead"
@@ -117,7 +117,7 @@ func (v *TimedUserValidator) GetBehaviorSeed() uint64 {
v.behaviorFused = true
if v.behaviorSeed == 0 {
v.behaviorSeed = rand.Uint64()
v.behaviorSeed = dice.RollUint64()
}
return v.behaviorSeed
}
+2 -2
View File
@@ -3,7 +3,6 @@ package wireguard
import (
"context"
"fmt"
"math/rand/v2"
"net/netip"
"reflect"
"strings"
@@ -15,6 +14,7 @@ import (
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net"
@@ -364,7 +364,7 @@ func MakeResolveLocal(d dns.Client, streamSettings *internet.MemoryStreamConfig)
return nil, dns.ErrEmptyResponse
}
}
return got[rand.N(len(got))], nil
return got[dice.Roll(len(got))], nil
}
}
+2 -2
View File
@@ -3,10 +3,10 @@ package internet
import (
"context"
"fmt"
"math/rand/v2"
"strings"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net/cnc"
@@ -260,7 +260,7 @@ func DialSystem(ctx context.Context, dest net.Destination, sockopt *SocketConfig
return nil, err
}
} else if sockopt.HappyEyeballs == nil || sockopt.HappyEyeballs.TryDelayMs == 0 || sockopt.HappyEyeballs.MaxConcurrentTry == 0 || len(ips) < 2 || len(sockopt.DialerProxy) > 0 || dest.Network != net.Network_TCP {
dest.Address = net.IPAddress(ips[rand.N(len(ips))])
dest.Address = net.IPAddress(ips[dice.Roll(len(ips))])
errors.LogInfo(ctx, "replace destination with "+dest.String())
} else {
return TcpRaceDial(ctx, src, ips, dest.Port, sockopt, dest.Address.String())
@@ -3,7 +3,8 @@ package header
import (
"encoding/binary"
"errors"
"math/rand/v2"
"github.com/xtls/xray-core/common/dice"
)
type dns struct {
@@ -16,7 +17,7 @@ func (h *dns) Size() int {
func (h *dns) Serialize(b []byte) {
copy(b, h.header)
binary.BigEndian.PutUint16(b[0:], uint16(rand.Uint32()))
binary.BigEndian.PutUint16(b[0:], dice.RollUint16())
}
func NewHeaderDNS(domain string) (*dns, error) {
+3 -2
View File
@@ -1,8 +1,9 @@
package http
import (
"math/rand/v2"
"strings"
"github.com/xtls/xray-core/common/dice"
)
func pickString(arr []string) string {
@@ -13,7 +14,7 @@ func pickString(arr []string) string {
case 1:
return arr[0]
default:
return arr[rand.N(n)]
return arr[dice.Roll(n)]
}
}
+2 -2
View File
@@ -3,11 +3,11 @@ package kcp
import (
"context"
"io"
"math/rand/v2"
"sync/atomic"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet"
@@ -15,7 +15,7 @@ import (
"github.com/xtls/xray-core/transport/internet/tls"
)
var globalConv = uint32(uint16(rand.Uint32()))
var globalConv = uint32(dice.RollUint16())
func fetchInput(_ context.Context, input io.Reader, reader PacketReader, conn *Connection) {
cache := make(chan *buf.Buffer, 1024)
+2 -2
View File
@@ -7,13 +7,13 @@ import (
"encoding/json"
"fmt"
"io"
"math/rand/v2"
"net/http"
"net/url"
"strings"
"sync"
"time"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/transport/internet"
)
@@ -182,7 +182,7 @@ func jitter(backoff time.Duration) time.Duration {
if half <= 0 {
return backoff
}
return half + rand.N(half)
return half + time.Duration(dice.RollInt63n(int64(half)))
}
func rateLimited(payload []byte) bool {